Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a584a7e39 | |||
| 0dc8002c6d |
@@ -1,16 +1,11 @@
|
||||
#include "safety_hyundai_common.h"
|
||||
|
||||
const SteeringLimits HYUNDAI_CANFD_STEERING_LIMITS = {
|
||||
// CLEARPILOT: bumped from comma defaults (270/2/3/112) by ~20% so this Tucson HDA2
|
||||
// can hold modest curvature in place. Mirrors the rate-limit shape comma uses for
|
||||
// its non-CAN-FD high-torque HKG default (384/3/7). Must stay in lockstep with
|
||||
// STEER_MAX in selfdrive/car/hyundai/values.py — panda enforces independently and
|
||||
// will reject larger commands if openpilot's value exceeds this.
|
||||
.max_steer = 324,
|
||||
.max_rt_delta = 134,
|
||||
.max_steer = 270,
|
||||
.max_rt_delta = 112,
|
||||
.max_rt_interval = 250000,
|
||||
.max_rate_up = 3,
|
||||
.max_rate_down = 5,
|
||||
.max_rate_up = 2,
|
||||
.max_rate_down = 3,
|
||||
.driver_torque_allowance = 250,
|
||||
.driver_torque_factor = 2,
|
||||
.type = TorqueDriverLimited,
|
||||
|
||||
@@ -27,14 +27,12 @@ class CarControllerParams:
|
||||
self.STEER_STEP = 1 # 100 Hz
|
||||
|
||||
if CP.carFingerprint in CANFD_CAR:
|
||||
# CLEARPILOT: bumped from comma defaults (270/2/3) by ~20% — must stay in
|
||||
# lockstep with HYUNDAI_CANFD_STEERING_LIMITS in panda/board/safety/safety_hyundai_canfd.h.
|
||||
self.STEER_MAX = 324
|
||||
self.STEER_MAX = 270
|
||||
self.STEER_DRIVER_ALLOWANCE = 250
|
||||
self.STEER_DRIVER_MULTIPLIER = 2
|
||||
self.STEER_THRESHOLD = 250
|
||||
self.STEER_DELTA_UP = 3
|
||||
self.STEER_DELTA_DOWN = 5
|
||||
self.STEER_DELTA_UP = 2
|
||||
self.STEER_DELTA_DOWN = 3
|
||||
|
||||
# To determine the limit for your car, find the maximum value that the stock LKAS will request.
|
||||
# If the max stock LKAS request is <384, add your car to this list.
|
||||
|
||||
@@ -12,20 +12,20 @@
|
||||
* Trip lifecycle state machine:
|
||||
*
|
||||
* WAITING:
|
||||
* - Process starts in this state
|
||||
* - Process starts in this state. Idle.
|
||||
* - Waits for valid system time (year >= 2024) AND car in drive gear
|
||||
* - Transitions to RECORDING when both conditions met
|
||||
*
|
||||
* RECORDING:
|
||||
* - Actively encoding frames, car is in drive
|
||||
* - Car leaves drive → start 10-min idle timer → IDLE_TIMEOUT
|
||||
*
|
||||
* IDLE_TIMEOUT:
|
||||
* - Car left drive, still recording with timer running
|
||||
* - Car re-enters drive → cancel timer → RECORDING
|
||||
* - Timer expires → close trip → WAITING
|
||||
* - Gear shift into PARK → close trip immediately → WAITING (idle)
|
||||
* - Ignition off → close trip → WAITING
|
||||
*
|
||||
* IDLE_TIMEOUT (deprecated, retained for safety):
|
||||
* - Was used to keep recording across brief drive-thru / fuel stops.
|
||||
* - Now unreachable: drive→park transitions close the trip immediately
|
||||
* and a fresh trip starts on the next drive engagement.
|
||||
*
|
||||
* Graceful shutdown (DashcamShutdown param):
|
||||
* - thermald sets DashcamShutdown="1" before device power-off
|
||||
* - dashcamd closes current segment, acks, exits
|
||||
@@ -301,10 +301,11 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
case RECORDING:
|
||||
if (!in_drive) {
|
||||
idle_timer_start = now;
|
||||
state = IDLE_TIMEOUT;
|
||||
LOGW("dashcamd: car left drive, starting 10-min idle timer");
|
||||
// CLEARPILOT: close trip immediately on park (no idle timer). User wants
|
||||
// dashcam idle in park, fresh trip on each drive engagement.
|
||||
if (gear == cereal::CarState::GearShifter::PARK) {
|
||||
LOGW("dashcamd: gear in park, closing trip");
|
||||
close_trip();
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -34,13 +34,21 @@ def plannerd_thread():
|
||||
while True:
|
||||
sm.update()
|
||||
if sm.updated['modelV2']:
|
||||
# CLEARPILOT: skip planning while parked. The downstream consumer (controlsd)
|
||||
# already short-circuits in park, so longitudinalPlan/uiPlan staleness is fine.
|
||||
if sm['carState'].gearShifter == car.CarState.GearShifter.park:
|
||||
continue
|
||||
longitudinal_planner.update(sm)
|
||||
# CLEARPILOT: skip the planning compute while parked, but KEEP publishing
|
||||
# at the normal cadence so consumers' alive flags stay healthy. Skipping
|
||||
# publishes entirely caused longitudinalPlan to go alive=False at
|
||||
# controlsd, which fires a real commIssue the moment we shift out of park.
|
||||
# Stale published values are fine — controlsd's own park short-circuit
|
||||
# ignores the longitudinalPlan content while parked anyway.
|
||||
parked = sm['carState'].gearShifter == car.CarState.GearShifter.park
|
||||
if not parked:
|
||||
longitudinal_planner.update(sm)
|
||||
longitudinal_planner.publish(sm, pm)
|
||||
publish_ui_plan(sm, pm, longitudinal_planner)
|
||||
# publish_ui_plan reads longitudinal_planner.a_desired_trajectory_full
|
||||
# which is only set inside update(). Skip it while parked — uiPlan is
|
||||
# UI-only, not on controlsd's commIssue check list, so going silent is fine.
|
||||
if not parked:
|
||||
publish_ui_plan(sm, pm, longitudinal_planner)
|
||||
|
||||
def main():
|
||||
plannerd_thread()
|
||||
|
||||
@@ -85,11 +85,15 @@ def frogpilot_thread():
|
||||
frogpilot_planner = FrogPilotPlanner(CP)
|
||||
frogpilot_planner.update_frogpilot_params()
|
||||
|
||||
# CLEARPILOT: skip planner work while parked.
|
||||
# CLEARPILOT: skip planner compute while parked, but KEEP publishing at
|
||||
# the normal cadence so frogpilotPlan stays alive at consumers. Skipping
|
||||
# publishes entirely caused commIssue ("not_alive: frogpilotPlan") at
|
||||
# controlsd the moment we shifted out of park.
|
||||
parked = sm['carState'].gearShifter == car.CarState.GearShifter.park
|
||||
if sm.updated['modelV2'] and not parked:
|
||||
frogpilot_planner.update(sm['carState'], sm['controlsState'], sm['frogpilotCarControl'], sm['frogpilotNavigation'],
|
||||
sm['liveLocationKalman'], sm['modelV2'], sm['radarState'])
|
||||
if sm.updated['modelV2']:
|
||||
if not parked:
|
||||
frogpilot_planner.update(sm['carState'], sm['controlsState'], sm['frogpilotCarControl'], sm['frogpilotNavigation'],
|
||||
sm['liveLocationKalman'], sm['modelV2'], sm['radarState'])
|
||||
frogpilot_planner.publish(sm, pm)
|
||||
|
||||
if not time_validated:
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
# Session: 2026-04-26 — Hyundai CAN-FD steering torque bump
|
||||
|
||||
Documentation for commit `4058269` on `clearpilot`. Reference for any
|
||||
future re-tuning.
|
||||
|
||||
## What changed
|
||||
|
||||
Bumped this Tucson HDA2 (CAN-FD platform) from comma's conservative
|
||||
steer ceiling to a value that gives more headroom on tighter on-ramp
|
||||
clovers, plus a small rate-limit nudge so the controller can actually
|
||||
reach the new ceiling within reasonable transient time.
|
||||
|
||||
| Constant | Before (comma default for CAN-FD) | After (this commit) | Comma's non-CAN-FD HKG default |
|
||||
|---|---:|---:|---:|
|
||||
| `max_steer` / `STEER_MAX` | 270 | **324** | 384 |
|
||||
| `max_rate_up` / `STEER_DELTA_UP` | 2 | **3** | 3 |
|
||||
| `max_rate_down` / `STEER_DELTA_DOWN` | 3 | **5** | 7 |
|
||||
| `max_rt_delta` | 112 | **134** | ~150 |
|
||||
|
||||
## Where the change lives — TWO files in lockstep
|
||||
|
||||
The panda safety firmware enforces these limits **independently** of
|
||||
openpilot. If only one side is bumped, panda rejects the larger
|
||||
commands and you get cut-out / `commIssue` behavior. **Always change
|
||||
both, always to the same numbers, in the same commit.**
|
||||
|
||||
1. **`panda/board/safety/safety_hyundai_canfd.h`** (lines 3-19)
|
||||
- `HYUNDAI_CANFD_STEERING_LIMITS` struct: `max_steer`, `max_rate_up`,
|
||||
`max_rate_down`, `max_rt_delta`.
|
||||
- This is C; modifying it changes the panda firmware hash, which
|
||||
forces an automatic re-flash on next `pandad` start. No manual
|
||||
panda flash command needed.
|
||||
|
||||
2. **`selfdrive/car/hyundai/values.py`** (CAN-FD branch of
|
||||
`CarControllerParams.__init__`, lines 29-36)
|
||||
- `STEER_MAX`, `STEER_DELTA_UP`, `STEER_DELTA_DOWN`.
|
||||
- Pure Python; picked up on next `controlsd` start.
|
||||
|
||||
## What each constant does
|
||||
|
||||
- **`max_steer` / `STEER_MAX`** — peak torque magnitude the controller
|
||||
can request. Hard ceiling. Going past this is the headline "more
|
||||
torque" knob.
|
||||
- **`max_rate_up` / `STEER_DELTA_UP`** — per-100Hz-cycle upward slew
|
||||
cap. Higher = faster ramp into a turn. With `max_rate_up = 3` and
|
||||
`max_steer = 324`, time from 0 to ceiling is 324 / 3 = 108 cycles =
|
||||
1.08 s.
|
||||
- **`max_rate_down` / `STEER_DELTA_DOWN`** — per-cycle downward slew
|
||||
cap. Higher = faster release back toward straight. We chose 5 (vs
|
||||
comma's 7) for a smoother release feel.
|
||||
- **`max_rt_delta`** — cumulative torque change allowed across a
|
||||
rolling 250 ms window (`max_rt_interval`). It's a long-window
|
||||
envelope check, separate from the per-cycle rate. Should scale with
|
||||
`max_steer` — we used `max_steer × ~0.41` to mirror comma's ratio.
|
||||
- **`driver_torque_allowance` / `STEER_DRIVER_ALLOWANCE`** — driver
|
||||
wheel torque (Nm read off the wheel) that's tolerated before the
|
||||
system starts derating its own command. Left at 250.
|
||||
- **`driver_torque_factor` / `STEER_DRIVER_MULTIPLIER`** — how
|
||||
aggressively the system fights driver input above the allowance.
|
||||
Left at 2.
|
||||
|
||||
## How to go higher (path to 384)
|
||||
|
||||
`384` is the community-consensus safe ceiling for HKG. Comma uses it
|
||||
as the default for every non-CAN-FD HKG that isn't on the explicit
|
||||
255-blacklist, and they merged it for HDA1 CAN-FD (EV6 / Ioniq 5) in
|
||||
[openpilot PR #25723](https://github.com/commaai/openpilot/pull/25723).
|
||||
The PR author noted "max steer needed to be 384 to make basic turns."
|
||||
Tucson NX4 HDA2 is **not** on the 255-blacklist (see
|
||||
[issue #24122](https://github.com/commaai/openpilot/issues/24122) for
|
||||
the verified blacklist).
|
||||
|
||||
To go from 324 → 384:
|
||||
|
||||
```c
|
||||
// panda/board/safety/safety_hyundai_canfd.h
|
||||
.max_steer = 384,
|
||||
.max_rt_delta = 158, // ~max_steer × 0.41
|
||||
.max_rate_up = 3,
|
||||
.max_rate_down = 5, // or 7 for comma-matched aggressive release
|
||||
```
|
||||
|
||||
```python
|
||||
# selfdrive/car/hyundai/values.py CAN-FD branch
|
||||
self.STEER_MAX = 384
|
||||
self.STEER_DELTA_UP = 3
|
||||
self.STEER_DELTA_DOWN = 5 # or 7
|
||||
```
|
||||
|
||||
Beyond 384 is uncharted for HKG — comma has not tested past it. Some
|
||||
forks (sunnypilot has discussions) try higher for very heavy vehicles
|
||||
but with mixed results. Don't go past 384 without an explicit reason.
|
||||
|
||||
## Things to watch for / community-flagged risks at higher values
|
||||
|
||||
1. **EPS time-out cut every ~90 frames.** The CAN-FD safety already
|
||||
forces a brief torque cut to stop the EPS from faulting (the
|
||||
`min_valid_request_frames = 89`, `max_invalid_request_frames = 2`,
|
||||
`min_valid_request_rt_interval = 810000` block of
|
||||
`HYUNDAI_CANFD_STEERING_LIMITS`). This is independent of
|
||||
`max_steer`. Bumping the ceiling does not lengthen the cut-free
|
||||
window — you just hold the higher torque for the same ~890 ms before
|
||||
the brief cut. If you're getting `Steering Temporarily Unavailable`
|
||||
*during sustained turns*, the issue is this cut, not the ceiling,
|
||||
and it can't be tuned without risking a real EPS fault.
|
||||
|
||||
2. **`steerTempUnavailable` / "Cruise Fault: Restart the Car".** Has
|
||||
been reported on cars in the 255-blacklist when pushed to 384.
|
||||
Tucson NX4 is not blacklisted, so 324–384 is normally safe — but if
|
||||
you see this alert during slow sweeping turns, that's the symptom.
|
||||
Roll back to 270 and confirm.
|
||||
|
||||
3. **Lateral accel retune.** Higher torque headroom can cause the
|
||||
torque controller to overshoot if `latAccelFactor` was tuned for
|
||||
the old ceiling. EV6/Ioniq 5 testing in PR #25723 had to drop
|
||||
lateral accel to 2.5 m/s² when bumping from 270 to 384. Watch for
|
||||
over-correction (zig-zag in lane center) after a bump and retune
|
||||
`latAccelFactor` in `selfdrive/locationd/torqued.py` or via the
|
||||
torque-tune Params if needed.
|
||||
|
||||
4. **Driver-fight feel.** `driver_torque_allowance = 250` /
|
||||
`driver_torque_factor = 2` is the blending knob. Most "openpilot
|
||||
fights my hands" complaints come from people who lowered allowance
|
||||
or raised factor. Don't touch these without a specific reason.
|
||||
|
||||
5. **Panda safety hash mismatch.** Changing
|
||||
`safety_hyundai_canfd.h` regenerates the panda firmware binary with
|
||||
a different signed hash. On the next `pandad` start, pandad detects
|
||||
the mismatch and re-flashes the panda automatically (see
|
||||
`pandad.log`: "Panda firmware out of date" → "flash: flashing" →
|
||||
"Done flashing"). Takes ~10 s. No manual action needed; just expect
|
||||
a brief delay before controls come up.
|
||||
|
||||
## Verifying the change took effect
|
||||
|
||||
```bash
|
||||
# 1. Confirm the rebuild happened and panda firmware was re-signed.
|
||||
grep "panda/board/obj/panda_h7" /tmp/build_only.log 2>/dev/null # or run build_only.sh and watch for "signing N bytes"
|
||||
|
||||
# 2. Watch for re-flash on launch.
|
||||
tail -f /data/log2/current/pandad.log
|
||||
# Should see: "Panda firmware out of date, update required"
|
||||
# "flash: flashing"
|
||||
# "Done flashing"
|
||||
|
||||
# 3. Confirm the openpilot side is using the new value.
|
||||
su - comma -c 'PYTHONPATH=/data/openpilot python3 -c "
|
||||
from cereal import car
|
||||
from openpilot.common.params import Params
|
||||
cp_bytes = Params().get(\"CarParams\")
|
||||
with car.CarParams.from_bytes(cp_bytes) as cp:
|
||||
print(\"safetyConfig safetyParam:\", [c.safetyParam for c in cp.safetyConfigs])
|
||||
"'
|
||||
|
||||
# 4. Live-check the actual commanded torque ceiling (drive a moderate turn).
|
||||
# carControl.actuators.steer should now be able to peak above 0.79 (270/255 normalized)
|
||||
# but stay under 1.0 (full saturation at the new ceiling).
|
||||
```
|
||||
|
||||
## Rollback
|
||||
|
||||
If anything misbehaves, revert just the two-file commit:
|
||||
|
||||
```bash
|
||||
git revert 4058269
|
||||
chown -R comma:comma /data/openpilot
|
||||
su - comma -c "bash /data/openpilot/build_only.sh"
|
||||
# Next pandad launch will re-flash back to 270.
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
- [openpilot PR #25723 — HDA1 EV6/Ioniq 5 270 → 384](https://github.com/commaai/openpilot/pull/25723)
|
||||
- [openpilot issue #24122 — HKG torque blacklist verification](https://github.com/commaai/openpilot/issues/24122)
|
||||
- [openpilot PR #26427 — Hyundai Tucson 2023 support](https://github.com/commaai/openpilot/pull/26427)
|
||||
- [sunnypilot — increasing torque help](https://community.sunnypilot.ai/t/increasing-torque-help-needed/2082)
|
||||
- [sunnypilot — raising torque for heavier vehicles](https://community.sunnypilot.ai/t/raising-the-torque-for-heavier-vehicles/862)
|
||||
Reference in New Issue
Block a user