Skip to content

Commit b10db87

Browse files
author
Casey Francis
committed
Steering fault fix
Update carcontroller.py Steering fault fix fault fix 1 fix conflict Rename oops
1 parent 4efd189 commit b10db87

File tree

3 files changed

+41
-5
lines changed

3 files changed

+41
-5
lines changed

panda/board/safety/safety_toyota.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ addr_checks toyota_rx_checks = {toyota_addr_checks, TOYOTA_ADDR_CHECKS_LEN};
4444
// global actuation limit states
4545
int toyota_dbc_eps_torque_factor = 100; // conversion factor for STEER_TORQUE_EPS in %: see dbc file
4646

47+
// steering faults occur when the angle rate is above a certain threshold for too long,
48+
// allow setting STEER_REQUEST bit to 0 with a non-zero desired torque when expected
49+
const uint8_t TOYOTA_MAX_STEER_RATE_FRAMES = 19U;
50+
uint8_t toyota_steer_req_matches; // counter for steer request bit matching non-zero torque
51+
4752
static uint8_t toyota_compute_checksum(CANPacket_t *to_push) {
4853
int addr = GET_ADDR(to_push);
4954
int len = GET_LEN(to_push);
@@ -227,13 +232,27 @@ static int toyota_tx_hook(CANPacket_t *to_send) {
227232
}
228233
}
229234

235+
// handle steer_req bit mismatches: we set the bit to 0 at an expected
236+
// interval to bypass an EPS fault, violation if we exceed that frequency
237+
bool steer_req_mismatch = (desired_torque != 0) && !steer_req;
238+
if (!steer_req_mismatch) {
239+
toyota_steer_req_matches = MIN(toyota_steer_req_matches + 1U, 255U);
240+
} else {
241+
// disallow torque cut if not enough recent matching steer_req messages
242+
if (toyota_steer_req_matches < (TOYOTA_MAX_STEER_RATE_FRAMES - 1U)) {
243+
violation = 1;
244+
}
245+
toyota_steer_req_matches = 0U;
246+
}
247+
230248
// no torque if controls is not allowed
231249
if (!controls_allowed && (desired_torque != 0)) {
232250
violation = 1;
233251
}
234252

235253
// reset to 0 if either controls is not allowed or there's a violation
236254
if (violation || !controls_allowed) {
255+
toyota_steer_req_matches = 0U;
237256
desired_torque_last = 0;
238257
rt_torque_last = 0;
239258
ts_last = ts;
@@ -250,6 +269,7 @@ static int toyota_tx_hook(CANPacket_t *to_send) {
250269

251270
static const addr_checks* toyota_init(int16_t param) {
252271
controls_allowed = 0;
272+
toyota_steer_req_matches = 0U;
253273
relay_malfunction_reset();
254274
gas_interceptor_detected = 0;
255275
toyota_dbc_eps_torque_factor = param;

selfdrive/car/toyota/carcontroller.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
from opendbc.can.packer import CANPacker
1111
VisualAlert = car.CarControl.HUDControl.VisualAlert
1212

13+
# constants for fault workaround
14+
MAX_STEER_RATE = 100 # deg/s
15+
MAX_STEER_RATE_FRAMES = 19
1316

1417
class CarController():
1518
def __init__(self, dbc_name, CP, VM):
@@ -19,7 +22,7 @@ def __init__(self, dbc_name, CP, VM):
1922
self.standstill_req = False
2023
self.steer_rate_limited = False
2124
self.CP = CP
22-
25+
self.steer_rate_counter = 0
2326
self.packer = CANPacker(dbc_name)
2427
self.gas = 0
2528
self.accel = 0
@@ -51,12 +54,22 @@ def update(self, enabled, active, CS, frame, actuators, pcm_cancel_cmd, hud_aler
5154
apply_steer = apply_toyota_steer_torque_limits(new_steer, self.last_steer, CS.out.steeringTorqueEps, CarControllerParams)
5255
self.steer_rate_limited = new_steer != apply_steer
5356

57+
# EPS_STATUS->LKA_STATE either goes to 21 or 25 on rising edge of a steering fault and
58+
# the value seems to describe how many frames the steering rate was above 100 deg/s, so
59+
# cut torque with some margin for the lower state
60+
if active and abs(CS.out.steeringRateDeg) >= MAX_STEER_RATE:
61+
self.steer_rate_counter += 1
62+
else:
63+
self.rate_limit_counter = 0
64+
65+
apply_steer_req = 1
5466
# Cut steering while we're in a known fault state (2s)
55-
if not active or CS.steer_state in (9, 25):
67+
if not active: # or CS.steer_state in (9, 25) or abs(CS.out.steeringRateDeg) > 100 or (abs(CS.out.steeringAngleDeg) > 150 and CS.CP.carFingerprint in [CAR.RAV4H, CAR.PRIUS]):
5668
apply_steer = 0
5769
apply_steer_req = 0
58-
else:
59-
apply_steer_req = 1
70+
elif self.steer_rate_counter > MAX_STEER_RATE_FRAMES:
71+
apply_steer_req = 0
72+
self.steer_rate_counter = 0
6073

6174
# TODO: probably can delete this. CS.pcm_acc_status uses a different signal
6275
# than CS.cruiseState.enabled. confirm they're not meaningfully different

selfdrive/car/toyota/carstate.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,10 @@ def update(self, cp, cp_cam):
8686
ret.steeringTorqueEps = cp.vl["STEER_TORQUE_SENSOR"]["STEER_TORQUE_EPS"] * self.eps_torque_scale
8787
# we could use the override bit from dbc, but it's triggered at too high torque values
8888
ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD
89-
ret.steerWarning = cp.vl["EPS_STATUS"]["LKA_STATE"] not in (1, 5)
89+
# steer rate fault, goes to 21 or 25 for 1 frame, then 9 for ~2 seconds
90+
ret.steerWarning = cp.vl["EPS_STATUS"]["LKA_STATE"] in (0, 9, 21, 25)
91+
# 17 is a fault from a prolonged high torque delta between cmd and user
92+
ret.steerError = cp.vl["EPS_STATUS"]["LKA_STATE"] == 17
9093

9194
if self.CP.carFingerprint in (CAR.LEXUS_IS, CAR.LEXUS_RC):
9295
ret.cruiseState.available = cp.vl["DSU_CRUISE"]["MAIN_ON"] != 0

0 commit comments

Comments
 (0)