Three independent changes bundled together.
Revert hyundai canfd steering torque limits to comma stock defaults
(270 / 2 / 3 / 112) in both panda safety and openpilot CarControllerParams.
The 270->324 bump caused overcorrection on turns and weaving on straights.
Web research turned up no public reports of any 4th gen Tucson NX4 owner
bumping STEER_MAX — the documented Tucson tuning effort is entirely on
lateralTuning (latAccelFactor ~2.9-3.1, friction ~0.095), not the cap.
hoomoose's EV6/Ioniq 5 PR #25723 is the canonical "raise STEER_MAX
without dropping latAccelFactor causes overcorrection" data point — and
even that change was reverted upstream. Right next move for this car is
to tune latAccelFactor / friction, not the torque ceiling.
plannerd: keep publishing longitudinalPlan at the normal cadence in park,
but skip update() compute. Skipping publishes entirely caused
longitudinalPlan to time out the alive flag at controlsd, which fired a
real commIssue ("not_alive") on park->drive. Stale published values are
fine because controlsd's own park short-circuit ignores the
longitudinalPlan content while parked. Also gate publish_ui_plan on
not-parked: it reads longitudinal_planner.a_desired_trajectory_full
which is only set inside update(), so calling it without a prior update
crashes plannerd with AttributeError (which fires "Process Not Running"
on screen). uiPlan is UI-only, not on controlsd's commIssue check list,
so going silent in park is fine.
frogpilot_process: same idea — keep publishing frogpilotPlan in park to
keep alive, skip the heavy update() compute.
dashcamd: close the trip immediately on gear shift to PARK (was: 10-min
idle timer before close). User wants the dashcam idle in park and a
fresh trip on every drive engagement; brief drive-thru / fuel-stop
across-trip continuity isn't valued.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The park short-circuit added in cea422b created lac_log as
LateralDebugState. publish_logs assigns lac_log to
controlsState.lateralControlState.<subtype> based on
CP.lateralTuning.which() — for torque-tuned cars (Hyundai Tucson here)
that's torqueState, expecting LateralTorqueState. The mismatch threw
a capnp KjException ("Value type mismatch") on the first state_control
cycle in park, killing controlsd. Manager respawned it, it crashed
again on the next park cycle, repeat — controlsState was never reliably
published, so the UI never saw the started/onroad transition and didn't
flip to the camera view.
Fix: call self.LaC.update(False, ...) which internally early-returns
when active is False (cheap) but produces the correct lac_log subtype
for whichever controller this car uses (LateralTorqueState for torque,
LateralPIDState for pid, LateralAngleState for angle). Pass through
the same sm reads the regular path uses; they're cached so the cost is
negligible.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reference for the 270->324 change in commit 4058269. Covers what each
constant means, the two-files-must-stay-in-lockstep rule, the path to
push higher (324 -> 384, the community-consensus safe ceiling), risks
and symptoms to watch for at higher values, verification steps, and
rollback procedure.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tucson (and other Hyundai CAN-FD HDA2 cars) get pinned to comma's
conservative steer ceiling of 270 in the CAN-FD branch of
selfdrive/car/hyundai/values.py and the matching panda safety limit
HYUNDAI_CANFD_STEERING_LIMITS. Comma's non-CAN-FD HKG default is 384;
PR commaai/openpilot#25723 merged 384 for HDA1 EV6/Ioniq 5 with
operator quote "max steer needed to be 384 to make basic turns."
Bumping to 324 (~+20%) keeps a safe margin under the proven 384
ceiling while giving enough headroom for moderate clover-style on-ramps
without the controller hitting the limit. Rate limits also nudged up
(2->3 up, 3->5 down) to match the slightly higher ceiling and reduce
ramp time / release lag; chose 5 instead of comma's 7 for delta_down to
keep release smoother. max_rt_delta scaled proportionally (112->134) so
the 250ms real-time check tracks the new ceiling.
Both files MUST stay in lockstep — panda safety enforces independently
and would reject larger commands if only one side was bumped. Panda
firmware re-flashes automatically on next pandad start because the
safety code hash changed.
References:
https://github.com/commaai/openpilot/pull/25723 (HDA1 270->384)
https://github.com/commaai/openpilot/issues/24122 (HKG torque blacklist)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces clearpilot's working state wholesale with the modelrevert branch's
tree (modelrevert tip cea422b). Discards the parked-controlsd manager-process
split and the two session READMEs that documented it; keeps the simpler
in-process park short-circuits (controlsd state_control, plannerd, frogpilot_process)
and the cached-output decimation (modeld, dmonitoringmodeld) that achieve
the same goal with less moving parts. Also brings in the locationd GPS
ignore, the calibrationd valid=calStatus gate, and the model-revert lineage's
controlsd / paramsd / torqued / events.py / carstate.py / interfaces.py.
This is a single new commit on clearpilot (no merge), so the branch advances
linearly while the file state matches modelrevert exactly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four logically-related changes that together get the manager booting
cleanly end-to-end after the prior session's baseline revert + parked-mode
split, plus a session doc.
boardd: trigger safety_setter_thread on ignition rising edge, not on
IsOnroad rising edge. The parked-mode split broke the stock assumption
that ignition rising implies IsOnroad rising — IsOnroad now requires
`started`, which requires thermald to see carState != park, which
requires controlsd_parked to publish carState, which can't happen until
boardd acks OBD multiplexing. Triggering on ignition edge restores the
"set safety as soon as the bus is alive" intent for both controlsd
variants.
controlsd: drop the two `params_memory.put_bool("no_lat_lane_change",
...)` calls. The key was never registered in common/params.cc so
state_control crashed with UnknownKeyName on first cycle. The carcontroller
reads off `frogpilot_variables.no_lat_lane_change` (in-process), which
controlsd already sets; the UI reads `frogpilotCarControl.NoLatLaneChange`
from cereal, which nobody was setting in the restored controlsd. Add
`self.FPCC.noLatLaneChange = True/False` in the same lane-change branch
so the UI lane-edge indicator reflects state. No actuator change.
cereal/services.py: restore deviceState/managerState declarations to 2Hz
to match the restored DT_TRML=0.5 (thermald at 2Hz). Earlier fan-control
work bumped both to 5Hz; the realtime.py revert undid the thermald rate
bump but services.py wasn't reverted, so freq window [4.0, 6.0]Hz failed
on every cycle and controlsd fired commIssue continuously.
locationd: add a `clearpilot_disable_gps` const at the top of handle_gps
and OR it into the existing reject condition. With it true, every
gpsLocation message falls through to determine_gps_mode() — openpilot's
stock no-GPS path. last_gps_msg never updates, is_gps_ok() permanently
false. gpsd is untouched so UI / dashcamd / clock-set / night-mode auto-
switch keep working unchanged. The user's "drift right on straight roads"
symptom went away after this edit; the previous gpsd.py was hard-coding
vNED=[0,0,0] while the car was moving, feeding the Kalman contradictory
GPS-vs-IMU velocity observations that propagated into latcontrol_torque
through liveLocationKalman.angularVelocityCalibrated. Reversible by
flipping the const to false.
sessions/: a single README documenting this session. Includes the
calibrationd-still-stale investigation — liveCalibration.valid stuck at
False because of a Python SubMaster freq_ok issue with carState under
poll='cameraOdometry' (likely MSGQ NUM_READERS=12 eviction with too many
subscribers). 7ee923b already solved this exact failure mode by gating
calibrationd's publish on calStatus instead of sm.all_checks(); that
commit was reverted in 47321e3 as part of the variable-FPS rollback
but is unrelated to that family and is the natural next move.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Briefing for the on-device agent covering commits 47321e3, f7e602c,
and 887b9c9: what was reverted vs kept, the UI re-wire, the parked
controlsd swap mechanism, build prerequisites, runtime verification
commands, and a troubleshooting playbook.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a second controlsd variant that runs while ignition is on but the
car is in Park. It only listens to CAN and publishes carState — no
model, no planner, no lateral/long control, no actuator commands — so
modeld, locationd, calibrationd, plannerd, radard, paramsd, torqued,
dmonitoring*, soundd, loggerd all stay stopped while parked.
Manager swaps between the two via mutually-exclusive predicates:
- controlsd_parked: ignition AND not started
- controlsd (full): started (= ignition AND not_parked)
Thermald owns the swap. It already subscribes to carState; we add a
new onroad condition `not_parked` derived from gearShifter, with a
1.5s hysteresis on going into parked (R/P/D thrash protection) and
zero hysteresis on going out (instant wake on shift to D/R/N). At
boot we assume parked so the heavy stack waits for carState to
confirm gear has actually left Park.
Manager predicates can only see persistent Params, not pandaStates,
so thermald exposes ignition as a new IgnitionOn param (edge-written).
Reverse is treated as not-parked — driver is moving.
Files:
- selfdrive/controls/controlsd_parked.py (new, ~50 lines)
- selfdrive/thermald/thermald.py: not_parked condition + IgnitionOn
- selfdrive/manager/process_config.py: parked_only predicate + entry
- selfdrive/manager/manager.py: seed IgnitionOn=False
- common/params.cc: register IgnitionOn
The full controlsd is unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds back the UI plumbing that the baseline controlsd doesn't have, so
the existing UI features keep working without changing driving logic:
- ScreenDisplayMode 5-state machine (auto-normal, auto-nightrider,
manual normal, screen-off, manual nightrider) driven by the LFA
debug button + gear edges. Replaces baseline's simple 0..2 cycle.
Pure params write — no actuator effect.
- Speed/cruise-warning overlay tick at ~2Hz feeding SpeedState, which
writes ClearpilotSpeedDisplay / ClearpilotSpeedLimitDisplay /
ClearpilotCruiseWarning for the onroad UI. Reads gpsLocation,
CarSpeedLimit, and CS.cruiseState — no actuator effect.
- frogpilot_variables.no_lat_lane_change is now populated alongside
the existing Params write, so the perf-optimized carcontroller (which
takes the bit as an argument instead of re-reading Params on the
100Hz hot path) still sees the lane-change suppression signal.
- ScreenDisplayMode init switched from put_bool to put_int (UI reads
it as int).
- gpsLocation added to SubMaster (ignore_alive/avg_freq/valid set,
since gpsd is a ClearPilot addition not present everywhere).
No changes to controlsd's lateral or longitudinal control paths.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.