diff --git a/frogpilot/common/frogpilot_utilities.py b/frogpilot/common/frogpilot_utilities.py index 864219eb1..0bf9f6c80 100644 --- a/frogpilot/common/frogpilot_utilities.py +++ b/frogpilot/common/frogpilot_utilities.py @@ -19,7 +19,6 @@ from cereal import log from openpilot.common.realtime import DT_DMON, DT_HW from openpilot.selfdrive.car.toyota.carcontroller import LOCK_CMD from openpilot.system.hardware import HARDWARE -from openpilot.system.manager.process_config import managed_processes from panda import Panda from openpilot.frogpilot.common.frogpilot_variables import EARTH_RADIUS, KONIK_PATH, MAPD_PATH, MAPS_PATH, params, params_memory @@ -39,6 +38,10 @@ locks = { "update_openpilot": threading.Lock(), } +def get_managed_processes(): + from openpilot.system.manager.process_config import managed_processes + return managed_processes + def run_thread_with_lock(name, target, args=(), report=True): if not running_threads.get(name, threading.Thread()).is_alive(): with locks[name]: @@ -170,7 +173,7 @@ def restart_processes(sm): if not any(ps.ignitionLine or ps.ignitionCan for ps in sm["pandaStates"] if ps.pandaType != log.PandaState.PandaType.unknown): for name in ["mapd", "ui"]: - managed_processes[name].stop(block=False, retry=False) + get_managed_processes()[name].stop(block=False, retry=False) def run_cmd(cmd, success_message, fail_message, report=True): try: diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index 9256f463a..9135e14ad 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -1,9 +1,13 @@ #!/usr/bin/bash + if [ -z "$BASEDIR" ]; then BASEDIR="/data/openpilot" fi +# One-time setup flag (reset on each overlay install) +ONCE_FLAG_FILE="/data/openpilot/.one_time_setup_done" + source "$BASEDIR/launch_env.sh" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" @@ -31,6 +35,22 @@ function agnos_init { fi } +function one_time_setup { + if [ ! -f "$ONCE_FLAG_FILE" ]; then + echo "Performing one-time setup tasks..." + + # Run once: + echo "Wiping old params..." + rm /data/params/d/DongleId + rm /data/params/d/StockDongleId + echo "Old params wiped." + + touch "$ONCE_FLAG_FILE" + else + echo "One-time setup already completed. Skipping." + fi +} + function launch { # Remove orphaned git lock if it exists on boot [ -f "$DIR/.git/index.lock" ] && rm -f $DIR/.git/index.lock @@ -92,4 +112,6 @@ function launch { while true; do sleep 1; done } +one_time_setup + launch diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index a66f73595..ab780122b 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -22,8 +22,7 @@ TransmissionType = car.CarParams.TransmissionType # Camera cancels up to 0.1s after brake is pressed, ECM allows 0.5s CAMERA_CANCEL_DELAY_FRAMES = 10 # Enforce a minimum interval between steering messages to avoid a fault -MIN_STEER_MSG_INTERVAL_MS = 15 - +MIN_STEER_MSG_INTERVAL_MS = 10 # Constants for pitch compensation PITCH_DEADZONE = 0.01 # [radians] 0.01 ≈ 1% grade BRAKE_PITCH_FACTOR_BP = [5., 10.] # [m/s] smoothly revert to planned accel at low speeds @@ -45,6 +44,8 @@ class CarController(CarControllerBase): self.lka_steering_cmd_counter = 0 self.lka_icon_status_last = (False, False) + self.last_oem_prndl2_ts_nanos = 0 + self.last_oem_regen_paddle_ts_nanos = 0 self.params = CarControllerParams(self.CP) self.params_ = Params() @@ -76,11 +77,11 @@ class CarController(CarControllerBase): press_regen_paddle = self.regen_paddle_pressed - # Updated regen gain ratios from bin-averaged 60–0 deceleration sweep + # Regen gain ratios from bin-averaged 60–0 deceleration sweep; Calculates stronger decel from paddle speed_mps = [0.559, 1.678, 2.797, 3.916, 5.035, 6.154, 7.273, 8.392, 9.511, 10.63, 11.749, 12.868, 13.987, 15.106, 16.225, 17.344, 18.463, 19.582, 20.701, 21.820, 22.939, 24.058, 25.177, 26.296] - regen_gain_ratio = [1.289606, 1.227308, 1.200043, 1.274589, 1.332296, 1.345979, 1.369975, + regen_gain_ratio = [1.01, 1.01, 1.02, 1.05, 1.08, 1.345979, 1.369975, 1.376302, 1.388052, 1.370367, 1.388498, 1.386030, 1.405950, 1.387555, 1.390392, 1.394946, 1.414915, 1.428535, 1.439611, 1.440106, 1.441438, 1.439395, 1.446909, 1.445738] @@ -88,14 +89,12 @@ class CarController(CarControllerBase): gain = interp(car_velocity, speed_mps, regen_gain_ratio) pedaloffset = interp(car_velocity, [0., 3, 6, 30], [0.10, 0.175, 0.240, 0.240]) - accel_cutoff = -0.5 * gain if press_regen_paddle: - pedal_gas = pedaloffset + (accel / gain) * 0.6 - pedal_gas = max(pedal_gas, 0.01) + pedal_gas = clip((pedaloffset + (accel / gain) * 0.6), 0.0, 1.0) else: pedal_gas = clip((pedaloffset + accel * 0.6), 0.0, 1.0) - pedal_gas = min(pedal_gas, 1.0) + return pedal_gas, press_regen_paddle @@ -114,34 +113,17 @@ class CarController(CarControllerBase): # Send CAN commands. can_sends = [] - # Only send regen paddle and PRNDL2 commands at 40Hz when regen is active - regen_active = ( - self.CP.carFingerprint in CC_REGEN_PADDLE_CAR and - self.CP.openpilotLongitudinalControl and - CC.longActive and - self.regen_paddle_pressed - ) - # Time guard: PRNDL2 must be spaced out > 25ms (matches ~40Hz) - if regen_active: - current_time_ms = now_nanos * 1e-6 - last_sent_time_ms = getattr(self, "last_prndl2_sent_time_ms", -1000) - frames_since_last = self.frame - getattr(self, "last_prndl2_frame", -4) - frame_wait = 3 if getattr(self, "wait_long_40hz", False) else 2 - if (frames_since_last >= frame_wait) and (current_time_ms - last_sent_time_ms >= 25): - self.last_prndl2_frame = self.frame - self.last_prndl2_sent_time_ms = current_time_ms - self.wait_long_40hz = not getattr(self, "wait_long_40hz", False) + # Only apply PRNDL2 and regen paddle spoofing for cars in CC_REGEN_PADDLE_CAR and when gas interceptor is enabled + if self.CP.carFingerprint in CC_REGEN_PADDLE_CAR and self.CP.enableGasInterceptor: + steer_phase = self.last_steer_frame % 3 + send_prndl_frame = (self.frame % 3) != steer_phase - prndl2_value = 7 - regen_paddle_value = 2 - manual_mode = 1 - - can_sends.append(gmcan.create_prndl2_command( - self.packer_pt, CanBus.POWERTRAIN, prndl2_value, manual_mode - )) - can_sends.append(gmcan.create_regen_paddle_command(self.packer_pt, CanBus.POWERTRAIN, regen_paddle_value)) + press_regen_paddle = self.regen_paddle_pressed + if send_prndl_frame and CC.longActive: + can_sends.append(gmcan.create_prndl2_command(self.packer_pt, CanBus.POWERTRAIN, press_regen_paddle)) + can_sends.append(gmcan.create_regen_paddle_command(self.packer_pt, CanBus.POWERTRAIN, press_regen_paddle)) # Steering (Active: 50Hz, inactive: 10Hz) diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index 7108fefff..c89c75828 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -56,6 +56,10 @@ class CarState(CarStateBase): self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 if self.loopback_lka_steering_cmd_updated: self.loopback_lka_steering_cmd_ts_nanos = loopback_cp.ts_nanos["ASCMLKASteeringCmd"]["RollingCounter"] + + # Track timestamps for OEM PRNDL2 and Regen Paddle messages (used to sync spoofing timing) + self.prndl2_ts_nanos = pt_cp.ts_nanos["ECMPRDNL2"]["PRNDL2"] + self.regen_paddle_ts_nanos = pt_cp.ts_nanos["EBCMRegenPaddle"]["RegenPaddle"] if self.CP.networkLocation == NetworkLocation.fwdCamera and not self.CP.flags & GMFlags.NO_CAMERA.value: self.pt_lka_steering_cmd_counter = pt_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] self.cam_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] @@ -224,13 +228,13 @@ class CarState(CarStateBase): if CP.carFingerprint in SDGM_CAR: messages += [ - ("ECMPRDNL2", 25), + ("ECMPRDNL2", 40), ("AcceleratorPedal2", 40), ("ECMEngineStatus", 80), ] else: messages += [ - ("ECMPRDNL2", 25), + ("ECMPRDNL2", 40), ("AcceleratorPedal2", 33), ("ECMEngineStatus", 100), ("BCMTurnSignals", 1), @@ -252,7 +256,7 @@ class CarState(CarStateBase): if CP.transmissionType == TransmissionType.direct: messages += [ - ("EBCMRegenPaddle", 25), + ("EBCMRegenPaddle", 40), ("EVDriveMode", 0), ] diff --git a/selfdrive/car/gm/gmcan.py b/selfdrive/car/gm/gmcan.py index 9c9ae261b..3bbf2969b 100644 --- a/selfdrive/car/gm/gmcan.py +++ b/selfdrive/car/gm/gmcan.py @@ -177,19 +177,9 @@ def create_lka_icon_command(bus, active, critical, steer): dat = b"\x00\x00\x00" return make_can_msg(0x104c006c, dat, bus) -def create_regen_paddle_command(packer, bus, regen_paddle_value): - values = { - "RegenPaddle": regen_paddle_value, - "Byte1": 0, - "Byte2": 0, - "Byte3": 0, - "Byte4": 0, - "Byte5": 0, - "Byte6": 0 - } - return packer.make_can_msg("EBCMRegenPaddle", bus, values) - -def create_prndl2_command(packer, bus, prndl2_value, manual_mode): +def create_prndl2_command(packer, bus, press_regen_paddle): + prndl2_value = 7 if press_regen_paddle else 6 + manual_mode = 1 if press_regen_paddle else 0 values = { "Byte0": 0x0C, "Byte1": 0x0C, @@ -202,6 +192,19 @@ def create_prndl2_command(packer, bus, prndl2_value, manual_mode): } return packer.make_can_msg("ECMPRDNL2", bus, values) +def create_regen_paddle_command(packer, bus, press_regen_paddle): + regen_paddle_value = 2 if press_regen_paddle else 0 + values = { + "RegenPaddle": regen_paddle_value, + "Byte1": 0, + "Byte2": 0, + "Byte3": 0, + "Byte4": 0, + "Byte5": 0, + "Byte6": 0 + } + return packer.make_can_msg("EBCMRegenPaddle", bus, values) + def create_gm_cc_spam_command(packer, controller, CS, actuators): if controller.params_.get_bool("IsMetric"): _CV = CV.MS_TO_KPH diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index 6580bffbb..ae645fbb8 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -92,11 +92,10 @@ class LongControl: self.CP = CP self.long_control_state = LongCtrlState.off self.experimental_mode = False - pos_p_limit = 0.0 self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV), (CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV), k_f=CP.longitudinalTuning.kf, rate=1 / DT_CTRL, - pos_p_limit=pos_p_limit) + pos_p_limit=None) self.v_pid = 0.0 self._mode_setup() self.last_output_accel = 0.0 diff --git a/selfdrive/ui/_spinner b/selfdrive/ui/_spinner index 81d9288ff..84742598b 100755 Binary files a/selfdrive/ui/_spinner and b/selfdrive/ui/_spinner differ diff --git a/selfdrive/ui/_text b/selfdrive/ui/_text index b9e38b1dd..da081a8b4 100755 Binary files a/selfdrive/ui/_text and b/selfdrive/ui/_text differ diff --git a/selfdrive/ui/ui b/selfdrive/ui/ui index 743011eea..2dc332f3f 100755 Binary files a/selfdrive/ui/ui and b/selfdrive/ui/ui differ