safety tests: create classes for common torque steering tests (#951)

* Create base class for common steering tests (motor/driver)

* fix class name
This commit is contained in:
Shane Smiskol 2022-05-25 19:24:55 -07:00 committed by GitHub
parent dff5e6ed31
commit 6117c381f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 150 additions and 40 deletions

View File

@ -12,6 +12,7 @@ from panda.tests.safety import libpandasafety_py
MAX_WRONG_COUNTERS = 5
def package_can_msg(msg):
addr, _, dat, bus = msg
ret = libpandasafety_py.ffi.new('CANPacket_t *')
@ -23,9 +24,11 @@ def package_can_msg(msg):
return ret
def make_msg(bus, addr, length=8):
return package_can_msg([addr, 0, b'\x00' * length, bus])
class CANPackerPanda(CANPacker):
_counters: Dict[str, int] = defaultdict(lambda: -1)
@ -38,6 +41,7 @@ class CANPackerPanda(CANPacker):
msg = fix_checksum(msg)
return package_can_msg(msg)
class PandaSafetyTestBase(unittest.TestCase):
@classmethod
def setUpClass(cls):
@ -51,6 +55,7 @@ class PandaSafetyTestBase(unittest.TestCase):
def _tx(self, msg):
return self.safety.safety_tx_hook(msg)
class InterceptorSafetyTest(PandaSafetyTestBase):
INTERCEPTOR_THRESHOLD = 0
@ -117,19 +122,143 @@ class InterceptorSafetyTest(PandaSafetyTestBase):
self.assertEqual(send, self._tx(self._interceptor_gas_cmd(gas)))
class TorqueSteeringSafetyTest(PandaSafetyTestBase):
class TorqueSteeringSafetyTestBase(PandaSafetyTestBase):
MAX_RATE_UP = 0
MAX_RATE_DOWN = 0
MAX_TORQUE = 0
MAX_RT_DELTA = 0
RT_INTERVAL = 0
@classmethod
def setUpClass(cls):
if cls.__name__ == "TorqueSteeringSafetyTestBase":
cls.safety = None
raise unittest.SkipTest
@abc.abstractmethod
def _torque_cmd_msg(self, torque, steer_req=1):
pass
def _set_prev_torque(self, t):
self.safety.set_desired_torque_last(t)
self.safety.set_rt_torque_last(t)
def test_steer_safety_check(self):
for enabled in [0, 1]:
for t in range(-self.MAX_TORQUE * 2, self.MAX_TORQUE * 2):
self.safety.set_controls_allowed(enabled)
self._set_prev_torque(t)
if abs(t) > self.MAX_TORQUE or (not enabled and abs(t) > 0):
self.assertFalse(self._tx(self._torque_cmd_msg(t)))
else:
self.assertTrue(self._tx(self._torque_cmd_msg(t)))
def test_non_realtime_limit_up(self):
self.safety.set_controls_allowed(True)
self._set_prev_torque(0)
self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_RATE_UP)))
self._set_prev_torque(0)
self.assertTrue(self._tx(self._torque_cmd_msg(-self.MAX_RATE_UP)))
self._set_prev_torque(0)
self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_RATE_UP + 1)))
self.safety.set_controls_allowed(True)
self._set_prev_torque(0)
self.assertFalse(self._tx(self._torque_cmd_msg(-self.MAX_RATE_UP - 1)))
class DriverTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase):
DRIVER_TORQUE_ALLOWANCE = 0
DRIVER_TORQUE_FACTOR = 0
@classmethod
def setUpClass(cls):
if cls.__name__ == "DriverTorqueSteeringSafetyTest":
cls.safety = None
raise unittest.SkipTest
@abc.abstractmethod
def _torque_cmd_msg(self, torque, steer_req=1):
pass
def test_non_realtime_limit_up(self):
self.safety.set_torque_driver(0, 0)
super().test_non_realtime_limit_up()
# TODO: make this test something
def test_non_realtime_limit_down(self):
self.safety.set_torque_driver(0, 0)
self.safety.set_controls_allowed(True)
def test_against_torque_driver(self):
self.safety.set_controls_allowed(True)
for sign in [-1, 1]:
for t in np.arange(0, self.DRIVER_TORQUE_ALLOWANCE + 1, 1):
t *= -sign
self.safety.set_torque_driver(t, t)
self._set_prev_torque(self.MAX_TORQUE * sign)
self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_TORQUE * sign)))
self.safety.set_torque_driver(self.DRIVER_TORQUE_ALLOWANCE + 1, self.DRIVER_TORQUE_ALLOWANCE + 1)
self.assertFalse(self._tx(self._torque_cmd_msg(-self.MAX_TORQUE)))
# spot check some individual cases
for sign in [-1, 1]:
driver_torque = (self.DRIVER_TORQUE_ALLOWANCE + 10) * sign
torque_desired = (self.MAX_TORQUE - 10 * self.DRIVER_TORQUE_FACTOR) * sign
delta = 1 * sign
self._set_prev_torque(torque_desired)
self.safety.set_torque_driver(-driver_torque, -driver_torque)
self.assertTrue(self._tx(self._torque_cmd_msg(torque_desired)))
self._set_prev_torque(torque_desired + delta)
self.safety.set_torque_driver(-driver_torque, -driver_torque)
self.assertFalse(self._tx(self._torque_cmd_msg(torque_desired + delta)))
self._set_prev_torque(self.MAX_TORQUE * sign)
self.safety.set_torque_driver(-self.MAX_TORQUE * sign, -self.MAX_TORQUE * sign)
self.assertTrue(self._tx(self._torque_cmd_msg((self.MAX_TORQUE - self.MAX_RATE_DOWN) * sign)))
self._set_prev_torque(self.MAX_TORQUE * sign)
self.safety.set_torque_driver(-self.MAX_TORQUE * sign, -self.MAX_TORQUE * sign)
self.assertTrue(self._tx(self._torque_cmd_msg(0)))
self._set_prev_torque(self.MAX_TORQUE * sign)
self.safety.set_torque_driver(-self.MAX_TORQUE * sign, -self.MAX_TORQUE * sign)
self.assertFalse(self._tx(self._torque_cmd_msg((self.MAX_TORQUE - self.MAX_RATE_DOWN + 1) * sign)))
def test_realtime_limits(self):
self.safety.set_controls_allowed(True)
for sign in [-1, 1]:
self.safety.init_tests()
self._set_prev_torque(0)
self.safety.set_torque_driver(0, 0)
for t in np.arange(0, self.MAX_RT_DELTA, 1):
t *= sign
self.assertTrue(self._tx(self._torque_cmd_msg(t)))
self.assertFalse(self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA + 1))))
self._set_prev_torque(0)
for t in np.arange(0, self.MAX_RT_DELTA, 1):
t *= sign
self.assertTrue(self._tx(self._torque_cmd_msg(t)))
# Increase timer to update rt_torque_last
self.safety.set_timer(self.RT_INTERVAL + 1)
self.assertTrue(self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA - 1))))
self.assertTrue(self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA + 1))))
class MotorTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase):
MAX_TORQUE_ERROR = 0
TORQUE_MEAS_TOLERANCE = 0
@classmethod
def setUpClass(cls):
if cls.__name__ == "TorqueSteeringSafetyTest":
if cls.__name__ == "MotorTorqueSteeringSafetyTest":
cls.safety = None
raise unittest.SkipTest
@ -138,24 +267,13 @@ class TorqueSteeringSafetyTest(PandaSafetyTestBase):
pass
@abc.abstractmethod
def _torque_msg(self, torque, steer_req=1):
def _torque_cmd_msg(self, torque, steer_req=1):
pass
def _set_prev_torque(self, t):
self.safety.set_desired_torque_last(t)
self.safety.set_rt_torque_last(t)
super()._set_prev_torque(t)
self.safety.set_torque_meas(t, t)
def test_steer_safety_check(self):
for enabled in [0, 1]:
for t in range(-self.MAX_TORQUE * 2, self.MAX_TORQUE * 2):
self.safety.set_controls_allowed(enabled)
self._set_prev_torque(t)
if abs(t) > self.MAX_TORQUE or (not enabled and abs(t) > 0):
self.assertFalse(self._tx(self._torque_msg(t)))
else:
self.assertTrue(self._tx(self._torque_msg(t)))
def test_torque_absolute_limits(self):
for controls_allowed in [True, False]:
for torque in np.arange(-self.MAX_TORQUE - 1000, self.MAX_TORQUE + 1000, self.MAX_RATE_UP):
@ -169,16 +287,7 @@ class TorqueSteeringSafetyTest(PandaSafetyTestBase):
else:
send = torque == 0
self.assertEqual(send, self._tx(self._torque_msg(torque)))
def test_non_realtime_limit_up(self):
self.safety.set_controls_allowed(True)
self._set_prev_torque(0)
self.assertTrue(self._tx(self._torque_msg(self.MAX_RATE_UP)))
self._set_prev_torque(0)
self.assertFalse(self._tx(self._torque_msg(self.MAX_RATE_UP + 1)))
self.assertEqual(send, self._tx(self._torque_cmd_msg(torque)))
def test_non_realtime_limit_down(self):
self.safety.set_controls_allowed(True)
@ -188,12 +297,12 @@ class TorqueSteeringSafetyTest(PandaSafetyTestBase):
self.safety.set_rt_torque_last(self.MAX_TORQUE)
self.safety.set_torque_meas(torque_meas, torque_meas)
self.safety.set_desired_torque_last(self.MAX_TORQUE)
self.assertTrue(self._tx(self._torque_msg(self.MAX_TORQUE - self.MAX_RATE_DOWN)))
self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_TORQUE - self.MAX_RATE_DOWN)))
self.safety.set_rt_torque_last(self.MAX_TORQUE)
self.safety.set_torque_meas(torque_meas, torque_meas)
self.safety.set_desired_torque_last(self.MAX_TORQUE)
self.assertFalse(self._tx(self._torque_msg(self.MAX_TORQUE - self.MAX_RATE_DOWN + 1)))
self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_TORQUE - self.MAX_RATE_DOWN + 1)))
def test_exceed_torque_sensor(self):
self.safety.set_controls_allowed(True)
@ -202,9 +311,9 @@ class TorqueSteeringSafetyTest(PandaSafetyTestBase):
self._set_prev_torque(0)
for t in np.arange(0, self.MAX_TORQUE_ERROR + 2, 2): # step needs to be smaller than MAX_TORQUE_ERROR
t *= sign
self.assertTrue(self._tx(self._torque_msg(t)))
self.assertTrue(self._tx(self._torque_cmd_msg(t)))
self.assertFalse(self._tx(self._torque_msg(sign * (self.MAX_TORQUE_ERROR + 2))))
self.assertFalse(self._tx(self._torque_cmd_msg(sign * (self.MAX_TORQUE_ERROR + 2))))
def test_realtime_limit_up(self):
self.safety.set_controls_allowed(True)
@ -215,19 +324,19 @@ class TorqueSteeringSafetyTest(PandaSafetyTestBase):
for t in np.arange(0, self.MAX_RT_DELTA + 1, 1):
t *= sign
self.safety.set_torque_meas(t, t)
self.assertTrue(self._tx(self._torque_msg(t)))
self.assertFalse(self._tx(self._torque_msg(sign * (self.MAX_RT_DELTA + 1))))
self.assertTrue(self._tx(self._torque_cmd_msg(t)))
self.assertFalse(self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA + 1))))
self._set_prev_torque(0)
for t in np.arange(0, self.MAX_RT_DELTA + 1, 1):
t *= sign
self.safety.set_torque_meas(t, t)
self.assertTrue(self._tx(self._torque_msg(t)))
self.assertTrue(self._tx(self._torque_cmd_msg(t)))
# Increase timer to update rt_torque_last
self.safety.set_timer(self.RT_INTERVAL + 1)
self.assertTrue(self._tx(self._torque_msg(sign * self.MAX_RT_DELTA)))
self.assertTrue(self._tx(self._torque_msg(sign * (self.MAX_RT_DELTA + 1))))
self.assertTrue(self._tx(self._torque_cmd_msg(sign * self.MAX_RT_DELTA)))
self.assertTrue(self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA + 1))))
def test_torque_measurements(self):
trq = 50

