revert hyundai canfd torque to stock; park-publish keepalive; dashcam idle on park
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>
This commit is contained in:
@@ -1,16 +1,11 @@
|
|||||||
#include "safety_hyundai_common.h"
|
#include "safety_hyundai_common.h"
|
||||||
|
|
||||||
const SteeringLimits HYUNDAI_CANFD_STEERING_LIMITS = {
|
const SteeringLimits HYUNDAI_CANFD_STEERING_LIMITS = {
|
||||||
// CLEARPILOT: bumped from comma defaults (270/2/3/112) by ~20% so this Tucson HDA2
|
.max_steer = 270,
|
||||||
// can hold modest curvature in place. Mirrors the rate-limit shape comma uses for
|
.max_rt_delta = 112,
|
||||||
// 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_rt_interval = 250000,
|
.max_rt_interval = 250000,
|
||||||
.max_rate_up = 3,
|
.max_rate_up = 2,
|
||||||
.max_rate_down = 5,
|
.max_rate_down = 3,
|
||||||
.driver_torque_allowance = 250,
|
.driver_torque_allowance = 250,
|
||||||
.driver_torque_factor = 2,
|
.driver_torque_factor = 2,
|
||||||
.type = TorqueDriverLimited,
|
.type = TorqueDriverLimited,
|
||||||
|
|||||||
@@ -27,14 +27,12 @@ class CarControllerParams:
|
|||||||
self.STEER_STEP = 1 # 100 Hz
|
self.STEER_STEP = 1 # 100 Hz
|
||||||
|
|
||||||
if CP.carFingerprint in CANFD_CAR:
|
if CP.carFingerprint in CANFD_CAR:
|
||||||
# CLEARPILOT: bumped from comma defaults (270/2/3) by ~20% — must stay in
|
self.STEER_MAX = 270
|
||||||
# lockstep with HYUNDAI_CANFD_STEERING_LIMITS in panda/board/safety/safety_hyundai_canfd.h.
|
|
||||||
self.STEER_MAX = 324
|
|
||||||
self.STEER_DRIVER_ALLOWANCE = 250
|
self.STEER_DRIVER_ALLOWANCE = 250
|
||||||
self.STEER_DRIVER_MULTIPLIER = 2
|
self.STEER_DRIVER_MULTIPLIER = 2
|
||||||
self.STEER_THRESHOLD = 250
|
self.STEER_THRESHOLD = 250
|
||||||
self.STEER_DELTA_UP = 3
|
self.STEER_DELTA_UP = 2
|
||||||
self.STEER_DELTA_DOWN = 5
|
self.STEER_DELTA_DOWN = 3
|
||||||
|
|
||||||
# To determine the limit for your car, find the maximum value that the stock LKAS will request.
|
# 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.
|
# If the max stock LKAS request is <384, add your car to this list.
|
||||||
|
|||||||
@@ -12,20 +12,20 @@
|
|||||||
* Trip lifecycle state machine:
|
* Trip lifecycle state machine:
|
||||||
*
|
*
|
||||||
* WAITING:
|
* WAITING:
|
||||||
* - Process starts in this state
|
* - Process starts in this state. Idle.
|
||||||
* - Waits for valid system time (year >= 2024) AND car in drive gear
|
* - Waits for valid system time (year >= 2024) AND car in drive gear
|
||||||
* - Transitions to RECORDING when both conditions met
|
* - Transitions to RECORDING when both conditions met
|
||||||
*
|
*
|
||||||
* RECORDING:
|
* RECORDING:
|
||||||
* - Actively encoding frames, car is in drive
|
* - Actively encoding frames, car is in drive
|
||||||
* - Car leaves drive → start 10-min idle timer → IDLE_TIMEOUT
|
* - Gear shift into PARK → close trip immediately → WAITING (idle)
|
||||||
*
|
|
||||||
* IDLE_TIMEOUT:
|
|
||||||
* - Car left drive, still recording with timer running
|
|
||||||
* - Car re-enters drive → cancel timer → RECORDING
|
|
||||||
* - Timer expires → close trip → WAITING
|
|
||||||
* - Ignition off → close trip → WAITING
|
* - 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):
|
* Graceful shutdown (DashcamShutdown param):
|
||||||
* - thermald sets DashcamShutdown="1" before device power-off
|
* - thermald sets DashcamShutdown="1" before device power-off
|
||||||
* - dashcamd closes current segment, acks, exits
|
* - dashcamd closes current segment, acks, exits
|
||||||
@@ -301,10 +301,11 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case RECORDING:
|
case RECORDING:
|
||||||
if (!in_drive) {
|
// CLEARPILOT: close trip immediately on park (no idle timer). User wants
|
||||||
idle_timer_start = now;
|
// dashcam idle in park, fresh trip on each drive engagement.
|
||||||
state = IDLE_TIMEOUT;
|
if (gear == cereal::CarState::GearShifter::PARK) {
|
||||||
LOGW("dashcamd: car left drive, starting 10-min idle timer");
|
LOGW("dashcamd: gear in park, closing trip");
|
||||||
|
close_trip();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -34,13 +34,21 @@ def plannerd_thread():
|
|||||||
while True:
|
while True:
|
||||||
sm.update()
|
sm.update()
|
||||||
if sm.updated['modelV2']:
|
if sm.updated['modelV2']:
|
||||||
# CLEARPILOT: skip planning while parked. The downstream consumer (controlsd)
|
# CLEARPILOT: skip the planning compute while parked, but KEEP publishing
|
||||||
# already short-circuits in park, so longitudinalPlan/uiPlan staleness is fine.
|
# at the normal cadence so consumers' alive flags stay healthy. Skipping
|
||||||
if sm['carState'].gearShifter == car.CarState.GearShifter.park:
|
# publishes entirely caused longitudinalPlan to go alive=False at
|
||||||
continue
|
# controlsd, which fires a real commIssue the moment we shift out of park.
|
||||||
longitudinal_planner.update(sm)
|
# 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)
|
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():
|
def main():
|
||||||
plannerd_thread()
|
plannerd_thread()
|
||||||
|
|||||||
@@ -85,11 +85,15 @@ def frogpilot_thread():
|
|||||||
frogpilot_planner = FrogPilotPlanner(CP)
|
frogpilot_planner = FrogPilotPlanner(CP)
|
||||||
frogpilot_planner.update_frogpilot_params()
|
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
|
parked = sm['carState'].gearShifter == car.CarState.GearShifter.park
|
||||||
if sm.updated['modelV2'] and not parked:
|
if sm.updated['modelV2']:
|
||||||
frogpilot_planner.update(sm['carState'], sm['controlsState'], sm['frogpilotCarControl'], sm['frogpilotNavigation'],
|
if not parked:
|
||||||
sm['liveLocationKalman'], sm['modelV2'], sm['radarState'])
|
frogpilot_planner.update(sm['carState'], sm['controlsState'], sm['frogpilotCarControl'], sm['frogpilotNavigation'],
|
||||||
|
sm['liveLocationKalman'], sm['modelV2'], sm['radarState'])
|
||||||
frogpilot_planner.publish(sm, pm)
|
frogpilot_planner.publish(sm, pm)
|
||||||
|
|
||||||
if not time_validated:
|
if not time_validated:
|
||||||
|
|||||||
Reference in New Issue
Block a user