Compare commits

..

76 Commits

Author SHA1 Message Date
firestar5683 3d1a99f2af User adjustable offsets 2026-02-07 23:33:16 -06:00
firestar5683 a4d61232c6 Integrator Smooth On Handoff 2026-02-06 15:48:45 -06:00
firestar5683 5881c17c59 Lights 2026-02-05 22:40:42 -06:00
firestar5683 d5e971c32b New Models 2026-02-05 15:07:42 -06:00
firestar5683 3024ed42f5 Revert "merry christmas"
This reverts commit 8a9d0e5e6a.
2026-02-05 13:33:58 -06:00
firestar5683 09a073c242 Increase Fault Resilience 2026-02-05 13:29:00 -06:00
firestarsdog 231ef85bed Stats 2026-02-02 01:05:58 -05:00
firestarsdog 740668c973 Stats 2026-02-01 22:47:02 -06:00
firestar5683 b343c6aa98 Revert "Mac Update"
This reverts commit c32a5fda39.
2026-01-19 11:44:30 -06:00
firestarsdog cc1a0e4697 Add SASCM to vehicle settings detection/stats 2026-01-19 10:37:27 -06:00
firestar5683 c32a5fda39 Mac Update 2026-01-18 22:21:59 -06:00
firestarsdog af14724e78 Stats 2026-01-18 22:17:50 -06:00
firestar5683 c85a34f324 Update carcontroller.py 2026-01-15 22:52:25 -06:00
firestar5683 70260c0ed2 fix redneck v2 2026-01-14 13:58:43 -06:00
firestar5683 0110bec1af Remove lat smooth seconds 2026-01-14 13:50:35 -06:00
firestar5683 94d881211c frogpilot migration 2026-01-12 22:12:07 -06:00
firestar5683 cea5b9cada More defaults 2026-01-12 22:04:34 -06:00
firestar5683 4269bb2309 Update defaults 2026-01-12 22:01:01 -06:00
firestar5683 5cc94240cd Big Mac 2026-01-11 16:58:51 -06:00
firestar5683 201458c3d6 Try Higher Friction 2026-01-10 14:05:27 -06:00
firestar5683 1af7a5ba65 Autotune Off 2026-01-09 22:42:42 -06:00
firestar5683 fb3d1a1392 merry christmas 2025-12-24 22:05:56 -06:00
firestar5683 d650757ff9 ds2 2025-12-24 21:30:15 -06:00
firestar5683 91e273e489 Try friction adjustment 2025-12-16 14:39:42 -06:00
firestar5683 d620145cdc Update frogpilot_tracking.py 2025-12-15 00:55:16 -06:00
firestar5683 23a5bedabc minsteer speed 2025-12-14 14:46:42 -06:00
firestar5683 ea45cbf382 Update Percentages 2025-12-13 19:14:46 -06:00
firestar5683 a1f7b451a6 Trailer Load Gas Tuning 2025-12-12 10:52:53 -06:00
firestar5683 1fabfd04bd Live Friction 2025-12-11 16:54:55 -06:00
firestar5683 8630693f7a Zero error 2025-12-11 15:13:40 -06:00
firestar5683 6df0333380 Updates
Update latcontrol_torque.py

interp friction threshold
2025-12-09 20:01:30 -06:00
firestar5683 8708ab2496 LattyBoi2.0 2025-12-03 23:30:46 -06:00
firestar5683 01ed483036 Latty Boi
Revert "Latty Boi"

This reverts commit af687e501cc4bdcda7840453d06595d7ea674148.

Reapply "Latty Boi"

This reverts commit ff5566d4439f5e4997fe83f4f21d0be62b75d75d.
2025-12-02 20:31:00 -06:00
firestar5683 23fb048ba6 Recovery Power 2025-12-02 17:18:59 -06:00
firestar5683 bee7628900 New planplus 2025-12-02 12:11:19 -06:00
Woohyun Rho 9b84afc5a8 Update 2025-11-28 17:14:08 -06:00
firestar5683 5f94a5b9e0 New Lateral Changes 2025-11-18 20:49:21 -06:00
firestar5683 41d69c31e7 Update 2025-11-15 14:47:04 -06:00
firestar5683 f6c89beebd Revert "Upstream Lateral"
This reverts commit 62c1345b2a.
2025-11-10 23:09:15 -06:00
firestar5683 62c1345b2a Upstream Lateral
Revert "Upstream Lateral"

This reverts commit 20f7d6631bb152860781b46533bb0e96223be132.

Reapply "Upstream Lateral"

This reverts commit 2a7a563e219a1b688529d341919fc377fed5038e.

Update latcontrol_torque.py

more lateral

Update ui
2025-11-07 00:14:57 -06:00
firestar5683 97bfbfbb0d Update carcontroller.py 2025-10-25 16:22:22 -05:00
firestar5683 67c9a8b52e Update 2025-10-25 15:46:56 -05:00
firestar5683 2f253174e9 Medium Fanta 2025-10-22 22:27:22 -05:00
firestar5683 5a39fa4ac1 Update interfaces.py 2025-10-20 13:50:27 -05:00
firestar5683 8a54eb5733 no nnff 2025-10-19 18:00:23 -05:00
firestar5683 a1edc6d6e7 Scene Complexity 2025-10-18 14:24:54 -05:00
firestar5683 05ded9d10b Update interface.py 2025-10-17 18:13:42 -05:00
firestar5683 d387c7934f CEM 2025-10-17 17:40:21 -05:00
firestar5683 4c9d393e37 lite 2025-10-17 17:14:41 -05:00
firestar5683 c14680edcb Modify torque tuning parameters in interfaces.py
Adjusted torque tuning parameters for improved performance.
2025-10-17 17:02:13 -05:00
firestar5683 95ea985218 Hurts Donut 2025-10-16 23:57:42 -05:00
firestar5683 376aeff9e3 Smoothy Boi 2025-10-16 23:40:06 -05:00
firestar5683 680c3acaf0 lat3 2025-10-15 22:21:08 -05:00
firestar5683 9cc2c20cdc Honda? 2025-10-12 00:30:14 -05:00
firestar5683 8c81eadf5d oopsie doopsie 2025-10-12 00:12:03 -05:00
firestar5683 88a29c67d0 Revert "Humanlanechanges fix"
This reverts commit 5e88e5beff.
2025-10-12 00:11:50 -05:00
firestar5683 6fe8f8b722 Revert "Duh"
This reverts commit b5b942a108.
2025-10-12 00:11:48 -05:00
firestarsdog b5b942a108 Duh 2025-10-11 20:56:35 -04:00
niknak6 5e88e5beff Humanlanechanges fix 2025-10-11 19:37:40 -04:00
firestar5683 8f27c4937c New Lateral Changes 2025-10-10 20:59:30 -05:00
firestar5683 c95f8fa8fc Fix Standard 2025-10-10 19:25:57 -05:00
firestar5683 8b55472a90 error? 2025-10-09 13:29:53 -05:00
firestar5683 9bcfeb1cf3 Honda2 2025-10-09 13:29:53 -05:00
firestar5683 93713aaacf honda 2025-10-08 22:38:53 -05:00
firestar5683 602641856d Fix New Devices 2025-10-08 22:20:55 -05:00
firestar5683 1f0d2092a3 No positive P-response for long control if user-selected parameter set 2025-10-08 07:44:53 -05:00
firestar5683 587dc140b7 Automatic updates 2025-10-04 16:03:30 -05:00
firestar5683 63ee52b4aa Steer Alerts 2025-10-04 01:48:56 -05:00
firestar5683 eb19b336e2 Update frogpilot_acceleration.py 2025-10-03 22:36:15 -05:00
firestar5683 06f95d0dcd SteerAlerts
Revert "SteerAlerts"

This reverts commit cbaba399c5b9caac5a8faf3917f0929d747a0acc.

Update controlsd.py
2025-10-03 22:14:06 -05:00
firestar5683 cd7f2f8bc6 Donut DM 2025-10-03 20:49:04 -05:00
firestar5683 82af86e04c Update gm_global_a_powertrain_generated.dbc 2025-10-03 16:41:03 -05:00
firestar5683 6934f375d5 Update 2025-10-03 00:43:23 -05:00
firestar5683 09afc383fd firehose 2025-09-30 20:47:05 -05:00
firestar5683 19f7685744 Update 2025-09-30 14:31:30 -05:00
firestar5683 6477ba6a5e Dom
Revert "Dom"

This reverts commit eb2218e733.

