mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-24 01:33:46 +08:00
Compare commits
298 Commits
standstill-ui
...
mayhem
| Author | SHA1 | Date | |
|---|---|---|---|
| 535ae098c6 | |||
| 0b26d1c050 | |||
| 7d52c80bf4 | |||
| 50630f121c | |||
| f26c89d6cb | |||
| e88854319c | |||
| 2e53b419d1 | |||
| f4bc8ee6b7 | |||
| 6daefdc0e1 | |||
| 96e578fa71 | |||
| 768a2f324c | |||
| f50b8dabbb | |||
| d9e0345a2b | |||
| 8a505e6677 | |||
| 40b5468615 | |||
| f7418649f8 | |||
| 5d3b0f4ea9 | |||
| 7e773e5373 | |||
| 6d088863a6 | |||
| 6b515db122 | |||
| bdc1532258 | |||
| afe15a9a80 | |||
| 02060a4b67 | |||
| efd25eca90 | |||
| b4f17f35f9 | |||
| a0669247e3 | |||
| be811cbe61 | |||
| 460b61ebe8 | |||
| 7411a11f83 | |||
| a7ad72489b | |||
| e82a4f034b | |||
| a8ec45ec12 | |||
| 0df2444e95 | |||
| 32cf065988 | |||
| 41c680e60c | |||
| fac7554cb6 | |||
| 92bc8ee934 | |||
| 9c30fc2387 | |||
| 3f5dc27170 | |||
| a5fb9a2cff | |||
| 201d0c0476 | |||
| 54e722ff00 | |||
| fb1c2ea1c4 | |||
| 0f43f042fb | |||
| ee1f0bbe83 | |||
| b811825b38 | |||
| ee71b70f24 | |||
| b75b21681d | |||
| 562c5eb58d | |||
| 2798c12c90 | |||
| 19d545b22e | |||
| 36e935c9dc | |||
| cf89678178 | |||
| 88e4004c9a | |||
| 9f0ae1a495 | |||
| f5a5b9e141 | |||
| 057ca874ce | |||
| 497eb3f771 | |||
| 284bb45c0c | |||
| 836b0278eb | |||
| 4ce9be2752 | |||
| 24fc6fe4e5 | |||
| 297ff1973d | |||
| 727985697f | |||
| 59d1581c0a | |||
| 3a86dffa17 | |||
| 9f7dcb68f9 | |||
| 6793c1a4f5 | |||
| f351dbac09 | |||
| 44255d67c2 | |||
| 1ce49be89b | |||
| bdf7bca569 | |||
| d8e292dc94 | |||
| f0601e27ec | |||
| cec9f090c4 | |||
| d08da1ff22 | |||
| 58b028cfc8 | |||
| d7f3037c88 | |||
| 028ee7b3f5 | |||
| 94aff6faed | |||
| b63039ce84 | |||
| aec5590d57 | |||
| abd19df5f4 | |||
| b1dae43ea8 | |||
| 8c32f6d99d | |||
| f6b51e6742 | |||
| d3881e6a77 | |||
| d83b065c53 | |||
| 16c3d5f48a | |||
| d6dc906ff8 | |||
| ea0ef444de | |||
| ea1da70b22 | |||
| ad9aa72979 | |||
| 1382200cda | |||
| 7e8832d672 | |||
| 9cd9a6201c | |||
| 6ee00d3f60 | |||
| d97100bd14 | |||
| bb36fe4287 | |||
| 066a0f2520 | |||
| c5a6e1da9d | |||
| f8cec6f270 | |||
| 544979d652 | |||
| 353672fb6a | |||
| 4101ab9b28 | |||
| 7fb1d854c6 | |||
| d8587bba31 | |||
| ad3bad8b85 | |||
| c91ac533ef | |||
| 32a6af9ac8 | |||
| e84c0e44ab | |||
| d28cd4df8b | |||
| cfd762f0a2 | |||
| 16d6af490a | |||
| 0b37a23c75 | |||
| bf8204e9a2 | |||
| 34813dee41 | |||
| d84518b97f | |||
| 2356823b62 | |||
| ce98b31cbf | |||
| 97881b5c66 | |||
| fc90fcb879 | |||
| 762c54bb2f | |||
| 9910651a9d | |||
| 42a23508b7 | |||
| fbb6eb651c | |||
| e4809535dc | |||
| 63490fe5e6 | |||
| a7b7148c25 | |||
| e50874baca | |||
| ef4f174c8d | |||
| 9c726d99de | |||
| 25a50a2ec3 | |||
| 5d3d5a884b | |||
| 7a3c1ede9a | |||
| d931d3007b | |||
| 05c2a90e16 | |||
| dc581f6300 | |||
| a6c5b43caf | |||
| 3ec82de5fc | |||
| cd08c87a80 | |||
| d8b715799c | |||
| 0bc009f800 | |||
| ff49f332b0 | |||
| f04b561f88 | |||
| 1f237019e7 | |||
| b47c18426d | |||
| 0e5d40fb1b | |||
| 496d36f805 | |||
| 9217bf289c | |||
| 2c2d8b86ab | |||
| c8128d2cde | |||
| 9c85ebc365 | |||
| 8c510f964c | |||
| 35e623c392 | |||
| 5eb6fe2dd9 | |||
| 64bb95e3cf | |||
| 96818d8efc | |||
| c23434b947 | |||
| 2a0053c046 | |||
| f1a256dac0 | |||
| 967fb96167 | |||
| bb4f3b74d9 | |||
| 7dab3a0ceb | |||
| e6b12d612a | |||
| d17a4bd6cb | |||
| 540becea52 | |||
| a71be7c47b | |||
| 7305822e67 | |||
| 6b0e5aed24 | |||
| 6f907e2060 | |||
| 29b777f12c | |||
| 335d6934fb | |||
| 60305edeae | |||
| da305d9da3 | |||
| 624f51aef4 | |||
| ba76832979 | |||
| 49126f29ae | |||
| 2ed92c88ae | |||
| a9771a0e85 | |||
| 1dcac8cfef | |||
| 18ea1dd170 | |||
| 59336096e7 | |||
| 57d7796edb | |||
| 2dc441d621 | |||
| 93ec2a94e6 | |||
| 56564d55c8 | |||
| 322364c1ca | |||
| 838c7fdc9b | |||
| e02d67c153 | |||
| 407e2ea90a | |||
| 712256eac4 | |||
| 1c2aedcc9a | |||
| 9af2969540 | |||
| 8a7946b26c | |||
| 53e0aded4c | |||
| 3ecd8be1f1 | |||
| 0262b934c4 | |||
| 9aeaf593c3 | |||
| 00c64ba805 | |||
| 7d939e1c76 | |||
| 8a4d2b558b | |||
| 0508653a29 | |||
| 2e75486d16 | |||
| 7bd73401cd | |||
| 4a107868cf | |||
| 53766ff6b7 | |||
| 4ee6758b9f | |||
| 4c1317e30d | |||
| 8a68dec71f | |||
| c7efa7fa20 | |||
| bd7394ea33 | |||
| fa7fa6afaf | |||
| 491ec0c0b8 | |||
| 87f1334ce9 | |||
| 140b047e7f | |||
| 21b1bfd600 | |||
| 5da99bc977 | |||
| a30dc40b8a | |||
| 96893d9c36 | |||
| 9be0defc29 | |||
| afc8c6fb4b | |||
| b559b0f827 | |||
| 79e31ff241 | |||
| 1e604fd80e | |||
| 56989a164e | |||
| eaf5d44037 | |||
| 93cb562321 | |||
| 31d3df673a | |||
| c0aa7a7460 | |||
| 498b7f14a9 | |||
| 95b6ecec86 | |||
| 8e6fc9bed3 | |||
| cf7822180b | |||
| f93c536f7e | |||
| d555d1f588 | |||
| 88e297b183 | |||
| 37f5c8ca58 | |||
| 7d53bd5af7 | |||
| 455a8ec11d | |||
| dac0610a19 | |||
| da5b3f829f | |||
| 02960fc8c2 | |||
| 4585938753 | |||
| f777e71c56 | |||
| 0a698d202b | |||
| 63db39082b | |||
| 4f48c2ec27 | |||
| 6faf9bd88a | |||
| a624cf89bb | |||
| e836ed09c8 | |||
| 8cc9c59330 | |||
| a11d064aeb | |||
| 77c82edb44 | |||
| 9a9ac3af77 | |||
| ac8511b211 | |||
| c3ff2e86db | |||
| 98d6a4eac0 | |||
| 5f413b967e | |||
| bdb0da4fa0 | |||
| cabacda0ad | |||
| d8c79a9712 | |||
| 88c259a666 | |||
| 796d081fce | |||
| 6d61feff11 | |||
| 5d0ab0cfb0 | |||
| 6c687a9f5c | |||
| 7a17c21fab | |||
| 1994a0bd16 | |||
| 8a1bfb925c | |||
| 914411fe06 | |||
| c88bebbc3e | |||
| aba65bf755 | |||
| cf1c99cf78 | |||
| 9c51a6024e | |||
| bec246c6ef | |||
| eeab4b8c85 | |||
| a6758eb9e6 | |||
| cdcc8da555 | |||
| 1f9aa83440 | |||
| 15d218677e | |||
| f8934840da | |||
| a888c5602a | |||
| 4134da76ca | |||
| 24b0f37ae7 | |||
| 559a738fe7 | |||
| f20b1f2a4f | |||
| c76b770807 | |||
| 3c0dea5747 | |||
| e47fbd1cb9 | |||
| efdc48980d | |||
| f84f7d4f17 | |||
| aa82ae0bd0 | |||
| 743ff67927 | |||
| 2880189713 | |||
| 2847d0fd8a | |||
| c23aeb9fcd | |||
| 980c85cfb1 |
@@ -165,6 +165,10 @@ jobs:
|
||||
"panda/board/obj/panda_h7.bin.signed"
|
||||
"panda/board/obj/panda_remote.bin.signed"
|
||||
"panda/board/obj/panda_h7_remote.bin.signed"
|
||||
"panda/board/obj/panda_can_ignition_only.bin.signed"
|
||||
"panda/board/obj/panda_h7_can_ignition_only.bin.signed"
|
||||
"panda/board/obj/panda_remote_can_ignition_only.bin.signed"
|
||||
"panda/board/obj/panda_h7_remote_can_ignition_only.bin.signed"
|
||||
"panda/board/obj/panda_jungle_h7.bin.signed"
|
||||
"panda/board/obj/body_h7.bin.signed"
|
||||
)
|
||||
|
||||
@@ -68,6 +68,7 @@ cppcheck_report.txt
|
||||
comma*.sh
|
||||
|
||||
selfdrive/modeld/models/*.pkl
|
||||
!selfdrive/modeld/models/driving_tinygrad.pkl
|
||||
!selfdrive/modeld/models/driving_vision_tinygrad.pkl
|
||||
!selfdrive/modeld/models/driving_policy_tinygrad.pkl
|
||||
!selfdrive/modeld/models/driving_vision_metadata.pkl
|
||||
|
||||
+22
-2
@@ -91,6 +91,13 @@ struct StarPilotCarState @0xf35cc4560bbf6ec2 {
|
||||
cancelPressed @20 :Bool;
|
||||
cancelLongPressed @21 :Bool;
|
||||
cancelVeryLongPressed @22 :Bool;
|
||||
pedalMaxRegen @23 :Bool; # pedal at max regen, driver should use brake for more decel
|
||||
pedalLongActive @24 :Bool; # Pre-AP pedal longitudinal mode is active (enableLongControl)
|
||||
teslaCCEngaged @25 :Bool; # rising edge of stock Tesla CC engaging (no-pedal mode)
|
||||
teslaCCDisengaged @26 :Bool; # falling edge of stock Tesla CC
|
||||
teslaCCNotArmed @27 :Bool; # lateral engaged but DI_cruiseState != STANDBY/ENABLED
|
||||
accelHardCruise @28 :Bool; # current/releasing accel cruise button came from GM hard-press signal
|
||||
decelHardCruise @29 :Bool; # current/releasing decel cruise button came from GM hard-press signal
|
||||
}
|
||||
|
||||
struct StarPilotDeviceState @0xda96579883444c35 {
|
||||
@@ -108,7 +115,11 @@ struct StarPilotModelDataV2 @0x80ae746ee2596b11 {
|
||||
}
|
||||
}
|
||||
|
||||
struct StarPilotOnroadEvent @0xa5cd762cd951a455 {
|
||||
struct StarPilotOnroadEvents @0xa5cd762cd951a455 {
|
||||
events @0 :List(StarPilotOnroadEvent);
|
||||
}
|
||||
|
||||
struct StarPilotOnroadEvent @0xe344718567f9ce71 {
|
||||
name @0 :EventName;
|
||||
|
||||
enable @1 :Bool;
|
||||
@@ -158,6 +169,14 @@ struct StarPilotOnroadEvent @0xa5cd762cd951a455 {
|
||||
switchbackModeInactive @30;
|
||||
lkasEnable @31;
|
||||
lkasDisable @32;
|
||||
lateralManeuver @33;
|
||||
pedalCruiseEnabled @34;
|
||||
pedalCruiseDisabled @35;
|
||||
pedalMaxRegen @36;
|
||||
teslaCCEngaged @37;
|
||||
teslaCCDisengaged @38;
|
||||
teslaCCNotArmed @39;
|
||||
pedalNotCalibrated @40;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +278,8 @@ struct CustomReserved9 @0xa1680744031fdb2d {
|
||||
wallTimeNanos @5 :UInt64;
|
||||
}
|
||||
|
||||
struct CustomReserved10 @0xcb9fd56c7057593a {
|
||||
struct StarPilotLateralManeuverPlanDEPRECATED @0xcb9fd56c7057593a {
|
||||
desiredCurvature @0 :Float32; # 1/m
|
||||
}
|
||||
|
||||
struct CustomReserved11 @0xc2243c65e0340384 {
|
||||
|
||||
Binary file not shown.
+118
-27
@@ -68,12 +68,12 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
||||
longitudinalManeuver @30;
|
||||
steerTempUnavailableSilent @31;
|
||||
resumeRequired @32;
|
||||
preDriverDistracted @33;
|
||||
promptDriverDistracted @34;
|
||||
driverDistracted @35;
|
||||
preDriverUnresponsive @36;
|
||||
promptDriverUnresponsive @37;
|
||||
driverUnresponsive @38;
|
||||
driverDistracted1 @33;
|
||||
driverDistracted2 @34;
|
||||
driverDistracted3 @35;
|
||||
driverUnresponsive1 @36;
|
||||
driverUnresponsive2 @37;
|
||||
driverUnresponsive3 @38;
|
||||
belowSteerSpeed @39;
|
||||
lowBattery @40;
|
||||
accFaulted @41;
|
||||
@@ -130,14 +130,6 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
||||
userBookmark @95;
|
||||
excessiveActuation @96;
|
||||
audioFeedback @97;
|
||||
lateralManeuver @98;
|
||||
pedalCruiseEnabled @99;
|
||||
pedalCruiseDisabled @100;
|
||||
pedalMaxRegen @101;
|
||||
teslaCCEngaged @102;
|
||||
teslaCCDisengaged @103;
|
||||
teslaCCNotArmed @104;
|
||||
pedalNotCalibrated @105;
|
||||
|
||||
soundsUnavailableDEPRECATED @47;
|
||||
}
|
||||
@@ -833,13 +825,30 @@ struct SelfdriveState {
|
||||
alertStatus @5 :AlertStatus;
|
||||
alertSize @6 :AlertSize;
|
||||
alertType @7 :Text;
|
||||
alertSound @8 :Car.CarControl.HUDControl.AudibleAlert;
|
||||
alertSound @13 :AudibleAlert;
|
||||
alertHudVisual @12 :Car.CarControl.HUDControl.VisualAlert;
|
||||
|
||||
# configurable driving settings
|
||||
experimentalMode @10 :Bool;
|
||||
personality @11 :LongitudinalPersonality;
|
||||
|
||||
enum AudibleAlert {
|
||||
none @0;
|
||||
|
||||
engage @1;
|
||||
disengage @2;
|
||||
refuse @3;
|
||||
|
||||
warningSoft @4;
|
||||
warningImmediate @5;
|
||||
|
||||
prompt @6;
|
||||
promptRepeat @7;
|
||||
promptDistracted @8;
|
||||
|
||||
preAlert @9;
|
||||
}
|
||||
|
||||
enum OpenpilotState @0xdbe58b96d2d1ac61 {
|
||||
disabled @0;
|
||||
preEnabled @1;
|
||||
@@ -860,6 +869,10 @@ struct SelfdriveState {
|
||||
mid @2;
|
||||
full @3;
|
||||
}
|
||||
|
||||
deprecated :group {
|
||||
alertSound @8 :Car.CarControl.HUDControl.AudibleAlert;
|
||||
}
|
||||
}
|
||||
|
||||
struct ControlsState @0x97ff69c53601abf1 {
|
||||
@@ -1095,7 +1108,7 @@ struct ModelDataV2 {
|
||||
confidence @23: ConfidenceClass;
|
||||
|
||||
# Model perceived motion
|
||||
temporalPose @21 :Pose;
|
||||
temporalPoseDEPRECATED @21 :Pose;
|
||||
|
||||
# e2e lateral planner
|
||||
action @26: Action;
|
||||
@@ -2179,7 +2192,6 @@ struct DriverStateV2 {
|
||||
rightBlinkProb @8 :Float32;
|
||||
sunglassesProb @9 :Float32;
|
||||
phoneProb @13 :Float32;
|
||||
sleepProb @14 :Float32;
|
||||
notReadyProbDEPRECATED @12 :List(Float32);
|
||||
occludedProbDEPRECATED @10 :Float32;
|
||||
readyProbDEPRECATED @11 :List(Float32);
|
||||
@@ -2221,7 +2233,7 @@ struct DriverStateDEPRECATED @0xb83c6cc593ed0a00 {
|
||||
stdDEPRECATED @2 :Float32;
|
||||
}
|
||||
|
||||
struct DriverMonitoringState @0xb83cda094a1da284 {
|
||||
struct DriverMonitoringStateDEPRECATED @0xb83cda094a1da284 {
|
||||
events @18 :List(OnroadEvent);
|
||||
faceDetected @1 :Bool;
|
||||
isDistracted @2 :Bool;
|
||||
@@ -2239,12 +2251,90 @@ struct DriverMonitoringState @0xb83cda094a1da284 {
|
||||
isActiveMode @16 :Bool;
|
||||
isRHD @4 :Bool;
|
||||
uncertainCount @19 :UInt32;
|
||||
phoneProbOffset @20 :Float32;
|
||||
phoneProbValidCount @21 :UInt32;
|
||||
|
||||
isPreviewDEPRECATED @15 :Bool;
|
||||
rhdCheckedDEPRECATED @5 :Bool;
|
||||
eventsDEPRECATED @0 :List(Car.OnroadEventDEPRECATED);
|
||||
deprecated :group {
|
||||
phoneProbOffset @20 :Float32;
|
||||
phoneProbValidCount @21 :UInt32;
|
||||
isPreview @15 :Bool;
|
||||
rhdChecked @5 :Bool;
|
||||
events @0 :List(Car.OnroadEventDEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
struct DriverMonitoringState {
|
||||
lockout @0 :Bool;
|
||||
lockoutRecoveryPercent @11 :Int8;
|
||||
alert3Count @12 :Int8;
|
||||
noResponseCount @13 :Int8;
|
||||
noResponseForceDecel @14 :Bool;
|
||||
|
||||
alwaysOn @3 :Bool;
|
||||
alwaysOnLockout @4 :Bool;
|
||||
|
||||
alertLevel @5 :AlertLevel;
|
||||
activePolicy @6 :MonitoringPolicy;
|
||||
isRHD @7 :Bool;
|
||||
rhdCalibration @8 :CalibrationState;
|
||||
|
||||
visionPolicyState @9 :VisionPolicyState;
|
||||
wheeltouchPolicyState @10 :WheeltouchPolicyState;
|
||||
|
||||
enum AlertLevel {
|
||||
# ordinal must match the name to prevent bugs
|
||||
# comparing against the raw ordinal value
|
||||
none @0;
|
||||
one @1;
|
||||
two @2;
|
||||
three @3;
|
||||
}
|
||||
|
||||
enum MonitoringPolicy {
|
||||
wheeltouch @0;
|
||||
vision @1;
|
||||
}
|
||||
|
||||
struct VisionPolicyState {
|
||||
awarenessPercent @0 :Int8;
|
||||
awarenessStep @1 :Float32;
|
||||
isDistracted @2 :Bool;
|
||||
distractedTypes @3 :DistractedTypes;
|
||||
|
||||
faceDetected @4 :Bool;
|
||||
pose @5 :Pose;
|
||||
wheeltouchFallbackPercent @6 :Int8;
|
||||
uncertainOffroadAlertPercent @7 :Int8;
|
||||
|
||||
struct DistractedTypes {
|
||||
pose @0: Bool;
|
||||
eye @1: Bool;
|
||||
phone @2: Bool;
|
||||
}
|
||||
|
||||
struct Pose {
|
||||
pitch @0 :Float32;
|
||||
yaw @1 :Float32;
|
||||
pitchCalib @2 :CalibrationState;
|
||||
yawCalib @3 :CalibrationState;
|
||||
calibrated @4 :Bool;
|
||||
uncertainty @5 :Float32;
|
||||
}
|
||||
}
|
||||
|
||||
struct WheeltouchPolicyState {
|
||||
awarenessPercent @0 :Int8;
|
||||
awarenessStep @1 :Float32;
|
||||
driverInteracting @2 :Bool;
|
||||
}
|
||||
|
||||
struct CalibrationState {
|
||||
calibratedPercent @0 :Int8;
|
||||
offset @1 :Float32;
|
||||
}
|
||||
|
||||
deprecated :group {
|
||||
alertCountLockoutPercent @1 :Int8;
|
||||
alertTimeLockoutPercent @2 :Int8;
|
||||
}
|
||||
}
|
||||
|
||||
struct Boot {
|
||||
@@ -2565,7 +2655,7 @@ struct Event {
|
||||
thumbnail @66: Thumbnail;
|
||||
onroadEvents @134: List(OnroadEvent);
|
||||
carParams @69: Car.CarParams;
|
||||
driverMonitoringState @71: DriverMonitoringState;
|
||||
driverMonitoringState @151 :DriverMonitoringState;
|
||||
livePose @129 :LivePose;
|
||||
modelV2 @75 :ModelDataV2;
|
||||
drivingModelData @128 :DrivingModelData;
|
||||
@@ -2614,8 +2704,8 @@ struct Event {
|
||||
userBookmark @93 :UserBookmark;
|
||||
bookmarkButton @148 :UserBookmark;
|
||||
audioFeedback @149 :AudioFeedback;
|
||||
lateralManeuverPlan @150 :LateralManeuverPlan;
|
||||
|
||||
lateralManeuverPlan @150 :LateralManeuverPlan;
|
||||
# *********** debug ***********
|
||||
testJoystick @52 :Joystick;
|
||||
roadEncodeData @86 :EncodeData;
|
||||
@@ -2644,12 +2734,12 @@ struct Event {
|
||||
starpilotCarState @109 :Custom.StarPilotCarState;
|
||||
starpilotDeviceState @110 :Custom.StarPilotDeviceState;
|
||||
starpilotModelV2 @111 :Custom.StarPilotModelDataV2;
|
||||
starpilotOnroadEvents @112 :List(Custom.StarPilotOnroadEvent);
|
||||
starpilotOnroadEvents @112 :Custom.StarPilotOnroadEvents;
|
||||
starpilotPlan @113 :Custom.StarPilotPlan;
|
||||
starpilotRadarState @114 :Custom.StarPilotRadarState;
|
||||
starpilotSelfdriveState @115 :Custom.StarPilotSelfdriveState;
|
||||
customReserved9 @116 :Custom.CustomReserved9;
|
||||
customReserved10 @136 :Custom.CustomReserved10;
|
||||
starpilotLateralManeuverPlanDEPRECATED @136 :Custom.StarPilotLateralManeuverPlanDEPRECATED;
|
||||
customReserved11 @137 :Custom.CustomReserved11;
|
||||
customReserved12 @138 :Custom.CustomReserved12;
|
||||
customReserved13 @139 :Custom.CustomReserved13;
|
||||
@@ -2707,5 +2797,6 @@ struct Event {
|
||||
gyroscope2DEPRECATED @100 :SensorEventData;
|
||||
accelerometer2DEPRECATED @101 :SensorEventData;
|
||||
temperatureSensor2DEPRECATED @123 :SensorEventData;
|
||||
driverMonitoringStateDEPRECATED @71 :DriverMonitoringStateDEPRECATED;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
+41
-12
@@ -42,7 +42,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"ExperimentalLongitudinalEnabled", {PERSISTENT, BOOL}},
|
||||
{"ExperimentalMode", {PERSISTENT, BOOL}},
|
||||
{"ExperimentalModeConfirmed", {PERSISTENT, BOOL}},
|
||||
{"PersistChillState", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"PersistExperimentalState", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"PersistedCCStatus", {PERSISTENT, INT, "0", "0"}},
|
||||
{"PersistedCEStatus", {PERSISTENT, INT, "0", "0"}},
|
||||
{"FirmwareQueryDone", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
||||
{"ForcePowerDown", {PERSISTENT, BOOL}},
|
||||
@@ -114,6 +116,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"PandaSomResetTriggered", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||
{"PandaSignatures", {CLEAR_ON_MANAGER_START, BYTES}},
|
||||
{"PrimeType", {PERSISTENT, INT}},
|
||||
{"PriusClusterOffsetMigrated", {PERSISTENT, BOOL, "0", "0"}},
|
||||
{"RecordAudio", {PERSISTENT, BOOL}},
|
||||
{"RecordAudioFeedback", {PERSISTENT, BOOL, "0"}},
|
||||
{"RecordFront", {PERSISTENT, BOOL}},
|
||||
@@ -160,6 +163,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"AggressiveJerkSpeed", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
|
||||
{"AggressiveJerkSpeedDecrease", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
|
||||
{"AlertVolumeControl", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"AllowImpossibleAcceleration", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||
{"AlwaysOnLateral", {PERSISTENT, BOOL, "1", "0", 0}},
|
||||
{"AlwaysOnLateralLKAS", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"ApiCache_DriveStats", {PERSISTENT, JSON, "{}", "{}"}},
|
||||
@@ -168,6 +172,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"AvailableModelNames", {PERSISTENT, STRING, "", "", 1}},
|
||||
{"AvailableModelSeries", {PERSISTENT, STRING, "", "", 1}},
|
||||
{"AvailableModels", {PERSISTENT, STRING, "", "", 1}},
|
||||
{"AvailableModelArtifactFormats", {PERSISTENT, STRING, "", "", 1}},
|
||||
{"BlacklistedModels", {PERSISTENT, STRING, "", "", 2}},
|
||||
{"BootLogo", {PERSISTENT, STRING, "starpilot", "stock", 0}},
|
||||
{"BuildMetadata", {PERSISTENT, STRING, "", "", 0}},
|
||||
@@ -178,6 +183,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"BorderWidth", {PERSISTENT, FLOAT, "100.0", "100.0", 2}},
|
||||
{"CalibratedLateralAcceleration", {PERSISTENT, FLOAT, "2.0", "2.0", 2}},
|
||||
{"CalibrationProgress", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||
{"CameraOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||
{"CameraView", {PERSISTENT, INT, "3", "0", 2}},
|
||||
{"CancelDownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||
{"DisableWideRoad", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||
@@ -195,15 +201,22 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"CESlowerLead", {PERSISTENT, BOOL, "1", "0", 1}},
|
||||
{"CESpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
|
||||
{"CESpeedLead", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
|
||||
{"CCMLead", {PERSISTENT, BOOL, "1", "0", 1}},
|
||||
{"CCMLaunchAssist", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"CCMSetSpeedMargin", {PERSISTENT, FLOAT, "3.0", "0.0", 1}},
|
||||
{"CCMSpeed", {PERSISTENT, FLOAT, "45.0", "0.0", 1}},
|
||||
{"CCMSpeedLead", {PERSISTENT, FLOAT, "35.0", "0.0", 1}},
|
||||
{"CCStatus", {CLEAR_ON_OFFROAD_TRANSITION, INT, "0", "0"}},
|
||||
{"CEStatus", {CLEAR_ON_OFFROAD_TRANSITION, INT, "0", "0"}},
|
||||
{"CEStopLights", {PERSISTENT, BOOL, "1", "0", 1}},
|
||||
{"CEStoppedLead", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"ClusterOffset", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
|
||||
{"ColorScheme", {PERSISTENT, STRING, "frog", "stock", 0}},
|
||||
{"ColorScheme", {PERSISTENT, STRING, "stock", "stock", 0}},
|
||||
{"ColorToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||
{"BootLogoToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||
{"Compass", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"CommunityFavorites", {PERSISTENT, STRING, "", "", 1}},
|
||||
{"ConditionalChill", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"ConditionalExperimental", {PERSISTENT, BOOL, "1", "0", 1}},
|
||||
{"CurvatureData", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
|
||||
{"CurveSpeedController", {PERSISTENT, BOOL, "1", "0", 1}},
|
||||
@@ -227,7 +240,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"AggressivePersonalityProfile", {PERSISTENT, BOOL, "1", "1", 2}},
|
||||
{"StandardPersonalityProfile", {PERSISTENT, BOOL, "1", "1", 2}},
|
||||
{"RelaxedPersonalityProfile", {PERSISTENT, BOOL, "1", "1", 2}},
|
||||
{"CustomThemes", {PERSISTENT, BOOL, "1", "0", 0}},
|
||||
{"CustomThemes", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||
{"CustomUI", {PERSISTENT, BOOL, "1", "0", 1}},
|
||||
{"DebugMode", {CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}},
|
||||
{"DecelerationProfile", {PERSISTENT, INT, "1", "0", 2}},
|
||||
@@ -274,6 +287,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"FlashPanda", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||
{"GMDashSpoofOffsets", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"GMPedalLongitudinal", {PERSISTENT, BOOL, "1", "1", 2}},
|
||||
{"IgnoreIgnitionLine", {PERSISTENT, BOOL, "0", "0"}},
|
||||
{"LongPitch", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"RemoteStartBootsComma", {PERSISTENT, BOOL, "0", "0"}},
|
||||
{"RemapCancelToDistance", {PERSISTENT, BOOL, "0", "0"}},
|
||||
@@ -301,10 +315,12 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"ForceStandstill", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"ForceTorqueController", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||
{"FPSCounter", {PERSISTENT, BOOL, "1", "0", 3}},
|
||||
{"GalaxyDashboardStats", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
|
||||
{"StarPilotApiToken", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
|
||||
{"StarPilotCarParams", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES, "", ""}},
|
||||
{"StarPilotCarParamsPersistent", {PERSISTENT, BYTES, "", ""}},
|
||||
{"StarPilotDongleId", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
|
||||
{"StarPilotFavoriteSlots", {PERSISTENT, JSON, "[]", "[]", 1}},
|
||||
{"StarPilotStats", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
|
||||
{"StarPilotTogglesUpdated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||
{"FrogsGoMoosTweak", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
@@ -320,12 +336,14 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"HideMaxSpeed", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"HideSpeed", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"HideSpeedLimit", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"HideSteeringWheel", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"HigherBitrate", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"HolidayThemes", {PERSISTENT, BOOL, "1", "0", 0}},
|
||||
{"HumanAcceleration", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"CoastUpToLeads", {PERSISTENT, BOOL, "1", "1", 2}},
|
||||
{"PrioritizeSmoothFollowing", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"HumanLaneChanges", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"IconPack", {PERSISTENT, STRING, "frog-animated", "stock", 0}},
|
||||
{"IconPack", {PERSISTENT, STRING, "stock", "stock", 0}},
|
||||
{"IconToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||
{"IncreasedStoppedDistance", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
|
||||
{"IncreasedStoppedDistanceLowVisibility", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
|
||||
@@ -367,12 +385,14 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"LongitudinalManeuverStatus", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON, "{}", "{}"}},
|
||||
{"LongitudinalTune", {PERSISTENT, BOOL, "1", "0", 0}},
|
||||
{"LoudBlindspotAlert", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||
{"LoudBlindspotAlertWhenDisengaged", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||
{"LowVoltageShutdown", {PERSISTENT, FLOAT, "11.8", "11.8", 3}},
|
||||
{"MainCruiseButtonControl", {PERSISTENT, INT, "9", "9", 2}},
|
||||
{"MainCruiseButtonControl", {PERSISTENT, INT, "0", "0", 2}},
|
||||
{"ManualUpdateInitiated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||
{"AMapKey1", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
|
||||
{"AMapKey2", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
|
||||
{"ApiCache_NavDestinations", {PERSISTENT, JSON, "[]", "[]"}},
|
||||
{"FavoriteDestinations", {PERSISTENT, JSON, "[]", "[]"}},
|
||||
{"MapAcceleration", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"MapboxPublicKey", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
|
||||
{"MapBoxRequests", {PERSISTENT, JSON, "{}", "{}"}},
|
||||
@@ -384,6 +404,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"MapSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
|
||||
{"NavDesiresAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"NavLongitudinalAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"ClearNavOnOffroad", {PERSISTENT, BOOL, "1", "1", 2}},
|
||||
{"NavDestination", {PERSISTENT | CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||
{"NavInstructionCollapsed", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}},
|
||||
{"NavInstructionState", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON, "{}", "{}"}},
|
||||
@@ -407,6 +428,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"ModelToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||
{"ModelUI", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"ModelVersions", {PERSISTENT, STRING, "", "", 1}},
|
||||
{"ModelManifestVersion", {PERSISTENT, STRING, "", "", 1}},
|
||||
{"NavigationUI", {PERSISTENT, BOOL, "1", "0", 1}},
|
||||
{"NNFF", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"NNFFLite", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
@@ -415,6 +437,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"NoLogging", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"NoUploads", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"NudgelessLaneChange", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||
{"NudgelessLaneChangeOnlyWhenEngaged", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"NumericalTemp", {PERSISTENT, BOOL, "1", "0", 3}},
|
||||
{"Offset1", {PERSISTENT, FLOAT, "5.0", "0.0", 0}},
|
||||
{"Offset2", {PERSISTENT, FLOAT, "5.0", "0.0", 0}},
|
||||
@@ -438,8 +461,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"PauseLateralSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
|
||||
{"LateralResumeDelay", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
|
||||
{"PedalsOnUI", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"PondPaired", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||
{"PondUploadPending", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||
{"GalaxyPaired", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||
{"GalaxyUploadPending", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||
{"PreferredSchedule", {PERSISTENT, INT, "2", "0", 0}},
|
||||
{"PreviousSpeedLimit", {PERSISTENT, FLOAT, "0.0", "0.0"}},
|
||||
{"PromptDistractedVolume", {PERSISTENT, INT, "101", "101", 2}},
|
||||
@@ -447,7 +470,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"QOLLateral", {PERSISTENT, BOOL, "1", "0", 1}},
|
||||
{"QOLLongitudinal", {PERSISTENT, BOOL, "1", "0", 1}},
|
||||
{"QOLVisuals", {PERSISTENT, BOOL, "1", "0", 0}},
|
||||
{"RadarTakeoffs", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"RadarTakeoffs", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"RadarTracksUI", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||
{"RainbowPath", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"RandomEvents", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
@@ -486,6 +509,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"SetSpeedLimit", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"SetSpeedOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
|
||||
{"ShowCEMStatus", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"ShowCCMStatus", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"ShowCPU", {PERSISTENT, BOOL, "1", "0", 3}},
|
||||
{"ShowCSCStatus", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"ShowGPU", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||
@@ -502,7 +526,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"ShowStorageUsed", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||
{"SidebarMetrics", {PERSISTENT, BOOL, "1", "0", 3}},
|
||||
{"SidebarOpen", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||
{"SignalAnimation", {PERSISTENT, STRING, "frog", "stock", 0}},
|
||||
{"SignalAnimation", {PERSISTENT, STRING, "stock", "stock", 0}},
|
||||
{"SignalMetrics", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||
{"SignalToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||
{"SimpleMode", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||
@@ -520,7 +544,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"SLCPriority1", {PERSISTENT, STRING, "Map Data", "Map Data", 2}},
|
||||
{"SLCPriority2", {PERSISTENT, STRING, "Dashboard", "Dashboard", 2}},
|
||||
{"SNGHack", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"SoundPack", {PERSISTENT, STRING, "frog", "stock", 0}},
|
||||
{"SoundPack", {PERSISTENT, STRING, "stock", "stock", 0}},
|
||||
{"SoundToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||
{"SLCAdoptSpeedLimit", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||
{"SLCForceCruiseSpeed", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
|
||||
@@ -545,8 +569,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"StandbyMode", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"StartAccel", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||
{"StartAccelStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||
{"StartupMessageBottom", {PERSISTENT, STRING, "Human-tested, frog-approved 🐸", "Always keep hands on wheel and eyes on road", 0}},
|
||||
{"StartupMessageTop", {PERSISTENT, STRING, "Hop in and buckle up!", "Be ready to take over at any time", 0}},
|
||||
{"StartupMessageBottom", {PERSISTENT, STRING, "Always keep hands on wheel and eyes on road", "Always keep hands on wheel and eyes on road", 0}},
|
||||
{"StartupMessageTop", {PERSISTENT, STRING, "Be ready to take over at any time", "Be ready to take over at any time", 0}},
|
||||
{"StaticPedalsOnUI", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"SteerDelay", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||
{"SteerDelayStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||
@@ -560,6 +584,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"SteerOffsetStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||
{"SteerRatio", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||
{"SteerRatioStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||
{"StockConfidenceBallWidget", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||
{"StockDongleId", {PERSISTENT, STRING, "", ""}},
|
||||
{"StopAccel", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||
{"StopAccelStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||
@@ -571,6 +596,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"SwitchbackModeCooldown", {PERSISTENT, INT, "5", "0", 2}},
|
||||
{"SwitchbackModeEnabled", {CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}},
|
||||
{"SubaruSNG", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"SubaruSNGManualParkingBrake", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"TacoTune", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"TestAlert", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||
{"TetheringEnabled", {PERSISTENT, INT, "0", "0", 0}},
|
||||
@@ -579,6 +605,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"Timezone", {PERSISTENT, STRING, "", ""}},
|
||||
{"TinygradUpdateAvailable", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"ToyotaDoors", {PERSISTENT, BOOL, "1", "0", 0}},
|
||||
{"TrailerLoad", {PERSISTENT, INT, "0", "0", 2}},
|
||||
{"TrafficFollow", {PERSISTENT, FLOAT, "0.5", "0.5", 2}},
|
||||
{"TrafficJerkAcceleration", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
|
||||
{"TrafficJerkDanger", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
|
||||
@@ -610,12 +637,14 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"VeryLongStarButtonControl", {PERSISTENT, INT, "0", "0", 2}},
|
||||
{"VoltSNG", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"GMAutoHold", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"VoltOnePedalMode", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"ToyotaAutoHold", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"WarningImmediateVolume", {PERSISTENT, INT, "101", "101", 2}},
|
||||
{"WarningSoftVolume", {PERSISTENT, INT, "101", "101", 2}},
|
||||
{"WeatherPresets", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"WeatherToken", {PERSISTENT | DONT_LOG, STRING, "", "", 2}},
|
||||
{"WheelControls", {PERSISTENT, STRING, "", "", 2}},
|
||||
{"WheelIcon", {PERSISTENT, STRING, "frog", "stock", 0}},
|
||||
{"WheelIcon", {PERSISTENT, STRING, "stock", "stock", 0}},
|
||||
{"WheelSpeed", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"WheelToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||
};
|
||||
|
||||
Binary file not shown.
+32
@@ -1,8 +1,40 @@
|
||||
import contextlib
|
||||
import gc
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def _prepend_host_pytest_runtime() -> None:
|
||||
if platform.system() != "Darwin" or os.getenv("SP_DISABLE_HOST_PYTEST_REDIRECT") == "1":
|
||||
return
|
||||
|
||||
root_dir = Path(__file__).resolve().parent
|
||||
work_dir = root_dir / ".host_runtime" / "darwin" / "worktree"
|
||||
required_extension = work_dir / "msgq_repo" / "msgq" / "ipc_pyx.so"
|
||||
if not required_extension.exists():
|
||||
return
|
||||
|
||||
extra_paths = [work_dir, work_dir / "starpilot" / "third_party"]
|
||||
extra_paths.extend(sorted(work_dir.glob("*_repo")))
|
||||
acados_dir = work_dir / "third_party" / "acados"
|
||||
if acados_dir.is_dir():
|
||||
extra_paths.append(acados_dir)
|
||||
|
||||
existing = set(sys.path)
|
||||
insert_at = 0
|
||||
for path in [str(p) for p in extra_paths if p.exists()]:
|
||||
if path in existing:
|
||||
continue
|
||||
sys.path.insert(insert_at, path)
|
||||
insert_at += 1
|
||||
|
||||
|
||||
_prepend_host_pytest_runtime()
|
||||
|
||||
from openpilot.common.prefix import OpenpilotPrefix
|
||||
from openpilot.system.manager import manager
|
||||
from openpilot.system.hardware import TICI, HARDWARE
|
||||
|
||||
+2
-1
@@ -4,7 +4,7 @@
|
||||
|
||||
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
||||
|
||||
# 325 Supported Cars
|
||||
# 326 Supported Cars
|
||||
|
||||
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br> |Video|Setup Video|
|
||||
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
@@ -110,6 +110,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Hyundai|Azera 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera 2022">Buy Here</a></sub></details>|||
|
||||
|Hyundai|Azera Hybrid 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera Hybrid 2019">Buy Here</a></sub></details>|||
|
||||
|Hyundai|Azera Hybrid 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera Hybrid 2020">Buy Here</a></sub></details>|||
|
||||
|Hyundai|Azera Hybrid (with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai S connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera Hybrid (with HDA II & LFA2) 2025">Buy Here</a></sub></details>|||
|
||||
|Hyundai|Custin 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Custin 2023">Buy Here</a></sub></details>|||
|
||||
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2017-18">Buy Here</a></sub></details>|||
|
||||
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2019">Buy Here</a></sub></details>|||
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
# StarPilot Unified Model Rebuild
|
||||
|
||||
This workflow rebuilds StarPilot driving and driver-monitoring artifacts for the vendored tinygrad revision. Driving-model behavior versions remain manifest metadata; every runtime driving artifact uses the `tinygrad_single_v1` layout.
|
||||
|
||||
## Safety
|
||||
|
||||
- The supported build device is `comma@192.168.3.110`.
|
||||
- Never run these commands against `192.168.3.109`.
|
||||
- Do not compile normal and big-GPU artifacts together. This workflow builds normal QCOM artifacts only.
|
||||
- Keep source ONNX files and compiled PKLs on the T5 workspace, not the comma.
|
||||
|
||||
## Workspace
|
||||
|
||||
The default workspace is:
|
||||
|
||||
```text
|
||||
/Volumes/T5/StarPilot-Model-Rebuild-2026-06-22/
|
||||
```
|
||||
|
||||
Important directories:
|
||||
|
||||
- `onnx/<model-id>/`: ID-prefixed source ONNX files.
|
||||
- `compiled/`: completed unified driving PKLs.
|
||||
- `driver-monitoring/`: DM ONNX, model PKL, metadata, and camera warps.
|
||||
- `ready-for-resources/`: flat repository-upload handoff.
|
||||
- Oversized models are represented by repository-safe `.p00`, `.p01`, and `.sha256` files in `ready-for-resources/`.
|
||||
- `logs/`: one remote compilation log per model.
|
||||
- `results/`: source and artifact checksum records.
|
||||
- `manifests/`: generated `model_names_v22.json`.
|
||||
|
||||
## Initialize And Extract
|
||||
|
||||
```bash
|
||||
python3 scripts/model_rebuild_pipeline.py init
|
||||
python3 scripts/model_rebuild_pipeline.py extract \
|
||||
--base-manifest /path/to/model_names_v21.json
|
||||
```
|
||||
|
||||
Extraction streams Git blobs directly to disk. LFS pointers are resolved from the local object cache or fetched by object ID, then checked against the pointer SHA-256 and size. Binary ONNX data is never stored in a shell variable.
|
||||
|
||||
To retry one source:
|
||||
|
||||
```bash
|
||||
python3 scripts/model_rebuild_pipeline.py extract \
|
||||
--model pop22 \
|
||||
--base-manifest /path/to/model_names_v21.json
|
||||
```
|
||||
|
||||
Source commits are defined in `scripts/model_source_map_v22.json`.
|
||||
|
||||
## Compile
|
||||
|
||||
Compile one model:
|
||||
|
||||
```bash
|
||||
python3 scripts/model_rebuild_pipeline.py compile \
|
||||
--model pop22 \
|
||||
--base-manifest /path/to/model_names_v21.json
|
||||
```
|
||||
|
||||
Compile or resume the full catalog:
|
||||
|
||||
```bash
|
||||
python3 scripts/model_rebuild_pipeline.py compile \
|
||||
--base-manifest /path/to/model_names_v21.json
|
||||
```
|
||||
|
||||
Existing artifacts are skipped unless `--force` is passed. Each model is staged in its own remote input directory, compiled on `.110`, copied back to the T5, hashed, and copied into `ready-for-resources/`. Failures are written to `results/<id>_failure.json`; rerunning the same command resumes incomplete models.
|
||||
|
||||
Validate one or all completed artifacts with synthetic camera inputs on QCOM:
|
||||
|
||||
```bash
|
||||
python3 scripts/model_rebuild_pipeline.py validate \
|
||||
--model pop22 \
|
||||
--base-manifest /path/to/model_names_v21.json
|
||||
```
|
||||
|
||||
The lower-level device compiler also supports direct use:
|
||||
|
||||
```bash
|
||||
./models --model pop22 --input-format split --version v11
|
||||
./models --model deeprl3v2 --input-format supercombo --version v15
|
||||
```
|
||||
|
||||
`--version` records behavioral semantics only. It does not change artifact layout.
|
||||
|
||||
If the compiled PKL exceeds 100 MiB, `./models` automatically keeps the full
|
||||
local PKL and creates 95 MiB upload parts beside it:
|
||||
|
||||
```text
|
||||
deeprl3v2_driving_tinygrad.pkl
|
||||
deeprl3v2_driving_tinygrad.pkl.p00
|
||||
deeprl3v2_driving_tinygrad.pkl.p01
|
||||
deeprl3v2_driving_tinygrad.pkl.sha256
|
||||
```
|
||||
|
||||
To split an already compiled artifact:
|
||||
|
||||
```bash
|
||||
./models --split-artifact /path/to/deeprl3v2_driving_tinygrad.pkl \
|
||||
--output-dir /path/to/upload-ready
|
||||
```
|
||||
|
||||
Upload only the numbered parts and checksum when the full PKL exceeds the
|
||||
repository limit. The downloader reassembles into a temporary file, verifies
|
||||
the companion SHA-256, and atomically installs the final PKL. No manifest field
|
||||
is required for multipart artifacts.
|
||||
|
||||
## Driver Monitoring
|
||||
|
||||
Stage the current DM ONNX in `uncompiledmodels`, then run:
|
||||
|
||||
```bash
|
||||
./models --dm \
|
||||
--input-dir /data/openpilot/uncompiledmodels \
|
||||
--output-dir /tmp/dm_artifacts
|
||||
```
|
||||
|
||||
This builds:
|
||||
|
||||
- `dmonitoring_model_tinygrad.pkl`
|
||||
- `dmonitoring_model_metadata.pkl`
|
||||
- `dm_warp_1928x1208_tinygrad.pkl`
|
||||
- `dm_warp_1344x760_tinygrad.pkl`
|
||||
|
||||
All four files must be updated together.
|
||||
|
||||
## Manifest
|
||||
|
||||
Generate v22 after compilation:
|
||||
|
||||
```bash
|
||||
python3 scripts/model_rebuild_pipeline.py manifest \
|
||||
--base-manifest /path/to/model_names_v21.json
|
||||
```
|
||||
|
||||
The generator preserves existing IDs and behavioral metadata and adds
|
||||
`deeprl3v2`. Manifest v22 implies the unified single-PKL runtime layout.
|
||||
Repository-hosted multipart files are discovered by naming convention, so no
|
||||
size, hash, format, or part-count metadata is required.
|
||||
|
||||
## Runtime Verification
|
||||
|
||||
Compilation validates JIT capture/replay, pickle round-trip, finite outputs, metadata slices, and both camera warps. Before release:
|
||||
|
||||
1. Select representative v8, v11, v12, v15, and supercombo models.
|
||||
2. Confirm `modeld` stays running.
|
||||
3. Confirm finite `modelV2` path, lane-line, lead, pose, and action data.
|
||||
4. Confirm `driverStateV2` on both supported camera resolutions.
|
||||
5. Test download, selection, deletion, randomization, migration, and fallback in QT, raylib/mici, and Galaxy.
|
||||
|
||||
The built-in South Carolina artifact is `selfdrive/modeld/models/driving_tinygrad.pkl`. If migration cannot download the selected v22 artifact, StarPilot switches to that built-in model.
|
||||
+3
-5
@@ -122,7 +122,6 @@ mods = [
|
||||
"msgq.ipc_pyx",
|
||||
"msgq.visionipc.visionipc_pyx",
|
||||
"openpilot.common.transformations.transformations",
|
||||
"openpilot.selfdrive.modeld.models.commonmodel_pyx",
|
||||
"openpilot.selfdrive.pandad.pandad_api_impl",
|
||||
"openpilot.selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx",
|
||||
"openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx",
|
||||
@@ -137,12 +136,11 @@ for mod in mods:
|
||||
|
||||
repo_root = Path.cwd().parents[1]
|
||||
required_files = [
|
||||
repo_root / "selfdrive/modeld/models/driving_vision_metadata.pkl",
|
||||
repo_root / "selfdrive/modeld/models/driving_policy_metadata.pkl",
|
||||
repo_root / "selfdrive/modeld/models/driving_vision_tinygrad.pkl",
|
||||
repo_root / "selfdrive/modeld/models/driving_policy_tinygrad.pkl",
|
||||
repo_root / "selfdrive/modeld/models/driving_tinygrad.pkl",
|
||||
repo_root / "selfdrive/modeld/models/dmonitoring_model_metadata.pkl",
|
||||
repo_root / "selfdrive/modeld/models/dmonitoring_model_tinygrad.pkl",
|
||||
repo_root / "selfdrive/modeld/models/dm_warp_1928x1208_tinygrad.pkl",
|
||||
repo_root / "selfdrive/modeld/models/dm_warp_1344x760_tinygrad.pkl",
|
||||
repo_root / "selfdrive/pandad/pandad_api_impl.so",
|
||||
repo_root / "selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/acados_ocp_solver_pyx.so",
|
||||
repo_root / "selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/libacados_ocp_solver_lat.so",
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ fi
|
||||
export QCOM_PRIORITY=12
|
||||
|
||||
if [ -z "$AGNOS_VERSION" ]; then
|
||||
export AGNOS_VERSION="12.8.16"
|
||||
export AGNOS_VERSION="12.8.17"
|
||||
fi
|
||||
|
||||
export STAGING_ROOT="/data/safe_staging"
|
||||
|
||||
@@ -34,9 +34,11 @@ import requests
|
||||
import zstandard
|
||||
|
||||
from cereal import log
|
||||
from openpilot.tools.lib.auth_config import DEFAULT_API_HOST, KONIK_API_HOST, get_token, normalize_api_host
|
||||
|
||||
|
||||
API_HOST = os.getenv("COMMA_API_HOST", "https://api.commadotai.com").rstrip("/")
|
||||
API_HOST = normalize_api_host(os.getenv("COMMA_API_HOST") or os.getenv("API_HOST") or DEFAULT_API_HOST)
|
||||
API_HOSTS = [API_HOST] if os.getenv("COMMA_API_HOST") or os.getenv("API_HOST") else [DEFAULT_API_HOST, KONIK_API_HOST]
|
||||
ROUTE_ID_RE = re.compile(r"([0-9a-f]{16})/([^/]+)")
|
||||
|
||||
|
||||
@@ -146,12 +148,12 @@ def parse_route_id(raw: str) -> RouteId:
|
||||
return RouteId(dongle_id=dongle_id, log_id=log_id)
|
||||
|
||||
|
||||
def route_url(route: RouteId) -> str:
|
||||
return f"{API_HOST}/v1/route/{quote(route.canonical_name, safe='')}/"
|
||||
def route_url(route: RouteId, api_host: str) -> str:
|
||||
return f"{api_host}/v1/route/{quote(route.canonical_name, safe='')}/"
|
||||
|
||||
|
||||
def route_files_url(route: RouteId) -> str:
|
||||
return f"{API_HOST}/v1/route/{quote(route.canonical_name, safe='')}/files"
|
||||
def route_files_url(route: RouteId, api_host: str) -> str:
|
||||
return f"{api_host}/v1/route/{quote(route.canonical_name, safe='')}/files"
|
||||
|
||||
|
||||
def format_segments(segments: list[int]) -> str:
|
||||
@@ -184,8 +186,13 @@ def relative_posix(path: Path, root: Path) -> str:
|
||||
return path.relative_to(root).as_posix()
|
||||
|
||||
|
||||
def fetch_json(session: requests.Session, url: str, timeout: float) -> Any:
|
||||
response = session.get(url, timeout=timeout, allow_redirects=True)
|
||||
def api_headers(api_host: str) -> dict[str, str] | None:
|
||||
token = get_token(api_host)
|
||||
return {"Authorization": f"JWT {token}"} if token else None
|
||||
|
||||
|
||||
def fetch_json(session: requests.Session, url: str, timeout: float, api_host: str | None = None) -> Any:
|
||||
response = session.get(url, timeout=timeout, allow_redirects=True, headers=api_headers(api_host) if api_host else None)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
@@ -312,24 +319,42 @@ def filename_from_url(url: str) -> str:
|
||||
|
||||
|
||||
def validate_route(route: RouteId, session: requests.Session, timeout: float) -> dict[str, Any]:
|
||||
try:
|
||||
route_meta = fetch_json(session, route_url(route), timeout)
|
||||
except requests.HTTPError as exc:
|
||||
status_code = exc.response.status_code if exc.response is not None else "unknown"
|
||||
raise ValidationError(route, [f"route is not publicly accessible from comma connect (HTTP {status_code})."]) from exc
|
||||
route_meta = None
|
||||
files_payload = None
|
||||
api_host = None
|
||||
not_found_hosts = []
|
||||
|
||||
for candidate_host in API_HOSTS:
|
||||
try:
|
||||
route_meta = fetch_json(session, route_url(route, candidate_host), timeout, candidate_host)
|
||||
except requests.HTTPError as exc:
|
||||
status_code = exc.response.status_code if exc.response is not None else "unknown"
|
||||
if status_code == 404 and len(API_HOSTS) > 1:
|
||||
not_found_hosts.append(candidate_host)
|
||||
continue
|
||||
raise ValidationError(route, [f"route is not publicly accessible from {candidate_host} (HTTP {status_code})."]) from exc
|
||||
|
||||
try:
|
||||
files_payload = fetch_json(session, route_files_url(route, candidate_host), timeout, candidate_host)
|
||||
except requests.HTTPError as exc:
|
||||
status_code = exc.response.status_code if exc.response is not None else "unknown"
|
||||
if status_code == 404 and len(API_HOSTS) > 1:
|
||||
not_found_hosts.append(candidate_host)
|
||||
continue
|
||||
raise ValidationError(route, [f"public route files could not be fetched from {candidate_host} (HTTP {status_code})."]) from exc
|
||||
|
||||
api_host = candidate_host
|
||||
break
|
||||
|
||||
if route_meta is None or files_payload is None or api_host is None:
|
||||
raise ValidationError(route, [f"route was not found on: {', '.join(not_found_hosts) or ', '.join(API_HOSTS)}."])
|
||||
|
||||
if not route_meta.get("is_public", False):
|
||||
raise ValidationError(route, ["route metadata loaded, but `is_public` was false."])
|
||||
|
||||
try:
|
||||
files_payload = fetch_json(session, route_files_url(route), timeout)
|
||||
except requests.HTTPError as exc:
|
||||
status_code = exc.response.status_code if exc.response is not None else "unknown"
|
||||
raise ValidationError(route, [f"public route files could not be fetched from comma connect (HTTP {status_code})."]) from exc
|
||||
|
||||
expected_segments = expected_segment_count(route_meta, files_payload)
|
||||
if expected_segments <= 0:
|
||||
raise ValidationError(route, ["could not determine any route segments from comma connect."])
|
||||
raise ValidationError(route, ["could not determine any route segments from the route API."])
|
||||
|
||||
failures: list[str] = []
|
||||
stream_urls: dict[str, list[Any]] = {}
|
||||
@@ -384,6 +409,7 @@ def validate_route(route: RouteId, session: requests.Session, timeout: float) ->
|
||||
raise ValidationError(route, failures)
|
||||
|
||||
return {
|
||||
"api_host": api_host,
|
||||
"route_meta": route_meta,
|
||||
"files_payload": files_payload,
|
||||
"expected_segments": expected_segments,
|
||||
@@ -532,6 +558,7 @@ def print_validation_summary(route: RouteId, validation: dict[str, Any]) -> None
|
||||
params = validation["params"]
|
||||
map_tiles: MapTileSummary = validation["map_tiles"]
|
||||
print(f"Validated {route.cli_name}")
|
||||
print(f" route API: {validation['api_host']}")
|
||||
print(f" public route: yes")
|
||||
print(f" segments: {validation['expected_segments']}")
|
||||
print(f" VisionSpeedLimitDetection: {params.get('VisionSpeedLimitDetection', '')}")
|
||||
|
||||
@@ -106,7 +106,7 @@ def make_tester_present_msg(addr, bus, subaddr=None, suppress_response=False):
|
||||
return CanData(addr, bytes(dat), bus)
|
||||
|
||||
|
||||
def get_safety_config(safety_model: structs.CarParams.SafetyModel, safety_param: int = None) -> structs.CarParams.SafetyConfig:
|
||||
def get_safety_config(safety_model, safety_param: int = None) -> structs.CarParams.SafetyConfig:
|
||||
ret = structs.CarParams.SafetyConfig()
|
||||
ret.safetyModel = safety_model
|
||||
if safety_param is not None:
|
||||
|
||||
@@ -205,11 +205,6 @@ struct CarState {
|
||||
vehicleSensorsInvalid @52 :Bool; # invalid steering angle readings, etc.
|
||||
lowSpeedAlert @56 :Bool; # lost steering control due to a dynamic min steering speed
|
||||
blockPcmEnable @60 :Bool; # whether to allow PCM to enable this frame
|
||||
pedalMaxRegen @61 :Bool; # pedal at max regen, driver should use brake for more decel
|
||||
pedalLongActive @62 :Bool; # Pre-AP pedal longitudinal mode is active (enableLongControl)
|
||||
teslaCCEngaged @63 :Bool; # rising edge of stock Tesla CC engaging (no-pedal mode)
|
||||
teslaCCDisengaged @64 :Bool; # falling edge of stock Tesla CC
|
||||
teslaCCNotArmed @65 :Bool; # lateral engaged but DI_cruiseState != STANDBY/ENABLED
|
||||
|
||||
# cruise state
|
||||
cruiseState @10 :CruiseState;
|
||||
@@ -640,7 +635,6 @@ struct CarParams {
|
||||
fcaGiorgio @32;
|
||||
rivian @33;
|
||||
volkswagenMeb @34;
|
||||
teslaPreap @35;
|
||||
}
|
||||
|
||||
enum SteerControlType {
|
||||
|
||||
@@ -334,6 +334,9 @@ def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multip
|
||||
CP.carFw = car_fw
|
||||
CP.fingerprintSource = source
|
||||
CP.fuzzyFingerprint = not exact_match
|
||||
post_fingerprint_params = getattr(CarInterface, "apply_post_fingerprint_params", None)
|
||||
if post_fingerprint_params is not None:
|
||||
post_fingerprint_params(CP, candidate, fingerprints, car_fw)
|
||||
|
||||
FPCP: StarPilotCarParams = CarInterface.get_starpilot_params(candidate, fingerprints, car_fw, CP, starpilot_toggles)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ from opendbc.can import CANPacker
|
||||
from opendbc.car import Bus, DT_CTRL
|
||||
from opendbc.car.lateral import apply_meas_steer_torque_limits
|
||||
from opendbc.car.chrysler import chryslercan
|
||||
from opendbc.car.chrysler.values import RAM_CARS, RAM_DT, CarControllerParams, ChryslerFlags
|
||||
from opendbc.car.chrysler.values import RAM_CARS, RAM_DT, CarControllerParams, ChryslerFlags, ChryslerStarPilotFlags
|
||||
from opendbc.car.interfaces import CarControllerBase
|
||||
|
||||
|
||||
@@ -50,7 +50,9 @@ class CarController(CarControllerBase):
|
||||
|
||||
# TODO: can we make this more sane? why is it different for all the cars?
|
||||
lkas_control_bit = self.lkas_control_bit_prev
|
||||
if self.CP.carFingerprint in RAM_DT:
|
||||
if self.FPCP is not None and self.FPCP.flags & ChryslerStarPilotFlags.NO_MIN_STEERING_SPEED:
|
||||
lkas_control_bit = CC.latActive
|
||||
elif self.CP.carFingerprint in RAM_DT:
|
||||
if self.CP.minEnableSpeed <= CS.out.vEgo <= self.CP.minEnableSpeed + 0.5:
|
||||
lkas_control_bit = True
|
||||
if (self.CP.minEnableSpeed >= 14.5) and (CS.out.gearShifter != 2):
|
||||
|
||||
@@ -21,6 +21,7 @@ class ChryslerFlags(IntFlag):
|
||||
|
||||
class ChryslerStarPilotFlags(IntFlag):
|
||||
RAM_HD_ALT_BUTTONS = 1
|
||||
NO_MIN_STEERING_SPEED = 2
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -10,11 +10,13 @@ from opendbc.car.gm.values import (
|
||||
CruiseButtons, GMFlags, GMSafetyFlags,
|
||||
)
|
||||
from opendbc.car.interfaces import CarControllerBase
|
||||
from openpilot.common.pid import PIDController
|
||||
from openpilot.common.params import Params, UnknownKeyName
|
||||
from openpilot.starpilot.common.testing_grounds import testing_ground
|
||||
|
||||
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
||||
NetworkLocation = structs.CarParams.NetworkLocation
|
||||
TransmissionType = structs.CarParams.TransmissionType
|
||||
LongCtrlState = structs.CarControl.Actuators.LongControlState
|
||||
GearShifter = structs.CarState.GearShifter
|
||||
|
||||
@@ -28,14 +30,42 @@ AUTO_HOLD_VOLT_CARS = {
|
||||
CAR.CHEVROLET_VOLT_ASCM,
|
||||
CAR.CHEVROLET_VOLT_CAMERA,
|
||||
}
|
||||
AUTO_HOLD_DRIVE_GEARS = {
|
||||
AUTO_HOLD_DRIVE_GEARS = (
|
||||
GearShifter.drive,
|
||||
GearShifter.low,
|
||||
GearShifter.manumatic,
|
||||
}
|
||||
)
|
||||
AUTO_HOLD_MIN_BRAKE = 80
|
||||
AUTO_HOLD_MAX_BRAKE = 240
|
||||
AUTO_HOLD_MIN_DRIVE_TIME_S = 3.0
|
||||
AUTO_HOLD_STOPPED_SPEED = 0.02
|
||||
AUTO_HOLD_2019_MIN_BRAKE = 100
|
||||
BOLT_ACC_PEDAL_FRICTION_RELEASE_FRAMES = 5
|
||||
BOLT_PEDAL_LONG_ACCEL_LIMIT_BP = [0.0, 1.5, 4.0, 8.0, 15.0, 30.0]
|
||||
BOLT_PEDAL_LONG_ACCEL_LIMIT_V = [-0.93, -1.28, -1.98, -2.58, -2.86, -2.95]
|
||||
VOLT_ONE_PEDAL_DECEL_BP = [0.5 * CV.MPH_TO_MS, 6.0 * CV.MPH_TO_MS]
|
||||
VOLT_ONE_PEDAL_DECEL_V = [-1.0, -1.1]
|
||||
VOLT_ONE_PEDAL_REGEN_PADDLE_DECEL_V = [-1.5, -1.6]
|
||||
VOLT_ONE_PEDAL_MAX_DECEL = min((*VOLT_ONE_PEDAL_DECEL_V, *VOLT_ONE_PEDAL_REGEN_PADDLE_DECEL_V)) - 0.5
|
||||
VOLT_ONE_PEDAL_PID_NEG_LIMIT = -3.5
|
||||
VOLT_ONE_PEDAL_SPEED_ERROR_FACTOR_BP = [1.5, 20.0]
|
||||
VOLT_ONE_PEDAL_SPEED_ERROR_FACTOR_V = [0.4, 0.2]
|
||||
VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_SPEED_FACTOR_BP = [0.0, 10.0 * CV.MPH_TO_MS]
|
||||
VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_SPEED_FACTOR_V = [0.2, 1.0]
|
||||
VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_STEER_FACTOR_BP = [20.0, 120.0]
|
||||
VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_STEER_FACTOR_V = [1.0, 0.2]
|
||||
VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_UP = 0.8 * DT_CTRL * 4
|
||||
VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_DOWN = 0.8 * DT_CTRL * 4
|
||||
VOLT_ONE_PEDAL_ACCEL_PITCH_FACTOR_BP = [4.0, 8.0]
|
||||
VOLT_ONE_PEDAL_ACCEL_PITCH_FACTOR_V = [0.4, 1.0]
|
||||
VOLT_ONE_PEDAL_ACCEL_PITCH_FACTOR_INCLINE_V = [0.2, 1.0]
|
||||
VOLT_ONE_PEDAL_LIFT_BRAKE_BP = [0.0, CarControllerParams.NEAR_STOP_BRAKE_PHASE, 2.0 * CV.MPH_TO_MS]
|
||||
VOLT_ONE_PEDAL_LIFT_BRAKE_V = [AUTO_HOLD_MIN_BRAKE, AUTO_HOLD_MIN_BRAKE, 20.0]
|
||||
VOLT_ONE_PEDAL_LIFT_BRAKE_FRAMES = 8
|
||||
TRUCK_LONG_SMOOTH_CARS = {
|
||||
CAR.CHEVROLET_SILVERADO,
|
||||
CAR.CHEVROLET_SILVERADO_CC,
|
||||
}
|
||||
|
||||
|
||||
def get_stock_cc_active_for_cancel(CP, CS):
|
||||
@@ -51,7 +81,13 @@ def use_interceptor_sng_launch(CP, CS, maneuver_mode=False):
|
||||
launch_speed = max(CP.vEgoStarting, 0.3)
|
||||
if maneuver_mode:
|
||||
launch_speed = max(launch_speed, 2.0)
|
||||
return CS.out.cruiseState.standstill and (CS.out.standstill or CS.out.vEgo < launch_speed)
|
||||
near_stop = CS.out.standstill or CS.out.vEgo < launch_speed
|
||||
if (
|
||||
getattr(CP, "carFingerprint", None) == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL and
|
||||
getattr(CP, "enableGasInterceptorDEPRECATED", False)
|
||||
):
|
||||
return near_stop
|
||||
return CS.out.cruiseState.standstill and near_stop
|
||||
|
||||
|
||||
def should_spoof_dash_speed(CP, starpilot_toggles):
|
||||
@@ -77,6 +113,13 @@ def should_send_acc_dashboard_status(CP, dash_speed_spoof_active):
|
||||
return status_car and (dash_speed_spoof_active or volt_camera_no_camera)
|
||||
|
||||
|
||||
def get_acc_dashboard_status_active(CP, CC):
|
||||
if CC.enabled:
|
||||
return True
|
||||
|
||||
return CP.carFingerprint == CAR.BUICK_LACROSSE_ASCM and CC.latActive
|
||||
|
||||
|
||||
def get_acc_dashboard_fcw_alert(hud_alert, CS):
|
||||
if hud_alert == VisualAlert.fcw:
|
||||
return 0x3
|
||||
@@ -92,29 +135,6 @@ def get_acc_dashboard_fcw_alert(hud_alert, CS):
|
||||
return 0
|
||||
|
||||
|
||||
def get_acc_dashboard_status_values(enabled, target_speed_kph, hud_control, CS):
|
||||
if enabled:
|
||||
return {
|
||||
"ACCCruiseState": 0,
|
||||
"ACCLeadCar": int(hud_control.leadVisible) & 0x1,
|
||||
"ACCResumeButton": 0,
|
||||
"ACCSpeedSetpoint": target_speed_kph,
|
||||
"ACCGapLevel": int(hud_control.leadDistanceBars) & 0x3,
|
||||
"ACCCmdActive": 1,
|
||||
}
|
||||
|
||||
# Replay the stock camera dashboard context when openpilot long is enabled
|
||||
# but openpilot itself is not actively driving the ACC cluster state.
|
||||
return {
|
||||
"ACCCruiseState": int(getattr(CS, "stock_acc_cruise_state", 0)) & 0x7,
|
||||
"ACCLeadCar": int(getattr(CS, "stock_acc_lead_car", 0)) & 0x1,
|
||||
"ACCResumeButton": int(getattr(CS, "stock_acc_resume_button", 0)) & 0x1,
|
||||
"ACCSpeedSetpoint": float(getattr(CS, "stock_acc_speed_setpoint_kph", 0.0)),
|
||||
"ACCGapLevel": int(getattr(CS, "stock_acc_gap_level", 0)) & 0x3,
|
||||
"ACCCmdActive": int(getattr(CS, "stock_acc_cmd_active", 0)) & 0x1,
|
||||
}
|
||||
|
||||
|
||||
ECM_CRUISE_SPOOF_CARS = {
|
||||
CAR.CHEVROLET_BOLT_CC_2017,
|
||||
CAR.CHEVROLET_BOLT_CC_2018_2021,
|
||||
@@ -150,14 +170,56 @@ def get_adas_keepalive_step(CP, is_kaofui_car):
|
||||
return None
|
||||
|
||||
|
||||
def should_send_adas_status(CP, is_kaofui_car):
|
||||
if CP.radarUnavailable:
|
||||
return False
|
||||
|
||||
if not is_kaofui_car:
|
||||
return True
|
||||
|
||||
if CP.carFingerprint in ASCM_INT:
|
||||
return False
|
||||
|
||||
return CP.networkLocation != NetworkLocation.fwdCamera and CP.carFingerprint not in SDGM_CAR
|
||||
|
||||
|
||||
def get_testing_ground_1_brake_switch_bias(v_ego: float) -> int:
|
||||
return int(round(np.interp(v_ego, [0.0, 6.0, 15.0, 30.0], [40.0, 85.0, 130.0, 170.0])))
|
||||
|
||||
|
||||
def shape_truck_positive_accel(accel: float, v_ego: float, enabled: bool) -> float:
|
||||
if not enabled or accel <= 0.0 or v_ego < 12.0:
|
||||
return accel
|
||||
|
||||
low_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.95, 0.88, 0.82, 0.76]))
|
||||
mid_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.98, 0.94, 0.89, 0.84]))
|
||||
|
||||
if accel <= 0.12:
|
||||
return accel * low_scale
|
||||
if accel <= 0.35:
|
||||
return float(np.interp(accel, [0.12, 0.35], [0.12 * low_scale, 0.35 * mid_scale]))
|
||||
if accel <= 0.65:
|
||||
return float(np.interp(accel, [0.35, 0.65], [0.35 * mid_scale, 0.65]))
|
||||
return accel
|
||||
|
||||
|
||||
def get_lka_steering_cmd_counter(next_counter: int, CS) -> int:
|
||||
if getattr(CS, "loopback_lka_steering_cmd_updated", False):
|
||||
return (getattr(CS, "loopback_lka_steering_cmd_counter", next_counter) + 1) % 4
|
||||
if next_counter < 0 and getattr(CS, "loopback_lka_steering_cmd_ts_nanos", 0) == 0:
|
||||
return (getattr(CS, "pt_lka_steering_cmd_counter", next_counter) + 1) % 4
|
||||
return next_counter
|
||||
|
||||
|
||||
def should_send_stock_long_cancel(cancel_counter: int, CS) -> bool:
|
||||
cs_out = getattr(CS, "out", None)
|
||||
return cancel_counter > CAMERA_CANCEL_DELAY_FRAMES and not bool(getattr(cs_out, "accFaulted", False))
|
||||
|
||||
|
||||
def supports_volt_auto_hold(CP, auto_hold_enabled: bool):
|
||||
safety_cfg = getattr(CP, "safetyConfigs", ())
|
||||
safety_param = safety_cfg[0].safetyParam if safety_cfg else 0
|
||||
stock_hold_safety_ready = CP.openpilotLongitudinalControl or bool(safety_param & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value)
|
||||
stock_hold_safety_ready = bool(safety_param & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value)
|
||||
return (
|
||||
auto_hold_enabled and
|
||||
stock_hold_safety_ready and
|
||||
@@ -165,19 +227,67 @@ def supports_volt_auto_hold(CP, auto_hold_enabled: bool):
|
||||
)
|
||||
|
||||
|
||||
def estimate_auto_hold_brake(driver_brake: float, op_brake: float) -> int:
|
||||
def supports_volt_one_pedal(CP, one_pedal_enabled: bool):
|
||||
safety_cfg = getattr(CP, "safetyConfigs", ())
|
||||
safety_param = safety_cfg[0].safetyParam if safety_cfg else 0
|
||||
stock_hold_safety_ready = bool(safety_param & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value)
|
||||
return (
|
||||
one_pedal_enabled and
|
||||
stock_hold_safety_ready and
|
||||
getattr(CP, "transmissionType", None) == TransmissionType.direct and
|
||||
CP.carFingerprint in AUTO_HOLD_VOLT_CARS
|
||||
)
|
||||
|
||||
|
||||
def estimate_auto_hold_brake(driver_brake: float, op_brake: float, CP=None) -> int:
|
||||
driver_hold = np.interp(float(driver_brake), [8.0, 20.0, 40.0, 80.0], [80.0, 110.0, 150.0, 220.0])
|
||||
hold_brake = max(float(op_brake), float(driver_hold))
|
||||
return int(round(np.clip(hold_brake, AUTO_HOLD_MIN_BRAKE, AUTO_HOLD_MAX_BRAKE)))
|
||||
min_brake = AUTO_HOLD_2019_MIN_BRAKE if getattr(CP, "carFingerprint", None) == CAR.CHEVROLET_VOLT_2019 else AUTO_HOLD_MIN_BRAKE
|
||||
return int(round(np.clip(hold_brake, min_brake, AUTO_HOLD_MAX_BRAKE)))
|
||||
|
||||
|
||||
def get_auto_hold_stop_threshold(CP, auto_hold_engaged: bool) -> float:
|
||||
if auto_hold_engaged and getattr(CP, "carFingerprint", None) == CAR.CHEVROLET_VOLT_2019:
|
||||
return CarControllerParams.NEAR_STOP_BRAKE_PHASE
|
||||
return AUTO_HOLD_STOPPED_SPEED
|
||||
|
||||
|
||||
def get_volt_one_pedal_target_decel(v_ego: float) -> float:
|
||||
return float(np.interp(v_ego, VOLT_ONE_PEDAL_DECEL_BP, VOLT_ONE_PEDAL_DECEL_V))
|
||||
|
||||
|
||||
def get_volt_one_pedal_lift_brake(v_ego: float) -> int:
|
||||
if v_ego > VOLT_ONE_PEDAL_LIFT_BRAKE_BP[-1]:
|
||||
return 0
|
||||
|
||||
return int(round(np.interp(v_ego, VOLT_ONE_PEDAL_LIFT_BRAKE_BP, VOLT_ONE_PEDAL_LIFT_BRAKE_V)))
|
||||
|
||||
|
||||
def should_activate_volt_one_pedal(one_pedal_ready: bool, cruise_main: bool, long_active: bool,
|
||||
gas_pressed: bool, brake_pressed: bool, regen_braking: bool,
|
||||
single_pedal_mode: bool, gear_shifter, drive_time_s: float) -> bool:
|
||||
# Volt rear wheel direction bits can falsely report reverse while stopping in L.
|
||||
return (
|
||||
one_pedal_ready and
|
||||
cruise_main and
|
||||
single_pedal_mode and
|
||||
gear_shifter in AUTO_HOLD_DRIVE_GEARS and
|
||||
drive_time_s >= AUTO_HOLD_MIN_DRIVE_TIME_S and
|
||||
not long_active and
|
||||
not gas_pressed and
|
||||
not brake_pressed and
|
||||
not regen_braking
|
||||
)
|
||||
|
||||
|
||||
def should_activate_auto_hold(hold_ready: bool, auto_hold_armed: bool, auto_hold_engaged: bool,
|
||||
brake_pressed: bool, standstill: bool, long_active: bool,
|
||||
regen_braking: bool, v_ego: float) -> bool:
|
||||
stopped = standstill or v_ego < 0.02
|
||||
brake_pressed: bool, gas_pressed: bool, standstill: bool, long_active: bool,
|
||||
regen_braking: bool, v_ego: float, stop_speed_threshold: float=AUTO_HOLD_STOPPED_SPEED) -> bool:
|
||||
stopped = standstill or v_ego < stop_speed_threshold
|
||||
return (
|
||||
hold_ready and
|
||||
(auto_hold_armed or auto_hold_engaged or brake_pressed) and
|
||||
not gas_pressed and
|
||||
stopped and
|
||||
not long_active and
|
||||
not regen_braking
|
||||
@@ -201,6 +311,104 @@ def get_friction_brake_bus(CP):
|
||||
return CanBus.CHASSIS
|
||||
|
||||
|
||||
def supports_bolt_acc_pedal_friction_experiment(CP) -> bool:
|
||||
return (
|
||||
CP.carFingerprint == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL and
|
||||
CP.openpilotLongitudinalControl and
|
||||
CP.enableGasInterceptorDEPRECATED and
|
||||
bool(CP.flags & GMFlags.PEDAL_LONG.value)
|
||||
)
|
||||
|
||||
|
||||
def get_bolt_acc_pedal_friction_brake(apply_brake, full_brake_accel, v_ego, params) -> int:
|
||||
if apply_brake <= 0:
|
||||
return 0
|
||||
|
||||
full_brake_accel = min(full_brake_accel, -0.1)
|
||||
legacy_full_scale = max(-params.ACCEL_MIN, 0.1)
|
||||
corrected_scale = legacy_full_scale / max(-full_brake_accel, 0.1)
|
||||
speed_gain = float(np.interp(v_ego, [0.0, 8.0, 15.0, 25.0], [1.0, 1.08, 1.2, 1.35]))
|
||||
onset_gain = float(np.interp(
|
||||
apply_brake,
|
||||
[0.0, 5.0, 20.0, 60.0, 120.0, 240.0, params.MAX_BRAKE],
|
||||
[0.0, 1.8, 1.65, 1.4, 1.22, 1.08, 1.0],
|
||||
))
|
||||
|
||||
shaped_brake = apply_brake * corrected_scale * speed_gain * onset_gain
|
||||
minimum_brake = float(np.interp(v_ego, [0.0, 6.0, 8.0, 12.0, 18.0, 25.0], [0.0, 0.0, 4.0, 10.0, 20.0, 28.0]))
|
||||
shaped_brake = max(shaped_brake, minimum_brake)
|
||||
|
||||
return int(round(np.clip(shaped_brake, 0, params.MAX_BRAKE)))
|
||||
|
||||
|
||||
def shape_bolt_acc_pedal_low_speed_friction(apply_brake: int, v_ego: float, stopping: bool, active: bool):
|
||||
if apply_brake <= 0:
|
||||
return 0, False
|
||||
|
||||
engage_threshold = float(np.interp(v_ego, [0.0, 1.5, 3.0, 5.0, 8.0], [40.0, 20.0, 12.0, 10.0, 0.0]))
|
||||
release_threshold = float(np.interp(v_ego, [0.0, 1.5, 3.0, 5.0, 8.0], [0.0, 8.0, 6.0, 4.0, 0.0]))
|
||||
|
||||
if not active:
|
||||
if apply_brake < engage_threshold:
|
||||
return 0, False
|
||||
active = True
|
||||
elif apply_brake < release_threshold:
|
||||
return 0, False
|
||||
|
||||
if stopping:
|
||||
stop_fade = float(np.interp(v_ego, [0.0, 0.6, 0.9, 1.2, 1.8, 2.8], [0.0, 0.0, 0.05, 0.12, 0.32, 0.78]))
|
||||
apply_brake = int(round(apply_brake * stop_fade))
|
||||
if apply_brake <= 0 or apply_brake < release_threshold:
|
||||
return 0, False
|
||||
|
||||
return apply_brake, active
|
||||
|
||||
|
||||
def get_bolt_pedal_long_accel_limit(v_ego: float) -> float:
|
||||
return float(np.interp(v_ego, BOLT_PEDAL_LONG_ACCEL_LIMIT_BP, BOLT_PEDAL_LONG_ACCEL_LIMIT_V))
|
||||
|
||||
|
||||
def get_bolt_acc_pedal_planner_brake_switch(v_ego: float, params, tire_radius: float, mass: float,
|
||||
coeff_drag: float, frontal_area: float, air_density: float) -> int:
|
||||
planner_accel_limit = get_bolt_pedal_long_accel_limit(v_ego)
|
||||
aero_drag_force = 0.5 * coeff_drag * frontal_area * air_density * v_ego ** 2
|
||||
planner_torque = tire_radius * ((mass * planner_accel_limit) + aero_drag_force)
|
||||
return int(round(planner_torque + params.ZERO_GAS))
|
||||
|
||||
|
||||
def get_bolt_acc_pedal_effective_brake_switch(stock_switch: int, planner_switch: int) -> int:
|
||||
return max(stock_switch, planner_switch)
|
||||
|
||||
|
||||
def get_bolt_acc_pedal_friction_command_state(apply_brake: int, cruise_main_on: bool, release_frames: int):
|
||||
command_brake = apply_brake if cruise_main_on else 0
|
||||
|
||||
if command_brake > 0:
|
||||
release_frames = BOLT_ACC_PEDAL_FRICTION_RELEASE_FRAMES
|
||||
elif release_frames > 0:
|
||||
release_frames -= 1
|
||||
|
||||
should_send = cruise_main_on or release_frames > 0
|
||||
return command_brake, release_frames, should_send
|
||||
|
||||
|
||||
def get_interceptor_sng_gas_cmd(CP, interceptor_gas_cmd: float, accel: float, params, maneuver_mode: bool) -> float:
|
||||
if maneuver_mode:
|
||||
return max(interceptor_gas_cmd, float(np.interp(accel, [0.0, 1.0, 2.0], [params.SNG_INTERCEPTOR_GAS, 0.11, 0.16])))
|
||||
|
||||
if supports_bolt_acc_pedal_friction_experiment(CP):
|
||||
return max(interceptor_gas_cmd, params.SNG_INTERCEPTOR_GAS)
|
||||
|
||||
return params.SNG_INTERCEPTOR_GAS
|
||||
|
||||
|
||||
def should_use_fixed_stopping_brake(CP, near_stop: bool, stopping: bool, resume: bool) -> bool:
|
||||
if not (near_stop and stopping and not resume):
|
||||
return False
|
||||
|
||||
return not supports_bolt_acc_pedal_friction_experiment(CP)
|
||||
|
||||
|
||||
class CarController(CarControllerBase):
|
||||
def __init__(self, dbc_names, CP):
|
||||
super().__init__(dbc_names, CP)
|
||||
@@ -254,10 +462,59 @@ class CarController(CarControllerBase):
|
||||
self.malibu_button_phase = 0
|
||||
self.malibu_last_button_ts_nanos = 0
|
||||
self.auto_hold_brake = 0
|
||||
self.volt_one_pedal_pid = PIDController(
|
||||
(CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
|
||||
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
|
||||
rate=1 / (DT_CTRL * 4),
|
||||
pos_limit=0.0,
|
||||
neg_limit=VOLT_ONE_PEDAL_PID_NEG_LIMIT,
|
||||
)
|
||||
self.volt_one_pedal_decel = 0.0
|
||||
self.volt_one_pedal_brake = 0
|
||||
self.volt_one_pedal_lift_frames = 0
|
||||
self.volt_one_pedal_gas_pressed_last = False
|
||||
try:
|
||||
self.gm_auto_hold_enabled = self.params_.get_bool("GMAutoHold")
|
||||
except UnknownKeyName:
|
||||
self.gm_auto_hold_enabled = False
|
||||
self.bolt_acc_pedal_friction_release_frames = 0
|
||||
self.bolt_acc_pedal_friction_low_speed_active = False
|
||||
|
||||
def _reset_volt_one_pedal(self):
|
||||
self.volt_one_pedal_pid.reset()
|
||||
self.volt_one_pedal_decel = min(0.0, float(self.aego))
|
||||
self.volt_one_pedal_brake = 0
|
||||
self.volt_one_pedal_lift_frames = 0
|
||||
|
||||
def _update_volt_one_pedal_brake(self, CC, CS):
|
||||
pitch_accel = 0.0
|
||||
if len(CC.orientationNED) == 3 and CS.out.vEgo > self.CP.vEgoStopping:
|
||||
pitch_accel = math.sin(CC.orientationNED[1]) * ACCELERATION_DUE_TO_GRAVITY
|
||||
pitch_factor_values = VOLT_ONE_PEDAL_ACCEL_PITCH_FACTOR_V if pitch_accel <= 0.0 else VOLT_ONE_PEDAL_ACCEL_PITCH_FACTOR_INCLINE_V
|
||||
pitch_accel *= float(np.interp(CS.out.vEgo, VOLT_ONE_PEDAL_ACCEL_PITCH_FACTOR_BP, pitch_factor_values))
|
||||
|
||||
target_decel = get_volt_one_pedal_target_decel(CS.out.vEgo)
|
||||
measured_decel = min(0.0, CS.out.aEgo + pitch_accel)
|
||||
error_factor = float(np.interp(CS.out.vEgo, VOLT_ONE_PEDAL_SPEED_ERROR_FACTOR_BP, VOLT_ONE_PEDAL_SPEED_ERROR_FACTOR_V))
|
||||
error = (target_decel - measured_decel) * error_factor
|
||||
|
||||
raw_decel = float(self.volt_one_pedal_pid.update(error, speed=CS.out.vEgo, feedforward=target_decel))
|
||||
rate_limit_factor = min(
|
||||
float(np.interp(CS.out.vEgo, VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_SPEED_FACTOR_BP, VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_SPEED_FACTOR_V)),
|
||||
float(np.interp(abs(CS.out.steeringAngleDeg), VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_STEER_FACTOR_BP, VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_STEER_FACTOR_V)),
|
||||
)
|
||||
lower = min(self.volt_one_pedal_decel, measured_decel) - VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_UP * rate_limit_factor
|
||||
upper = max(self.volt_one_pedal_decel, measured_decel) + VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_DOWN + rate_limit_factor
|
||||
self.volt_one_pedal_decel = float(np.clip(raw_decel, lower, upper))
|
||||
self.volt_one_pedal_decel = max(self.volt_one_pedal_decel, VOLT_ONE_PEDAL_MAX_DECEL)
|
||||
self.volt_one_pedal_brake = int(round(np.clip(
|
||||
np.interp(self.volt_one_pedal_decel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V),
|
||||
0,
|
||||
self.params.MAX_BRAKE,
|
||||
)))
|
||||
if self.volt_one_pedal_lift_frames > 0:
|
||||
self.volt_one_pedal_brake = max(self.volt_one_pedal_brake, get_volt_one_pedal_lift_brake(CS.out.vEgo))
|
||||
self.volt_one_pedal_lift_frames -= 1
|
||||
|
||||
def calc_pedal_command(self, accel: float, long_active: bool, v_ego: float):
|
||||
if not long_active:
|
||||
@@ -411,7 +668,37 @@ class CarController(CarControllerBase):
|
||||
accel = actuators.accel
|
||||
press_regen_paddle = False
|
||||
auto_hold_enabled = supports_volt_auto_hold(self.CP, self.gm_auto_hold_enabled)
|
||||
stock_hold_apply_brake = self.apply_brake if self.CP.openpilotLongitudinalControl else 0
|
||||
volt_one_pedal_supported = supports_volt_one_pedal(
|
||||
self.CP, bool(getattr(starpilot_toggles, "volt_one_pedal_mode", False))
|
||||
)
|
||||
volt_one_pedal_active = should_activate_volt_one_pedal(
|
||||
volt_one_pedal_supported,
|
||||
CS.out.cruiseState.available,
|
||||
CC.longActive,
|
||||
CS.out.gasPressed,
|
||||
CS.out.brakePressed,
|
||||
CS.out.regenBraking,
|
||||
bool(getattr(CS, "single_pedal_mode", False)),
|
||||
CS.out.gearShifter,
|
||||
float(getattr(CS, "one_pedal_drive_time", 0.0)),
|
||||
)
|
||||
if volt_one_pedal_active and self.volt_one_pedal_gas_pressed_last and not CS.out.gasPressed:
|
||||
if CS.out.vEgo < VOLT_ONE_PEDAL_LIFT_BRAKE_BP[-1]:
|
||||
self.volt_one_pedal_lift_frames = VOLT_ONE_PEDAL_LIFT_BRAKE_FRAMES
|
||||
elif CS.out.gasPressed or not volt_one_pedal_active:
|
||||
self.volt_one_pedal_lift_frames = 0
|
||||
|
||||
if self.frame % 4 == 0:
|
||||
if volt_one_pedal_active:
|
||||
self._update_volt_one_pedal_brake(CC, CS)
|
||||
else:
|
||||
self._reset_volt_one_pedal()
|
||||
if not self.CP.openpilotLongitudinalControl:
|
||||
self.apply_gas = 0
|
||||
self.apply_brake = self.volt_one_pedal_brake if volt_one_pedal_active else 0
|
||||
self.volt_one_pedal_gas_pressed_last = CS.out.gasPressed
|
||||
|
||||
stock_hold_apply_brake = max(self.apply_brake if self.CP.openpilotLongitudinalControl else 0, self.volt_one_pedal_brake)
|
||||
|
||||
hold_ready = (
|
||||
auto_hold_enabled and
|
||||
@@ -421,6 +708,8 @@ class CarController(CarControllerBase):
|
||||
)
|
||||
if not hold_ready or CS.out.gasPressed:
|
||||
CS.auto_hold_armed = False
|
||||
if CS.out.gasPressed:
|
||||
CS.auto_hold_engaged = False
|
||||
elif CS.regen_release_timer > 0.0:
|
||||
CS.auto_hold_armed = False
|
||||
elif not CS.auto_hold_armed and (CS.out.vEgo > 0.03 or ((CS.out.standstill or CS.out.vEgo < 0.02) and CS.out.brakePressed)):
|
||||
@@ -429,7 +718,7 @@ class CarController(CarControllerBase):
|
||||
if CS.out.vEgo > 0.1 or CS.out.gasPressed or CS.out.gearShifter not in AUTO_HOLD_DRIVE_GEARS:
|
||||
self.auto_hold_brake = 0
|
||||
elif CS.out.brakePressed or stock_hold_apply_brake > 0:
|
||||
self.auto_hold_brake = estimate_auto_hold_brake(CS.out.brake, stock_hold_apply_brake)
|
||||
self.auto_hold_brake = estimate_auto_hold_brake(CS.out.brake, stock_hold_apply_brake, self.CP)
|
||||
|
||||
if self.frame % 25 == 0:
|
||||
try:
|
||||
@@ -520,10 +809,23 @@ class CarController(CarControllerBase):
|
||||
CS.auto_hold_armed,
|
||||
CS.auto_hold_engaged,
|
||||
CS.out.brakePressed,
|
||||
CS.out.gasPressed,
|
||||
CS.out.standstill,
|
||||
CC.longActive,
|
||||
CS.out.regenBraking,
|
||||
CS.out.vEgo,
|
||||
get_auto_hold_stop_threshold(self.CP, CS.auto_hold_engaged),
|
||||
)
|
||||
bolt_acc_pedal_friction_experiment = supports_bolt_acc_pedal_friction_experiment(self.CP)
|
||||
bolt_acc_pedal_friction_main_on = bolt_acc_pedal_friction_experiment and CS.out.cruiseState.available
|
||||
if not bolt_acc_pedal_friction_main_on:
|
||||
self.bolt_acc_pedal_friction_low_speed_active = False
|
||||
volt_one_pedal_braking = volt_one_pedal_active and self.volt_one_pedal_brake > 0
|
||||
volt_one_pedal_hold_active = (
|
||||
volt_one_pedal_braking and
|
||||
not auto_hold_active and
|
||||
CS.one_pedal_drive_time >= AUTO_HOLD_MIN_DRIVE_TIME_S and
|
||||
(CS.out.standstill or CS.out.vEgo < 0.02)
|
||||
)
|
||||
|
||||
# Steering (Active: 50Hz, inactive: 10Hz)
|
||||
@@ -578,6 +880,7 @@ class CarController(CarControllerBase):
|
||||
# ASCM sends max regen when not enabled
|
||||
self.apply_gas = self.params.INACTIVE_REGEN
|
||||
self.apply_brake = 0
|
||||
self.bolt_acc_pedal_friction_low_speed_active = False
|
||||
self.planner_regen_hold = False
|
||||
self.regen_paddle_pressed = False
|
||||
self.regen_paddle_timer = 0
|
||||
@@ -585,7 +888,7 @@ class CarController(CarControllerBase):
|
||||
self.regen_release_counter = 0
|
||||
self.regen_min_on_frames = 0
|
||||
self.regen_min_off_frames = 0
|
||||
elif near_stop and stopping and not CC.cruiseControl.resume:
|
||||
elif should_use_fixed_stopping_brake(self.CP, near_stop, stopping, CC.cruiseControl.resume):
|
||||
stop_accel = getattr(starpilot_toggles, "stopAccel", self.CP.stopAccel)
|
||||
self.apply_gas = self.params.INACTIVE_REGEN
|
||||
self.apply_brake = int(min(-100 * stop_accel, self.params.MAX_BRAKE))
|
||||
@@ -629,7 +932,16 @@ class CarController(CarControllerBase):
|
||||
if testing_ground.use_1:
|
||||
accel_max = min(accel_max, np.interp(CS.out.vEgo, [0.0, 4.0, 12.0], [1.25, 1.6, self.params.ACCEL_MAX]))
|
||||
|
||||
accel_cmd = float(np.clip(actuators.accel + accel_due_to_pitch, self.params.ACCEL_MIN, accel_max))
|
||||
accel_input = actuators.accel + accel_due_to_pitch
|
||||
if (
|
||||
getattr(starpilot_toggles, "truck_tuning", False) and
|
||||
self.CP.carFingerprint in TRUCK_LONG_SMOOTH_CARS and
|
||||
getattr(self.CP, "transmissionType", None) == TransmissionType.automatic and
|
||||
not self.CP.enableGasInterceptorDEPRECATED
|
||||
):
|
||||
accel_input = shape_truck_positive_accel(accel_input, CS.out.vEgo, True)
|
||||
|
||||
accel_cmd = float(np.clip(accel_input, self.params.ACCEL_MIN, accel_max))
|
||||
torque = self.tireRadius * ((self.mass * accel_cmd) + (0.5 * self.coeffDrag * self.frontalArea * self.airDensity * CS.out.vEgo ** 2))
|
||||
scaled_torque = torque + self.params.ZERO_GAS
|
||||
apply_gas_torque = np.clip(scaled_torque, self.params.MAX_ACC_REGEN, gas_max)
|
||||
@@ -637,9 +949,27 @@ class CarController(CarControllerBase):
|
||||
if testing_ground.use_1:
|
||||
brake_switch_bias = get_testing_ground_1_brake_switch_bias(CS.out.vEgo)
|
||||
brake_switch = min(self.params.ZERO_GAS, brake_switch + brake_switch_bias)
|
||||
if bolt_acc_pedal_friction_main_on:
|
||||
planner_brake_switch = get_bolt_acc_pedal_planner_brake_switch(
|
||||
CS.out.vEgo, self.params, self.tireRadius, self.mass, self.coeffDrag, self.frontalArea, self.airDensity,
|
||||
)
|
||||
brake_switch = get_bolt_acc_pedal_effective_brake_switch(brake_switch, planner_brake_switch)
|
||||
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(np.interp(brake_accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V)))
|
||||
if bolt_acc_pedal_friction_main_on:
|
||||
if self.apply_brake > 0:
|
||||
full_brake_accel = min(
|
||||
self.params.ACCEL_MIN + (0.5 * self.coeffDrag * self.frontalArea * self.airDensity * CS.out.vEgo ** 2) / self.mass +
|
||||
(self.params.ZERO_GAS - brake_switch) / (self.tireRadius * self.mass),
|
||||
-0.1,
|
||||
)
|
||||
self.apply_brake = get_bolt_acc_pedal_friction_brake(
|
||||
self.apply_brake, full_brake_accel, CS.out.vEgo, self.params,
|
||||
)
|
||||
self.apply_brake, self.bolt_acc_pedal_friction_low_speed_active = shape_bolt_acc_pedal_low_speed_friction(
|
||||
self.apply_brake, CS.out.vEgo, stopping, self.bolt_acc_pedal_friction_low_speed_active,
|
||||
)
|
||||
if self.apply_brake > 0:
|
||||
self.apply_gas = self.params.INACTIVE_REGEN
|
||||
|
||||
@@ -650,15 +980,19 @@ class CarController(CarControllerBase):
|
||||
# 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)
|
||||
|
||||
if volt_one_pedal_braking:
|
||||
self.apply_gas = self.params.INACTIVE_REGEN
|
||||
self.apply_brake = max(self.apply_brake, self.volt_one_pedal_brake)
|
||||
|
||||
maneuver_sng_launch = self.longitudinal_maneuver_mode and self.is_volt
|
||||
if (
|
||||
self.CP.enableGasInterceptorDEPRECATED and
|
||||
self.apply_gas > self.params.INACTIVE_REGEN and
|
||||
use_interceptor_sng_launch(self.CP, CS, maneuver_sng_launch)
|
||||
):
|
||||
interceptor_gas_cmd = self.params.SNG_INTERCEPTOR_GAS
|
||||
if maneuver_sng_launch:
|
||||
interceptor_gas_cmd = max(interceptor_gas_cmd, float(np.interp(actuators.accel, [0.0, 1.0, 2.0], [self.params.SNG_INTERCEPTOR_GAS, 0.11, 0.16])))
|
||||
interceptor_gas_cmd = get_interceptor_sng_gas_cmd(
|
||||
self.CP, interceptor_gas_cmd, actuators.accel, self.params, maneuver_sng_launch,
|
||||
)
|
||||
self.apply_brake = 0
|
||||
self.apply_gas = self.params.INACTIVE_REGEN
|
||||
|
||||
@@ -692,6 +1026,27 @@ class CarController(CarControllerBase):
|
||||
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.DECEL_SET))
|
||||
if self.CP.enableGasInterceptorDEPRECATED:
|
||||
can_sends.append(create_gas_interceptor_command(self.packer_pt, interceptor_gas_cmd, idx))
|
||||
if bolt_acc_pedal_friction_experiment:
|
||||
friction_brake_bus = get_friction_brake_bus(self.CP)
|
||||
if self.CP.networkLocation == NetworkLocation.fwdCamera:
|
||||
at_full_stop = at_full_stop and stopping
|
||||
|
||||
experiment_brake, self.bolt_acc_pedal_friction_release_frames, should_send_bolt_acc_pedal_friction = \
|
||||
get_bolt_acc_pedal_friction_command_state(
|
||||
self.apply_brake,
|
||||
bolt_acc_pedal_friction_main_on,
|
||||
self.bolt_acc_pedal_friction_release_frames,
|
||||
)
|
||||
|
||||
# This fingerprint is routed through the CC-only pedal path, so it
|
||||
# does not fall through to the normal friction-brake sender below.
|
||||
# Never apply stock friction with cruise main off, but do send a short
|
||||
# explicit zero-brake unwind so the last nonzero stock-EBCM command
|
||||
# cannot linger after a disengage or main-off event.
|
||||
if should_send_bolt_acc_pedal_friction:
|
||||
can_sends.append(gmcan.create_friction_brake_command(
|
||||
self.packer_ch, friction_brake_bus, experiment_brake, idx, bolt_acc_pedal_friction_main_on,
|
||||
near_stop, at_full_stop, self.CP))
|
||||
if self.CP.carFingerprint not in CC_ONLY_CAR:
|
||||
friction_brake_bus = get_friction_brake_bus(self.CP)
|
||||
# GM Camera exceptions
|
||||
@@ -709,57 +1064,65 @@ class CarController(CarControllerBase):
|
||||
acc_engaged = CC.enabled
|
||||
|
||||
if auto_hold_active:
|
||||
hold_brake = self.auto_hold_brake or estimate_auto_hold_brake(CS.out.brake, self.apply_brake)
|
||||
hold_brake = max(self.volt_one_pedal_brake, self.auto_hold_brake or estimate_auto_hold_brake(CS.out.brake, self.apply_brake, self.CP))
|
||||
hold_standstill = CS.pcm_acc_status == AccState.STANDSTILL
|
||||
hold_near_stop = CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE
|
||||
can_sends.append(gmcan.create_friction_brake_command(
|
||||
self.packer_ch, friction_brake_bus, hold_brake, idx, False, hold_near_stop, hold_standstill, self.CP))
|
||||
self.packer_ch, friction_brake_bus, hold_brake, idx, False, hold_near_stop, hold_standstill,
|
||||
self.CP, allow_near_stop_mode=True))
|
||||
CS.auto_hold_engaged = True
|
||||
CS.auto_hold_fault_suppression_timer = 1.0
|
||||
elif volt_one_pedal_hold_active:
|
||||
hold_brake = max(self.volt_one_pedal_brake, self.auto_hold_brake or estimate_auto_hold_brake(0.0, self.volt_one_pedal_brake, self.CP))
|
||||
hold_standstill = CS.pcm_acc_status == AccState.STANDSTILL
|
||||
hold_near_stop = CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE
|
||||
can_sends.append(gmcan.create_friction_brake_command(
|
||||
self.packer_ch, friction_brake_bus, hold_brake, idx, False, hold_near_stop, hold_standstill,
|
||||
self.CP, allow_near_stop_mode=True))
|
||||
CS.auto_hold_engaged = True
|
||||
CS.auto_hold_fault_suppression_timer = 1.0
|
||||
else:
|
||||
if volt_one_pedal_braking:
|
||||
at_full_stop = at_full_stop or CS.pcm_acc_status == AccState.STANDSTILL
|
||||
near_stop = near_stop or (CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE)
|
||||
# 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,
|
||||
include_always_one3=self.CP.carFingerprint in kaofui_cars, use_volt_layout=self.is_volt))
|
||||
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,
|
||||
allow_near_stop_mode=volt_one_pedal_braking))
|
||||
CS.auto_hold_engaged = False
|
||||
|
||||
if should_send_acc_dashboard_status(self.CP, dash_speed_spoof_active):
|
||||
acc_dashboard_status = get_acc_dashboard_status_values(CC.enabled, hud_v_cruise * CV.MS_TO_KPH, hud_control, CS)
|
||||
fcw_alert = get_acc_dashboard_fcw_alert(hud_alert, CS)
|
||||
can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN,
|
||||
acc_dashboard_status, fcw_alert))
|
||||
acc_dashboard_status_active = get_acc_dashboard_status_active(self.CP, CC)
|
||||
can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN, acc_dashboard_status_active,
|
||||
hud_v_cruise * CV.MS_TO_KPH, hud_control, fcw_alert))
|
||||
|
||||
# Radar needs to know current speed and yaw rate (50hz),
|
||||
# and that ADAS is alive (10hz)
|
||||
if not self.CP.radarUnavailable:
|
||||
send_adas = True
|
||||
if should_send_adas_status(self.CP, self.CP.carFingerprint in kaofui_cars):
|
||||
tt = self.frame * DT_CTRL
|
||||
if self.CP.carFingerprint in kaofui_cars:
|
||||
if self.CP.carFingerprint not in ASCM_INT:
|
||||
send_adas = (self.CP.networkLocation != NetworkLocation.fwdCamera) and (self.CP.carFingerprint not in SDGM_CAR)
|
||||
|
||||
if send_adas:
|
||||
tt = self.frame * DT_CTRL
|
||||
if self.CP.carFingerprint in kaofui_cars:
|
||||
time_and_headlights_step = 10
|
||||
speed_and_accelerometer_step = 2
|
||||
if self.frame % time_and_headlights_step == 0:
|
||||
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_headlights_status(self.packer_obj, CanBus.OBSTACLE))
|
||||
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_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx))
|
||||
else:
|
||||
time_and_headlights_step = 20
|
||||
if self.frame % time_and_headlights_step == 0:
|
||||
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_headlights_status(self.packer_obj, CanBus.OBSTACLE))
|
||||
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))
|
||||
time_and_headlights_step = 10
|
||||
speed_and_accelerometer_step = 2
|
||||
if self.frame % time_and_headlights_step == 0:
|
||||
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_headlights_status(self.packer_obj, CanBus.OBSTACLE))
|
||||
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_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx))
|
||||
else:
|
||||
time_and_headlights_step = 20
|
||||
if self.frame % time_and_headlights_step == 0:
|
||||
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_headlights_status(self.packer_obj, CanBus.OBSTACLE))
|
||||
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))
|
||||
|
||||
keepalive_step = get_adas_keepalive_step(self.CP, self.CP.carFingerprint in kaofui_cars)
|
||||
if keepalive_step is not None and self.frame % keepalive_step == 0:
|
||||
@@ -785,14 +1148,33 @@ class CarController(CarControllerBase):
|
||||
else:
|
||||
if self.frame % 4 == 0 and auto_hold_active:
|
||||
idx = (self.frame // 4) % 4
|
||||
hold_brake = self.auto_hold_brake or estimate_auto_hold_brake(CS.out.brake, stock_hold_apply_brake)
|
||||
hold_brake = max(self.volt_one_pedal_brake, self.auto_hold_brake or estimate_auto_hold_brake(CS.out.brake, stock_hold_apply_brake, self.CP))
|
||||
hold_standstill = CS.pcm_acc_status == AccState.STANDSTILL
|
||||
hold_near_stop = CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE
|
||||
can_sends.append(gmcan.create_friction_brake_command(
|
||||
self.packer_ch, get_friction_brake_bus(self.CP), hold_brake, idx, False, hold_near_stop, hold_standstill, self.CP))
|
||||
self.packer_ch, get_friction_brake_bus(self.CP), hold_brake, idx, False, hold_near_stop, hold_standstill,
|
||||
self.CP, allow_near_stop_mode=True))
|
||||
CS.auto_hold_engaged = True
|
||||
CS.auto_hold_fault_suppression_timer = 1.0
|
||||
elif self.frame % 4 == 0 and volt_one_pedal_hold_active:
|
||||
idx = (self.frame // 4) % 4
|
||||
hold_brake = max(self.volt_one_pedal_brake, self.auto_hold_brake or estimate_auto_hold_brake(0.0, self.volt_one_pedal_brake, self.CP))
|
||||
hold_standstill = CS.pcm_acc_status == AccState.STANDSTILL
|
||||
hold_near_stop = CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE
|
||||
can_sends.append(gmcan.create_friction_brake_command(
|
||||
self.packer_ch, get_friction_brake_bus(self.CP), hold_brake, idx, False, hold_near_stop, hold_standstill,
|
||||
self.CP, allow_near_stop_mode=True))
|
||||
CS.auto_hold_engaged = True
|
||||
CS.auto_hold_fault_suppression_timer = 1.0
|
||||
elif self.frame % 4 == 0 and volt_one_pedal_braking:
|
||||
idx = (self.frame // 4) % 4
|
||||
near_stop = CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE
|
||||
can_sends.append(gmcan.create_friction_brake_command(
|
||||
self.packer_ch, get_friction_brake_bus(self.CP), self.volt_one_pedal_brake, idx, False, near_stop, False,
|
||||
self.CP, allow_near_stop_mode=True))
|
||||
CS.auto_hold_engaged = False
|
||||
elif self.frame % 4 == 0:
|
||||
self.apply_brake = 0
|
||||
CS.auto_hold_engaged = False
|
||||
|
||||
# While car is braking, cancel button causes ECM to enter a soft disable state with a fault status.
|
||||
|
||||
@@ -33,6 +33,13 @@ AUTO_HOLD_REGEN_RELEASE_COOLDOWN_S = 1.0
|
||||
|
||||
BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise,
|
||||
CruiseButtons.MAIN: ButtonType.mainCruise, CruiseButtons.CANCEL: ButtonType.cancel}
|
||||
HARD_BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise}
|
||||
NORMAL_CRUISE_BUTTONS = (CruiseButtons.RES_ACCEL, CruiseButtons.DECEL_SET)
|
||||
|
||||
|
||||
def get_hard_cruise_buttons(steering_button_msg: dict) -> int:
|
||||
return steering_button_msg.get("ACCButtonsHard", CruiseButtons.INIT)
|
||||
|
||||
|
||||
GearShifter = structs.CarState.GearShifter
|
||||
BOLT_GEN1_CANCEL_PERSONALITY_CARS = {
|
||||
@@ -45,6 +52,19 @@ BOLT_CANCEL_BUTTON_CARS = BOLT_GEN1_CANCEL_PERSONALITY_CARS | {
|
||||
}
|
||||
|
||||
|
||||
def update_auto_hold_drive_timers(in_drive_for_hold: bool, moving_for_hold: bool,
|
||||
auto_hold_drive_time: float, one_pedal_drive_time: float) -> tuple[float, float]:
|
||||
if in_drive_for_hold:
|
||||
if moving_for_hold:
|
||||
auto_hold_drive_time = min(auto_hold_drive_time + DT_CTRL, AUTO_HOLD_MIN_DRIVE_TIME_S)
|
||||
one_pedal_drive_time = min(one_pedal_drive_time + DT_CTRL, AUTO_HOLD_MIN_DRIVE_TIME_S)
|
||||
else:
|
||||
auto_hold_drive_time = 0.0
|
||||
one_pedal_drive_time = 0.0
|
||||
|
||||
return auto_hold_drive_time, one_pedal_drive_time
|
||||
|
||||
|
||||
class CarState(CarStateBase):
|
||||
def __init__(self, CP, FPCP):
|
||||
super().__init__(CP, FPCP)
|
||||
@@ -64,11 +84,14 @@ class CarState(CarStateBase):
|
||||
|
||||
self.prev_distance_button = 0
|
||||
self.distance_button = 0
|
||||
self.hard_cruise_buttons = CruiseButtons.INIT
|
||||
self.force_reset_cruise_buttons = False
|
||||
|
||||
self.single_pedal_mode = False
|
||||
self.auto_hold_armed = False
|
||||
self.auto_hold_engaged = False
|
||||
self.auto_hold_drive_time = 0.0
|
||||
self.one_pedal_drive_time = 0.0
|
||||
self.auto_hold_fault_suppression_timer = 0.0
|
||||
self.regen_release_timer = 0.0
|
||||
self.user_regen_paddle_pressed = False
|
||||
@@ -81,12 +104,6 @@ class CarState(CarStateBase):
|
||||
self.lkas_enabled = 0
|
||||
self.pcm_acc_status = AccState.OFF
|
||||
self.stock_fcw_alert = 0
|
||||
self.stock_acc_cruise_state = 0
|
||||
self.stock_acc_lead_car = 0
|
||||
self.stock_acc_resume_button = 0
|
||||
self.stock_acc_speed_setpoint_kph = 0.0
|
||||
self.stock_acc_gap_level = 0
|
||||
self.stock_acc_cmd_active = 0
|
||||
|
||||
def update_button_enable(self, buttonEvents: list[structs.CarState.ButtonEvent]):
|
||||
if not self.CP.pcmCruise:
|
||||
@@ -119,21 +136,36 @@ class CarState(CarStateBase):
|
||||
sdgm_non_volt = self.CP.carFingerprint in SDGM_CAR and self.CP.carFingerprint not in kaofui_state_cars
|
||||
|
||||
prev_cruise_buttons = self.cruise_buttons
|
||||
prev_hard_cruise_buttons = self.hard_cruise_buttons
|
||||
prev_distance_button = self.distance_button
|
||||
if not sdgm_non_volt:
|
||||
self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"]
|
||||
self.distance_button = pt_cp.vl["ASCMSteeringButton"]["DistanceButton"]
|
||||
self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"]
|
||||
self.steering_button_checksum = pt_cp.vl["ASCMSteeringButton"]["SteeringButtonChecksum"]
|
||||
steering_button_msg = pt_cp.vl["ASCMSteeringButton"]
|
||||
self.cruise_buttons = steering_button_msg["ACCButtons"]
|
||||
self.hard_cruise_buttons = get_hard_cruise_buttons(steering_button_msg)
|
||||
self.distance_button = steering_button_msg["DistanceButton"]
|
||||
self.buttons_counter = steering_button_msg["RollingCounter"]
|
||||
self.steering_button_checksum = steering_button_msg["SteeringButtonChecksum"]
|
||||
self.steering_button_ts_nanos = pt_cp.ts_nanos["ASCMSteeringButton"]["ACCButtons"]
|
||||
acc_always_one = pt_cp.vl["ASCMSteeringButton"]["ACCAlwaysOne"]
|
||||
acc_hidden_bit = pt_cp.vl["ASCMSteeringButton"].get("ACCHiddenBit", 0)
|
||||
acc_always_one = steering_button_msg["ACCAlwaysOne"]
|
||||
acc_hidden_bit = steering_button_msg.get("ACCHiddenBit", 0)
|
||||
self.steering_button_prefix = (int(acc_always_one) & 1) | ((int(acc_hidden_bit) & 1) << 6)
|
||||
else:
|
||||
self.cruise_buttons = cam_cp.vl["ASCMSteeringButton"]["ACCButtons"]
|
||||
self.distance_button = cam_cp.vl["ASCMSteeringButton"]["DistanceButton"]
|
||||
self.buttons_counter = cam_cp.vl["ASCMSteeringButton"]["RollingCounter"]
|
||||
steering_button_msg = cam_cp.vl["ASCMSteeringButton"]
|
||||
self.cruise_buttons = steering_button_msg["ACCButtons"]
|
||||
self.hard_cruise_buttons = get_hard_cruise_buttons(steering_button_msg)
|
||||
self.distance_button = steering_button_msg["DistanceButton"]
|
||||
self.buttons_counter = steering_button_msg["RollingCounter"]
|
||||
self.steering_button_ts_nanos = cam_cp.ts_nanos["ASCMSteeringButton"]["ACCButtons"]
|
||||
|
||||
# A GM hard press keeps the normal cruise button signal active too. Suppress
|
||||
# the normal button until the wheel reports a different normal state.
|
||||
if self.hard_cruise_buttons != CruiseButtons.INIT and self.cruise_buttons in NORMAL_CRUISE_BUTTONS:
|
||||
self.force_reset_cruise_buttons = True
|
||||
if self.force_reset_cruise_buttons and self.cruise_buttons in NORMAL_CRUISE_BUTTONS:
|
||||
self.cruise_buttons = CruiseButtons.UNPRESS
|
||||
elif self.force_reset_cruise_buttons and self.cruise_buttons not in NORMAL_CRUISE_BUTTONS:
|
||||
self.force_reset_cruise_buttons = False
|
||||
|
||||
self.pscm_status = copy.copy(pt_cp.vl["PSCMStatus"])
|
||||
self.moving_backward = (pt_cp.vl["EBCMWheelSpdRear"]["RLWheelDir"] == 2) or (pt_cp.vl["EBCMWheelSpdRear"]["RRWheelDir"] == 2)
|
||||
|
||||
@@ -178,7 +210,10 @@ class CarState(CarStateBase):
|
||||
ret.brakePressed = ret.brake >= VOLT_EBCM_BRAKE_PRESSED_THRESHOLD
|
||||
elif 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) and (self.CP.carFingerprint != CAR.CHEVROLET_BLAZER)):
|
||||
elif (self.CP.flags & GMFlags.FORCE_BRAKE_C9.value) or (
|
||||
self.CP.networkLocation == NetworkLocation.fwdCamera and
|
||||
self.CP.carFingerprint not in (SDGM_CAR | ASCM_INT | {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
|
||||
@@ -189,13 +224,10 @@ class CarState(CarStateBase):
|
||||
ret.brakePressed = ret.brake >= analog_thresh
|
||||
|
||||
in_drive_for_hold = ret.gearShifter in (GearShifter.drive, GearShifter.low, GearShifter.manumatic)
|
||||
if in_drive_for_hold:
|
||||
if ret.brakePressed:
|
||||
self.auto_hold_drive_time = AUTO_HOLD_MIN_DRIVE_TIME_S
|
||||
else:
|
||||
self.auto_hold_drive_time = min(self.auto_hold_drive_time + DT_CTRL, AUTO_HOLD_MIN_DRIVE_TIME_S)
|
||||
else:
|
||||
self.auto_hold_drive_time = 0.0
|
||||
self.auto_hold_drive_time, self.one_pedal_drive_time = update_auto_hold_drive_timers(
|
||||
in_drive_for_hold, ret.vEgo > 0.1, self.auto_hold_drive_time, self.one_pedal_drive_time
|
||||
)
|
||||
if not in_drive_for_hold:
|
||||
self.auto_hold_armed = False
|
||||
self.auto_hold_engaged = False
|
||||
|
||||
@@ -280,12 +312,6 @@ class CarState(CarStateBase):
|
||||
acc_dashboard_status = cam_cp.vl["ASCMActiveCruiseControlStatus"]
|
||||
if self.CP.carFingerprint not in CC_ONLY_CAR:
|
||||
ret.cruiseState.speed = acc_dashboard_status["ACCSpeedSetpoint"] * CV.KPH_TO_MS
|
||||
self.stock_acc_cruise_state = int(acc_dashboard_status["ACCCruiseState"])
|
||||
self.stock_acc_lead_car = int(acc_dashboard_status["ACCLeadCar"])
|
||||
self.stock_acc_resume_button = int(acc_dashboard_status["ACCResumeButton"])
|
||||
self.stock_acc_speed_setpoint_kph = float(acc_dashboard_status["ACCSpeedSetpoint"])
|
||||
self.stock_acc_gap_level = int(acc_dashboard_status["ACCGapLevel"])
|
||||
self.stock_acc_cmd_active = int(acc_dashboard_status["ACCCmdActive"])
|
||||
# Preserve the stock camera FCW level from 0x370 so the controller can
|
||||
# replay it when that message is blocked and spoofed by openpilot long.
|
||||
self.stock_fcw_alert = int(acc_dashboard_status["FCWAlert"])
|
||||
@@ -374,19 +400,26 @@ class CarState(CarStateBase):
|
||||
lkas_events = [] if (suppress_malibu_side_buttons or suppress_bolt_cancel_lkas) else create_button_events(
|
||||
self.lkas_enabled, self.lkas_previously_enabled, {1: ButtonType.lkas}
|
||||
)
|
||||
hard_cruise_events = create_button_events(
|
||||
self.hard_cruise_buttons, prev_hard_cruise_buttons, HARD_BUTTONS_DICT, unpressed_btn=CruiseButtons.INIT
|
||||
)
|
||||
|
||||
# Don't add events if transitioning from INIT, unless it's to an actual button.
|
||||
if self.cruise_buttons != CruiseButtons.UNPRESS or prev_cruise_buttons != CruiseButtons.INIT:
|
||||
if (self.cruise_buttons != CruiseButtons.UNPRESS or prev_cruise_buttons != CruiseButtons.INIT or
|
||||
self.hard_cruise_buttons != CruiseButtons.INIT or prev_hard_cruise_buttons != CruiseButtons.INIT):
|
||||
ret.buttonEvents = [
|
||||
*cruise_events,
|
||||
*distance_events,
|
||||
*lkas_events,
|
||||
*hard_cruise_events,
|
||||
]
|
||||
|
||||
if ret.vEgo < self.CP.minSteerSpeed:
|
||||
ret.lowSpeedAlert = True
|
||||
|
||||
fp_ret = custom.StarPilotCarState.new_message()
|
||||
fp_ret.accelHardCruise = self.hard_cruise_buttons == CruiseButtons.RES_ACCEL or prev_hard_cruise_buttons == CruiseButtons.RES_ACCEL
|
||||
fp_ret.decelHardCruise = self.hard_cruise_buttons == CruiseButtons.DECEL_SET or prev_hard_cruise_buttons == CruiseButtons.DECEL_SET
|
||||
if bolt_cancel_button and self.cruise_buttons == CruiseButtons.CANCEL:
|
||||
fp_ret.cancelPressed = True
|
||||
fp_ret.sportGear = pt_cp.vl["SportMode"]["SportMode"] == 1
|
||||
|
||||
@@ -7,6 +7,7 @@ from opendbc.car.gm.values import CAR
|
||||
|
||||
CAMERA_DIAGNOSTIC_ADDRESS = 0x24b
|
||||
CAMERA_DIAGNOSTIC_RX_ADDRESS = 0x64b
|
||||
SASCM_ADDRESS = 0x2FF
|
||||
|
||||
|
||||
FINGERPRINTS = {
|
||||
@@ -210,6 +211,7 @@ FINGERPRINTS.update({
|
||||
CAR.GMC_ACADIA_ASCM: FINGERPRINTS[CAR.GMC_ACADIA],
|
||||
CAR.CHEVROLET_MALIBU_ASCM: FINGERPRINTS[CAR.CHEVROLET_MALIBU],
|
||||
CAR.CADILLAC_ESCALADE_ASCM: FINGERPRINTS[CAR.CADILLAC_ESCALADE],
|
||||
CAR.CADILLAC_ESCALADE_ESV_2019_ASCM: [{**fp, SASCM_ADDRESS: 8} for fp in FINGERPRINTS[CAR.CADILLAC_ESCALADE_ESV_2019]],
|
||||
CAR.CHEVROLET_SUBURBAN: FINGERPRINTS[CAR.CHEVROLET_SUBURBAN_CC],
|
||||
CAR.GMC_YUKON_CC: FINGERPRINTS[CAR.GMC_YUKON],
|
||||
CAR.CADILLAC_XT6: FINGERPRINTS[CAR.CHEVROLET_TRAVERSE],
|
||||
|
||||
@@ -179,22 +179,28 @@ def create_ecm_cruise_control_command(packer, bus, enabled, target_speed_kph):
|
||||
return CanData(0x3D1, bytes(dat), bus)
|
||||
|
||||
|
||||
def create_friction_brake_command(packer, bus, apply_brake, idx, enabled, near_stop, at_full_stop, CP):
|
||||
def get_friction_brake_mode(apply_brake, enabled, near_stop, at_full_stop, CP, allow_near_stop_mode=False):
|
||||
mode = 0x1
|
||||
|
||||
# TODO: Understand this better. Volts and ICE Camera ACC cars are 0x1 when enabled with no brake
|
||||
if enabled and CP.carFingerprint in (CAR.CHEVROLET_BOLT_ACC_2022_2023,):
|
||||
if enabled and CP.carFingerprint in (CAR.CHEVROLET_BOLT_ACC_2022_2023, CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL):
|
||||
mode = 0x9
|
||||
|
||||
if apply_brake > 0:
|
||||
mode = 0xa
|
||||
if at_full_stop:
|
||||
mode = 0xd
|
||||
elif allow_near_stop_mode and near_stop:
|
||||
# Stock Volt auto hold can run with cruise main on but ACC inactive, so
|
||||
# there is no stock STANDSTILL state to promote 0xa -> 0xd. Restore the
|
||||
# older near-stop hold mode only for that path.
|
||||
mode = 0xb
|
||||
|
||||
# TODO: this is to have GM bringing the car to complete stop,
|
||||
# but currently it conflicts with OP controls, so turned off. Not set by all cars
|
||||
#elif near_stop:
|
||||
# mode = 0xb
|
||||
return mode
|
||||
|
||||
|
||||
def create_friction_brake_command(packer, bus, apply_brake, idx, enabled, near_stop, at_full_stop, CP, allow_near_stop_mode=False):
|
||||
mode = get_friction_brake_mode(apply_brake, enabled, near_stop, at_full_stop, CP, allow_near_stop_mode)
|
||||
|
||||
brake = (0x1000 - apply_brake) & 0xfff
|
||||
checksum = (0x10000 - (mode << 12) - brake - idx) & 0xffff
|
||||
@@ -209,18 +215,17 @@ def create_friction_brake_command(packer, bus, apply_brake, idx, enabled, near_s
|
||||
return packer.make_can_msg("EBCMFrictionBrakeCmd", bus, values)
|
||||
|
||||
|
||||
def create_acc_dashboard_command(packer, bus, status_values, fcw_alert):
|
||||
target_speed = min(max(float(status_values.get("ACCSpeedSetpoint", 0.0)), 0.0), 255.0)
|
||||
def create_acc_dashboard_command(packer, bus, enabled, target_speed_kph, hud_control, fcw_alert):
|
||||
target_speed = min(target_speed_kph, 255)
|
||||
|
||||
values = {
|
||||
"ACCAlwaysOne": 1,
|
||||
"ACCCruiseState": int(status_values.get("ACCCruiseState", 0)) & 0x7,
|
||||
"ACCResumeButton": int(status_values.get("ACCResumeButton", 0)) & 0x1,
|
||||
"ACCResumeButton": 0,
|
||||
"ACCSpeedSetpoint": target_speed,
|
||||
"ACCGapLevel": int(status_values.get("ACCGapLevel", 0)) & 0x3,
|
||||
"ACCCmdActive": int(status_values.get("ACCCmdActive", 0)) & 0x1,
|
||||
"ACCGapLevel": hud_control.leadDistanceBars * enabled, # 3 "far", 0 "inactive"
|
||||
"ACCCmdActive": enabled,
|
||||
"ACCAlwaysOne2": 1,
|
||||
"ACCLeadCar": int(status_values.get("ACCLeadCar", 0)) & 0x1,
|
||||
"ACCLeadCar": hud_control.leadVisible,
|
||||
"FCWAlert": int(fcw_alert) & 0x3,
|
||||
}
|
||||
|
||||
|
||||
@@ -62,9 +62,13 @@ NON_LINEAR_TORQUE_PARAMS = {
|
||||
"left": [3.8, 0.81, 0.24, 0.0465122],
|
||||
"right": [3.8, 0.81, 0.24, 0.0465122],
|
||||
},
|
||||
CAR.CADILLAC_XT4: {
|
||||
"left": [2.4, 0.95, 0.28, 0.0],
|
||||
"right": [2.4, 0.95, 0.28, 0.0],
|
||||
},
|
||||
CAR.CHEVROLET_VOLT: {
|
||||
"left": [1.5, 1.0, 0.155, 0.0],
|
||||
"right": [1.5, 1.0, 0.155, 0.0],
|
||||
"left": [1.525, 1.05, 0.155, 0.0],
|
||||
"right": [1.525, 0.95, 0.150, 0.0],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -129,7 +133,11 @@ class CarInterface(CarInterfaceBase):
|
||||
@staticmethod
|
||||
def get_pid_accel_limits(CP, current_speed, cruise_speed):
|
||||
if CP.enableGasInterceptorDEPRECATED and bool(CP.flags & GMFlags.PEDAL_LONG.value):
|
||||
if CP.carFingerprint in BOLT_PEDAL_LONG_CARS:
|
||||
if CP.carFingerprint == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL:
|
||||
accel_min = CarControllerParams.ACCEL_MIN
|
||||
accel_max = np.interp(current_speed, [0.0, 1.5, 4.0, 8.0, 15.0],
|
||||
[0.54, 0.74, 1.03, 1.46, CarControllerParams.ACCEL_MAX])
|
||||
elif CP.carFingerprint in BOLT_PEDAL_LONG_CARS:
|
||||
accel_min = np.interp(current_speed, [0.0, 1.5, 4.0, 8.0, 15.0, 30.0],
|
||||
[-0.93, -1.28, -1.98, -2.58, -2.86, -2.95])
|
||||
accel_max = np.interp(current_speed, [0.0, 1.5, 4.0, 8.0, 15.0],
|
||||
@@ -213,6 +221,10 @@ class CarInterface(CarInterfaceBase):
|
||||
gm_auto_hold = params.get_bool("GMAutoHold")
|
||||
except UnknownKeyName:
|
||||
gm_auto_hold = False
|
||||
try:
|
||||
volt_one_pedal_mode = params.get_bool("VoltOnePedalMode")
|
||||
except UnknownKeyName:
|
||||
volt_one_pedal_mode = False
|
||||
|
||||
ret.brand = "gm"
|
||||
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.gm)]
|
||||
@@ -420,7 +432,7 @@ class CarInterface(CarInterfaceBase):
|
||||
elif candidate == CAR.CADILLAC_ESCALADE_ASCM:
|
||||
CarInterfaceBase.configure_torque_tune(CAR.CADILLAC_ESCALADE, ret.lateralTuning)
|
||||
|
||||
elif candidate in (CAR.CADILLAC_ESCALADE_ESV, CAR.CADILLAC_ESCALADE_ESV_2019):
|
||||
elif candidate in (CAR.CADILLAC_ESCALADE_ESV, CAR.CADILLAC_ESCALADE_ESV_2019, CAR.CADILLAC_ESCALADE_ESV_2019_ASCM):
|
||||
ret.minEnableSpeed = -1. # engage speed is decided by pcm
|
||||
|
||||
if candidate == CAR.CADILLAC_ESCALADE_ESV:
|
||||
@@ -429,7 +441,8 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.lateralTuning.pid.kf = 0.000045
|
||||
else:
|
||||
ret.steerActuatorDelay = 0.2
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
torque_candidate = CAR.CADILLAC_ESCALADE_ESV_2019 if candidate == CAR.CADILLAC_ESCALADE_ESV_2019_ASCM else candidate
|
||||
CarInterfaceBase.configure_torque_tune(torque_candidate, ret.lateralTuning)
|
||||
|
||||
elif candidate in (
|
||||
CAR.CHEVROLET_BOLT_ACC_2022_2023,
|
||||
@@ -515,7 +528,19 @@ class CarInterface(CarInterfaceBase):
|
||||
if not ret.openpilotLongitudinalControl:
|
||||
ret.minEnableSpeed = -1.
|
||||
if candidate == CAR.CHEVROLET_BLAZER:
|
||||
# The Blazer builds brake torque noticeably later than the rest of the GM set.
|
||||
# A slightly larger planner delay estimate starts the request earlier and keeps
|
||||
# stopped-lead approaches from turning into a late, harsh max-brake catch-up.
|
||||
ret.longitudinalActuatorDelay = 0.7
|
||||
ret.longitudinalTuning.kpBP = [0.0, 4.0, 12.0, 35.0]
|
||||
ret.longitudinalTuning.kpV = [0.09, 0.075, 0.055, 0.040]
|
||||
ret.longitudinalTuning.kiBP = [0.0, 4.0, 12.0, 35.0]
|
||||
ret.longitudinalTuning.kiV = [0.03, 0.04, 0.055, 0.07]
|
||||
ret.minEnableSpeed = 5 * CV.KPH_TO_MS
|
||||
ret.stoppingDecelRate = 1.0
|
||||
ret.vEgoStopping = 0.35
|
||||
ret.vEgoStarting = 0.35
|
||||
ret.stopAccel = -0.30
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
|
||||
elif candidate == CAR.BUICK_BABYENCLAVE:
|
||||
@@ -645,7 +670,7 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
# Exception for flashed cars, or cars whose camera was removed.
|
||||
missing_camera_msg = CAM_MSG not in fingerprint.get(CanBus.CAMERA, {})
|
||||
if (ret.networkLocation == NetworkLocation.fwdCamera or candidate in CC_ONLY_CAR) and missing_camera_msg and candidate not in SDGM_CAR:
|
||||
if (ret.networkLocation == NetworkLocation.fwdCamera or candidate in CC_ONLY_CAR) and missing_camera_msg and candidate not in (ASCM_INT | SDGM_CAR):
|
||||
ret.flags |= GMFlags.NO_CAMERA.value
|
||||
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_CAMERA.value
|
||||
|
||||
@@ -663,8 +688,8 @@ class CarInterface(CarInterfaceBase):
|
||||
if remote_start_boots_comma:
|
||||
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_REMOTE_START_BOOTS_COMMA.value
|
||||
|
||||
volt_stock_auto_hold_safety = (
|
||||
gm_auto_hold and
|
||||
volt_stock_friction_brake_safety = (
|
||||
(gm_auto_hold or volt_one_pedal_mode) and
|
||||
candidate in {
|
||||
CAR.CHEVROLET_VOLT,
|
||||
CAR.CHEVROLET_VOLT_2019,
|
||||
@@ -672,13 +697,28 @@ class CarInterface(CarInterfaceBase):
|
||||
CAR.CHEVROLET_VOLT_CAMERA,
|
||||
}
|
||||
)
|
||||
if volt_stock_auto_hold_safety:
|
||||
# Reuse the paddle-scheduler safety bit as a Volt auto-hold marker on
|
||||
# non-pedal paths. Hold can run while OP longitudinal is configured but
|
||||
# not currently active, so the bit must be present regardless of the
|
||||
# current long-control mode.
|
||||
if volt_stock_friction_brake_safety:
|
||||
# Reuse the paddle-scheduler safety bit as a Volt stock friction-brake
|
||||
# marker on non-pedal paths. Both auto hold and one-pedal can run while
|
||||
# OP longitudinal is configured but not currently active, so the bit must
|
||||
# be present regardless of the current long-control mode.
|
||||
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value
|
||||
|
||||
volt_stock_one_pedal_safety = (
|
||||
volt_one_pedal_mode and
|
||||
candidate in {
|
||||
CAR.CHEVROLET_VOLT,
|
||||
CAR.CHEVROLET_VOLT_2019,
|
||||
CAR.CHEVROLET_VOLT_ASCM,
|
||||
CAR.CHEVROLET_VOLT_CAMERA,
|
||||
}
|
||||
)
|
||||
if volt_stock_one_pedal_safety:
|
||||
# Reuse the 3D1 scheduler bit as a Volt one-pedal marker on non-pedal
|
||||
# ACC paths. The bit is ignored by the actual 3D1 scheduler unless the
|
||||
# car is on a pedal-long CC-only path, so this stays isolated from Bolt.
|
||||
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_PANDA_3D1_SCHED.value
|
||||
|
||||
use_panda_3d1_sched = (
|
||||
ret.openpilotLongitudinalControl and
|
||||
ret.enableGasInterceptorDEPRECATED and
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import sys
|
||||
import types
|
||||
from types import SimpleNamespace
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from opendbc.car import structs
|
||||
|
||||
fake_interfaces = types.ModuleType("opendbc.car.interfaces")
|
||||
|
||||
@@ -33,21 +37,40 @@ fake_testing_grounds.testing_ground = SimpleNamespace(use_1=False)
|
||||
sys.modules.setdefault("openpilot.starpilot.common.testing_grounds", fake_testing_grounds)
|
||||
|
||||
from opendbc.car.gm.carcontroller import (
|
||||
AUTO_HOLD_DRIVE_GEARS,
|
||||
CarController,
|
||||
estimate_auto_hold_brake,
|
||||
get_adas_keepalive_step,
|
||||
get_auto_hold_stop_threshold,
|
||||
get_bolt_acc_pedal_friction_brake,
|
||||
get_bolt_acc_pedal_friction_command_state,
|
||||
get_bolt_acc_pedal_effective_brake_switch,
|
||||
get_bolt_acc_pedal_planner_brake_switch,
|
||||
get_bolt_pedal_long_accel_limit,
|
||||
get_interceptor_sng_gas_cmd,
|
||||
get_lka_steering_cmd_counter,
|
||||
get_volt_one_pedal_target_decel,
|
||||
get_testing_ground_1_brake_switch_bias,
|
||||
get_acc_dashboard_status_active,
|
||||
get_stock_cc_active_for_cancel,
|
||||
shape_bolt_acc_pedal_low_speed_friction,
|
||||
shape_truck_positive_accel,
|
||||
should_use_fixed_stopping_brake,
|
||||
should_activate_auto_hold,
|
||||
should_activate_volt_one_pedal,
|
||||
should_send_adas_status,
|
||||
should_send_stock_long_cancel,
|
||||
should_spoof_dash_speed,
|
||||
should_spoof_ecm_cruise_status,
|
||||
supports_bolt_acc_pedal_friction_experiment,
|
||||
supports_volt_auto_hold,
|
||||
supports_volt_one_pedal,
|
||||
use_interceptor_sng_launch,
|
||||
)
|
||||
from opendbc.car.gm.values import AccState, CAR, GMFlags
|
||||
from opendbc.car.gm.gmcan import get_friction_brake_mode
|
||||
from opendbc.car.gm.values import AccState, CAR, CarControllerParams, GMFlags
|
||||
from opendbc.car.structs import CarParams
|
||||
from opendbc.car.common.conversions import Conversions as CV
|
||||
|
||||
|
||||
def _cs(enabled, pcm_acc_status):
|
||||
@@ -81,6 +104,7 @@ def _controller(car_fingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021):
|
||||
controller.pedal_steady = 0.0
|
||||
controller.aego = 0.0
|
||||
controller.maneuver_paddle_mode = "auto"
|
||||
controller.bolt_acc_pedal_friction_low_speed_active = False
|
||||
return controller
|
||||
|
||||
|
||||
@@ -96,12 +120,201 @@ def test_gen2_bolt_acc_pedal_cancel_uses_enabled_only():
|
||||
assert not get_stock_cc_active_for_cancel(CP, _cs(False, AccState.ACTIVE))
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_friction_experiment_is_single_fingerprint_only():
|
||||
assert supports_bolt_acc_pedal_friction_experiment(SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
|
||||
openpilotLongitudinalControl=True,
|
||||
enableGasInterceptorDEPRECATED=True,
|
||||
flags=GMFlags.PEDAL_LONG.value,
|
||||
))
|
||||
assert not supports_bolt_acc_pedal_friction_experiment(SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_MALIBU_HYBRID_CC,
|
||||
openpilotLongitudinalControl=True,
|
||||
enableGasInterceptorDEPRECATED=True,
|
||||
flags=GMFlags.PEDAL_LONG.value,
|
||||
))
|
||||
assert not supports_bolt_acc_pedal_friction_experiment(SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
|
||||
openpilotLongitudinalControl=False,
|
||||
enableGasInterceptorDEPRECATED=True,
|
||||
flags=GMFlags.PEDAL_LONG.value,
|
||||
))
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_friction_blend_preserves_zero_before_crossover():
|
||||
params = SimpleNamespace(ACCEL_MIN=-4.0, MAX_BRAKE=400)
|
||||
|
||||
assert get_bolt_acc_pedal_friction_brake(0, -2.8, 20.0, params) == 0
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_friction_blend_uses_full_brake_range_after_regen():
|
||||
params = SimpleNamespace(ACCEL_MIN=-4.0, MAX_BRAKE=400)
|
||||
|
||||
# Legacy mapping tops out early once regen has already consumed part of the
|
||||
# decel request. The experiment remaps that reduced span back to full scale.
|
||||
assert get_bolt_acc_pedal_friction_brake(286, -2.86, 20.0, params) == 400
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_friction_blend_biases_small_commands_upward_at_speed():
|
||||
params = SimpleNamespace(ACCEL_MIN=-4.0, MAX_BRAKE=400)
|
||||
|
||||
low_speed = get_bolt_acc_pedal_friction_brake(31, -2.86, 0.0, params)
|
||||
high_speed = get_bolt_acc_pedal_friction_brake(31, -2.86, 20.0, params)
|
||||
|
||||
assert low_speed > 31
|
||||
assert high_speed > low_speed
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_friction_blend_applies_a_minimum_pre_stop_command_at_speed():
|
||||
params = SimpleNamespace(ACCEL_MIN=-4.0, MAX_BRAKE=400)
|
||||
|
||||
assert get_bolt_acc_pedal_friction_brake(2, -2.86, 17.0, params) >= 18
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_friction_blend_boosts_midrange_commands_before_stopping_phase():
|
||||
params = SimpleNamespace(ACCEL_MIN=-4.0, MAX_BRAKE=400)
|
||||
|
||||
assert get_bolt_acc_pedal_friction_brake(40, -2.86, 15.0, params) >= 80
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_low_speed_friction_ignores_tiny_inactive_brake_requests():
|
||||
apply_brake, active = shape_bolt_acc_pedal_low_speed_friction(9, 5.0, False, False)
|
||||
|
||||
assert apply_brake == 0
|
||||
assert not active
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_low_speed_friction_uses_hysteresis_once_active():
|
||||
apply_brake, active = shape_bolt_acc_pedal_low_speed_friction(24, 3.0, False, False)
|
||||
assert apply_brake == 24
|
||||
assert active
|
||||
|
||||
apply_brake, active = shape_bolt_acc_pedal_low_speed_friction(5, 3.0, False, active)
|
||||
assert apply_brake == 0
|
||||
assert not active
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_low_speed_friction_fades_out_at_standstill():
|
||||
apply_brake, active = shape_bolt_acc_pedal_low_speed_friction(80, 0.2, True, True)
|
||||
|
||||
assert apply_brake == 0
|
||||
assert not active
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_low_speed_friction_preserves_rolling_stop_authority():
|
||||
apply_brake, active = shape_bolt_acc_pedal_low_speed_friction(80, 1.2, True, True)
|
||||
|
||||
assert 0 < apply_brake < 80
|
||||
assert active
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_low_speed_friction_drops_out_before_two_clamp():
|
||||
apply_brake, active = shape_bolt_acc_pedal_low_speed_friction(80, 0.9, True, True)
|
||||
|
||||
assert apply_brake == 0
|
||||
assert not active
|
||||
|
||||
|
||||
def test_bolt_pedal_long_accel_limit_matches_planner_regen_envelope():
|
||||
assert get_bolt_pedal_long_accel_limit(6.66) == pytest.approx(-2.379, abs=1e-3)
|
||||
assert get_bolt_pedal_long_accel_limit(3.0) == pytest.approx(-1.70, abs=1e-3)
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_planner_brake_switch_is_lower_than_stock_switch():
|
||||
params = SimpleNamespace(ZERO_GAS=6150, BRAKE_SWITCH_LOOKUP_BP=[0.5, 10.0], BRAKE_SWITCH_LOOKUP_V=[6150, 5500])
|
||||
v_ego = 6.66
|
||||
|
||||
stock_switch = int(round(np.interp(v_ego, params.BRAKE_SWITCH_LOOKUP_BP, params.BRAKE_SWITCH_LOOKUP_V)))
|
||||
planner_switch = get_bolt_acc_pedal_planner_brake_switch(
|
||||
v_ego, params, tire_radius=0.336, mass=1832.0, coeff_drag=0.30, frontal_area=2.35, air_density=1.225,
|
||||
)
|
||||
|
||||
assert planner_switch < stock_switch
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_effective_brake_switch_never_suppresses_stock_friction():
|
||||
params = SimpleNamespace(ZERO_GAS=6150, BRAKE_SWITCH_LOOKUP_BP=[0.5, 10.0], BRAKE_SWITCH_LOOKUP_V=[6150, 5500])
|
||||
v_ego = 5.434
|
||||
mass = 1805.0
|
||||
tire_radius = 0.075 * 2.63779 + 0.1453
|
||||
frontal_area = 1.05 * 2.63779 + 0.0679
|
||||
coeff_drag = 0.30
|
||||
air_density = 1.225
|
||||
accel_cmd = -1.399
|
||||
|
||||
aero_drag_force = 0.5 * coeff_drag * frontal_area * air_density * v_ego ** 2
|
||||
torque = tire_radius * ((mass * accel_cmd) + aero_drag_force)
|
||||
scaled_torque = torque + params.ZERO_GAS
|
||||
|
||||
stock_switch = int(round(np.interp(v_ego, params.BRAKE_SWITCH_LOOKUP_BP, params.BRAKE_SWITCH_LOOKUP_V)))
|
||||
planner_switch = get_bolt_acc_pedal_planner_brake_switch(
|
||||
v_ego, params, tire_radius=tire_radius, mass=mass,
|
||||
coeff_drag=coeff_drag, frontal_area=frontal_area, air_density=air_density,
|
||||
)
|
||||
effective_switch = get_bolt_acc_pedal_effective_brake_switch(stock_switch, planner_switch)
|
||||
|
||||
stock_brake_accel = min((scaled_torque - stock_switch) / (tire_radius * mass), 0)
|
||||
effective_brake_accel = min((scaled_torque - effective_switch) / (tire_radius * mass), 0)
|
||||
|
||||
assert planner_switch < stock_switch
|
||||
assert effective_switch == stock_switch
|
||||
assert stock_brake_accel < 0
|
||||
assert effective_brake_accel == stock_brake_accel
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_friction_command_state_requires_cruise_main_for_positive_brake():
|
||||
command_brake, release_frames, should_send = get_bolt_acc_pedal_friction_command_state(120, False, 0)
|
||||
|
||||
assert command_brake == 0
|
||||
assert release_frames == 0
|
||||
assert not should_send
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_friction_command_state_sends_zero_unwind_after_main_off():
|
||||
command_brake, release_frames, should_send = get_bolt_acc_pedal_friction_command_state(120, True, 0)
|
||||
|
||||
assert command_brake == 120
|
||||
assert release_frames > 0
|
||||
assert should_send
|
||||
|
||||
command_brake, release_frames, should_send = get_bolt_acc_pedal_friction_command_state(0, False, release_frames)
|
||||
|
||||
assert command_brake == 0
|
||||
assert release_frames >= 0
|
||||
assert should_send
|
||||
|
||||
|
||||
def test_fixed_stopping_brake_is_disabled_for_bolt_acc_pedal_experiment():
|
||||
CP = SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
|
||||
openpilotLongitudinalControl=True,
|
||||
enableGasInterceptorDEPRECATED=True,
|
||||
flags=GMFlags.PEDAL_LONG.value,
|
||||
)
|
||||
|
||||
assert not should_use_fixed_stopping_brake(CP, True, True, False)
|
||||
|
||||
|
||||
def test_fixed_stopping_brake_stays_enabled_for_normal_acc_path():
|
||||
CP = SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023,
|
||||
openpilotLongitudinalControl=True,
|
||||
enableGasInterceptorDEPRECATED=False,
|
||||
flags=0,
|
||||
)
|
||||
|
||||
assert should_use_fixed_stopping_brake(CP, True, True, False)
|
||||
assert not should_use_fixed_stopping_brake(CP, False, True, False)
|
||||
assert not should_use_fixed_stopping_brake(CP, True, False, False)
|
||||
assert not should_use_fixed_stopping_brake(CP, True, True, True)
|
||||
|
||||
|
||||
def test_stock_cancel_is_suppressed_when_acc_is_faulted():
|
||||
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_CAMERA)
|
||||
cs = _cs(True, AccState.FAULTED)
|
||||
cs.out.accFaulted = True
|
||||
|
||||
assert not get_stock_cc_active_for_cancel(CP, cs)
|
||||
assert get_stock_cc_active_for_cancel(CP, cs)
|
||||
assert not should_send_stock_long_cancel(11, cs)
|
||||
|
||||
|
||||
@@ -143,11 +356,35 @@ def test_live_camera_path_does_not_send_pt_keepalive():
|
||||
assert get_adas_keepalive_step(cp, is_kaofui_car=True) is None
|
||||
|
||||
|
||||
def test_ascm_int_cars_do_not_send_radar_status():
|
||||
common = {
|
||||
"networkLocation": CarParams.NetworkLocation.fwdCamera,
|
||||
"radarUnavailable": False,
|
||||
}
|
||||
|
||||
assert not should_send_adas_status(SimpleNamespace(carFingerprint=CAR.BUICK_LACROSSE_ASCM, **common), is_kaofui_car=True)
|
||||
assert not should_send_adas_status(SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_ASCM, **common), is_kaofui_car=True)
|
||||
|
||||
|
||||
def test_lacrosse_ascm_marks_acc_dashboard_active_for_aol_only():
|
||||
cc = SimpleNamespace(enabled=False, latActive=True)
|
||||
|
||||
assert get_acc_dashboard_status_active(SimpleNamespace(carFingerprint=CAR.BUICK_LACROSSE_ASCM), cc)
|
||||
assert not get_acc_dashboard_status_active(SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_ASCM), cc)
|
||||
assert not get_acc_dashboard_status_active(SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023), cc)
|
||||
|
||||
|
||||
def test_acc_dashboard_status_active_for_normal_enabled_cars():
|
||||
cc = SimpleNamespace(enabled=True, latActive=False)
|
||||
|
||||
assert get_acc_dashboard_status_active(SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_ASCM), cc)
|
||||
|
||||
|
||||
def test_volt_auto_hold_requires_toggle_supported_non_cc_only_volt_and_stock_safety():
|
||||
stock_safety = [SimpleNamespace(safetyParam=0x8000)]
|
||||
no_safety = [SimpleNamespace(safetyParam=0)]
|
||||
|
||||
assert supports_volt_auto_hold(
|
||||
assert not supports_volt_auto_hold(
|
||||
SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
|
||||
openpilotLongitudinalControl=True,
|
||||
@@ -165,6 +402,15 @@ def test_volt_auto_hold_requires_toggle_supported_non_cc_only_volt_and_stock_saf
|
||||
),
|
||||
True,
|
||||
)
|
||||
assert supports_volt_auto_hold(
|
||||
SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
|
||||
openpilotLongitudinalControl=True,
|
||||
networkLocation=CarParams.NetworkLocation.fwdCamera,
|
||||
safetyConfigs=stock_safety,
|
||||
),
|
||||
True,
|
||||
)
|
||||
assert supports_volt_auto_hold(
|
||||
SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_VOLT,
|
||||
@@ -208,6 +454,60 @@ def test_auto_hold_brake_estimate_uses_driver_or_op_brake_and_clamps():
|
||||
assert estimate_auto_hold_brake(20.0, 40.0) == 110
|
||||
assert estimate_auto_hold_brake(20.0, 160.0) == 160
|
||||
assert estimate_auto_hold_brake(100.0, 400.0) == 240
|
||||
assert estimate_auto_hold_brake(7.0, 0.0, SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_2019)) == 100
|
||||
|
||||
|
||||
def test_volt_one_pedal_requires_toggle_supported_volt_stock_safety_and_ev_transmission():
|
||||
stock_safety = [SimpleNamespace(safetyParam=0x8000)]
|
||||
no_safety = [SimpleNamespace(safetyParam=0)]
|
||||
|
||||
assert supports_volt_one_pedal(
|
||||
SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
|
||||
safetyConfigs=stock_safety,
|
||||
transmissionType=structs.CarParams.TransmissionType.direct,
|
||||
),
|
||||
True,
|
||||
)
|
||||
assert not supports_volt_one_pedal(
|
||||
SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
|
||||
safetyConfigs=no_safety,
|
||||
transmissionType=structs.CarParams.TransmissionType.direct,
|
||||
),
|
||||
True,
|
||||
)
|
||||
assert not supports_volt_one_pedal(
|
||||
SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_VOLT_CC,
|
||||
safetyConfigs=stock_safety,
|
||||
transmissionType=structs.CarParams.TransmissionType.direct,
|
||||
),
|
||||
True,
|
||||
)
|
||||
assert not supports_volt_one_pedal(
|
||||
SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
|
||||
safetyConfigs=stock_safety,
|
||||
transmissionType=structs.CarParams.TransmissionType.automatic,
|
||||
),
|
||||
True,
|
||||
)
|
||||
assert not supports_volt_one_pedal(
|
||||
SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
|
||||
safetyConfigs=stock_safety,
|
||||
transmissionType=structs.CarParams.TransmissionType.direct,
|
||||
),
|
||||
False,
|
||||
)
|
||||
|
||||
|
||||
def test_auto_hold_drive_gears_accept_capnp_dynamic_enum_membership():
|
||||
msg = structs.CarState.new_message()
|
||||
msg.gearShifter = structs.CarState.GearShifter.drive
|
||||
|
||||
assert msg.gearShifter in AUTO_HOLD_DRIVE_GEARS
|
||||
|
||||
|
||||
def test_auto_hold_activation_allows_direct_entry_from_stopped_brake_press():
|
||||
@@ -216,6 +516,7 @@ def test_auto_hold_activation_allows_direct_entry_from_stopped_brake_press():
|
||||
False,
|
||||
False,
|
||||
True,
|
||||
False,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
@@ -229,6 +530,7 @@ def test_auto_hold_activation_stays_latched_after_brake_release():
|
||||
False,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
@@ -236,12 +538,42 @@ def test_auto_hold_activation_stays_latched_after_brake_release():
|
||||
)
|
||||
|
||||
|
||||
def test_volt_2019_auto_hold_engaged_uses_near_stop_creep_hysteresis():
|
||||
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_2019)
|
||||
|
||||
assert get_auto_hold_stop_threshold(CP, True) == CarControllerParams.NEAR_STOP_BRAKE_PHASE
|
||||
assert should_activate_auto_hold(
|
||||
True,
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
0.05,
|
||||
get_auto_hold_stop_threshold(CP, True),
|
||||
)
|
||||
assert not should_activate_auto_hold(
|
||||
True,
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
0.05,
|
||||
)
|
||||
|
||||
|
||||
def test_auto_hold_activation_blocks_when_long_is_active_or_motion_is_above_threshold():
|
||||
assert not should_activate_auto_hold(
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
True,
|
||||
False,
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
@@ -254,6 +586,8 @@ def test_auto_hold_activation_blocks_when_long_is_active_or_motion_is_above_thre
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
0.03,
|
||||
)
|
||||
|
||||
@@ -264,6 +598,7 @@ def test_auto_hold_activation_allows_standstill_even_if_speed_filter_is_slightly
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
@@ -271,6 +606,150 @@ def test_auto_hold_activation_allows_standstill_even_if_speed_filter_is_slightly
|
||||
)
|
||||
|
||||
|
||||
def test_auto_hold_activation_releases_immediately_on_gas_press():
|
||||
assert not should_activate_auto_hold(
|
||||
True,
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
0.0,
|
||||
)
|
||||
|
||||
|
||||
def test_volt_one_pedal_activation_requires_main_l_mode_and_no_driver_input():
|
||||
assert should_activate_volt_one_pedal(
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
True,
|
||||
structs.CarState.GearShifter.low,
|
||||
3.0,
|
||||
)
|
||||
assert not should_activate_volt_one_pedal(
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
True,
|
||||
structs.CarState.GearShifter.low,
|
||||
3.0,
|
||||
)
|
||||
assert not should_activate_volt_one_pedal(
|
||||
True,
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
True,
|
||||
structs.CarState.GearShifter.low,
|
||||
3.0,
|
||||
)
|
||||
assert not should_activate_volt_one_pedal(
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
True,
|
||||
structs.CarState.GearShifter.low,
|
||||
3.0,
|
||||
)
|
||||
assert not should_activate_volt_one_pedal(
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
True,
|
||||
True,
|
||||
structs.CarState.GearShifter.low,
|
||||
3.0,
|
||||
)
|
||||
assert not should_activate_volt_one_pedal(
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
structs.CarState.GearShifter.drive,
|
||||
3.0,
|
||||
)
|
||||
|
||||
|
||||
def test_volt_one_pedal_target_decel_stays_active_above_low_speed_band():
|
||||
assert get_volt_one_pedal_target_decel(0.5 * CV.MPH_TO_MS) == -1.0
|
||||
assert get_volt_one_pedal_target_decel(6.0 * CV.MPH_TO_MS) == -1.1
|
||||
assert get_volt_one_pedal_target_decel(20.0 * CV.MPH_TO_MS) == -1.1
|
||||
|
||||
|
||||
def test_volt_one_pedal_regression_ignores_noisy_wheel_direction_bits():
|
||||
assert should_activate_volt_one_pedal(
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
True,
|
||||
structs.CarState.GearShifter.low,
|
||||
3.0,
|
||||
)
|
||||
|
||||
|
||||
def test_volt_one_pedal_requires_time_in_drive_before_arming():
|
||||
assert not should_activate_volt_one_pedal(
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
True,
|
||||
structs.CarState.GearShifter.low,
|
||||
2.5,
|
||||
)
|
||||
|
||||
|
||||
def test_friction_brake_mode_keeps_near_stop_disabled_for_regular_long_braking():
|
||||
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_ASCM)
|
||||
|
||||
assert get_friction_brake_mode(120, False, True, False, CP) == 0xa
|
||||
|
||||
|
||||
def test_friction_brake_mode_uses_near_stop_hold_mode_for_volt_auto_hold():
|
||||
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_ASCM)
|
||||
|
||||
assert get_friction_brake_mode(120, False, True, False, CP, allow_near_stop_mode=True) == 0xb
|
||||
assert get_friction_brake_mode(120, False, True, True, CP, allow_near_stop_mode=True) == 0xd
|
||||
|
||||
|
||||
def test_friction_brake_mode_uses_stock_bolt_unwind_for_pedal_print_when_enabled():
|
||||
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL)
|
||||
|
||||
assert get_friction_brake_mode(0, False, True, False, CP) == 0x1
|
||||
assert get_friction_brake_mode(0, True, True, False, CP) == 0x9
|
||||
|
||||
|
||||
def test_friction_brake_mode_keeps_bolt_pedal_braking_mode_unchanged():
|
||||
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL)
|
||||
|
||||
assert get_friction_brake_mode(120, True, False, False, CP) == 0xa
|
||||
assert get_friction_brake_mode(120, True, True, True, CP) == 0xd
|
||||
|
||||
|
||||
def test_calc_pedal_command_small_accel_deadband_keeps_creep_target_stable():
|
||||
pos_controller = _controller()
|
||||
neg_controller = _controller()
|
||||
@@ -317,6 +796,27 @@ def test_calc_pedal_command_keeps_strong_positive_requests_responsive():
|
||||
assert pedal_gas - 0.18 > 0.04
|
||||
|
||||
|
||||
def test_shape_truck_positive_accel_softens_small_highway_requests():
|
||||
shaped = shape_truck_positive_accel(0.12, 26.0, True)
|
||||
|
||||
assert 0.09 < shaped < 0.10
|
||||
|
||||
|
||||
def test_shape_truck_positive_accel_keeps_mid_follow_requests_available():
|
||||
shaped = shape_truck_positive_accel(0.45, 13.5, True)
|
||||
|
||||
assert 0.43 < shaped < 0.45
|
||||
|
||||
|
||||
def test_shape_truck_positive_accel_leaves_large_requests_alone():
|
||||
assert shape_truck_positive_accel(1.0, 26.0, True) == 1.0
|
||||
|
||||
|
||||
def test_shape_truck_positive_accel_is_inactive_when_disabled_or_low_speed():
|
||||
assert shape_truck_positive_accel(0.12, 26.0, False) == 0.12
|
||||
assert shape_truck_positive_accel(0.12, 6.0, True) == 0.12
|
||||
|
||||
|
||||
def test_use_interceptor_sng_launch_requires_actual_near_stop():
|
||||
CP = SimpleNamespace(vEgoStarting=0.25)
|
||||
|
||||
@@ -326,6 +826,42 @@ def test_use_interceptor_sng_launch_requires_actual_near_stop():
|
||||
assert not use_interceptor_sng_launch(CP, _sng_cs(0.0, True, False))
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_sng_launch_uses_physical_standstill_without_stock_acc_bit():
|
||||
CP = SimpleNamespace(
|
||||
vEgoStarting=0.25,
|
||||
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
|
||||
enableGasInterceptorDEPRECATED=True,
|
||||
)
|
||||
|
||||
assert use_interceptor_sng_launch(CP, _sng_cs(0.0, True, False))
|
||||
assert use_interceptor_sng_launch(CP, _sng_cs(0.2, False, False))
|
||||
assert not use_interceptor_sng_launch(CP, _sng_cs(1.2, False, False))
|
||||
|
||||
|
||||
def test_bolt_acc_pedal_sng_launch_preserves_stronger_computed_pedal():
|
||||
CP = SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
|
||||
openpilotLongitudinalControl=True,
|
||||
enableGasInterceptorDEPRECATED=True,
|
||||
flags=GMFlags.PEDAL_LONG.value,
|
||||
)
|
||||
params = SimpleNamespace(SNG_INTERCEPTOR_GAS=18. / 255.)
|
||||
|
||||
assert get_interceptor_sng_gas_cmd(CP, 0.2, 0.54, params, False) == pytest.approx(0.2)
|
||||
|
||||
|
||||
def test_other_pedal_sng_launch_keeps_fixed_floor_behavior():
|
||||
CP = SimpleNamespace(
|
||||
carFingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021,
|
||||
openpilotLongitudinalControl=True,
|
||||
enableGasInterceptorDEPRECATED=True,
|
||||
flags=GMFlags.PEDAL_LONG.value,
|
||||
)
|
||||
params = SimpleNamespace(SNG_INTERCEPTOR_GAS=18. / 255.)
|
||||
|
||||
assert get_interceptor_sng_gas_cmd(CP, 0.2, 0.54, params, False) == pytest.approx(18. / 255.)
|
||||
|
||||
|
||||
def test_use_interceptor_sng_launch_extends_for_maneuver_mode():
|
||||
CP = SimpleNamespace(vEgoStarting=0.25)
|
||||
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import pytest
|
||||
import numpy as np
|
||||
from types import SimpleNamespace
|
||||
from parameterized import parameterized
|
||||
|
||||
from cereal import custom
|
||||
from opendbc.can import CANPacker, CANParser
|
||||
from opendbc.car import Bus, DT_CTRL, structs
|
||||
from opendbc.car.car_helpers import interfaces
|
||||
from opendbc.car.gm import gmcan
|
||||
from opendbc.car.gm.carstate import CarState as GMCarState
|
||||
from opendbc.car.gm.carstate import CarState as GMCarState, get_hard_cruise_buttons, update_auto_hold_drive_timers
|
||||
from opendbc.car.gm.carcontroller import (
|
||||
VisualAlert,
|
||||
get_acc_dashboard_fcw_alert,
|
||||
get_acc_dashboard_status_values,
|
||||
get_volt_one_pedal_lift_brake,
|
||||
should_send_acc_dashboard_status,
|
||||
should_send_cc_button_spam,
|
||||
should_spoof_dash_speed,
|
||||
@@ -18,7 +20,7 @@ from opendbc.car.gm.carcontroller import (
|
||||
import opendbc.car.gm.interface as gm_interface
|
||||
from opendbc.car.common.conversions import Conversions as CV
|
||||
from opendbc.car.gm.fingerprints import FINGERPRINTS
|
||||
from opendbc.car.gm.values import CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, DBC, GM_RX_OFFSET, GMFlags, GMSafetyFlags
|
||||
from opendbc.car.gm.values import ASCM_INT, CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, DBC, GM_RX_OFFSET, CarControllerParams, CruiseButtons, GMFlags, GMSafetyFlags
|
||||
from opendbc.safety import ALTERNATIVE_EXPERIENCE
|
||||
from openpilot.common.params import Params
|
||||
|
||||
@@ -63,6 +65,52 @@ class TestGMFingerprint:
|
||||
|
||||
|
||||
class TestGMInterface:
|
||||
def test_bolt_acc_pedal_pid_accel_limits_keep_full_negative_authority(self):
|
||||
cp = SimpleNamespace(
|
||||
enableGasInterceptorDEPRECATED=True,
|
||||
flags=GMFlags.PEDAL_LONG.value,
|
||||
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
|
||||
)
|
||||
|
||||
accel_min, accel_max = gm_interface.CarInterface.get_pid_accel_limits(cp, 4.73, 0.0)
|
||||
|
||||
assert accel_min == pytest.approx(CarControllerParams.ACCEL_MIN)
|
||||
assert accel_max == pytest.approx(np.interp(4.73, [0.0, 1.5, 4.0, 8.0, 15.0],
|
||||
[0.54, 0.74, 1.03, 1.46, CarControllerParams.ACCEL_MAX]))
|
||||
|
||||
def test_bolt_cc_pedal_pid_accel_limits_remain_regen_limited(self):
|
||||
cp = SimpleNamespace(
|
||||
enableGasInterceptorDEPRECATED=True,
|
||||
flags=GMFlags.PEDAL_LONG.value,
|
||||
carFingerprint=CAR.CHEVROLET_BOLT_CC_2022_2023,
|
||||
)
|
||||
|
||||
accel_min, _ = gm_interface.CarInterface.get_pid_accel_limits(cp, 4.73, 0.0)
|
||||
|
||||
assert accel_min == pytest.approx(np.interp(4.73, [0.0, 1.5, 4.0, 8.0, 15.0, 30.0],
|
||||
[-0.93, -1.28, -1.98, -2.58, -2.86, -2.95]))
|
||||
|
||||
def test_missing_hard_cruise_signal_defaults_to_init(self):
|
||||
assert get_hard_cruise_buttons({"ACCButtons": CruiseButtons.RES_ACCEL}) == CruiseButtons.INIT
|
||||
assert get_hard_cruise_buttons({"ACCButtonsHard": CruiseButtons.DECEL_SET}) == CruiseButtons.DECEL_SET
|
||||
|
||||
def test_volt_auto_hold_drive_timer_requires_motion_before_startup_arming(self):
|
||||
auto_hold_time, one_pedal_time = update_auto_hold_drive_timers(True, False, 0.0, 0.0)
|
||||
|
||||
assert auto_hold_time == 0.0
|
||||
assert one_pedal_time == 0.0
|
||||
|
||||
def test_volt_auto_hold_drive_timer_accumulates_only_while_moving(self):
|
||||
auto_hold_time, one_pedal_time = update_auto_hold_drive_timers(True, True, 0.0, 0.0)
|
||||
|
||||
assert auto_hold_time == pytest.approx(DT_CTRL)
|
||||
assert one_pedal_time == pytest.approx(DT_CTRL)
|
||||
|
||||
auto_hold_time, one_pedal_time = update_auto_hold_drive_timers(True, False, auto_hold_time, one_pedal_time)
|
||||
|
||||
assert auto_hold_time == pytest.approx(DT_CTRL)
|
||||
assert one_pedal_time == pytest.approx(DT_CTRL)
|
||||
|
||||
@parameterized.expand(VOLT_CARS)
|
||||
def test_volt_min_steer_speed_is_7_mph(self, car_model):
|
||||
CarInterface = interfaces[car_model]
|
||||
@@ -84,12 +132,15 @@ class TestGMInterface:
|
||||
|
||||
old_testing_ground = gm_interface.testing_ground
|
||||
gm_interface.testing_ground = SimpleNamespace(use_2=True)
|
||||
params = Params()
|
||||
params.put_bool("GMPedalLongitudinal", True)
|
||||
|
||||
try:
|
||||
car_params = CarInterface.get_params(CAR.CHEVROLET_VOLT_ASCM, fingerprint, [], alpha_long=False, is_release=False, docs=False,
|
||||
starpilot_toggles=_test_starpilot_toggles())
|
||||
finally:
|
||||
gm_interface.testing_ground = old_testing_ground
|
||||
params.remove("GMPedalLongitudinal")
|
||||
|
||||
if pedal_present:
|
||||
assert list(car_params.longitudinalTuning.kpV) == pytest.approx([0.10, 0.072, 0.05, 0.04])
|
||||
@@ -132,6 +183,27 @@ class TestGMInterface:
|
||||
assert list(car_params.longitudinalTuning.kiBP) == pytest.approx([0.0, 5.0, 15.0, 35.0])
|
||||
assert list(car_params.longitudinalTuning.kiV) == pytest.approx([0.28, 0.26, 0.20, 0.16])
|
||||
|
||||
def test_blazer_uses_softer_low_speed_stop_hold_tune(self):
|
||||
CarInterface = interfaces[CAR.CHEVROLET_BLAZER]
|
||||
fingerprint = _empty_fingerprint()
|
||||
fingerprint[0] = FINGERPRINTS[CAR.CHEVROLET_BLAZER][0].copy()
|
||||
fingerprint[0][0x2FF] = 8 # SASCM present so alpha-long can enable on this platform
|
||||
|
||||
car_params = CarInterface.get_params(CAR.CHEVROLET_BLAZER, fingerprint, [], alpha_long=True, is_release=False,
|
||||
docs=False, starpilot_toggles=_test_starpilot_toggles())
|
||||
|
||||
assert car_params.openpilotLongitudinalControl
|
||||
assert list(car_params.longitudinalTuning.kpBP) == pytest.approx([0.0, 4.0, 12.0, 35.0])
|
||||
assert list(car_params.longitudinalTuning.kpV) == pytest.approx([0.09, 0.075, 0.055, 0.04])
|
||||
assert list(car_params.longitudinalTuning.kiBP) == pytest.approx([0.0, 4.0, 12.0, 35.0])
|
||||
assert list(car_params.longitudinalTuning.kiV) == pytest.approx([0.03, 0.04, 0.055, 0.07])
|
||||
assert car_params.longitudinalActuatorDelay == pytest.approx(0.7)
|
||||
assert car_params.minEnableSpeed == pytest.approx(5 * CV.KPH_TO_MS)
|
||||
assert car_params.stoppingDecelRate == pytest.approx(1.0)
|
||||
assert car_params.vEgoStopping == pytest.approx(0.35)
|
||||
assert car_params.vEgoStarting == pytest.approx(0.35)
|
||||
assert car_params.stopAccel == pytest.approx(-0.30)
|
||||
|
||||
def test_volt_gateway_without_accel_pos_uses_brake_pedal_message(self):
|
||||
CarInterface = interfaces[CAR.CHEVROLET_VOLT]
|
||||
fingerprint = _empty_fingerprint()
|
||||
@@ -163,6 +235,25 @@ class TestGMInterface:
|
||||
assert car_params.openpilotLongitudinalControl
|
||||
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value
|
||||
|
||||
def test_volt_one_pedal_sets_stock_hold_safety_bit_without_auto_hold(self):
|
||||
CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM]
|
||||
fingerprint = _empty_fingerprint()
|
||||
fingerprint[0][0x2FF] = 8
|
||||
|
||||
params = Params()
|
||||
try:
|
||||
params.put_bool("GMAutoHold", False)
|
||||
params.put_bool("VoltOnePedalMode", True)
|
||||
car_params = CarInterface.get_params(CAR.CHEVROLET_VOLT_ASCM, fingerprint, [], alpha_long=True, is_release=False,
|
||||
docs=False, starpilot_toggles=_test_starpilot_toggles())
|
||||
finally:
|
||||
params.remove("GMAutoHold")
|
||||
params.remove("VoltOnePedalMode")
|
||||
|
||||
assert car_params.openpilotLongitudinalControl
|
||||
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value
|
||||
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_3D1_SCHED.value
|
||||
|
||||
@parameterized.expand(VOLT_CARS)
|
||||
def test_volt_bsm_is_enabled_without_fingerprint_match(self, car_model):
|
||||
CarInterface = interfaces[car_model]
|
||||
@@ -209,14 +300,17 @@ class TestGMInterface:
|
||||
params = Params()
|
||||
toggles = _test_starpilot_toggles()
|
||||
try:
|
||||
params.put_bool("GMPedalLongitudinal", True)
|
||||
params.put_bool("RemapCancelToDistance", True)
|
||||
car_params = CarInterface.get_params(CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL, fingerprint, [], alpha_long=False,
|
||||
is_release=False, docs=False, starpilot_toggles=toggles)
|
||||
finally:
|
||||
params.remove("GMPedalLongitudinal")
|
||||
params.remove("RemapCancelToDistance")
|
||||
|
||||
assert car_params.alternativeExperience & ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE
|
||||
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_BOLT_2022_PEDAL.value
|
||||
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value
|
||||
|
||||
def test_cadillac_xt5_sdgm_sascm_gates_alpha_long(self):
|
||||
CarInterface = interfaces[CAR.CADILLAC_XT5]
|
||||
@@ -242,6 +336,49 @@ class TestGMInterface:
|
||||
assert not sascm_params.pcmCruise
|
||||
assert sascm_params.safetyConfigs[0].safetyParam & GMSafetyFlags.HW_CAM_LONG.value
|
||||
|
||||
def test_cadillac_escalade_esv_2019_ascm_uses_sascm_and_2019_tune(self):
|
||||
base_fingerprint = FINGERPRINTS[CAR.CADILLAC_ESCALADE_ESV_2019][0]
|
||||
ascm_fingerprint = FINGERPRINTS[CAR.CADILLAC_ESCALADE_ESV_2019_ASCM][0]
|
||||
|
||||
assert CAR.CADILLAC_ESCALADE_ESV_2019_ASCM in ASCM_INT
|
||||
assert ascm_fingerprint[0x2FF] == 8
|
||||
assert {addr: length for addr, length in ascm_fingerprint.items() if addr != 0x2FF} == base_fingerprint
|
||||
|
||||
CarInterface = interfaces[CAR.CADILLAC_ESCALADE_ESV_2019_ASCM]
|
||||
fingerprint = _empty_fingerprint()
|
||||
fingerprint[0] = ascm_fingerprint.copy()
|
||||
|
||||
car_params = CarInterface.get_params(CAR.CADILLAC_ESCALADE_ESV_2019_ASCM, fingerprint, [], alpha_long=True, is_release=False,
|
||||
docs=False, starpilot_toggles=_test_starpilot_toggles())
|
||||
|
||||
assert car_params.flags & GMFlags.SASCM.value
|
||||
assert car_params.networkLocation == structs.CarParams.NetworkLocation.fwdCamera
|
||||
assert car_params.openpilotLongitudinalControl
|
||||
assert not car_params.pcmCruise
|
||||
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.HW_ASCM_INT.value
|
||||
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.HW_CAM_LONG.value
|
||||
assert car_params.lateralTuning.torque.latAccelFactor == pytest.approx(1.15)
|
||||
assert car_params.lateralTuning.torque.friction == pytest.approx(0.2)
|
||||
|
||||
def test_cadillac_xt4_uses_nonlinear_torque_curve_with_center_boost(self):
|
||||
CarInterface = interfaces[CAR.CADILLAC_XT4]
|
||||
car_params = CarInterface.get_non_essential_params(CAR.CADILLAC_XT4)
|
||||
ci = CarInterface(car_params, custom.StarPilotCarParams.new_message())
|
||||
torque_from_lataccel = ci.torque_from_lateral_accel()
|
||||
|
||||
low_lataccel = 0.2
|
||||
high_lataccel = 1.0
|
||||
low_torque = torque_from_lataccel(low_lataccel, car_params.lateralTuning.torque)
|
||||
high_torque = torque_from_lataccel(high_lataccel, car_params.lateralTuning.torque)
|
||||
|
||||
linear_low_torque = low_lataccel / car_params.lateralTuning.torque.latAccelFactor
|
||||
linear_high_torque = high_lataccel / car_params.lateralTuning.torque.latAccelFactor
|
||||
|
||||
assert low_torque > linear_low_torque * 1.15
|
||||
assert low_torque < linear_low_torque * 1.30
|
||||
assert high_torque == pytest.approx(linear_high_torque, rel=0.03)
|
||||
assert torque_from_lataccel(-low_lataccel, car_params.lateralTuning.torque) == pytest.approx(-low_torque, rel=1e-6)
|
||||
|
||||
|
||||
class TestGMCarController:
|
||||
def test_dash_speed_spoof_respects_live_stock_acc_toggles(self):
|
||||
@@ -256,6 +393,11 @@ class TestGMCarController:
|
||||
|
||||
assert should_spoof_dash_speed(cp, SimpleNamespace(disable_openpilot_long=False))
|
||||
|
||||
def test_volt_one_pedal_lift_brake_seeds_low_speed_braking(self):
|
||||
assert get_volt_one_pedal_lift_brake(2.1 * CV.MPH_TO_MS) == 0
|
||||
assert get_volt_one_pedal_lift_brake(2.0 * CV.MPH_TO_MS) == 20
|
||||
assert get_volt_one_pedal_lift_brake(0.10) == 80
|
||||
|
||||
def test_volt_camera_no_camera_sends_acc_dashboard_without_dash_spoof(self):
|
||||
cp = SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_CAMERA, flags=GMFlags.NO_CAMERA.value)
|
||||
|
||||
@@ -354,14 +496,9 @@ class TestGMCarController:
|
||||
msg = gmcan.create_acc_dashboard_command(
|
||||
packer,
|
||||
0,
|
||||
{
|
||||
"ACCCruiseState": 0,
|
||||
"ACCLeadCar": 1,
|
||||
"ACCResumeButton": 0,
|
||||
"ACCSpeedSetpoint": 100,
|
||||
"ACCGapLevel": 3,
|
||||
"ACCCmdActive": 1,
|
||||
},
|
||||
True,
|
||||
100,
|
||||
SimpleNamespace(leadDistanceBars=3, leadVisible=True),
|
||||
0x2,
|
||||
)
|
||||
|
||||
@@ -369,23 +506,26 @@ class TestGMCarController:
|
||||
|
||||
assert parser.vl["ASCMActiveCruiseControlStatus"]["FCWAlert"] == 2
|
||||
|
||||
def test_acc_dashboard_command_can_replay_stock_status_payload(self):
|
||||
def test_acc_dashboard_command_uses_openpilot_hud_when_disengaged(self):
|
||||
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_ASCM][Bus.pt])
|
||||
parser = CANParser(DBC[CAR.CHEVROLET_VOLT_ASCM][Bus.pt], [("ASCMActiveCruiseControlStatus", 0)], 0)
|
||||
msg = gmcan.create_acc_dashboard_command(
|
||||
packer,
|
||||
0,
|
||||
{
|
||||
"ACCCruiseState": 0,
|
||||
"ACCLeadCar": 1,
|
||||
"ACCResumeButton": 0,
|
||||
"ACCSpeedSetpoint": 50,
|
||||
"ACCGapLevel": 2,
|
||||
"ACCCmdActive": 0,
|
||||
},
|
||||
False,
|
||||
50,
|
||||
SimpleNamespace(leadDistanceBars=2, leadVisible=True),
|
||||
0x3,
|
||||
)
|
||||
|
||||
assert msg[1].hex() == "010023200113"
|
||||
parser.update([0, [msg]])
|
||||
values = parser.vl["ASCMActiveCruiseControlStatus"]
|
||||
|
||||
assert values["ACCSpeedSetpoint"] == 50
|
||||
assert values["ACCGapLevel"] == 0
|
||||
assert values["ACCCmdActive"] == 0
|
||||
assert values["ACCLeadCar"] == 1
|
||||
assert values["FCWAlert"] == 3
|
||||
|
||||
def test_acc_dashboard_fcw_alert_prefers_openpilot_alert(self):
|
||||
cs = SimpleNamespace(
|
||||
@@ -418,45 +558,3 @@ class TestGMCarController:
|
||||
)
|
||||
|
||||
assert get_acc_dashboard_fcw_alert(VisualAlert.none, cs) == 0x3
|
||||
|
||||
def test_acc_dashboard_status_values_use_openpilot_hud_when_enabled(self):
|
||||
cs = SimpleNamespace(
|
||||
stock_acc_cruise_state=5,
|
||||
stock_acc_lead_car=0,
|
||||
stock_acc_resume_button=1,
|
||||
stock_acc_speed_setpoint_kph=42.0,
|
||||
stock_acc_gap_level=1,
|
||||
stock_acc_cmd_active=0,
|
||||
)
|
||||
|
||||
values = get_acc_dashboard_status_values(True, 105.0, SimpleNamespace(leadDistanceBars=3, leadVisible=True), cs)
|
||||
|
||||
assert values == {
|
||||
"ACCCruiseState": 0,
|
||||
"ACCLeadCar": 1,
|
||||
"ACCResumeButton": 0,
|
||||
"ACCSpeedSetpoint": 105.0,
|
||||
"ACCGapLevel": 3,
|
||||
"ACCCmdActive": 1,
|
||||
}
|
||||
|
||||
def test_acc_dashboard_status_values_reuse_stock_camera_status_when_disabled(self):
|
||||
cs = SimpleNamespace(
|
||||
stock_acc_cruise_state=0,
|
||||
stock_acc_lead_car=1,
|
||||
stock_acc_resume_button=0,
|
||||
stock_acc_speed_setpoint_kph=50.0,
|
||||
stock_acc_gap_level=2,
|
||||
stock_acc_cmd_active=0,
|
||||
)
|
||||
|
||||
values = get_acc_dashboard_status_values(False, 0.0, SimpleNamespace(leadDistanceBars=0, leadVisible=False), cs)
|
||||
|
||||
assert values == {
|
||||
"ACCCruiseState": 0,
|
||||
"ACCLeadCar": 1,
|
||||
"ACCResumeButton": 0,
|
||||
"ACCSpeedSetpoint": 50.0,
|
||||
"ACCGapLevel": 2,
|
||||
"ACCCmdActive": 0,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
from opendbc.can import CANPacker
|
||||
from opendbc.car.gm import gmcan
|
||||
from opendbc.car.gm.values import CAR, DBC
|
||||
@@ -26,6 +28,39 @@ class TestGMCan:
|
||||
assert dat[1] & 0x1
|
||||
assert decoded == 8848
|
||||
|
||||
def test_prndl2_command_matches_bolt_gen2_regen_paddle_spoof(self):
|
||||
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL)
|
||||
|
||||
addr, dat, bus = gmcan.create_prndl2_command(self.packer, 0, False, CP)
|
||||
assert addr == 0x1F5
|
||||
assert bus == 0
|
||||
assert dat.hex() == "0c0c000600000100"
|
||||
|
||||
addr, dat, bus = gmcan.create_prndl2_command(self.packer, 0, True, CP)
|
||||
assert addr == 0x1F5
|
||||
assert bus == 0
|
||||
assert dat.hex() == "0c0c000500020100"
|
||||
|
||||
def test_prndl2_command_matches_bolt_gen1_regen_paddle_spoof(self):
|
||||
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021)
|
||||
|
||||
addr, dat, bus = gmcan.create_prndl2_command(self.packer, 0, True, CP)
|
||||
|
||||
assert addr == 0x1F5
|
||||
assert bus == 0
|
||||
assert dat.hex() == "0c0c000700020100"
|
||||
|
||||
def test_regen_paddle_command_matches_bolt_spoof(self):
|
||||
addr, dat, bus = gmcan.create_regen_paddle_command(self.packer, 0, False)
|
||||
assert addr == 0xBD
|
||||
assert bus == 0
|
||||
assert dat.hex() == "00000000000000"
|
||||
|
||||
addr, dat, bus = gmcan.create_regen_paddle_command(self.packer, 0, True)
|
||||
assert addr == 0xBD
|
||||
assert bus == 0
|
||||
assert dat.hex() == "20000000000000"
|
||||
|
||||
|
||||
def test_gas_regen_command_matches_starpilot_volt_2019(self):
|
||||
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_2019]["pt"])
|
||||
@@ -42,11 +77,3 @@ class TestGMCan:
|
||||
assert addr == 0x2CB
|
||||
assert bus == 0
|
||||
assert dat.hex() == "41429c4000bd63bf"
|
||||
|
||||
def test_gas_regen_command_matches_opgm_plain_volt_layout(self):
|
||||
packer = CANPacker("gm_global_a_powertrain_generated")
|
||||
addr, dat, bus = gmcan.create_gas_regen_command(packer, 0, 5000, 1, True, False, use_generated_layout=True)
|
||||
|
||||
assert addr == 0x2CB
|
||||
assert bus == 0
|
||||
assert dat.hex() == "41435c7000bca38f"
|
||||
|
||||
@@ -303,6 +303,10 @@ class CAR(Platforms):
|
||||
[GMCarDocs("Cadillac Escalade ESV 2019", "Adaptive Cruise Control (ACC) & LKAS")],
|
||||
CADILLAC_ESCALADE_ESV.specs,
|
||||
)
|
||||
CADILLAC_ESCALADE_ESV_2019_ASCM = GMPlatformConfig(
|
||||
[GMCarDocs("Cadillac Escalade ESV Platinum 2019 ASCM Harness", "Adaptive Cruise Control (ACC) & LKAS")],
|
||||
CADILLAC_ESCALADE_ESV_2019.specs,
|
||||
)
|
||||
CHEVROLET_BOLT_ACC_2022_2023 = GMPlatformConfig(
|
||||
[
|
||||
GMCarDocs("Chevrolet Bolt ACC 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", video="https://youtu.be/xvwzGMUA210"),
|
||||
@@ -576,7 +580,14 @@ CC_REGEN_PADDLE_CAR = {
|
||||
CAMERA_ACC_CAR.update(CC_ONLY_CAR)
|
||||
|
||||
# ASCM-INT paths are only enabled when SASCM (0x2FF) is detected at runtime
|
||||
ASCM_INT = {CAR.CHEVROLET_VOLT_ASCM, CAR.GMC_ACADIA_ASCM, CAR.CHEVROLET_MALIBU_ASCM, CAR.CADILLAC_ESCALADE_ASCM, CAR.BUICK_LACROSSE_ASCM}
|
||||
ASCM_INT = {
|
||||
CAR.CHEVROLET_VOLT_ASCM,
|
||||
CAR.GMC_ACADIA_ASCM,
|
||||
CAR.CHEVROLET_MALIBU_ASCM,
|
||||
CAR.CADILLAC_ESCALADE_ASCM,
|
||||
CAR.CADILLAC_ESCALADE_ESV_2019_ASCM,
|
||||
CAR.BUICK_LACROSSE_ASCM,
|
||||
}
|
||||
|
||||
STEER_THRESHOLD = 1.0
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ from opendbc.car.lateral import apply_driver_steer_torque_limits, apply_steer_an
|
||||
from opendbc.car.common.conversions import Conversions as CV
|
||||
from opendbc.car.hyundai import hyundaicanfd, hyundaican
|
||||
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from opendbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR, CANFD_RADAR_LIVE_LONGITUDINAL_CAR
|
||||
from opendbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR, CANFD_RADAR_LIVE_LONGITUDINAL_CAR, \
|
||||
kia_ev6_gt_line_longitudinal_tuning
|
||||
from opendbc.car.interfaces import CarControllerBase
|
||||
from opendbc.car.vehicle_model import VehicleModel
|
||||
from openpilot.common.params import Params
|
||||
@@ -63,6 +64,21 @@ REDNECK_BUTTON_COPIES_TIME = 7
|
||||
REDNECK_BUTTON_COPIES_TIME_IMPERIAL = [REDNECK_BUTTON_COPIES_TIME + 3, 70]
|
||||
REDNECK_BUTTON_COPIES_TIME_METRIC = [REDNECK_BUTTON_COPIES_TIME, 40]
|
||||
ANGLE_SAFETY_BASELINE_MODEL = str(CAR.KIA_SPORTAGE_HEV_2026)
|
||||
DEFAULT_ANGLE_SMOOTHING_VEGO_BP = [5.0, 10.0, 20.0]
|
||||
DEFAULT_ANGLE_SMOOTHING_ALPHA_V = [0.2, 0.1, 0.0]
|
||||
EV9_HIGH_ANGLE_GAIN_BP = [70.0, 120.0, 220.0, 320.0]
|
||||
EV9_HIGH_ANGLE_GAIN_CAP_V = [0.85, 0.55, 0.30, 0.16]
|
||||
EV9_HIGH_ANGLE_GAIN_MIN = 0.004
|
||||
|
||||
|
||||
def egmp_dynamic_longitudinal_tuning(CP) -> bool:
|
||||
return CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 or \
|
||||
kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, getattr(CP, "carVin", ""))
|
||||
|
||||
|
||||
def should_reset_ev6_gt_line_longitudinal_tuning(CP, long_control_state: LongCtrlState) -> bool:
|
||||
return kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, getattr(CP, "carVin", "")) and \
|
||||
long_control_state == LongCtrlState.off
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -78,6 +94,13 @@ class Ioniq6LongitudinalTuningState:
|
||||
long_control_state_last: LongCtrlState = LongCtrlState.off
|
||||
|
||||
|
||||
def reset_ev6_gt_line_longitudinal_tuning(state: Ioniq6LongitudinalTuningState, CP,
|
||||
long_control_state: LongCtrlState) -> Ioniq6LongitudinalTuningState:
|
||||
if should_reset_ev6_gt_line_longitudinal_tuning(CP, long_control_state):
|
||||
return Ioniq6LongitudinalTuningState(long_control_state_last=long_control_state)
|
||||
return state
|
||||
|
||||
|
||||
@dataclass
|
||||
class GenesisG90LongitudinalTuningState:
|
||||
actual_accel: float = 0.0
|
||||
@@ -202,6 +225,10 @@ def get_baseline_safety_cp():
|
||||
return CarInterface.get_non_essential_params(ANGLE_SAFETY_BASELINE_MODEL)
|
||||
|
||||
|
||||
def get_angle_smoothing_alpha(CP, v_ego: float) -> float:
|
||||
return float(np.interp(v_ego, DEFAULT_ANGLE_SMOOTHING_VEGO_BP, DEFAULT_ANGLE_SMOOTHING_ALPHA_V))
|
||||
|
||||
|
||||
def compute_torque_reduction_gain(steering_torque, v_ego, lat_active, last_gain):
|
||||
if lat_active:
|
||||
ceiling = np.interp(v_ego, [0.5, 1.5], [1.0, 0.85])
|
||||
@@ -219,6 +246,14 @@ def compute_torque_reduction_gain(steering_torque, v_ego, lat_active, last_gain)
|
||||
return round(gain / 0.004) * 0.004
|
||||
|
||||
|
||||
def apply_ev9_high_angle_gain_cap(CP, gain: float, steering_angle_deg: float, lat_active: bool) -> float:
|
||||
if CP.carFingerprint != CAR.KIA_EV9 or not CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING or not lat_active:
|
||||
return gain
|
||||
|
||||
cap = float(np.interp(abs(steering_angle_deg), EV9_HIGH_ANGLE_GAIN_BP, EV9_HIGH_ANGLE_GAIN_CAP_V))
|
||||
return max(EV9_HIGH_ANGLE_GAIN_MIN, min(gain, cap))
|
||||
|
||||
|
||||
def process_hud_alert(enabled, fingerprint, hud_control):
|
||||
sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
|
||||
|
||||
@@ -364,7 +399,7 @@ class CarController(CarControllerBase):
|
||||
-self.params.ANGLE_LIMITS.STEER_ANGLE_MAX,
|
||||
self.params.ANGLE_LIMITS.STEER_ANGLE_MAX))
|
||||
|
||||
self.angle_filter.update_alpha(float(np.interp(CS.out.vEgo, [5.0, 10.0, 20.0], [0.2, 0.1, 0.0])))
|
||||
self.angle_filter.update_alpha(get_angle_smoothing_alpha(self.CP, CS.out.vEgo))
|
||||
desired_angle = self.angle_filter.update(desired_angle)
|
||||
|
||||
apply_angle = apply_steer_angle_limits_vm(desired_angle, self.apply_angle_last, v_ego_raw,
|
||||
@@ -375,6 +410,7 @@ class CarController(CarControllerBase):
|
||||
CS.out.steeringAngleDeg, CC.latActive, self.params, self.BASELINE_VM)
|
||||
|
||||
apply_torque = compute_torque_reduction_gain(CS.out.steeringTorque, v_ego_raw, CC.latActive, self.apply_torque_last)
|
||||
apply_torque = apply_ev9_high_angle_gain_cap(self.CP, apply_torque, CS.out.steeringAngleDeg, CC.latActive)
|
||||
apply_steer_req = CC.latActive and apply_torque != 0.0
|
||||
torque_fault = False
|
||||
|
||||
@@ -426,22 +462,25 @@ class CarController(CarControllerBase):
|
||||
# longitudinal messages - stock ECU is still active and these would conflict
|
||||
self.long_active_ecu = self.CP.openpilotLongitudinalControl and not self.ecu_disable_failed
|
||||
|
||||
use_ioniq_6_dynamic_long_tuning = self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and self.long_active_ecu and \
|
||||
actuators.longControlState in (LongCtrlState.starting, LongCtrlState.pid, LongCtrlState.stopping)
|
||||
if use_ioniq_6_dynamic_long_tuning and self.frame % 5 == 0:
|
||||
use_egmp_dynamic_long_tuning = egmp_dynamic_longitudinal_tuning(self.CP) and self.long_active_ecu and \
|
||||
actuators.longControlState in (LongCtrlState.starting, LongCtrlState.pid, LongCtrlState.stopping)
|
||||
if should_reset_ev6_gt_line_longitudinal_tuning(self.CP, actuators.longControlState):
|
||||
self._ioniq_6_long_tuning = reset_ev6_gt_line_longitudinal_tuning(self._ioniq_6_long_tuning, self.CP,
|
||||
actuators.longControlState)
|
||||
elif use_egmp_dynamic_long_tuning and self.frame % 5 == 0:
|
||||
self._ioniq_6_long_tuning = update_ioniq_6_longitudinal_tuning(self._ioniq_6_long_tuning, accel_cmd,
|
||||
CS.out.vEgo, CS.out.aEgo,
|
||||
actuators.longControlState, self.long_active_ecu)
|
||||
use_ioniq_6_smoothed_accel = use_ioniq_6_dynamic_long_tuning and (
|
||||
use_egmp_smoothed_accel = use_egmp_dynamic_long_tuning and (
|
||||
accel_cmd >= self._ioniq_6_long_tuning.actual_accel or
|
||||
self._ioniq_6_long_tuning.launch_active or
|
||||
self._ioniq_6_long_tuning.stopping
|
||||
)
|
||||
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and self.long_active_ecu:
|
||||
if use_ioniq_6_smoothed_accel:
|
||||
if use_egmp_dynamic_long_tuning:
|
||||
if use_egmp_smoothed_accel:
|
||||
accel = self._ioniq_6_long_tuning.actual_accel
|
||||
stopping = self._ioniq_6_long_tuning.stopping
|
||||
elif use_ioniq_6_dynamic_long_tuning:
|
||||
else:
|
||||
accel = float(np.clip(accel_cmd,
|
||||
self.accel_last - IONIQ_6_CANFD_SCC_DECEL_STEP,
|
||||
self.accel_last + IONIQ_6_CANFD_SCC_ACCEL_STEP))
|
||||
@@ -566,20 +605,31 @@ class CarController(CarControllerBase):
|
||||
lka_steering = self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING
|
||||
lka_steering_long = lka_steering and self.long_active_ecu
|
||||
ccnc_non_hda2 = self.CP.flags & HyundaiFlags.CCNC and not lka_steering
|
||||
use_ioniq_6_dynamic_long_tuning = self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and self.long_active_ecu and \
|
||||
CC.actuators.longControlState == LongCtrlState.pid
|
||||
use_ioniq_6_smoothed_accel = use_ioniq_6_dynamic_long_tuning and CC.actuators.accel >= self._ioniq_6_long_tuning.actual_accel
|
||||
use_egmp_dynamic_long_tuning = egmp_dynamic_longitudinal_tuning(self.CP) and self.long_active_ecu and \
|
||||
CC.actuators.longControlState in (LongCtrlState.starting, LongCtrlState.pid, LongCtrlState.stopping)
|
||||
use_egmp_smoothed_accel = use_egmp_dynamic_long_tuning and (
|
||||
CC.actuators.accel >= self._ioniq_6_long_tuning.actual_accel or
|
||||
self._ioniq_6_long_tuning.launch_active or
|
||||
self._ioniq_6_long_tuning.stopping
|
||||
)
|
||||
|
||||
# steering control
|
||||
preserve_stock_lkas = self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and not self.long_active_ecu
|
||||
preserve_stock_lkas = bool(self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING) and not self.long_active_ecu
|
||||
steering_msg_active = apply_steer_req
|
||||
if self.CP.carFingerprint == CAR.KIA_EV9 and self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
|
||||
# EV9 faults if the angle-steering status drops inactive during torque limiting.
|
||||
# Hold the angle status active while lateral is active; VM/safety limits handle actuation.
|
||||
steering_msg_active = CC.latActive
|
||||
|
||||
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled,
|
||||
apply_steer_req, apply_torque, apply_angle,
|
||||
steering_msg_active, apply_torque, apply_angle,
|
||||
CS.stock_lfa_msg,
|
||||
CS.stock_lkas_msg if preserve_stock_lkas else None,
|
||||
lka_icon=lka_icon))
|
||||
|
||||
# prevent LFA from activating on LKA steering cars by sending "no lane lines detected" to ADAS ECU
|
||||
if self.frame % 5 == 0 and lka_steering:
|
||||
suppress_lfa = bool(lka_steering)
|
||||
if self.frame % 5 == 0 and suppress_lfa:
|
||||
can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.lfa_block_msg,
|
||||
self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT))
|
||||
|
||||
@@ -625,7 +675,8 @@ class CarController(CarControllerBase):
|
||||
# and stops publishing object tracks when it disappears. Spoof it periodically on
|
||||
# PT bus so the radar keeps tracking.
|
||||
if self.CP.carFingerprint in CANFD_RADAR_LIVE_LONGITUDINAL_CAR and self.frame % 4 == 0:
|
||||
can_sends.append(hyundaicanfd.create_accelerator_brake_alt_spoof(0, self.frame // 4, CS.out.brakePressed, CS.out.gasPressed))
|
||||
can_sends.append(hyundaicanfd.create_accelerator_brake_alt_spoof(0, self.frame // 4, CS.out.brakePressed,
|
||||
CS.out.gasPressed, self.CP.carFingerprint))
|
||||
elif not ccnc_non_hda2:
|
||||
can_sends.extend(hyundaicanfd.create_fca_warning_light(self.packer, self.CAN, self.frame))
|
||||
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and self.frame % 5 == 0:
|
||||
@@ -656,8 +707,8 @@ class CarController(CarControllerBase):
|
||||
"lead_rel_speed": lead_rel_speed,
|
||||
"lead_visible": lead_visible,
|
||||
}
|
||||
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
|
||||
if use_ioniq_6_smoothed_accel:
|
||||
if use_egmp_dynamic_long_tuning:
|
||||
if use_egmp_smoothed_accel:
|
||||
acc_kwargs["jerk_lower"] = self._ioniq_6_long_tuning.jerk_lower
|
||||
acc_kwargs["jerk_upper"] = self._ioniq_6_long_tuning.jerk_upper
|
||||
can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
|
||||
|
||||
@@ -75,7 +75,14 @@ class CarState(CarStateBase):
|
||||
self.cruise_buttons: deque = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
|
||||
self.main_buttons: deque = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
|
||||
self.lda_button = 0
|
||||
self.sonata_hybrid_lkas_source = None
|
||||
self.sonata_hybrid_lkas_sources = {
|
||||
"bcm": 0,
|
||||
"clu13": 0,
|
||||
"swl_stat": 0,
|
||||
}
|
||||
self.lda_button_raw = 0
|
||||
self.lda_button_raw_initialized = False
|
||||
self.lda_button_last_raw_rise_ts_nanos = 0
|
||||
self.left_paddle = 0
|
||||
self.mode_button = 0
|
||||
@@ -174,15 +181,20 @@ class CarState(CarStateBase):
|
||||
|
||||
return False
|
||||
|
||||
def create_alt_bus_lda_button_events(self, cp_source: CANParser) -> list[structs.CarState.ButtonEvent]:
|
||||
def get_alt_bus_lda_button_raw_state(self, cp_source: CANParser) -> tuple[int, int]:
|
||||
if self.CP.carFingerprint in ALT_BUS_LDA_BUTTON_SWL_STAT_CARS:
|
||||
raw_lda_button = int(cp_source.vl["CLU13"]["CF_Clu_SWL_Stat"] == 4)
|
||||
raw_lda_button_ts_nanos = cp_source.ts_nanos["CLU13"]["CF_Clu_SWL_Stat"]
|
||||
else:
|
||||
raw_lda_button = int(cp_source.vl["CLU13"]["CF_Clu_LdwsLkasSW"])
|
||||
raw_lda_button_ts_nanos = cp_source.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"]
|
||||
return int(cp_source.vl["CLU13"]["CF_Clu_SWL_Stat"] == 4), cp_source.ts_nanos["CLU13"]["CF_Clu_SWL_Stat"]
|
||||
return int(cp_source.vl["CLU13"]["CF_Clu_LdwsLkasSW"]), cp_source.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"]
|
||||
|
||||
def create_alt_bus_lda_button_events(self, cp_source: CANParser) -> list[structs.CarState.ButtonEvent]:
|
||||
raw_lda_button, raw_lda_button_ts_nanos = self.get_alt_bus_lda_button_raw_state(cp_source)
|
||||
button_events: list[structs.CarState.ButtonEvent] = []
|
||||
|
||||
if not self.lda_button_raw_initialized:
|
||||
self.lda_button_raw_initialized = True
|
||||
self.lda_button_raw = raw_lda_button
|
||||
return button_events
|
||||
|
||||
# Some alt-bus LKAS button layouts pulse several times per physical press burst.
|
||||
# Collapse each burst into a single synthetic press/release pair.
|
||||
if raw_lda_button and not self.lda_button_raw:
|
||||
@@ -198,8 +210,10 @@ class CarState(CarStateBase):
|
||||
return button_events
|
||||
|
||||
def create_lkas_button_events(self, cp: CANParser, prev_lda_button: int) -> list[structs.CarState.ButtonEvent]:
|
||||
if self.CP.carFingerprint == CAR.HYUNDAI_SONATA_HYBRID:
|
||||
self.lda_button = self.get_sonata_hybrid_lkas_button_state(cp)
|
||||
# Some classic HKG platforms publish the LKAS button on the cluster bus instead of BCM_PO_11.
|
||||
if cp.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"] > 0:
|
||||
elif cp.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"] > 0:
|
||||
self.lda_button = int(cp.vl["CLU13"]["CF_Clu_LdwsLkasSW"])
|
||||
elif cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0:
|
||||
self.lda_button = int(cp.vl["BCM_PO_11"]["LDA_BTN"])
|
||||
@@ -208,6 +222,32 @@ class CarState(CarStateBase):
|
||||
|
||||
return create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas})
|
||||
|
||||
def get_sonata_hybrid_lkas_button_state(self, cp: CANParser) -> int:
|
||||
source_states = {
|
||||
"bcm": int(cp.vl["BCM_PO_11"]["LDA_BTN"]) if cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0 else 0,
|
||||
"clu13": int(cp.vl["CLU13"]["CF_Clu_LdwsLkasSW"]) if cp.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"] > 0 else 0,
|
||||
"swl_stat": int(cp.vl["CLU13"]["CF_Clu_SWL_Stat"] == 4) if cp.ts_nanos["CLU13"]["CF_Clu_SWL_Stat"] > 0 else 0,
|
||||
}
|
||||
|
||||
changed_sources = [source for source, state in source_states.items() if state != self.sonata_hybrid_lkas_sources[source]]
|
||||
active_sources = [source for source, state in source_states.items() if state]
|
||||
|
||||
selected_source = None
|
||||
if self.sonata_hybrid_lkas_source in changed_sources:
|
||||
selected_source = self.sonata_hybrid_lkas_source
|
||||
elif active_sources:
|
||||
selected_source = active_sources[0]
|
||||
elif changed_sources:
|
||||
selected_source = changed_sources[0]
|
||||
elif self.sonata_hybrid_lkas_source is not None:
|
||||
selected_source = self.sonata_hybrid_lkas_source
|
||||
|
||||
self.sonata_hybrid_lkas_sources.update(source_states)
|
||||
if selected_source is not None:
|
||||
self.sonata_hybrid_lkas_source = selected_source
|
||||
return source_states[selected_source]
|
||||
return 0
|
||||
|
||||
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
|
||||
cp = can_parsers[Bus.pt]
|
||||
cp_cam = can_parsers[Bus.cam]
|
||||
@@ -348,7 +388,7 @@ class CarState(CarStateBase):
|
||||
lkas_button_events = []
|
||||
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
|
||||
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
|
||||
if self.CP.carFingerprint in ALT_BUS_LDA_BUTTON_CARS and cp_alt is not None and cp_alt.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"] > 0:
|
||||
if self.CP.carFingerprint in ALT_BUS_LDA_BUTTON_CARS and cp_alt is not None and self.get_alt_bus_lda_button_raw_state(cp_alt)[1] > 0:
|
||||
lkas_button_events = self.create_alt_bus_lda_button_events(cp_alt)
|
||||
else:
|
||||
lkas_button_events = self.create_lkas_button_events(cp, prev_lda_button)
|
||||
|
||||
@@ -38,6 +38,14 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00IGhe SCC FHCUP 1.00 1.02 99110-M9000 ',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_AZERA_HEV_7TH_GEN: {
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00GN7HMFC AT KOR LHD 1.00 1.01 99211-N1110 240423',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00GN7_ RDR ----- 1.00 1.00 99110-N1100 ',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_GENESIS: {
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00DH LKAS 1.1 -150210',
|
||||
@@ -607,6 +615,17 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00CD ESC \x0b 101 \x10\x03 58910-J7AC0',
|
||||
],
|
||||
},
|
||||
CAR.KIA_XCEED_PHEV: {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00CDph SCC F-CUP 1.00 1.01 99110-CR100 ',
|
||||
],
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00CDe MDPS C 1.00 1.01 56310-XX000 4CDHC101',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00CD2 LKAS AT EUR LHD 1.00 1.01 99211-CR010 621',
|
||||
],
|
||||
},
|
||||
CAR.KIA_FORTE: {
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00BD MDPS C 1.00 1.02 56310-XX000 4BD2C102',
|
||||
|
||||
@@ -39,7 +39,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
||||
CAR.HYUNDAI_IONIQ_EV_2020, CAR.HYUNDAI_IONIQ_PHEV, CAR.KIA_SELTOS, CAR.HYUNDAI_ELANTRA_2021, CAR.GENESIS_G70_2020,
|
||||
CAR.HYUNDAI_ELANTRA_HEV_2021, CAR.HYUNDAI_SONATA_HYBRID, CAR.HYUNDAI_KONA_EV, CAR.HYUNDAI_KONA_HEV, CAR.HYUNDAI_KONA_EV_2022,
|
||||
CAR.HYUNDAI_SANTA_FE_2022, CAR.KIA_K5_2021, CAR.HYUNDAI_IONIQ_HEV_2022, CAR.HYUNDAI_SANTA_FE_HEV_2022,
|
||||
CAR.HYUNDAI_SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED,
|
||||
CAR.HYUNDAI_SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED, CAR.KIA_XCEED_PHEV,
|
||||
CAR.HYUNDAI_AZERA_6TH_GEN, CAR.HYUNDAI_AZERA_HEV_6TH_GEN, CAR.HYUNDAI_CUSTIN_1ST_GEN, CAR.HYUNDAI_KONA_2022):
|
||||
values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
|
||||
values["CF_Lkas_LdwsOpt_USM"] = 2
|
||||
|
||||
@@ -96,6 +96,8 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
|
||||
lfa_base_values=None, lkas_base_values=None, lka_icon=None):
|
||||
if lka_icon is None:
|
||||
lka_icon = 2 if enabled else 1
|
||||
ev9_angle_lkas_alt = str(CP.carFingerprint) == "KIA_EV9" and CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING and \
|
||||
CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT
|
||||
|
||||
control_values = {
|
||||
"LKA_MODE": 2,
|
||||
@@ -128,6 +130,48 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
|
||||
lkas_values["ADAS_StrAnglReqVal"] = apply_angle
|
||||
lkas_values["LKAS_ANGLE_ACTIVE"] = 2 if lat_active else 1
|
||||
lkas_values["ADAS_ACIAnglTqRedcGainVal"] = apply_torque if lat_active else 0.0
|
||||
if ev9_angle_lkas_alt:
|
||||
if lat_active:
|
||||
lkas_values.update({
|
||||
"LKA_MODE": 0,
|
||||
"LKA_AVAILABLE": 3,
|
||||
"LKA_WARNING": 0,
|
||||
"LKA_ICON": lka_icon,
|
||||
"FCA_SYSWARN": 0,
|
||||
"TORQUE_REQUEST": 0,
|
||||
"STEER_REQ": 0,
|
||||
"LFA_BUTTON": 0,
|
||||
"LKA_ASSIST": 0,
|
||||
"DAMP_FACTOR": 100,
|
||||
"HAS_LANE_SAFETY": 0,
|
||||
})
|
||||
elif lkas_base_values:
|
||||
for signal in ("LKA_MODE", "LKA_AVAILABLE", "LKA_WARNING", "LKA_ICON", "FCA_SYSWARN",
|
||||
"LFA_BUTTON", "LKA_ASSIST", "DAMP_FACTOR", "HAS_LANE_SAFETY"):
|
||||
if signal in lkas_base_values:
|
||||
lkas_values[signal] = lkas_base_values[signal]
|
||||
lkas_values.update({
|
||||
"TORQUE_REQUEST": 0,
|
||||
"STEER_REQ": 0,
|
||||
})
|
||||
else:
|
||||
lkas_values.update({
|
||||
"LKA_MODE": 0,
|
||||
"LKA_AVAILABLE": 0,
|
||||
"LKA_WARNING": 0,
|
||||
"LKA_ICON": lka_icon,
|
||||
"FCA_SYSWARN": 0,
|
||||
"TORQUE_REQUEST": 0,
|
||||
"STEER_REQ": 0,
|
||||
"LFA_BUTTON": 0,
|
||||
"LKA_ASSIST": 0,
|
||||
"DAMP_FACTOR": 100,
|
||||
"HAS_LANE_SAFETY": 0,
|
||||
})
|
||||
# These signals overlap DAMP_FACTOR in the local DBC naming; omitting them
|
||||
# preserves the stock angle-steering damping byte expected by the ADAS ECU.
|
||||
lkas_values.pop("STEER_MODE", None)
|
||||
lkas_values.pop("NEW_SIGNAL_2", None)
|
||||
|
||||
ret = []
|
||||
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||
@@ -709,11 +753,15 @@ def hkg_can_fd_checksum(address: int, sig, d: bytearray) -> int:
|
||||
# radar stops publishing real object tracks. Spoof this message ourselves with valid CRC
|
||||
# and current pedal state so the radar keeps tracking.
|
||||
# Length is 24 bytes on Ioniq 6 (DBC declares 32 for ICE Hyundais, but EV firmware uses 24).
|
||||
# Byte template captured from a real ADAS broadcast; bytes 6-23 appear static / config.
|
||||
# Byte templates captured from real ADAS broadcasts; only checksum, counter,
|
||||
# brake, and accelerator bits are updated for the radar heartbeat.
|
||||
_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("000000020000fcff000000000020000055ff000068000000")
|
||||
_KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("00000000ff006f00e80400001201030055ffff0000000000")
|
||||
|
||||
def create_accelerator_brake_alt_spoof(bus: int, counter: int, brake_pressed: bool, accelerator_pressed: bool) -> CanData:
|
||||
d = bytearray(_ACCEL_BRAKE_ALT_TEMPLATE)
|
||||
def create_accelerator_brake_alt_spoof(bus: int, counter: int, brake_pressed: bool, accelerator_pressed: bool,
|
||||
car_fingerprint=None) -> CanData:
|
||||
template = _KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE if str(car_fingerprint) == "KIA_EV9" else _ACCEL_BRAKE_ALT_TEMPLATE
|
||||
d = bytearray(template)
|
||||
d[2] = counter & 0xFF # COUNTER (bit 16, 8-bit)
|
||||
d[4] = (d[4] & ~0x01) | (0x01 if brake_pressed else 0x00) # BRAKE_PRESSED (bit 32)
|
||||
d[22] = (d[22] & ~0x01) | (0x01 if accelerator_pressed else 0x00) # ACCELERATOR_PEDAL_PRESSED (bit 176)
|
||||
|
||||
@@ -4,12 +4,15 @@ from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from opendbc.car.hyundai.values import HyundaiFlags, CAR, CarControllerParams, \
|
||||
CANFD_UNSUPPORTED_LONGITUDINAL_CAR, \
|
||||
CANFD_SECURITYACCESS_CAR, \
|
||||
CANFD_ANGLE_LONGITUDINAL_CAR, \
|
||||
CANFD_RADAR_LIVE_LONGITUDINAL_CAR, \
|
||||
RADAR_LIVE_LONGITUDINAL_CAR, \
|
||||
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags, \
|
||||
LEGACY_LONGITUDINAL_CAR, \
|
||||
HyundaiStarPilotSafetyFlags, \
|
||||
hyundai_cancel_button_enables_cruise
|
||||
from opendbc.car.hyundai.radar_interface import get_radar_track_config
|
||||
hyundai_cancel_button_enables_cruise, \
|
||||
kia_ev6_gt_line_longitudinal_tuning
|
||||
from opendbc.car.hyundai.radar_interface import get_radar_track_config, radar_tracks_available
|
||||
from opendbc.car.interfaces import CarInterfaceBase, ACCEL_MIN
|
||||
from opendbc.car.disable_ecu import disable_ecu, ecu_log
|
||||
from opendbc.car.hyundai.carcontroller import CarController
|
||||
@@ -39,6 +42,12 @@ def apply_platform_longitudinal_params(ret: structs.CarParams) -> None:
|
||||
ret.stoppingDecelRate = 0.4
|
||||
|
||||
|
||||
def apply_kia_ev6_gt_line_longitudinal_params(ret: structs.CarParams) -> None:
|
||||
ret.startAccel = 1.4
|
||||
ret.longitudinalActuatorDelay = 0.35
|
||||
ret.vEgoStarting = 0.5
|
||||
|
||||
|
||||
def apply_ecu_disable_failure_fallback(CP: structs.CarParams, params) -> None:
|
||||
params.put_bool("EcuDisableFailed", True)
|
||||
CP.safetyConfigs[-1].safetyParam &= ~HyundaiSafetyFlags.LONG.value
|
||||
@@ -67,6 +76,11 @@ class CarInterface(CarInterfaceBase):
|
||||
def get_pid_accel_limits(CP, current_speed, cruise_speed):
|
||||
return ACCEL_MIN, CarControllerParams.ACCEL_MAX
|
||||
|
||||
@staticmethod
|
||||
def apply_post_fingerprint_params(CP: structs.CarParams, candidate, fingerprint, car_fw) -> None:
|
||||
if kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, CP.carVin):
|
||||
apply_kia_ev6_gt_line_longitudinal_params(CP)
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
|
||||
ret.brand = "hyundai"
|
||||
@@ -86,8 +100,8 @@ class CarInterface(CarInterfaceBase):
|
||||
# this needs to be figured out for cars without an ADAS ECU
|
||||
# Cars in CANFD_SECURITYACCESS_CAR are known to have ADAS ECUs that work with SecurityAccess
|
||||
ret.alphaLongitudinalAvailable = False
|
||||
if lka_steering and ret.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
|
||||
# Angle-steering LKA platforms still need stock longitudinal validation.
|
||||
if lka_steering and ret.flags & HyundaiFlags.CANFD_ANGLE_STEERING and candidate not in CANFD_ANGLE_LONGITUDINAL_CAR:
|
||||
# Most angle-steering LKA platforms still need stock longitudinal validation.
|
||||
ret.alphaLongitudinalAvailable = False
|
||||
|
||||
ret.enableBsm = 0x1ba in fingerprint[CAN.ECAN]
|
||||
@@ -139,7 +153,7 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
else:
|
||||
# Shared configuration for non CAN-FD cars
|
||||
ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR
|
||||
ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR or candidate in LEGACY_LONGITUDINAL_CAR
|
||||
ret.enableBsm = 0x58b in fingerprint[CAN.ECAN]
|
||||
|
||||
# Send LFA message on cars with HDA
|
||||
@@ -191,13 +205,13 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
# Common longitudinal control setup
|
||||
|
||||
radar_config = get_radar_track_config(ret.carFingerprint)
|
||||
radar_tracks_available = radar_config is not None and radar_config.start_addr in fingerprint[radar_config.bus]
|
||||
ret.radarUnavailable = not radar_tracks_available
|
||||
radar_config = get_radar_track_config(ret.carFingerprint, ret.flags)
|
||||
radar_available = radar_tracks_available(radar_config, fingerprint)
|
||||
ret.radarUnavailable = not radar_available
|
||||
if ret.flags & HyundaiFlags.NON_SCC:
|
||||
ret.alphaLongitudinalAvailable = False
|
||||
ret.openpilotLongitudinalControl = alpha_long and ret.alphaLongitudinalAvailable
|
||||
if ret.openpilotLongitudinalControl and not (candidate in RADAR_LIVE_LONGITUDINAL_CAR and radar_tracks_available):
|
||||
if ret.openpilotLongitudinalControl and not (candidate in RADAR_LIVE_LONGITUDINAL_CAR and radar_available):
|
||||
ret.radarUnavailable = True
|
||||
ret.pcmCruise = not ret.openpilotLongitudinalControl
|
||||
apply_platform_longitudinal_params(ret)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import math
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, replace
|
||||
|
||||
from opendbc.can import CANParser
|
||||
from opendbc.can.dbc import DBC as DBCReader
|
||||
from opendbc.can.parser import get_raw_value
|
||||
from opendbc.car import Bus, structs
|
||||
from opendbc.car.interfaces import RadarInterfaceBase
|
||||
from opendbc.car.hyundai.values import CAR, DBC, HYUNDAI_MANDO_FRONT_RADAR_DBC, HYUNDAI_MRREVO14F_RADAR_DBC, \
|
||||
from opendbc.car.hyundai.values import CAR, DBC, HyundaiFlags, HYUNDAI_MANDO_FRONT_RADAR_DBC, HYUNDAI_MRREVO14F_RADAR_DBC, \
|
||||
HYUNDAI_MRR30_RADAR_DBC, HYUNDAI_MRR35_RADAR_DBC
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
@@ -29,6 +29,7 @@ class RadarTrackConfig:
|
||||
bus: int = 1
|
||||
frequency: int = 50
|
||||
parser_msg_count: int | None = None
|
||||
expected_length: int | None = None
|
||||
|
||||
@property
|
||||
def can_parser_msg_count(self) -> int:
|
||||
@@ -38,18 +39,37 @@ class RadarTrackConfig:
|
||||
RADAR_TRACK_CONFIGS = {
|
||||
HYUNDAI_MANDO_FRONT_RADAR_DBC: RadarTrackConfig(RADAR_START_ADDR, RADAR_MSG_COUNT, "mando"),
|
||||
HYUNDAI_MRREVO14F_RADAR_DBC: RadarTrackConfig(MRREVO14F_RADAR_START_ADDR, MRREVO14F_RADAR_MSG_COUNT, "mrrevo14f"),
|
||||
HYUNDAI_MRR30_RADAR_DBC: RadarTrackConfig(MRR30_RADAR_START_ADDR, MRR30_RADAR_MSG_COUNT, "mrr30", bus=0),
|
||||
HYUNDAI_MRR35_RADAR_DBC: RadarTrackConfig(MRR35_RADAR_START_ADDR, MRR35_RADAR_MSG_COUNT, "mrr35", bus=0, frequency=20),
|
||||
HYUNDAI_MRR30_RADAR_DBC: RadarTrackConfig(MRR30_RADAR_START_ADDR, MRR30_RADAR_MSG_COUNT, "mrr30", bus=0, expected_length=32),
|
||||
HYUNDAI_MRR35_RADAR_DBC: RadarTrackConfig(MRR35_RADAR_START_ADDR, MRR35_RADAR_MSG_COUNT, "mrr35", bus=0, frequency=20, expected_length=24),
|
||||
}
|
||||
|
||||
# POC for parsing corner radars: https://github.com/commaai/openpilot/pull/24221/
|
||||
|
||||
|
||||
def get_radar_track_config(car_fingerprint) -> RadarTrackConfig | None:
|
||||
def get_radar_track_config(car_fingerprint, flags: int = 0) -> RadarTrackConfig | None:
|
||||
radar_dbc = DBC[car_fingerprint].get(Bus.radar)
|
||||
if car_fingerprint == CAR.GENESIS_G90 and radar_dbc == HYUNDAI_MANDO_FRONT_RADAR_DBC:
|
||||
return RadarTrackConfig(RADAR_START_ADDR, G90_RADAR_MSG_COUNT, "mando", parser_msg_count=RADAR_MSG_COUNT)
|
||||
return RADAR_TRACK_CONFIGS.get(radar_dbc)
|
||||
|
||||
radar_config = RADAR_TRACK_CONFIGS.get(radar_dbc)
|
||||
if radar_config is None:
|
||||
return None
|
||||
|
||||
if car_fingerprint == CAR.HYUNDAI_IONIQ_6 and flags & HyundaiFlags.CANFD_CAMERA_SCC:
|
||||
return replace(radar_config, bus=1)
|
||||
|
||||
return radar_config
|
||||
|
||||
|
||||
def radar_tracks_available(radar_config: RadarTrackConfig | None, fingerprint) -> bool:
|
||||
if radar_config is None:
|
||||
return False
|
||||
|
||||
msg_len = fingerprint[radar_config.bus].get(radar_config.start_addr)
|
||||
if msg_len is None:
|
||||
return False
|
||||
|
||||
return radar_config.expected_length is None or msg_len == radar_config.expected_length
|
||||
|
||||
|
||||
def get_radar_can_parser(CP, radar_config):
|
||||
@@ -64,7 +84,7 @@ def get_radar_can_parser(CP, radar_config):
|
||||
class RadarInterface(RadarInterfaceBase):
|
||||
def __init__(self, CP):
|
||||
super().__init__(CP)
|
||||
self.radar_config = get_radar_track_config(CP.carFingerprint)
|
||||
self.radar_config = get_radar_track_config(CP.carFingerprint, CP.flags)
|
||||
self.updated_messages = set()
|
||||
self.trigger_msg = (self.radar_config.start_addr + self.radar_config.can_parser_msg_count - 1
|
||||
if self.radar_config is not None else RADAR_START_ADDR)
|
||||
|
||||
@@ -9,7 +9,9 @@ from opendbc.car.structs import CarControl, CarParams
|
||||
from opendbc.car.fw_versions import build_fw_dict, match_fw_to_car
|
||||
from opendbc.car.hyundai.carcontroller import CarController, Ioniq6LongitudinalTuningState, GenesisG90LongitudinalTuningState, \
|
||||
update_ioniq_6_longitudinal_tuning, \
|
||||
update_genesis_g90_longitudinal_tuning
|
||||
update_genesis_g90_longitudinal_tuning, egmp_dynamic_longitudinal_tuning, \
|
||||
should_reset_ev6_gt_line_longitudinal_tuning, reset_ev6_gt_line_longitudinal_tuning, \
|
||||
get_angle_smoothing_alpha, apply_ev9_high_angle_gain_cap
|
||||
from opendbc.car.hyundai.carstate import CarState, decode_canfd_camera_lead, decode_ioniq_6_blindspot_radar_state
|
||||
from opendbc.car.hyundai.interface import CarInterface
|
||||
from opendbc.car.hyundai import hyundaican, hyundaicanfd
|
||||
@@ -19,8 +21,8 @@ from opendbc.car.hyundai.radar_interface import MRREVO14F_RADAR_START_ADDR, MRR3
|
||||
from opendbc.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, DATE_FW_ECUS, \
|
||||
HYBRID_CAR, EV_CAR, FW_QUERY_CONFIG, LEGACY_SAFETY_MODE_CAR, CANFD_FUZZY_WHITELIST, \
|
||||
UNSUPPORTED_LONGITUDINAL_CAR, PLATFORM_CODE_ECUS, HYUNDAI_VERSION_REQUEST_LONG, \
|
||||
CarControllerParams, DBC, HyundaiFlags, get_platform_codes, HyundaiSafetyFlags, \
|
||||
HyundaiStarPilotSafetyFlags, Buttons
|
||||
LEGACY_LONGITUDINAL_CAR, DBC, HyundaiFlags, get_platform_codes, HyundaiSafetyFlags, \
|
||||
HyundaiStarPilotSafetyFlags, Buttons, kia_ev6_gt_line_longitudinal_tuning
|
||||
|
||||
LongCtrlState = CarControl.Actuators.LongControlState
|
||||
from opendbc.car.hyundai.fingerprints import FW_VERSIONS
|
||||
@@ -44,6 +46,7 @@ NO_DATES_PLATFORMS = {
|
||||
CAR.HYUNDAI_ELANTRA,
|
||||
CAR.HYUNDAI_ELANTRA_GT_I30,
|
||||
CAR.KIA_CEED,
|
||||
CAR.KIA_XCEED_PHEV,
|
||||
CAR.KIA_FORTE,
|
||||
CAR.KIA_OPTIMA_G4,
|
||||
CAR.KIA_OPTIMA_G4_FL,
|
||||
@@ -91,6 +94,7 @@ CCNC_NON_HDA2_CARS = (
|
||||
)
|
||||
|
||||
ANGLE_STEERING_CARS = (
|
||||
CAR.HYUNDAI_AZERA_HEV_7TH_GEN,
|
||||
CAR.HYUNDAI_SANTA_FE_HEV_5TH_GEN,
|
||||
CAR.HYUNDAI_IONIQ_5_PE,
|
||||
CAR.HYUNDAI_IONIQ_9,
|
||||
@@ -130,6 +134,7 @@ class TestHyundaiFingerprint:
|
||||
CAR.HYUNDAI_SANTA_FE_PHEV_2022,
|
||||
CAR.HYUNDAI_SONATA,
|
||||
CAR.HYUNDAI_SONATA_HYBRID,
|
||||
CAR.KIA_XCEED_PHEV,
|
||||
CAR.KIA_K5_HEV_2020,
|
||||
CAR.KIA_NIRO_EV,
|
||||
CAR.KIA_NIRO_PHEV,
|
||||
@@ -151,7 +156,7 @@ class TestHyundaiFingerprint:
|
||||
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[1][RADAR_START_ADDR] = 8
|
||||
for candidate in (CAR.HYUNDAI_SONATA, CAR.HYUNDAI_SONATA_HYBRID, CAR.GENESIS_G90):
|
||||
for candidate in (CAR.HYUNDAI_SONATA, CAR.HYUNDAI_SONATA_HYBRID, CAR.KIA_XCEED_PHEV, CAR.GENESIS_G90):
|
||||
CP = CarInterface.get_params(candidate, fingerprint, [], True, False, False, None)
|
||||
assert CP.openpilotLongitudinalControl
|
||||
assert not CP.radarUnavailable
|
||||
@@ -164,37 +169,58 @@ class TestHyundaiFingerprint:
|
||||
(CAR.KIA_EV6_2025, MRR30_RADAR_START_ADDR),
|
||||
(CAR.GENESIS_GV60_EV_1ST_GEN, MRR30_RADAR_START_ADDR),
|
||||
(CAR.HYUNDAI_KONA_EV_2ND_GEN, MRR35_RADAR_START_ADDR),
|
||||
(CAR.HYUNDAI_IONIQ_6, MRR35_RADAR_START_ADDR),
|
||||
(CAR.HYUNDAI_IONIQ_9, MRR35_RADAR_START_ADDR),
|
||||
(CAR.KIA_EV9, MRR35_RADAR_START_ADDR),
|
||||
):
|
||||
radar_config = get_radar_track_config(candidate)
|
||||
assert radar_config.start_addr == radar_addr
|
||||
for radar in (True, False):
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
if radar:
|
||||
fingerprint[radar_config.bus][radar_addr] = 8
|
||||
fingerprint[radar_config.bus][radar_addr] = radar_config.expected_length or 8
|
||||
CP = CarInterface.get_params(candidate, fingerprint, [], False, False, False, None)
|
||||
assert CP.radarUnavailable != radar
|
||||
|
||||
assert get_radar_track_config(CAR.HYUNDAI_KONA_EV_2022).bus == 1
|
||||
assert get_radar_track_config(CAR.HYUNDAI_IONIQ_5).bus == 0
|
||||
assert get_radar_track_config(CAR.HYUNDAI_IONIQ_6).start_addr == MRR35_RADAR_START_ADDR
|
||||
ioniq_6_hda2_radar_config = get_radar_track_config(CAR.HYUNDAI_IONIQ_6)
|
||||
ioniq_6_hda1_radar_config = get_radar_track_config(CAR.HYUNDAI_IONIQ_6, HyundaiFlags.CANFD_CAMERA_SCC)
|
||||
assert ioniq_6_hda2_radar_config.start_addr == MRR35_RADAR_START_ADDR
|
||||
assert ioniq_6_hda2_radar_config.bus == 0
|
||||
assert ioniq_6_hda1_radar_config.bus == 1
|
||||
assert ioniq_6_hda1_radar_config.frequency == 20
|
||||
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[1][MRR35_RADAR_START_ADDR] = 24
|
||||
fingerprint[0][MRR35_RADAR_START_ADDR] = 8
|
||||
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, fingerprint, [], False, False, False, None)
|
||||
assert not CP.openpilotLongitudinalControl
|
||||
assert CP.radarUnavailable
|
||||
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[ioniq_6_hda1_radar_config.bus][MRR35_RADAR_START_ADDR] = 24
|
||||
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, fingerprint, [], False, False, False, None)
|
||||
assert not CP.openpilotLongitudinalControl
|
||||
assert CP.flags & HyundaiFlags.CANFD_CAMERA_SCC
|
||||
assert not CP.radarUnavailable
|
||||
|
||||
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, gen_empty_fingerprint(), [], True, False, False, None)
|
||||
assert CP.openpilotLongitudinalControl
|
||||
assert CP.radarUnavailable
|
||||
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[get_radar_track_config(CAR.HYUNDAI_IONIQ_6).bus][MRR35_RADAR_START_ADDR] = 24
|
||||
fingerprint[ioniq_6_hda1_radar_config.bus][MRR35_RADAR_START_ADDR] = 24
|
||||
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, fingerprint, [], True, False, False, None)
|
||||
assert CP.openpilotLongitudinalControl
|
||||
assert CP.flags & HyundaiFlags.CANFD_CAMERA_SCC
|
||||
assert not CP.radarUnavailable
|
||||
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[CanBus(None, fingerprint).CAM][0x50] = 32
|
||||
fingerprint[ioniq_6_hda2_radar_config.bus][MRR35_RADAR_START_ADDR] = 24
|
||||
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, fingerprint, [], True, False, False, None)
|
||||
assert CP.openpilotLongitudinalControl
|
||||
assert CP.flags & HyundaiFlags.CANFD_LKA_STEERING
|
||||
assert not CP.radarUnavailable
|
||||
assert get_radar_track_config(CAR.HYUNDAI_IONIQ_6).frequency == 20
|
||||
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[CanBus(None, fingerprint).CAM][0x50] = 32
|
||||
@@ -203,6 +229,22 @@ class TestHyundaiFingerprint:
|
||||
assert CP.openpilotLongitudinalControl
|
||||
assert not CP.radarUnavailable
|
||||
|
||||
ev9_radar_config = get_radar_track_config(CAR.KIA_EV9)
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[CanBus(None, fingerprint).CAM][0x110] = 32
|
||||
fingerprint[ev9_radar_config.bus][ev9_radar_config.start_addr] = ev9_radar_config.expected_length
|
||||
ev9_car_fw = [CarParams.CarFw(ecu=Ecu.adas, fwVersion=b"", address=0x730, brand="hyundai")]
|
||||
CP = CarInterface.get_params(CAR.KIA_EV9, fingerprint, ev9_car_fw, True, False, False, None)
|
||||
assert not CP.alphaLongitudinalAvailable
|
||||
assert not CP.openpilotLongitudinalControl
|
||||
assert not CP.radarUnavailable
|
||||
assert CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT
|
||||
assert not (CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.LONG)
|
||||
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CANFD_ANGLE_STEERING
|
||||
|
||||
CP = CarInterface.get_params(CAR.KIA_EV9, fingerprint, [], True, False, False, None)
|
||||
assert not CP.openpilotLongitudinalControl
|
||||
|
||||
for candidate in HYUNDAI_NON_SCC_CARS:
|
||||
CP = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], True, False, False, None)
|
||||
assert bool(CP.flags & HyundaiFlags.NON_SCC)
|
||||
@@ -237,6 +279,26 @@ class TestHyundaiFingerprint:
|
||||
assert CP.steerControlType == CarParams.SteerControlType.angle
|
||||
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CANFD_ANGLE_STEERING
|
||||
|
||||
def test_ev9_uses_shared_angle_smoothing(self):
|
||||
ev9_cp = SimpleNamespace(carFingerprint=CAR.KIA_EV9)
|
||||
other_cp = SimpleNamespace(carFingerprint=CAR.KIA_SPORTAGE_HEV_2026)
|
||||
|
||||
assert get_angle_smoothing_alpha(ev9_cp, 0.0) == pytest.approx(get_angle_smoothing_alpha(other_cp, 0.0))
|
||||
assert get_angle_smoothing_alpha(ev9_cp, 13.8) == pytest.approx(get_angle_smoothing_alpha(other_cp, 13.8))
|
||||
assert get_angle_smoothing_alpha(ev9_cp, 20.0) == pytest.approx(get_angle_smoothing_alpha(other_cp, 20.0))
|
||||
assert get_angle_smoothing_alpha(other_cp, 20.0) == pytest.approx(0.0)
|
||||
|
||||
def test_ev9_high_angle_gain_cap_is_ev9_only_and_nonzero(self):
|
||||
ev9_cp = SimpleNamespace(carFingerprint=CAR.KIA_EV9, flags=int(HyundaiFlags.CANFD_ANGLE_STEERING))
|
||||
sportage_cp = SimpleNamespace(carFingerprint=CAR.KIA_SPORTAGE_HEV_2026, flags=int(HyundaiFlags.CANFD_ANGLE_STEERING))
|
||||
|
||||
assert apply_ev9_high_angle_gain_cap(ev9_cp, 0.70, 60.0, True) == pytest.approx(0.70)
|
||||
assert apply_ev9_high_angle_gain_cap(ev9_cp, 0.70, 120.0, True) == pytest.approx(0.55)
|
||||
assert apply_ev9_high_angle_gain_cap(ev9_cp, 0.70, 320.0, True) == pytest.approx(0.16)
|
||||
assert apply_ev9_high_angle_gain_cap(ev9_cp, 0.0, 320.0, True) > 0.0
|
||||
assert apply_ev9_high_angle_gain_cap(ev9_cp, 0.70, 320.0, False) == pytest.approx(0.70)
|
||||
assert apply_ev9_high_angle_gain_cap(sportage_cp, 0.70, 320.0, True) == pytest.approx(0.70)
|
||||
|
||||
def test_ccnc_hda2_lka_layout_does_not_set_ccnc_safety_param(self):
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
cam_can = CanBus(None, fingerprint).CAM
|
||||
@@ -447,6 +509,54 @@ class TestHyundaiFingerprint:
|
||||
assert CP.pcmCruise
|
||||
assert not (CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.LONG)
|
||||
|
||||
def test_xceed_phev_alpha_long_is_isolated_legacy_experiment(self):
|
||||
toggles = get_test_toggles()
|
||||
|
||||
ceed = CarInterface.get_params(CAR.KIA_CEED, gen_empty_fingerprint(), [], True, False, False, toggles)
|
||||
assert CAR.KIA_CEED not in LEGACY_LONGITUDINAL_CAR
|
||||
assert not ceed.alphaLongitudinalAvailable
|
||||
assert not ceed.openpilotLongitudinalControl
|
||||
assert ceed.pcmCruise
|
||||
assert ceed.safetyConfigs[-1].safetyModel == CarParams.SafetyModel.hyundaiLegacy
|
||||
assert not (ceed.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.LONG)
|
||||
|
||||
stock_xceed = CarInterface.get_params(CAR.KIA_XCEED_PHEV, gen_empty_fingerprint(), [], False, False, False, toggles)
|
||||
assert CAR.KIA_XCEED_PHEV in LEGACY_LONGITUDINAL_CAR
|
||||
assert stock_xceed.alphaLongitudinalAvailable
|
||||
assert not stock_xceed.openpilotLongitudinalControl
|
||||
assert stock_xceed.pcmCruise
|
||||
assert stock_xceed.safetyConfigs[-1].safetyModel == CarParams.SafetyModel.hyundaiLegacy
|
||||
assert stock_xceed.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.HYBRID_GAS
|
||||
assert not (stock_xceed.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.LONG)
|
||||
|
||||
long_xceed = CarInterface.get_params(CAR.KIA_XCEED_PHEV, gen_empty_fingerprint(), [], True, False, False, toggles)
|
||||
assert long_xceed.alphaLongitudinalAvailable
|
||||
assert long_xceed.openpilotLongitudinalControl
|
||||
assert not long_xceed.pcmCruise
|
||||
assert long_xceed.safetyConfigs[-1].safetyModel == CarParams.SafetyModel.hyundaiLegacy
|
||||
assert long_xceed.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.HYBRID_GAS
|
||||
assert long_xceed.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.LONG
|
||||
|
||||
def test_xceed_phev_disable_failure_falls_back_to_stock_acc(self, monkeypatch):
|
||||
toggles = get_test_toggles()
|
||||
CP = CarInterface.get_params(CAR.KIA_XCEED_PHEV, gen_empty_fingerprint(), [], True, False, False, toggles)
|
||||
|
||||
called = {}
|
||||
|
||||
def fake_disable_ecu(*args, **kwargs):
|
||||
called.update(kwargs)
|
||||
return False
|
||||
|
||||
monkeypatch.setattr("opendbc.car.hyundai.interface.disable_ecu", fake_disable_ecu)
|
||||
CarInterface.init(CP, None, None)
|
||||
|
||||
assert called["addr"] == 0x7d0
|
||||
assert called["bus"] == 0
|
||||
assert called["reset"] is False
|
||||
assert not CP.openpilotLongitudinalControl
|
||||
assert CP.pcmCruise
|
||||
assert not (CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.LONG)
|
||||
|
||||
def test_canfd_longitudinal_params_match_family_tune(self):
|
||||
toggles = get_test_toggles()
|
||||
CP = CarInterface.get_params(CAR.KIA_EV6, gen_empty_fingerprint(), [], True, False, False, toggles)
|
||||
@@ -457,6 +567,47 @@ class TestHyundaiFingerprint:
|
||||
assert CP.longitudinalActuatorDelay == pytest.approx(0.5)
|
||||
assert CP.startingState
|
||||
|
||||
def test_kia_ev6_gt_line_post_fingerprint_longitudinal_params(self):
|
||||
toggles = get_test_toggles()
|
||||
CP = CarInterface.get_params(CAR.KIA_EV6, gen_empty_fingerprint(), [], True, False, False, toggles)
|
||||
CP.carVin = "KNDC4DLC0P0000000"
|
||||
|
||||
CarInterface.apply_post_fingerprint_params(CP, CAR.KIA_EV6, gen_empty_fingerprint(), [])
|
||||
|
||||
assert CP.startAccel == pytest.approx(1.4)
|
||||
assert CP.vEgoStarting == pytest.approx(0.5)
|
||||
assert CP.longitudinalActuatorDelay == pytest.approx(0.35)
|
||||
assert CP.vEgoStopping == pytest.approx(0.3)
|
||||
assert CP.stoppingDecelRate == pytest.approx(0.4)
|
||||
assert kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, CP.carVin)
|
||||
assert egmp_dynamic_longitudinal_tuning(CP)
|
||||
assert should_reset_ev6_gt_line_longitudinal_tuning(CP, LongCtrlState.off)
|
||||
assert not should_reset_ev6_gt_line_longitudinal_tuning(CP, LongCtrlState.pid)
|
||||
|
||||
stale_state = Ioniq6LongitudinalTuningState(desired_accel=-2.2, actual_accel=-2.2, accel_last=-2.2,
|
||||
jerk_upper=1.0, jerk_lower=5.0,
|
||||
long_control_state_last=LongCtrlState.stopping)
|
||||
reset_state = reset_ev6_gt_line_longitudinal_tuning(stale_state, CP, LongCtrlState.off)
|
||||
assert reset_state.actual_accel == pytest.approx(0.0)
|
||||
assert reset_state.accel_last == pytest.approx(0.0)
|
||||
assert reset_state.long_control_state_last == LongCtrlState.off
|
||||
|
||||
def test_kia_ev6_non_gt_line_keeps_family_longitudinal_params(self):
|
||||
toggles = get_test_toggles()
|
||||
CP = CarInterface.get_params(CAR.KIA_EV6, gen_empty_fingerprint(), [], True, False, False, toggles)
|
||||
CP.carVin = "KNDC3DLC0P0000000"
|
||||
|
||||
CarInterface.apply_post_fingerprint_params(CP, CAR.KIA_EV6, gen_empty_fingerprint(), [])
|
||||
|
||||
assert CP.startAccel == pytest.approx(1.0)
|
||||
assert CP.vEgoStarting == pytest.approx(0.1)
|
||||
assert CP.longitudinalActuatorDelay == pytest.approx(0.5)
|
||||
assert not kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, CP.carVin)
|
||||
assert not egmp_dynamic_longitudinal_tuning(CP)
|
||||
assert not should_reset_ev6_gt_line_longitudinal_tuning(CP, LongCtrlState.off)
|
||||
stale_state = Ioniq6LongitudinalTuningState(actual_accel=-2.2, accel_last=-2.2)
|
||||
assert reset_ev6_gt_line_longitudinal_tuning(stale_state, CP, LongCtrlState.off) is stale_state
|
||||
|
||||
def test_genesis_g90_longitudinal_params_bias_toward_earlier_stop_handoff(self):
|
||||
toggles = get_test_toggles()
|
||||
CP = CarInterface.get_params(CAR.GENESIS_G90, gen_empty_fingerprint(), [], True, False, False, toggles)
|
||||
@@ -662,7 +813,7 @@ class TestHyundaiFingerprint:
|
||||
ret = update(0, 3)
|
||||
assert any(be.type == ButtonType.lkas and not be.pressed for be in ret.buttonEvents)
|
||||
|
||||
def test_sonata_hybrid_uses_alt_bus_lkas_parser(self):
|
||||
def test_sonata_hybrid_uses_main_bus_lkas_parser(self):
|
||||
toggles = get_test_toggles()
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[0][0x391] = 8
|
||||
@@ -673,9 +824,9 @@ class TestHyundaiFingerprint:
|
||||
car_state = CarState(CP, FPCP)
|
||||
can_parsers = car_state.get_can_parsers(CP)
|
||||
|
||||
assert Bus.alt in can_parsers
|
||||
assert Bus.alt not in can_parsers
|
||||
|
||||
def test_sonata_hybrid_alt_bus_clu13_lkas_button_event(self):
|
||||
def test_sonata_hybrid_bcm_lkas_button_event(self):
|
||||
toggles = get_test_toggles()
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[0][0x391] = 8
|
||||
@@ -687,6 +838,139 @@ class TestHyundaiFingerprint:
|
||||
can_parsers = car_state.get_can_parsers(CP)
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
|
||||
def update(lkas_button: int, frame: int):
|
||||
msg = packer.make_can_msg("BCM_PO_11", 0, {
|
||||
"LDA_BTN": lkas_button,
|
||||
})
|
||||
can_parsers[Bus.pt].update([(frame, [msg])])
|
||||
return car_state.update(can_parsers, toggles)[0]
|
||||
|
||||
update(0, 1)
|
||||
ret = update(1, 2)
|
||||
assert any(be.type == ButtonType.lkas and be.pressed for be in ret.buttonEvents)
|
||||
|
||||
ret = update(0, 3)
|
||||
assert any(be.type == ButtonType.lkas and not be.pressed for be in ret.buttonEvents)
|
||||
|
||||
def test_sonata_hybrid_prefers_bcm_lkas_button_over_dead_main_bus_clu13(self):
|
||||
toggles = get_test_toggles()
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[0][0x391] = 8
|
||||
fingerprint[1][0x50C] = 8
|
||||
CP = CarInterface.get_params(CAR.HYUNDAI_SONATA_HYBRID, fingerprint, [], False, False, False, toggles)
|
||||
FPCP = CarInterface.get_starpilot_params(CAR.HYUNDAI_SONATA_HYBRID, fingerprint, [], CP, toggles)
|
||||
|
||||
car_state = CarState(CP, FPCP)
|
||||
can_parsers = car_state.get_can_parsers(CP)
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
|
||||
def update(clu13_lkas_button: int, bcm_lkas_button: int, frame: int):
|
||||
msgs = [
|
||||
packer.make_can_msg("CLU13", 0, {
|
||||
"CF_Clu_LdwsLkasSW": clu13_lkas_button,
|
||||
}),
|
||||
packer.make_can_msg("BCM_PO_11", 0, {
|
||||
"LDA_BTN": bcm_lkas_button,
|
||||
}),
|
||||
]
|
||||
can_parsers[Bus.pt].update([(frame, msgs)])
|
||||
return car_state.update(can_parsers, toggles)[0]
|
||||
|
||||
update(0, 0, 1)
|
||||
ret = update(0, 1, 2)
|
||||
assert any(be.type == ButtonType.lkas and be.pressed for be in ret.buttonEvents)
|
||||
|
||||
ret = update(0, 0, 3)
|
||||
assert any(be.type == ButtonType.lkas and not be.pressed for be in ret.buttonEvents)
|
||||
|
||||
def test_sonata_hybrid_falls_back_to_main_bus_clu13_lkas_button_when_bcm_stays_dead(self):
|
||||
toggles = get_test_toggles()
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[0][0x391] = 8
|
||||
fingerprint[1][0x50C] = 8
|
||||
CP = CarInterface.get_params(CAR.HYUNDAI_SONATA_HYBRID, fingerprint, [], False, False, False, toggles)
|
||||
FPCP = CarInterface.get_starpilot_params(CAR.HYUNDAI_SONATA_HYBRID, fingerprint, [], CP, toggles)
|
||||
|
||||
car_state = CarState(CP, FPCP)
|
||||
can_parsers = car_state.get_can_parsers(CP)
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
|
||||
def update(clu13_lkas_button: int, bcm_lkas_button: int, frame: int):
|
||||
msgs = [
|
||||
packer.make_can_msg("CLU13", 0, {
|
||||
"CF_Clu_LdwsLkasSW": clu13_lkas_button,
|
||||
}),
|
||||
packer.make_can_msg("BCM_PO_11", 0, {
|
||||
"LDA_BTN": bcm_lkas_button,
|
||||
}),
|
||||
]
|
||||
can_parsers[Bus.pt].update([(frame, msgs)])
|
||||
return car_state.update(can_parsers, toggles)[0]
|
||||
|
||||
update(0, 0, 1)
|
||||
ret = update(1, 0, 2)
|
||||
assert any(be.type == ButtonType.lkas and be.pressed for be in ret.buttonEvents)
|
||||
|
||||
ret = update(0, 0, 3)
|
||||
assert any(be.type == ButtonType.lkas and not be.pressed for be in ret.buttonEvents)
|
||||
|
||||
def test_sonata_hybrid_falls_back_to_main_bus_clu13_swl_stat_lkas_button_when_other_sources_are_dead(self):
|
||||
toggles = get_test_toggles()
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[0][0x391] = 8
|
||||
fingerprint[1][0x50C] = 8
|
||||
CP = CarInterface.get_params(CAR.HYUNDAI_SONATA_HYBRID, fingerprint, [], False, False, False, toggles)
|
||||
FPCP = CarInterface.get_starpilot_params(CAR.HYUNDAI_SONATA_HYBRID, fingerprint, [], CP, toggles)
|
||||
|
||||
car_state = CarState(CP, FPCP)
|
||||
can_parsers = car_state.get_can_parsers(CP)
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
|
||||
def update(swl_stat: int, frame: int):
|
||||
msgs = [
|
||||
packer.make_can_msg("CLU13", 0, {
|
||||
"CF_Clu_LdwsLkasSW": 0,
|
||||
"CF_Clu_SWL_Stat": swl_stat,
|
||||
}),
|
||||
packer.make_can_msg("BCM_PO_11", 0, {
|
||||
"LDA_BTN": 0,
|
||||
}),
|
||||
]
|
||||
can_parsers[Bus.pt].update([(frame, msgs)])
|
||||
return car_state.update(can_parsers, toggles)[0]
|
||||
|
||||
update(0, 1)
|
||||
ret = update(4, 2)
|
||||
assert any(be.type == ButtonType.lkas and be.pressed for be in ret.buttonEvents)
|
||||
|
||||
ret = update(0, 3)
|
||||
assert any(be.type == ButtonType.lkas and not be.pressed for be in ret.buttonEvents)
|
||||
|
||||
def test_sonata_hybrid_ignores_noisy_alt_bus_clu13_lkas_button(self):
|
||||
toggles = get_test_toggles()
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[0][0x391] = 8
|
||||
fingerprint[1][0x50C] = 8
|
||||
CP = CarInterface.get_params(CAR.HYUNDAI_SONATA_HYBRID, fingerprint, [], False, False, False, toggles)
|
||||
FPCP = CarInterface.get_starpilot_params(CAR.HYUNDAI_SONATA_HYBRID, fingerprint, [], CP, toggles)
|
||||
|
||||
car_state = CarState(CP, FPCP)
|
||||
can_parsers = car_state.get_can_parsers(CP)
|
||||
|
||||
assert Bus.alt not in can_parsers
|
||||
|
||||
def test_sonata_alt_bus_clu13_swl_stat_lkas_button_event(self):
|
||||
toggles = get_test_toggles()
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[0][0x391] = 8
|
||||
fingerprint[1][0x50C] = 8
|
||||
CP = CarInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False, toggles)
|
||||
FPCP = CarInterface.get_starpilot_params(CAR.HYUNDAI_SONATA, fingerprint, [], CP, toggles)
|
||||
|
||||
car_state = CarState(CP, FPCP)
|
||||
can_parsers = car_state.get_can_parsers(CP)
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
|
||||
def update(lkas_button: int, frame: int):
|
||||
msg = packer.make_can_msg("CLU13", 1, {
|
||||
"CF_Clu_SWL_Stat": lkas_button,
|
||||
@@ -1077,6 +1361,167 @@ class TestHyundaiFingerprint:
|
||||
assert lead_distance == pytest.approx(20.0)
|
||||
assert lead_rel_speed == pytest.approx(0.0)
|
||||
|
||||
def test_ev9_angle_status_stays_active_when_gain_is_zero(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.KIA_EV9
|
||||
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING |
|
||||
HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT)
|
||||
CP.openpilotLongitudinalControl = False
|
||||
|
||||
controller = CarController(DBC[CP.carFingerprint], CP)
|
||||
controller.frame = 1
|
||||
can_bus = CanBus(CP)
|
||||
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("LKAS_ALT", 0)], can_bus.ACAN)
|
||||
stock_lkas = {
|
||||
"CHECKSUM": 1234,
|
||||
"COUNTER": 42,
|
||||
"LKA_MODE": 2,
|
||||
"LKA_AVAILABLE": 3,
|
||||
"LKA_WARNING": 1,
|
||||
"LKA_ICON": 1,
|
||||
"FCA_SYSWARN": 1,
|
||||
"TORQUE_REQUEST": 17,
|
||||
"STEER_REQ": 1,
|
||||
"LFA_BUTTON": 1,
|
||||
"LKA_ASSIST": 1,
|
||||
"STEER_MODE": 5,
|
||||
"NEW_SIGNAL_2": 0,
|
||||
"LKAS_ANGLE_ACTIVE": 1,
|
||||
"HAS_LANE_SAFETY": 1,
|
||||
"ADAS_StrAnglReqVal": 12.3,
|
||||
"ADAS_ACIAnglTqRedcGainVal": 0.42,
|
||||
"DAMP_FACTOR": 0,
|
||||
}
|
||||
cc = SimpleNamespace(enabled=True, latActive=True, actuators=SimpleNamespace(longControlState=LongCtrlState.off),
|
||||
leftBlinker=False, rightBlinker=False, hudControl=SimpleNamespace())
|
||||
cs = SimpleNamespace(stock_lfa_msg=None, stock_lkas_msg=stock_lkas,
|
||||
out=SimpleNamespace(steeringAngleDeg=0.0))
|
||||
|
||||
msgs = controller.create_canfd_msgs(0, False, 0.0, 8.5, 0.0, 0.0, False, cc.hudControl, cs, cc,
|
||||
get_test_toggles(), lka_icon=2, lfa_icon=2)
|
||||
lkas_msgs = [msg for msg in msgs if msg[0] == 0x110]
|
||||
assert len(lkas_msgs) == 1
|
||||
|
||||
parser.update([(1, lkas_msgs)])
|
||||
|
||||
assert parser.can_valid
|
||||
assert parser.vl["LKAS_ALT"]["LKAS_ANGLE_ACTIVE"] == 2
|
||||
assert parser.vl["LKAS_ALT"]["ADAS_ACIAnglTqRedcGainVal"] == pytest.approx(0.0)
|
||||
assert parser.vl["LKAS_ALT"]["ADAS_StrAnglReqVal"] == pytest.approx(8.5)
|
||||
|
||||
def test_ev9_inactive_angle_status_keeps_standby_damping_without_stock_lkas(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.KIA_EV9
|
||||
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING |
|
||||
HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT)
|
||||
CP.openpilotLongitudinalControl = False
|
||||
|
||||
controller = CarController(DBC[CP.carFingerprint], CP)
|
||||
can_bus = CanBus(CP)
|
||||
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("LKAS_ALT", 0)], can_bus.ACAN)
|
||||
cc = SimpleNamespace(enabled=False, latActive=False, actuators=SimpleNamespace(longControlState=LongCtrlState.off),
|
||||
leftBlinker=False, rightBlinker=False, hudControl=SimpleNamespace())
|
||||
lfa_block_msg = {f"BYTE{i}": 0 for i in range(3, 32) if i != 7}
|
||||
lfa_block_msg["COUNTER"] = 0
|
||||
cs = SimpleNamespace(stock_lfa_msg=None, stock_lkas_msg={}, lfa_block_msg=lfa_block_msg,
|
||||
out=SimpleNamespace(steeringAngleDeg=-201.0))
|
||||
|
||||
msgs = controller.create_canfd_msgs(0, False, 0.0, -201.0, 0.0, 0.0, False, cc.hudControl, cs, cc,
|
||||
get_test_toggles(), lka_icon=1, lfa_icon=1)
|
||||
lkas_msgs = [msg for msg in msgs if msg[0] == 0x110]
|
||||
assert len(lkas_msgs) == 1
|
||||
|
||||
parser.update([(1, lkas_msgs)])
|
||||
|
||||
assert parser.can_valid
|
||||
assert parser.vl["LKAS_ALT"]["LKAS_ANGLE_ACTIVE"] == 1
|
||||
assert parser.vl["LKAS_ALT"]["ADAS_ACIAnglTqRedcGainVal"] == pytest.approx(0.0)
|
||||
assert parser.vl["LKAS_ALT"]["ADAS_StrAnglReqVal"] == pytest.approx(-201.0)
|
||||
assert parser.vl["LKAS_ALT"]["DAMP_FACTOR"] == pytest.approx(100.0)
|
||||
assert parser.vl["LKAS_ALT"]["STEER_MODE"] == 2
|
||||
assert parser.vl["LKAS_ALT"]["NEW_SIGNAL_2"] == 3
|
||||
|
||||
def test_ev9_inactive_angle_steering_still_suppresses_stock_lfa(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.KIA_EV9
|
||||
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING |
|
||||
HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT)
|
||||
CP.openpilotLongitudinalControl = False
|
||||
|
||||
controller = CarController(DBC[CP.carFingerprint], CP)
|
||||
controller.frame = 5
|
||||
can_bus = CanBus(CP)
|
||||
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("CAM_0x362", 0)], can_bus.ECAN)
|
||||
cc = SimpleNamespace(enabled=False, latActive=False, actuators=SimpleNamespace(longControlState=LongCtrlState.off),
|
||||
leftBlinker=False, rightBlinker=False, hudControl=SimpleNamespace())
|
||||
lfa_block_msg = {f"BYTE{i}": 0 for i in range(3, 32) if i != 7}
|
||||
lfa_block_msg["COUNTER"] = 0
|
||||
cs = SimpleNamespace(stock_lfa_msg=None, stock_lkas_msg={}, lfa_block_msg=lfa_block_msg,
|
||||
out=SimpleNamespace(steeringAngleDeg=0.0))
|
||||
|
||||
msgs = controller.create_canfd_msgs(0, False, 0.0, 0.0, 0.0, 0.0, False, cc.hudControl, cs, cc,
|
||||
get_test_toggles(), lka_icon=1, lfa_icon=1)
|
||||
suppress_msgs = [msg for msg in msgs if msg[0] == 0x362]
|
||||
assert len(suppress_msgs) == 1
|
||||
|
||||
parser.update([(1, suppress_msgs)])
|
||||
|
||||
assert parser.can_valid
|
||||
assert parser.vl["CAM_0x362"]["LEFT_LANE_LINE"] == 0
|
||||
assert parser.vl["CAM_0x362"]["RIGHT_LANE_LINE"] == 0
|
||||
|
||||
def test_ev9_high_steering_angle_keeps_active_status_and_gain(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.KIA_EV9
|
||||
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING |
|
||||
HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT)
|
||||
CP.openpilotLongitudinalControl = False
|
||||
|
||||
controller = CarController(DBC[CP.carFingerprint], CP)
|
||||
controller.frame = 5
|
||||
can_bus = CanBus(CP)
|
||||
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("LKAS_ALT", 0)], can_bus.ACAN)
|
||||
stock_lkas = {
|
||||
"CHECKSUM": 1234,
|
||||
"COUNTER": 42,
|
||||
"LKA_MODE": 2,
|
||||
"LKA_AVAILABLE": 3,
|
||||
"LKA_WARNING": 1,
|
||||
"LKA_ICON": 1,
|
||||
"FCA_SYSWARN": 1,
|
||||
"TORQUE_REQUEST": 17,
|
||||
"STEER_REQ": 1,
|
||||
"LFA_BUTTON": 1,
|
||||
"LKA_ASSIST": 1,
|
||||
"STEER_MODE": 5,
|
||||
"NEW_SIGNAL_2": 0,
|
||||
"LKAS_ANGLE_ACTIVE": 1,
|
||||
"HAS_LANE_SAFETY": 1,
|
||||
"ADAS_StrAnglReqVal": 12.3,
|
||||
"ADAS_ACIAnglTqRedcGainVal": 0.42,
|
||||
"DAMP_FACTOR": 0,
|
||||
}
|
||||
cc = SimpleNamespace(enabled=True, latActive=True, actuators=SimpleNamespace(longControlState=LongCtrlState.off),
|
||||
leftBlinker=False, rightBlinker=False, hudControl=SimpleNamespace())
|
||||
lfa_block_msg = {f"BYTE{i}": 0 for i in range(3, 32) if i != 7}
|
||||
lfa_block_msg["COUNTER"] = 0
|
||||
cs = SimpleNamespace(stock_lfa_msg=None, stock_lkas_msg=stock_lkas, lfa_block_msg=lfa_block_msg,
|
||||
out=SimpleNamespace(steeringAngleDeg=120.0))
|
||||
|
||||
msgs = controller.create_canfd_msgs(0, True, 0.44, 120.0, 0.0, 0.0, False, cc.hudControl, cs, cc,
|
||||
get_test_toggles(), lka_icon=2, lfa_icon=2)
|
||||
lkas_msgs = [msg for msg in msgs if msg[0] == 0x110]
|
||||
suppress_msgs = [msg for msg in msgs if msg[0] == 0x362]
|
||||
assert len(lkas_msgs) == 1
|
||||
assert len(suppress_msgs) == 1
|
||||
|
||||
parser.update([(1, lkas_msgs)])
|
||||
|
||||
assert parser.can_valid
|
||||
assert parser.vl["LKAS_ALT"]["LKAS_ANGLE_ACTIVE"] == 2
|
||||
assert parser.vl["LKAS_ALT"]["ADAS_ACIAnglTqRedcGainVal"] == pytest.approx(0.44)
|
||||
assert parser.vl["LKAS_ALT"]["ADAS_StrAnglReqVal"] == pytest.approx(120.0)
|
||||
|
||||
def test_can_acc_commands_use_default_values(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.GENESIS_G90
|
||||
@@ -1246,6 +1691,84 @@ class TestHyundaiFingerprint:
|
||||
assert parser.can_valid
|
||||
assert parser.vl["LFA"]["LKA_ICON"] == 3
|
||||
|
||||
def test_kia_ev6_lfa_helper_preserves_stock_ui_fields_with_stock_long(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.KIA_EV6
|
||||
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CANFD_LKA_STEERING)
|
||||
CP.openpilotLongitudinalControl = False
|
||||
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
can_bus = CanBus(CP)
|
||||
|
||||
stock_lfa = {
|
||||
"CHECKSUM": 1234,
|
||||
"COUNTER": 42,
|
||||
"LKA_MODE": 6,
|
||||
"NEW_SIGNAL_1": 3,
|
||||
"LKA_WARNING": 1,
|
||||
"LKA_ICON": 1,
|
||||
"TORQUE_REQUEST": 17,
|
||||
"STEER_REQ": 0,
|
||||
"LFA_BUTTON": 1,
|
||||
"LKA_ASSIST": 1,
|
||||
"STEER_MODE": 5,
|
||||
"NEW_SIGNAL_2": 2,
|
||||
"NEW_SIGNAL_4": 7,
|
||||
"HAS_LANE_SAFETY": 1,
|
||||
"DAMP_FACTOR": 0x77,
|
||||
}
|
||||
|
||||
msgs = hyundaicanfd.create_steering_messages(packer, CP, can_bus, True, True, 123, 0.0, stock_lfa)
|
||||
assert [(packer.dbc.addr_to_msg[addr].name, bus) for addr, _, bus in msgs] == [
|
||||
("LKAS", can_bus.ACAN),
|
||||
]
|
||||
|
||||
def test_kia_ev6_lkas_helper_preserves_stock_camera_fields_with_stock_long(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.KIA_EV6
|
||||
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CANFD_LKA_STEERING)
|
||||
CP.openpilotLongitudinalControl = False
|
||||
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
can_bus = CanBus(CP)
|
||||
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("LKAS", 0)], can_bus.ACAN)
|
||||
|
||||
stock_lkas = {
|
||||
"CHECKSUM": 1234,
|
||||
"COUNTER": 42,
|
||||
"LKA_MODE": 6,
|
||||
"LKA_AVAILABLE": 3,
|
||||
"LKA_WARNING": 1,
|
||||
"LKA_ICON": 1,
|
||||
"FCA_SYSWARN": 1,
|
||||
"TORQUE_REQUEST": 17,
|
||||
"STEER_REQ": 0,
|
||||
"LFA_BUTTON": 1,
|
||||
"LKA_ASSIST": 1,
|
||||
"STEER_MODE": 5,
|
||||
"NEW_SIGNAL_2": 2,
|
||||
"HAS_LANE_SAFETY": 1,
|
||||
"DAMP_FACTOR": 0x70,
|
||||
}
|
||||
|
||||
msgs = hyundaicanfd.create_steering_messages(packer, CP, can_bus, True, True, 123, 0.0,
|
||||
lkas_base_values=stock_lkas)
|
||||
lkas_msgs = [msg for msg in msgs if msg[0] == 0x50]
|
||||
assert len(lkas_msgs) == 1
|
||||
|
||||
parser.update([(1, lkas_msgs)])
|
||||
|
||||
assert parser.can_valid
|
||||
assert parser.vl["LKAS"]["LKA_AVAILABLE"] == 3
|
||||
assert parser.vl["LKAS"]["LKA_WARNING"] == 1
|
||||
assert parser.vl["LKAS"]["FCA_SYSWARN"] == 1
|
||||
assert parser.vl["LKAS"]["LFA_BUTTON"] == 1
|
||||
assert parser.vl["LKAS"]["HAS_LANE_SAFETY"] == 1
|
||||
assert parser.vl["LKAS"]["DAMP_FACTOR"] == 0x70
|
||||
assert parser.vl["LKAS"]["TORQUE_REQUEST"] == 123
|
||||
assert parser.vl["LKAS"]["STEER_REQ"] == 1
|
||||
assert parser.vl["LKAS"]["LKA_ICON"] == 2
|
||||
|
||||
def test_ioniq_6_lkas_alt_helper_preserves_stock_camera_fields(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.HYUNDAI_IONIQ_6
|
||||
@@ -1294,6 +1817,121 @@ class TestHyundaiFingerprint:
|
||||
assert parser.vl["LKAS_ALT"]["STEER_REQ"] == 1
|
||||
assert parser.vl["LKAS_ALT"]["LKA_ICON"] == 2
|
||||
|
||||
def test_ev9_angle_lkas_alt_uses_angle_status_fields(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.KIA_EV9
|
||||
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING |
|
||||
HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT)
|
||||
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
can_bus = CanBus(CP)
|
||||
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("LKAS_ALT", 0)], can_bus.ACAN)
|
||||
|
||||
stock_lkas = {
|
||||
"CHECKSUM": 1234,
|
||||
"COUNTER": 42,
|
||||
"LKA_MODE": 2,
|
||||
"LKA_AVAILABLE": 0,
|
||||
"LKA_WARNING": 1,
|
||||
"LKA_ICON": 1,
|
||||
"FCA_SYSWARN": 1,
|
||||
"TORQUE_REQUEST": 17,
|
||||
"STEER_REQ": 1,
|
||||
"LFA_BUTTON": 1,
|
||||
"LKA_ASSIST": 1,
|
||||
"STEER_MODE": 5,
|
||||
"NEW_SIGNAL_2": 0,
|
||||
"LKAS_ANGLE_ACTIVE": 1,
|
||||
"HAS_LANE_SAFETY": 1,
|
||||
"ADAS_StrAnglReqVal": 12.3,
|
||||
"ADAS_ACIAnglTqRedcGainVal": 0.42,
|
||||
"DAMP_FACTOR": 0,
|
||||
}
|
||||
|
||||
msgs = hyundaicanfd.create_steering_messages(packer, CP, can_bus, True, True, 0.44, -31.5,
|
||||
lkas_base_values=stock_lkas, lka_icon=2)
|
||||
lkas_msgs = [msg for msg in msgs if msg[0] == 0x110]
|
||||
assert len(lkas_msgs) == 1
|
||||
|
||||
parser.update([(1, lkas_msgs)])
|
||||
|
||||
assert parser.can_valid
|
||||
assert parser.vl["LKAS_ALT"]["LKA_MODE"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["LKA_AVAILABLE"] == 3
|
||||
assert parser.vl["LKAS_ALT"]["LKA_WARNING"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["LKA_ICON"] == 2
|
||||
assert parser.vl["LKAS_ALT"]["FCA_SYSWARN"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["TORQUE_REQUEST"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["STEER_REQ"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["LFA_BUTTON"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["LKA_ASSIST"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["DAMP_FACTOR"] == 100
|
||||
assert parser.vl["LKAS_ALT"]["LKAS_ANGLE_ACTIVE"] == 2
|
||||
assert parser.vl["LKAS_ALT"]["HAS_LANE_SAFETY"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["ADAS_StrAnglReqVal"] == pytest.approx(-31.5)
|
||||
assert parser.vl["LKAS_ALT"]["ADAS_ACIAnglTqRedcGainVal"] == pytest.approx(0.44)
|
||||
|
||||
def test_ev9_angle_lkas_alt_preserves_stock_status_when_inactive(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.KIA_EV9
|
||||
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING |
|
||||
HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT)
|
||||
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
can_bus = CanBus(CP)
|
||||
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("LKAS_ALT", 0)], can_bus.ACAN)
|
||||
|
||||
stock_lkas = {
|
||||
"CHECKSUM": 1234,
|
||||
"COUNTER": 42,
|
||||
"LKA_MODE": 2,
|
||||
"LKA_AVAILABLE": 3,
|
||||
"LKA_WARNING": 1,
|
||||
"LKA_ICON": 1,
|
||||
"FCA_SYSWARN": 1,
|
||||
"TORQUE_REQUEST": 17,
|
||||
"STEER_REQ": 1,
|
||||
"LFA_BUTTON": 1,
|
||||
"LKA_ASSIST": 1,
|
||||
"STEER_MODE": 5,
|
||||
"NEW_SIGNAL_2": 0,
|
||||
"LKAS_ANGLE_ACTIVE": 2,
|
||||
"HAS_LANE_SAFETY": 1,
|
||||
"ADAS_StrAnglReqVal": 12.3,
|
||||
"ADAS_ACIAnglTqRedcGainVal": 0.42,
|
||||
"DAMP_FACTOR": 0,
|
||||
}
|
||||
|
||||
msgs = hyundaicanfd.create_steering_messages(packer, CP, can_bus, False, False, 0.44, -31.5,
|
||||
lkas_base_values=stock_lkas, lka_icon=1)
|
||||
lkas_msgs = [msg for msg in msgs if msg[0] == 0x110]
|
||||
assert len(lkas_msgs) == 1
|
||||
|
||||
parser.update([(1, lkas_msgs)])
|
||||
|
||||
assert parser.can_valid
|
||||
assert parser.vl["LKAS_ALT"]["LKA_MODE"] == 2
|
||||
assert parser.vl["LKAS_ALT"]["LKA_AVAILABLE"] == 3
|
||||
assert parser.vl["LKAS_ALT"]["LKA_WARNING"] == 1
|
||||
assert parser.vl["LKAS_ALT"]["LKA_ICON"] == 1
|
||||
assert parser.vl["LKAS_ALT"]["FCA_SYSWARN"] == 1
|
||||
assert parser.vl["LKAS_ALT"]["TORQUE_REQUEST"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["STEER_REQ"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["LFA_BUTTON"] == 1
|
||||
assert parser.vl["LKAS_ALT"]["LKA_ASSIST"] == 1
|
||||
assert parser.vl["LKAS_ALT"]["DAMP_FACTOR"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["LKAS_ANGLE_ACTIVE"] == 1
|
||||
assert parser.vl["LKAS_ALT"]["HAS_LANE_SAFETY"] == 1
|
||||
assert parser.vl["LKAS_ALT"]["ADAS_StrAnglReqVal"] == pytest.approx(-31.5)
|
||||
assert parser.vl["LKAS_ALT"]["ADAS_ACIAnglTqRedcGainVal"] == pytest.approx(0.0)
|
||||
|
||||
def test_ev9_accelerator_brake_alt_spoof_matches_route_template(self):
|
||||
msg = hyundaicanfd.create_accelerator_brake_alt_spoof(0, 0x66, True, False, CAR.KIA_EV9)
|
||||
|
||||
assert msg.address == 0x100
|
||||
assert msg.src == 0
|
||||
assert msg.dat.hex() == "470c6600ff006f00e80400001201030055ffff0000000000"
|
||||
|
||||
def test_ioniq_6_lfahda_cluster_allows_lfa_icon_override(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.HYUNDAI_IONIQ_6
|
||||
|
||||
@@ -54,6 +54,9 @@ class CarControllerParams:
|
||||
if CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
|
||||
self.STEER_THRESHOLD = 175
|
||||
|
||||
elif CP.flags & HyundaiFlags.CANFD:
|
||||
pass
|
||||
|
||||
# To determine the limit for your car, find the maximum value that the stock LKAS will request.
|
||||
# If the max stock LKAS request is <384, add your car to this list.
|
||||
elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.HYUNDAI_ELANTRA, CAR.HYUNDAI_ELANTRA_GT_I30, CAR.HYUNDAI_IONIQ,
|
||||
@@ -255,6 +258,14 @@ class CAR(Platforms):
|
||||
CarSpecs(mass=1675, wheelbase=2.885, steerRatio=14.5),
|
||||
flags=HyundaiFlags.HYBRID,
|
||||
)
|
||||
HYUNDAI_AZERA_HEV_7TH_GEN = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Hyundai Azera Hybrid (with HDA II & LFA2) 2025", "Highway Driving Assist II & Lane Follow Assist 2",
|
||||
car_parts=CarParts.common([CarHarness.hyundai_s])),
|
||||
],
|
||||
CarSpecs(mass=1720, wheelbase=2.895, steerRatio=13.5),
|
||||
flags=HyundaiFlags.CANFD_ANGLE_STEERING,
|
||||
)
|
||||
HYUNDAI_ELANTRA = HyundaiPlatformConfig(
|
||||
[
|
||||
# TODO: 2017-18 could be Hyundai G
|
||||
@@ -725,13 +736,18 @@ class CAR(Platforms):
|
||||
CarSpecs(mass=1450, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5),
|
||||
flags=HyundaiFlags.LEGACY,
|
||||
)
|
||||
KIA_XCEED_PHEV = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia XCeed Plug-in Hybrid 2021", car_parts=CarParts.common([CarHarness.hyundai_b]))],
|
||||
CarSpecs(mass=1650, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5),
|
||||
flags=HyundaiFlags.LEGACY | HyundaiFlags.HYBRID | HyundaiFlags.MANDO_RADAR,
|
||||
)
|
||||
KIA_EV6 = HyundaiCanFDPlatformConfig(
|
||||
[
|
||||
HyundaiCarDocs("Kia EV6 (Southeast Asia only) 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_p])),
|
||||
HyundaiCarDocs("Kia EV6 (without HDA II) 2022-24", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_l])),
|
||||
HyundaiCarDocs("Kia EV6 (with HDA II) 2022-24", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))
|
||||
],
|
||||
CarSpecs(mass=2055, wheelbase=2.9, steerRatio=16, tireStiffnessFactor=0.65),
|
||||
CarSpecs(mass=2055, wheelbase=2.9, steerRatio=14.25, tireStiffnessFactor=0.65),
|
||||
flags=HyundaiFlags.EV,
|
||||
radar_dbc=HYUNDAI_MRR30_RADAR_DBC,
|
||||
)
|
||||
@@ -739,7 +755,7 @@ class CAR(Platforms):
|
||||
[
|
||||
HyundaiCarDocs("Kia EV6 (with HDA I) 2025", "Highway Driving Assist I", car_parts=CarParts.common([CarHarness.hyundai_p]))
|
||||
],
|
||||
CarSpecs(mass=2055, wheelbase=2.9, steerRatio=16, tireStiffnessFactor=0.65),
|
||||
CarSpecs(mass=2055, wheelbase=2.9, steerRatio=14.26, tireStiffnessFactor=0.65),
|
||||
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
|
||||
radar_dbc=HYUNDAI_MRR30_RADAR_DBC,
|
||||
)
|
||||
@@ -906,20 +922,22 @@ CANCEL_BUTTON_ENABLE_CARS = frozenset({
|
||||
CAR.HYUNDAI_PALISADE_2023,
|
||||
})
|
||||
|
||||
KIA_EV6_GT_LINE_LONG_TUNING_VDS_PREFIXES = frozenset({
|
||||
"C4DLC",
|
||||
})
|
||||
|
||||
|
||||
# These classic HKG platforms publish the LKAS button on CLU13 over the alt bus.
|
||||
# Keep G90 excluded until its alt-bus path is route-proven without the recent
|
||||
# engage/disengage regression.
|
||||
ALT_BUS_LDA_BUTTON_CARS = frozenset({
|
||||
CAR.HYUNDAI_SONATA,
|
||||
CAR.HYUNDAI_SONATA_HYBRID,
|
||||
})
|
||||
|
||||
# On these Sonata layouts the alt-bus LKAS button pulses through the CLU13
|
||||
# steering-wheel-status field instead of the dedicated LKAS bit.
|
||||
ALT_BUS_LDA_BUTTON_SWL_STAT_CARS = frozenset({
|
||||
CAR.HYUNDAI_SONATA,
|
||||
CAR.HYUNDAI_SONATA_HYBRID,
|
||||
})
|
||||
|
||||
|
||||
@@ -927,6 +945,11 @@ def hyundai_cancel_button_enables_cruise(car_fingerprint) -> bool:
|
||||
return car_fingerprint in CANCEL_BUTTON_ENABLE_CARS
|
||||
|
||||
|
||||
def kia_ev6_gt_line_longitudinal_tuning(car_fingerprint, vin: str) -> bool:
|
||||
return car_fingerprint == CAR.KIA_EV6 and isinstance(vin, str) and \
|
||||
len(vin) == 17 and vin[3:8] in KIA_EV6_GT_LINE_LONG_TUNING_VDS_PREFIXES
|
||||
|
||||
|
||||
def get_platform_codes(fw_versions: list[bytes]) -> set[tuple[bytes, bytes | None]]:
|
||||
# Returns unique, platform-specific identification codes for a set of versions
|
||||
codes = set() # (code-Optional[part], date)
|
||||
@@ -1083,7 +1106,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
non_essential_ecus={
|
||||
Ecu.abs: [CAR.HYUNDAI_PALISADE, CAR.HYUNDAI_SONATA, CAR.HYUNDAI_SANTA_FE_2022, CAR.KIA_K5_2021, CAR.HYUNDAI_ELANTRA_2021,
|
||||
CAR.HYUNDAI_SANTA_FE, CAR.HYUNDAI_KONA_EV_2022, CAR.HYUNDAI_KONA_EV, CAR.HYUNDAI_CUSTIN_1ST_GEN, CAR.KIA_SORENTO,
|
||||
CAR.KIA_CEED, CAR.KIA_SELTOS],
|
||||
CAR.KIA_CEED, CAR.KIA_XCEED_PHEV, CAR.KIA_SELTOS],
|
||||
Ecu.fwdRadar: [CAR.HYUNDAI_KONA_NON_SCC],
|
||||
},
|
||||
extra_ecus=[
|
||||
@@ -1114,6 +1137,7 @@ CANFD_RADAR_SCC_CAR = CAR.with_flags(HyundaiFlags.RADAR_SCC) # TODO: merge with
|
||||
# CAN-FD cars with ADAS ECUs that work with the communication-control path.
|
||||
CANFD_SECURITYACCESS_CAR = {CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_KONA_EV_2ND_GEN}
|
||||
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) - CANFD_SECURITYACCESS_CAR # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
|
||||
CANFD_ANGLE_LONGITUDINAL_CAR = set()
|
||||
CANFD_RADAR_LIVE_LONGITUDINAL_CAR = {CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV6, CAR.GENESIS_GV60_EV_1ST_GEN}
|
||||
RADAR_LIVE_LONGITUDINAL_CAR = CANFD_RADAR_LIVE_LONGITUDINAL_CAR | {
|
||||
CAR.HYUNDAI_IONIQ,
|
||||
@@ -1123,6 +1147,7 @@ RADAR_LIVE_LONGITUDINAL_CAR = CANFD_RADAR_LIVE_LONGITUDINAL_CAR | {
|
||||
CAR.HYUNDAI_SANTA_FE_PHEV_2022,
|
||||
CAR.HYUNDAI_SONATA,
|
||||
CAR.HYUNDAI_SONATA_HYBRID,
|
||||
CAR.KIA_XCEED_PHEV,
|
||||
CAR.GENESIS_G90,
|
||||
}
|
||||
|
||||
@@ -1140,4 +1165,6 @@ NON_SCC_CAR = CAR.with_flags(HyundaiFlags.NON_SCC)
|
||||
# HyundaiFlags.CANFD_RADAR_SCC | HyundaiFlags.CANFD_NO_RADAR_DISABLE | )
|
||||
UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.LEGACY) | CAR.with_flags(HyundaiFlags.UNSUPPORTED_LONGITUDINAL)
|
||||
|
||||
LEGACY_LONGITUDINAL_CAR = {CAR.KIA_XCEED_PHEV}
|
||||
|
||||
DBC = CAR.create_dbc_map()
|
||||
|
||||
@@ -22,6 +22,7 @@ from opendbc.car.honda.values import CAR as HONDA, HONDA_BOSCH, HondaFlags, Hond
|
||||
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from opendbc.car.hyundai.values import CAR as HYUNDAI, CANFD_CAR, HyundaiFlags, HyundaiStarPilotFlags, HyundaiStarPilotSafetyFlags, ALT_BUS_LDA_BUTTON_CARS
|
||||
from opendbc.car.mock.values import CAR as MOCK
|
||||
from opendbc.car.subaru.values import CAR as SUBARU, SubaruSafetyFlags
|
||||
from opendbc.car.toyota.values import CAR as TOYOTA, NO_DSU_CAR, TSS2_CAR, UNSUPPORTED_DSU_CAR, ToyotaStarPilotFlags, ToyotaSafetyFlags
|
||||
from opendbc.car.values import PLATFORMS
|
||||
from opendbc.can import CANParser
|
||||
@@ -133,6 +134,7 @@ class CarInterfaceBase(ABC):
|
||||
|
||||
dbc_names = {bus: cp.dbc_name for bus, cp in self.can_parsers.items()}
|
||||
self.CC: CarControllerBase = self.CarController(dbc_names, CP)
|
||||
self.CC.FPCP = FPCP
|
||||
|
||||
self.FPCP = FPCP
|
||||
|
||||
@@ -174,8 +176,11 @@ class CarInterfaceBase(ABC):
|
||||
|
||||
ret = cls._get_params(ret, candidate, fingerprint, car_fw, alpha_long, is_release, docs)
|
||||
|
||||
trailer_load_kg = float(np.clip(getattr(starpilot_toggles, "trailer_load_kg", 0.0) or 0.0, 0.0, 15000.0 * CV.LB_TO_KG))
|
||||
|
||||
# Vehicle mass is published curb weight plus assumed payload such as a human driver; notCars have no assumed payload
|
||||
if not ret.notCar:
|
||||
ret.mass = ret.mass + trailer_load_kg
|
||||
ret.mass = ret.mass + STD_CARGO_KG
|
||||
|
||||
# Set params dependent on values set by the car interface
|
||||
@@ -211,6 +216,9 @@ class CarInterfaceBase(ABC):
|
||||
if candidate == CHRYSLER.RAM_HD_5TH_GEN:
|
||||
if 570 not in fingerprint[0]:
|
||||
fp_ret.flags |= ChryslerStarPilotFlags.RAM_HD_ALT_BUTTONS.value
|
||||
if 0x4FF in fingerprint[0]:
|
||||
fp_ret.flags |= ChryslerStarPilotFlags.NO_MIN_STEERING_SPEED.value
|
||||
CP.minSteerSpeed = 0.
|
||||
|
||||
elif platform in GM:
|
||||
fp_ret.canUsePedal = True
|
||||
@@ -263,6 +271,10 @@ class CarInterfaceBase(ABC):
|
||||
elif platform.config.platform_str == "TESLA_MODEL_S_PREAP":
|
||||
fp_ret.canUsePedal = True
|
||||
|
||||
elif platform in SUBARU:
|
||||
if getattr(starpilot_toggles, "subaru_sng", False):
|
||||
fp_ret.safetyConfigs[-1].safetyParam |= SubaruSafetyFlags.STOP_AND_GO.value
|
||||
|
||||
return fp_ret
|
||||
|
||||
@staticmethod
|
||||
@@ -497,6 +509,7 @@ class CarStateBase(ABC):
|
||||
class CarControllerBase(ABC):
|
||||
def __init__(self, dbc_names: dict[StrEnum, str], CP: structs.CarParams):
|
||||
self.CP = CP
|
||||
self.FPCP: custom.StarPilotCarParams | None = None
|
||||
self.frame = 0
|
||||
self.secoc_key: bytes = b"00" * 16
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import numpy as np
|
||||
from opendbc.can import CANPacker
|
||||
from opendbc.car import Bus, make_tester_present_msg
|
||||
from opendbc.car import Bus, DT_CTRL, make_tester_present_msg
|
||||
from opendbc.car.lateral import apply_driver_steer_torque_limits, common_fault_avoidance
|
||||
from opendbc.car.interfaces import CarControllerBase
|
||||
from opendbc.car.subaru import subarucan
|
||||
@@ -26,14 +26,9 @@ class CarController(CarControllerBase):
|
||||
self.p = CarControllerParams(CP)
|
||||
self.packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
|
||||
self.manual_hold = False
|
||||
self.prev_standstill = False
|
||||
self.sng_acc_resume = False
|
||||
|
||||
self.prev_close_distance = 0
|
||||
self.prev_cruise_state = 0
|
||||
self.sng_acc_resume_cnt = 0
|
||||
self.standstill_start = 0
|
||||
self.epb_resume_frames_remaining = -1
|
||||
self.last_standstill_frame = 0
|
||||
|
||||
def update(self, CC, CS, now_nanos, starpilot_toggles):
|
||||
actuators = CC.actuators
|
||||
@@ -70,8 +65,9 @@ class CarController(CarControllerBase):
|
||||
self.apply_torque_last = apply_torque
|
||||
|
||||
# *** stop and go ***
|
||||
subaru_sng_manual_parking_brake = getattr(starpilot_toggles, "subaru_sng_manual_parking_brake", False)
|
||||
if starpilot_toggles.subaru_sng:
|
||||
throttle_cmd, speed_cmd = self.stop_and_go(CC, CS)
|
||||
throttle_cmd, speed_cmd = self.stop_and_go(CC, CS, subaru_sng_manual_parking_brake)
|
||||
|
||||
# *** longitudinal ***
|
||||
|
||||
@@ -110,7 +106,11 @@ class CarController(CarControllerBase):
|
||||
can_sends.append(subarucan.create_preglobal_es_distance(self.packer, cruise_button, CS.es_distance_msg))
|
||||
|
||||
if starpilot_toggles.subaru_sng:
|
||||
can_sends.append(subarucan.create_preglobal_throttle(self.packer, CS.throttle_msg["COUNTER"] + 1, CS.throttle_msg, throttle_cmd))
|
||||
can_sends.append(subarucan.create_preglobal_throttle(self.packer, CS.throttle_msg["COUNTER"] + 1, CS.throttle_msg,
|
||||
throttle_cmd))
|
||||
if self.frame % 2 == 0:
|
||||
can_sends.append(subarucan.create_preglobal_brake_pedal(self.packer, CS.brake_pedal_msg,
|
||||
speed_cmd))
|
||||
else:
|
||||
if self.frame % 10 == 0:
|
||||
can_sends.append(subarucan.create_es_dashstatus(self.packer, self.frame // 10, CS.es_dashstatus_msg, CC.enabled,
|
||||
@@ -124,9 +124,11 @@ class CarController(CarControllerBase):
|
||||
can_sends.append(subarucan.create_es_infotainment(self.packer, self.frame // 10, CS.es_infotainment_msg, hud_control.visualAlert))
|
||||
|
||||
if starpilot_toggles.subaru_sng:
|
||||
can_sends.append(subarucan.create_throttle(self.packer, CS.throttle_msg["COUNTER"] + 1, CS.throttle_msg, throttle_cmd))
|
||||
can_sends.append(subarucan.create_throttle(self.packer, CS.throttle_msg["COUNTER"] + 1, CS.throttle_msg,
|
||||
throttle_cmd))
|
||||
if self.frame % 2 == 0:
|
||||
can_sends.append(subarucan.create_brake_pedal(self.packer, self.frame // 2, CS.brake_pedal_msg, speed_cmd, pcm_cancel_cmd))
|
||||
can_sends.append(subarucan.create_brake_pedal(self.packer, self.frame // 2, CS.brake_pedal_msg,
|
||||
speed_cmd, pcm_cancel_cmd))
|
||||
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
if self.frame % 5 == 0:
|
||||
@@ -166,49 +168,37 @@ class CarController(CarControllerBase):
|
||||
self.frame += 1
|
||||
return new_actuators, can_sends
|
||||
|
||||
def stop_and_go(self, CC, CS, speed_cmd=False, throttle_cmd=False):
|
||||
if self.CP.flags & SubaruFlags.PREGLOBAL:
|
||||
trigger_resume = CC.enabled
|
||||
trigger_resume &= CS.car_follow == 1
|
||||
trigger_resume &= CS.close_distance > self.prev_close_distance
|
||||
trigger_resume &= CS.out.standstill
|
||||
trigger_resume &= _SNG_ACC_MIN_DIST < CS.close_distance < _SNG_ACC_MAX_DIST
|
||||
def stop_and_go(self, CC, CS, manual_parking_brake=False):
|
||||
throttle_cmd = False
|
||||
speed_cmd = False
|
||||
|
||||
if trigger_resume:
|
||||
self.sng_acc_resume = True
|
||||
else:
|
||||
if CS.car_follow == 0 and CS.cruise_state == 3 and CS.out.standstill and self.prev_cruise_state == 1:
|
||||
self.manual_hold = True
|
||||
if not CC.enabled or not CC.hudControl.leadVisible:
|
||||
return throttle_cmd, speed_cmd
|
||||
|
||||
if not CS.out.standstill:
|
||||
self.manual_hold = False
|
||||
close_distance = CS.close_distance
|
||||
if not CS.out.standstill:
|
||||
self.last_standstill_frame = self.frame
|
||||
|
||||
trigger_resume = CC.enabled
|
||||
trigger_resume &= CS.car_follow == 1
|
||||
trigger_resume &= CS.close_distance > self.prev_close_distance
|
||||
trigger_resume &= CS.cruise_state == 3
|
||||
trigger_resume &= not self.manual_hold
|
||||
trigger_resume &= _SNG_ACC_MIN_DIST < CS.close_distance < _SNG_ACC_MAX_DIST
|
||||
standstill_timers = (0.75, 0.8) if self.CP.flags & SubaruFlags.PREGLOBAL else (0.5, 0.55)
|
||||
standstill_duration = (self.frame - self.last_standstill_frame) * DT_CTRL
|
||||
in_standstill_hold = standstill_duration > standstill_timers[0]
|
||||
if standstill_duration >= standstill_timers[1]:
|
||||
self.last_standstill_frame = self.frame
|
||||
|
||||
if trigger_resume:
|
||||
self.sng_acc_resume = True
|
||||
if manual_parking_brake or not (self.CP.flags & SubaruFlags.PREGLOBAL):
|
||||
speed_cmd = in_standstill_hold
|
||||
|
||||
if CC.enabled and CS.car_follow == 1 and CS.out.standstill and self.frame > self.standstill_start + 50:
|
||||
speed_cmd = True
|
||||
should_resume = (
|
||||
CS.out.standstill and
|
||||
_SNG_ACC_MIN_DIST < close_distance < _SNG_ACC_MAX_DIST and
|
||||
close_distance > self.prev_close_distance
|
||||
)
|
||||
if should_resume:
|
||||
self.epb_resume_frames_remaining = 15
|
||||
|
||||
if CS.out.standstill and not self.prev_standstill:
|
||||
self.standstill_start = self.frame
|
||||
throttle_cmd = self.epb_resume_frames_remaining > 0
|
||||
if self.epb_resume_frames_remaining > 0:
|
||||
self.epb_resume_frames_remaining -= 1
|
||||
|
||||
self.prev_standstill = CS.out.standstill
|
||||
self.prev_cruise_state = CS.cruise_state
|
||||
|
||||
if self.sng_acc_resume:
|
||||
if self.sng_acc_resume_cnt < 5:
|
||||
throttle_cmd = True
|
||||
self.sng_acc_resume_cnt += 1
|
||||
else:
|
||||
self.sng_acc_resume = False
|
||||
self.sng_acc_resume_cnt = -1
|
||||
|
||||
self.prev_close_distance = CS.close_distance
|
||||
self.prev_close_distance = close_distance
|
||||
return throttle_cmd, speed_cmd
|
||||
|
||||
@@ -358,6 +358,19 @@ def create_brake_pedal(packer, frame, brake_pedal_msg, speed_cmd, brake_cmd):
|
||||
return packer.make_can_msg("Brake_Pedal", CanBus.camera, values)
|
||||
|
||||
|
||||
def create_preglobal_brake_pedal(packer, brake_pedal_msg, speed_cmd):
|
||||
values = {s: brake_pedal_msg[s] for s in sorted([
|
||||
"Brake_Pedal",
|
||||
"Signal1",
|
||||
"Speed",
|
||||
])}
|
||||
|
||||
if speed_cmd:
|
||||
values["Speed"] = 1
|
||||
|
||||
return packer.make_can_msg("Brake_Pedal", CanBus.camera, values)
|
||||
|
||||
|
||||
def create_throttle(packer, frame, throttle_msg, throttle_cmd):
|
||||
values = {s: throttle_msg[s] for s in sorted([
|
||||
"CHECKSUM",
|
||||
|
||||
@@ -1,4 +1,57 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
from opendbc.car.subaru.carcontroller import CarController
|
||||
from opendbc.car.subaru.fingerprints import FW_VERSIONS
|
||||
from opendbc.car.subaru.values import SubaruFlags
|
||||
|
||||
|
||||
def make_sng_controller(flags=0, prev_close_distance=4.0):
|
||||
controller = object.__new__(CarController)
|
||||
controller.CP = SimpleNamespace(flags=flags)
|
||||
controller.frame = 60
|
||||
controller.last_standstill_frame = 0
|
||||
controller.prev_close_distance = prev_close_distance
|
||||
controller.epb_resume_frames_remaining = -1
|
||||
return controller
|
||||
|
||||
|
||||
def make_sng_state(close_distance=4.0, standstill=True):
|
||||
cc = SimpleNamespace(enabled=True, hudControl=SimpleNamespace(leadVisible=True))
|
||||
cs = SimpleNamespace(
|
||||
close_distance=close_distance,
|
||||
out=SimpleNamespace(standstill=standstill),
|
||||
)
|
||||
return cc, cs
|
||||
|
||||
|
||||
def test_global_sng_keeps_standstill_alive_without_manual_parking_brake_toggle():
|
||||
controller = make_sng_controller()
|
||||
cc, cs = make_sng_state()
|
||||
|
||||
throttle_cmd, speed_cmd = controller.stop_and_go(cc, cs, manual_parking_brake=False)
|
||||
|
||||
assert throttle_cmd is False
|
||||
assert speed_cmd is True
|
||||
|
||||
|
||||
def test_manual_parking_brake_sng_still_sends_resume_throttle():
|
||||
controller = make_sng_controller(prev_close_distance=3.9)
|
||||
cc, cs = make_sng_state(close_distance=4.0)
|
||||
|
||||
throttle_cmd, speed_cmd = controller.stop_and_go(cc, cs, manual_parking_brake=True)
|
||||
|
||||
assert throttle_cmd is True
|
||||
assert speed_cmd is True
|
||||
|
||||
|
||||
def test_preglobal_sng_does_not_send_standstill_keepalive_without_manual_toggle():
|
||||
controller = make_sng_controller(flags=SubaruFlags.PREGLOBAL)
|
||||
cc, cs = make_sng_state()
|
||||
|
||||
throttle_cmd, speed_cmd = controller.stop_and_go(cc, cs, manual_parking_brake=False)
|
||||
|
||||
assert throttle_cmd is False
|
||||
assert speed_cmd is False
|
||||
|
||||
|
||||
class TestSubaruFingerprint:
|
||||
|
||||
@@ -59,6 +59,7 @@ class SubaruSafetyFlags(IntFlag):
|
||||
GEN2 = 1
|
||||
LONG = 2
|
||||
PREGLOBAL_REVERSED_DRIVER_TORQUE = 4
|
||||
STOP_AND_GO = 8
|
||||
|
||||
|
||||
class SubaruFlags(IntFlag):
|
||||
|
||||
@@ -126,16 +126,16 @@ def update_preap(cs, can_parsers):
|
||||
|
||||
cs.das_control = None
|
||||
cs.cruise_enabled_prev = ret.cruiseState.enabled
|
||||
ret.pedalMaxRegen = cs.pccEvent == "pedalMaxRegen"
|
||||
ret.teslaCCEngaged = cs.pccEvent == "teslaCCEngaged"
|
||||
ret.teslaCCDisengaged = cs.pccEvent == "teslaCCDisengaged"
|
||||
ret.teslaCCNotArmed = (
|
||||
fp_ret.pedalMaxRegen = cs.pccEvent == "pedalMaxRegen"
|
||||
fp_ret.teslaCCEngaged = cs.pccEvent == "teslaCCEngaged"
|
||||
fp_ret.teslaCCDisengaged = cs.pccEvent == "teslaCCDisengaged"
|
||||
fp_ret.teslaCCNotArmed = (
|
||||
not nap_conf.use_pedal and
|
||||
cs.cruiseEnabled and
|
||||
cs.enableLongControl and
|
||||
cs.di_cruise_state not in ("STANDBY", "ENABLED")
|
||||
)
|
||||
ret.pedalLongActive = cs.enableLongControl and nap_conf.use_pedal
|
||||
fp_ret.pedalLongActive = cs.enableLongControl and nap_conf.use_pedal
|
||||
return ret, fp_ret
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ from opendbc.car.tesla.preap.nap_conf import nap_conf
|
||||
PREAP_FLAG_ENABLE_PEDAL = 1
|
||||
PREAP_FLAG_RADAR_EMULATION = 2
|
||||
PREAP_FLAG_RADAR_BEHIND_NOSECONE = 4
|
||||
SAFETY_TESLA_PREAP = 35
|
||||
|
||||
|
||||
def get_preap_accel_limits(current_speed: float) -> tuple[float, float]:
|
||||
@@ -29,7 +30,7 @@ def get_preap_params(ret: structs.CarParams) -> structs.CarParams:
|
||||
safety_flags |= PREAP_FLAG_RADAR_BEHIND_NOSECONE
|
||||
|
||||
use_pedal = nap_conf.use_pedal and nap_conf.pedal_calibrated
|
||||
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.teslaPreap, safety_flags)]
|
||||
ret.safetyConfigs = [get_safety_config(SAFETY_TESLA_PREAP, safety_flags)]
|
||||
ret.radarUnavailable = not nap_conf.radar_enabled
|
||||
ret.steerControlType = structs.CarParams.SteerControlType.angle
|
||||
ret.openpilotLongitudinalControl = use_pedal
|
||||
|
||||
@@ -22,12 +22,14 @@ non_tested_cars = [
|
||||
MOCK.MOCK,
|
||||
GM.CADILLAC_ATS,
|
||||
GM.CADILLAC_ESCALADE_ASCM,
|
||||
GM.CADILLAC_ESCALADE_ESV_2019_ASCM,
|
||||
GM.CADILLAC_XT5,
|
||||
GM.HOLDEN_ASTRA,
|
||||
GM.CHEVROLET_MALIBU,
|
||||
HYUNDAI.GENESIS_G90,
|
||||
HYUNDAI.GENESIS_GV70_ELECTRIFIED_2ND_GEN,
|
||||
HYUNDAI.GENESIS_GV80_2025,
|
||||
HYUNDAI.HYUNDAI_AZERA_HEV_7TH_GEN,
|
||||
HYUNDAI.HYUNDAI_IONIQ_5_PE,
|
||||
HYUNDAI.HYUNDAI_IONIQ_5_N,
|
||||
HYUNDAI.HYUNDAI_SANTA_FE_HEV_5TH_GEN,
|
||||
@@ -163,6 +165,7 @@ routes = [
|
||||
CarTestRoute("de59124955b921d8/2023-06-24--00-12-50", HYUNDAI.KIA_CARNIVAL_4TH_GEN),
|
||||
CarTestRoute("409c9409979a8abc/2023-07-11--09-06-44", HYUNDAI.KIA_CARNIVAL_4TH_GEN), # Chinese model
|
||||
CarTestRoute("e0e98335f3ebc58f/2021-03-07--16-38-29", HYUNDAI.KIA_CEED),
|
||||
CarTestRoute("22703002ddbe2a08/0000000e--083b76c42c", HYUNDAI.KIA_XCEED_PHEV, segment=0),
|
||||
CarTestRoute("7653b2bce7bcfdaa/2020-03-04--15-34-32", HYUNDAI.KIA_OPTIMA_G4),
|
||||
CarTestRoute("018654717bc93d7d/2022-09-19--23-11-10", HYUNDAI.KIA_OPTIMA_G4_FL, segment=0),
|
||||
CarTestRoute("f9716670b2481438/2023-08-23--14-49-50", HYUNDAI.KIA_OPTIMA_H),
|
||||
|
||||
@@ -4,9 +4,17 @@ import pytest
|
||||
from opendbc.car.can_definitions import CanData
|
||||
from opendbc.car.car_helpers import FRAME_FINGERPRINT, _apply_starpilot_access_policy, _get_gm_stored_candidate_fallback, can_fingerprint
|
||||
from opendbc.car.fingerprints import _FINGERPRINTS as FINGERPRINTS
|
||||
from opendbc.car.gm.values import CAR as GM
|
||||
|
||||
|
||||
class TestCanFingerprint:
|
||||
@staticmethod
|
||||
def _fingerprint_from_can(fingerprint):
|
||||
can = [CanData(address=address, dat=b'\x00' * length, src=src)
|
||||
for address, length in fingerprint.items() for src in (0, 1)]
|
||||
fingerprint_iter = iter([can])
|
||||
return can_fingerprint(lambda **kwargs: [next(fingerprint_iter, [])]) # noqa: B023
|
||||
|
||||
@pytest.mark.parametrize("car_model, fingerprints", FINGERPRINTS.items())
|
||||
def test_can_fingerprint(self, car_model, fingerprints):
|
||||
"""Tests online fingerprinting function on offline fingerprints"""
|
||||
@@ -23,6 +31,12 @@ class TestCanFingerprint:
|
||||
assert finger[1] == fingerprint
|
||||
assert finger[2] == {}
|
||||
|
||||
def test_gm_sascm_superset_fingerprint_matches_ascm_variant(self):
|
||||
car_fingerprint, finger = self._fingerprint_from_can(FINGERPRINTS[GM.CADILLAC_ESCALADE_ESV_2019_ASCM][0])
|
||||
|
||||
assert car_fingerprint == GM.CADILLAC_ESCALADE_ESV_2019_ASCM
|
||||
assert finger[0][0x2FF] == 8
|
||||
|
||||
def test_timing(self, subtests):
|
||||
# just pick any CAN fingerprinting car
|
||||
car_model = "CHEVROLET_BOLT_ACC_2022_2023"
|
||||
|
||||
@@ -8,9 +8,13 @@ from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
from cereal import custom
|
||||
from opendbc.car import DT_CTRL, CanData, structs
|
||||
from opendbc.can import CANParser
|
||||
from opendbc.car import Bus, DT_CTRL, CanData, structs
|
||||
from opendbc.car.car_helpers import _apply_disable_openpilot_long, interfaces
|
||||
from opendbc.car.chrysler.carcontroller import CarController as ChryslerCarController
|
||||
from opendbc.car.chrysler.carstate import CarState as ChryslerCarState
|
||||
from opendbc.car.chrysler.interface import CarInterface as ChryslerCarInterface
|
||||
from opendbc.car.chrysler.values import CAR as CHRYSLER_CAR, DBC as CHRYSLER_DBC, ChryslerStarPilotFlags
|
||||
from opendbc.car.fingerprints import FW_VERSIONS
|
||||
from opendbc.car.fw_versions import FW_QUERY_CONFIGS
|
||||
from opendbc.car.hyundai.interface import CarInterface as HyundaiCarInterface
|
||||
@@ -74,6 +78,7 @@ def get_test_starpilot_toggles() -> SimpleNamespace:
|
||||
reverse_cruise_increase=False,
|
||||
sng_hack=False,
|
||||
subaru_sng=False,
|
||||
subaru_sng_manual_parking_brake=False,
|
||||
unlock_doors=False,
|
||||
vEgoStopping=0.5,
|
||||
volt_sng=False,
|
||||
@@ -160,6 +165,53 @@ class TestCarInterfaces:
|
||||
"Center_Stack_2": {"LKAS_Button": 1},
|
||||
}, is_ram=True)
|
||||
|
||||
def test_chrysler_wd_mod_enables_steer_to_zero(self):
|
||||
fingerprint = {bus: {} for bus in range(8)}
|
||||
fingerprint[0][0x4FF] = 8
|
||||
toggles = get_test_starpilot_toggles()
|
||||
|
||||
car_params = ChryslerCarInterface.get_params(
|
||||
CHRYSLER_CAR.CHRYSLER_PACIFICA_2020,
|
||||
fingerprint,
|
||||
[],
|
||||
alpha_long=False,
|
||||
is_release=False,
|
||||
docs=False,
|
||||
starpilot_toggles=toggles,
|
||||
)
|
||||
assert car_params.minSteerSpeed > 0.
|
||||
|
||||
fp_car_params = ChryslerCarInterface.get_starpilot_params(
|
||||
CHRYSLER_CAR.CHRYSLER_PACIFICA_2020,
|
||||
fingerprint,
|
||||
[],
|
||||
car_params,
|
||||
toggles,
|
||||
)
|
||||
assert fp_car_params.flags & ChryslerStarPilotFlags.NO_MIN_STEERING_SPEED
|
||||
assert car_params.minSteerSpeed == 0.
|
||||
|
||||
controller = ChryslerCarController({Bus.pt: CHRYSLER_DBC[car_params.carFingerprint][Bus.pt]}, car_params)
|
||||
controller.FPCP = fp_car_params
|
||||
controller.frame = 202
|
||||
|
||||
CC = structs.CarControl()
|
||||
CC.latActive = True
|
||||
CC.actuators.torque = 0.1
|
||||
CC = CC.as_reader()
|
||||
CS = SimpleNamespace(
|
||||
out=SimpleNamespace(vEgo=0.0, steeringTorqueEps=0.0, gearShifter=structs.CarState.GearShifter.drive),
|
||||
lkas_car_model=-1,
|
||||
button_counter=0,
|
||||
button_message="CRUISE_BUTTONS",
|
||||
auto_high_beam=0,
|
||||
)
|
||||
_, can_sends = controller.update(CC, CS, 0, toggles)
|
||||
|
||||
lkas_parser = CANParser(CHRYSLER_DBC[car_params.carFingerprint][Bus.pt], [("LKAS_COMMAND", 50)], 0)
|
||||
lkas_parser.update([0, can_sends])
|
||||
assert lkas_parser.vl["LKAS_COMMAND"]["LKAS_CONTROL_BIT"] == 1
|
||||
|
||||
def test_gm_bolt_gen2_pedal_safety_flags(self):
|
||||
CarInterface = interfaces[GM_CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL]
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
|
||||
# Toyota LTA also has torque
|
||||
"TOYOTA_RAV4_TSS2_2023" = [nan, 3.0, nan]
|
||||
"TOYOTA_MATRIX_RETROFIT" = [4.05, 1.84, 0.10]
|
||||
|
||||
# Tesla angle based controllers
|
||||
"TESLA_MODEL_3" = [nan, 2.5, nan]
|
||||
@@ -74,6 +75,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"HYUNDAI_TUCSON_HEV_2025" = [2.5, 2.5, 0.1]
|
||||
"HYUNDAI_TUCSON_PHEV_2025" = [2.5, 2.5, 0.1]
|
||||
"KIA_SPORTAGE_5TH_GEN" = [2.6, 2.6, 0.1]
|
||||
"KIA_XCEED_PHEV" = [2.9638737459977467, 2.1259108157250735, 0.07813665616927593]
|
||||
"KIA_SPORTAGE_2026" = [nan, 2.5, nan]
|
||||
"KIA_SPORTAGE_HEV_2026" = [nan, 2.5, nan]
|
||||
"GENESIS_GV70_1ST_GEN" = [2.42, 2.42, 0.1]
|
||||
@@ -96,6 +98,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"HYUNDAI_IONIQ_9" = [nan, 2.5, nan]
|
||||
"HYUNDAI_AZERA_6TH_GEN" = [1.8, 1.8, 0.1]
|
||||
"HYUNDAI_AZERA_HEV_6TH_GEN" = [1.8, 1.8, 0.1]
|
||||
"HYUNDAI_AZERA_HEV_7TH_GEN" = [nan, 2.5, nan]
|
||||
"KIA_K8_HEV_1ST_GEN" = [2.5, 2.5, 0.1]
|
||||
"KIA_K4_2025" = [2.5, 2.5, 0.1]
|
||||
"KIA_K5_2025" = [2.5, 2.5, 0.1]
|
||||
|
||||
@@ -69,6 +69,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"BUICK_REGAL" = "CHEVROLET_VOLT"
|
||||
"CADILLAC_ESCALADE_ASCM" = "CADILLAC_ESCALADE"
|
||||
"CADILLAC_ESCALADE_ESV" = "CHEVROLET_VOLT"
|
||||
"CADILLAC_ESCALADE_ESV_2019_ASCM" = "CADILLAC_ESCALADE_ESV_2019"
|
||||
"CADILLAC_ATS" = "CHEVROLET_VOLT"
|
||||
"CHEVROLET_MALIBU" = "CHEVROLET_VOLT"
|
||||
"CHEVROLET_MALIBU_ASCM" = "CHEVROLET_VOLT"
|
||||
|
||||
@@ -26,6 +26,7 @@ ACCEL_WINDDOWN_LIMIT = -4.0 * DT_CTRL * 3 # m/s^2 / frame
|
||||
ACCEL_PID_UNWIND = 0.03 * DT_CTRL * 3 # m/s^2 / frame
|
||||
PRIUS_INTEGRAL_MISMATCH_UNWIND = 8.0
|
||||
PRIUS_POSITIVE_FEEDFORWARD_SCALE = 0.7
|
||||
PRIUS_CRUISE_FEEDFORWARD_SCALE = 0.85
|
||||
|
||||
MAX_PITCH_COMPENSATION = 1.5 # m/s^2
|
||||
TOYOTA_COAST_BRAKE_MIN_SPEED = 15.0 # m/s
|
||||
@@ -43,6 +44,7 @@ MAX_STEER_RATE_FRAMES = 18 # tx control frames needed before torque can be cut
|
||||
MAX_USER_TORQUE = 500
|
||||
|
||||
PARK = structs.CarState.GearShifter.park
|
||||
REVERSE = structs.CarState.GearShifter.reverse
|
||||
|
||||
# Lock / unlock door commands - Credit goes to AlexandreSato!
|
||||
LOCK_CMD = b"\x40\x05\x30\x11\x00\x80\x00\x00"
|
||||
@@ -65,6 +67,11 @@ def get_long_tune(CP, params):
|
||||
rate=1 / (DT_CTRL * 3))
|
||||
|
||||
|
||||
def get_prius_positive_feedforward_scale(v_ego: float) -> float:
|
||||
return float(np.interp(v_ego, [0.0, 8.0, 20.0],
|
||||
[PRIUS_POSITIVE_FEEDFORWARD_SCALE, PRIUS_POSITIVE_FEEDFORWARD_SCALE, PRIUS_CRUISE_FEEDFORWARD_SCALE]))
|
||||
|
||||
|
||||
def update_permit_braking(current: bool, net_acceleration_request_min: float, stopping: bool,
|
||||
long_active: bool, v_ego: float, lead_visible: bool) -> bool:
|
||||
if stopping or not long_active:
|
||||
@@ -192,18 +199,23 @@ class CarController(CarControllerBase):
|
||||
self.secoc_prev_reset_counter = 0
|
||||
|
||||
self.doors_locked = False
|
||||
self.auto_brake_hold = bool(self.CP.flags & ToyotaFlags.AUTO_BRAKE_HOLD.value)
|
||||
self.brake_hold_active = False
|
||||
self._brake_hold_counter = 0
|
||||
self._brake_hold_reset = False
|
||||
self._prev_brake_pressed = False
|
||||
|
||||
def _compute_interceptor_gas_cmd(self, CC, CS):
|
||||
if not (self.CP.enableGasInterceptorDEPRECATED and self.CP.openpilotLongitudinalControl and CC.longActive):
|
||||
return 0.0
|
||||
|
||||
if self.CP.minEnableSpeed < 0.0:
|
||||
return 0.12 if CS.out.standstill and self.accel > 0.0 else 0.0
|
||||
if CS.out.standstill:
|
||||
return 0.12 if self.accel > 0.0 else 0.0
|
||||
|
||||
max_interceptor_gas = 0.5
|
||||
if self.CP.carFingerprint == CAR.TOYOTA_RAV4:
|
||||
pedal_scale = float(np.interp(CS.out.vEgo, [0.0, MIN_ACC_SPEED, MIN_ACC_SPEED + PEDAL_TRANSITION], [0.15, 0.3, 0.0]))
|
||||
elif self.CP.carFingerprint == CAR.TOYOTA_COROLLA:
|
||||
elif self.CP.carFingerprint in (CAR.TOYOTA_COROLLA, CAR.TOYOTA_MATRIX_RETROFIT):
|
||||
pedal_scale = float(np.interp(CS.out.vEgo, [0.0, MIN_ACC_SPEED, MIN_ACC_SPEED + PEDAL_TRANSITION], [0.3, 0.4, 0.0]))
|
||||
else:
|
||||
pedal_scale = float(np.interp(CS.out.vEgo, [0.0, MIN_ACC_SPEED, MIN_ACC_SPEED + PEDAL_TRANSITION], [0.4, 0.5, 0.0]))
|
||||
@@ -237,6 +249,27 @@ class CarController(CarControllerBase):
|
||||
|
||||
self.last_standstill = CS.out.standstill
|
||||
|
||||
def create_auto_brake_hold_messages(self, CS: structs.CarState, brake_hold_allowed_timer: int = 100):
|
||||
can_sends = []
|
||||
brake_hold_allowed = (CS.out.standstill and CS.out.cruiseState.available and
|
||||
not CS.out.gasPressed and not CS.out.cruiseState.enabled and
|
||||
CS.out.gearShifter not in (PARK, REVERSE))
|
||||
|
||||
if brake_hold_allowed:
|
||||
self._brake_hold_counter += 1
|
||||
self.brake_hold_active = self._brake_hold_counter > brake_hold_allowed_timer and not self._brake_hold_reset
|
||||
self._brake_hold_reset = not self._prev_brake_pressed and CS.out.brakePressed and not self._brake_hold_reset
|
||||
else:
|
||||
self._brake_hold_counter = 0
|
||||
self.brake_hold_active = False
|
||||
self._brake_hold_reset = False
|
||||
self._prev_brake_pressed = CS.out.brakePressed
|
||||
|
||||
if self.frame % 2 == 0:
|
||||
can_sends.append(toyotacan.create_brake_hold_command(self.packer, self.frame, CS.pre_collision_2, self.brake_hold_active))
|
||||
|
||||
return can_sends
|
||||
|
||||
def update(self, CC, CS, now_nanos, starpilot_toggles):
|
||||
actuators = CC.actuators
|
||||
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||
@@ -330,6 +363,9 @@ class CarController(CarControllerBase):
|
||||
# *** gas and brake ***
|
||||
|
||||
self._update_standstill_request(CC, CS, actuators, starpilot_toggles)
|
||||
if self.auto_brake_hold:
|
||||
can_sends.extend(self.create_auto_brake_hold_messages(CS))
|
||||
|
||||
interceptor_gas_cmd = self._compute_interceptor_gas_cmd(CC, CS)
|
||||
|
||||
# handle UI messages
|
||||
@@ -405,9 +441,8 @@ class CarController(CarControllerBase):
|
||||
|
||||
feedforward = pcm_accel_cmd
|
||||
if self.CP.carFingerprint == CAR.TOYOTA_PRIUS:
|
||||
# Keep Prius positive handoffs softer than the stock tune, while restoring some launch authority.
|
||||
if feedforward > 0.0:
|
||||
feedforward *= PRIUS_POSITIVE_FEEDFORWARD_SCALE
|
||||
feedforward *= get_prius_positive_feedforward_scale(CS.out.vEgo)
|
||||
|
||||
pcm_accel_cmd = self.long_pid.update(error_future,
|
||||
speed=CS.out.vEgo,
|
||||
|
||||
@@ -80,6 +80,8 @@ class CarState(CarStateBase):
|
||||
self.has_can_filter = self.FPCP.flags & ToyotaStarPilotFlags.RADAR_CAN_FILTER.value
|
||||
self.has_SDSU = self.FPCP.flags & ToyotaStarPilotFlags.SMART_DSU.value
|
||||
self.has_ZSS = self.FPCP.flags & ToyotaStarPilotFlags.ZSS.value
|
||||
self.auto_brake_hold = bool(self.CP.flags & ToyotaFlags.AUTO_BRAKE_HOLD.value)
|
||||
self.pre_collision_2 = {}
|
||||
|
||||
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
|
||||
cp = can_parsers[Bus.pt]
|
||||
@@ -211,6 +213,9 @@ class CarState(CarStateBase):
|
||||
if self.CP.carFingerprint != CAR.TOYOTA_PRIUS_V:
|
||||
self.lkas_hud = copy.copy(cp_cam.vl["LKAS_HUD"])
|
||||
|
||||
if self.auto_brake_hold:
|
||||
self.pre_collision_2 = copy.copy(cp_cam.vl["PRE_COLLISION_2"])
|
||||
|
||||
if self.CP.carFingerprint not in UNSUPPORTED_DSU_CAR:
|
||||
self.pcm_follow_distance = cp.vl["PCM_CRUISE_2"]["PCM_FOLLOW_DISTANCE"]
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@ from opendbc.car.toyota.values import CAR
|
||||
|
||||
Ecu = CarParams.Ecu
|
||||
|
||||
FINGERPRINTS = {
|
||||
CAR.TOYOTA_MATRIX_RETROFIT: [{}],
|
||||
}
|
||||
|
||||
FW_VERSIONS = {
|
||||
CAR.TOYOTA_AVALON: {
|
||||
(Ecu.abs, 0x7b0, None): [
|
||||
|
||||
@@ -2,11 +2,13 @@ from opendbc.car import Bus, structs, get_safety_config, uds
|
||||
from opendbc.car.toyota.carstate import CarState
|
||||
from opendbc.car.toyota.carcontroller import CarController
|
||||
from opendbc.car.toyota.radar_interface import RadarInterface
|
||||
from opendbc.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \
|
||||
from opendbc.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, SECOC_CAR, NO_DSU_CAR, \
|
||||
MIN_ACC_SPEED, EPS_SCALE, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR, \
|
||||
ToyotaSafetyFlags
|
||||
from opendbc.car.disable_ecu import disable_ecu
|
||||
from opendbc.car.interfaces import CarInterfaceBase
|
||||
from opendbc.safety import ALTERNATIVE_EXPERIENCE
|
||||
from openpilot.common.params import Params
|
||||
|
||||
SteerControlType = structs.CarParams.SteerControlType
|
||||
|
||||
@@ -66,10 +68,11 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
if candidate == CAR.TOYOTA_PRIUS:
|
||||
stop_and_go = True
|
||||
ret.flags |= ToyotaFlags.HYBRID.value
|
||||
# Only give steer angle deadzone to for bad angle sensor prius
|
||||
for fw in car_fw:
|
||||
if fw.ecu == "eps" and not fw.fwVersion == b'8965B47060\x00\x00\x00\x00\x00\x00':
|
||||
ret.steerActuatorDelay = 0.25
|
||||
ret.steerActuatorDelay = 0.14
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg=0.3)
|
||||
|
||||
elif candidate in (CAR.LEXUS_RX, CAR.LEXUS_RX_TSS2):
|
||||
@@ -137,6 +140,13 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
ret.autoResumeSng = ret.openpilotLongitudinalControl and candidate in NO_STOP_TIMER_CAR
|
||||
ret.enableGasInterceptorDEPRECATED = 0x201 in fingerprint[0] and ret.openpilotLongitudinalControl
|
||||
if ret.enableGasInterceptorDEPRECATED:
|
||||
ret.safetyConfigs[0].safetyParam |= ToyotaSafetyFlags.GAS_INTERCEPTOR.value
|
||||
|
||||
toyota_auto_hold = Params(return_defaults=True).get_bool("ToyotaAutoHold")
|
||||
if toyota_auto_hold and candidate in (TSS2_CAR - RADAR_ACC_CAR - SECOC_CAR):
|
||||
ret.alternativeExperience |= ALTERNATIVE_EXPERIENCE.ALLOW_AEB
|
||||
ret.flags |= ToyotaFlags.AUTO_BRAKE_HOLD.value
|
||||
|
||||
if not ret.openpilotLongitudinalControl:
|
||||
ret.safetyConfigs[0].safetyParam |= ToyotaSafetyFlags.STOCK_LONGITUDINAL.value
|
||||
@@ -145,7 +155,9 @@ class CarInterface(CarInterfaceBase):
|
||||
# to a negative value, so it won't matter.
|
||||
ret.minEnableSpeed = -1. if (stop_and_go or ret.enableGasInterceptorDEPRECATED) else MIN_ACC_SPEED
|
||||
|
||||
if candidate in TSS2_CAR or ret.enableGasInterceptorDEPRECATED:
|
||||
prius_long_defaults = candidate == CAR.TOYOTA_PRIUS and ret.openpilotLongitudinalControl
|
||||
|
||||
if candidate in TSS2_CAR or ret.enableGasInterceptorDEPRECATED or prius_long_defaults:
|
||||
ret.flags |= ToyotaFlags.RAISED_ACCEL_LIMIT.value
|
||||
|
||||
ret.vEgoStopping = 0.25
|
||||
|
||||
@@ -2,19 +2,21 @@ from types import SimpleNamespace
|
||||
|
||||
from hypothesis import given, settings, strategies as st
|
||||
|
||||
from opendbc.car import Bus
|
||||
from opendbc.car import Bus, structs
|
||||
from opendbc.can import CANPacker, CANParser
|
||||
from opendbc.car.structs import CarParams
|
||||
from opendbc.car.fw_versions import build_fw_dict
|
||||
from opendbc.car.toyota import toyotacan
|
||||
from opendbc.car.toyota.carcontroller import CarController, limit_interceptor_pcm_accel, limit_interceptor_stopping_accel, \
|
||||
limit_prius_stopping_accel, update_permit_braking
|
||||
from opendbc.car.toyota.carcontroller import CarController, get_prius_positive_feedforward_scale, limit_interceptor_pcm_accel, \
|
||||
limit_interceptor_stopping_accel, limit_prius_stopping_accel, update_permit_braking
|
||||
from opendbc.car.toyota.carstate import calculate_interceptor_gas_pressed
|
||||
from opendbc.car.toyota.fingerprints import FW_VERSIONS
|
||||
from opendbc.car.toyota.interface import CarInterface
|
||||
from opendbc.car.toyota.values import CAR, DBC, TSS2_CAR, ANGLE_CONTROL_CAR, RADAR_ACC_CAR, SECOC_CAR, \
|
||||
FW_QUERY_CONFIG, PLATFORM_CODE_ECUS, FUZZY_EXCLUDED_PLATFORMS, \
|
||||
get_platform_codes
|
||||
ToyotaFlags, ToyotaSafetyFlags, get_platform_codes
|
||||
from opendbc.safety import ALTERNATIVE_EXPERIENCE
|
||||
from openpilot.common.params import Params
|
||||
|
||||
Ecu = CarParams.Ecu
|
||||
|
||||
@@ -40,6 +42,43 @@ class TestToyotaInterfaces:
|
||||
if car_model in TSS2_CAR and car_model not in SECOC_CAR:
|
||||
assert dbc[Bus.pt] == "toyota_nodsu_pt_generated"
|
||||
|
||||
def test_auto_hold_sets_flag_on_supported_tss2(self):
|
||||
params = Params()
|
||||
try:
|
||||
params.put_bool("ToyotaAutoHold", True)
|
||||
car_params = CarInterface.get_params(
|
||||
CAR.TOYOTA_CAMRY_TSS2,
|
||||
{bus: {} for bus in range(8)},
|
||||
[],
|
||||
alpha_long=False,
|
||||
is_release=False,
|
||||
docs=False,
|
||||
starpilot_toggles=SimpleNamespace(),
|
||||
)
|
||||
finally:
|
||||
params.remove("ToyotaAutoHold")
|
||||
|
||||
assert car_params.flags & ToyotaFlags.AUTO_BRAKE_HOLD.value
|
||||
assert car_params.alternativeExperience & ALTERNATIVE_EXPERIENCE.ALLOW_AEB
|
||||
|
||||
def test_prius_openpilot_long_uses_hybrid_long_defaults(self):
|
||||
car_params = CarInterface.get_params(
|
||||
CAR.TOYOTA_PRIUS,
|
||||
{0: {0x2FF: 8}},
|
||||
[],
|
||||
alpha_long=False,
|
||||
is_release=False,
|
||||
docs=False,
|
||||
starpilot_toggles=SimpleNamespace(),
|
||||
)
|
||||
|
||||
assert car_params.openpilotLongitudinalControl
|
||||
assert car_params.flags & ToyotaFlags.HYBRID.value
|
||||
assert car_params.flags & ToyotaFlags.RAISED_ACCEL_LIMIT.value
|
||||
assert abs(car_params.longitudinalActuatorDelay - 0.05) < 1e-6
|
||||
assert abs(car_params.vEgoStopping - 0.25) < 1e-6
|
||||
assert abs(car_params.vEgoStarting - 0.25) < 1e-6
|
||||
|
||||
def test_essential_ecus(self, subtests):
|
||||
# Asserts standard ECUs exist for each platform
|
||||
common_ecus = {Ecu.fwdRadar, Ecu.fwdCamera}
|
||||
@@ -261,6 +300,14 @@ class TestToyotaCarController:
|
||||
limited = limit_prius_stopping_accel(-3.28, -2.0, True, 0.0, True)
|
||||
assert limited == -3.28
|
||||
|
||||
def test_prius_positive_feedforward_scale_stays_soft_at_launch_speed(self):
|
||||
assert abs(get_prius_positive_feedforward_scale(0.0) - 0.7) < 1e-6
|
||||
assert abs(get_prius_positive_feedforward_scale(8.0) - 0.7) < 1e-6
|
||||
|
||||
def test_prius_positive_feedforward_scale_restores_cruise_authority(self):
|
||||
assert get_prius_positive_feedforward_scale(20.0) > get_prius_positive_feedforward_scale(8.0)
|
||||
assert abs(get_prius_positive_feedforward_scale(20.0) - 0.85) < 1e-6
|
||||
|
||||
def test_sng_hack_clears_existing_standstill_latch(self):
|
||||
controller = self._make_controller(standstill_req=True, last_standstill=True)
|
||||
|
||||
@@ -297,6 +344,33 @@ class TestToyotaCarController:
|
||||
assert parser.vl["LKAS_HUD"]["LEFT_LINE"] == 0
|
||||
assert parser.vl["LKAS_HUD"]["RIGHT_LINE"] == 0
|
||||
|
||||
def test_auto_brake_hold_sends_modified_pre_collision_after_timer(self):
|
||||
controller = self._make_controller()
|
||||
controller.packer = CANPacker(DBC[CAR.TOYOTA_CAMRY_TSS2][Bus.pt])
|
||||
controller.frame = 0
|
||||
controller.brake_hold_active = False
|
||||
controller._brake_hold_counter = 0
|
||||
controller._brake_hold_reset = False
|
||||
controller._prev_brake_pressed = False
|
||||
cs = SimpleNamespace(
|
||||
out=SimpleNamespace(
|
||||
standstill=True,
|
||||
cruiseState=SimpleNamespace(available=True, enabled=False),
|
||||
gasPressed=False,
|
||||
brakePressed=False,
|
||||
gearShifter=structs.CarState.GearShifter.drive,
|
||||
),
|
||||
pre_collision_2={},
|
||||
)
|
||||
|
||||
can_sends = controller.create_auto_brake_hold_messages(cs, brake_hold_allowed_timer=0)
|
||||
|
||||
parser = CANParser(DBC[CAR.TOYOTA_CAMRY_TSS2][Bus.pt], [("PRE_COLLISION_2", 0)], 0)
|
||||
parser.update([(1, can_sends)])
|
||||
assert controller.brake_hold_active
|
||||
assert parser.vl["PRE_COLLISION_2"]["DSS1GDRV"] == -1.0
|
||||
assert parser.vl["PRE_COLLISION_2"]["PBRTRGR"] == 1
|
||||
|
||||
def test_interceptor_stop_and_go_holds_small_launch_at_standstill(self):
|
||||
controller = self._make_controller()
|
||||
controller.CP.enableGasInterceptorDEPRECATED = True
|
||||
@@ -323,6 +397,20 @@ class TestToyotaCarController:
|
||||
|
||||
assert 0.0 < gas_cmd <= 0.5
|
||||
|
||||
def test_interceptor_corolla_scales_with_accel_request_when_pedal_enables_sng(self):
|
||||
controller = self._make_controller()
|
||||
controller.CP.enableGasInterceptorDEPRECATED = True
|
||||
controller.CP.carFingerprint = CAR.TOYOTA_COROLLA
|
||||
controller.CP.minEnableSpeed = -1.0
|
||||
controller.accel = 0.8
|
||||
|
||||
gas_cmd = controller._compute_interceptor_gas_cmd(
|
||||
SimpleNamespace(longActive=True),
|
||||
SimpleNamespace(out=SimpleNamespace(standstill=False, vEgo=8.0)),
|
||||
)
|
||||
|
||||
assert 0.0 < gas_cmd <= 0.5
|
||||
|
||||
def test_interceptor_disabled_returns_zero(self):
|
||||
controller = self._make_controller()
|
||||
controller.accel = 1.0
|
||||
@@ -401,6 +489,7 @@ class TestToyotaCarController:
|
||||
)
|
||||
|
||||
assert CP.enableGasInterceptorDEPRECATED
|
||||
assert CP.safetyConfigs[0].safetyParam & ToyotaSafetyFlags.GAS_INTERCEPTOR
|
||||
assert abs(CP.longitudinalActuatorDelay - 0.2) < 1e-6
|
||||
assert CP.stopAccel == -1.5
|
||||
|
||||
|
||||
@@ -86,6 +86,38 @@ def create_pcs_commands(packer, accel, active, mass):
|
||||
return [msg1, msg2]
|
||||
|
||||
|
||||
def create_brake_hold_command(packer, frame, pre_collision_2, brake_hold_active):
|
||||
values = {s: pre_collision_2[s] for s in [
|
||||
"DSS1GDRV",
|
||||
"DS1STAT2",
|
||||
"DS1STBK2",
|
||||
"PCSWAR",
|
||||
"PCSALM",
|
||||
"PCSOPR",
|
||||
"PCSABK",
|
||||
"PBATRGR",
|
||||
"PPTRGR",
|
||||
"IBTRGR",
|
||||
"CLEXTRGR",
|
||||
"IRLT_REQ",
|
||||
"BRKHLD",
|
||||
"AVSTRGR",
|
||||
"VGRSTRGR",
|
||||
"PREFILL",
|
||||
"PBRTRGR",
|
||||
"PCSDIS",
|
||||
"PBPREPMP",
|
||||
] if s in pre_collision_2}
|
||||
|
||||
if brake_hold_active:
|
||||
values = {
|
||||
"DSS1GDRV": 0x3FF,
|
||||
"PBRTRGR": frame % 730 < 727,
|
||||
}
|
||||
|
||||
return packer.make_can_msg("PRE_COLLISION_2", 0, values)
|
||||
|
||||
|
||||
def create_acc_cancel_command(packer):
|
||||
values = {
|
||||
"GAS_RELEASED": 0,
|
||||
|
||||
@@ -57,6 +57,7 @@ class ToyotaSafetyFlags(IntFlag):
|
||||
LTA = (4 << 8)
|
||||
SECOC = (8 << 8)
|
||||
LONG_FILTER = (16 << 8)
|
||||
GAS_INTERCEPTOR = (32 << 8)
|
||||
|
||||
|
||||
class ToyotaFlags(IntFlag):
|
||||
@@ -75,6 +76,7 @@ class ToyotaFlags(IntFlag):
|
||||
# these cars can utilize 2.0 m/s^2
|
||||
RAISED_ACCEL_LIMIT = 1024
|
||||
SECOC = 2048
|
||||
AUTO_BRAKE_HOLD = 4096
|
||||
|
||||
# deprecated flags
|
||||
# these cars are speculated to allow stop and go when the DSU is unplugged
|
||||
@@ -201,6 +203,11 @@ class CAR(Platforms):
|
||||
CarSpecs(mass=2860. * CV.LB_TO_KG, wheelbase=2.7, steerRatio=18.27, tireStiffnessFactor=0.444),
|
||||
dbc_dict('toyota_new_mc_pt_generated', 'toyota_adas'),
|
||||
)
|
||||
TOYOTA_MATRIX_RETROFIT = PlatformConfig(
|
||||
[ToyotaCommunityCarDocs("Toyota Matrix 2005 Retrofit", package="Custom retrofit")],
|
||||
TOYOTA_COROLLA.specs,
|
||||
dbc_dict('toyota_new_mc_pt_generated', 'toyota_adas'),
|
||||
)
|
||||
# LSS2 Lexus UX Hybrid is same as a TSS2 Corolla Hybrid
|
||||
TOYOTA_COROLLA_TSS2 = ToyotaTSS2PlatformConfig(
|
||||
[
|
||||
@@ -548,7 +555,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
],
|
||||
non_essential_ecus={
|
||||
# FIXME: On some models, abs can sometimes be missing
|
||||
Ecu.abs: [CAR.TOYOTA_RAV4, CAR.TOYOTA_COROLLA, CAR.TOYOTA_HIGHLANDER, CAR.TOYOTA_SIENNA, CAR.LEXUS_IS, CAR.TOYOTA_ALPHARD_TSS2],
|
||||
Ecu.abs: [CAR.TOYOTA_RAV4, CAR.TOYOTA_COROLLA, CAR.TOYOTA_MATRIX_RETROFIT, CAR.TOYOTA_HIGHLANDER, CAR.TOYOTA_SIENNA, CAR.LEXUS_IS, CAR.TOYOTA_ALPHARD_TSS2],
|
||||
# On some models, the engine can show on two different addresses
|
||||
Ecu.engine: [CAR.TOYOTA_HIGHLANDER, CAR.TOYOTA_CAMRY, CAR.TOYOTA_COROLLA_TSS2, CAR.TOYOTA_CHR, CAR.TOYOTA_CHR_TSS2, CAR.LEXUS_IS,
|
||||
CAR.LEXUS_IS_TSS2, CAR.LEXUS_RC, CAR.LEXUS_NX, CAR.LEXUS_NX_TSS2, CAR.LEXUS_RX, CAR.LEXUS_RX_TSS2],
|
||||
@@ -589,7 +596,8 @@ STEER_THRESHOLD = 100
|
||||
|
||||
# These cars have non-standard EPS torque scale factors. All others are 73
|
||||
EPS_SCALE = defaultdict(lambda: 73,
|
||||
{CAR.TOYOTA_PRIUS: 66, CAR.TOYOTA_COROLLA: 88, CAR.LEXUS_IS: 77, CAR.LEXUS_RC: 77, CAR.LEXUS_CTH: 100, CAR.TOYOTA_PRIUS_V: 100})
|
||||
{CAR.TOYOTA_PRIUS: 66, CAR.TOYOTA_COROLLA: 88, CAR.TOYOTA_MATRIX_RETROFIT: 88,
|
||||
CAR.LEXUS_IS: 77, CAR.LEXUS_RC: 77, CAR.LEXUS_CTH: 100, CAR.TOYOTA_PRIUS_V: 100})
|
||||
|
||||
# Toyota/Lexus Safety Sense 2.0 and 2.5
|
||||
TSS2_CAR = CAR.with_flags(ToyotaFlags.TSS2)
|
||||
|
||||
@@ -62,6 +62,12 @@ VAL_TABLE_ HandsOffSWDetectionMode 2 "Failed" 1 "Enabled" 0 "Disabled" ;
|
||||
|
||||
BO_ 189 EBCMRegenPaddle: 7 K17_EBCM
|
||||
SG_ RegenPaddle : 7|4@0+ (1,0) [0|0] "" NEO
|
||||
SG_ Byte1 : 15|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte2 : 23|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte3 : 31|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte4 : 39|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte5 : 47|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte6 : 55|8@0+ (1,0) [0|255] "" NEO
|
||||
|
||||
BO_ 190 ECMAcceleratorPos: 6 K20_ECM
|
||||
SG_ BrakePedalPos : 15|8@0+ (1,0) [0|0] "sticky" NEO
|
||||
@@ -146,6 +152,7 @@ BO_ 481 ASCMSteeringButton: 7 K124_ASCM
|
||||
SG_ LKAButton : 23|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ ACCAlwaysOne : 24|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ ACCButtons : 46|3@0+ (1,0) [0|0] "" NEO
|
||||
SG_ ACCButtonsHard : 26|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ DriveModeButton : 39|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ RollingCounter : 33|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ SteeringButtonChecksum : 43|12@0+ (1,0) [0|255] "" NEO
|
||||
@@ -173,9 +180,14 @@ BO_ 500 SportMode: 6 XXX
|
||||
SG_ SportMode : 15|1@0+ (1,0) [0|1] "" XXX
|
||||
|
||||
BO_ 501 ECMPRDNL2: 8 K20_ECM
|
||||
SG_ Byte0 : 7|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte1 : 15|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte2 : 23|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ TransmissionState : 48|4@1+ (1,0) [0|7] "" NEO
|
||||
SG_ PRNDL2 : 27|4@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte4 : 39|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ ManualMode : 41|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ Byte7 : 63|8@0+ (1,0) [0|255] "" NEO
|
||||
|
||||
BO_ 532 BRAKE_RELATED: 6 XXX
|
||||
SG_ UserBrakePressure : 0|9@0+ (1,0) [0|511] "" XXX
|
||||
|
||||
@@ -37,11 +37,24 @@ BO_ 740 STEERING_LKA: 5 XXX
|
||||
|
||||
BO_ 836 PRE_COLLISION_2: 8 DSU
|
||||
SG_ DSS1GDRV : 7|10@0- (0.1,0) [0|0] "m/s^2" Vector__XXX
|
||||
SG_ DS1STAT2 : 13|3@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ DS1STBK2 : 10|3@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PCSWAR : 18|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ PCSALM : 17|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ PCSOPR : 16|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PCSABK : 31|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ IBTRGR : 27|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ PBATRGR : 30|2@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PPTRGR : 28|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ CLEXTRGR : 26|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ IRLT_REQ : 25|2@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ BRKHLD : 37|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PREFILL : 33|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ AVSTRGR : 36|1@0+ (1,0) [0|0] "" SCS
|
||||
SG_ VGRSTRGR : 35|2@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PBRTRGR : 32|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PCSDIS : 43|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PBPREPMP : 40|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ CHECKSUM : 63|8@0+ (1,0) [0|0] "" XXX
|
||||
|
||||
CM_ SG_ 466 NEUTRAL_FORCE "force in newtons the engine/electric motors are applying without any acceleration commands or user input";
|
||||
|
||||
@@ -82,6 +82,12 @@ VAL_TABLE_ HandsOffSWDetectionMode 2 "Failed" 1 "Enabled" 0 "Disabled" ;
|
||||
|
||||
BO_ 189 EBCMRegenPaddle: 7 K17_EBCM
|
||||
SG_ RegenPaddle : 7|4@0+ (1,0) [0|0] "" NEO
|
||||
SG_ Byte1 : 15|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte2 : 23|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte3 : 31|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte4 : 39|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte5 : 47|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte6 : 55|8@0+ (1,0) [0|255] "" NEO
|
||||
|
||||
BO_ 190 ECMAcceleratorPos: 6 K20_ECM
|
||||
SG_ BrakePedalPos : 15|8@0+ (1,0) [0|0] "sticky" NEO
|
||||
@@ -166,6 +172,7 @@ BO_ 481 ASCMSteeringButton: 7 K124_ASCM
|
||||
SG_ LKAButton : 23|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ ACCAlwaysOne : 24|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ ACCButtons : 46|3@0+ (1,0) [0|0] "" NEO
|
||||
SG_ ACCButtonsHard : 26|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ DriveModeButton : 39|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ RollingCounter : 33|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ SteeringButtonChecksum : 43|12@0+ (1,0) [0|255] "" NEO
|
||||
@@ -193,9 +200,14 @@ BO_ 500 SportMode: 6 XXX
|
||||
SG_ SportMode : 15|1@0+ (1,0) [0|1] "" XXX
|
||||
|
||||
BO_ 501 ECMPRDNL2: 8 K20_ECM
|
||||
SG_ Byte0 : 7|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte1 : 15|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte2 : 23|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ TransmissionState : 48|4@1+ (1,0) [0|7] "" NEO
|
||||
SG_ PRNDL2 : 27|4@0+ (1,0) [0|255] "" NEO
|
||||
SG_ Byte4 : 39|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ ManualMode : 41|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ Byte7 : 63|8@0+ (1,0) [0|255] "" NEO
|
||||
|
||||
BO_ 532 BRAKE_RELATED: 6 XXX
|
||||
SG_ UserBrakePressure : 0|9@0+ (1,0) [0|511] "" XXX
|
||||
|
||||
@@ -650,11 +650,24 @@ BO_ 740 STEERING_LKA: 5 XXX
|
||||
|
||||
BO_ 836 PRE_COLLISION_2: 8 DSU
|
||||
SG_ DSS1GDRV : 7|10@0- (0.1,0) [0|0] "m/s^2" Vector__XXX
|
||||
SG_ DS1STAT2 : 13|3@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ DS1STBK2 : 10|3@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PCSWAR : 18|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ PCSALM : 17|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ PCSOPR : 16|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PCSABK : 31|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ IBTRGR : 27|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ PBATRGR : 30|2@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PPTRGR : 28|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ CLEXTRGR : 26|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ IRLT_REQ : 25|2@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ BRKHLD : 37|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PREFILL : 33|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ AVSTRGR : 36|1@0+ (1,0) [0|0] "" SCS
|
||||
SG_ VGRSTRGR : 35|2@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PBRTRGR : 32|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PCSDIS : 43|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PBPREPMP : 40|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ CHECKSUM : 63|8@0+ (1,0) [0|0] "" XXX
|
||||
|
||||
CM_ SG_ 466 NEUTRAL_FORCE "force in newtons the engine/electric motors are applying without any acceleration commands or user input";
|
||||
|
||||
@@ -650,11 +650,24 @@ BO_ 740 STEERING_LKA: 5 XXX
|
||||
|
||||
BO_ 836 PRE_COLLISION_2: 8 DSU
|
||||
SG_ DSS1GDRV : 7|10@0- (0.1,0) [0|0] "m/s^2" Vector__XXX
|
||||
SG_ DS1STAT2 : 13|3@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ DS1STBK2 : 10|3@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PCSWAR : 18|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ PCSALM : 17|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ PCSOPR : 16|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PCSABK : 31|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ IBTRGR : 27|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ PBATRGR : 30|2@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PPTRGR : 28|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ CLEXTRGR : 26|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ IRLT_REQ : 25|2@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ BRKHLD : 37|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PREFILL : 33|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ AVSTRGR : 36|1@0+ (1,0) [0|0] "" SCS
|
||||
SG_ VGRSTRGR : 35|2@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PBRTRGR : 32|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PCSDIS : 43|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PBPREPMP : 40|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ CHECKSUM : 63|8@0+ (1,0) [0|0] "" XXX
|
||||
|
||||
CM_ SG_ 466 NEUTRAL_FORCE "force in newtons the engine/electric motors are applying without any acceleration commands or user input";
|
||||
|
||||
@@ -650,11 +650,24 @@ BO_ 740 STEERING_LKA: 5 XXX
|
||||
|
||||
BO_ 836 PRE_COLLISION_2: 8 DSU
|
||||
SG_ DSS1GDRV : 7|10@0- (0.1,0) [0|0] "m/s^2" Vector__XXX
|
||||
SG_ DS1STAT2 : 13|3@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ DS1STBK2 : 10|3@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PCSWAR : 18|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ PCSALM : 17|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ PCSOPR : 16|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PCSABK : 31|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ IBTRGR : 27|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ PBATRGR : 30|2@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PPTRGR : 28|1@0+ (1,0) [0|0] "" FCM
|
||||
SG_ CLEXTRGR : 26|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ IRLT_REQ : 25|2@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ BRKHLD : 37|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PREFILL : 33|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ AVSTRGR : 36|1@0+ (1,0) [0|0] "" SCS
|
||||
SG_ VGRSTRGR : 35|2@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PBRTRGR : 32|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PCSDIS : 43|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ PBPREPMP : 40|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ CHECKSUM : 63|8@0+ (1,0) [0|0] "" XXX
|
||||
|
||||
CM_ SG_ 466 NEUTRAL_FORCE "force in newtons the engine/electric motors are applying without any acceleration commands or user input";
|
||||
|
||||
@@ -61,6 +61,7 @@ static bool gm_panda_paddle_sched = false;
|
||||
static bool gm_bolt_2022_pedal = false;
|
||||
static bool gm_alt_brake = false;
|
||||
static bool gm_volt_auto_hold = false;
|
||||
static bool gm_volt_one_pedal = false;
|
||||
|
||||
static bool gm_cc_long = false;
|
||||
static bool gm_has_acc = true;
|
||||
@@ -365,9 +366,10 @@ static bool gm_tx_hook(const CANPacket_t *msg) {
|
||||
if (msg->addr == 0x315U) {
|
||||
int brake = ((msg->data[0] & 0xFU) << 8) + msg->data[1];
|
||||
brake = (0x1000 - brake) & 0xFFF;
|
||||
bool stock_auto_hold_brake_allowed = gm_volt_auto_hold && !vehicle_moving && !gas_pressed_prev;
|
||||
bool stock_auto_hold_brake_allowed = gm_volt_auto_hold && acc_main_on && !vehicle_moving && !gas_pressed_prev;
|
||||
bool stock_one_pedal_brake_allowed = gm_volt_one_pedal && acc_main_on && !gas_pressed_prev && !brake_pressed;
|
||||
bool violation = false;
|
||||
violation |= !(get_longitudinal_allowed() || stock_auto_hold_brake_allowed) && (brake != 0);
|
||||
violation |= !(get_longitudinal_allowed() || stock_auto_hold_brake_allowed || stock_one_pedal_brake_allowed) && (brake != 0);
|
||||
if (stock_auto_hold_brake_allowed && !get_longitudinal_allowed()) {
|
||||
violation |= brake > GM_VOLT_AUTO_HOLD_MAX_BRAKE;
|
||||
} else {
|
||||
@@ -612,6 +614,11 @@ static safety_config gm_init(uint16_t param) {
|
||||
{0x200, 0, 6, .check_relay = false},
|
||||
{0x1E1, 0, 7, .check_relay = false},
|
||||
{0xBD, 0, 7, .check_relay = false}, {0x1F5, 0, 8, .check_relay = false}}; // pt bus
|
||||
static const CanMsg GM_CAM_BOLT_2022_PEDAL_FRICTION_TX_MSGS[] = {{0x180, 0, 4, .check_relay = true}, {0x370, 0, 6, .check_relay = false}, {0x3D1, 0, 8, .check_relay = false}, {0x315, 0, 5, .check_relay = true}, // pt bus
|
||||
{0x1E1, 2, 7, .check_relay = false}, {0x184, 2, 8, .check_relay = true}, // camera bus
|
||||
{0x200, 0, 6, .check_relay = false},
|
||||
{0x1E1, 0, 7, .check_relay = false},
|
||||
{0xBD, 0, 7, .check_relay = false}, {0x1F5, 0, 8, .check_relay = false}}; // pt bus
|
||||
static const CanMsg GM_CAM_VOLT_AUTO_HOLD_TX_MSGS[] = {{0x180, 0, 4, .check_relay = true}, {0x370, 0, 6, .check_relay = false}, {0x3D1, 0, 8, .check_relay = false}, {0x315, 0, 5, .check_relay = true}, // pt bus
|
||||
{0x1E1, 2, 7, .check_relay = false}, {0x184, 2, 8, .check_relay = true}, // camera bus
|
||||
{0x200, 0, 6, .check_relay = false},
|
||||
@@ -635,6 +642,12 @@ static safety_config gm_init(uint16_t param) {
|
||||
{0x200, 0, 6, .check_relay = false},
|
||||
{0x1E1, 0, 7, .check_relay = false},
|
||||
{0xBD, 0, 7, .check_relay = false}, {0x1F5, 0, 8, .check_relay = false}}; // pt bus
|
||||
static const CanMsg GM_CAM_NO_CAMERA_BOLT_2022_PEDAL_FRICTION_TX_MSGS[] = {{0x180, 0, 4, .check_relay = false}, {0x370, 0, 6, .check_relay = false}, {0x3D1, 0, 8, .check_relay = false}, {0x315, 0, 5, .check_relay = false}, // pt bus
|
||||
{0x409, 0, 7, .check_relay = false}, {0x40A, 0, 7, .check_relay = false},
|
||||
{0x1E1, 2, 7, .check_relay = false}, {0x184, 2, 8, .check_relay = false}, // camera bus
|
||||
{0x200, 0, 6, .check_relay = false},
|
||||
{0x1E1, 0, 7, .check_relay = false},
|
||||
{0xBD, 0, 7, .check_relay = false}, {0x1F5, 0, 8, .check_relay = false}}; // pt bus
|
||||
static const CanMsg GM_CAM_NO_CAMERA_VOLT_AUTO_HOLD_TX_MSGS[] = {{0x180, 0, 4, .check_relay = false}, {0x370, 0, 6, .check_relay = false}, {0x3D1, 0, 8, .check_relay = false}, {0x315, 0, 5, .check_relay = false}, // pt bus
|
||||
{0x409, 0, 7, .check_relay = false}, {0x40A, 0, 7, .check_relay = false},
|
||||
{0x1E1, 2, 7, .check_relay = false}, {0x184, 2, 8, .check_relay = false}, // camera bus
|
||||
@@ -699,6 +712,10 @@ static safety_config gm_init(uint16_t param) {
|
||||
gm_panda_paddle_sched = GET_FLAG(param, GM_PARAM_PANDA_PADDLE_SCHED) && gm_pedal_long && enable_gas_interceptor;
|
||||
// Reuse the paddle-scheduler bit as a stock-Volt auto-hold marker on non-pedal ACC paths.
|
||||
gm_volt_auto_hold = GET_FLAG(param, GM_PARAM_PANDA_PADDLE_SCHED) && !gm_pedal_long && !gm_cc_long && gm_has_acc;
|
||||
// Reuse the 3D1 scheduler bit as a stock-Volt one-pedal marker on non-pedal
|
||||
// ACC paths. The actual 3D1 scheduler still requires pedal-long and no-ACC,
|
||||
// so this stays isolated from the Bolt pedal path.
|
||||
gm_volt_one_pedal = GET_FLAG(param, GM_PARAM_PANDA_3D1_SCHED) && !gm_pedal_long && !gm_cc_long && gm_has_acc;
|
||||
gm_alt_brake = GET_FLAG(param, GM_PARAM_NO_CAMERA) && (gm_hw == GM_ASCM) && !gm_sdgm && !gm_ascm_int;
|
||||
|
||||
gm_3d1_spoof_valid = false;
|
||||
@@ -730,6 +747,11 @@ static safety_config gm_init(uint16_t param) {
|
||||
gm_pcm_cruise = (gm_hw == GM_CAM || gm_sdgm) && !gm_cam_long && !gm_force_ascm && !gm_pedal_long;
|
||||
const bool gm_ascm_int_stock_cam = gm_ascm_int && (gm_hw == GM_CAM) && gm_pcm_cruise && !gm_cam_long && !gm_pedal_long && !gm_cc_long;
|
||||
const bool gm_ascm_int_no_accel_pos = gm_ascm_int && (gm_hw == GM_CAM) && gm_force_brake_c9;
|
||||
// FLAG_GM_BOLT_2022_PEDAL is shared with Malibu Hybrid pedal-long. Requiring
|
||||
// the paddle scheduler bit narrows this whitelist to the Gen2 Bolt pedal-long
|
||||
// experiment, which is the only path that should probe chassis friction brake
|
||||
// while stock ACC remains canceled.
|
||||
const bool gm_bolt_2022_pedal_friction = gm_bolt_2022_pedal && gm_panda_paddle_sched && !gm_has_acc;
|
||||
gm_steer_limits = GET_FLAG(param, GM_PARAM_BOLT_2017) ? &GM_BOLT_2017_STEERING_LIMITS : &GM_STEERING_LIMITS;
|
||||
|
||||
if ((gm_hw == GM_ASCM && !gm_sdgm) || gm_ascm_int || gm_force_ascm) {
|
||||
@@ -740,9 +762,10 @@ static safety_config gm_init(uint16_t param) {
|
||||
|
||||
safety_config ret;
|
||||
const bool gm_sdgm_stock = gm_sdgm && !gm_cc_long && !gm_cam_long && !gm_no_camera;
|
||||
const bool gm_volt_stock_brake = gm_volt_auto_hold || gm_volt_one_pedal;
|
||||
// SDGM behaves like a forwarding camera path for whitelist/forwarding purposes.
|
||||
if (gm_sdgm_stock) {
|
||||
if (gm_volt_auto_hold) {
|
||||
if (gm_volt_stock_brake) {
|
||||
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_SDGM_VOLT_AUTO_HOLD_TX_MSGS);
|
||||
} else {
|
||||
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_SDGM_TX_MSGS);
|
||||
@@ -764,16 +787,22 @@ static safety_config gm_init(uint16_t param) {
|
||||
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_LONG_TX_MSGS);
|
||||
}
|
||||
} else {
|
||||
if (gm_volt_auto_hold && gm_sdgm) {
|
||||
if (gm_volt_stock_brake && gm_sdgm) {
|
||||
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_SDGM_VOLT_AUTO_HOLD_TX_MSGS);
|
||||
} else if (gm_no_camera) {
|
||||
if (gm_volt_auto_hold) {
|
||||
if (gm_bolt_2022_pedal_friction) {
|
||||
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_NO_CAMERA_BOLT_2022_PEDAL_FRICTION_TX_MSGS);
|
||||
} else if (gm_volt_stock_brake) {
|
||||
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_NO_CAMERA_VOLT_AUTO_HOLD_TX_MSGS);
|
||||
} else {
|
||||
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_NO_CAMERA_TX_MSGS);
|
||||
}
|
||||
} else {
|
||||
if (gm_volt_auto_hold) {
|
||||
if (gm_bolt_2022_pedal_friction) {
|
||||
// Experimental Gen2 Bolt pedal-long path: keep stock ACC canceled but
|
||||
// allow OP to probe chassis friction-brake acceptance through panda.
|
||||
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_BOLT_2022_PEDAL_FRICTION_TX_MSGS);
|
||||
} else if (gm_volt_stock_brake) {
|
||||
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_VOLT_AUTO_HOLD_TX_MSGS);
|
||||
} else {
|
||||
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_TX_MSGS);
|
||||
|
||||
@@ -70,6 +70,13 @@ static const CanMsg HYUNDAI_TX_MSGS[] = {
|
||||
HYUNDAI_COMMON_TX_MSGS(0)
|
||||
};
|
||||
|
||||
static const CanMsg HYUNDAI_LONG_TX_MSGS[] = {
|
||||
HYUNDAI_LONG_COMMON_TX_MSGS(0)
|
||||
{0x38D, 0, 8, .check_relay = false}, // FCA11 Bus 0
|
||||
{0x483, 0, 8, .check_relay = false}, // FCA12 Bus 0
|
||||
{0x7D0, 0, 8, .check_relay = false}, // radar UDS TX addr Bus 0 (for radar disable)
|
||||
};
|
||||
|
||||
static bool hyundai_legacy = false;
|
||||
|
||||
static uint8_t hyundai_get_counter(const CANPacket_t *msg) {
|
||||
@@ -322,13 +329,6 @@ static bool hyundai_tx_hook(const CANPacket_t *msg) {
|
||||
}
|
||||
|
||||
static safety_config hyundai_init(uint16_t param) {
|
||||
static const CanMsg HYUNDAI_LONG_TX_MSGS[] = {
|
||||
HYUNDAI_LONG_COMMON_TX_MSGS(0)
|
||||
{0x38D, 0, 8, .check_relay = false}, // FCA11 Bus 0
|
||||
{0x483, 0, 8, .check_relay = false}, // FCA12 Bus 0
|
||||
{0x7D0, 0, 8, .check_relay = false}, // radar UDS TX addr Bus 0 (for radar disable)
|
||||
};
|
||||
|
||||
static const CanMsg HYUNDAI_CAMERA_SCC_TX_MSGS[] = {
|
||||
HYUNDAI_COMMON_TX_MSGS(2)
|
||||
};
|
||||
@@ -556,9 +556,9 @@ static safety_config hyundai_legacy_init(uint16_t param) {
|
||||
|
||||
hyundai_common_init(param);
|
||||
hyundai_legacy = true;
|
||||
hyundai_longitudinal = false;
|
||||
hyundai_camera_scc = false;
|
||||
return BUILD_SAFETY_CFG(hyundai_legacy_rx_checks, HYUNDAI_TX_MSGS);
|
||||
return hyundai_longitudinal ? BUILD_SAFETY_CFG(hyundai_legacy_rx_checks, HYUNDAI_LONG_TX_MSGS) :
|
||||
BUILD_SAFETY_CFG(hyundai_legacy_rx_checks, HYUNDAI_TX_MSGS);
|
||||
}
|
||||
|
||||
const safety_hooks hyundai_hooks = {
|
||||
|
||||
@@ -221,7 +221,8 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
|
||||
}
|
||||
|
||||
// steering
|
||||
const unsigned int steer_addr = (hyundai_canfd_lka_steering && !hyundai_longitudinal) ? hyundai_canfd_get_lka_addr() : 0x12aU;
|
||||
const unsigned int steer_addr = (hyundai_canfd_lka_steering && (hyundai_canfd_angle_steering || !hyundai_longitudinal)) ?
|
||||
hyundai_canfd_get_lka_addr() : 0x12aU;
|
||||
if (msg->addr == steer_addr) {
|
||||
if (hyundai_canfd_angle_steering) {
|
||||
const int lkas_angle_active = (msg->data[9] >> 4U) & 0x3U;
|
||||
@@ -334,6 +335,21 @@ static safety_config hyundai_canfd_init(uint16_t param) {
|
||||
{0x1DA, 1, 32, .check_relay = false}, // ADRV_0x1da
|
||||
};
|
||||
|
||||
static const CanMsg HYUNDAI_CANFD_LKA_STEERING_ALT_LONG_TX_MSGS[] = {
|
||||
HYUNDAI_CANFD_LKA_STEERING_ALT_COMMON_TX_MSGS(0, 1)
|
||||
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(1)
|
||||
HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(1, true)
|
||||
HYUNDAI_CANFD_BLINDSPOT_DASH_TX_MSGS(1)
|
||||
{0x51, 0, 32, .check_relay = false}, // ADRV_0x51
|
||||
{0x100, 0, 24, .check_relay = false}, // ACCELERATOR_BRAKE_ALT radar heartbeat spoof
|
||||
{0x730, 1, 8, .check_relay = false}, // tester present for ADAS ECU disable
|
||||
{0x160, 1, 16, .check_relay = false}, // ADRV_0x160
|
||||
{0x1EA, 1, 32, .check_relay = false}, // ADRV_0x1ea
|
||||
{0x200, 1, 8, .check_relay = false}, // ADRV_0x200
|
||||
{0x345, 1, 8, .check_relay = false}, // ADRV_0x345
|
||||
{0x1DA, 1, 32, .check_relay = false}, // ADRV_0x1da
|
||||
};
|
||||
|
||||
static const CanMsg HYUNDAI_CANFD_LFA_STEERING_TX_MSGS[] = {
|
||||
HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(2)
|
||||
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(0)
|
||||
@@ -382,7 +398,11 @@ static safety_config hyundai_canfd_init(uint16_t param) {
|
||||
};
|
||||
|
||||
SET_RX_CHECKS(hyundai_canfd_lka_steering_long_rx_checks, ret);
|
||||
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS, ret);
|
||||
if (hyundai_canfd_lka_steering_alt) {
|
||||
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_ALT_LONG_TX_MSGS, ret);
|
||||
} else {
|
||||
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS, ret);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Longitudinal checks for LFA steering
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define MSG_SUBARU_Throttle 0x40U
|
||||
#define MSG_SUBARU_Steering_Torque 0x119U
|
||||
#define MSG_SUBARU_Wheel_Speeds 0x13aU
|
||||
#define MSG_SUBARU_Brake_Pedal 0x139U
|
||||
|
||||
#define MSG_SUBARU_ES_LKAS 0x122U
|
||||
#define MSG_SUBARU_ES_Brake 0x220U
|
||||
@@ -63,6 +64,10 @@
|
||||
{MSG_SUBARU_ES_STATIC_1, SUBARU_MAIN_BUS, 8, .check_relay = false}, \
|
||||
{MSG_SUBARU_ES_STATIC_2, SUBARU_MAIN_BUS, 8, .check_relay = false}, \
|
||||
|
||||
#define SUBARU_STOP_AND_GO_ADDITIONAL_TX_MSGS() \
|
||||
{MSG_SUBARU_Throttle, SUBARU_CAM_BUS, 8, .check_relay = true}, \
|
||||
{MSG_SUBARU_Brake_Pedal, SUBARU_CAM_BUS, 8, .check_relay = true}, \
|
||||
|
||||
#define SUBARU_COMMON_RX_CHECKS(alt_bus) \
|
||||
{.msg = {{MSG_SUBARU_Throttle, SUBARU_MAIN_BUS, 8, 100U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{MSG_SUBARU_Steering_Torque, SUBARU_MAIN_BUS, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
@@ -72,6 +77,7 @@
|
||||
|
||||
static bool subaru_gen2 = false;
|
||||
static bool subaru_longitudinal = false;
|
||||
static bool subaru_stop_and_go = false;
|
||||
|
||||
static uint32_t subaru_get_checksum(const CANPacket_t *msg) {
|
||||
return (uint8_t)msg->data[0];
|
||||
@@ -227,6 +233,12 @@ static safety_config subaru_init(uint16_t param) {
|
||||
SUBARU_GEN2_LONG_ADDITIONAL_TX_MSGS()
|
||||
};
|
||||
|
||||
static const CanMsg SUBARU_STOP_AND_GO_TX_MSGS[] = {
|
||||
SUBARU_BASE_TX_MSGS(SUBARU_MAIN_BUS, MSG_SUBARU_ES_LKAS)
|
||||
SUBARU_COMMON_TX_MSGS(SUBARU_MAIN_BUS)
|
||||
SUBARU_STOP_AND_GO_ADDITIONAL_TX_MSGS()
|
||||
};
|
||||
|
||||
static RxCheck subaru_rx_checks[] = {
|
||||
SUBARU_COMMON_RX_CHECKS(SUBARU_MAIN_BUS)
|
||||
};
|
||||
@@ -239,6 +251,9 @@ static safety_config subaru_init(uint16_t param) {
|
||||
|
||||
subaru_gen2 = GET_FLAG(param, SUBARU_PARAM_GEN2);
|
||||
|
||||
const uint16_t SUBARU_PARAM_STOP_AND_GO = 8;
|
||||
subaru_stop_and_go = GET_FLAG(param, SUBARU_PARAM_STOP_AND_GO);
|
||||
|
||||
#ifdef ALLOW_DEBUG
|
||||
const uint16_t SUBARU_PARAM_LONGITUDINAL = 2;
|
||||
subaru_longitudinal = GET_FLAG(param, SUBARU_PARAM_LONGITUDINAL);
|
||||
@@ -250,6 +265,7 @@ static safety_config subaru_init(uint16_t param) {
|
||||
BUILD_SAFETY_CFG(subaru_gen2_rx_checks, SUBARU_GEN2_TX_MSGS);
|
||||
} else {
|
||||
ret = subaru_longitudinal ? BUILD_SAFETY_CFG(subaru_rx_checks, SUBARU_LONG_TX_MSGS) : \
|
||||
subaru_stop_and_go ? BUILD_SAFETY_CFG(subaru_rx_checks, SUBARU_STOP_AND_GO_TX_MSGS) : \
|
||||
BUILD_SAFETY_CFG(subaru_rx_checks, SUBARU_TX_MSGS);
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -17,7 +17,16 @@
|
||||
#define SUBARU_PG_MAIN_BUS 0U
|
||||
#define SUBARU_PG_CAM_BUS 2U
|
||||
|
||||
#define SUBARU_PG_COMMON_TX_MSGS() \
|
||||
{MSG_SUBARU_PG_ES_Distance, SUBARU_PG_MAIN_BUS, 8, .check_relay = true}, \
|
||||
{MSG_SUBARU_PG_ES_LKAS, SUBARU_PG_MAIN_BUS, 8, .check_relay = true}, \
|
||||
|
||||
#define SUBARU_PG_STOP_AND_GO_ADDITIONAL_TX_MSGS() \
|
||||
{MSG_SUBARU_PG_Throttle, SUBARU_PG_CAM_BUS, 8, .check_relay = false}, \
|
||||
{MSG_SUBARU_PG_Brake_Pedal, SUBARU_PG_CAM_BUS, 4, .check_relay = false}, \
|
||||
|
||||
static bool subaru_pg_reversed_driver_torque = false;
|
||||
static bool subaru_pg_stop_and_go = false;
|
||||
|
||||
static void subaru_preglobal_rx_hook(const CANPacket_t *msg) {
|
||||
if (msg->bus == SUBARU_PG_MAIN_BUS) {
|
||||
@@ -81,8 +90,12 @@ static bool subaru_preglobal_tx_hook(const CANPacket_t *msg) {
|
||||
|
||||
static safety_config subaru_preglobal_init(uint16_t param) {
|
||||
static const CanMsg SUBARU_PG_TX_MSGS[] = {
|
||||
{MSG_SUBARU_PG_ES_Distance, SUBARU_PG_MAIN_BUS, 8, .check_relay = true},
|
||||
{MSG_SUBARU_PG_ES_LKAS, SUBARU_PG_MAIN_BUS, 8, .check_relay = true}
|
||||
SUBARU_PG_COMMON_TX_MSGS()
|
||||
};
|
||||
|
||||
static const CanMsg SUBARU_PG_STOP_AND_GO_TX_MSGS[] = {
|
||||
SUBARU_PG_COMMON_TX_MSGS()
|
||||
SUBARU_PG_STOP_AND_GO_ADDITIONAL_TX_MSGS()
|
||||
};
|
||||
|
||||
// TODO: do checksum and counter checks after adding the signals to the outback dbc file
|
||||
@@ -95,9 +108,14 @@ static safety_config subaru_preglobal_init(uint16_t param) {
|
||||
};
|
||||
|
||||
const uint16_t SUBARU_PG_PARAM_REVERSED_DRIVER_TORQUE = 4;
|
||||
const uint16_t SUBARU_PG_PARAM_STOP_AND_GO = 8;
|
||||
|
||||
subaru_pg_reversed_driver_torque = GET_FLAG(param, SUBARU_PG_PARAM_REVERSED_DRIVER_TORQUE);
|
||||
return BUILD_SAFETY_CFG(subaru_preglobal_rx_checks, SUBARU_PG_TX_MSGS);
|
||||
subaru_pg_stop_and_go = GET_FLAG(param, SUBARU_PG_PARAM_STOP_AND_GO);
|
||||
|
||||
safety_config ret = subaru_pg_stop_and_go ? BUILD_SAFETY_CFG(subaru_preglobal_rx_checks, SUBARU_PG_STOP_AND_GO_TX_MSGS) : \
|
||||
BUILD_SAFETY_CFG(subaru_preglobal_rx_checks, SUBARU_PG_TX_MSGS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const safety_hooks subaru_preglobal_hooks = {
|
||||
|
||||
@@ -69,6 +69,9 @@
|
||||
{.msg = {{0x116, 0, 8, 42U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{0x101, 0, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
|
||||
#define TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK \
|
||||
{.msg = {{0x201, 0, 6, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
|
||||
static bool toyota_secoc = false;
|
||||
static bool toyota_alt_brake = false;
|
||||
static bool toyota_stock_longitudinal = false;
|
||||
@@ -90,6 +93,12 @@ static uint32_t toyota_get_checksum(const CANPacket_t *msg) {
|
||||
return (uint8_t)(msg->data[checksum_byte]);
|
||||
}
|
||||
|
||||
static int toyota_get_interceptor(const CANPacket_t *msg) {
|
||||
uint16_t val1 = ((uint16_t)msg->data[0] << 8U) | (uint16_t)msg->data[1];
|
||||
uint16_t val2 = ((uint16_t)msg->data[2] << 8U) | (uint16_t)msg->data[3];
|
||||
return (int)((val1 + val2) / 2U);
|
||||
}
|
||||
|
||||
static bool toyota_get_quality_flag_valid(const CANPacket_t *msg) {
|
||||
|
||||
bool valid = false;
|
||||
@@ -150,7 +159,9 @@ static void toyota_rx_hook(const CANPacket_t *msg) {
|
||||
if (msg->addr == 0x1D2U) {
|
||||
bool cruise_engaged = GET_BIT(msg, 5U); // PCM_CRUISE.CRUISE_ACTIVE
|
||||
pcm_cruise_check(cruise_engaged);
|
||||
gas_pressed = !GET_BIT(msg, 4U); // PCM_CRUISE.GAS_RELEASED
|
||||
if (!enable_gas_interceptor) {
|
||||
gas_pressed = !GET_BIT(msg, 4U); // PCM_CRUISE.GAS_RELEASED
|
||||
}
|
||||
}
|
||||
if (!toyota_alt_brake && (msg->addr == 0x226U)) {
|
||||
brake_pressed = GET_BIT(msg, 37U); // BRAKE_MODULE.BRAKE_PRESSED (toyota_nodsu_pt_generated.dbc)
|
||||
@@ -181,6 +192,14 @@ static void toyota_rx_hook(const CANPacket_t *msg) {
|
||||
if (msg->addr == 0x365U) {
|
||||
acc_main_on = GET_BIT(msg, 0U);
|
||||
}
|
||||
|
||||
if (enable_gas_interceptor && (msg->addr == 0x201U)) {
|
||||
// Match the DBC's physical pedal threshold to avoid controls state mismatches.
|
||||
const int toyota_gas_interceptor_threshold = 805;
|
||||
int gas_interceptor = toyota_get_interceptor(msg);
|
||||
gas_pressed = gas_interceptor > toyota_gas_interceptor_threshold;
|
||||
gas_interceptor_prev = gas_interceptor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,6 +370,17 @@ static bool toyota_tx_hook(const CANPacket_t *msg) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((msg->addr == 0x200U) && longitudinal_interceptor_checks(msg)) {
|
||||
tx = false;
|
||||
}
|
||||
|
||||
// Auto brake hold replaces the camera AEB message only while stopped.
|
||||
if ((msg->addr == 0x344U) && ((alternative_experience & ALT_EXP_ALLOW_AEB) != 0)) {
|
||||
if (vehicle_moving || gas_pressed || !acc_main_on) {
|
||||
tx = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UDS: Only tester present ("\x0F\x02\x3E\x00\x00\x00\x00\x00") allowed on diagnostics address
|
||||
@@ -384,6 +414,16 @@ static safety_config toyota_init(uint16_t param) {
|
||||
TOYOTA_COMMON_LONG_TX_MSGS_FILTER
|
||||
};
|
||||
|
||||
static const CanMsg TOYOTA_INTERCEPTOR_TX_MSGS[] = {
|
||||
TOYOTA_COMMON_LONG_TX_MSGS
|
||||
{0x200, 0, 6, .check_relay = false},
|
||||
};
|
||||
|
||||
static const CanMsg TOYOTA_INTERCEPTOR_TX_MSGS_FILTER[] = {
|
||||
TOYOTA_COMMON_LONG_TX_MSGS_FILTER
|
||||
{0x200, 0, 6, .check_relay = false},
|
||||
};
|
||||
|
||||
static const CanMsg TOYOTA_SECOC_LONG_TX_MSGS[] = {
|
||||
TOYOTA_COMMON_SECOC_LONG_TX_MSGS
|
||||
};
|
||||
@@ -396,6 +436,7 @@ static safety_config toyota_init(uint16_t param) {
|
||||
const uint32_t TOYOTA_PARAM_STOCK_LONGITUDINAL = 2UL << TOYOTA_PARAM_OFFSET;
|
||||
const uint32_t TOYOTA_PARAM_LTA = 4UL << TOYOTA_PARAM_OFFSET;
|
||||
const uint32_t TOYOTA_PARAM_LONG_FILTER = 16UL << TOYOTA_PARAM_OFFSET;
|
||||
const uint32_t TOYOTA_PARAM_GAS_INTERCEPTOR = 32UL << TOYOTA_PARAM_OFFSET;
|
||||
|
||||
#ifdef ALLOW_DEBUG
|
||||
const uint32_t TOYOTA_PARAM_SECOC = 8UL << TOYOTA_PARAM_OFFSET;
|
||||
@@ -406,8 +447,13 @@ static safety_config toyota_init(uint16_t param) {
|
||||
toyota_stock_longitudinal = GET_FLAG(param, TOYOTA_PARAM_STOCK_LONGITUDINAL);
|
||||
toyota_lta = GET_FLAG(param, TOYOTA_PARAM_LTA);
|
||||
toyota_long_filter = GET_FLAG(param, TOYOTA_PARAM_LONG_FILTER);
|
||||
enable_gas_interceptor = GET_FLAG(param, TOYOTA_PARAM_GAS_INTERCEPTOR);
|
||||
toyota_dbc_eps_torque_factor = param & TOYOTA_EPS_FACTOR;
|
||||
|
||||
if (toyota_stock_longitudinal || toyota_secoc) {
|
||||
enable_gas_interceptor = false;
|
||||
}
|
||||
|
||||
safety_config ret;
|
||||
if (toyota_secoc) {
|
||||
if (toyota_stock_longitudinal) {
|
||||
@@ -418,6 +464,12 @@ static safety_config toyota_init(uint16_t param) {
|
||||
} else {
|
||||
if (toyota_stock_longitudinal) {
|
||||
SET_TX_MSGS(TOYOTA_TX_MSGS, ret);
|
||||
} else if (enable_gas_interceptor) {
|
||||
if (toyota_long_filter) {
|
||||
SET_TX_MSGS(TOYOTA_INTERCEPTOR_TX_MSGS_FILTER, ret);
|
||||
} else {
|
||||
SET_TX_MSGS(TOYOTA_INTERCEPTOR_TX_MSGS, ret);
|
||||
}
|
||||
} else {
|
||||
if (toyota_long_filter) {
|
||||
SET_TX_MSGS(TOYOTA_LONG_TX_MSGS_FILTER, ret);
|
||||
@@ -438,8 +490,16 @@ static safety_config toyota_init(uint16_t param) {
|
||||
static RxCheck toyota_lta_rx_checks[] = {
|
||||
TOYOTA_RX_CHECKS(true)
|
||||
};
|
||||
static RxCheck toyota_lta_interceptor_rx_checks[] = {
|
||||
TOYOTA_RX_CHECKS(true)
|
||||
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
|
||||
};
|
||||
|
||||
SET_RX_CHECKS(toyota_lta_rx_checks, ret);
|
||||
if (enable_gas_interceptor) {
|
||||
SET_RX_CHECKS(toyota_lta_interceptor_rx_checks, ret);
|
||||
} else {
|
||||
SET_RX_CHECKS(toyota_lta_rx_checks, ret);
|
||||
}
|
||||
} else {
|
||||
static RxCheck toyota_lka_rx_checks[] = {
|
||||
TOYOTA_RX_CHECKS(false)
|
||||
@@ -447,8 +507,20 @@ static safety_config toyota_init(uint16_t param) {
|
||||
static RxCheck toyota_lka_alt_brake_rx_checks[] = {
|
||||
TOYOTA_ALT_BRAKE_RX_CHECKS(false)
|
||||
};
|
||||
static RxCheck toyota_lka_interceptor_rx_checks[] = {
|
||||
TOYOTA_RX_CHECKS(false)
|
||||
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
|
||||
};
|
||||
static RxCheck toyota_lka_alt_brake_interceptor_rx_checks[] = {
|
||||
TOYOTA_ALT_BRAKE_RX_CHECKS(false)
|
||||
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
|
||||
};
|
||||
|
||||
if (!toyota_alt_brake) {
|
||||
if (enable_gas_interceptor && !toyota_alt_brake) {
|
||||
SET_RX_CHECKS(toyota_lka_interceptor_rx_checks, ret);
|
||||
} else if (enable_gas_interceptor) {
|
||||
SET_RX_CHECKS(toyota_lka_alt_brake_interceptor_rx_checks, ret);
|
||||
} else if (!toyota_alt_brake) {
|
||||
SET_RX_CHECKS(toyota_lka_rx_checks, ret);
|
||||
} else {
|
||||
SET_RX_CHECKS(toyota_lka_alt_brake_rx_checks, ret);
|
||||
@@ -458,10 +530,20 @@ static safety_config toyota_init(uint16_t param) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool toyota_fwd_hook(int bus_num, int addr) {
|
||||
bool block_msg = false;
|
||||
if (bus_num == 2) {
|
||||
block_msg = (addr == 0x344) && ((alternative_experience & ALT_EXP_ALLOW_AEB) != 0) &&
|
||||
!vehicle_moving && !gas_pressed && acc_main_on;
|
||||
}
|
||||
return block_msg;
|
||||
}
|
||||
|
||||
const safety_hooks toyota_hooks = {
|
||||
.init = toyota_init,
|
||||
.rx = toyota_rx_hook,
|
||||
.tx = toyota_tx_hook,
|
||||
.fwd = toyota_fwd_hook,
|
||||
.get_checksum = toyota_get_checksum,
|
||||
.compute_checksum = toyota_compute_checksum,
|
||||
.get_quality_flag_valid = toyota_get_quality_flag_valid,
|
||||
|
||||
@@ -973,8 +973,8 @@ class SafetyTest(SafetyTestBase):
|
||||
continue
|
||||
if {attr, current_test}.issubset({'TestGmCameraSafety', 'TestGmCameraLongitudinalSafety', 'TestGmAscmSafety',
|
||||
'TestGmCameraEVSafety', 'TestGmCameraLongitudinalEVSafety', 'TestGmAscmEVSafety',
|
||||
'TestGmInterceptorSafety', 'TestGmCcLongitudinalSafety',
|
||||
'TestGmCcLongitudinalPandaSchedSafety'}):
|
||||
'TestGmInterceptorSafety', 'TestGmBolt2022PedalFrictionSafety',
|
||||
'TestGmCcLongitudinalSafety', 'TestGmCcLongitudinalPandaSchedSafety'}):
|
||||
continue
|
||||
if attr.startswith('TestFord') and current_test.startswith('TestFord'):
|
||||
continue
|
||||
@@ -984,7 +984,8 @@ class SafetyTest(SafetyTestBase):
|
||||
continue
|
||||
if {attr, current_test}.issubset({'TestHyundaiLongitudinalSafety', 'TestHyundaiLongitudinalSafetyCameraSCC',
|
||||
'TestHyundaiSafetyFCEVLong', 'TestHyundaiLongitudinalAolLkasOnEngageSafety',
|
||||
'TestHyundaiCanCanfdBlendedLongitudinalSafety'}):
|
||||
'TestHyundaiCanCanfdBlendedLongitudinalSafety',
|
||||
'TestHyundaiLegacyLongitudinalSafetyHEV'}):
|
||||
continue
|
||||
volkswagen_shared = ('TestVolkswagenMqb', 'TestVolkswagenMlb')
|
||||
if attr.startswith(volkswagen_shared) and current_test.startswith(volkswagen_shared):
|
||||
@@ -1017,7 +1018,8 @@ class SafetyTest(SafetyTestBase):
|
||||
|
||||
if attr.startswith('TestHyundaiLongitudinal') or attr in ('TestHyundaiSafetyFCEVLong',
|
||||
'TestHyundaiLongitudinalAolLkasOnEngageSafety',
|
||||
'TestHyundaiCanCanfdBlendedLongitudinalSafety'):
|
||||
'TestHyundaiCanCanfdBlendedLongitudinalSafety',
|
||||
'TestHyundaiLegacyLongitudinalSafetyHEV'):
|
||||
# exceptions for common msgs across different Hyundai CAN platforms
|
||||
tx = list(filter(lambda m: m[0] not in [0x420, 0x50A, 0x389, 0x4A2], tx))
|
||||
all_tx.append([[m[0], m[1], attr] for m in tx])
|
||||
|
||||
@@ -307,6 +307,28 @@ def test_gm_ascm_int_long_no_accel_pos_uses_stock_cam_rx_checks():
|
||||
assert safety.safety_config_valid()
|
||||
|
||||
|
||||
def test_ascm_int_camera_long_blocks_radar_status_tx():
|
||||
safety = libsafety_py.libsafety
|
||||
radar_status_msgs = (
|
||||
(0xA1, 7),
|
||||
(0x306, 8),
|
||||
(0x308, 7),
|
||||
(0x310, 2),
|
||||
)
|
||||
ascm_int_long = GMSafetyFlags.HW_CAM | GMSafetyFlags.HW_CAM_LONG | GMSafetyFlags.HW_ASCM_INT
|
||||
|
||||
safety.set_safety_hooks(CarParams.SafetyModel.gm, ascm_int_long)
|
||||
safety.init_tests()
|
||||
for addr, length in radar_status_msgs:
|
||||
assert not safety.safety_tx_hook(common.make_msg(1, addr, length))
|
||||
|
||||
volt_sdgm_long = GMSafetyFlags.HW_CAM | GMSafetyFlags.HW_CAM_LONG | GMSafetyFlags.HW_SDGM
|
||||
safety.set_safety_hooks(CarParams.SafetyModel.gm, volt_sdgm_long)
|
||||
safety.init_tests()
|
||||
for addr, length in radar_status_msgs:
|
||||
assert not safety.safety_tx_hook(common.make_msg(1, addr, length))
|
||||
|
||||
|
||||
class TestGmCameraEVSafety(GmCameraAccEVRegenMixin, TestGmCameraSafety, TestGmEVSafetyBase):
|
||||
pass
|
||||
|
||||
@@ -447,6 +469,71 @@ class TestGmInterceptorSafety(common.GasInterceptorSafetyTest, TestGmCameraSafet
|
||||
return to_send
|
||||
|
||||
|
||||
class TestGmBolt2022PedalFrictionSafety(TestGmInterceptorSafety):
|
||||
TX_MSGS = TestGmInterceptorSafety.TX_MSGS + [[0x315, 0]]
|
||||
FWD_BLACKLISTED_ADDRS = {2: [0x180, 0x370, 0x315], 0: [0x184, 0x3D1]}
|
||||
RELAY_MALFUNCTION_ADDRS = {0: (0x180, 0x315), 2: (0x184,)}
|
||||
EXTRA_SAFETY_PARAM = GMSafetyFlags.FLAG_GM_BOLT_2022_PEDAL
|
||||
|
||||
def setUp(self):
|
||||
self.packer = CANPackerPanda("gm_global_a_powertrain_generated")
|
||||
self.packer_chassis = CANPackerPanda("gm_global_a_chassis")
|
||||
self.safety = libsafety_py.libsafety
|
||||
self.safety.set_safety_hooks(
|
||||
CarParams.SafetyModel.gm,
|
||||
GMSafetyFlags.HW_CAM |
|
||||
GMSafetyFlags.FLAG_GM_NO_ACC |
|
||||
GMSafetyFlags.FLAG_GM_PEDAL_LONG |
|
||||
GMSafetyFlags.FLAG_GM_GAS_INTERCEPTOR |
|
||||
GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED |
|
||||
self.EXTRA_SAFETY_PARAM)
|
||||
self.safety.init_tests()
|
||||
|
||||
def _send_brake_msg(self, brake):
|
||||
values = {"FrictionBrakeCmd": -brake}
|
||||
return self.packer_chassis.make_can_msg_safety("EBCMFrictionBrakeCmd", 0, values)
|
||||
|
||||
def _engage_longitudinal(self):
|
||||
self._rx(self.packer.make_can_msg_panda("ASCMSteeringButton", 0, {"ACCButtons": Buttons.DECEL_SET}))
|
||||
self._rx(self.packer.make_can_msg_panda("ASCMSteeringButton", 0, {"ACCButtons": Buttons.UNPRESS}))
|
||||
self.assertTrue(self.safety.get_controls_allowed())
|
||||
self.assertTrue(self.safety.get_longitudinal_allowed())
|
||||
|
||||
def test_tx_hook_on_wrong_safety_mode(self):
|
||||
self.skipTest("Gen2 Bolt pedal friction experiment intentionally shares the interceptor TX set plus 0x315")
|
||||
|
||||
def test_buttons(self):
|
||||
for controls_allowed in (False, True):
|
||||
self.safety.set_controls_allowed(controls_allowed)
|
||||
for btn in range(8):
|
||||
self.assertEqual(btn == Buttons.CANCEL, self._tx(self._button_msg(btn)))
|
||||
|
||||
def test_brake_allowed_when_controls_allowed(self):
|
||||
self._engage_longitudinal()
|
||||
self.assertTrue(self._tx(self._send_brake_msg(100)))
|
||||
|
||||
def test_brake_blocked_without_controls(self):
|
||||
self.safety.set_controls_allowed(False)
|
||||
self.assertFalse(self._tx(self._send_brake_msg(100)))
|
||||
|
||||
def test_brake_limit_enforced(self):
|
||||
self._engage_longitudinal()
|
||||
self.assertTrue(self._tx(self._send_brake_msg(400)))
|
||||
self.assertFalse(self._tx(self._send_brake_msg(401)))
|
||||
|
||||
def test_brake_whitelist_requires_paddle_scheduler_selector(self):
|
||||
self.safety.set_safety_hooks(
|
||||
CarParams.SafetyModel.gm,
|
||||
GMSafetyFlags.HW_CAM |
|
||||
GMSafetyFlags.FLAG_GM_NO_ACC |
|
||||
GMSafetyFlags.FLAG_GM_PEDAL_LONG |
|
||||
GMSafetyFlags.FLAG_GM_GAS_INTERCEPTOR |
|
||||
self.EXTRA_SAFETY_PARAM)
|
||||
self.safety.init_tests()
|
||||
self._engage_longitudinal()
|
||||
self.assertFalse(self._tx(self._send_brake_msg(100)))
|
||||
|
||||
|
||||
class TestGmCcLongitudinalSafety(TestGmCameraSafety):
|
||||
TX_MSGS = [[0x180, 0], [0x370, 0], [0x1E1, 0], [0x3D1, 0], [0xBD, 0], [0x1F5, 0], [0x184, 2], [0x1E1, 2]]
|
||||
FWD_BLACKLISTED_ADDRS = {2: [0x180], 0: [0x184, 0x3D1]} # block LKAS, PSCMStatus, and stock cruise status
|
||||
@@ -546,18 +633,62 @@ class TestGmVoltAutoHoldCameraSafety(TestGmCameraSafetyBase):
|
||||
values = {"FrictionBrakeCmd": -brake}
|
||||
return self.packer_chassis.make_can_msg_safety("EBCMFrictionBrakeCmd", 0, values)
|
||||
|
||||
def test_standstill_brake_allowed_without_controls(self):
|
||||
def test_standstill_brake_allowed_without_controls_when_main_on(self):
|
||||
self._rx(self._speed_msg(0))
|
||||
self._rx(self._toggle_aol(True))
|
||||
self.safety.set_controls_allowed(False)
|
||||
self.assertTrue(self._tx(self._send_brake_msg(100)))
|
||||
|
||||
def test_standstill_brake_blocked_without_main_on(self):
|
||||
self._rx(self._speed_msg(0))
|
||||
self._rx(self._toggle_aol(False))
|
||||
self.safety.set_controls_allowed(False)
|
||||
self.assertFalse(self._tx(self._send_brake_msg(100)))
|
||||
|
||||
def test_moving_brake_blocked_without_controls(self):
|
||||
self._rx(self._speed_msg(self.STANDSTILL_THRESHOLD + 1))
|
||||
self._rx(self._toggle_aol(True))
|
||||
self.safety.set_controls_allowed(False)
|
||||
self.assertFalse(self._tx(self._send_brake_msg(100)))
|
||||
|
||||
def test_gas_blocks_standstill_brake_without_controls(self):
|
||||
self._rx(self._speed_msg(0))
|
||||
self._rx(self._toggle_aol(True))
|
||||
self._rx(self._user_gas_msg(True))
|
||||
self.safety.set_controls_allowed(False)
|
||||
self.assertFalse(self._tx(self._send_brake_msg(100)))
|
||||
|
||||
|
||||
class TestGmVoltOnePedalCameraSafety(TestGmCameraSafetyBase):
|
||||
TX_MSGS = TestGmCameraSafety.TX_MSGS + [[0x315, 0]]
|
||||
EXTRA_SAFETY_PARAM = GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED | GMSafetyFlags.FLAG_GM_PANDA_3D1_SCHED
|
||||
|
||||
def setUp(self):
|
||||
self.packer = CANPackerSafety("gm_global_a_powertrain_generated")
|
||||
self.packer_chassis = CANPackerSafety("gm_global_a_chassis")
|
||||
self.safety = libsafety_py.libsafety
|
||||
self.safety.set_safety_hooks(CarParams.SafetyModel.gm, GMSafetyFlags.HW_CAM | self.EXTRA_SAFETY_PARAM)
|
||||
self.safety.init_tests()
|
||||
|
||||
def _send_brake_msg(self, brake):
|
||||
values = {"FrictionBrakeCmd": -brake}
|
||||
return self.packer_chassis.make_can_msg_safety("EBCMFrictionBrakeCmd", 0, values)
|
||||
|
||||
def test_moving_brake_allowed_without_controls_when_main_on(self):
|
||||
self._rx(self._speed_msg(self.STANDSTILL_THRESHOLD + 1))
|
||||
self._rx(self._toggle_aol(True))
|
||||
self.safety.set_controls_allowed(False)
|
||||
self.assertTrue(self._tx(self._send_brake_msg(100)))
|
||||
|
||||
def test_moving_brake_blocked_without_main_on(self):
|
||||
self._rx(self._speed_msg(self.STANDSTILL_THRESHOLD + 1))
|
||||
self._rx(self._toggle_aol(False))
|
||||
self.safety.set_controls_allowed(False)
|
||||
self.assertFalse(self._tx(self._send_brake_msg(100)))
|
||||
|
||||
def test_gas_blocks_moving_brake_without_controls(self):
|
||||
self._rx(self._speed_msg(self.STANDSTILL_THRESHOLD + 1))
|
||||
self._rx(self._toggle_aol(True))
|
||||
self._rx(self._user_gas_msg(True))
|
||||
self.safety.set_controls_allowed(False)
|
||||
self.assertFalse(self._tx(self._send_brake_msg(100)))
|
||||
@@ -578,13 +709,21 @@ class TestGmVoltAutoHoldSdgmSafety(TestGmSafetyBase):
|
||||
values = {"FrictionBrakeCmd": -brake}
|
||||
return self.packer_chassis.make_can_msg_safety("EBCMFrictionBrakeCmd", 2, values)
|
||||
|
||||
def test_standstill_brake_allowed_without_controls(self):
|
||||
def test_standstill_brake_allowed_without_controls_when_main_on(self):
|
||||
self._rx(self._speed_msg(0))
|
||||
self._rx(self._toggle_aol(True))
|
||||
self.safety.set_controls_allowed(False)
|
||||
self.assertTrue(self._tx(self._send_brake_msg(100)))
|
||||
|
||||
def test_standstill_brake_blocked_without_main_on(self):
|
||||
self._rx(self._speed_msg(0))
|
||||
self._rx(self._toggle_aol(False))
|
||||
self.safety.set_controls_allowed(False)
|
||||
self.assertFalse(self._tx(self._send_brake_msg(100)))
|
||||
|
||||
def test_moving_brake_blocked_without_controls(self):
|
||||
self._rx(self._speed_msg(self.STANDSTILL_THRESHOLD + 1))
|
||||
self._rx(self._toggle_aol(True))
|
||||
self.safety.set_controls_allowed(False)
|
||||
self.assertFalse(self._tx(self._send_brake_msg(100)))
|
||||
|
||||
|
||||
@@ -416,6 +416,14 @@ class TestHyundaiSafetyFCEVLong(TestHyundaiLongitudinalSafety, TestHyundaiSafety
|
||||
self.safety.init_tests()
|
||||
|
||||
|
||||
class TestHyundaiLegacyLongitudinalSafetyHEV(TestHyundaiLongitudinalSafety, TestHyundaiLegacySafetyHEV):
|
||||
def setUp(self):
|
||||
self.packer = CANPackerSafety("hyundai_kia_generic")
|
||||
self.safety = libsafety_py.libsafety
|
||||
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiLegacy, HyundaiSafetyFlags.HYBRID_GAS | HyundaiSafetyFlags.LONG)
|
||||
self.safety.init_tests()
|
||||
|
||||
|
||||
class TestHyundaiLongitudinalAolLkasOnEngageSafety(HyundaiAolLkasOnEngageBase, TestHyundaiLongitudinalSafety):
|
||||
def setUp(self):
|
||||
self.packer = CANPackerSafety("hyundai_kia_generic")
|
||||
|
||||
@@ -559,6 +559,61 @@ class TestHyundaiCanfdLKASteeringLongEV(HyundaiLongitudinalBase, TestHyundaiCanf
|
||||
return self.packer.make_can_msg_safety("SCC_CONTROL", 1, values)
|
||||
|
||||
|
||||
class TestHyundaiCanfdLKASteeringAltAngleLongEV(HyundaiLongitudinalBase, TestHyundaiCanfdAngleSteering):
|
||||
|
||||
TX_MSGS = [[0x110, 0], [0x1CF, 1], [0x362, 0], [0x51, 0], [0x100, 0], [0x730, 1], [0x12a, 1], [0x160, 1],
|
||||
[0x1ba, 1], [0x1e0, 1], [0x1e5, 1], [0x31a, 1], [0x3b5, 1], [0x3c1, 1],
|
||||
[0x1a0, 1], [0x1ea, 1], [0x200, 1], [0x345, 1], [0x1da, 1]]
|
||||
|
||||
RELAY_MALFUNCTION_ADDRS = {0: (0x110, 0x362), 1: (0x1a0,)} # LKAS_ALT, CAM_0x362, SCC_CONTROL
|
||||
FWD_BLACKLISTED_ADDRS = {0: MRR35_RADAR_TRACK_ADDRS, 2: [0x110, 0x362]}
|
||||
|
||||
DISABLED_ECU_UDS_MSG = (0x730, 1)
|
||||
DISABLED_ECU_ACTUATION_MSG = (0x1a0, 1)
|
||||
|
||||
PT_BUS = 1
|
||||
SCC_BUS = 1
|
||||
BUTTONS_TX_BUS = 1
|
||||
STEER_MSG = "LKAS_ALT"
|
||||
GAS_MSG = ("ACCELERATOR", "ACCELERATOR_PEDAL")
|
||||
SAFETY_PARAM = HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.CANFD_LKA_STEERING_ALT | \
|
||||
HyundaiSafetyFlags.CANFD_ANGLE_STEERING | HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.EV_GAS
|
||||
|
||||
def _angle_cmd_msg(self, angle, enabled, increment_timer=True, gain_raw=250):
|
||||
if increment_timer:
|
||||
self.safety.set_timer(self.angle_cmd_cnt * int(1e6 / self.LATERAL_FREQUENCY))
|
||||
self.angle_cmd_cnt += 1
|
||||
|
||||
values = {
|
||||
"LKA_MODE": 0,
|
||||
"LKA_AVAILABLE": 3 if enabled else 0,
|
||||
"LKA_WARNING": 0,
|
||||
"LKA_ICON": 2 if enabled else 1,
|
||||
"FCA_SYSWARN": 0,
|
||||
"TORQUE_REQUEST": 0,
|
||||
"STEER_REQ": 0,
|
||||
"LFA_BUTTON": 0,
|
||||
"LKA_ASSIST": 0,
|
||||
"DAMP_FACTOR": 100,
|
||||
"LKAS_ANGLE_ACTIVE": 2 if enabled else 1,
|
||||
"HAS_LANE_SAFETY": 0,
|
||||
"ADAS_StrAnglReqVal": angle,
|
||||
"ADAS_ACIAnglTqRedcGainVal": gain_raw * 0.004 if enabled or gain_raw != 250 else 0.0,
|
||||
}
|
||||
return self.packer.make_can_msg_safety("LKAS_ALT", 0, values)
|
||||
|
||||
def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
|
||||
values = {
|
||||
"aReqRaw": accel,
|
||||
"aReqValue": accel,
|
||||
}
|
||||
return self.packer.make_can_msg_safety("SCC_CONTROL", 1, values)
|
||||
|
||||
def _tx_acc_state_msg(self, main_on):
|
||||
values = {"MainMode_ACC": int(main_on), "ACCMode": 0}
|
||||
return self.packer.make_can_msg_safety("SCC_CONTROL", 1, values)
|
||||
|
||||
|
||||
# Tests longitudinal for ICE, hybrid, EV cars with LFA steering
|
||||
class TestHyundaiCanfdLFASteeringLongBase(HyundaiLongitudinalBase, TestHyundaiCanfdLFASteeringBase):
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ class SubaruMsg(enum.IntEnum):
|
||||
Throttle = 0x40
|
||||
Steering_Torque = 0x119
|
||||
Wheel_Speeds = 0x13a
|
||||
Brake_Pedal = 0x139
|
||||
ES_LKAS = 0x122
|
||||
ES_LKAS_ANGLE = 0x124
|
||||
ES_Brake = 0x220
|
||||
@@ -182,6 +183,12 @@ class TestSubaruGen1TorqueStockLongitudinalSafety(TestSubaruStockLongitudinalSaf
|
||||
TX_MSGS = lkas_tx_msgs(SUBARU_MAIN_BUS)
|
||||
|
||||
|
||||
class TestSubaruGen1StopAndGoSafety(TestSubaruStockLongitudinalSafetyBase, TestSubaruTorqueSafetyBase):
|
||||
FLAGS = SubaruSafetyFlags.STOP_AND_GO
|
||||
TX_MSGS = lkas_tx_msgs(SUBARU_MAIN_BUS) + [[SubaruMsg.Throttle, SUBARU_CAM_BUS],
|
||||
[SubaruMsg.Brake_Pedal, SUBARU_CAM_BUS]]
|
||||
|
||||
|
||||
class TestSubaruGen2TorqueSafetyBase(TestSubaruTorqueSafetyBase):
|
||||
ALT_MAIN_BUS = SUBARU_ALT_BUS
|
||||
ALT_CAM_BUS = SUBARU_ALT_BUS
|
||||
|
||||
@@ -70,5 +70,10 @@ class TestSubaruPreglobalReversedDriverTorqueSafety(TestSubaruPreglobalSafety):
|
||||
DBC = "subaru_outback_2019_generated"
|
||||
|
||||
|
||||
class TestSubaruPreglobalStopAndGoSafety(TestSubaruPreglobalSafety):
|
||||
FLAGS = SubaruSafetyFlags.STOP_AND_GO
|
||||
TX_MSGS = [[0x161, 0], [0x164, 0], [0x140, 2], [0xD1, 2]]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import unittest
|
||||
|
||||
from opendbc.car.structs import CarParams
|
||||
from opendbc.car.tesla.preap.interface import SAFETY_TESLA_PREAP
|
||||
from opendbc.safety.tests.libsafety import libsafety_py
|
||||
import opendbc.safety.tests.common as common
|
||||
|
||||
@@ -14,7 +14,7 @@ class TestTeslaPreAPSafety(common.SafetyTestBase):
|
||||
self._set_mode(0)
|
||||
|
||||
def _set_mode(self, param: int) -> None:
|
||||
self.safety.set_safety_hooks(CarParams.SafetyModel.teslaPreap, param)
|
||||
self.safety.set_safety_hooks(SAFETY_TESLA_PREAP, param)
|
||||
self.safety.init_tests()
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -9,6 +9,7 @@ from opendbc.car.structs import CarParams
|
||||
from opendbc.safety.tests.libsafety import libsafety_py
|
||||
import opendbc.safety.tests.common as common
|
||||
from opendbc.safety.tests.common import CANPackerSafety
|
||||
from opendbc.safety import ALTERNATIVE_EXPERIENCE
|
||||
|
||||
TOYOTA_COMMON_TX_MSGS = [[0x2E4, 0], [0x191, 0], [0x412, 0], [0x343, 0], [0x1D2, 0], [0x1D3, 0]] # LKAS + LTA + ACC & PCM cancel cmds
|
||||
TOYOTA_SECOC_TX_MSGS = [[0x131, 0], [0x183, 0]] + TOYOTA_COMMON_TX_MSGS
|
||||
@@ -16,6 +17,8 @@ TOYOTA_COMMON_LONG_TX_MSGS = [[0x283, 0], [0x2E6, 0], [0x2E7, 0], [0x33E, 0], [0
|
||||
[0x128, 1], [0x141, 1], [0x160, 1], [0x161, 1], [0x470, 1], # DSU bus 1
|
||||
[0x411, 0], # PCS_HUD
|
||||
[0x750, 0]] # radar diagnostic address
|
||||
TOYOTA_COMMON_LONG_TX_MSGS_FILTER = TOYOTA_COMMON_LONG_TX_MSGS[:-1]
|
||||
GAS_INTERCEPTOR_TX_MSGS = [[0x200, 0]]
|
||||
|
||||
|
||||
class TestToyotaSafetyBase(common.CarSafetyTest, common.LongitudinalAccelSafetyTest):
|
||||
@@ -94,6 +97,30 @@ class TestToyotaSafetyBase(common.CarSafetyTest, common.LongitudinalAccelSafetyT
|
||||
msg = libsafety_py.make_CANPacket(0x283, 0, bytes(dat))
|
||||
self.assertEqual(not bad and not stock_longitudinal, self._tx(msg))
|
||||
|
||||
def test_auto_brake_hold_aeb_replacement_only_at_standstill(self):
|
||||
self.safety.set_alternative_experience(ALTERNATIVE_EXPERIENCE.ALLOW_AEB)
|
||||
hold_msg = libsafety_py.make_CANPacket(0x344, 0, b"\xfd\x80\x00\x00\x00\x00\x00\xcc")
|
||||
|
||||
self._rx(self._speed_msg(0))
|
||||
self._rx(self._toggle_aol(True))
|
||||
self._rx(self._user_gas_msg(False))
|
||||
self.assertTrue(self._tx(hold_msg))
|
||||
self.assertEqual(-1, self.safety.safety_fwd_hook(2, 0x344))
|
||||
|
||||
self._rx(self._speed_msg(1.0))
|
||||
self.assertFalse(self._tx(hold_msg))
|
||||
self.assertEqual(0, self.safety.safety_fwd_hook(2, 0x344))
|
||||
|
||||
self._rx(self._speed_msg(0))
|
||||
self._rx(self._user_gas_msg(True))
|
||||
self.assertFalse(self._tx(hold_msg))
|
||||
self.assertEqual(0, self.safety.safety_fwd_hook(2, 0x344))
|
||||
|
||||
self._rx(self._user_gas_msg(False))
|
||||
self._rx(self._toggle_aol(False))
|
||||
self.assertFalse(self._tx(hold_msg))
|
||||
self.assertEqual(0, self.safety.safety_fwd_hook(2, 0x344))
|
||||
|
||||
# Only allow LTA msgs with no actuation
|
||||
def test_lta_steer_cmd(self):
|
||||
for engaged, req, req2, torque_wind_down, angle in itertools.product([True, False],
|
||||
@@ -271,6 +298,47 @@ class TestToyotaAltBrakeSafety(TestToyotaSafetyTorque):
|
||||
pass
|
||||
|
||||
|
||||
class TestToyotaSafetyGasInterceptorBase(common.GasInterceptorSafetyTest, TestToyotaSafetyBase):
|
||||
|
||||
TX_MSGS = TOYOTA_COMMON_TX_MSGS + TOYOTA_COMMON_LONG_TX_MSGS + GAS_INTERCEPTOR_TX_MSGS
|
||||
INTERCEPTOR_THRESHOLD = 805
|
||||
DBC = "toyota_nodsu_pt_generated"
|
||||
SAFETY_PARAM = TestToyotaSafetyBase.EPS_SCALE | ToyotaSafetyFlags.GAS_INTERCEPTOR
|
||||
|
||||
def setUp(self):
|
||||
self.packer = CANPackerSafety(self.DBC)
|
||||
self.safety = libsafety_py.libsafety
|
||||
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.SAFETY_PARAM)
|
||||
self.safety.init_tests()
|
||||
|
||||
def _user_gas_msg(self, gas):
|
||||
return self._interceptor_user_gas(self.INTERCEPTOR_THRESHOLD + 1 if gas else 0)
|
||||
|
||||
def test_stock_longitudinal_disables_interceptor(self):
|
||||
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota,
|
||||
self.SAFETY_PARAM | ToyotaSafetyFlags.STOCK_LONGITUDINAL)
|
||||
self.safety.init_tests()
|
||||
self.safety.set_controls_allowed(True)
|
||||
self.assertFalse(self._tx(self._interceptor_gas_cmd(100)))
|
||||
|
||||
|
||||
class TestToyotaSafetyTorqueGasInterceptor(TestToyotaSafetyGasInterceptorBase, TestToyotaSafetyTorque):
|
||||
pass
|
||||
|
||||
|
||||
class TestToyotaAltBrakeLongFilterGasInterceptor(TestToyotaSafetyGasInterceptorBase, TestToyotaAltBrakeSafety):
|
||||
|
||||
TX_MSGS = TOYOTA_COMMON_TX_MSGS + TOYOTA_COMMON_LONG_TX_MSGS_FILTER + GAS_INTERCEPTOR_TX_MSGS
|
||||
RELAY_MALFUNCTION_ADDRS = {0: (0x2E4, 0x191, 0x412)}
|
||||
FWD_BLACKLISTED_ADDRS = {2: [0x2E4, 0x412, 0x191]}
|
||||
DBC = "toyota_new_mc_pt_generated"
|
||||
SAFETY_PARAM = (TestToyotaSafetyBase.EPS_SCALE | ToyotaSafetyFlags.ALT_BRAKE |
|
||||
ToyotaSafetyFlags.LONG_FILTER | ToyotaSafetyFlags.GAS_INTERCEPTOR)
|
||||
|
||||
def test_diagnostics(self):
|
||||
super().test_diagnostics(ecu_disabled=False)
|
||||
|
||||
|
||||
class TestToyotaStockLongitudinalBase(TestToyotaSafetyBase):
|
||||
|
||||
TX_MSGS = TOYOTA_COMMON_TX_MSGS
|
||||
@@ -398,7 +466,5 @@ class TestToyotaSecOcSafety(TestToyotaSecOcSafetyBase):
|
||||
self.assertEqual(should_tx, self._tx(self._accel_msg_343(accel)))
|
||||
self.assertEqual(should_tx, self._tx(self._accel_msg_343(accel, cancel_req=1)))
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -169,6 +169,10 @@ build_project("panda", base_project_f4, "./board/main.c", [])
|
||||
build_project("panda_h7", base_project_h7, "./board/main.c", [])
|
||||
build_project("panda_remote", base_project_f4, "./board/main.c", ["-DPANDA_GM_REMOTE_START_C9"])
|
||||
build_project("panda_h7_remote", base_project_h7, "./board/main.c", ["-DPANDA_GM_REMOTE_START_C9"])
|
||||
build_project("panda_can_ignition_only", base_project_f4, "./board/main.c", ["-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
build_project("panda_h7_can_ignition_only", base_project_h7, "./board/main.c", ["-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
build_project("panda_remote_can_ignition_only", base_project_f4, "./board/main.c", ["-DPANDA_GM_REMOTE_START_C9", "-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
build_project("panda_h7_remote_can_ignition_only", base_project_h7, "./board/main.c", ["-DPANDA_GM_REMOTE_START_C9", "-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
|
||||
# panda jungle fw
|
||||
flags = [
|
||||
|
||||
+13
-1
@@ -27,9 +27,21 @@
|
||||
#include "board/obj/gitversion.h"
|
||||
|
||||
#include "board/can_comms.h"
|
||||
|
||||
static bool panda_ignition_line(void);
|
||||
|
||||
#include "board/main_comms.h"
|
||||
|
||||
|
||||
static bool panda_ignition_line(void) {
|
||||
#ifdef PANDA_IGNORE_IGNITION_LINE
|
||||
return false;
|
||||
#else
|
||||
return harness_check_ignition();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ********************* Serial debugging *********************
|
||||
|
||||
void debug_ring_callback(uart_ring *ring) {
|
||||
@@ -176,7 +188,7 @@ static void tick_handler(void) {
|
||||
const bool recent_heartbeat = heartbeat_counter == 0U;
|
||||
|
||||
// tick drivers at 1Hz
|
||||
bool started = harness_check_ignition() || ignition_can;
|
||||
bool started = panda_ignition_line() || ignition_can;
|
||||
bootkick_tick(started, recent_heartbeat);
|
||||
|
||||
// increase heartbeat counter and cap it at the uint32 limit
|
||||
|
||||
@@ -12,7 +12,7 @@ static int get_health_pkt(void *dat) {
|
||||
health->voltage_pkt = current_board->read_voltage_mV();
|
||||
health->current_pkt = current_board->read_current_mA();
|
||||
|
||||
health->ignition_line_pkt = (uint8_t)(harness_check_ignition());
|
||||
health->ignition_line_pkt = (uint8_t)(panda_ignition_line());
|
||||
health->ignition_can_pkt = ignition_can;
|
||||
|
||||
health->controls_allowed_pkt = controls_allowed;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,2 +1,2 @@
|
||||
extern const uint8_t gitversion[19];
|
||||
const uint8_t gitversion[19] = "DEV-e5cc7460-DEBUG";
|
||||
const uint8_t gitversion[19] = "DEV-40b54686-DEBUG";
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user