Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions openpilot/cereal/log.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,22 @@ struct ModelDataV2 {
desiredAcceleration @1 :Float32;
shouldStop @2 :Bool;
lateralActionTime @3 :Float32; # Seconds from the source vision frame to the lateral action target; zero means unavailable.
lateralSource @4 :LateralSource; # where desiredCurvature came from; unknown in older logs
delayInput @5 :DelayInput; # which model input carries the told lateral delay; unknown in older logs

enum LateralSource {
unknown @0;
plan @1; # read off the plan at lateralActionTime (floored at MIN_STABLE_DELAY)
actionHead @2; # the model's own action output
curvatureHead @3; # the model's desired_curvature output (non-tinygrad models)
}

enum DelayInput {
unknown @0;
none @1;
actionT @2;
lateralControlParams @3;
}
}

deprecated :group {
Expand Down
64 changes: 47 additions & 17 deletions openpilot/nrdr/docs/firmware_controller_profiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,41 @@ changing it requires offroad confirmation. PIF's Device Yaw Correction is separa
| Detected vehicle / EPS family | Calibration | Prediction delay |
| --- | --- | --- |
| HONDA_CLARITY / 39990-TRW-A020, modified EPS | Existing Clarity A020 | Measured speed schedule |
| HONDA_CIVIC_BOSCH / 39990-TBA-C020, modified EPS | Civic C020 TargetMapD / Tracker4500 / Norm1650 / P117to265 / D737 / KFF45 | Normal live/manual path |
| HONDA_CIVIC / 39990-TEG-A010, modified EPS | TEG-A010 corrected PTM build, command row 3 (provisional until driven on that build) | Normal live/manual path |
| HONDA_INSIGHT / 39990-TXM-A040, modified EPS | Insight TXM-A040 corrected PTM build (the Clarity's own command map and P table, 4096 E4 per unit, measured load, R6 from its A table) | Clarity's measured speed schedule |
| HONDA_CIVIC_BOSCH / 39990-TBA-C020, modified EPS | Civic C020 TargetMapD / Tracker4500 / Norm1650 / P117to265 / D737 / KFF45 | Its own speed schedule (provisional) |
| HONDA_CIVIC / 39990-TEG-A010, modified EPS | TEG-A010 corrected PTM build, command row 3 (driven on that build) | Its own measured schedule |
| HONDA_INSIGHT / 39990-TXM-A040, modified EPS | Insight TXM-A040 corrected PTM build (the Clarity's own command map and P table, 3840 E4 per unit, measured load, R6 from its A table) | Clarity's measured speed schedule |
| HONDA_CIVIC_BOSCH / 39990-TBA-C120, modified EPS | C120 corrected PTM starting calibration: rows 0-4 the Clarity's R5 per key (3840 E4 per unit, its image's key clamp 1663), R6 from its A table, the C020's load and trims | The C020's speed schedule |
| HONDA_CIVIC_BOSCH / 39990-TGG-A120, modified EPS | TGG-A120 corrected PTM starting calibration: row 0, built for 4096 E4 per unit but sent 3840 (its key clamp 1663), R6 from its A table (the C020's), the C020's load and trims | The C020's speed schedule |
| HONDA_CIVIC / 39990-TBA-A030, modified EPS | A030 corrected PTM starting calibration: the TEG-A010's row 3 on every row, R6 from its A table (the TEG's), the TEG's measured load | The TEG-A010's speed schedule |
| HONDA_CRV_5G / 39990-TLA-A040, modified EPS | CR-V A040 corrected PTM starting calibration: row 0, key clamp 1774, R6 from its A table, the owner's measured load, untrimmed | Normal live/manual path |
| HONDA_CRV_5G / 39990-TLA-A220, modified EPS | CR-V A220 corrected PTM starting calibration: rows 0-5 Clarity-equivalent, its own envelope, the A040's A table, R6, load and trims | Normal live/manual path |

PID CarParams and a matching firmware steer-ratio profile are also required. No
other Civic, firmware version, diesel, CR-V, or generic Honda inherits the fallback.
other Civic, firmware version, diesel, CR-V, or generic Honda inherits a calibration.
The five starting calibrations are provisional: their firmware fields are read from
each corrected image, while load, trims and command delay are carried from the
nearest measured car until the owner's drives measure them.

## Required corrected firmware

The Civic TEG-A010 calibration requires
`39990-TEG,A010-20261016b-PTMFix-ClarityEquivMap-ClarityPKnots-Row6Stock-A280FlatRows023`
(RWD SHA-256 starts `04147917`). It replaces the Bosch placeholder, but remains
provisional: it has not yet been road-validated on this corrected build.
(RWD SHA-256 starts `04147917`). It replaces the Bosch placeholder. It has been
driven on this corrected build (owner's route `0000013d`, 2026-10-17): the car runs
the corrected map (median R5 residual 35 counts over 104k frames, against 822 for the
earlier build's), the column load
holds out at R^2 0.810 (the same as a refit), and its telemetry R6 word agrees with the R6 computed from its Table A
(-156.16 at centre) within 0.8% on unrailed frames.

The Insight TXM-A040 calibration requires `39990-TXM,A040-PTM-20261016b`
(RWD SHA-256 starts `7ba37432`). Its source configuration has been driven on the
corrected build; that is not independent validation of this port.

The starting calibrations require, by RWD SHA-256 prefix: Civic Bosch TBA-C120
`9261b8db`, Civic TGG-A120 `6640806d`, Civic TBA-A030 `55c37266`, CR-V TLA-A040
`2e6a8802`, CR-V TLA-A220 `2c992997` (each `...-20261016b-PTMFix-ClarityEquivMap-...`).
The controller logs the required build at start and shows it in its description.

Older builds report the same EPS version strings as these corrected builds.
Family admission cannot verify the actual flashed image. Confirm the flashed
build separately before selecting Firmware Controller; do not pair these
Expand All @@ -37,16 +54,29 @@ The temporary fixed 0.30-second prediction override is removed. Clarity uses
0.15 / 0.08 / 0.10 / 0.20 / 0.30 seconds at 3.5 / 7 / 12 / 20 / 30 m/s,
interpolated every frame, with endpoints held. Both model runtimes and controlsd
use the same profile. Saved live/manual settings are preserved but unavailable
while that schedule is selected. Civic has no measured prediction schedule in the
source and therefore keeps live/manual delay normally, subject to Suggested locks.
while that schedule is selected. The Civics have their own schedules (2026-10-18):
TEG-A010 0.20 seconds at every speed, measured on its owner's drives, and C020 0.28 /
0.28 / 0.28 / 0.26 / 0.26 seconds, provisional (from a drive on an older controller).
Each is the car's lag from the camera frame to its yaw-sensor curvature, less modeld's
fixed 0.075 seconds. lagd told the TEG 0.37-0.39 seconds, which ran it early.
Model-specific smoothing remains separate, as in the source implementation.

Command delay is a separate interpolated curvature history buffer, not a blocking
sleep. It fades between 10 and 15 m/s. Clarity retains its saved endpoints, default
0.145 / 0.025 seconds. Civic (and the Insight) uses fixed 0.175 / 0.025 seconds (source 0.150 / 0.000
plus the existing port's 0.025-second model-action compensation); saved Clarity
command-delay settings do not retune Civic. These are model-dependent calibrations,
not a guarantee for every driving model.
sleep. It moves between its ends from 10 to 15 m/s. Clarity retains its saved endpoints,
default 0.145 / 0.125 seconds (the high end was 0.025 until the Clarity, on an action-head
model, measured 0.10-0.14 seconds early above 15 m/s without it). The Insight uses fixed 0.175 / 0.025 seconds and the Civics
0.175 seconds at every speed, since they ran as early on the highway as in town
(source 0.150 plus the existing port's 0.025-second model-action compensation); saved
Clarity command-delay settings do not retune them. These are model-dependent
calibrations, not a guarantee for every driving model.

They are what an action-head model needs. modeld now records where the steering came
from (`modelV2.action.lateralSource`: `plan`, `actionHead` or `curvatureHead`) and how
the told delay reached the model (`delayInput`). On a plan model (Pop v2, TCP v3) the
plan is read no earlier than `MIN_STABLE_DELAY` (0.3 s); with the schedule telling it
the car's own lag, the command delay becomes `max(0.3 - lateralActionTime, 0)`, which
undoes that floor and nothing else. The delay slews at 0.3 s per second when the
source changes.

## Calibration and unchanged behavior

Expand All @@ -58,13 +88,13 @@ newer angle-dependent R6 conversion and all existing core numerical behavior.
TEG-A010 now uses its corrected firmware's command row 3 and shared Clarity P
knots, with its own telemetry-derived column load and angle-dependent R6. It
retains the C020 base gains, P/I trims and Civic command delay. Its existing
3840-count transport and user-selected geometry are unchanged. It remains
provisional, especially at crawl speeds not covered by the source telemetry.
3840-count transport and user-selected geometry are unchanged. Crawl speeds
are still thinly covered by its owner's drives (few turns below 9 m/s).

Insight TXM-A040 uses the corrected firmware's Clarity command map and P table,
its own load and angle-dependent R6, the C020 base gains/P-I trims, Civic command
delay, and Clarity prediction schedule. Its 4096-count transport is accounted
for in the inversion; no transport or safety limit is increased.
delay, and Clarity prediction schedule. It is sent 3840 counts per unit, the
image's own command clamp (as the Clarity); no transport or safety limit is increased.

Shared steer-ratio selection, driver override, torque clipping, safety checks,
inactive reset/history behavior and single output LPF are preserved. Optimized
Expand Down
35 changes: 31 additions & 4 deletions openpilot/nrdr/features/lateral/controller_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
Firmware version strings identify the family, not the contents of a modified image.
The owner must still confirm the flashed build. TEG-A010 runs its own calibration for the corrected PTM
build (command row 3; rows 2 and 3 make the same command there), with R6 and load measured on one
car's telemetry. It stays provisional until it has been driven on that build, and it is never a
car's telemetry, and driven on that build (owner's route 0000013d, 2026-10-17). It is never a
generic Honda fallback. Insight TXM-A040 runs its corrected PTM build's calibration, which has been driven.
The corrected builds of the C120, TGG-A120, A030 and both CR-V images have provisional starting calibrations.
"""
from dataclasses import dataclass

Expand All @@ -19,21 +20,47 @@ class FirmwareControllerProfile:
calibration: str
prediction_schedule: bool = False
provisional: bool = False
# The corrected PTM build the calibration models (RWD SHA-256 prefix). Older builds report the same EPS version,
# so admission cannot check it; it is shown and logged so the owner can.
required_rwd: str = ""


CLARITY_PROFILE = FirmwareControllerProfile("Clarity A020", "clarity_a020", prediction_schedule=True)
CIVIC_PROFILE = FirmwareControllerProfile("Civic Bosch C020", "civic_bosch_c020")
CIVIC_PROFILE = FirmwareControllerProfile("Civic Bosch C020", "civic_bosch_c020", prediction_schedule=True)
TEG_PROFILE = FirmwareControllerProfile(
"Civic TEG-A010 corrected PTM, row 3 (not yet driven)", "civic_teg_a010", provisional=True,
"Civic TEG-A010 corrected PTM, row 3", "civic_teg_a010", prediction_schedule=True, required_rwd="04147917",
)
INSIGHT_PROFILE = FirmwareControllerProfile(
"Insight TXM-A040 corrected PTM", "insight_txm_a040", prediction_schedule=True,
"Insight TXM-A040 corrected PTM", "insight_txm_a040", prediction_schedule=True, required_rwd="7ba37432",
)
# Corrected-PTM (revision b) starting calibrations: firmware read from each image, the vehicle side carried from
# the nearest measured car until its owner's drives measure it. The Civics take that car's delay schedule too (the
# A030 the TEG's, the C120 and TGG the C020's); the CR-Vs keep live/manual delay until a CR-V drive is measured.
C120_PROFILE = FirmwareControllerProfile(
"Civic Bosch TBA-C120 corrected PTM (starting calibration)", "civic_tba_c120", prediction_schedule=True, provisional=True, required_rwd="9261b8db",
)
TGG_PROFILE = FirmwareControllerProfile(
"Civic TGG-A120 corrected PTM (starting calibration)", "civic_tgg_a120", prediction_schedule=True, provisional=True, required_rwd="6640806d",
)
A030_PROFILE = FirmwareControllerProfile(
"Civic TBA-A030 corrected PTM (starting calibration)", "civic_tba_a030", prediction_schedule=True, provisional=True, required_rwd="55c37266",
)
CRV_A040_PROFILE = FirmwareControllerProfile(
"CR-V TLA-A040 corrected PTM (starting calibration)", "crv_tla_a040", provisional=True, required_rwd="2e6a8802",
)
CRV_A220_PROFILE = FirmwareControllerProfile(
"CR-V TLA-A220 corrected PTM (starting calibration)", "crv_tla_a220", provisional=True, required_rwd="2c992997",
)
_PROFILES = {
("HONDA_CLARITY", "39990-TRW-A020"): CLARITY_PROFILE,
("HONDA_CIVIC_BOSCH", "39990-TBA-C020"): CIVIC_PROFILE,
("HONDA_CIVIC", "39990-TEG-A010"): TEG_PROFILE,
("HONDA_INSIGHT", "39990-TXM-A040"): INSIGHT_PROFILE,
("HONDA_CIVIC_BOSCH", "39990-TBA-C120"): C120_PROFILE,
("HONDA_CIVIC_BOSCH", "39990-TGG-A120"): TGG_PROFILE,
("HONDA_CIVIC", "39990-TBA-A030"): A030_PROFILE,
("HONDA_CRV_5G", "39990-TLA-A040"): CRV_A040_PROFILE,
("HONDA_CRV_5G", "39990-TLA-A220"): CRV_A220_PROFILE,
}


Expand Down
4 changes: 3 additions & 1 deletion openpilot/nrdr/features/lateral/honda_vgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ def physical_to_linear(self, angle_deg: float) -> float:
("39990-TBA-C120", "39990-TBA-A030", "39990-TEG-A010"), _CIVIC_C120_X, _CIVIC_C120_Y),
HondaVgrProfile("Civic C020/TGG-A120", ("HONDA_CIVIC_BOSCH",),
("39990-TBA-C020", "39990-TGG-A120"), _CIVIC_C020_X, _CIVIC_C020_Y),
HondaVgrProfile("CR-V TLA-A040", ("HONDA_CRV_5G",), ("39990-TLA-A040",), _TLA_A040_X, _TLA_A040_Y),
# The corrected TLA-A220 image carries the A040's Table A byte for byte (same offset, same values).
HondaVgrProfile("CR-V TLA-A040", ("HONDA_CRV_5G",), ("39990-TLA-A040", "39990-TLA-A220"), _TLA_A040_X, _TLA_A040_Y),
HondaVgrProfile("Insight TXM-A040", ("HONDA_INSIGHT",), ("39990-TXM-A040",), _TXM_A040_X, _TXM_A040_Y),
)

Expand All @@ -138,6 +139,7 @@ def physical_to_linear(self, angle_deg: float) -> float:
("HONDA_CIVIC_BOSCH", "39990-TBA-C020"): HONDA_VGR_PROFILES[2],
("HONDA_CIVIC_BOSCH", "39990-TGG-A120"): HONDA_VGR_PROFILES[2],
("HONDA_CRV_5G", "39990-TLA-A040"): HONDA_VGR_PROFILES[3],
("HONDA_CRV_5G", "39990-TLA-A220"): HONDA_VGR_PROFILES[3],
("HONDA_INSIGHT", "39990-TXM-A040"): HONDA_VGR_PROFILES[4],
}

Expand Down
Loading
Loading