Ford: parse the PSCM LatCtl status broadcast + opt-in hands-on context for steerSaturated#155
Open
jrneulight wants to merge 2 commits into
Open
Ford: parse the PSCM LatCtl status broadcast + opt-in hands-on context for steerSaturated#155jrneulight wants to merge 2 commits into
jrneulight wants to merge 2 commits into
Conversation
This was referenced Jul 20, 2026
… carStateBP The PSCM broadcasts its lateral-control availability policy and hands-on estimate on Lane_Assist_Data3_FD1 at 33Hz on CAN platforms too, not just CANFD. Parse it (non-critical, seen-latched) and publish LaActAvail_D_Actl, LaActDeny_B_Actl, LaHandsOff_B_Actl and TjaHandsOnCnfdnc_B_Est under carStateBP.pscmLatCtl so every route carries the PSCM's own account of whether it is serving lateral control and whether it detects hands. Per the DBC VAL_ table LaActAvail_D_Actl is a feature matrix: bit1 = LCA/LKA centering available, bit0 = LDW not suppressed.
jrneulight
force-pushed
the
bp-7.0-pscm-status
branch
from
July 20, 2026 19:15
a19a2e3 to
61fa7c1
Compare
…dcast The param existed but was connected to nothing. Wire it conservatively: steerSaturated is hidden only while the EPS itself reports hands on the wheel (LaHandsOff_B_Actl == 0) -- the PSCM detects grip at ~0.5 Nm where steeringPressed needs ~1.0, and those sub-threshold resisting hands both cause the alert storms and prove the driver is already holding the wheel. If the EPS reports hands-off, the alert always shows. The toggle is exposed on both settings surfaces: the sunnylink source (settings_ui.json regenerated with the compiler) and the on-device vehicle settings (TICI and MICI layouts, directly under the pinion toggle). carStateBP joins selfdrived's SubMaster ignore lists: only brands whose carstate builds the message publish it (Ford today), so it must never gate all_checks()/commIssue on other cars. The key is registered in common/params_keys.h -- bluepilot/params/params.json is a separate registry that Params() does not consult, and reading an unregistered key raises UnknownKeyName (selfdrived crash-looped on device until this line existed).
jrneulight
force-pushed
the
bp-7.0-pscm-status
branch
from
July 20, 2026 19:19
61fa7c1 to
4f5ac1a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The evidence that motivated this
Lane_Assist_Data3_FD1(CAN 972, 33 Hz) on CAN platforms too — openpilot only parses the message on CANFD, and only for a signal that is dead on Q3 (LatCtlSte_D_Stat).00000027--97********,00000010--93********,00000001--be********,00000002--71********,00000003--a1********) found two live, load-bearing signals:LaActAvail_D_Actl— the PSCM declares lateral actuation unavailable below a single sharp ~40 km/h line: 130 of 153 observed 0↔2 transitions sit at 24.2–25.0 mph in both directions, avail=0 covers 100% of sub-threshold frames on every route, and it reads 0 even while disengaged with nothing on the wire (it is the PSCM's own speed policy, not a reaction to commands). This is the root cause of the long-observed Q3 low-speed authority derate: below the line the PSCM serves LatCtl commands in a degraded best-effort regime. Per the DBC VAL_ table this is a feature matrix — bit1 = LCA/LKA centering available, bit0 = LDW not suppressed; states 1/3 are the LDW-available variants seen while active lateral control isn't running.LaHandsOff_B_Actl— a graded hands-on detector ~2x more sensitive thansteeringPressed: it flags hands at 0.5–1.0 Nm column torque in 82–93% of frames wheresteeringPressedfires 2–9%.Why the fix is shaped this way
float('nan')frequency, theBCM_Lamp_Stat_FD1pattern) with a seen-latch, so a Ford that doesn't broadcast it can never break CAN validity anddataAvailablestays honest.considered and withdrawn: it trades alert timing for every driver to address a cause
specific to hands-on driving. This toggle addresses the cause directly and only for
drivers who opt in.
FordPrefHideSteerSaturatedAlertstoggle enabled, steerSaturated is hidden only while the EPS itself reports hands on the wheel; if the PSCM reports hands-off, the alert always shows. Default OFF — zero behavior change until opted in.carStateBPjoins selfdrived's SubMaster ignore lists: only brands whose carstate builds the message publish it (Ford today), so it must never gateall_checks()/commIssue on other cars.common/params_keys.h—bluepilot/params/params.jsonalone is not consulted byParams(), and reading an unregistered key raisesUnknownKeyName(found the hard way: selfdrived crash-looped on-device until this line existed).The evidence afterwards
Validation drive
0000002a--ce********(8 segments): live-parsed values vs an independent raw-CAN bit decode of 972 = 0.00% mismatch on both signals over 41,714 samples; live avail transitions at 24.6–24.9 mph, right on the 40 km/h line;carStateBPsteady at 100 Hz; zero process crashes.What each change is
cereal/custom.capnp:CarStateBP.pscmLatCtl(dataAvailable, laActAvail, laActDeny, laHandsOff, tjaHandsOnConfidence).opendbc/car/ford/carstate.py:Lane_Assist_Data3_FD1added to the non-CANFD parser list, non-critical.opendbc/sunnypilot/car/ford/carstate_ext.py: seen-latched populate of the new struct.selfdrive/selfdrived/selfdrived.py: SubMaster entry (ignore-listed) + the opt-in hands-on alert context.common/params_keys.h: registerFordPrefHideSteerSaturatedAlerts.settings_ui_src/pages/vehicle.yaml+ regeneratedsettings_ui.json(viatools/compile_settings_ui.py;--checkclean): the toggle.selfdrive/ui/bp/layouts/settings/bluepilot.py+mici/.../vehicle_mici.py: the same toggle on the on-device vehicle settings (both surfaces, directly under the pinion toggle).Test it yourself
carStateBP.pscmLatCtl.laActAvailflips 0↔2 crossing ~40 km/h; cross-check against raw CAN 972 (Motorola bits 5–4 of byte 0).Risks / limits
availconsumers should key on bit1 (values 0/1 = centering policy-suppressed); bit0 only reflects LDW suppression.