Skip to content

Commit

Permalink
EU guidlines angle limits for E8x
Browse files Browse the repository at this point in the history
  • Loading branch information
dzid26 committed Nov 8, 2024
1 parent c313e72 commit 313ee80
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 22 deletions.
5 changes: 3 additions & 2 deletions board/safety/safety_bmw.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ float BMW_MARGIN = 0.1;

#define BMW_LAT_ACC_MAX 3.0 // EU guideline

// steering angle based on EU 3m/s2 lat acc limit for 2.66m wheelbase and 12.5 steer ratio
const struct lookup_t BMW_LOOKUP_MAX_ANGLE = {
{5., 15., 30.}, // m/s
{200., 20., 10.}}; // deg
{5., 15., 25.}, // m/s
{228.6, 25.4, 9.1}}; // deg


const struct lookup_t BMW_ANGLE_RATE_WINDUP = { // deg/s windup rate limit
Expand Down
40 changes: 20 additions & 20 deletions tests/safety/test_bmw.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
MS_TO_KPH = 3.6
SAMPLING_FREQ = 100 #Hz

ANGLE_MAX_BP = [5., 15., 30] #m/s
ANGLE_MAX = [200., 20., 10.] #deg
ANGLE_MAX_BP = [5., 15., 25.] #m/s
ANGLE_MAX = [228.6, 42.3, 15.2] #deg

ANGLE_RATE_BP = [0., 5., 15.] # m/s
ANGLE_RATE_BP = [0., 5., 25.] # m/s
ANGLE_RATE_WINDUP = [500., 80., 15.] #deg/s windup rate limit
ANGLE_RATE_UNWIND = [500., 350., 40.] #deg/s unwind rate limit

Expand Down Expand Up @@ -43,7 +43,7 @@ def sign(a):
return -1



class TestBmwSafety(unittest.TestCase):
def setUp(self):
self.safety = libpanda_py.libpanda
Expand All @@ -52,7 +52,7 @@ def setUp(self):

def _angle_meas_msg(self, angle, angle_rate):
to_send = make_msg(0, 0xc4, 7)

angle_int = int(angle / CAN_BMW_ANGLE_FAC)
angle_t = twos_comp(angle_int, 16) # signed

Expand All @@ -70,22 +70,22 @@ def _set_prev_angle(self, t):


def _actuator_angle_cmd_msg(self, mode, torque_req, angle_delta):

to_send = make_msg(2, 558)

cnt = 0

steer_angle = int(twos_comp(angle_delta / CAN_ACTUATOR_POS_FAC, 16)) # signed angle_delta
steer_tq = int(twos_comp(torque_req / CAN_ACTUATOR_TQ_FAC, 11))

checksum = (cnt + mode + steer_angle + steer_tq)
checksum = checksum >> 8 + checksum & 0xFF
checksum = checksum & 0xFF

to_send[0].RDLR = (checksum & 0xFF) | ((cnt & 0xF) << 8) | ((mode & 0x3) << 12) | ((steer_angle & 0xFFFF) << 16)
to_send[0].RDHR = (steer_tq & 0xFF) << 0
return to_send


def _speed_msg(self, speed):
to_send = make_msg(0, 0x1a0)
Expand All @@ -109,7 +109,7 @@ def _cruise_button_msg(self, buttons_bitwise): #todo: read creuisesate
else:
request_0xF = 0x0

if (buttons_bitwise & (1<<7 | 1<<4)): #if any cancel pressed
if (buttons_bitwise & (1<<7 | 1<<4)): #if any cancel pressed
notCancel = 0x0
else:
notCancel = 0xF
Expand All @@ -130,8 +130,8 @@ def test_angle_cmd_when_enabled(self): #todo add faulty BMW angle sensor (step a

self.safety.set_controls_allowed(1)
self.assertTrue(self.safety.get_controls_allowed())
self.safety.safety_rx_hook(self._speed_msg(s)) #receive speed which triggers angle limits to be updated to be later used by tx
self.safety.safety_rx_hook(self._speed_msg(s)) #receive speed which triggers angle limits to be updated to be later used by tx

# Stay within limits
# Up
self.safety.safety_rx_hook(self._angle_meas_msg(max_angle, max_delta_up))
Expand All @@ -155,13 +155,13 @@ def test_angle_cmd_when_enabled(self): #todo add faulty BMW angle sensor (step a
self.assertTrue(self.safety.get_controls_allowed())
self.assertEqual(1, self.safety.safety_tx_hook(self._actuator_angle_cmd_msg(MODE_OFF, 0, 0)))
self.assertTrue(self.safety.get_controls_allowed())

# Up
# # Inject too large measured angle
self.safety.set_controls_allowed(1)
self.safety.safety_rx_hook(self._angle_meas_msg(max_angle+1, max_delta_up))
self.assertFalse(self.safety.get_controls_allowed())

# Reset to 0 angle
self.safety.set_controls_allowed(1)
self.assertTrue(self.safety.get_controls_allowed())
Expand All @@ -174,13 +174,13 @@ def test_angle_cmd_when_enabled(self): #todo add faulty BMW angle sensor (step a
self.safety.safety_rx_hook(self._angle_meas_msg(max_angle, max_delta_up+1))
self.assertFalse(self.safety.get_controls_allowed(),\
'Speed: %f, Angle: %f, Delta: %f' % (s, max_angle, max_delta_down))

# Reset to 0 angle
self.safety.set_controls_allowed(1)
self.assertTrue(self.safety.get_controls_allowed())
self.assertEqual(1, self.safety.safety_tx_hook(self._actuator_angle_cmd_msg(MODE_OFF, 0, 0)))
self.assertTrue(self.safety.get_controls_allowed())

# Up
# Inject too high command angle rate - since last angle value is 0, sending angle value represents angle rate
self.safety.set_controls_allowed(1)
Expand All @@ -199,13 +199,13 @@ def test_angle_cmd_when_enabled(self): #todo add faulty BMW angle sensor (step a
self.assertEqual(1, self.safety.safety_tx_hook(self._actuator_angle_cmd_msg(MODE_OFF, 0, 0)))
self.assertTrue(self.safety.get_controls_allowed())


# Down
# Inject too large measured angle
self.safety.set_controls_allowed(1)
self.safety.safety_rx_hook(self._angle_meas_msg(-max_angle-1, -max_delta_down))
self.assertFalse(self.safety.get_controls_allowed())

# Reset to 0 angle
self.safety.set_controls_allowed(1)
self.assertTrue(self.safety.get_controls_allowed())
Expand Down Expand Up @@ -246,16 +246,16 @@ def test_brake_disengage(self):
self.safety.set_controls_allowed(1)
self.safety.safety_rx_hook(self._brake_msg(0))
self.assertTrue(self.safety.get_controls_allowed())


self.safety.safety_rx_hook(self._speed_msg(10)) #ALLOW_DEBUG keeps the actuator active even at 0 speed
self.safety.safety_rx_hook(self._brake_msg(1))
self.assertFalse(self.safety.get_controls_allowed())

def test_cruise_buttons(self):
self.safety.set_controls_allowed(1)
self.assertTrue(self.safety.get_controls_allowed())

self.safety.safety_rx_hook(self._cruise_button_msg(0x0)) # No button pressed
self.assertTrue(self.safety.get_controls_allowed())

Expand Down

0 comments on commit 313ee80

Please sign in to comment.