mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-28 11:43:44 +08:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 890876c233 | |||
| 981cc7d30b | |||
| ccadc60b13 | |||
| a9defe7a3d | |||
| 8edaf3e2e3 | |||
| 43332bf3b3 | |||
| 5230a5264b | |||
| 50eec7fe22 | |||
| bcdd694154 | |||
| ee8028ebcd | |||
| 90e38339e7 | |||
| 1ad0de4e6d | |||
| dd58cc48ee | |||
| 13fbf4b90d | |||
| dfd6f30f2c |
@@ -1,4 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
import time
|
||||
|
||||
from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from openpilot.common.realtime import DT_MDL
|
||||
from openpilot.common.numpy_fast import interp
|
||||
@@ -32,6 +34,10 @@ class ConditionalExperimentalMode:
|
||||
LIGHT_BOOST_LOW = 1.15
|
||||
LIGHT_BOOST_HIGH = 1.2
|
||||
|
||||
# Small latch to avoid frame-to-frame mode chatter.
|
||||
CEM_TRANSITION_GUARD_TIME = 0.50
|
||||
CEM_TRANSITION_BUFFER_TIME = 0.25
|
||||
|
||||
@staticmethod
|
||||
def get_speed_based_param(speed_mph, param_array):
|
||||
"""Get parameter value based on current speed using smooth interpolation between breakpoints [0, 35, 55, 70]"""
|
||||
@@ -49,8 +55,12 @@ class ConditionalExperimentalMode:
|
||||
self.experimental_mode = False
|
||||
self.stop_light_detected = False
|
||||
self.prev_experimental_mode = False # For hysteresis
|
||||
self.mode_hold_until = 0.0
|
||||
self.mode_false_since = 0.0
|
||||
|
||||
def update(self, v_ego, sm, frogpilot_toggles):
|
||||
now = time.monotonic()
|
||||
|
||||
if frogpilot_toggles.experimental_mode_via_press:
|
||||
self.status_value = params_memory.get_int("CEStatus")
|
||||
else:
|
||||
@@ -58,28 +68,23 @@ class ConditionalExperimentalMode:
|
||||
|
||||
if self.status_value not in {1, 2} and not sm["carState"].standstill:
|
||||
self.update_conditions(v_ego, sm, frogpilot_toggles)
|
||||
new_experimental_mode = self.check_conditions(v_ego, sm, frogpilot_toggles)
|
||||
|
||||
# Add hysteresis to prevent rapid toggling
|
||||
if new_experimental_mode and not self.prev_experimental_mode:
|
||||
# Require weaker conditions to turn on
|
||||
hysteresis_factor = 0.9
|
||||
elif not new_experimental_mode and self.prev_experimental_mode:
|
||||
# Require stronger conditions to turn off
|
||||
hysteresis_factor = 1.2
|
||||
else:
|
||||
hysteresis_factor = 1.0
|
||||
triggered = self.check_conditions(v_ego, sm, frogpilot_toggles)
|
||||
if triggered:
|
||||
self.mode_hold_until = now + self.CEM_TRANSITION_GUARD_TIME
|
||||
self.mode_false_since = 0.0
|
||||
elif self.mode_false_since == 0.0:
|
||||
self.mode_false_since = now
|
||||
|
||||
# Apply hysteresis to key conditions
|
||||
if hasattr(self, 'slow_lead_detected'):
|
||||
self.slow_lead_detected = self.slow_lead_detected if hysteresis_factor == 1.0 else (self.slow_lead_filter.x >= scale_threshold(v_ego) * hysteresis_factor)
|
||||
if hasattr(self, 'curve_detected'):
|
||||
self.curve_detected = self.curve_detected if hysteresis_factor == 1.0 else (self.curvature_filter.x >= THRESHOLD * hysteresis_factor)
|
||||
hold_active = now < self.mode_hold_until
|
||||
transition_buffer_active = self.mode_false_since != 0.0 and (now - self.mode_false_since) < self.CEM_TRANSITION_BUFFER_TIME
|
||||
|
||||
self.experimental_mode = self.check_conditions(v_ego, sm, frogpilot_toggles)
|
||||
self.experimental_mode = triggered or hold_active or transition_buffer_active
|
||||
self.prev_experimental_mode = self.experimental_mode
|
||||
params_memory.put_int("CEStatus", self.status_value if self.experimental_mode else 0)
|
||||
else:
|
||||
self.mode_hold_until = 0.0
|
||||
self.mode_false_since = 0.0
|
||||
self.experimental_mode = self.status_value == 2 or sm["carState"].standstill and self.experimental_mode and self.frogpilot_planner.model_stopped
|
||||
self.stop_light_detected &= self.status_value not in {1, 2}
|
||||
self.stop_light_filter.x = 0
|
||||
|
||||
@@ -190,6 +190,8 @@ class ModelState:
|
||||
# Add policy_generation attribute after loading policy_metadata
|
||||
self.policy_generation = model_version or "v8"
|
||||
self.is_v11 = (self.policy_generation == "v11")
|
||||
self.is_v10 = (self.policy_generation == "v10")
|
||||
self.is_v12 = (self.policy_generation == "v12")
|
||||
self.is_v9 = (self.policy_generation == "v9")
|
||||
self.mlsim = (self.policy_generation in ("v8", "v10", "v11", "v12"))
|
||||
|
||||
@@ -328,14 +330,14 @@ class ModelState:
|
||||
self.full_prev_desired_curv[0,-1,:] = policy_outputs_dict['desired_curvature'][0, :]
|
||||
|
||||
if self.prev_desired_curv_key is not None:
|
||||
# v9 models expect zeros for prev_desired_curv(s); others use history
|
||||
if self.is_v9:
|
||||
# v9/v10/v11/v12 models expect zeros for prev_desired_curv(s); others use history
|
||||
if self.is_v9 or self.is_v10 or self.is_v11 or self.is_v12:
|
||||
self.numpy_inputs[self.prev_desired_curv_key][:] = 0 * self.full_prev_desired_curv[0, self.temporal_idxs]
|
||||
else:
|
||||
self.numpy_inputs[self.prev_desired_curv_key][:] = self.full_prev_desired_curv[0, self.temporal_idxs]
|
||||
|
||||
if self.off_policy_enabled and self.off_policy_prev_desired_curv_key is not None:
|
||||
if self.is_v9:
|
||||
if self.is_v9 or self.is_v12:
|
||||
self.off_policy_numpy_inputs[self.off_policy_prev_desired_curv_key][:] = 0 * self.full_prev_desired_curv[0, self.temporal_idxs]
|
||||
else:
|
||||
self.off_policy_numpy_inputs[self.off_policy_prev_desired_curv_key][:] = self.full_prev_desired_curv[0, self.temporal_idxs]
|
||||
|
||||
+118
-16
@@ -48,16 +48,16 @@ const CanMsg GM_ASCM_TX_MSGS[] = {{0x180, 0, 4}, {0x409, 0, 7}, {0x40A, 0, 7}, {
|
||||
{0xA1, 1, 7}, {0x306, 1, 8}, {0x308, 1, 7}, {0x310, 1, 2}, // obs bus
|
||||
{0x315, 2, 5}}; // ch bus
|
||||
|
||||
const CanMsg GM_CAM_TX_MSGS[] = {{0x180, 0, 4}, {0x200, 0, 6}, {0x1E1, 0, 7}, {0xBD, 0, 7}, {0x1F5, 0, 8}, // pt bus
|
||||
const CanMsg GM_CAM_TX_MSGS[] = {{0x180, 0, 4}, {0x370, 0, 6}, {0x200, 0, 6}, {0x1E1, 0, 7}, {0x3D1, 0, 8}, {0xBD, 0, 7}, {0x1F5, 0, 8}, // pt bus
|
||||
{0x1E1, 2, 7}, {0x184, 2, 8}}; // camera bus
|
||||
|
||||
const CanMsg GM_CAM_LONG_TX_MSGS[] = {{0x180, 0, 4}, {0x315, 0, 5}, {0x2CB, 0, 8}, {0x370, 0, 6}, {0x200, 0, 6}, {0xBD, 0, 7}, {0x1F5, 0, 8}, // pt bus
|
||||
const CanMsg GM_CAM_LONG_TX_MSGS[] = {{0x180, 0, 4}, {0x315, 0, 5}, {0x2CB, 0, 8}, {0x370, 0, 6}, {0x200, 0, 6}, {0x3D1, 0, 8}, {0xBD, 0, 7}, {0x1F5, 0, 8}, // pt bus
|
||||
{0x315, 2, 5}, {0x1E1, 2, 7}, {0x184, 2, 8}}; // camera bus
|
||||
|
||||
const CanMsg GM_SDGM_TX_MSGS[] = {{0x180, 0, 4}, {0x1E1, 0, 7}, {0xBD, 0, 7}, {0x1F5, 0, 8}, // pt bus
|
||||
{0x184, 2, 8}}; // camera bus
|
||||
|
||||
const CanMsg GM_CC_LONG_TX_MSGS[] = {{0x180, 0, 4}, {0x1E1, 0, 7}, {0xBD, 0, 7}, {0x1F5, 0, 8}, // pt bus
|
||||
const CanMsg GM_CC_LONG_TX_MSGS[] = {{0x180, 0, 4}, {0x370, 0, 6}, {0x1E1, 0, 7}, {0x3D1, 0, 8}, {0xBD, 0, 7}, {0x1F5, 0, 8}, // pt bus
|
||||
{0x184, 2, 8}, {0x1E1, 2, 7}}; // camera bus
|
||||
|
||||
// TODO: do checksum and counter checks. Add correct timestep, 0.1s for now.
|
||||
@@ -86,6 +86,14 @@ const uint16_t GM_PARAM_HW_SDGM = 1024;
|
||||
const uint16_t GM_PARAM_BOLT_2017 = 2048;
|
||||
const uint16_t GM_PARAM_BOLT_2022_PEDAL = 4096;
|
||||
const uint16_t GM_PARAM_REMOTE_START_BOOTS_COMMA = 8192;
|
||||
const uint16_t GM_PARAM_PANDA_3D1_SCHED = 16384;
|
||||
|
||||
const uint32_t GM_3D1_PERIOD_US = 100000U;
|
||||
const uint32_t GM_3D1_TX_OFFSET_US = 0U;
|
||||
const uint32_t GM_3D1_LOCK_TOLERANCE_US = 20000U;
|
||||
|
||||
void can_send(CANPacket_t *to_push, uint8_t bus_number, bool skip_tx_hook);
|
||||
void can_set_checksum(CANPacket_t *packet);
|
||||
|
||||
enum {
|
||||
GM_BTN_UNPRESS = 1,
|
||||
@@ -111,6 +119,41 @@ bool gm_bolt_2022_pedal = false;
|
||||
bool gm_ascm_int = false;
|
||||
bool gm_force_brake_c9 = false;
|
||||
bool gm_remote_start_boots_comma = false;
|
||||
bool gm_panda_3d1_sched = false;
|
||||
|
||||
bool gm_3d1_spoof_valid = false;
|
||||
bool gm_3d1_internal_tx = false;
|
||||
uint8_t gm_3d1_spoof_data[8] = {0U};
|
||||
uint32_t gm_3d1_next_tx_us = 0U;
|
||||
uint32_t gm_3d1_expected_stock_us = 0U;
|
||||
uint32_t gm_3d1_last_stock_us = 0U;
|
||||
bool gm_3d1_phase_locked = false;
|
||||
|
||||
static void gm_try_send_3d1_spoof(uint32_t now_us) {
|
||||
if (!(gm_panda_3d1_sched && gm_3d1_spoof_valid && (gm_3d1_next_tx_us != 0U))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int32_t)(now_us - gm_3d1_next_tx_us) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
CANPacket_t to_send = {0};
|
||||
to_send.returned = 0U;
|
||||
to_send.rejected = 0U;
|
||||
to_send.extended = 0U;
|
||||
to_send.addr = 0x3D1U;
|
||||
to_send.bus = 0U;
|
||||
to_send.data_len_code = 8U;
|
||||
(void)memcpy(to_send.data, gm_3d1_spoof_data, 8U);
|
||||
can_set_checksum(&to_send);
|
||||
|
||||
gm_3d1_internal_tx = true;
|
||||
can_send(&to_send, 0U, false);
|
||||
gm_3d1_internal_tx = false;
|
||||
|
||||
gm_3d1_next_tx_us += GM_3D1_PERIOD_US;
|
||||
}
|
||||
|
||||
static void gm_rx_hook(const CANPacket_t *to_push) {
|
||||
if (GET_BUS(to_push) == 0U) {
|
||||
@@ -183,12 +226,35 @@ static void gm_rx_hook(const CANPacket_t *to_push) {
|
||||
|
||||
// Cruise check for CC only cars
|
||||
if ((addr == 0x3D1) && !gm_has_acc) {
|
||||
uint32_t now_us = microsecond_timer_get();
|
||||
gm_3d1_last_stock_us = now_us;
|
||||
bool cruise_engaged = (GET_BYTE(to_push, 4) >> 7) != 0U;
|
||||
if (gm_cc_long) {
|
||||
pcm_cruise_check(cruise_engaged);
|
||||
} else {
|
||||
cruise_engaged_prev = cruise_engaged;
|
||||
}
|
||||
|
||||
if (gm_panda_3d1_sched) {
|
||||
if (!gm_3d1_phase_locked) {
|
||||
gm_3d1_phase_locked = true;
|
||||
gm_3d1_expected_stock_us = now_us + GM_3D1_PERIOD_US;
|
||||
} else {
|
||||
int32_t phase_err_us = (int32_t)(now_us - gm_3d1_expected_stock_us);
|
||||
if (phase_err_us < 0) {
|
||||
phase_err_us = -phase_err_us;
|
||||
}
|
||||
|
||||
if ((uint32_t)phase_err_us <= GM_3D1_LOCK_TOLERANCE_US) {
|
||||
gm_3d1_expected_stock_us += GM_3D1_PERIOD_US;
|
||||
} else {
|
||||
gm_3d1_expected_stock_us = now_us + GM_3D1_PERIOD_US;
|
||||
}
|
||||
}
|
||||
|
||||
gm_3d1_next_tx_us = now_us + GM_3D1_TX_OFFSET_US;
|
||||
gm_try_send_3d1_spoof(now_us);
|
||||
}
|
||||
}
|
||||
|
||||
if (addr == 0xBD) {
|
||||
@@ -291,6 +357,28 @@ static bool gm_tx_hook(const CANPacket_t *to_send) {
|
||||
}
|
||||
}
|
||||
|
||||
// Cruise status spoofing only for non-ACC (CC-only) paths
|
||||
if (addr == 0x3D1) {
|
||||
bool allowed_cruise_status = !gm_has_acc;
|
||||
if (!allowed_cruise_status) {
|
||||
tx = false;
|
||||
} else if (gm_panda_3d1_sched) {
|
||||
if (gm_3d1_internal_tx) {
|
||||
tx = true;
|
||||
} else {
|
||||
uint32_t now_us = microsecond_timer_get();
|
||||
(void)memcpy(gm_3d1_spoof_data, to_send->data, 8U);
|
||||
gm_3d1_spoof_valid = true;
|
||||
if (gm_3d1_next_tx_us == 0U) {
|
||||
gm_3d1_next_tx_us = now_us + GM_3D1_TX_OFFSET_US;
|
||||
}
|
||||
bool stock_stale = (gm_3d1_last_stock_us == 0U) || (get_ts_elapsed(now_us, gm_3d1_last_stock_us) > 300000U);
|
||||
bool scheduler_ready = gm_3d1_phase_locked && !stock_stale;
|
||||
tx = !scheduler_ready;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// REGEN PADDLE
|
||||
if (addr == 0xBD) {
|
||||
bool regen_apply = GET_BIT(to_send, 7) || GET_BIT(to_send, 6) || GET_BIT(to_send, 5) || GET_BIT(to_send, 4);
|
||||
@@ -317,26 +405,32 @@ static int gm_fwd_hook(int bus_num, int addr) {
|
||||
if (bus_num == 0) {
|
||||
// block PSCMStatus; forwarded through openpilot to hide an alert from the camera
|
||||
bool is_pscm_msg = (addr == 0x184);
|
||||
if (!is_pscm_msg) {
|
||||
// For non-ACC camera/SDGM paths, keep stock ECMCruiseControl off camera side
|
||||
// so openpilot's spoofed 0x3D1 is the only cruise-status source there.
|
||||
bool is_ecm_cruise_status_msg = (addr == 0x3D1) && !gm_has_acc;
|
||||
if (!is_pscm_msg && !is_ecm_cruise_status_msg) {
|
||||
bus_fwd = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (bus_num == 2) {
|
||||
bool is_lkas_msg = (addr == 0x180);
|
||||
bool block_msg = false;
|
||||
if (gm_bolt_2022_pedal) {
|
||||
// Block 0x370 only for experimental long without pedal interceptor
|
||||
bool is_acc_msg = (addr == 0x315) || (addr == 0x2CB);
|
||||
if (gm_cam_long && !enable_gas_interceptor) {
|
||||
is_acc_msg = is_acc_msg || (addr == 0x370);
|
||||
}
|
||||
block_msg = is_lkas_msg || (is_acc_msg && gm_cam_long);
|
||||
} else {
|
||||
// block lkas message and acc messages if gm_cam_long, forward all others
|
||||
bool is_acc_msg = (addr == 0x315) || (addr == 0x2CB) || (addr == 0x370);
|
||||
block_msg = is_lkas_msg || (is_acc_msg && gm_cam_long);
|
||||
bool is_acc_status_msg = (addr == 0x370);
|
||||
bool is_acc_actuation_msg = (addr == 0x315) || (addr == 0x2CB);
|
||||
|
||||
// Block steering if we are controlling LKA
|
||||
bool block_msg = is_lkas_msg;
|
||||
|
||||
// Block Dashboard Status if we are in Native Long OR Pedal Long
|
||||
if (gm_cam_long || gm_pedal_long) {
|
||||
block_msg |= is_acc_status_msg;
|
||||
}
|
||||
|
||||
// Block Native Actuation ONLY if we are in Native Long (not Pedal)
|
||||
if (gm_cam_long) {
|
||||
block_msg |= is_acc_actuation_msg;
|
||||
}
|
||||
|
||||
if (!block_msg) {
|
||||
bus_fwd = 0;
|
||||
}
|
||||
@@ -376,6 +470,14 @@ static safety_config gm_init(uint16_t param) {
|
||||
gm_has_acc = !GET_FLAG(param, GM_PARAM_NO_ACC);
|
||||
gm_force_brake_c9 = GET_FLAG(param, GM_PARAM_FORCE_BRAKE_C9);
|
||||
gm_remote_start_boots_comma = GET_FLAG(param, GM_PARAM_REMOTE_START_BOOTS_COMMA);
|
||||
gm_panda_3d1_sched = GET_FLAG(param, GM_PARAM_PANDA_3D1_SCHED) && gm_pedal_long && !gm_has_acc && !gm_bolt_2022_pedal;
|
||||
|
||||
gm_3d1_spoof_valid = false;
|
||||
gm_3d1_internal_tx = false;
|
||||
gm_3d1_next_tx_us = 0U;
|
||||
gm_3d1_expected_stock_us = 0U;
|
||||
gm_3d1_last_stock_us = 0U;
|
||||
gm_3d1_phase_locked = false;
|
||||
|
||||
safety_config ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_ASCM_TX_MSGS);
|
||||
if (gm_hw == GM_CAM) {
|
||||
|
||||
@@ -243,6 +243,7 @@ class Panda:
|
||||
FLAG_GM_BOLT_2017 = 2048
|
||||
FLAG_GM_BOLT_2022_PEDAL = 4096
|
||||
FLAG_GM_REMOTE_START_BOOTS_COMMA = 8192
|
||||
FLAG_GM_PANDA_3D1_SCHED = 16384
|
||||
|
||||
FLAG_FORD_LONG_CONTROL = 1
|
||||
FLAG_FORD_CANFD = 2
|
||||
|
||||
@@ -386,7 +386,7 @@ class TestGmInterceptorSafety(common.GasInterceptorSafetyTest, TestGmCameraSafet
|
||||
|
||||
|
||||
class TestGmCcLongitudinalSafety(TestGmCameraSafety):
|
||||
TX_MSGS = [[384, 0], [481, 0], [0x1F5, 0], [388, 2]]
|
||||
TX_MSGS = [[384, 0], [481, 0], [0x3D1, 0], [0x1F5, 0], [388, 2]]
|
||||
FWD_BLACKLISTED_ADDRS = {2: [384], 0: [388]} # block LKAS message and PSCMStatus
|
||||
BUTTONS_BUS = 0 # tx only
|
||||
|
||||
|
||||
@@ -70,8 +70,9 @@ interface_names = _get_interface_names()
|
||||
interfaces = load_interfaces(interface_names)
|
||||
|
||||
|
||||
def can_fingerprint(next_can: Callable) -> tuple[str | None, dict[int, dict]]:
|
||||
def can_fingerprint(next_can: Callable) -> tuple[str | None, dict[int, dict], dict[int, set[int]]]:
|
||||
finger = gen_empty_fingerprint()
|
||||
nonzero_addrs = {bus: set() for bus in finger}
|
||||
candidate_cars = {i: all_legacy_fingerprint_cars() for i in [0, 1]} # attempt fingerprint on both bus 0 and 1
|
||||
frame = 0
|
||||
car_fingerprint = None
|
||||
@@ -86,7 +87,10 @@ def can_fingerprint(next_can: Callable) -> tuple[str | None, dict[int, dict]]:
|
||||
if can.src < 128:
|
||||
if can.src not in finger:
|
||||
finger[can.src] = {}
|
||||
nonzero_addrs[can.src] = set()
|
||||
finger[can.src][can.address] = len(can.dat)
|
||||
if any(can.dat):
|
||||
nonzero_addrs[can.src].add(can.address)
|
||||
|
||||
for b in candidate_cars:
|
||||
# Ignore extended messages and VIN query response.
|
||||
@@ -107,7 +111,7 @@ def can_fingerprint(next_can: Callable) -> tuple[str | None, dict[int, dict]]:
|
||||
|
||||
frame += 1
|
||||
|
||||
return car_fingerprint, finger
|
||||
return car_fingerprint, finger, nonzero_addrs
|
||||
|
||||
|
||||
# **** for use live only ****
|
||||
@@ -164,7 +168,7 @@ def fingerprint(logcan, sendcan, num_pandas):
|
||||
# CAN fingerprint
|
||||
# drain CAN socket so we get the latest messages
|
||||
messaging.drain_sock_raw(logcan)
|
||||
car_fingerprint, finger = can_fingerprint(lambda: get_one_can(logcan))
|
||||
car_fingerprint, finger, nonzero_addrs = can_fingerprint(lambda: get_one_can(logcan))
|
||||
|
||||
exact_match = True
|
||||
source = car.CarParams.FingerprintSource.can
|
||||
@@ -183,7 +187,7 @@ def fingerprint(logcan, sendcan, num_pandas):
|
||||
fw_count=len(car_fw), ecu_responses=list(ecu_rx_addrs), vin_rx_addr=vin_rx_addr, vin_rx_bus=vin_rx_bus,
|
||||
fingerprints=repr(finger), fw_query_time=fw_query_time, error=True)
|
||||
|
||||
return car_fingerprint, finger, vin, car_fw, source, exact_match
|
||||
return car_fingerprint, finger, nonzero_addrs, vin, car_fw, source, exact_match
|
||||
|
||||
|
||||
def get_car_interface(CP, FPCP):
|
||||
@@ -250,7 +254,7 @@ def migrate_legacy_bolt_candidate(candidate: str) -> str:
|
||||
|
||||
|
||||
def get_car(logcan, sendcan, experimental_long_allowed, params, num_pandas=1, frogpilot_toggles=None):
|
||||
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan, num_pandas)
|
||||
candidate, fingerprints, nonzero_addrs, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan, num_pandas)
|
||||
|
||||
if candidate is None or frogpilot_toggles.force_fingerprint:
|
||||
if frogpilot_toggles.car_model is not None:
|
||||
@@ -299,12 +303,12 @@ def get_car(logcan, sendcan, experimental_long_allowed, params, num_pandas=1, fr
|
||||
if year_code in year_map:
|
||||
vin_candidate = year_map[year_code]
|
||||
if vin_candidate == GM_CAR.CHEVROLET_BOLT_ACC_2022_2023:
|
||||
has_acc_msg = (
|
||||
0x370 in fingerprints.get(GMCanBus.CAMERA, {}) or
|
||||
0x370 in fingerprints.get(GMCanBus.POWERTRAIN, {})
|
||||
has_acc_data = (
|
||||
0x370 in nonzero_addrs.get(GMCanBus.CAMERA, set()) or
|
||||
0x370 in nonzero_addrs.get(GMCanBus.POWERTRAIN, set())
|
||||
)
|
||||
has_pedal_msg = 0x201 in fingerprints.get(GMCanBus.POWERTRAIN, {})
|
||||
if has_acc_msg:
|
||||
if has_acc_data:
|
||||
vin_candidate = GM_CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL if has_pedal_msg else GM_CAR.CHEVROLET_BOLT_ACC_2022_2023
|
||||
else:
|
||||
vin_candidate = GM_CAR.CHEVROLET_BOLT_CC_2022_2023
|
||||
|
||||
@@ -368,7 +368,21 @@ class CarController(CarControllerBase):
|
||||
if now_nanos - self.last_steer_ts_ns >= flush_gap_ns:
|
||||
can_sends.extend(paddle_sends)
|
||||
|
||||
spoof_ecm_cruise_cars = {
|
||||
CAR.CHEVROLET_BOLT_CC_2017,
|
||||
CAR.CHEVROLET_BOLT_CC_2019_2021,
|
||||
CAR.CHEVROLET_BOLT_CC_2022_2023,
|
||||
CAR.CHEVROLET_MALIBU_HYBRID_CC,
|
||||
}
|
||||
non_acc_pedal_long = (self.CP.flags & GMFlags.PEDAL_LONG.value) and self.CP.carFingerprint in spoof_ecm_cruise_cars and self.CP.enableGasInterceptor
|
||||
if non_acc_pedal_long and self.frame % 4 == 0:
|
||||
spoof_enabled = True
|
||||
spoof_set_speed_kph = hud_v_cruise * CV.MS_TO_KPH
|
||||
can_sends.append(gmcan.create_ecm_cruise_control_command(
|
||||
self.packer_pt, CanBus.POWERTRAIN, spoof_enabled, spoof_set_speed_kph))
|
||||
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
|
||||
# Gas/regen, brakes, and UI commands - all at 25Hz
|
||||
if self.frame % 4 == 0:
|
||||
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||
@@ -419,10 +433,10 @@ class CarController(CarControllerBase):
|
||||
|
||||
gas_max = self.params.MAX_GAS
|
||||
accel_max = self.params.ACCEL_MAX
|
||||
|
||||
|
||||
accel = clip(actuators.accel + accel_due_to_pitch, self.params.ACCEL_MIN, accel_max)
|
||||
torque = self.tireRadius * ((self.mass*accel) + (0.5*self.coeffDrag*self.frontalArea*self.airDensity*CS.out.vEgo**2))
|
||||
|
||||
|
||||
scaled_torque = torque + self.params.ZERO_GAS
|
||||
apply_gas_torque = clip(scaled_torque, self.params.MAX_ACC_REGEN, gas_max)
|
||||
BRAKE_SWITCH = int(round(interp(CS.out.vEgo, self.params.BRAKE_SWITCH_LOOKUP_BP, self.params.BRAKE_SWITCH_LOOKUP_V)))
|
||||
@@ -467,7 +481,7 @@ class CarController(CarControllerBase):
|
||||
friction_brake_bus = CanBus.CHASSIS
|
||||
# GM Camera exceptions
|
||||
# TODO: can we always check the longControlState?
|
||||
if self.CP.networkLocation == NetworkLocation.fwdCamera and self.CP.carFingerprint not in CC_ONLY_CAR:
|
||||
if self.CP.networkLocation == NetworkLocation.fwdCamera:
|
||||
at_full_stop = at_full_stop and stopping
|
||||
friction_brake_bus = CanBus.POWERTRAIN
|
||||
if self.CP.carFingerprint in SDGM_CAR:
|
||||
@@ -488,10 +502,11 @@ class CarController(CarControllerBase):
|
||||
can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, friction_brake_bus, self.apply_brake,
|
||||
idx, CC.enabled, near_stop, at_full_stop, self.CP))
|
||||
|
||||
# Send dashboard UI commands (ACC status)
|
||||
is_bolt_acc_pedal = self.CP.carFingerprint == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL
|
||||
if self.CP.carFingerprint not in CC_ONLY_CAR or is_bolt_acc_pedal:
|
||||
send_fcw = hud_alert == VisualAlert.fcw
|
||||
can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN, CC.enabled,
|
||||
hud_v_cruise * CV.MS_TO_KPH, hud_control, send_fcw))
|
||||
can_sends.append(gmcan.create_acc_dashboard_command(
|
||||
self.packer_pt, CanBus.POWERTRAIN, CC.enabled, hud_v_cruise * CV.MS_TO_KPH, hud_control, send_fcw))
|
||||
else:
|
||||
# to keep accel steady for logs when not sending gas
|
||||
accel += self.accel_g
|
||||
@@ -501,7 +516,10 @@ class CarController(CarControllerBase):
|
||||
if not self.CP.radarUnavailable:
|
||||
send_adas = True
|
||||
if self.CP.carFingerprint in kaofui_cars:
|
||||
send_adas = (self.CP.networkLocation != NetworkLocation.fwdCamera) and (self.CP.carFingerprint not in SDGM_CAR)
|
||||
if self.CP.carFingerprint in ASCM_INT:
|
||||
send_adas = True
|
||||
else:
|
||||
send_adas = (self.CP.networkLocation != NetworkLocation.fwdCamera) and (self.CP.carFingerprint not in SDGM_CAR)
|
||||
|
||||
if send_adas:
|
||||
tt = self.frame * DT_CTRL
|
||||
|
||||
@@ -34,6 +34,8 @@ class CarState(CarStateBase):
|
||||
|
||||
self.single_pedal_mode = False
|
||||
self.pedal_steady = 0.
|
||||
self.ecm_cruise_control_ts_nanos = 0
|
||||
self.accelerator_pedal2_ts_nanos = 0
|
||||
|
||||
def update(self, pt_cp, cam_cp, loopback_cp, frogpilot_toggles):
|
||||
ret = car.CarState.new_message()
|
||||
@@ -97,7 +99,9 @@ class CarState(CarStateBase):
|
||||
else:
|
||||
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(pt_cp.vl["ECMPRDNL2"]["PRNDL2"], None))
|
||||
|
||||
if self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG.value:
|
||||
no_accel_pos = bool(self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG.value)
|
||||
|
||||
if no_accel_pos:
|
||||
if self.CP.carFingerprint in kaofui_state_cars:
|
||||
ret.brake = pt_cp.vl.get("EBCMBrakePedalPosition", {}).get("BrakePedalPosition", 0) / 0xd0
|
||||
else:
|
||||
@@ -107,20 +111,17 @@ class CarState(CarStateBase):
|
||||
ret.brake = pt_cp.vl.get("ECMAcceleratorPos", {}).get("BrakePedalPos", 0)
|
||||
else:
|
||||
ret.brake = pt_cp.vl["ECMAcceleratorPos"]["BrakePedalPos"]
|
||||
if self.CP.carFingerprint == CAR.CHEVROLET_BLAZER:
|
||||
# Blazer can miss light taps on analog threshold; include digital brake switch.
|
||||
ret.brakePressed = (pt_cp.vl["ECMEngineStatus"]["BrakePressed"] != 0) or (ret.brake >= 0.7)
|
||||
elif self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_CC:
|
||||
# Malibu CC: keep strict opgm behavior using BrakePedalPos >= 8.
|
||||
|
||||
if self.CP.carFingerprint in {CAR.CHEVROLET_MALIBU_CC} or (self.CP.carFingerprint == CAR.CHEVROLET_BLAZER and not no_accel_pos):
|
||||
ret.brakePressed = ret.brake >= 8
|
||||
elif (self.CP.flags & GMFlags.FORCE_BRAKE_C9.value) or (self.CP.networkLocation == NetworkLocation.fwdCamera):
|
||||
elif (self.CP.flags & GMFlags.FORCE_BRAKE_C9.value) or ((self.CP.networkLocation == NetworkLocation.fwdCamera) and (self.CP.carFingerprint != CAR.CHEVROLET_BLAZER)):
|
||||
ret.brakePressed = pt_cp.vl["ECMEngineStatus"]["BrakePressed"] != 0
|
||||
else:
|
||||
# Some Volt 2016-17 have loose brake pedal push rod retainers which causes the ECM to believe
|
||||
# that the brake is being intermittently pressed without user interaction.
|
||||
# To avoid a cruise fault we need to use a conservative brake position threshold
|
||||
# https://static.nhtsa.gov/odi/tsbs/2017/MC-10137629-9999.pdf
|
||||
analog_thresh = 0.15 if (self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG.value) else 8
|
||||
analog_thresh = 0.10 if no_accel_pos else 8
|
||||
ret.brakePressed = ret.brake >= analog_thresh
|
||||
|
||||
# Regen braking is braking
|
||||
@@ -194,6 +195,8 @@ class CarState(CarStateBase):
|
||||
if self.CP.pcmCruise and self.CP.carFingerprint not in ASCM_INT:
|
||||
ret.cruiseState.nonAdaptive = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCCruiseState"] not in (2, 3)
|
||||
if self.CP.carFingerprint in CC_ONLY_CAR:
|
||||
self.ecm_cruise_control_ts_nanos = pt_cp.ts_nanos["ECMCruiseControl"]["CruiseActive"]
|
||||
self.accelerator_pedal2_ts_nanos = pt_cp.ts_nanos["AcceleratorPedal2"]["CruiseState"]
|
||||
ret.accFaulted = False
|
||||
ret.cruiseState.speed = pt_cp.vl["ECMCruiseControl"]["CruiseSetSpeed"] * CV.KPH_TO_MS
|
||||
if self.CP.carFingerprint == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL:
|
||||
@@ -207,6 +210,9 @@ class CarState(CarStateBase):
|
||||
ret.cruiseState.enabled = pt_cp.vl["ECMCruiseControl"]["CruiseActive"] != 0
|
||||
except:
|
||||
ret.cruiseState.enabled = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCCmdActive"] != 0
|
||||
else:
|
||||
self.ecm_cruise_control_ts_nanos = 0
|
||||
self.accelerator_pedal2_ts_nanos = 0
|
||||
|
||||
if self.CP.enableBsm:
|
||||
if not sdgm_non_volt:
|
||||
|
||||
@@ -111,7 +111,7 @@ FINGERPRINTS = {
|
||||
170: 8, 188: 8, 189: 7, 190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 384: 4, 386: 8, 388: 8, 390: 7, 407: 7, 417: 7, 419: 1, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 513: 6, 528: 5, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 6, 567: 5, 568: 1, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 717: 5, 753: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 872: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 985: 5, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1265: 8, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1904: 7, 1905: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1922: 7, 1927: 7
|
||||
}],
|
||||
CAR.CHEVROLET_BOLT_CC_2019_2021: [
|
||||
# Chevy Bolt EV 2019-2021
|
||||
# Chevy Bolt EV 2018-2021
|
||||
# Bolt Premier no ACC 2018 + Pedal
|
||||
{
|
||||
170: 8, 188: 8, 189: 7, 190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 384: 4, 386: 8, 388: 8, 390: 7, 407: 7, 417: 7, 419: 1, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 2, 508: 8, 513: 6, 528: 5, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 6, 567: 5, 568: 1, 573: 1, 577: 8, 592: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 717: 5, 753: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 872: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 985: 5, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1265: 8, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1601: 8, 1616: 8, 1904: 7, 1905: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1922: 7, 1927: 7, 2020: 8, 2023: 8, 2028: 8, 2031: 8
|
||||
|
||||
@@ -185,6 +185,23 @@ def create_acc_dashboard_command(packer, bus, enabled, target_speed_kph, hud_con
|
||||
|
||||
return packer.make_can_msg("ASCMActiveCruiseControlStatus", bus, values)
|
||||
|
||||
def create_ecm_cruise_control_command(packer, bus, enabled, target_speed_kph):
|
||||
dat = bytearray(8)
|
||||
dat[0] = 0x01
|
||||
# Match observed stock shape on non-ACC CC paths: byte4 is usually 0x00
|
||||
# (with occasional 0x80 from stock state transitions). Keep this spoofed
|
||||
# path at 0x00 to avoid plausibility mismatch on non-speed bits.
|
||||
dat[4] = 0x00
|
||||
|
||||
set_speed_raw = 0
|
||||
if enabled:
|
||||
set_speed_raw = int(round(max(0., target_speed_kph) / 0.0625))
|
||||
set_speed_raw = max(0, min(set_speed_raw, 0x0FFF))
|
||||
|
||||
dat[2] = (set_speed_raw >> 8) & 0xFF
|
||||
dat[3] = set_speed_raw & 0xFF
|
||||
return make_can_msg(0x3D1, bytes(dat), bus)
|
||||
|
||||
|
||||
def create_adas_time_status(bus, tt, idx):
|
||||
dat = [(tt >> 20) & 0xff, (tt >> 12) & 0xff, (tt >> 4) & 0xff,
|
||||
|
||||
@@ -382,6 +382,14 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.lateralTuning.torque.kd = 0.93
|
||||
ret.lateralTuning.torque.kfDEPRECATED = 0.02
|
||||
|
||||
if candidate in (CAR.CHEVROLET_BOLT_CC_2019_2021,
|
||||
CAR.CHEVROLET_BOLT_ACC_2022_2023,
|
||||
CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
|
||||
CAR.CHEVROLET_BOLT_CC_2022_2023):
|
||||
# Apply 2019-style negative FF and Ki-mult tweaks to 2019-2021 and 2022 variants.
|
||||
ret.lateralTuning.torque.ki *= 1.07
|
||||
ret.lateralTuning.torque.kd *= 0.93
|
||||
|
||||
if candidate == CAR.CHEVROLET_BOLT_CC_2017:
|
||||
gm_safety_cfg.safetyParam |= Panda.FLAG_GM_BOLT_2017
|
||||
|
||||
@@ -399,8 +407,6 @@ class CarInterface(CarInterfaceBase):
|
||||
# On the Bolt, the ECM and camera independently check that you are either above 5 kph or at a stop
|
||||
# with foot on brake to allow engagement, but this platform only has that check in the camera.
|
||||
# TODO: check if this is split by EV/ICE with more platforms in the future
|
||||
if ret.openpilotLongitudinalControl:
|
||||
ret.minEnableSpeed = -1.
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
|
||||
elif candidate in (CAR.CHEVROLET_EQUINOX, CAR.CHEVROLET_EQUINOX_CC):
|
||||
@@ -536,6 +542,16 @@ class CarInterface(CarInterfaceBase):
|
||||
if ACCELERATOR_POS_MSG not in fingerprint.get(CanBus.POWERTRAIN, {}):
|
||||
ret.flags |= GMFlags.NO_ACCELERATOR_POS_MSG.value
|
||||
|
||||
use_panda_3d1_sched = (
|
||||
ret.openpilotLongitudinalControl and
|
||||
ret.enableGasInterceptor and
|
||||
bool(ret.flags & GMFlags.PEDAL_LONG.value) and
|
||||
candidate in CC_ONLY_CAR and
|
||||
candidate != CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL
|
||||
)
|
||||
if use_panda_3d1_sched:
|
||||
gm_safety_cfg.safetyParam |= Panda.FLAG_GM_PANDA_3D1_SCHED
|
||||
|
||||
return ret
|
||||
|
||||
# returns a car.CarState
|
||||
|
||||
@@ -273,7 +273,7 @@ class CAR(Platforms):
|
||||
CHEVROLET_VOLT.specs,
|
||||
)
|
||||
CHEVROLET_BOLT_CC_2019_2021 = GMPlatformConfig(
|
||||
[GMCarDocs("Chevrolet Bolt EV 2019-2021 - No-ACC")],
|
||||
[GMCarDocs("Chevrolet Bolt EV 2018-2021 - No-ACC")],
|
||||
CHEVROLET_BOLT_ACC_2022_2023.specs,
|
||||
)
|
||||
CHEVROLET_BOLT_ACC_2022_2023_PEDAL = GMPlatformConfig(
|
||||
@@ -285,7 +285,6 @@ class CAR(Platforms):
|
||||
CHEVROLET_BOLT_CC_2022_2023 = GMPlatformConfig(
|
||||
[
|
||||
GMCarDocs("Chevrolet Bolt EV 2022-2023 - No-ACC"),
|
||||
GMCarDocs("Chevrolet Bolt EV 2022-2023 - No-ACC"),
|
||||
],
|
||||
CHEVROLET_BOLT_ACC_2022_2023.specs,
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@ class TestCanFingerprint:
|
||||
|
||||
fingerprint_iter = iter([can])
|
||||
empty_can = messaging.new_message('can', 0)
|
||||
car_fingerprint, finger = can_fingerprint(lambda: next(fingerprint_iter, empty_can)) # noqa: B023
|
||||
car_fingerprint, finger, _ = can_fingerprint(lambda: next(fingerprint_iter, empty_can)) # noqa: B023
|
||||
|
||||
assert car_fingerprint == car_model
|
||||
assert finger[0] == fingerprint
|
||||
@@ -56,6 +56,6 @@ class TestCanFingerprint:
|
||||
frames += 1
|
||||
return can # noqa: B023
|
||||
|
||||
car_fingerprint, _ = can_fingerprint(test)
|
||||
car_fingerprint, _, _ = can_fingerprint(test)
|
||||
assert car_fingerprint == car_model
|
||||
assert frames == expected_frames + 2# TODO: fix extra frames
|
||||
|
||||
@@ -44,7 +44,9 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"CADILLAC_ESCALADE_ESV_2019" = [1.15, 1.3, 0.2]
|
||||
"CADILLAC_XT4" = [1.45, 1.6, 0.2]
|
||||
"CADILLAC_XT6" = [1.33, 1.9, 0.16]
|
||||
"CHEVROLET_BOLT_ACC_2022_2023" = [2.0, 2.0, 0.09]
|
||||
"CHEVROLET_BOLT_ACC_2022_2023" = [2.0, 2.0, 0.13]
|
||||
"CHEVROLET_BOLT_CC_2017" = [1.5, 2.0, 0.245]
|
||||
"CHEVROLET_BOLT_CC_2019_2021" = [2.0, 2.0, 0.13]
|
||||
"CHEVROLET_BLAZER" = [1.33, 1.33, 0.18]
|
||||
"CHEVROLET_MALIBU_CC" = [1.58, 1.8422651988094612, 0.205]
|
||||
"CHEVROLET_SILVERADO" = [1.9, 1.9, 0.112]
|
||||
|
||||
@@ -64,10 +64,8 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"CHEVROLET_VOLT_ASCM" = "CHEVROLET_VOLT"
|
||||
"GMC_ACADIA_ASCM" = "GMC_ACADIA"
|
||||
"CHEVROLET_VOLT_2019" = "CHEVROLET_VOLT"
|
||||
"CHEVROLET_BOLT_CC_2019_2021" = "CHEVROLET_BOLT_ACC_2022_2023"
|
||||
"CHEVROLET_BOLT_ACC_2022_2023_PEDAL" = "CHEVROLET_BOLT_ACC_2022_2023"
|
||||
"CHEVROLET_BOLT_CC_2022_2023" = "CHEVROLET_BOLT_ACC_2022_2023"
|
||||
"CHEVROLET_BOLT_CC_2017" = "CHEVROLET_BOLT_ACC_2022_2023"
|
||||
"CHEVROLET_EQUINOX_CC" = "CHEVROLET_EQUINOX"
|
||||
"CHEVROLET_SUBURBAN" = "CHEVROLET_SILVERADO"
|
||||
"CHEVROLET_SUBURBAN_CC" = "CHEVROLET_SILVERADO"
|
||||
|
||||
@@ -147,8 +147,7 @@ class VCruiseHelper:
|
||||
# initializing is handled by the PCM
|
||||
if self.CP.pcmCruise:
|
||||
return
|
||||
|
||||
initial = V_CRUISE_INITIAL_EXPERIMENTAL_MODE if experimental_mode and not frogpilot_toggles.conditional_experimental_mode else V_CRUISE_INITIAL
|
||||
engage_floor_kph = max(V_CRUISE_MIN, 7.0 * CV.MPH_TO_KPH)
|
||||
|
||||
# 250kph or above probably means we never had a set speed
|
||||
if any(b.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for b in CS.buttonEvents) and self.v_cruise_kph_last < 250:
|
||||
@@ -157,7 +156,7 @@ class VCruiseHelper:
|
||||
if desired_speed_limit != 0 and frogpilot_toggles.set_speed_limit:
|
||||
self.v_cruise_kph = int(round(desired_speed_limit * CV.MS_TO_KPH))
|
||||
else:
|
||||
self.v_cruise_kph = int(round(clip(CS.vEgo * CV.MS_TO_KPH, initial, V_CRUISE_MAX)))
|
||||
self.v_cruise_kph = int(round(clip(CS.vEgo * CV.MS_TO_KPH, engage_floor_kph, V_CRUISE_MAX)))
|
||||
|
||||
self.v_cruise_cluster_kph = self.v_cruise_kph
|
||||
|
||||
|
||||
@@ -43,11 +43,18 @@ DEADZONE_BOOST_LAT_ACCEL = 0.08
|
||||
UNWIND_D_DES_THRESHOLD = -1.0
|
||||
UNWIND_LAT_ACCEL_NEAR_ZERO = 0.3
|
||||
|
||||
BOLT_CARS = (
|
||||
BOLT_2022_2023_CARS = (
|
||||
GM_CAR.CHEVROLET_BOLT_ACC_2022_2023,
|
||||
GM_CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
|
||||
GM_CAR.CHEVROLET_BOLT_CC_2022_2023,
|
||||
)
|
||||
BOLT_2019_2021_CARS = (
|
||||
GM_CAR.CHEVROLET_BOLT_CC_2019_2021,
|
||||
)
|
||||
BOLT_2017_CARS = (
|
||||
GM_CAR.CHEVROLET_BOLT_CC_2017,
|
||||
)
|
||||
BOLT_CARS = BOLT_2022_2023_CARS + BOLT_2019_2021_CARS + BOLT_2017_CARS
|
||||
|
||||
class LatControlTorque(LatControl):
|
||||
def __init__(self, CP, CI, dt):
|
||||
@@ -71,6 +78,13 @@ class LatControlTorque(LatControl):
|
||||
self.prev_desired_lateral_accel = 0.0
|
||||
|
||||
self.is_bolt = CP.carFingerprint in BOLT_CARS
|
||||
self.is_bolt_2022_2023 = CP.carFingerprint in BOLT_2022_2023_CARS
|
||||
self.is_bolt_2019_2021 = CP.carFingerprint in BOLT_2019_2021_CARS
|
||||
self.is_bolt_2017 = CP.carFingerprint in BOLT_2017_CARS
|
||||
# Keep Bolt-specific FF controls isolated by generation.
|
||||
self.use_bolt_ff_scaling = self.is_bolt_2022_2023 or self.is_bolt_2019_2021
|
||||
self.use_bolt_deadzone_boost = self.is_bolt_2022_2023 or self.is_bolt_2019_2021
|
||||
self.use_bolt_ki_multiplier = self.is_bolt_2022_2023 or self.is_bolt_2019_2021
|
||||
self.torque_ff_scale_pos = 1.0
|
||||
self.torque_ff_scale_neg = 1.0
|
||||
self.torque_deadzone_boost_neg = 0.0
|
||||
@@ -80,7 +94,7 @@ class LatControlTorque(LatControl):
|
||||
self.torque_ff_scale_neg = float(self.torque_params.ki)
|
||||
self.torque_ki_mult = float(self.torque_params.kd)
|
||||
self.torque_deadzone_boost_neg = float(getattr(self.torque_params, "kfDEPRECATED", 0.0))
|
||||
if self.torque_ki_mult > 0.0 and self.torque_ki_mult != 1.0:
|
||||
if self.use_bolt_ki_multiplier and self.torque_ki_mult > 0.0 and self.torque_ki_mult != 1.0:
|
||||
self.pid._k_i = [self.pid._k_i[0], [k * self.torque_ki_mult for k in self.pid._k_i[1]]]
|
||||
|
||||
def update_live_torque_params(self, latAccelFactor, latAccelOffset, friction):
|
||||
@@ -143,13 +157,13 @@ class LatControlTorque(LatControl):
|
||||
# latAccelOffset corrects roll compensation bias from device roll misalignment relative to car roll
|
||||
ff -= self.torque_params.latAccelOffset
|
||||
ff_scale = 1.0
|
||||
if self.is_bolt:
|
||||
if self.use_bolt_ff_scaling:
|
||||
ff_scale = np.interp(ff, [-FF_SCALE_BLEND_LAT_ACCEL, 0.0, FF_SCALE_BLEND_LAT_ACCEL],
|
||||
[self.torque_ff_scale_neg, 1.0, self.torque_ff_scale_pos])
|
||||
ff *= ff_scale
|
||||
ff += get_friction(error_with_lsf + JERK_GAIN * desired_lateral_jerk, lateral_accel_deadzone, get_friction_threshold(CS.vEgo), self.torque_params)
|
||||
deadzone_boost_active = False
|
||||
if self.is_bolt and self.torque_deadzone_boost_neg > 0.0 and gravity_adjusted_future_lateral_accel < 0.0:
|
||||
if self.use_bolt_deadzone_boost and self.torque_deadzone_boost_neg > 0.0 and gravity_adjusted_future_lateral_accel < 0.0:
|
||||
if abs(gravity_adjusted_future_lateral_accel) < DEADZONE_BOOST_LAT_ACCEL:
|
||||
boost_scale = np.interp(abs(gravity_adjusted_future_lateral_accel), [0.0, DEADZONE_BOOST_LAT_ACCEL], [1.0, 0.0])
|
||||
ff -= self.torque_deadzone_boost_neg * boost_scale
|
||||
|
||||
@@ -348,7 +348,8 @@ class LongitudinalPlanner:
|
||||
(self.a_desired > 0.0) and
|
||||
self.stable_lead and
|
||||
(uncertainty <= 0.425) and
|
||||
(desire_entropy < 0.41)
|
||||
(desire_entropy < 0.41) and
|
||||
(v_ego > 5.0)
|
||||
)
|
||||
|
||||
# dwell timers for robust gating
|
||||
@@ -427,7 +428,8 @@ class LongitudinalPlanner:
|
||||
self.a_desired = float(self.a_desired - pre_brake)
|
||||
|
||||
# Apply tiny feed-forward nudge when released and safe
|
||||
if now_t < self.accel_nudge_until and self.a_desired > -0.1:
|
||||
close_lead = self.lead_one.status and self.lead_one.dRel < 10.0
|
||||
if now_t < self.accel_nudge_until and self.a_desired > -0.1 and not close_lead:
|
||||
self.a_desired = float(min(self.a_desired + 0.12, get_max_accel(v_ego)))
|
||||
|
||||
# Small deadzone around zero accel to kill micro-dithers
|
||||
|
||||
Reference in New Issue
Block a user