Abstract steering safety tests for Toyota and Chrysler (#520)
* start abstracting torque steering tests * remove duplicate * chrysler * remove that * revert that for now * fix toyota * unusedmaster
parent
2299ecffc4
commit
9874e73350
|
@ -109,6 +109,141 @@ class InterceptorSafetyTest(PandaSafetyTestBase):
|
|||
self.assertEqual(send, self._tx(self._interceptor_msg(gas, 0x200)))
|
||||
|
||||
|
||||
class TorqueSteeringSafetyTest(PandaSafetyTestBase):
|
||||
|
||||
MAX_RATE_UP = 0
|
||||
MAX_RATE_DOWN = 0
|
||||
MAX_TORQUE = 0
|
||||
MAX_RT_DELTA = 0
|
||||
RT_INTERVAL = 0
|
||||
MAX_TORQUE_ERROR = 0
|
||||
TORQUE_MEAS_TOLERANCE = 0
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
if cls.__name__ == "TorqueSteeringSafetyTest":
|
||||
cls.safety = None
|
||||
raise unittest.SkipTest
|
||||
|
||||
@abc.abstractmethod
|
||||
def _torque_meas_msg(self, torque):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def _torque_msg(self, torque):
|
||||
pass
|
||||
|
||||
def _set_prev_torque(self, t):
|
||||
self.safety.set_desired_torque_last(t)
|
||||
self.safety.set_rt_torque_last(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):
|
||||
self.safety.set_controls_allowed(controls_allowed)
|
||||
self.safety.set_rt_torque_last(torque)
|
||||
self.safety.set_torque_meas(torque, torque)
|
||||
self.safety.set_desired_torque_last(torque - self.MAX_RATE_UP)
|
||||
|
||||
if controls_allowed:
|
||||
send = (-self.MAX_TORQUE <= torque <= self.MAX_TORQUE)
|
||||
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)))
|
||||
|
||||
def test_non_realtime_limit_down(self):
|
||||
self.safety.set_controls_allowed(True)
|
||||
|
||||
torque_meas = self.MAX_TORQUE - self.MAX_TORQUE_ERROR - 50
|
||||
|
||||
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.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)))
|
||||
|
||||
def test_exceed_torque_sensor(self):
|
||||
self.safety.set_controls_allowed(True)
|
||||
|
||||
for sign in [-1, 1]:
|
||||
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.assertFalse(self._tx(self._torque_msg(sign * (self.MAX_TORQUE_ERROR + 2))))
|
||||
|
||||
def test_realtime_limit_up(self):
|
||||
self.safety.set_controls_allowed(True)
|
||||
|
||||
for sign in [-1, 1]:
|
||||
self.safety.init_tests()
|
||||
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.assertFalse(self._tx(self._torque_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)))
|
||||
|
||||
# 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))))
|
||||
|
||||
def test_torque_measurements(self):
|
||||
trq = 50
|
||||
for t in [trq, -trq, 0, 0, 0, 0]:
|
||||
self._rx(self._torque_meas_msg(t))
|
||||
|
||||
max_range = range(trq, trq + self.TORQUE_MEAS_TOLERANCE + 1)
|
||||
min_range = range(-(trq+self.TORQUE_MEAS_TOLERANCE), -trq + 1)
|
||||
self.assertTrue(self.safety.get_torque_meas_min() in min_range)
|
||||
self.assertTrue(self.safety.get_torque_meas_max() in max_range)
|
||||
|
||||
max_range = range(0, self.TORQUE_MEAS_TOLERANCE+1)
|
||||
min_range = range(-(trq+self.TORQUE_MEAS_TOLERANCE), -trq + 1)
|
||||
self._rx(self._torque_meas_msg(0))
|
||||
self.assertTrue(self.safety.get_torque_meas_min() in min_range)
|
||||
self.assertTrue(self.safety.get_torque_meas_max() in max_range)
|
||||
|
||||
max_range = range(0, self.TORQUE_MEAS_TOLERANCE+1)
|
||||
min_range = range(-self.TORQUE_MEAS_TOLERANCE, 0 + 1)
|
||||
self._rx(self._torque_meas_msg(0))
|
||||
self.assertTrue(self.safety.get_torque_meas_min() in min_range)
|
||||
self.assertTrue(self.safety.get_torque_meas_max() in max_range)
|
||||
|
||||
|
||||
class PandaSafetyTest(PandaSafetyTestBase):
|
||||
TX_MSGS = None
|
||||
STANDSTILL_THRESHOLD = None
|
||||
|
|
|
@ -1,20 +1,10 @@
|
|||
#!/usr/bin/env python3
|
||||
import unittest
|
||||
import numpy as np
|
||||
from panda import Panda
|
||||
from panda.tests.safety import libpandasafety_py
|
||||
import panda.tests.safety.common as common
|
||||
from panda.tests.safety.common import make_msg
|
||||
|
||||
MAX_RATE_UP = 3
|
||||
MAX_RATE_DOWN = 3
|
||||
MAX_STEER = 261
|
||||
|
||||
MAX_RT_DELTA = 112
|
||||
RT_INTERVAL = 250000
|
||||
|
||||
MAX_TORQUE_ERROR = 80
|
||||
|
||||
|
||||
def chrysler_checksum(msg, len_msg):
|
||||
checksum = 0xFF
|
||||
|
@ -41,12 +31,7 @@ def chrysler_checksum(msg, len_msg):
|
|||
shift = shift >> 1
|
||||
return ~checksum & 0xFF
|
||||
|
||||
class TestChryslerSafety(common.PandaSafetyTest):
|
||||
cnt_torque_meas = 0
|
||||
cnt_gas = 0
|
||||
cnt_cruise = 0
|
||||
cnt_brake = 0
|
||||
|
||||
class TestChryslerSafety(common.PandaSafetyTest, common.TorqueSteeringSafetyTest):
|
||||
TX_MSGS = [[571, 0], [658, 0], [678, 0]]
|
||||
STANDSTILL_THRESHOLD = 0
|
||||
RELAY_MALFUNCTION_ADDR = 0x292
|
||||
|
@ -54,6 +39,18 @@ class TestChryslerSafety(common.PandaSafetyTest):
|
|||
FWD_BLACKLISTED_ADDRS = {2: [658, 678]}
|
||||
FWD_BUS_LOOKUP = {0: 2, 2: 0}
|
||||
|
||||
MAX_RATE_UP = 3
|
||||
MAX_RATE_DOWN = 3
|
||||
MAX_TORQUE = 261
|
||||
MAX_RT_DELTA = 112
|
||||
RT_INTERVAL = 250000
|
||||
MAX_TORQUE_ERROR = 80
|
||||
|
||||
cnt_torque_meas = 0
|
||||
cnt_gas = 0
|
||||
cnt_cruise = 0
|
||||
cnt_brake = 0
|
||||
|
||||
def setUp(self):
|
||||
self.safety = libpandasafety_py.libpandasafety
|
||||
self.safety.set_safety_hooks(Panda.SAFETY_CHRYSLER, 0)
|
||||
|
@ -94,11 +91,6 @@ class TestChryslerSafety(common.PandaSafetyTest):
|
|||
self.__class__.cnt_brake += 1
|
||||
return to_send
|
||||
|
||||
def _set_prev_torque(self, t):
|
||||
self.safety.set_desired_torque_last(t)
|
||||
self.safety.set_rt_torque_last(t)
|
||||
self.safety.set_torque_meas(t, t)
|
||||
|
||||
def _torque_meas_msg(self, torque):
|
||||
to_send = make_msg(0, 544)
|
||||
to_send[0].RDHR = ((torque + 1024) >> 8) + (((torque + 1024) & 0xff) << 8)
|
||||
|
@ -112,17 +104,6 @@ class TestChryslerSafety(common.PandaSafetyTest):
|
|||
to_send[0].RDLR = ((torque + 1024) >> 8) + (((torque + 1024) & 0xff) << 8)
|
||||
return to_send
|
||||
|
||||
def test_steer_safety_check(self):
|
||||
for enabled in [0, 1]:
|
||||
for t in range(-MAX_STEER*2, MAX_STEER*2):
|
||||
self.safety.set_controls_allowed(enabled)
|
||||
self._set_prev_torque(t)
|
||||
if abs(t) > MAX_STEER or (not enabled and abs(t) > 0):
|
||||
self.assertFalse(self._tx(self._torque_msg(t)))
|
||||
else:
|
||||
self.assertTrue(self._tx(self._torque_msg(t)))
|
||||
|
||||
# TODO: why does chrysler check if moving?
|
||||
def test_disengage_on_gas(self):
|
||||
self.safety.set_controls_allowed(1)
|
||||
self._rx(self._speed_msg(2.2))
|
||||
|
@ -133,82 +114,6 @@ class TestChryslerSafety(common.PandaSafetyTest):
|
|||
self._rx(self._gas_msg(1))
|
||||
self.assertFalse(self.safety.get_controls_allowed())
|
||||
|
||||
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(MAX_RATE_UP)))
|
||||
|
||||
self._set_prev_torque(0)
|
||||
self.assertFalse(self._tx(self._torque_msg(MAX_RATE_UP + 1)))
|
||||
|
||||
def test_non_realtime_limit_down(self):
|
||||
self.safety.set_controls_allowed(True)
|
||||
|
||||
self.safety.set_rt_torque_last(MAX_STEER)
|
||||
torque_meas = MAX_STEER - MAX_TORQUE_ERROR - 20
|
||||
self.safety.set_torque_meas(torque_meas, torque_meas)
|
||||
self.safety.set_desired_torque_last(MAX_STEER)
|
||||
self.assertTrue(self._tx(self._torque_msg(MAX_STEER - MAX_RATE_DOWN)))
|
||||
|
||||
self.safety.set_rt_torque_last(MAX_STEER)
|
||||
self.safety.set_torque_meas(torque_meas, torque_meas)
|
||||
self.safety.set_desired_torque_last(MAX_STEER)
|
||||
self.assertFalse(self._tx(self._torque_msg(MAX_STEER - MAX_RATE_DOWN + 1)))
|
||||
|
||||
def test_exceed_torque_sensor(self):
|
||||
self.safety.set_controls_allowed(True)
|
||||
|
||||
for sign in [-1, 1]:
|
||||
self._set_prev_torque(0)
|
||||
for t in np.arange(0, 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.assertFalse(self._tx(self._torque_msg(sign * (MAX_TORQUE_ERROR + 2))))
|
||||
|
||||
def test_realtime_limit_up(self):
|
||||
self.safety.set_controls_allowed(True)
|
||||
|
||||
for sign in [-1, 1]:
|
||||
self.safety.init_tests_chrysler()
|
||||
self._set_prev_torque(0)
|
||||
for t in np.arange(0, 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 * (MAX_RT_DELTA + 1))))
|
||||
|
||||
self._set_prev_torque(0)
|
||||
for t in np.arange(0, MAX_RT_DELTA+1, 1):
|
||||
t *= sign
|
||||
self.safety.set_torque_meas(t, t)
|
||||
self.assertTrue(self._tx(self._torque_msg(t)))
|
||||
|
||||
# Increase timer to update rt_torque_last
|
||||
self.safety.set_timer(RT_INTERVAL + 1)
|
||||
self.assertTrue(self._tx(self._torque_msg(sign * MAX_RT_DELTA)))
|
||||
self.assertTrue(self._tx(self._torque_msg(sign * (MAX_RT_DELTA + 1))))
|
||||
|
||||
def test_torque_measurements(self):
|
||||
self._rx(self._torque_meas_msg(50))
|
||||
self._rx(self._torque_meas_msg(-50))
|
||||
self._rx(self._torque_meas_msg(0))
|
||||
self._rx(self._torque_meas_msg(0))
|
||||
self._rx(self._torque_meas_msg(0))
|
||||
self._rx(self._torque_meas_msg(0))
|
||||
|
||||
self.assertEqual(-50, self.safety.get_torque_meas_min())
|
||||
self.assertEqual(50, self.safety.get_torque_meas_max())
|
||||
|
||||
self._rx(self._torque_meas_msg(0))
|
||||
self.assertEqual(0, self.safety.get_torque_meas_max())
|
||||
self.assertEqual(-50, self.safety.get_torque_meas_min())
|
||||
|
||||
self._rx(self._torque_meas_msg(0))
|
||||
self.assertEqual(0, self.safety.get_torque_meas_max())
|
||||
self.assertEqual(0, self.safety.get_torque_meas_min())
|
||||
|
||||
def test_cancel_button(self):
|
||||
CANCEL = 1
|
||||
for b in range(0, 0x1ff):
|
||||
|
|
|
@ -6,22 +6,14 @@ from panda.tests.safety import libpandasafety_py
|
|||
import panda.tests.safety.common as common
|
||||
from panda.tests.safety.common import CANPackerPanda, make_msg, UNSAFE_MODE
|
||||
|
||||
MAX_RATE_UP = 10
|
||||
MAX_RATE_DOWN = 25
|
||||
MAX_TORQUE = 1500
|
||||
|
||||
MAX_ACCEL = 1.5
|
||||
MIN_ACCEL = -3.0
|
||||
|
||||
ISO_MAX_ACCEL = 2.0
|
||||
ISO_MIN_ACCEL = -3.5
|
||||
|
||||
MAX_RT_DELTA = 375
|
||||
RT_INTERVAL = 250000
|
||||
|
||||
MAX_TORQUE_ERROR = 350
|
||||
|
||||
class TestToyotaSafety(common.PandaSafetyTest, common.InterceptorSafetyTest):
|
||||
class TestToyotaSafety(common.PandaSafetyTest, common.InterceptorSafetyTest, \
|
||||
common.TorqueSteeringSafetyTest):
|
||||
|
||||
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
|
||||
|
@ -34,6 +26,14 @@ class TestToyotaSafety(common.PandaSafetyTest, common.InterceptorSafetyTest):
|
|||
FWD_BUS_LOOKUP = {0: 2, 2: 0}
|
||||
INTERCEPTOR_THRESHOLD = 845
|
||||
|
||||
MAX_RATE_UP = 10
|
||||
MAX_RATE_DOWN = 25
|
||||
MAX_TORQUE = 1500
|
||||
MAX_RT_DELTA = 375
|
||||
RT_INTERVAL = 250000
|
||||
MAX_TORQUE_ERROR = 350
|
||||
TORQUE_MEAS_TOLERANCE = 1 # toyota safety adds one to be conversative for rounding
|
||||
|
||||
@classmethod
|
||||
def setUp(self):
|
||||
self.packer = CANPackerPanda("toyota_prius_2017_pt_generated")
|
||||
|
@ -41,11 +41,6 @@ class TestToyotaSafety(common.PandaSafetyTest, common.InterceptorSafetyTest):
|
|||
self.safety.set_safety_hooks(Panda.SAFETY_TOYOTA, 66)
|
||||
self.safety.init_tests()
|
||||
|
||||
def _set_prev_torque(self, t):
|
||||
self.safety.set_desired_torque_last(t)
|
||||
self.safety.set_rt_torque_last(t)
|
||||
self.safety.set_torque_meas(t, t)
|
||||
|
||||
def _torque_meas_msg(self, torque):
|
||||
values = {"STEER_TORQUE_EPS": torque}
|
||||
return self.packer.make_can_msg_panda("STEER_TORQUE_SENSOR", 0, values)
|
||||
|
@ -98,93 +93,6 @@ class TestToyotaSafety(common.PandaSafetyTest, common.InterceptorSafetyTest):
|
|||
should_tx = np.isclose(accel, 0, atol=0.0001)
|
||||
self.assertEqual(should_tx, self._tx(self._accel_msg(accel)))
|
||||
|
||||
def test_torque_absolute_limits(self):
|
||||
for controls_allowed in [True, False]:
|
||||
for torque in np.arange(-MAX_TORQUE - 1000, MAX_TORQUE + 1000, MAX_RATE_UP):
|
||||
self.safety.set_controls_allowed(controls_allowed)
|
||||
self.safety.set_rt_torque_last(torque)
|
||||
self.safety.set_torque_meas(torque, torque)
|
||||
self.safety.set_desired_torque_last(torque - MAX_RATE_UP)
|
||||
|
||||
if controls_allowed:
|
||||
send = (-MAX_TORQUE <= torque <= MAX_TORQUE)
|
||||
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(MAX_RATE_UP)))
|
||||
|
||||
self._set_prev_torque(0)
|
||||
self.assertFalse(self._tx(self._torque_msg(MAX_RATE_UP + 1)))
|
||||
|
||||
def test_non_realtime_limit_down(self):
|
||||
self.safety.set_controls_allowed(True)
|
||||
|
||||
self.safety.set_rt_torque_last(1000)
|
||||
self.safety.set_torque_meas(500, 500)
|
||||
self.safety.set_desired_torque_last(1000)
|
||||
self.assertTrue(self._tx(self._torque_msg(1000 - MAX_RATE_DOWN)))
|
||||
|
||||
self.safety.set_rt_torque_last(1000)
|
||||
self.safety.set_torque_meas(500, 500)
|
||||
self.safety.set_desired_torque_last(1000)
|
||||
self.assertFalse(self._tx(self._torque_msg(1000 - MAX_RATE_DOWN + 1)))
|
||||
|
||||
def test_exceed_torque_sensor(self):
|
||||
self.safety.set_controls_allowed(True)
|
||||
|
||||
for sign in [-1, 1]:
|
||||
self._set_prev_torque(0)
|
||||
for t in np.arange(0, MAX_TORQUE_ERROR + 10, 10):
|
||||
t *= sign
|
||||
self.assertTrue(self._tx(self._torque_msg(t)))
|
||||
|
||||
self.assertFalse(self._tx(self._torque_msg(sign * (MAX_TORQUE_ERROR + 10))))
|
||||
|
||||
def test_realtime_limit_up(self):
|
||||
self.safety.set_controls_allowed(True)
|
||||
|
||||
for sign in [-1, 1]:
|
||||
self.safety.init_tests()
|
||||
self._set_prev_torque(0)
|
||||
for t in np.arange(0, 380, 10):
|
||||
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 * 380)))
|
||||
|
||||
self._set_prev_torque(0)
|
||||
for t in np.arange(0, 370, 10):
|
||||
t *= sign
|
||||
self.safety.set_torque_meas(t, t)
|
||||
self.assertTrue(self._tx(self._torque_msg(t)))
|
||||
|
||||
# Increase timer to update rt_torque_last
|
||||
self.safety.set_timer(RT_INTERVAL + 1)
|
||||
self.assertTrue(self._tx(self._torque_msg(sign * 370)))
|
||||
self.assertTrue(self._tx(self._torque_msg(sign * 380)))
|
||||
|
||||
def test_torque_measurements(self):
|
||||
for trq in [50, -50, 0, 0, 0, 0]:
|
||||
self._rx(self._torque_meas_msg(trq))
|
||||
|
||||
# toyota safety adds one to be conservative on rounding
|
||||
self.assertEqual(-51, self.safety.get_torque_meas_min())
|
||||
self.assertEqual(51, self.safety.get_torque_meas_max())
|
||||
|
||||
self._rx(self._torque_meas_msg(0))
|
||||
self.assertEqual(1, self.safety.get_torque_meas_max())
|
||||
self.assertEqual(-51, self.safety.get_torque_meas_min())
|
||||
|
||||
self._rx(self._torque_meas_msg(0))
|
||||
self.assertEqual(1, self.safety.get_torque_meas_max())
|
||||
self.assertEqual(-1, self.safety.get_torque_meas_min())
|
||||
|
||||
def test_rx_hook(self):
|
||||
# checksum checks
|
||||
for msg in ["trq", "pcm"]:
|
||||
|
|
Loading…
Reference in New Issue