Module 5: The Safety Boundary

Goal. Find the exact point in the system where a steering or acceleration decision stops being software's opinion and becomes a physically enforced limit, and verify by reading the real enforcement code what it actually checks — not the one-line textbook version of the answer.

Setup. No hardware in this module (there is no panda board attached to this checkout), so unlike Modules 1-4 there's nothing to run: this module is source reading, checked against docs/SAFETY.md, rather than a captured command trace.

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

The safety boundary

Quiz

  1. TorqueSteeringLimits.type picks between driver_limit_check and dist_to_meas_check for 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 need TorqueDriverLimited specifically — what's different about how it reports its own steering state?
  2. Suppose a bug in controlsd caused 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?
  3. mads_heartbeat_engaged_check waits 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

Answer Key — Module 5
  1. A car whose CAN bus doesn't reliably report a clean, independent measured steering torque value for dist_to_meas_check to 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.
  2. The rate limit check (driver_limit_check, since this scenario is describing exactly the TorqueDriverLimited case) — it compares the commanded torque against torque_driver, the driver's own applied torque sampled from CAN, and its driver_torque_allowance/ driver_torque_multiplier terms are specifically there to squeeze the allowed commanded range down when the driver is pushing back, independent of anything controlsd claims it wants.
  3. 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.

↑ Back to Quiz 5

→ Module 6: Reproducing & What's Next