Dom
2025-09-30 13:06:51 -05:00
22 changed files with 194 additions and 567 deletions
@@ -49,8 +49,8 @@ A_CRUISE_MIN_SPORT = A_CRUISE_MIN * 2
A_CRUISE_MAX_BP_CUSTOM = [0.0, 5., 10., 15., 20., 25., 40.] A_CRUISE_MAX_BP_CUSTOM = [0.0, 5., 10., 15., 20., 25., 40.]
A_CRUISE_MAX_VALS_ECO_EV = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] A_CRUISE_MAX_VALS_ECO_EV = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
A_CRUISE_MAX_VALS_SPORT_EV = [1.25, 1.25, 1.25, 1.25, 1.5, 1.5, 2.0] A_CRUISE_MAX_VALS_SPORT_EV = [1.25, 1.25, 1.25, 1.25, 1.5, 1.5, 2.0]
A_CRUISE_MAX_VALS_ECO_GAS = [6.0, 1.40, 0.90, 0.65, 0.60, 0.55, 0.42] A_CRUISE_MAX_VALS_ECO_GAS = [2.0, 1.5, 1.0, 0.8, 0.6, 0.4, 0.2]
A_CRUISE_MAX_VALS_SPORT_GAS = [6.0, 1.50, 1.00, 0.72, 0.65, 0.60, 0.45] A_CRUISE_MAX_VALS_SPORT_GAS = [3.0, 2.5, 2.0, 1.5, 1.0, 0.8, 0.6]
def get_max_accel_eco(v_ego, ev_tuning=True): def get_max_accel_eco(v_ego, ev_tuning=True):
cruise_vals = A_CRUISE_MAX_VALS_ECO_EV if ev_tuning else A_CRUISE_MAX_VALS_ECO_GAS cruise_vals = A_CRUISE_MAX_VALS_ECO_EV if ev_tuning else A_CRUISE_MAX_VALS_ECO_GAS
BIN
View File
Binary file not shown.
Binary file not shown.
+8 -8
View File
@@ -120,14 +120,14 @@ def get_city_center(latitude, longitude):
def update_branch_commits(now): def update_branch_commits(now):
points = [] points = []
for branch in ["FrogPilot", "FrogPilot-Staging", "FrogPilot-Testing"]: branch = get_build_metadata().channel # Current running branch
try: try:
response = requests.get(f"https://api.github.com/repos/FrogAi/FrogPilot/commits/{branch}") response = requests.get(f"https://api.github.com/repos/firestar5683/StarPilot/commits/{branch}")
response.raise_for_status() response.raise_for_status()
sha = response.json()["sha"] sha = response.json()["sha"]
points.append(Point("branch_commits").field("commit", sha).tag("branch", branch).time(now)) points.append(Point("branch_commits").field("commit", sha).tag("branch", branch).time(now))
except Exception as e: except Exception as e:
print(f"Failed to fetch commit for {branch}: {e}") print(f"Failed to fetch commit for {branch}: {e}")
return points return points
+4 -15
View File
@@ -82,12 +82,6 @@ VAL_TABLE_ HandsOffSWDetectionMode 2 "Failed" 1 "Enabled" 0 "Disabled" ;
BO_ 189 EBCMRegenPaddle: 7 K17_EBCM BO_ 189 EBCMRegenPaddle: 7 K17_EBCM
SG_ RegenPaddle : 7|4@0+ (1,0) [0|0] "" NEO SG_ RegenPaddle : 7|4@0+ (1,0) [0|0] "" NEO
SG_ Byte1 : 8|8@1+ (1,0) [0|255] "" NEO
SG_ Byte2 : 16|8@1+ (1,0) [0|255] "" NEO
SG_ Byte3 : 24|8@1+ (1,0) [0|255] "" NEO
SG_ Byte4 : 32|8@1+ (1,0) [0|255] "" NEO
SG_ Byte5 : 40|8@1+ (1,0) [0|255] "" NEO
SG_ Byte6 : 48|8@1+ (1,0) [0|255] "" NEO
BO_ 190 ECMAcceleratorPos: 6 K20_ECM BO_ 190 ECMAcceleratorPos: 6 K20_ECM
SG_ BrakePedalPos : 15|8@0+ (1,0) [0|0] "sticky" NEO SG_ BrakePedalPos : 15|8@0+ (1,0) [0|0] "sticky" NEO
@@ -198,15 +192,10 @@ BO_ 500 SportMode: 6 XXX
SG_ SportMode : 15|1@0+ (1,0) [0|1] "" XXX SG_ SportMode : 15|1@0+ (1,0) [0|1] "" XXX
BO_ 501 ECMPRDNL2: 8 K20_ECM BO_ 501 ECMPRDNL2: 8 K20_ECM
SG_ Byte0 : 0|8@1+ (1,0) [0|255] "" NEO
SG_ Byte1 : 8|8@1+ (1,0) [0|255] "" NEO
SG_ Byte2 : 16|8@1+ (1,0) [0|255] "" NEO
SG_ PRNDL2 : 27|4@0+ (1,0) [0|255] "" NEO
SG_ Byte4 : 32|8@1+ (1,0) [0|255] "" NEO
SG_ ManualMode : 41|1@0+ (1,0) [0|1] "" NEO
SG_ TransmissionState : 48|4@1+ (1,0) [0|7] "" NEO SG_ TransmissionState : 48|4@1+ (1,0) [0|7] "" NEO
SG_ Byte7 : 56|8@1+ (1,0) [0|255] "" NEO SG_ PRNDL2 : 27|4@0+ (1,0) [0|255] "" NEO
SG_ ManualMode : 41|1@0+ (1,0) [0|1] "" NEO
BO_ 532 BRAKE_RELATED: 6 XXX BO_ 532 BRAKE_RELATED: 6 XXX
SG_ UserBrakePressure : 0|9@0+ (1,0) [0|511] "" XXX SG_ UserBrakePressure : 0|9@0+ (1,0) [0|511] "" XXX
@@ -381,6 +370,6 @@ VAL_ 715 GasRegenCmdActive 1 "Active" 0 "Inactive" ;
VAL_ 320 Intellibeam 1 "Active" 0 "Inactive" ; VAL_ 320 Intellibeam 1 "Active" 0 "Inactive" ;
VAL_ 320 HighBeamsActive 1 "Active" 0 "Inactive" ; VAL_ 320 HighBeamsActive 1 "Active" 0 "Inactive" ;
VAL_ 320 HighBeamsTemporary 1 "Active" 0 "Inactive" ; VAL_ 320 HighBeamsTemporary 1 "Active" 0 "Inactive" ;
VAL_ 501 PRNDL2 7 "L2" 6 "L" 5 "L3" 4 "D" 3 "N" 2 "R" 1 "P" 0 "Shifting"; VAL_ 501 PRNDL2 6 "L" 4 "D" 3 "N" 2 "R" 1 "P" 0 "Shifting";
VAL_ 501 TransmissionState 11 "Shifting" 10 "Reverse" 9 "Forward" 8 "Disengaged"; VAL_ 501 TransmissionState 11 "Shifting" 10 "Reverse" 9 "Forward" 8 "Disengaged";
VAL_ 501 ManualMode 1 "Active" 0 "Inactive" VAL_ 501 ManualMode 1 "Active" 0 "Inactive"
+3 -3
View File
@@ -202,9 +202,9 @@ void ignition_can_hook(CANPacket_t *to_push) {
int len = GET_LEN(to_push); int len = GET_LEN(to_push);
// GM exception // GM exception
if ((addr == 0xC9) && (len == 8)) { if ((addr == 0x1F1) && (len == 8)) {
// Matches SystemPowerMode (1=Run, 0=Off) // SystemPowerMode (2=Run, 3=Crank Request)
ignition_can = (GET_BYTE(to_push, 6) & 0x10U) != 0U; ignition_can = (GET_BYTE(to_push, 0) & 0x2U) != 0U;
ignition_can_cnt = 0U; ignition_can_cnt = 0U;
} }
+1 -1
View File
@@ -88,7 +88,7 @@ int safety_fwd_hook(int bus_num, int addr) {
} }
bool get_longitudinal_allowed(void) { bool get_longitudinal_allowed(void) {
return controls_allowed && !gas_pressed; return controls_allowed && !gas_pressed_prev;
} }
// Given a CRC-8 poly, generate a static lookup table to use with a fast CRC-8 // Given a CRC-8 poly, generate a static lookup table to use with a fast CRC-8
+16 -32
View File
@@ -10,16 +10,16 @@ const SteeringLimits GM_STEERING_LIMITS = {
}; };
const LongitudinalLimits GM_ASCM_LONG_LIMITS = { const LongitudinalLimits GM_ASCM_LONG_LIMITS = {
.max_gas = 7168, .max_gas = 3072,
.min_gas = 5500, .min_gas = 1404,
.inactive_gas = 5500, .inactive_gas = 1404,
.max_brake = 400, .max_brake = 400,
}; };
const LongitudinalLimits GM_CAM_LONG_LIMITS = { const LongitudinalLimits GM_CAM_LONG_LIMITS = {
.max_gas = 7496, .max_gas = 3400,
.min_gas = 5610, .min_gas = 1514,
.inactive_gas = 5650, .inactive_gas = 1554,
.max_brake = 400, .max_brake = 400,
}; };
@@ -29,23 +29,23 @@ const int GM_STANDSTILL_THRSLD = 10; // 0.311kph
// panda interceptor threshold needs to be equivalent to openpilot threshold to avoid controls mismatches // panda interceptor threshold needs to be equivalent to openpilot threshold to avoid controls mismatches
// If thresholds are mismatched then it is possible for panda to see the gas fall and rise while openpilot is in the pre-enabled state // If thresholds are mismatched then it is possible for panda to see the gas fall and rise while openpilot is in the pre-enabled state
const int GM_GAS_INTERCEPTOR_THRESHOLD = 595; // (675 + 355) / 2 ratio between offset and gain from dbc file const int GM_GAS_INTERCEPTOR_THRESHOLD = 515; // (675 + 355) / 2 ratio between offset and gain from dbc file
#define GM_GET_INTERCEPTOR(msg) (((GET_BYTE((msg), 0) << 8) + GET_BYTE((msg), 1) + (GET_BYTE((msg), 2) << 8) + GET_BYTE((msg), 3)) / 2U) // avg between 2 tracks #define GM_GET_INTERCEPTOR(msg) (((GET_BYTE((msg), 0) << 8) + GET_BYTE((msg), 1) + (GET_BYTE((msg), 2) << 8) + GET_BYTE((msg), 3)) / 2U) // avg between 2 tracks
const CanMsg GM_ASCM_TX_MSGS[] = {{0x180, 0, 4}, {0x409, 0, 7}, {0x40A, 0, 7}, {0x2CB, 0, 8}, {0x370, 0, 6}, {0x200, 0, 6}, {0xBD, 0, 7}, {0x1F5, 0, 8}, // pt bus const CanMsg GM_ASCM_TX_MSGS[] = {{0x180, 0, 4}, {0x409, 0, 7}, {0x40A, 0, 7}, {0x2CB, 0, 8}, {0x370, 0, 6}, {0x200, 0, 6}, // pt bus
{0xA1, 1, 7}, {0x306, 1, 8}, {0x308, 1, 7}, {0x310, 1, 2}, // obs bus {0xA1, 1, 7}, {0x306, 1, 8}, {0x308, 1, 7}, {0x310, 1, 2}, // obs bus
{0x315, 2, 5}}; // ch 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}, {0x200, 0, 6}, {0x1E1, 0, 7}, // pt bus
{0x1E1, 2, 7}, {0x184, 2, 8}}; // camera 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}, // pt bus
{0x1E1, 2, 7}, {0x184, 2, 8}}; // camera bus {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 const CanMsg GM_SDGM_TX_MSGS[] = {{0x180, 0, 4}, {0x1E1, 0, 7}, // pt bus
{0x184, 2, 8}}; // camera 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}, {0x1E1, 0, 7}, // pt bus
{0x184, 2, 8}, {0x1E1, 2, 7}}; // camera bus {0x184, 2, 8}, {0x1E1, 2, 7}}; // camera bus
// TODO: do checksum and counter checks. Add correct timestep, 0.1s for now. // TODO: do checksum and counter checks. Add correct timestep, 0.1s for now.
@@ -143,7 +143,7 @@ static void gm_rx_hook(const CANPacket_t *to_push) {
} }
if ((addr == 0xC9) && ((gm_hw == GM_CAM) || (gm_hw == GM_SDGM))) { if ((addr == 0xC9) && ((gm_hw == GM_CAM) || (gm_hw == GM_SDGM))) {
brake_pressed = GET_BIT(to_push, 40U) != 0U; brake_pressed = GET_BIT(to_push, 40U);
} }
if (addr == 0xC9) { if (addr == 0xC9) {
@@ -229,7 +229,7 @@ static bool gm_tx_hook(const CANPacket_t *to_send) {
// GAS/REGEN: safety check // GAS/REGEN: safety check
if (addr == 0x2CB) { if (addr == 0x2CB) {
bool apply = GET_BIT(to_send, 0U); bool apply = GET_BIT(to_send, 0U);
int gas_regen = ((GET_BYTE(to_send, 1) & 0x1U) << 13) + ((GET_BYTE(to_send, 2) & 0xFFU) << 5) + ((GET_BYTE(to_send, 3) & 0xF8U) >> 3); int gas_regen = ((GET_BYTE(to_send, 2) & 0x7FU) << 5) + ((GET_BYTE(to_send, 3) & 0xF8U) >> 3);
bool violation = false; bool violation = false;
// Allow apply bit in pre-enabled and overriding states // Allow apply bit in pre-enabled and overriding states
@@ -256,22 +256,6 @@ static bool gm_tx_hook(const CANPacket_t *to_send) {
} }
} }
// 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);
if (!controls_allowed && regen_apply) {
tx = false;
}
}
// PRNDL2 regen check (7 for Gen0, Gen1. 5 For Gen2)
if (addr == 0x1F5) {
uint8_t prndl2 = GET_BYTE(to_send, 3) & 0xF;
bool prndl_apply = (prndl2 == 7) || (prndl2 == 5);
if (!controls_allowed && prndl_apply) {
tx = false;
}
}
return tx; return tx;
} }
@@ -313,9 +297,9 @@ static safety_config gm_init(uint16_t param) {
gm_force_ascm = GET_FLAG(param, GM_PARAM_HW_ASCM_LONG); gm_force_ascm = GET_FLAG(param, GM_PARAM_HW_ASCM_LONG);
if (gm_hw == GM_ASCM || gm_force_ascm) { if (gm_hw == GM_ASCM || gm_force_ascm) {
gm_long_limits = &GM_ASCM_LONG_LIMITS; gm_long_limits = &GM_ASCM_LONG_LIMITS;
} else if ((gm_hw == GM_CAM) || (gm_hw == GM_SDGM)) { } else if ((gm_hw == GM_CAM) || (gm_hw == GM_SDGM)) {
gm_long_limits = &GM_CAM_LONG_LIMITS; gm_long_limits = &GM_CAM_LONG_LIMITS;
} else { } else {
} }
+40 -280
View File
@@ -1,7 +1,3 @@
from typing import Tuple
import time
import math
from openpilot.common.swaglog import cloudlog
from cereal import car from cereal import car
from openpilot.common.conversions import Conversions as CV from openpilot.common.conversions import Conversions as CV
from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.filter_simple import FirstOrderFilter
@@ -11,11 +7,10 @@ from openpilot.common.params_pyx import Params
from opendbc.can.packer import CANPacker from opendbc.can.packer import CANPacker
from openpilot.selfdrive.car import apply_driver_steer_torque_limits, create_gas_interceptor_command from openpilot.selfdrive.car import apply_driver_steer_torque_limits, create_gas_interceptor_command
from openpilot.selfdrive.car.gm import gmcan from openpilot.selfdrive.car.gm import gmcan
from openpilot.selfdrive.car.gm.values import CAR, DBC, AccState, CanBus, CarControllerParams, CruiseButtons, GMFlags, CC_ONLY_CAR, SDGM_CAR, EV_CAR, CC_REGEN_PADDLE_CAR from openpilot.selfdrive.car.gm.values import DBC, AccState, CanBus, CarControllerParams, CruiseButtons, GMFlags, CC_ONLY_CAR, SDGM_CAR, EV_CAR
from openpilot.selfdrive.car.interfaces import CarControllerBase from openpilot.selfdrive.car.interfaces import CarControllerBase
from openpilot.selfdrive.controls.lib.drive_helpers import apply_deadzone from openpilot.selfdrive.controls.lib.drive_helpers import apply_deadzone
from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
from openpilot.common.swaglog import cloudlog
VisualAlert = car.CarControl.HUDControl.VisualAlert VisualAlert = car.CarControl.HUDControl.VisualAlert
NetworkLocation = car.CarParams.NetworkLocation NetworkLocation = car.CarParams.NetworkLocation
@@ -27,15 +22,7 @@ TransmissionType = car.CarParams.TransmissionType
CAMERA_CANCEL_DELAY_FRAMES = 10 CAMERA_CANCEL_DELAY_FRAMES = 10
# Enforce a minimum interval between steering messages to avoid a fault # Enforce a minimum interval between steering messages to avoid a fault
MIN_STEER_MSG_INTERVAL_MS = 15 MIN_STEER_MSG_INTERVAL_MS = 15
# Twosided spacing tuned for ~33 Hz steer; target a 10 ms wide window per interval
# Paddle spoofing and scheduling constants
PADDLE_STEER_GAP_MIN_NS = 5_000_000 # ≥5 ms each side (EPS guard)
PADDLE_STEER_GAP_MAX_NS = 12_000_000 # cap for long intervals
PADDLE_GAP_TARGET_NS = 5_000_000 # aim perside gap even if interval//2 early is larger
PADDLE_NONBLOCK_GAP_NS = 1_000_000 # ≥1 ms since last paddle send
PADDLE_SLOT_EARLY_NS = 1_000_000 # allow firing up to 1 ms before slot
OVERFLOW_THRESH = 1.00 # fire one extra slot whenever credits ≥ 1.0
PADDLE_TARGET_HZ = 42.0 # desired paddle rate (Hz) when regen active; steer is ~33 Hz
# Constants for pitch compensation # Constants for pitch compensation
BRAKE_PITCH_FACTOR_BP = [5., 10.] # [m/s] smoothly revert to planned accel at low speeds BRAKE_PITCH_FACTOR_BP = [5., 10.] # [m/s] smoothly revert to planned accel at low speeds
BRAKE_PITCH_FACTOR_V = [0., 1.] # [unitless in [0,1]]; don't touch BRAKE_PITCH_FACTOR_V = [0., 1.] # [unitless in [0,1]]; don't touch
@@ -51,11 +38,6 @@ class CarController(CarControllerBase):
self.apply_speed = 0 self.apply_speed = 0
self.frame = 0 self.frame = 0
self.last_steer_frame = 0 self.last_steer_frame = 0
self.last_steer_ts_ns = 0
self.last_regen_active = False
self.prev_steer_ts_ns = 0
self.last_spoof_ts_ns = 0
self.last_paddle_ts_ns = 0
self.last_button_frame = 0 self.last_button_frame = 0
self.cancel_counter = 0 self.cancel_counter = 0
self.pedal_steady = 0. self.pedal_steady = 0.
@@ -66,101 +48,33 @@ class CarController(CarControllerBase):
self.params = CarControllerParams(self.CP) self.params = CarControllerParams(self.CP)
self.params_ = Params() self.params_ = Params()
self.mass = CP.mass
self.tireRadius = 0.075 * CP.wheelbase + 0.1453
self.frontalArea = 1.05 * CP.wheelbase + 0.0679
self.coeffDrag = 0.30
self.airDensity = 1.225
self.packer_pt = CANPacker(DBC[self.CP.carFingerprint]['pt']) self.packer_pt = CANPacker(DBC[self.CP.carFingerprint]['pt'])
self.packer_obj = CANPacker(DBC[self.CP.carFingerprint]['radar']) self.packer_obj = CANPacker(DBC[self.CP.carFingerprint]['radar'])
self.packer_ch = CANPacker(DBC[self.CP.carFingerprint]['chassis']) self.packer_ch = CANPacker(DBC[self.CP.carFingerprint]['chassis'])
# FrogPilot variables # FrogPilot variables
self.accel_g = 0.0 self.accel_g = 0.0
self.pitch = FirstOrderFilter(0., 0.09 * 4, DT_CTRL * 4) # runs at 25 Hz self.pitch = FirstOrderFilter(0., 0.09 * 4, DT_CTRL * 4) # runs at 25 Hz
self.accel_g = 0.0
self.regen_paddle_pressed = False
self.aego = 0.0
self.regen_paddle_timer = 0
self.planner_regen_hold = False
@staticmethod
def calc_pedal_command(accel: float, long_active: bool) -> float:
if not long_active: return 0.
zero = 0.15625 # 40/256
if accel > 0.:
# Scales the accel from 0-1 to 0.156-1
pedal_gas = clip(((1 - zero) * accel + zero), 0., 1.)
else:
# if accel is negative, -0.1 -> 0.015625
pedal_gas = clip(zero + accel, 0., zero) # Make brake the same size as gas, but clip to regen
# Midpoint + overflow spoof accumulator and flags return pedal_gas
self.spoof_accum = 0.0
self.spoof_mid_sent = False
self.spoof_over_sent = False
self.last_interval_ns = 0
def calc_pedal_command(self, accel: float, long_active: bool, car_velocity) -> Tuple[float, bool]:
if not long_active:
self.planner_regen_hold = False
return 0., False
# Regen paddle hysteresis (frame-based): hold 10 frames, with decrement dead-zone
if not hasattr(self, 'regen_paddle_timer'):
self.regen_paddle_timer = 0 # frames
# Regen paddle hysteresis (framebased): count frames when decelerating hard, decrement only when truly released
if self.aego < -0.7:
self.regen_paddle_timer += 1
elif self.aego > -0.3:
self.regen_paddle_timer = max(self.regen_paddle_timer - 1, 0)
# else: hold timer between -0.7 and -0.3
# Base paddle press hysteresis
self.regen_paddle_pressed = self.regen_paddle_timer >= 10 # 10 frames
press_regen_paddle = self.regen_paddle_pressed or self.planner_regen_hold
# Regen gain ratios from bin-averaged 600 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.000000, 1.057308, 1.131123, 1.220611, 1.270247, 1.300253, 1.339543, 1.361002,
1.388410, 1.403253, 1.414721, 1.430949, 1.420289, 1.436787, 1.434116, 1.436805,
1.417508, 1.402213, 1.395360, 1.360921, 1.342030, 1.292219, 1.270048, 1.239172
]
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])
# Compute raw pedal gas
raw_pedal_gas = clip((pedaloffset + (accel / gain) * 0.6), 0.0, 1.0) if press_regen_paddle else clip((pedaloffset + accel * 0.6), 0.0, 1.0)
# --- Immediate application of raw pedal gas, no blending ---
pedal_gas = raw_pedal_gas
# Safety cap: ramp from 22% at 0 m/s to 37.25% at 10 mph (4.47 m/s), then allow full throttle
pedal_gas_max = interp(car_velocity, [0.0, 4.47, 4.48], [0.22, 0.3725, 1.0])
pedal_gas = clip(pedal_gas, 0.0, pedal_gas_max)
return pedal_gas, press_regen_paddle
def update(self, CC, CS, now_nanos, frogpilot_toggles): def update(self, CC, CS, now_nanos, frogpilot_toggles):
self.CS = CS
self.aego = CS.out.aEgo
actuators = CC.actuators actuators = CC.actuators
accel = brake_accel = actuators.accel accel = brake_accel = actuators.accel
press_regen_paddle = False
# Planner-driven regen hold: gate by car support and OP long active, use commanded accel thresholds
if (self.CP.enableGasInterceptor and self.CP.carFingerprint in CC_REGEN_PADDLE_CAR
and self.CP.openpilotLongitudinalControl and CC.longActive):
# Match original hysteresis intent: vehicle can usually stop without paddle up to ~1.0 m/s^2
# Use the same thresholds as the aEgo-based hysteresis, but on commanded accel for preemption
planner_press_threshold = -0.7
planner_release_threshold = -0.3
if accel <= planner_press_threshold:
self.planner_regen_hold = True
elif accel >= planner_release_threshold:
self.planner_regen_hold = False
else:
self.planner_regen_hold = False
hud_control = CC.hudControl hud_control = CC.hudControl
hud_alert = hud_control.visualAlert hud_alert = hud_control.visualAlert
hud_v_cruise = hud_control.setSpeed hud_v_cruise = hud_control.setSpeed
@@ -169,138 +83,6 @@ class CarController(CarControllerBase):
# Send CAN commands. # Send CAN commands.
can_sends = [] can_sends = []
paddle_sends = []
raw_regen_active = (
self.CP.carFingerprint in CC_REGEN_PADDLE_CAR and
self.CP.openpilotLongitudinalControl and
CC.longActive and
self.CP.enableGasInterceptor and
(self.regen_paddle_timer >= 10 or self.planner_regen_hold) # hysteresis or planner hint
)
regen_active = raw_regen_active
# === Spoof scheduling: midpoint + overflow (~target Hz) ===
# Rising-edge reset on regen start
if raw_regen_active and not self.last_regen_active:
self.prev_steer_ts_ns = self.last_steer_ts_ns
self.last_spoof_ts_ns = 0
self.spoof_accum = 0.0
self.spoof_mid_sent = False
self.spoof_over_sent = False
if raw_regen_active:
# Interval between last two bus-0 steer sends
interval_ns = self.last_steer_ts_ns - self.prev_steer_ts_ns
# Adaptive twosided gap sized to the current steer interval, but capped to a target so the window stays wide enough
gap_ns = (PADDLE_STEER_GAP_MIN_NS if interval_ns <= 0 else
max(PADDLE_STEER_GAP_MIN_NS,
min(PADDLE_STEER_GAP_MAX_NS,
min((interval_ns // 2) - PADDLE_SLOT_EARLY_NS, PADDLE_GAP_TARGET_NS))))
# New steer interval? clear per-interval flags and add credits to reach target Hz
if interval_ns != self.last_interval_ns:
self.spoof_mid_sent = False
self.spoof_over_sent = False
self.last_interval_ns = interval_ns
# Add credits once per new steer interval to reach the desired paddle rate
if interval_ns > 0:
steer_hz = 1e9 / float(interval_ns)
extra_needed = max(0.0, (PADDLE_TARGET_HZ / steer_hz) - 1.0) # e.g., 42/33 1 ≈ 0.2727
self.spoof_accum += extra_needed
# Midpoint spoof: one per interval
if not self.spoof_mid_sent and interval_ns > 0:
midpoint_ns = self.prev_steer_ts_ns + interval_ns // 2
cloudlog.error("PADDLE MID: Δafter=%.1fms Δbefore=%.1fms credits=%.3f timer=%d",
(now_nanos - self.last_steer_ts_ns) * 1e-6,
(now_nanos - self.prev_steer_ts_ns) * 1e-6,
self.spoof_accum,
self.regen_paddle_timer)
# Compute spacing to last and next steer (two-sided guard)
next_steer_ts_ns = self.last_steer_ts_ns + interval_ns if interval_ns > 0 else 0
delta_after_ns = now_nanos - self.last_steer_ts_ns
delta_before_ns = (next_steer_ts_ns - now_nanos) if interval_ns > 0 else 1_000_000_000
if (CS.out.vEgo > 2.68
and now_nanos >= (midpoint_ns - PADDLE_SLOT_EARLY_NS)
and delta_after_ns >= gap_ns
and delta_before_ns >= gap_ns):
# Non-blocking 1 ms spacing for paddle frames
if now_nanos - self.last_paddle_ts_ns >= PADDLE_NONBLOCK_GAP_NS:
paddle_sends.append(gmcan.create_prndl2_command(self.packer_pt, CanBus.POWERTRAIN, True))
paddle_sends.append(gmcan.create_regen_paddle_command(self.packer_pt, CanBus.POWERTRAIN, True))
self.last_paddle_ts_ns = now_nanos
self.last_spoof_ts_ns = now_nanos
self.spoof_mid_sent = True
# Overflow spoof: insert extra when accumulator allows
if self.spoof_accum >= OVERFLOW_THRESH and not self.spoof_over_sent and interval_ns > 0:
slot2_ns = self.prev_steer_ts_ns + (interval_ns * 2) // 3
cloudlog.error("PADDLE OFL: Δafter=%.1fms Δbefore=%.1fms credits=%.3f thresh=%.1f timer=%d",
(now_nanos - self.last_steer_ts_ns) * 1e-6,
(now_nanos - self.prev_steer_ts_ns) * 1e-6,
self.spoof_accum,
OVERFLOW_THRESH,
self.regen_paddle_timer)
# Two-sided spacing relative to steer
next_steer_ts_ns = self.last_steer_ts_ns + interval_ns if interval_ns > 0 else 0
delta_after_ns = now_nanos - self.last_steer_ts_ns
delta_before_ns = (next_steer_ts_ns - now_nanos) if interval_ns > 0 else 1_000_000_000
if (CS.out.vEgo > 2.68
and now_nanos >= (slot2_ns - PADDLE_SLOT_EARLY_NS)
and delta_after_ns >= gap_ns
and delta_before_ns >= gap_ns):
# Non-blocking 1 ms spacing for paddle frames
if now_nanos - self.last_paddle_ts_ns >= PADDLE_NONBLOCK_GAP_NS:
paddle_sends.append(gmcan.create_prndl2_command(self.packer_pt, CanBus.POWERTRAIN, True))
paddle_sends.append(gmcan.create_regen_paddle_command(self.packer_pt, CanBus.POWERTRAIN, True))
self.last_paddle_ts_ns = now_nanos
self.last_spoof_ts_ns = now_nanos
self.spoof_over_sent = True
self.spoof_accum -= OVERFLOW_THRESH
# === End Spoof scheduling ===
# === Off-pulse scheduling on regen release ===
if not raw_regen_active and self.last_regen_active:
# schedule two off-slots at 1/3 and 2/3 of the last steer interval
if self.prev_steer_ts_ns and self.last_steer_ts_ns:
intv = self.last_steer_ts_ns - self.prev_steer_ts_ns
self.off_schedule_ns = [
self.prev_steer_ts_ns + intv // 3,
self.prev_steer_ts_ns + (2 * intv) // 3
]
self.off_sent = [False, False]
if hasattr(self, "off_schedule_ns"):
for i, t_ns in enumerate(self.off_schedule_ns):
if not self.off_sent[i] and now_nanos >= (t_ns - PADDLE_SLOT_EARLY_NS):
cloudlog.error("PADDLE OFF %d: Δafter=%.1fms Δto_slot=%.1fms timer=%d",
i,
(now_nanos - self.last_steer_ts_ns) * 1e-6,
(now_nanos - t_ns) * 1e-6,
self.regen_paddle_timer)
# Two-sided spacing to steer before sending
interval_ns = self.last_steer_ts_ns - self.prev_steer_ts_ns
gap_ns = (PADDLE_STEER_GAP_MIN_NS if interval_ns <= 0 else
max(PADDLE_STEER_GAP_MIN_NS,
min(PADDLE_STEER_GAP_MAX_NS,
min((interval_ns // 2) - PADDLE_SLOT_EARLY_NS, PADDLE_GAP_TARGET_NS))))
next_steer_ts_ns = self.last_steer_ts_ns + interval_ns if interval_ns > 0 else 0
delta_after_ns = now_nanos - self.last_steer_ts_ns
delta_before_ns = (next_steer_ts_ns - now_nanos) if interval_ns > 0 else 1_000_000_000
if (delta_after_ns >= gap_ns and delta_before_ns >= gap_ns):
# Non-blocking 1 ms spacing for paddle frames
if now_nanos - self.last_paddle_ts_ns >= PADDLE_NONBLOCK_GAP_NS:
paddle_sends.append(gmcan.create_prndl2_command(self.packer_pt, CanBus.POWERTRAIN, False))
paddle_sends.append(gmcan.create_regen_paddle_command(self.packer_pt, CanBus.POWERTRAIN, False))
self.last_paddle_ts_ns = now_nanos
self.off_sent[i] = True
# clean up once both off pulses are sent
if hasattr(self, "off_sent") and all(self.off_sent):
del self.off_schedule_ns
del self.off_sent
# === End off-pulse scheduling ===
# Steering (Active: 50Hz, inactive: 10Hz) # Steering (Active: 50Hz, inactive: 10Hz)
steer_step = self.params.STEER_STEP if CC.latActive else self.params.INACTIVE_STEER_STEP steer_step = self.params.STEER_STEP if CC.latActive else self.params.INACTIVE_STEER_STEP
@@ -330,35 +112,24 @@ class CarController(CarControllerBase):
else: else:
apply_steer = 0 apply_steer = 0
if (self.CP.flags & GMFlags.CC_LONG.value) and CC.enabled and not CS.out.cruiseState.enabled: # Send 0 so Panda doesn't error
apply_steer = 0
# shift previous steer timestamp
self.prev_steer_ts_ns = self.last_steer_ts_ns
self.last_steer_ts_ns = now_nanos
self.last_steer_frame = self.frame self.last_steer_frame = self.frame
self.apply_steer_last = apply_steer self.apply_steer_last = apply_steer
idx = self.lka_steering_cmd_counter % 4 idx = self.lka_steering_cmd_counter % 4
can_sends.append(gmcan.create_steering_control(self.packer_pt, CanBus.POWERTRAIN, apply_steer, idx, CC.latActive)) can_sends.append(gmcan.create_steering_control(self.packer_pt, CanBus.POWERTRAIN, apply_steer, idx, CC.latActive))
# Update regen_active state and last_regen_paddle_pressed for next loop
self.last_regen_active = regen_active
self.last_regen_paddle_pressed = self.regen_paddle_pressed or self.planner_regen_hold
if paddle_sends:
interval_ns = self.last_steer_ts_ns - self.prev_steer_ts_ns
flush_gap_ns = (PADDLE_STEER_GAP_MIN_NS if interval_ns <= 0 else
max(PADDLE_STEER_GAP_MIN_NS,
min(PADDLE_STEER_GAP_MAX_NS,
min((interval_ns // 2) - PADDLE_SLOT_EARLY_NS, PADDLE_GAP_TARGET_NS))))
if now_nanos - self.last_steer_ts_ns >= flush_gap_ns:
can_sends.extend(paddle_sends)
if self.CP.openpilotLongitudinalControl: if self.CP.openpilotLongitudinalControl:
# Gas/regen, brakes, and UI commands - all at 25Hz # Gas/regen, brakes, and UI commands - all at 25Hz
if self.frame % 4 == 0: if self.frame % 4 == 0:
stopping = actuators.longControlState == LongCtrlState.stopping stopping = actuators.longControlState == LongCtrlState.stopping
# Pitch compensated acceleration;
# TODO: include future pitch (sm['modelDataV2'].orientation.y) to account for long actuator delay
if frogpilot_toggles.long_pitch and len(CC.orientationNED) > 1:
self.pitch.update(CC.orientationNED[1])
self.accel_g = ACCELERATION_DUE_TO_GRAVITY * apply_deadzone(self.pitch.x, PITCH_DEADZONE) # driving uphill is positive pitch
accel += self.accel_g
brake_accel = actuators.accel + self.accel_g * interp(CS.out.vEgo, BRAKE_PITCH_FACTOR_BP, BRAKE_PITCH_FACTOR_V)
at_full_stop = CC.longActive and CS.out.standstill at_full_stop = CC.longActive and CS.out.standstill
near_stop = CC.longActive and (CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE) near_stop = CC.longActive and (CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE)
interceptor_gas_cmd = 0 interceptor_gas_cmd = 0
@@ -370,33 +141,21 @@ class CarController(CarControllerBase):
self.apply_gas = self.params.INACTIVE_REGEN self.apply_gas = self.params.INACTIVE_REGEN
self.apply_brake = int(min(-100 * frogpilot_toggles.stopAccel, self.params.MAX_BRAKE)) self.apply_brake = int(min(-100 * frogpilot_toggles.stopAccel, self.params.MAX_BRAKE))
else: else:
if len(CC.orientationNED) == 3 and CS.out.vEgo > self.CP.vEgoStopping: # Normal operation
accel_due_to_pitch = math.sin(CC.orientationNED[1]) * ACCELERATION_DUE_TO_GRAVITY if self.CP.carFingerprint in EV_CAR:
self.params.update_ev_gas_brake_threshold(CS.out.vEgo)
self.apply_gas = int(round(interp(accel, self.params.EV_GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V)))
self.apply_brake = int(round(interp(brake_accel, self.params.EV_BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V)))
else: else:
accel_due_to_pitch = 0.0 self.apply_gas = int(round(interp(accel, self.params.GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V)))
self.apply_brake = int(round(interp(brake_accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V)))
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)))
brake_accel = min((scaled_torque - BRAKE_SWITCH)/(self.tireRadius*self.mass), 0)
self.apply_gas = int(round(apply_gas_torque))
self.apply_brake = int(round(interp(brake_accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V)))
if self.apply_brake > 0:
self.apply_gas = self.params.INACTIVE_REGEN
# Don't allow any gas above inactive regen while stopping # Don't allow any gas above inactive regen while stopping
# FIXME: brakes aren't applied immediately when enabling at a stop # FIXME: brakes aren't applied immediately when enabling at a stop
if stopping: if stopping:
self.apply_gas = self.params.INACTIVE_REGEN self.apply_gas = self.params.INACTIVE_REGEN
if self.CP.carFingerprint in CC_ONLY_CAR: if self.CP.carFingerprint in CC_ONLY_CAR:
# gas interceptor only used for full long control on cars without ACC # gas interceptor only used for full long control on cars without ACC
interceptor_gas_cmd, press_regen_paddle = self.calc_pedal_command(actuators.accel, CC.longActive, CS.out.vEgo) interceptor_gas_cmd = self.calc_pedal_command(actuators.accel, CC.longActive)
if self.CP.enableGasInterceptor and self.apply_gas > self.params.INACTIVE_REGEN and CS.out.cruiseState.standstill: if self.CP.enableGasInterceptor and self.apply_gas > self.params.INACTIVE_REGEN and CS.out.cruiseState.standstill:
# "Tap" the accelerator pedal to re-engage ACC # "Tap" the accelerator pedal to re-engage ACC
@@ -409,10 +168,7 @@ class CarController(CarControllerBase):
if self.CP.flags & GMFlags.CC_LONG.value: if self.CP.flags & GMFlags.CC_LONG.value:
if CC.longActive and CS.out.cruiseState.enabled and CS.out.vEgo > self.CP.minEnableSpeed: if CC.longActive and CS.out.cruiseState.enabled and CS.out.vEgo > self.CP.minEnableSpeed:
# Using extend instead of append since the message is only sent intermittently # Using extend instead of append since the message is only sent intermittently
can_sends.extend(gmcan.create_gm_cc_spam_command(self.packer_pt, self, CS, actuators, frogpilot_toggles)) can_sends.extend(gmcan.create_gm_cc_spam_command(self.packer_pt, self, CS, actuators))
elif (CS.out.cruiseState.enabled and CC.enabled and self.frame % 52 == 0 and
CS.cruise_buttons == CruiseButtons.UNPRESS and CS.out.gasPressed and CS.out.cruiseState.speed < CS.out.vEgo < hud_v_cruise):
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.DECEL_SET))
if self.CP.enableGasInterceptor: if self.CP.enableGasInterceptor:
can_sends.append(create_gas_interceptor_command(self.packer_pt, interceptor_gas_cmd, idx)) can_sends.append(create_gas_interceptor_command(self.packer_pt, interceptor_gas_cmd, idx))
if self.CP.carFingerprint not in CC_ONLY_CAR: if self.CP.carFingerprint not in CC_ONLY_CAR:
@@ -435,7 +191,7 @@ class CarController(CarControllerBase):
# GasRegenCmdActive needs to be 1 to avoid cruise faults. It describes the ACC state, not actuation # GasRegenCmdActive needs to be 1 to avoid cruise faults. It describes the ACC state, not actuation
can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, CanBus.POWERTRAIN, self.apply_gas, idx, acc_engaged, at_full_stop)) can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, CanBus.POWERTRAIN, self.apply_gas, idx, acc_engaged, at_full_stop))
can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, friction_brake_bus, self.apply_brake, 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)) idx, CC.enabled, near_stop, at_full_stop, self.CP))
# Send dashboard UI commands (ACC status) # Send dashboard UI commands (ACC status)
send_fcw = hud_alert == VisualAlert.fcw send_fcw = hud_alert == VisualAlert.fcw
@@ -446,18 +202,22 @@ class CarController(CarControllerBase):
accel += self.accel_g accel += self.accel_g
# Radar needs to know current speed and yaw rate (50hz), # Radar needs to know current speed and yaw rate (50hz),
# and that ADAS is alive (5hz, previously 10hz) # and that ADAS is alive (10hz)
if not self.CP.radarUnavailable: if not self.CP.radarUnavailable:
tt = self.frame * DT_CTRL tt = self.frame * DT_CTRL
time_and_headlights_step = 20 time_and_headlights_step = 10
if self.frame % time_and_headlights_step == 0: if self.frame % time_and_headlights_step == 0:
idx = (self.frame // time_and_headlights_step) % 4 idx = (self.frame // time_and_headlights_step) % 4
can_sends.append(gmcan.create_adas_time_status(CanBus.OBSTACLE, int((tt - self.start_time) * 60), idx)) can_sends.append(gmcan.create_adas_time_status(CanBus.OBSTACLE, int((tt - self.start_time) * 60), idx))
can_sends.append(gmcan.create_adas_headlights_status(self.packer_obj, CanBus.OBSTACLE)) can_sends.append(gmcan.create_adas_headlights_status(self.packer_obj, CanBus.OBSTACLE))
speed_and_accelerometer_step = 2
if self.frame % speed_and_accelerometer_step == 0:
idx = (self.frame // speed_and_accelerometer_step) % 4
can_sends.append(gmcan.create_adas_steering_status(CanBus.OBSTACLE, idx)) can_sends.append(gmcan.create_adas_steering_status(CanBus.OBSTACLE, idx))
can_sends.append(gmcan.create_adas_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx)) can_sends.append(gmcan.create_adas_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx))
if self.CP.networkLocation == NetworkLocation.gateway and self.frame % (self.params.ADAS_KEEPALIVE_STEP * 2) == 0: if self.CP.networkLocation == NetworkLocation.gateway and self.frame % self.params.ADAS_KEEPALIVE_STEP == 0:
can_sends += gmcan.create_adas_keepalive(CanBus.POWERTRAIN) can_sends += gmcan.create_adas_keepalive(CanBus.POWERTRAIN)
# TODO: integrate this with the code block below? # TODO: integrate this with the code block below?
@@ -485,7 +245,7 @@ class CarController(CarControllerBase):
if self.CP.networkLocation == NetworkLocation.fwdCamera: if self.CP.networkLocation == NetworkLocation.fwdCamera:
# Silence "Take Steering" alert sent by camera, forward PSCMStatus with HandsOffSWlDetectionStatus=1 # Silence "Take Steering" alert sent by camera, forward PSCMStatus with HandsOffSWlDetectionStatus=1
if self.frame % 20 == 0: if self.frame % 10 == 0:
can_sends.append(gmcan.create_pscm_status(self.packer_pt, CanBus.CAMERA, CS.pscm_status)) can_sends.append(gmcan.create_pscm_status(self.packer_pt, CanBus.CAMERA, CS.pscm_status))
new_actuators = actuators.as_builder() new_actuators = actuators.as_builder()
+11 -19
View File
@@ -5,7 +5,7 @@ from openpilot.common.numpy_fast import mean
from opendbc.can.can_define import CANDefine from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.gm.values import DBC, AccState, CanBus, STEER_THRESHOLD, GMFlags, CC_ONLY_CAR, CAMERA_ACC_CAR, SDGM_CAR, CC_REGEN_PADDLE_CAR, CAR from openpilot.selfdrive.car.gm.values import DBC, AccState, CanBus, STEER_THRESHOLD, GMFlags, CC_ONLY_CAR, CAMERA_ACC_CAR, SDGM_CAR
TransmissionType = car.CarParams.TransmissionType TransmissionType = car.CarParams.TransmissionType
NetworkLocation = car.CarParams.NetworkLocation NetworkLocation = car.CarParams.NetworkLocation
@@ -53,13 +53,6 @@ class CarState(CarStateBase):
self.moving_backward = (pt_cp.vl["EBCMWheelSpdRear"]["RLWheelDir"] == 2) or (pt_cp.vl["EBCMWheelSpdRear"]["RRWheelDir"] == 2) self.moving_backward = (pt_cp.vl["EBCMWheelSpdRear"]["RLWheelDir"] == 2) or (pt_cp.vl["EBCMWheelSpdRear"]["RRWheelDir"] == 2)
# Variables used for avoiding LKAS faults # Variables used for avoiding LKAS faults
# Track timestamps for OEM PRNDL2 and Regen Paddle messages (used to sync spoofing timing)
self.prndl2_ts_nanos = pt_cp.ts_nanos["ECMPRDNL2"]["PRNDL2"]
if self.CP.carFingerprint in CC_REGEN_PADDLE_CAR:
self.regen_paddle_ts_nanos = pt_cp.ts_nanos["EBCMRegenPaddle"]["RegenPaddle"]
else:
self.regen_paddle_ts_nanos = 0
self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0
if self.loopback_lka_steering_cmd_updated: if self.loopback_lka_steering_cmd_updated:
self.loopback_lka_steering_cmd_ts_nanos = loopback_cp.ts_nanos["ASCMLKASteeringCmd"]["RollingCounter"] self.loopback_lka_steering_cmd_ts_nanos = loopback_cp.ts_nanos["ASCMLKASteeringCmd"]["RollingCounter"]
@@ -78,7 +71,10 @@ class CarState(CarStateBase):
# sample rear wheel speeds, standstill=True if ECM allows engagement with brake # sample rear wheel speeds, standstill=True if ECM allows engagement with brake
ret.standstill = ret.wheelSpeeds.rl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD ret.standstill = ret.wheelSpeeds.rl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(pt_cp.vl["ECMPRDNL2"]["PRNDL2"], None)) if pt_cp.vl["ECMPRDNL2"]["ManualMode"] == 1:
ret.gearShifter = self.parse_gear_shifter("T")
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: if self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG.value:
ret.brake = pt_cp.vl["EBCMBrakePedalPosition"]["BrakePedalPosition"] / 0xd0 ret.brake = pt_cp.vl["EBCMBrakePedalPosition"]["BrakePedalPosition"] / 0xd0
@@ -96,11 +92,11 @@ class CarState(CarStateBase):
# Regen braking is braking # Regen braking is braking
if self.CP.transmissionType == TransmissionType.direct: if self.CP.transmissionType == TransmissionType.direct:
ret.regenBraking = pt_cp.vl["EBCMRegenPaddle"]["RegenPaddle"] != 0 ret.regenBraking = pt_cp.vl["EBCMRegenPaddle"]["RegenPaddle"] != 0
self.single_pedal_mode = ret.gearShifter == GearShifter.low or pt_cp.vl["EVDriveMode"]["SinglePedalModeActive"] == 1 or (ret.regenBraking and GearShifter.manumatic) or (self.CP.carFingerprint in [CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_BOLT_CC] and self.CP.enableGasInterceptor) self.single_pedal_mode = ret.gearShifter == GearShifter.low or pt_cp.vl["EVDriveMode"]["SinglePedalModeActive"] == 1 or (ret.regenBraking and GearShifter.manumatic)
if self.CP.enableGasInterceptor: if self.CP.enableGasInterceptor:
ret.gas = (pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS"] + pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS2"]) / 2. ret.gas = (pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS"] + pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS2"]) / 2.
threshold = 23 if self.CP.carFingerprint in CAMERA_ACC_CAR else 4 # Panda 595 threshold = 23.65. Set lower to avoid panda blocking messages and GasInterceptor faulting. threshold = 10 if self.CP.carFingerprint in CAMERA_ACC_CAR else 4 # Panda 515 threshold = 10.88. Set lower to avoid panda blocking messages and GasInterceptor faulting.
ret.gasPressed = ret.gas > threshold ret.gasPressed = ret.gas > threshold
else: else:
ret.gas = pt_cp.vl["AcceleratorPedal2"]["AcceleratorPedal2"] / 254. ret.gas = pt_cp.vl["AcceleratorPedal2"]["AcceleratorPedal2"] / 254.
@@ -163,11 +159,7 @@ class CarState(CarStateBase):
if self.CP.carFingerprint in CC_ONLY_CAR: if self.CP.carFingerprint in CC_ONLY_CAR:
ret.accFaulted = False ret.accFaulted = False
ret.cruiseState.speed = pt_cp.vl["ECMCruiseControl"]["CruiseSetSpeed"] * CV.KPH_TO_MS ret.cruiseState.speed = pt_cp.vl["ECMCruiseControl"]["CruiseSetSpeed"] * CV.KPH_TO_MS
# Try ECM first for cars that might have it (like most GMs), fall back to ASCM ret.cruiseState.enabled = pt_cp.vl["ECMCruiseControl"]["CruiseActive"] != 0
try:
ret.cruiseState.enabled = pt_cp.vl["ECMCruiseControl"]["CruiseActive"] != 0
except:
ret.cruiseState.enabled = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCCmdActive"] != 0
if self.CP.enableBsm: if self.CP.enableBsm:
if self.CP.carFingerprint not in SDGM_CAR: if self.CP.carFingerprint not in SDGM_CAR:
@@ -210,7 +202,7 @@ class CarState(CarStateBase):
messages += [ messages += [
("AEBCmd", 10), ("AEBCmd", 10),
] ]
# Include ASCMActiveCruiseControlStatus for all non-SDGM fwdCamera cars if CP.carFingerprint not in CC_ONLY_CAR:
messages += [ messages += [
("ASCMActiveCruiseControlStatus", 25), ("ASCMActiveCruiseControlStatus", 25),
] ]
@@ -238,7 +230,7 @@ class CarState(CarStateBase):
] ]
else: else:
messages += [ messages += [
("ECMPRDNL2", 40), ("ECMPRDNL2", 10),
("AcceleratorPedal2", 33), ("AcceleratorPedal2", 33),
("ECMEngineStatus", 100), ("ECMEngineStatus", 100),
("BCMTurnSignals", 1), ("BCMTurnSignals", 1),
@@ -260,7 +252,7 @@ class CarState(CarStateBase):
if CP.transmissionType == TransmissionType.direct: if CP.transmissionType == TransmissionType.direct:
messages += [ messages += [
("EBCMRegenPaddle", 40), ("EBCMRegenPaddle", 50),
("EVDriveMode", 0), ("EVDriveMode", 0),
] ]
+25 -48
View File
@@ -66,6 +66,7 @@ def create_gas_regen_command(packer, bus, throttle, idx, enabled, at_full_stop):
"GasRegenFullStopActive": at_full_stop, "GasRegenFullStopActive": at_full_stop,
"GasRegenAlwaysOne": 1, "GasRegenAlwaysOne": 1,
"GasRegenAlwaysOne2": 1, "GasRegenAlwaysOne2": 1,
"GasRegenAlwaysOne3": 1,
} }
dat = packer.make_can_msg("ASCMGasRegenCmd", bus, values)[2] dat = packer.make_can_msg("ASCMGasRegenCmd", bus, values)[2]
@@ -176,69 +177,45 @@ def create_lka_icon_command(bus, active, critical, steer):
dat = b"\x00\x00\x00" dat = b"\x00\x00\x00"
return make_can_msg(0x104c006c, dat, bus) return make_can_msg(0x104c006c, dat, bus)
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_prndl2_command(packer, bus, press_regen_paddle): def create_gm_cc_spam_command(packer, controller, CS, actuators):
prndl2_value = 5 if press_regen_paddle else 6 if controller.params_.get_bool("IsMetric"):
manual_mode = 1 if press_regen_paddle else 0 _CV = CV.MS_TO_KPH
values = { RATE_UP_MAX = 0.04
"Byte0": 0x0C, RATE_DOWN_MAX = 0.04
"Byte1": 0x0C, else:
"Byte2": 0x00, _CV = CV.MS_TO_MPH
"PRNDL2": prndl2_value, RATE_UP_MAX = 0.2
"Byte4": 0x00, RATE_DOWN_MAX = 0.2
"ManualMode": manual_mode,
"TransmissionState": 1,
"Byte7": 0x00
}
return packer.make_can_msg("ECMPRDNL2", bus, values)
def create_gm_cc_spam_command(packer, controller, CS, actuators, frogpilot_toggles): accel = actuators.accel * _CV # m/s/s to mph/s
accel = actuators.accel speedSetPoint = int(round(CS.out.cruiseState.speed * _CV))
Vego = CS.out.vEgo
cruiseBtn = CruiseButtons.INIT cruiseBtn = CruiseButtons.INIT
if abs(accel) <= 0.15: if speedSetPoint == CS.CP.minEnableSpeed and accel < -1:
rate = 1
else:
rate = 0.2
MS_CONVERT = CV.MS_TO_KPH if frogpilot_toggles.is_metric else CV.MS_TO_MPH
speedSetPoint = int(round(CS.out.cruiseState.speed * MS_CONVERT))
if accel > 0:
DesiredSetPoint = int(round((Vego * 1.01 + 3 * accel) * MS_CONVERT)) # 1.01 factor to match cluster speed better
else: # accel <= 0
DesiredSetPoint = int(round((Vego * 1.01 + 3 * accel) * MS_CONVERT))
if CS.CP.minEnableSpeed - (DesiredSetPoint / MS_CONVERT) > 3.25:
cruiseBtn = CruiseButtons.CANCEL cruiseBtn = CruiseButtons.CANCEL
controller.apply_speed = 0 controller.apply_speed = 0
elif DesiredSetPoint < speedSetPoint and speedSetPoint > CS.CP.minEnableSpeed * MS_CONVERT + 1: rate = 0.04
elif accel < 0:
cruiseBtn = CruiseButtons.DECEL_SET cruiseBtn = CruiseButtons.DECEL_SET
if speedSetPoint > (CS.out.vEgo * _CV) + 3.0: # If accel is changing directions, bring set speed to current speed as fast as possible
rate = RATE_DOWN_MAX
else:
rate = max(-1 / accel, RATE_DOWN_MAX)
controller.apply_speed = speedSetPoint - 1 controller.apply_speed = speedSetPoint - 1
elif DesiredSetPoint > speedSetPoint: elif accel > 0:
cruiseBtn = CruiseButtons.RES_ACCEL cruiseBtn = CruiseButtons.RES_ACCEL
if speedSetPoint < (CS.out.vEgo * _CV) - 3.0:
rate = RATE_UP_MAX
else:
rate = max(1 / accel, RATE_UP_MAX)
controller.apply_speed = speedSetPoint + 1 controller.apply_speed = speedSetPoint + 1
else: else:
cruiseBtn = CruiseButtons.INIT
controller.apply_speed = speedSetPoint controller.apply_speed = speedSetPoint
rate = float('inf')
# Check rlogs closely - our message shouldn't show up on the pt bus for us # Check rlogs closely - our message shouldn't show up on the pt bus for us
# Or bus 2, since we're forwarding... but I think it does # Or bus 2, since we're forwarding... but I think it does
# TODO: Cleanup the timing - normal is every 30ms...
if (cruiseBtn != CruiseButtons.INIT) and ((controller.frame - controller.last_button_frame) * DT_CTRL > rate): if (cruiseBtn != CruiseButtons.INIT) and ((controller.frame - controller.last_button_frame) * DT_CTRL > rate):
controller.last_button_frame = controller.frame controller.last_button_frame = controller.frame
idx = (CS.buttons_counter + 1) % 4 # Need to predict the next idx for '22-23 EUV idx = (CS.buttons_counter + 1) % 4 # Need to predict the next idx for '22-23 EUV
+31 -58
View File
@@ -27,22 +27,10 @@ CAM_MSG = 0x320 # AEBCmd
ACCELERATOR_POS_MSG = 0xbe ACCELERATOR_POS_MSG = 0xbe
NON_LINEAR_TORQUE_PARAMS = { NON_LINEAR_TORQUE_PARAMS = {
CAR.CHEVROLET_BOLT_EUV: { CAR.CHEVROLET_BOLT_EUV: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178],
"left": [2.6531724862969748, 1.1, 0.1719764879840985, 0.0], CAR.CHEVROLET_BOLT_CC: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178],
"right": [2.8531724862969748, 1.0, 0.1469764879840985, 0.0], CAR.GMC_ACADIA: [4.78003305, 1.0, 0.3122, 0.05591772],
}, CAR.CHEVROLET_SILVERADO: [3.29974374, 1.0, 0.25571356, 0.0465122]
CAR.CHEVROLET_BOLT_CC: {
"left": [2.6531724862969748, 1.1, 0.1719764879840985, 0.0],
"right": [2.8531724862969748, 1.0, 0.1469764879840985, 0.0],
},
CAR.GMC_ACADIA: {
"left": [4.78003305, 1.0, 0.3122, 0.05591772],
"right": [4.78003305, 1.0, 0.3122, 0.05591772],
},
CAR.CHEVROLET_SILVERADO: {
"left": [3.8, 0.81, 0.24, 0.0465122],
"right": [3.8, 0.81, 0.24, 0.0465122],
},
} }
@@ -76,12 +64,10 @@ class CarInterface(CarInterfaceBase):
# This has big effect on the stability about 0 (noise when going straight) # This has big effect on the stability about 0 (noise when going straight)
non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint) non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint)
assert non_linear_torque_params, "The params are not defined" assert non_linear_torque_params, "The params are not defined"
# Left is positive a, b, c, _ = non_linear_torque_params
side_key = "left" if lateral_acceleration >= 0 else "right"
a, b, c, d = non_linear_torque_params[side_key]
sig_input = a * lateral_acceleration sig_input = a * lateral_acceleration
sig = np.sign(sig_input) * (1 / (1 + exp(-fabs(sig_input))) - 0.5) sig = np.sign(sig_input) * (1 / (1 + exp(-fabs(sig_input))) - 0.5)
steer_torque = (sig * b) + (lateral_acceleration * c) + d steer_torque = (sig * b) + (lateral_acceleration * c)
return float(steer_torque) return float(steer_torque)
lataccel_values = np.arange(-5.0, 5.0, 0.01) lataccel_values = np.arange(-5.0, 5.0, 0.01)
@@ -131,37 +117,31 @@ class CarInterface(CarInterfaceBase):
if PEDAL_MSG in fingerprint[0]: if PEDAL_MSG in fingerprint[0]:
ret.enableGasInterceptor = True ret.enableGasInterceptor = True
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_GAS_INTERCEPTOR ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_GAS_INTERCEPTOR
# When a pedal interceptor is present, always use normal longitudinal (block stock cruise)
experimental_long = False
if candidate in EV_CAR: if candidate in EV_CAR:
ret.transmissionType = TransmissionType.direct ret.transmissionType = TransmissionType.direct
else: else:
ret.transmissionType = TransmissionType.automatic ret.transmissionType = TransmissionType.automatic
ret.longitudinalTuning.kiBP = [5., 35., 60.] ret.longitudinalTuning.kiBP = [5., 35.]
if candidate in CAMERA_ACC_CAR: if candidate in CAMERA_ACC_CAR:
# For ACC models with pedal interceptor, behave like CC_ONLY_CAR ret.experimentalLongitudinalAvailable = candidate not in CC_ONLY_CAR
ret.experimentalLongitudinalAvailable = (candidate not in CC_ONLY_CAR) and not ret.enableGasInterceptor
ret.networkLocation = NetworkLocation.fwdCamera ret.networkLocation = NetworkLocation.fwdCamera
ret.radarUnavailable = True # no radar ret.radarUnavailable = True # no radar
# Only use pcmCruise if no pedal interceptor (bolt_cc style behavior) ret.pcmCruise = True
ret.pcmCruise = not ret.enableGasInterceptor
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM
# Use default minEnableSpeed for ACC models (will be overridden by pedal interceptor section if present)
ret.minEnableSpeed = 5 * CV.KPH_TO_MS ret.minEnableSpeed = 5 * CV.KPH_TO_MS
ret.minSteerSpeed = 10 * CV.KPH_TO_MS ret.minSteerSpeed = 10 * CV.KPH_TO_MS
# Tuning for experimental long # Tuning for experimental long
ret.longitudinalTuning.kiV = [0.5, 0.5, 0.5] ret.longitudinalTuning.kiV = [2.0, 1.5]
ret.vEgoStopping = 0.1 ret.vEgoStopping = 0.1
ret.vEgoStarting = 0.1 ret.vEgoStarting = 0.1
ret.stoppingDecelRate = 1.0 # reach brake quickly after enabling ret.stoppingDecelRate = 2.0 # reach brake quickly after enabling
ret.vEgoStopping = 0.25 ret.vEgoStopping = 0.25
ret.vEgoStarting = 0.25 ret.vEgoStarting = 0.25
ret.stopAccel = -0.25
if ret.experimentalLongitudinalAvailable and experimental_long: if ret.experimentalLongitudinalAvailable and experimental_long:
ret.pcmCruise = False ret.pcmCruise = False
@@ -169,7 +149,7 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG
elif candidate in SDGM_CAR: elif candidate in SDGM_CAR:
ret.longitudinalTuning.kiV = [0., 0., 0.] # TODO: tuning ret.longitudinalTuning.kiV = [0., 0.] # TODO: tuning
ret.experimentalLongitudinalAvailable = False ret.experimentalLongitudinalAvailable = False
ret.networkLocation = NetworkLocation.fwdCamera ret.networkLocation = NetworkLocation.fwdCamera
ret.pcmCruise = True ret.pcmCruise = True
@@ -188,7 +168,7 @@ class CarInterface(CarInterfaceBase):
ret.minSteerSpeed = 7 * CV.MPH_TO_MS ret.minSteerSpeed = 7 * CV.MPH_TO_MS
# Tuning # Tuning
ret.longitudinalTuning.kiV = [0.5, 0.5, 0.5] ret.longitudinalTuning.kiV = [2.4, 1.5]
if ret.enableGasInterceptor: if ret.enableGasInterceptor:
# Need to set ASCM long limits when using pedal interceptor, instead of camera ACC long limits # Need to set ASCM long limits when using pedal interceptor, instead of camera ACC long limits
@@ -242,19 +222,11 @@ class CarInterface(CarInterfaceBase):
ret.steerActuatorDelay = 0.2 ret.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
# Bolt-only lateral tuning overrides if ret.enableGasInterceptor:
ret.lateralTuning.torque.kp = 1.03 # ACC Bolts use pedal for full longitudinal control, not just sng
ret.lateralTuning.torque.ki = 1.07 ret.flags |= GMFlags.PEDAL_LONG.value
ret.lateralTuning.torque.kd = 0.93
ret.lateralTuning.torque.kfDEPRECATED = 0.02
# Enable pedal interceptor for ACC models when detected elif candidate == CAR.CHEVROLET_SILVERADO:
if candidate in CAMERA_ACC_CAR and ret.enableGasInterceptor:
# ACC models with pedal interceptor get full pedal longitudinal control
ret.flags |= GMFlags.PEDAL_LONG.value
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_NO_ACC
if candidate == CAR.CHEVROLET_SILVERADO:
# On the Bolt, the ECM and camera independently check that you are either above 5 kph or at a stop # 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. # 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 # TODO: check if this is split by EV/ICE with more platforms in the future
@@ -314,13 +286,13 @@ class CarInterface(CarInterfaceBase):
ret.stoppingControl = True ret.stoppingControl = True
ret.autoResumeSng = True ret.autoResumeSng = True
if candidate in CC_ONLY_CAR or (candidate in CAMERA_ACC_CAR and ret.enableGasInterceptor): #pedal interceptor tuning if candidate in CC_ONLY_CAR:
ret.flags |= GMFlags.PEDAL_LONG.value ret.flags |= GMFlags.PEDAL_LONG.value
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_PEDAL_LONG ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_PEDAL_LONG
# Note: Low speed, stop and go not tested. Should be fairly smooth on highway # Note: Low speed, stop and go not tested. Should be fairly smooth on highway
ret.longitudinalTuning.kiBP = [0., 3., 6., 35.] ret.longitudinalTuning.kiBP = [0.0, 5., 35.]
ret.longitudinalTuning.kiV = [0.125, 0.175, 0.225, 0.33] ret.longitudinalTuning.kiV = [0.0, 0.35, 0.5]
ret.longitudinalTuning.kfDEPRECATED = 0.25 ret.longitudinalTuning.kfDEPRECATED = 0.15
ret.stoppingDecelRate = 0.8 ret.stoppingDecelRate = 0.8
else: # Pedal used for SNG, ACC for longitudinal control otherwise else: # Pedal used for SNG, ACC for longitudinal control otherwise
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG
@@ -337,15 +309,16 @@ class CarInterface(CarInterfaceBase):
ret.openpilotLongitudinalControl = not frogpilot_toggles.disable_openpilot_long ret.openpilotLongitudinalControl = not frogpilot_toggles.disable_openpilot_long
ret.pcmCruise = False ret.pcmCruise = False
if not ret.enableGasInterceptor and candidate in CC_ONLY_CAR: #redneck tuning ret.stoppingDecelRate = 11.18 # == 25 mph/s (.04 rate)
ret.longitudinalTuning.kpBP = [10.7, 10.8, 28.] # 10.7 m/s == 24 mph
ret.longitudinalTuning.kpV = [0., 5., 2.] # set lower end to 0 since we can't drive below that speed ret.longitudinalTuning.deadzoneBP = [0.]
ret.longitudinalTuning.deadzoneBP = [0., 1.] ret.longitudinalTuning.deadzoneV = [0.56] # == 2 km/h/s, 1.25 mph/s
ret.longitudinalTuning.deadzoneV = [0.9, 0.9] # == 2 km/h/s, 1.25 mph/s ret.longitudinalActuatorDelay = 1. # TODO: measure this
ret.longitudinalActuatorDelay = 1. # TODO: measure this
ret.longitudinalTuning.kiBP = [0.] ret.longitudinalTuning.kpBP = [10.7, 10.8, 28.] # 10.7 m/s == 24 mph
ret.longitudinalTuning.kiV = [0.1] ret.longitudinalTuning.kpV = [0., 20., 20.] # set lower end to 0 since we can't drive below that speed
ret.stoppingDecelRate = 11.18 # == 25 mph/s (.04 rate) ret.longitudinalTuning.kiBP = [0.]
ret.longitudinalTuning.kiV = [0.1]
if candidate in CC_ONLY_CAR: if candidate in CC_ONLY_CAR:
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_NO_ACC ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_NO_ACC
+14 -28
View File
@@ -33,53 +33,41 @@ class CarControllerParams:
# Our controller should still keep the 2 second average above # Our controller should still keep the 2 second average above
# -3.5 m/s^2 as per planner limits # -3.5 m/s^2 as per planner limits
ACCEL_MAX = 2. # m/s^2 ACCEL_MAX = 2. # m/s^2
ACCEL_MAX_PLUS = 4. # m/s^2
ACCEL_MIN = -4. # m/s^2 ACCEL_MIN = -4. # m/s^2
def __init__(self, CP): def __init__(self, CP):
# Gas/brake lookups # Gas/brake lookups
self.ZERO_GAS = 6150 # Coasting self.ZERO_GAS = 2048 # Coasting
self.MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen self.MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen
if CP.carFingerprint in CAMERA_ACC_CAR and CP.carFingerprint not in CC_ONLY_CAR: if CP.carFingerprint in CAMERA_ACC_CAR and CP.carFingerprint not in CC_ONLY_CAR:
self.MAX_GAS = 8848 self.MAX_GAS = 3400
self.MAX_GAS_PLUS = 8848 self.MAX_ACC_REGEN = 1514
self.MAX_ACC_REGEN = 5610 self.INACTIVE_REGEN = 1554
self.INACTIVE_REGEN = 5650
# Camera ACC vehicles have no regen while enabled. # Camera ACC vehicles have no regen while enabled.
# Camera transitions to MAX_ACC_REGEN from ZERO_GAS and uses friction brakes instantly # Camera transitions to MAX_ACC_REGEN from ZERO_GAS and uses friction brakes instantly
max_regen_acceleration = 0. max_regen_acceleration = 0.
self.BRAKE_SWITCH_MAX = self.MAX_ACC_REGEN if CP.carFingerprint in EV_CAR else self.ZERO_GAS
elif CP.carFingerprint in SDGM_CAR: elif CP.carFingerprint in SDGM_CAR:
self.MAX_GAS = 8191 self.MAX_GAS = 3400
self.MAX_GAS_PLUS = 8191 self.MAX_ACC_REGEN = 1514
self.MAX_ACC_REGEN = 5500 self.INACTIVE_REGEN = 1554
self.INACTIVE_REGEN = 5500
max_regen_acceleration = 0. max_regen_acceleration = 0.
self.BRAKE_SWITCH = self.ZERO_GAS
else: else:
self.MAX_GAS = 7168 # Safety limit, not ACC max. Stock ACC >8192 from standstill. self.MAX_GAS = 3072 # Safety limit, not ACC max. Stock ACC >4096 from standstill.
self.MAX_GAS_PLUS = 7168 # 8292 uses new bit, possible but not tested. Matches Twilsonco tw-main max self.MAX_ACC_REGEN = 1404 # Max ACC regen is slightly less than max paddle regen
self.MAX_ACC_REGEN = 5500 # Max ACC regen is slightly less than max paddle regen self.INACTIVE_REGEN = 1404
self.INACTIVE_REGEN = 5500
# ICE has much less engine braking force compared to regen in EVs, # ICE has much less engine braking force compared to regen in EVs,
# lower threshold removes some braking deadzone # lower threshold removes some braking deadzone
max_regen_acceleration = -3. if CP.carFingerprint in EV_CAR else -0.1 max_regen_acceleration = -1. if CP.carFingerprint in EV_CAR else -0.1
self.BRAKE_SWITCH_MAX = self.MAX_ACC_REGEN if CP.carFingerprint in EV_CAR else self.ZERO_GAS
self.GAS_LOOKUP_BP = [max_regen_acceleration, 0., self.ACCEL_MAX] self.GAS_LOOKUP_BP = [max_regen_acceleration, 0., self.ACCEL_MAX]
self.GAS_LOOKUP_BP_PLUS = [max_regen_acceleration, 0., self.ACCEL_MAX_PLUS]
self.GAS_LOOKUP_V = [self.MAX_ACC_REGEN, self.ZERO_GAS, self.MAX_GAS] self.GAS_LOOKUP_V = [self.MAX_ACC_REGEN, self.ZERO_GAS, self.MAX_GAS]
self.GAS_LOOKUP_V_PLUS = [self.MAX_ACC_REGEN, self.ZERO_GAS, self.MAX_GAS_PLUS]
self.BRAKE_LOOKUP_BP = [self.ACCEL_MIN, 0.] self.BRAKE_LOOKUP_BP = [self.ACCEL_MIN, max_regen_acceleration]
self.BRAKE_LOOKUP_V = [self.MAX_BRAKE, 0.] self.BRAKE_LOOKUP_V = [self.MAX_BRAKE, 0.]
self.BRAKE_SWITCH_LOOKUP_BP = [0.5, 10]
self.BRAKE_SWITCH_LOOKUP_V = [self.ZERO_GAS, self.BRAKE_SWITCH_MAX]
# determined by letting Volt regen to a stop in L gear from 89mph, # determined by letting Volt regen to a stop in L gear from 89mph,
# and by letting off gas and allowing car to creep, for determining # and by letting off gas and allowing car to creep, for determining
# the positive threshold values at very low speed # the positive threshold values at very low speed
@@ -88,11 +76,10 @@ class CarControllerParams:
def update_ev_gas_brake_threshold(self, v_ego): def update_ev_gas_brake_threshold(self, v_ego):
gas_brake_threshold = interp(v_ego, self.EV_GAS_BRAKE_THRESHOLD_BP, self.EV_GAS_BRAKE_THRESHOLD_V) gas_brake_threshold = interp(v_ego, self.EV_GAS_BRAKE_THRESHOLD_BP, self.EV_GAS_BRAKE_THRESHOLD_V)
self.GAS_LOOKUP_BP_PLUS = [self.max_regen_acceleration, 0., self.ACCEL_MAX_PLUS]
self.EV_GAS_LOOKUP_BP = [gas_brake_threshold, max(0., gas_brake_threshold), self.ACCEL_MAX] self.EV_GAS_LOOKUP_BP = [gas_brake_threshold, max(0., gas_brake_threshold), self.ACCEL_MAX]
self.EV_GAS_LOOKUP_BP_PLUS = [gas_brake_threshold, max(0., gas_brake_threshold), self.ACCEL_MAX_PLUS]
self.EV_BRAKE_LOOKUP_BP = [self.ACCEL_MIN, gas_brake_threshold] self.EV_BRAKE_LOOKUP_BP = [self.ACCEL_MIN, gas_brake_threshold]
@dataclass @dataclass
class GMCarDocs(CarDocs): class GMCarDocs(CarDocs):
package: str = "Adaptive Cruise Control (ACC)" package: str = "Adaptive Cruise Control (ACC)"
@@ -175,7 +162,7 @@ class CAR(Platforms):
GMCarDocs("Chevrolet Silverado 1500 2020-21", "Safety Package II"), GMCarDocs("Chevrolet Silverado 1500 2020-21", "Safety Package II"),
GMCarDocs("GMC Sierra 1500 2020-21", "Driver Alert Package II", video_link="https://youtu.be/5HbNoBLzRwE"), GMCarDocs("GMC Sierra 1500 2020-21", "Driver Alert Package II", video_link="https://youtu.be/5HbNoBLzRwE"),
], ],
GMCarSpecs(mass=2994, wheelbase=3.75, steerRatio=16.3, tireStiffnessFactor=1.0), GMCarSpecs(mass=2450, wheelbase=3.75, steerRatio=16.3, tireStiffnessFactor=1.0),
) )
CHEVROLET_EQUINOX = GMPlatformConfig( CHEVROLET_EQUINOX = GMPlatformConfig(
[GMCarDocs("Chevrolet Equinox 2019-22")], [GMCarDocs("Chevrolet Equinox 2019-22")],
@@ -331,7 +318,6 @@ FW_QUERY_CONFIG = FwQueryConfig(
EV_CAR = {CAR.CHEVROLET_VOLT, CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_BOLT_CC} EV_CAR = {CAR.CHEVROLET_VOLT, CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_BOLT_CC}
CC_ONLY_CAR = {CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_BOLT_CC, CAR.CHEVROLET_EQUINOX_CC, CAR.CHEVROLET_SUBURBAN_CC, CAR.GMC_YUKON_CC, CAR.CADILLAC_CT6_CC, CAR.CHEVROLET_TRAILBLAZER_CC, CAR.CADILLAC_XT5_CC, CAR.CHEVROLET_MALIBU_CC} CC_ONLY_CAR = {CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_BOLT_CC, CAR.CHEVROLET_EQUINOX_CC, CAR.CHEVROLET_SUBURBAN_CC, CAR.GMC_YUKON_CC, CAR.CADILLAC_CT6_CC, CAR.CHEVROLET_TRAILBLAZER_CC, CAR.CADILLAC_XT5_CC, CAR.CHEVROLET_MALIBU_CC}
# CC_ONLY_CAR = set(c for c in CAR if str(c).endswith('_CC')) # CC_ONLY_CAR = set(c for c in CAR if str(c).endswith('_CC'))
CC_REGEN_PADDLE_CAR = {CAR.CHEVROLET_BOLT_CC, CAR.CHEVROLET_BOLT_EUV}
# We're integrated at the Safety Data Gateway Module on these cars # We're integrated at the Safety Data Gateway Module on these cars
SDGM_CAR = {CAR.CADILLAC_XT4, CAR.CHEVROLET_TRAVERSE, CAR.BUICK_BABYENCLAVE} SDGM_CAR = {CAR.CADILLAC_XT4, CAR.CHEVROLET_TRAVERSE, CAR.BUICK_BABYENCLAVE}
+5 -5
View File
@@ -286,11 +286,11 @@ class CarController(CarControllerBase):
self.gas = pcm_accel / self.params.NIDEC_GAS_MAX self.gas = pcm_accel / self.params.NIDEC_GAS_MAX
new_actuators = actuators.as_builder() new_actuators = actuators.as_builder()
new_actuators.speed = self.speed new_actuators.speed = float(self.speed)
new_actuators.accel = self.accel new_actuators.accel = float(self.accel)
new_actuators.gas = self.gas new_actuators.gas = float(self.gas)
new_actuators.brake = self.brake new_actuators.brake = float(self.brake)
new_actuators.steer = self.last_steer new_actuators.steer = float(self.last_steer)
new_actuators.steerOutputCan = apply_steer new_actuators.steerOutputCan = apply_steer
self.frame += 1 self.frame += 1
+3 -3
View File
@@ -76,14 +76,14 @@ def create_brake_command(packer, CAN, apply_brake, pump_on, pcm_override, pcm_ca
return packer.make_can_msg("BRAKE_COMMAND", CAN.pt, values) return packer.make_can_msg("BRAKE_COMMAND", CAN.pt, values)
def create_acc_commands(packer, CAN, enabled, active, accel, gas, stopping_counter, car_fingerprint): def create_acc_commands(packer, CAN, enabled, active, accel, gas, stopping_counter, car_fingerprint, gas_force):
commands = [] commands = []
min_gas_accel = CarControllerParams.BOSCH_GAS_LOOKUP_BP[0] min_gas_accel = CarControllerParams.BOSCH_GAS_LOOKUP_BP[0]
control_on = 5 if enabled else 0 control_on = 5 if enabled else 0
gas_command = gas if active and accel > min_gas_accel else -30000 gas_command = gas if active and gas_force > min_gas_accel else -30000
accel_command = accel if active else 0 accel_command = accel if active else 0
braking = 1 if active and accel < min_gas_accel else 0 braking = 1 if active and gas_force < min_gas_accel else 0
standstill = 1 if active and stopping_counter > 0 else 0 standstill = 1 if active and stopping_counter > 0 else 0
standstill_release = 1 if active and stopping_counter == 0 else 0 standstill_release = 1 if active and stopping_counter == 0 else 0
+7 -4
View File
@@ -85,10 +85,10 @@ class CarInterface(CarInterfaceBase):
ret.longitudinalActuatorDelay = 0.5 # s ret.longitudinalActuatorDelay = 0.5 # s
if candidate in HONDA_BOSCH_RADARLESS: if candidate in HONDA_BOSCH_RADARLESS:
ret.stopAccel = CarControllerParams.BOSCH_ACCEL_MIN # stock uses -4.0 m/s^2 once stopped but limited by safety model ret.stopAccel = CarControllerParams.BOSCH_ACCEL_MIN # stock uses -4.0 m/s^2 once stopped but limited by safety model
else:
# default longitudinal tuning for all hondas # default longitudinal tuning for all hondas
ret.longitudinalTuning.kiBP = [0., 5., 35.] ret.longitudinalTuning.kiBP = [0., 5., 35.]
ret.longitudinalTuning.kiV = [1.2, 0.8, 0.5] ret.longitudinalTuning.kiV = [1.2, 0.8, 0.5]
eps_modified = False eps_modified = False
for fw in car_fw: for fw in car_fw:
@@ -117,6 +117,9 @@ class CarInterface(CarInterfaceBase):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
if candidate == CAR.HONDA_CIVIC_BOSCH:
CarControllerParams.BOSCH_GAS_LOOKUP_V = [0, 750]
elif candidate == CAR.HONDA_ACCORD: elif candidate == CAR.HONDA_ACCORD:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
+3 -3
View File
@@ -37,12 +37,12 @@ EventName = car.CarEvent.EventName
MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS
ACCEL_MAX = 2.0 ACCEL_MAX = 2.0
ACCEL_MIN = -3.5 ACCEL_MIN = -3.5
FRICTION_THRESHOLD = 0.12 FRICTION_THRESHOLD = 0.09
def get_friction_threshold(v_ego): def get_friction_threshold(v_ego):
# Interpolate friction threshold # Interpolate friction threshold from 0.09 at 50 mph to 0.15 at 75 mph
from openpilot.common.numpy_fast import interp from openpilot.common.numpy_fast import interp
return interp(v_ego, [1 * CV.MPH_TO_MS, 75 * CV.MPH_TO_MS], [0.12, 0.3]) return interp(v_ego, [1 * CV.MPH_TO_MS, 75 * CV.MPH_TO_MS], [0.12, 0.25])
TORQUE_PARAMS_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/params.toml') TORQUE_PARAMS_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/params.toml')
TORQUE_OVERRIDE_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/override.toml') TORQUE_OVERRIDE_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/override.toml')
+2 -2
View File
@@ -43,9 +43,9 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"CADILLAC_ESCALADE" = [1.899999976158142, 1.842270016670227, 0.1120000034570694] "CADILLAC_ESCALADE" = [1.899999976158142, 1.842270016670227, 0.1120000034570694]
"CADILLAC_ESCALADE_ESV_2019" = [1.15, 1.3, 0.2] "CADILLAC_ESCALADE_ESV_2019" = [1.15, 1.3, 0.2]
"CADILLAC_XT4" = [1.45, 1.6, 0.2] "CADILLAC_XT4" = [1.45, 1.6, 0.2]
"CHEVROLET_BOLT_EUV" = [2.0, 2.0, 0.09] "CHEVROLET_BOLT_EUV" = [2.0, 2.0, 0.05]
"CHEVROLET_MALIBU_CC" = [1.85, 1.85, 0.075] "CHEVROLET_MALIBU_CC" = [1.85, 1.85, 0.075]
"CHEVROLET_SILVERADO" = [2.014, 1.9, 0.125] "CHEVROLET_SILVERADO" = [1.9, 1.9, 0.112]
"CHEVROLET_TRAILBLAZER" = [1.33, 1.9, 0.16] "CHEVROLET_TRAILBLAZER" = [1.33, 1.9, 0.16]
"CHEVROLET_TRAVERSE" = [1.33, 1.33, 0.18] "CHEVROLET_TRAVERSE" = [1.33, 1.33, 0.18]
"CHEVROLET_EQUINOX" = [2.5, 2.5, 0.05] "CHEVROLET_EQUINOX" = [2.5, 2.5, 0.05]
+6 -1
View File
@@ -44,7 +44,7 @@ CAMERA_OFFSET = 0.04
REPLAY = "REPLAY" in os.environ REPLAY = "REPLAY" in os.environ
SIMULATION = "SIMULATION" in os.environ SIMULATION = "SIMULATION" in os.environ
TESTING_CLOSET = "TESTING_CLOSET" in os.environ TESTING_CLOSET = "TESTING_CLOSET" in os.environ
IGNORE_PROCESSES = {"loggerd", "encoderd", "statsd", "micd", "soundd"} IGNORE_PROCESSES = {"loggerd", "encoderd", "statsd"}
ThermalStatus = log.DeviceState.ThermalStatus ThermalStatus = log.DeviceState.ThermalStatus
State = log.ControlsState.OpenpilotState State = log.ControlsState.OpenpilotState
@@ -117,6 +117,9 @@ class Controls:
self.is_metric = self.params.get_bool("IsMetric") self.is_metric = self.params.get_bool("IsMetric")
self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled") self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled")
# detect sound card presence and ensure successful init
sounds_available = HARDWARE.get_sound_card_online()
car_recognized = self.CP.carName != 'mock' car_recognized = self.CP.carName != 'mock'
# cleanup old params # cleanup old params
@@ -170,6 +173,8 @@ class Controls:
else: else:
self.startup_event = get_startup_event(car_recognized, not self.CP.passive, len(self.CP.carFw) > 0) self.startup_event = get_startup_event(car_recognized, not self.CP.passive, len(self.CP.carFw) > 0)
if not sounds_available:
self.events.add(EventName.soundsUnavailable, static=True)
if not car_recognized: if not car_recognized:
self.events.add(EventName.carUnrecognized, static=True) self.events.add(EventName.carUnrecognized, static=True)
if len(self.CP.carFw) > 0: if len(self.CP.carFw) > 0:
+6 -1
View File
@@ -779,6 +779,11 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
Priority.LOWER, VisualAlert.none, AudibleAlert.none, .2, creation_delay=600.) Priority.LOWER, VisualAlert.none, AudibleAlert.none, .2, creation_delay=600.)
}, },
EventName.soundsUnavailable: {
ET.PERMANENT: NormalPermanentAlert("Speaker not found", "Reboot your Device"),
ET.NO_ENTRY: NoEntryAlert("Speaker not found"),
},
EventName.tooDistracted: { EventName.tooDistracted: {
ET.NO_ENTRY: NoEntryAlert("Distraction Level Too High"), ET.NO_ENTRY: NoEntryAlert("Distraction Level Too High"),
}, },
@@ -977,7 +982,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
"", "",
AlertStatus.normal, AlertSize.full, AlertStatus.normal, AlertSize.full,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5), Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5),
ET.USER_DISABLE: ImmediateDisableAlert("Wrong Gear"), ET.USER_DISABLE: ImmediateDisableAlert("Reverse Gear"),
ET.NO_ENTRY: NoEntryAlert("Reverse Gear"), ET.NO_ENTRY: NoEntryAlert("Reverse Gear"),
}, },
+4 -51
View File
@@ -7,7 +7,6 @@ from openpilot.selfdrive.car.interfaces import FRICTION_THRESHOLD, get_friction_
from openpilot.selfdrive.controls.lib.drive_helpers import MIN_SPEED, get_friction from openpilot.selfdrive.controls.lib.drive_helpers import MIN_SPEED, get_friction
from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.selfdrive.controls.lib.latcontrol import LatControl, MIN_LATERAL_CONTROL_SPEED from openpilot.selfdrive.controls.lib.latcontrol import LatControl, MIN_LATERAL_CONTROL_SPEED
from openpilot.selfdrive.car.gm.values import CAR as GM_CAR
from openpilot.selfdrive.controls.lib.pid import PIDController from openpilot.selfdrive.controls.lib.pid import PIDController
from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
@@ -22,8 +21,8 @@ from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_G
# Additionally, there is friction in the steering wheel that needs # Additionally, there is friction in the steering wheel that needs
# to be overcome to move it at all, this is compensated for too. # to be overcome to move it at all, this is compensated for too.
KP = 0.7 KP = 0.6
KI = 0.35 KI = 0.3
INTERP_SPEEDS = [1, 1.5, 2.0, 3.0, 5, 7.5, 10, 15, 30] INTERP_SPEEDS = [1, 1.5, 2.0, 3.0, 5, 7.5, 10, 15, 30]
KP_INTERP = [250, 120, 65, 30, 11.5, 5.5, 3.5, 2.0, KP] KP_INTERP = [250, 120, 65, 30, 11.5, 5.5, 3.5, 2.0, KP]
@@ -37,12 +36,6 @@ JERK_LOOKAHEAD_SECONDS = 0.19
JERK_GAIN = 0.22 JERK_GAIN = 0.22
LAT_ACCEL_REQUEST_BUFFER_SECONDS = 1.0 LAT_ACCEL_REQUEST_BUFFER_SECONDS = 1.0
VERSION = 2 VERSION = 2
DEBUG_TORQUE_TUNE = False
FF_SCALE_BLEND_LAT_ACCEL = 0.05
DEADZONE_BOOST_LAT_ACCEL = 0.08
UNWIND_D_DES_THRESHOLD = -1.0
UNWIND_LAT_ACCEL_NEAR_ZERO = 0.3
BOLT_CARS = (GM_CAR.CHEVROLET_BOLT_EUV, GM_CAR.CHEVROLET_BOLT_CC)
class LatControlTorque(LatControl): class LatControlTorque(LatControl):
def __init__(self, CP, CI, dt): def __init__(self, CP, CI, dt):
@@ -62,21 +55,6 @@ class LatControlTorque(LatControl):
self.previous_measurement = 0.0 self.previous_measurement = 0.0
self.measurement_rate_filter = FirstOrderFilter(0.0, 1 / (2 * np.pi * (MAX_LAT_JERK_UP - 0.5)), self.dt) self.measurement_rate_filter = FirstOrderFilter(0.0, 1 / (2 * np.pi * (MAX_LAT_JERK_UP - 0.5)), self.dt)
self.low_speed_reset_threshold = max(CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED) self.low_speed_reset_threshold = max(CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED)
self.debug_counter = 0
self.prev_desired_lateral_accel = 0.0
self.is_bolt = CP.carFingerprint in BOLT_CARS
self.torque_ff_scale_pos = 1.0
self.torque_ff_scale_neg = 1.0
self.torque_deadzone_boost_neg = 0.0
self.torque_ki_mult = 1.0
if self.is_bolt:
self.torque_ff_scale_pos = float(self.torque_params.kp)
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:
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): def update_live_torque_params(self, latAccelFactor, latAccelOffset, friction):
self.torque_params.latAccelFactor = latAccelFactor self.torque_params.latAccelFactor = latAccelFactor
@@ -98,7 +76,6 @@ class LatControlTorque(LatControl):
self.previous_measurement = 0.0 self.previous_measurement = 0.0
self.measurement_rate_filter.x = 0.0 self.measurement_rate_filter.x = 0.0
self.lat_accel_request_buffer = deque([0.] * self.lat_accel_request_buffer_len , maxlen=self.lat_accel_request_buffer_len) self.lat_accel_request_buffer = deque([0.] * self.lat_accel_request_buffer_len , maxlen=self.lat_accel_request_buffer_len)
self.prev_desired_lateral_accel = 0.0
else: else:
if self.prev_steering_pressed and not CS.steeringPressed: if self.prev_steering_pressed and not CS.steeringPressed:
self.pid.i *= self.steer_release_i_decay self.pid.i *= self.steer_release_i_decay
@@ -117,10 +94,6 @@ class LatControlTorque(LatControl):
desired_lateral_jerk = np.clip(self.jerk_filter.update(raw_lateral_jerk), -MAX_LAT_JERK_UP, MAX_LAT_JERK_UP) desired_lateral_jerk = np.clip(self.jerk_filter.update(raw_lateral_jerk), -MAX_LAT_JERK_UP, MAX_LAT_JERK_UP)
gravity_adjusted_future_lateral_accel = future_desired_lateral_accel - roll_compensation gravity_adjusted_future_lateral_accel = future_desired_lateral_accel - roll_compensation
setpoint = expected_lateral_accel + desired_lateral_jerk * lat_delay setpoint = expected_lateral_accel + desired_lateral_jerk * lat_delay
desired_lateral_accel_rate = (setpoint - self.prev_desired_lateral_accel) / self.dt
unwind_detected = (desired_lateral_accel_rate < UNWIND_D_DES_THRESHOLD and
abs(setpoint) < UNWIND_LAT_ACCEL_NEAR_ZERO)
self.prev_desired_lateral_accel = setpoint
measurement = measured_curvature * CS.vEgo ** 2 measurement = measured_curvature * CS.vEgo ** 2
measurement_rate = self.measurement_rate_filter.update((measurement - self.previous_measurement) / self.dt) measurement_rate = self.measurement_rate_filter.update((measurement - self.previous_measurement) / self.dt)
@@ -137,25 +110,11 @@ class LatControlTorque(LatControl):
ff = gravity_adjusted_future_lateral_accel ff = gravity_adjusted_future_lateral_accel
# latAccelOffset corrects roll compensation bias from device roll misalignment relative to car roll # latAccelOffset corrects roll compensation bias from device roll misalignment relative to car roll
ff -= self.torque_params.latAccelOffset ff -= self.torque_params.latAccelOffset
ff_scale = 1.0 ff += get_friction(error_with_lsf + JERK_GAIN * desired_lateral_jerk, lateral_accel_deadzone, get_friction_threshold(CS.vEgo), self.torque_params)
if self.is_bolt:
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
friction = get_friction(error_with_lsf + JERK_GAIN * desired_lateral_jerk, lateral_accel_deadzone,
get_friction_threshold(CS.vEgo), self.torque_params)
ff += friction
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 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
deadzone_boost_active = True
if CS.vEgo < self.low_speed_reset_threshold: if CS.vEgo < self.low_speed_reset_threshold:
self.pid.reset() self.pid.reset()
freeze_integrator = (steer_limited_by_safety or CS.steeringPressed or freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < self.low_speed_reset_threshold
CS.vEgo < self.low_speed_reset_threshold or unwind_detected)
output_lataccel = self.pid.update(pid_log.error, error_rate=-measurement_rate, speed=CS.vEgo, feedforward=ff, freeze_integrator=freeze_integrator) output_lataccel = self.pid.update(pid_log.error, error_rate=-measurement_rate, speed=CS.vEgo, feedforward=ff, freeze_integrator=freeze_integrator)
output_torque = self.torque_from_lateral_accel(output_lataccel, self.torque_params) output_torque = self.torque_from_lateral_accel(output_lataccel, self.torque_params)
@@ -170,12 +129,6 @@ class LatControlTorque(LatControl):
pid_log.desiredLateralJerk = float(desired_lateral_jerk) pid_log.desiredLateralJerk = float(desired_lateral_jerk)
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_safety, curvature_limited)) pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_safety, curvature_limited))
if DEBUG_TORQUE_TUNE and self.is_bolt:
self.debug_counter += 1
if self.debug_counter % 50 == 0:
print(f"bolt_torque ff_scale={ff_scale:.3f} pos={self.torque_ff_scale_pos:.3f} "
f"neg={self.torque_ff_scale_neg:.3f} deadzone_boost_active={deadzone_boost_active}")
self.prev_steering_pressed = CS.steeringPressed self.prev_steering_pressed = CS.steeringPressed
# TODO left is positive in this convention # TODO left is positive in this convention
@@ -17,9 +17,9 @@ from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_UNSET, CONTR
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog
LON_MPC_STEP = 0.2 # first step is 0.2s LON_MPC_STEP = 0.2 # first step is 0.2s
A_CRUISE_MIN = -1.0 A_CRUISE_MIN = -1.2
A_CRUISE_MAX_BP = [0.0, 5., 10., 15., 20., 25., 40.] A_CRUISE_MAX_VALS = [1.6, 1.2, 0.8, 0.6]
A_CRUISE_MAX_VALS = [1.125, 1.125, 1.125, 1.125, 1.25, 1.25, 1.5] A_CRUISE_MAX_BP = [0., 10.0, 25., 40.]
CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N] CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
ALLOW_THROTTLE_THRESHOLD = 0.5 ALLOW_THROTTLE_THRESHOLD = 0.5
MIN_ALLOW_THROTTLE_SPEED = 2.5 MIN_ALLOW_THROTTLE_SPEED = 2.5