View File

@ -5,7 +5,8 @@ from panda.tests.safety import libpandasafety_py
import panda.tests.safety.common as common
from panda.tests.safety.common import CANPackerPanda
class TestChryslerSafety(common.PandaSafetyTest, common.TorqueSteeringSafetyTest):
class TestChryslerSafety(common.PandaSafetyTest, common.MotorTorqueSteeringSafetyTest):
TX_MSGS = [[571, 0], [658, 0], [678, 0]]
STANDSTILL_THRESHOLD = 0
RELAY_MALFUNCTION_ADDR = 0x292
@ -61,7 +62,7 @@ class TestChryslerSafety(common.PandaSafetyTest, common.TorqueSteeringSafetyTest
self.__class__.cnt_torque_meas += 1
return self.packer.make_can_msg_panda("EPS_STATUS", 0, values)
def _torque_msg(self, torque, steer_req=1):
def _torque_cmd_msg(self, torque, steer_req=1):
values = {"LKAS_STEERING_TORQUE": torque}
return self.packer.make_can_msg_panda("LKAS_COMMAND", 0, values)

View File

@ -22,7 +22,7 @@ def interceptor_msg(gas, addr):
class TestToyotaSafety(common.PandaSafetyTest, common.InterceptorSafetyTest,
common.TorqueSteeringSafetyTest):
common.MotorTorqueSteeringSafetyTest):
TX_MSGS = [[0x283, 0], [0x2E6, 0], [0x2E7, 0], [0x33E, 0], [0x344, 0], [0x365, 0], [0x366, 0], [0x4CB, 0], # DSU bus 0
[0x128, 1], [0x141, 1], [0x160, 1], [0x161, 1], [0x470, 1], # DSU bus 1
@ -54,7 +54,7 @@ class TestToyotaSafety(common.PandaSafetyTest, common.InterceptorSafetyTest,
values = {"STEER_TORQUE_EPS": (torque / self.EPS_SCALE) * 100.}
return self.packer.make_can_msg_panda("STEER_TORQUE_SENSOR", 0, values)
def _torque_msg(self, torque, steer_req=1):
def _torque_cmd_msg(self, torque, steer_req=1):
values = {"STEER_TORQUE_CMD": torque, "STEER_REQUEST": steer_req}
return self.packer.make_can_msg_panda("STEERING_LKA", 0, values)
@ -147,11 +147,11 @@ class TestToyotaSafety(common.PandaSafetyTest, common.InterceptorSafetyTest,
self.safety.set_controls_allowed(True)
for _ in range(100):
self._set_prev_torque(self.MAX_TORQUE)
self.assertFalse(self._tx(self._torque_msg(self.MAX_TORQUE, steer_req=0)))
self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0)))
self._set_prev_torque(self.MAX_TORQUE)
for _ in range(100):
self.assertTrue(self._tx(self._torque_msg(self.MAX_TORQUE, steer_req=1)))
self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1)))
def test_rx_hook(self):
# checksum checks