Module 3: One Instant in a Drive

Goal. Take a single instant from the demo route and follow it through five of the six messages from Module 2, from what the camera model saw to what the car was told to do, using only your own captured numbers — not a description of how the pipeline is "supposed to" work.

Setup. .venv active, same capture as Module 2 (Log page, vEgo=27.209 m/s, cruise set to 33.528 m/s, no lead detected).

Predict

longitudinalPlan.longitudinalPlanSource in your capture reads e2e ("end-to-end" — the driving model's own suggestion, as opposed to a classical control-theory solver reacting to a tracked lead car). Before reading the code: if the source is e2e, do you expect longitudinalPlan.aTarget to be a straight copy of whatever the model suggested, or something else derived from it?

Run

Line up the five messages from your own capture into the order they were produced, each one naming which of the earlier ones it depends on:

stage message depends on key field(s), your capture
1. perception modelV2 camera frame action.desiredAcceleration = 0.306, laneLineProbs = [0.56, 0.92, 0.39, 0.03]
2. radar tracking radarState can (radar returns) leadOne.status = False (no lead)
3. planning longitudinalPlan modelV2 + radarState + carState longitudinalPlanSource = e2e, aTarget = 0.306
4. control carControl longitudinalPlan + carState longActive = True, actuators.accel = 0.277
5. state selfdriveState driver + system events state = enabled, active = True

(cross-check: Log page)

Now check the claim from Predict against the actual planner code, selfdrive/controls/lib/longitudinal_planner.py:

output_a_target_e2e = sm['modelV2'].action.desiredAcceleration
output_should_stop_e2e = sm['modelV2'].action.shouldStop

if self.is_e2e(sm):
  output_a_target = min(output_a_target_e2e, output_a_target_mpc)
  self.output_should_stop = output_should_stop_e2e or output_should_stop_mpc
  if output_a_target < output_a_target_mpc:
    self.mpc.source = LongitudinalPlanSource.e2e
else:
  output_a_target = output_a_target_mpc
  self.output_should_stop = output_should_stop_mpc

(selfdrive/controls/lib/longitudinal_planner.py lines 160-170.) output_a_target_mpc, computed two lines above this excerpt in the same function via get_accel_from_plan, comes from a completely separate classical solver, LongitudinalMpc, which reacts to radarState's tracked lead car and cruise speed — not to the model at all.

Observe

Your capture: modelV2.action.desiredAcceleration = 0.306, longitudinalPlan.aTarget = 0.306 — identical, to three decimal places, not merely similar.

Explain

That equality isn't a coincidence and it isn't the model's value being copied through unconditionally either: it's min(output_a_target_e2e, output_a_target_mpc) landing on the first argument. The label longitudinalPlanSource = e2e doesn't mean "the plan is the model's opinion," it means "the model's suggestion was the more conservative of two independently computed candidates, this cycle" — the code sets that label only if output_a_target < output_a_target_mpc. There's a second, purely classical estimate, output_a_target_mpc, computed every cycle whether or not it ends up winning, and the system always takes whichever of the two asks for less acceleration. In this instant, since there was no lead car (radarState.leadOne.status = False) and cruise was still well above current speed (33.528 vs. 27.209 m/s), the classical solver had reason to accelerate harder toward the cruise target than the model did — so the model's more conservative number won and got labeled e2e. A different instant, with a lead car close ahead, would very plausibly flip which side wins, still under the exact same min(...) rule.

This is the same shape as Module 1's "the manager loop re-decides every iteration, not once at boot": here too, the safer-looking label (e2e, evoking a single learned model driving the car) turns out to name the outcome of a race between two independent estimates, computed every cycle, rather than a mode switch the system committed to once.

Diagram: the message chain

One instant, five messages

Boxes are processes, arrows are the one message flowing between them relevant to this instant. radard and plannerd are drawn as separate boxes because they are: radard doesn't plan anything, it only turns raw CAN radar returns into a tracked radarState, and plannerd is the one that reads both modelV2 and radarState to decide aTarget.

Quiz

  1. If the demo route had approached slow traffic (a real lead car close ahead), would you expect output_a_target_mpc to go up or down relative to what you measured, and what effect would that have on which source label longitudinalPlan reports?
  2. radarState.leadOne.status was False in your capture. Trace through the min(...) logic: does the absence of a lead car push the winning source toward e2e or away from it, and why?
  3. carControl.longActive was True in your capture even though carState.gasPressed was False. Module 4 covers exactly this signal in depth — for now, just from the message chain above, which upstream message would you check first to understand why longitudinal control was active at this instant?

→ Answer Key — Module 3

Answer Key — Module 3
  1. Slow traffic close ahead makes the classical solver brake or hold back, so output_a_target_mpc would go down — likely negative if a real braking response were needed. Whether the source label flips depends on which of the two is now smaller: if the MPC solver's braking response is more conservative than whatever the model itself is suggesting, the MPC side would win instead, and longitudinalPlanSource would no longer read e2e for that cycle.
  2. Away from e2e, not toward it, in a specific sense: with no lead car, the classical solver's job simplifies to "get to cruise speed," which especially below the cruise set point tends to ask for more acceleration, not less — exactly what you measured (cruise 33.528 m/s well above vEgo = 27.209 m/s). That makes the MPC side the more aggressive of the two, which is precisely why the more conservative model side won the min(...) and got labeled e2e here. A lead car appearing would give the MPC side a reason to be conservative too, making the outcome closer and harder to predict from cruise speed alone.
  3. selfdriveState, not longitudinalPlan. longActive is carControl's own field, set by controlsd from selfdriveState.active (whether the whole system is currently allowed to actuate) combined with longitudinalPlan's output — but whether the system is active at all is a decision selfdrived makes independently of any single plan, and that's exactly what Module 4 traces.

↑ Back to Quiz 3

→ Module 4: MADS State Machine