mirror of https://github.com/commaai/panda.git
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:
parent
dff5e6ed31
commit
6117c381f2
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue