mirror of
https://github.com/infiniteCable2/panda.git
synced 2026-02-19 01:33:52 +08:00
safety tests: add common longitudinal accel class (#1298)
* add longitudinal safety test class * rename to accel_cmd_msg * line * do hyundai * set default min and max accel * revert * thanks pylint
This commit is contained in:
@@ -131,6 +131,40 @@ class InterceptorSafetyTest(PandaSafetyTestBase):
|
||||
self.assertEqual(send, self._tx(self._interceptor_gas_cmd(gas)))
|
||||
|
||||
|
||||
class LongitudinalAccelSafetyTest(PandaSafetyTestBase, abc.ABC):
|
||||
|
||||
MIN_ACCEL: float = 2.0
|
||||
MAX_ACCEL: float = -3.5
|
||||
INACTIVE_ACCEL: float = 0.0
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
if cls.__name__ == "LongitudinalAccelSafetyTest":
|
||||
cls.safety = None
|
||||
raise unittest.SkipTest
|
||||
|
||||
@abc.abstractmethod
|
||||
def _accel_msg(self, accel: float):
|
||||
pass
|
||||
|
||||
def test_accel_actuation_limits(self, stock_longitudinal=False):
|
||||
limits = ((self.MIN_ACCEL, self.MAX_ACCEL, ALTERNATIVE_EXPERIENCE.DEFAULT),
|
||||
(self.MIN_ACCEL, self.MAX_ACCEL, ALTERNATIVE_EXPERIENCE.RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX))
|
||||
|
||||
for min_accel, max_accel, alternative_experience in limits:
|
||||
for accel in np.arange(min_accel - 1, max_accel + 1, 0.05):
|
||||
for controls_allowed in [True, False]:
|
||||
self.safety.set_controls_allowed(controls_allowed)
|
||||
self.safety.set_alternative_experience(alternative_experience)
|
||||
if stock_longitudinal:
|
||||
should_tx = False
|
||||
elif controls_allowed:
|
||||
should_tx = int(min_accel * 1000) <= int(accel * 1000) <= int(max_accel * 1000)
|
||||
else:
|
||||
should_tx = np.isclose(accel, self.INACTIVE_ACCEL, atol=0.0001)
|
||||
self.assertEqual(should_tx, self._tx(self._accel_msg(accel)))
|
||||
|
||||
|
||||
class TorqueSteeringSafetyTestBase(PandaSafetyTestBase, abc.ABC):
|
||||
|
||||
MAX_RATE_UP = 0
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import numpy as np
|
||||
from typing import Tuple
|
||||
import unittest
|
||||
|
||||
import panda.tests.safety.common as common
|
||||
from panda.tests.libpanda import libpanda_py
|
||||
from panda.tests.safety.common import make_msg
|
||||
|
||||
@@ -12,8 +13,6 @@ class Buttons:
|
||||
CANCEL = 4
|
||||
|
||||
|
||||
MAX_ACCEL = 2.0
|
||||
MIN_ACCEL = -3.5
|
||||
PREV_BUTTON_SAMPLES = 8
|
||||
ENABLE_BUTTONS = (Buttons.RESUME, Buttons.SET, Buttons.CANCEL)
|
||||
|
||||
@@ -75,12 +74,18 @@ class HyundaiButtonBase:
|
||||
self._rx(self._button_msg(Buttons.NONE))
|
||||
|
||||
|
||||
class HyundaiLongitudinalBase:
|
||||
class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest):
|
||||
# pylint: disable=no-member,abstract-method
|
||||
|
||||
DISABLED_ECU_UDS_MSG: Tuple[int, int]
|
||||
DISABLED_ECU_ACTUATION_MSG: Tuple[int, int]
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
if cls.__name__ == "HyundaiLongitudinalBase":
|
||||
cls.safety = None
|
||||
raise unittest.SkipTest
|
||||
|
||||
# override these tests from PandaSafetyTest, hyundai longitudinal uses button enable
|
||||
def test_disable_control_allowed_from_cruise(self):
|
||||
pass
|
||||
@@ -128,14 +133,6 @@ class HyundaiLongitudinalBase:
|
||||
self._rx(self._button_msg(Buttons.CANCEL))
|
||||
self.assertFalse(self.safety.get_controls_allowed())
|
||||
|
||||
def test_accel_safety_check(self):
|
||||
for controls_allowed in [True, False]:
|
||||
for accel in np.arange(MIN_ACCEL - 1, MAX_ACCEL + 1, 0.01):
|
||||
accel = round(accel, 2) # floats might not hit exact boundary conditions without rounding
|
||||
self.safety.set_controls_allowed(controls_allowed)
|
||||
send = MIN_ACCEL <= accel <= MAX_ACCEL if controls_allowed else accel == 0
|
||||
self.assertEqual(send, self._tx(self._accel_msg(accel)), (controls_allowed, accel))
|
||||
|
||||
def test_tester_present_allowed(self):
|
||||
"""
|
||||
Ensure tester present diagnostic message is allowed to keep ECU knocked out
|
||||
|
||||
@@ -7,10 +7,7 @@ import itertools
|
||||
from panda import Panda
|
||||
from panda.tests.libpanda import libpanda_py
|
||||
import panda.tests.safety.common as common
|
||||
from panda.tests.safety.common import CANPackerPanda, make_msg, ALTERNATIVE_EXPERIENCE
|
||||
|
||||
MAX_ACCEL = 2.0
|
||||
MIN_ACCEL = -3.5
|
||||
from panda.tests.safety.common import CANPackerPanda, make_msg
|
||||
|
||||
|
||||
def interceptor_msg(gas, addr):
|
||||
@@ -22,7 +19,8 @@ def interceptor_msg(gas, addr):
|
||||
return to_send
|
||||
|
||||
|
||||
class TestToyotaSafetyBase(common.PandaSafetyTest, common.InterceptorSafetyTest):
|
||||
class TestToyotaSafetyBase(common.PandaSafetyTest, common.InterceptorSafetyTest,
|
||||
common.LongitudinalAccelSafetyTest):
|
||||
|
||||
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
|
||||
@@ -94,23 +92,6 @@ class TestToyotaSafetyBase(common.PandaSafetyTest, common.InterceptorSafetyTest)
|
||||
msg = libpanda_py.make_CANPacket(0x283, 0, bytes(dat))
|
||||
self.assertEqual(not bad, self._tx(msg))
|
||||
|
||||
def test_accel_actuation_limits(self, stock_longitudinal=False):
|
||||
limits = ((MIN_ACCEL, MAX_ACCEL, ALTERNATIVE_EXPERIENCE.DEFAULT),
|
||||
(MIN_ACCEL, MAX_ACCEL, ALTERNATIVE_EXPERIENCE.RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX))
|
||||
|
||||
for min_accel, max_accel, alternative_experience in limits:
|
||||
for accel in np.arange(min_accel - 1, max_accel + 1, 0.1):
|
||||
for controls_allowed in [True, False]:
|
||||
self.safety.set_controls_allowed(controls_allowed)
|
||||
self.safety.set_alternative_experience(alternative_experience)
|
||||
if stock_longitudinal:
|
||||
should_tx = False
|
||||
elif controls_allowed:
|
||||
should_tx = int(min_accel * 1000) <= int(accel * 1000) <= int(max_accel * 1000)
|
||||
else:
|
||||
should_tx = np.isclose(accel, 0, atol=0.0001)
|
||||
self.assertEqual(should_tx, self._tx(self._accel_msg(accel)))
|
||||
|
||||
# Only allow LTA msgs with no actuation
|
||||
def test_lta_steer_cmd(self):
|
||||
for engaged, req, req2, setme_x64, angle in itertools.product([True, False],
|
||||
@@ -211,7 +192,7 @@ class TestToyotaStockLongitudinalBase(TestToyotaSafetyBase):
|
||||
"""
|
||||
for controls_allowed in [True, False]:
|
||||
self.safety.set_controls_allowed(controls_allowed)
|
||||
for accel in np.arange(MIN_ACCEL - 1, MAX_ACCEL + 1, 0.1):
|
||||
for accel in np.arange(self.MIN_ACCEL - 1, self.MAX_ACCEL + 1, 0.1):
|
||||
self.assertFalse(self._tx(self._accel_msg(accel)))
|
||||
should_tx = np.isclose(accel, 0, atol=0.0001)
|
||||
self.assertEqual(should_tx, self._tx(self._accel_msg(accel, cancel_req=1)))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
import numpy as np
|
||||
import unittest
|
||||
from panda import Panda
|
||||
from panda.tests.libpanda import libpanda_py
|
||||
@@ -17,8 +16,6 @@ MSG_MOTOR_5 = 0x480 # RX from ECU, for ACC main switch state
|
||||
MSG_ACC_GRA_ANZEIGE = 0x56A # TX by OP, ACC HUD
|
||||
MSG_LDW_1 = 0x5BE # TX by OP, Lane line recognition and text alerts
|
||||
|
||||
MAX_ACCEL = 2.0
|
||||
MIN_ACCEL = -3.5
|
||||
|
||||
class TestVolkswagenPqSafety(common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest):
|
||||
cruise_engaged = False
|
||||
@@ -142,7 +139,7 @@ class TestVolkswagenPqStockSafety(TestVolkswagenPqSafety):
|
||||
self.assertTrue(self._tx(self._button_msg(resume=True)))
|
||||
|
||||
|
||||
class TestVolkswagenPqLongSafety(TestVolkswagenPqSafety):
|
||||
class TestVolkswagenPqLongSafety(TestVolkswagenPqSafety, common.LongitudinalAccelSafetyTest):
|
||||
TX_MSGS = [[MSG_HCA_1, 0], [MSG_LDW_1, 0], [MSG_ACC_SYSTEM, 0], [MSG_ACC_GRA_ANZEIGE, 0]]
|
||||
FWD_BLACKLISTED_ADDRS = {2: [MSG_HCA_1, MSG_LDW_1, MSG_ACC_SYSTEM, MSG_ACC_GRA_ANZEIGE]}
|
||||
FWD_BUS_LOOKUP = {0: 2, 2: 0}
|
||||
@@ -192,15 +189,6 @@ class TestVolkswagenPqLongSafety(TestVolkswagenPqSafety):
|
||||
self._rx(self._motor_5_msg(main_switch=False))
|
||||
self.assertFalse(self.safety.get_controls_allowed(), "controls allowed after ACC main switch off")
|
||||
|
||||
def test_accel_safety_check(self):
|
||||
for controls_allowed in [True, False]:
|
||||
for accel in np.arange(MIN_ACCEL - 2, MAX_ACCEL + 2, 0.005):
|
||||
accel = round(accel, 2) # floats might not hit exact boundary conditions without rounding
|
||||
send = MIN_ACCEL <= accel <= MAX_ACCEL if controls_allowed else accel == self.INACTIVE_ACCEL
|
||||
self.safety.set_controls_allowed(controls_allowed)
|
||||
# primary accel request used by ECU
|
||||
self.assertEqual(send, self._tx(self._accel_msg(accel)), (controls_allowed, accel))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user