Module 5: The Safety Boundary
Predict
Before this workshop was generated, a calibration question asked where sunnypilot's safety model
is primarily enforced, and offered panda's C firmware, because it's the last line before the
car as one option — which is correct, and which you picked. Two follow-up questions that answer
alone doesn't settle: when panda checks a commanded steering torque, does it recompute what the
correct value should be, or only clamp/reject whatever the Linux side asks for? And when it
decides whether steering assistance is currently allowed to be active at all, does it trust the
Linux side's claim about that, or verify it independently?
Run
Every commanded steering torque value passes through one function before it's allowed onto the CAN bus:
bool steer_torque_cmd_checks(int desired_torque, int steer_req, const TorqueSteeringLimits limits) {
bool violation = false;
uint32_t ts = microsecond_timer_get();
if (controls_allowed || controls_allowed_lateral) {
// Some safety models support variable torque limit based on vehicle speed
int max_torque = limits.max_torque;
if (limits.dynamic_max_torque) {
const float fudged_speed = (vehicle_speed.min / VEHICLE_SPEED_FACTOR) - 1.;
max_torque = safety_interpolate(limits.max_torque_lookup, fudged_speed) + 1;
max_torque = SAFETY_CLAMP(max_torque, -limits.max_torque, limits.max_torque);
}
// *** global torque limit check ***
violation |= safety_max_limit_check(desired_torque, max_torque, -max_torque);
// *** torque rate limit check ***
if (limits.type == TorqueDriverLimited) {
violation |= driver_limit_check(desired_torque, desired_torque_last, &torque_driver,
max_torque, limits.max_rate_up, limits.max_rate_down,
limits.driver_torque_allowance, limits.driver_torque_multiplier);
} else {
violation |= dist_to_meas_check(desired_torque, desired_torque_last, &torque_meas,
limits.max_rate_up, limits.max_rate_down, limits.max_torque_error);
}
desired_torque_last = desired_torque;
// *** torque real time rate limit check ***
violation |= rt_torque_rate_limit_check(desired_torque, rt_torque_last, limits.max_rt_delta);
(opendbc_repo/opendbc/safety/lateral.h lines 61-89, the start of steer_torque_cmd_checks,
elided at its closing brace.) This is C, running on the panda's own microcontroller, not on the
Linux computer that runs every process from Modules 1-4 — a crash, hang, or bug anywhere in
controlsd, plannerd, or any of the ~40 processes from Module 1 cannot skip this function,
because it never runs on that computer at all.
Observe
Three independent checks run on every single commanded torque value, not one:
| check | compares commanded torque against | rejects if |
|---|---|---|
| global limit | a fixed (or speed-interpolated) max_torque |
magnitude exceeds the limit at all |
| rate limit | either the driver's own applied torque (driver_limit_check) or the measured torque from the car (dist_to_meas_check), depending on the car's TorqueSteeringLimits.type |
it moved too far, too fast, from that reference |
| real-time rate limit | the torque commanded on the previous cycle (rt_torque_rate_limit_check) |
it jumped too much in one control cycle |
Explain
Notice what dist_to_meas_check and driver_limit_check compare the commanded value against:
not "whatever controlsd said last time," but the car's own measured torque or the
driver's own applied torque — values panda reads directly off the CAN bus itself, not values
the Linux side reports. Panda doesn't recompute the "correct" steering torque (it has no
driving model, no planner); it constrains how far the requested value is allowed to diverge from
what the car and driver are physically doing right now. That answers the first Predict question:
clamp/reject against independently-observed reality, not recomputation, and not blind trust of
the requester either.
The second Predict question — does panda trust the Linux side's claim about whether steering
assistance is currently allowed — has an equally concrete answer, and it's the same
controls_allowed_lateral flag gating the function above. Recall from Module 4 that
sunnypilot.mads.state.StateMachine decides, in Python, whether MADS-controlled steering should
be active. Python's decision reaches the panda over a USB heartbeat command, but panda keeps its
own copy of "is lateral engaged," and checks the two against each other:
inline void mads_heartbeat_engaged_check(void) {
if (controls_allowed_lateral && !heartbeat_engaged_mads) {
heartbeat_engaged_mads_mismatches += 1U;
if (heartbeat_engaged_mads_mismatches >= 3U) {
mads_exit_controls(MADS_DISENGAGE_REASON_HEARTBEAT_ENGAGED_MISMATCH);
}
} else {
heartbeat_engaged_mads_mismatches = 0U;
}
}
(opendbc_repo/opendbc/safety/sunnypilot/mads.h lines 136-145.) If panda's own
controls_allowed_lateral says steering is engaged but three consecutive heartbeats fail to
confirm that from the Linux side, panda disengages lateral control itself, unprompted. This is
the same "verify, don't trust" pattern as the torque checks above, one level up: not just "is
this torque value physically plausible" but "does the Linux side's own claim about its current
mode match what I've independently been tracking" — checked on a firmware timer that keeps
running even if the Linux side has stopped saying anything at all.
docs/SAFETY.md states the two requirements this whole boundary exists to satisfy: the driver
must always be able to retake manual control, and the actuators must not move so quickly the
driver can't safely react to it (citing ISO 11270/15622, translating to "0.9 seconds of maximum
actuation to achieve a 1m lateral deviation"). Everything in this module is that second
requirement implemented as C code that runs independently of, and doesn't fully trust, every
process traced in Modules 1-4.
Diagram: where the boundary sits
Quiz
TorqueSteeringLimits.typepicks betweendriver_limit_checkanddist_to_meas_checkfor the rate-limit check. Given what each compares against (the driver's applied torque vs. the car's measured torque), what kind of car do you think would needTorqueDriverLimitedspecifically — what's different about how it reports its own steering state?- Suppose a bug in
controlsdcaused it to keep asking for high steering torque long after the driver had grabbed the wheel and was resisting it. Which specific check in the table above would catch that, and against which reference value? mads_heartbeat_engaged_checkwaits for three consecutive mismatches before disengaging, rather than acting on the first one. What failure mode would acting on the very first mismatch risk causing, given that the heartbeat travels over USB rather than being computed locally?
Answer Key — Module 5
- A car whose CAN bus doesn't reliably report a clean, independent measured steering torque
value for
dist_to_meas_checkto compare against — so the safety code instead measures against the driver's torque input, which most cars do report distinctly, as the more reliable independent reference for that platform. - The rate limit check (
driver_limit_check, since this scenario is describing exactly theTorqueDriverLimitedcase) — it compares the commanded torque againsttorque_driver, the driver's own applied torque sampled from CAN, and itsdriver_torque_allowance/driver_torque_multiplierterms are specifically there to squeeze the allowed commanded range down when the driver is pushing back, independent of anythingcontrolsdclaims it wants. - Acting on one mismatch risks disengaging lateral control on a single dropped or delayed USB heartbeat packet, which is a plausible transient (bus contention, scheduling jitter) rather than evidence the Linux side has actually diverged from panda's state — three consecutive misses is a hedge against reacting to ordinary noise as if it were a real fault.