Compare commits

..

3 Commits

Author SHA1 Message Date
firestar5683 847d19d029 Microslop 2026-06-03 22:00:28 -05:00
firestar5683 1554392614 build 2026-06-02 20:08:09 -05:00
firestar5683 2486728e11 hi 2026-06-02 20:05:38 -05:00
1306 changed files with 222729 additions and 223348 deletions
@@ -165,10 +165,6 @@ 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"
)
-1
View File
@@ -68,7 +68,6 @@ 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
+7 -8
View File
@@ -1,7 +1,7 @@
# StarPilot
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/firestar5683/StarPilot)
[![Discord](https://img.shields.io/discord/1387432184121393333?label=Discord)](https://firestar.link/discord)
[![Discord](https://img.shields.io/discord/1137853399715549214?label=Discord)](https://firestar.link/discord)
[![Last Updated](https://img.shields.io/github/last-commit/firestar5683/StarPilot/StarPilot)](https://github.com/firestar5683/StarPilot)
[![Wiki](https://img.shields.io/badge/Wiki-StarPilot-blue?logo=wiki)](https://wiki.firestar.link)
@@ -15,11 +15,11 @@ Openpilot provides
* Lane Change Assist
* Driver Monitoring *without wheel nags*
StarPilot was formerly a GM targeted fork,
but [has expanded to offer Quality-Of-Life improvements for all](#features)!
StarPilot adds support for many GM vehicles along with improved tuning,
especially for radar-less (camera only) vehicles.
StarPilot is built off of [FrogPilot](https://github.com/FrogAi/FrogPilot)
and supports the major features FrogPilot offers.
StarPilot is built off of [StarPilot](https://github.com/FrogAi/StarPilot)
and supports the major features StarPilot offers.
StarPilot has a vibrant, welcoming community [discord](https://firestar.link/discord).
Stop by to chat or ask questions!
@@ -32,9 +32,9 @@ installation guides, and software configuration.
## Features
* Full support for Comma C3, C3X, and C4
* C4 is currently in release testing. Join our fleet of C4 testers!
* Model switcher with all of comma's tinygrad driving models
* Special longitudinal planner tuning for VoACC (visual only, radar-less) vehicles
* Custom-tuned torque controllers for an expanding list of cars.
* Galaxy: StarPilot's portal to configure your comma device using your phone from anywhere.
Download models, change settings, update software, visualize live model outputs for tuning.
* Always On Lateral (full time steering assist)*
@@ -49,9 +49,8 @@ Download models, change settings, update software, visualize live model outputs
* ZSS support*
* High quality dashcam recordings*
* Enhanced tuning for CEM (dynamic experimental mode switching)
* And more!
\* [Inherited from FrogPilot](https://github.com/FrogAi/FrogPilot#openpilot-vs-frogpilot)
\* [Inherited from StarPilot](https://github.com/FrogAi/StarPilot#openpilot-vs-starpilot)
## GM-only Features
+2 -22
View File
@@ -91,13 +91,6 @@ 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 {
@@ -115,11 +108,7 @@ struct StarPilotModelDataV2 @0x80ae746ee2596b11 {
}
}
struct StarPilotOnroadEvents @0xa5cd762cd951a455 {
events @0 :List(StarPilotOnroadEvent);
}
struct StarPilotOnroadEvent @0xe344718567f9ce71 {
struct StarPilotOnroadEvent @0xa5cd762cd951a455 {
name @0 :EventName;
enable @1 :Bool;
@@ -169,14 +158,6 @@ struct StarPilotOnroadEvent @0xe344718567f9ce71 {
switchbackModeInactive @30;
lkasEnable @31;
lkasDisable @32;
lateralManeuver @33;
pedalCruiseEnabled @34;
pedalCruiseDisabled @35;
pedalMaxRegen @36;
teslaCCEngaged @37;
teslaCCDisengaged @38;
teslaCCNotArmed @39;
pedalNotCalibrated @40;
}
}
@@ -278,8 +259,7 @@ struct CustomReserved9 @0xa1680744031fdb2d {
wallTimeNanos @5 :UInt64;
}
struct StarPilotLateralManeuverPlanDEPRECATED @0xcb9fd56c7057593a {
desiredCurvature @0 :Float32; # 1/m
struct CustomReserved10 @0xcb9fd56c7057593a {
}
struct CustomReserved11 @0xc2243c65e0340384 {
Binary file not shown.
+27 -118
View File
@@ -68,12 +68,12 @@ struct OnroadEvent @0xc4fa6047f024e718 {
longitudinalManeuver @30;
steerTempUnavailableSilent @31;
resumeRequired @32;
driverDistracted1 @33;
driverDistracted2 @34;
driverDistracted3 @35;
driverUnresponsive1 @36;
driverUnresponsive2 @37;
driverUnresponsive3 @38;
preDriverDistracted @33;
promptDriverDistracted @34;
driverDistracted @35;
preDriverUnresponsive @36;
promptDriverUnresponsive @37;
driverUnresponsive @38;
belowSteerSpeed @39;
lowBattery @40;
accFaulted @41;
@@ -130,6 +130,14 @@ 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;
}
@@ -825,30 +833,13 @@ struct SelfdriveState {
alertStatus @5 :AlertStatus;
alertSize @6 :AlertSize;
alertType @7 :Text;
alertSound @13 :AudibleAlert;
alertSound @8 :Car.CarControl.HUDControl.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;
@@ -869,10 +860,6 @@ struct SelfdriveState {
mid @2;
full @3;
}
deprecated :group {
alertSound @8 :Car.CarControl.HUDControl.AudibleAlert;
}
}
struct ControlsState @0x97ff69c53601abf1 {
@@ -1108,7 +1095,7 @@ struct ModelDataV2 {
confidence @23: ConfidenceClass;
# Model perceived motion
temporalPoseDEPRECATED @21 :Pose;
temporalPose @21 :Pose;
# e2e lateral planner
action @26: Action;
@@ -2192,6 +2179,7 @@ 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);
@@ -2233,7 +2221,7 @@ struct DriverStateDEPRECATED @0xb83c6cc593ed0a00 {
stdDEPRECATED @2 :Float32;
}
struct DriverMonitoringStateDEPRECATED @0xb83cda094a1da284 {
struct DriverMonitoringState @0xb83cda094a1da284 {
events @18 :List(OnroadEvent);
faceDetected @1 :Bool;
isDistracted @2 :Bool;
@@ -2251,90 +2239,12 @@ struct DriverMonitoringStateDEPRECATED @0xb83cda094a1da284 {
isActiveMode @16 :Bool;
isRHD @4 :Bool;
uncertainCount @19 :UInt32;
phoneProbOffset @20 :Float32;
phoneProbValidCount @21 :UInt32;
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;
}
isPreviewDEPRECATED @15 :Bool;
rhdCheckedDEPRECATED @5 :Bool;
eventsDEPRECATED @0 :List(Car.OnroadEventDEPRECATED);
}
struct Boot {
@@ -2655,7 +2565,7 @@ struct Event {
thumbnail @66: Thumbnail;
onroadEvents @134: List(OnroadEvent);
carParams @69: Car.CarParams;
driverMonitoringState @151 :DriverMonitoringState;
driverMonitoringState @71: DriverMonitoringState;
livePose @129 :LivePose;
modelV2 @75 :ModelDataV2;
drivingModelData @128 :DrivingModelData;
@@ -2704,8 +2614,8 @@ struct Event {
userBookmark @93 :UserBookmark;
bookmarkButton @148 :UserBookmark;
audioFeedback @149 :AudioFeedback;
lateralManeuverPlan @150 :LateralManeuverPlan;
# *********** debug ***********
testJoystick @52 :Joystick;
roadEncodeData @86 :EncodeData;
@@ -2734,12 +2644,12 @@ struct Event {
starpilotCarState @109 :Custom.StarPilotCarState;
starpilotDeviceState @110 :Custom.StarPilotDeviceState;
starpilotModelV2 @111 :Custom.StarPilotModelDataV2;
starpilotOnroadEvents @112 :Custom.StarPilotOnroadEvents;
starpilotOnroadEvents @112 :List(Custom.StarPilotOnroadEvent);
starpilotPlan @113 :Custom.StarPilotPlan;
starpilotRadarState @114 :Custom.StarPilotRadarState;
starpilotSelfdriveState @115 :Custom.StarPilotSelfdriveState;
customReserved9 @116 :Custom.CustomReserved9;
starpilotLateralManeuverPlanDEPRECATED @136 :Custom.StarPilotLateralManeuverPlanDEPRECATED;
customReserved10 @136 :Custom.CustomReserved10;
customReserved11 @137 :Custom.CustomReserved11;
customReserved12 @138 :Custom.CustomReserved12;
customReserved13 @139 :Custom.CustomReserved13;
@@ -2797,6 +2707,5 @@ struct Event {
gyroscope2DEPRECATED @100 :SensorEventData;
accelerometer2DEPRECATED @101 :SensorEventData;
temperatureSensor2DEPRECATED @123 :SensorEventData;
driverMonitoringStateDEPRECATED @71 :DriverMonitoringStateDEPRECATED;
}
}
Binary file not shown.
+11 -41
View File
@@ -42,9 +42,7 @@ 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}},
@@ -116,7 +114,6 @@ 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}},
@@ -163,7 +160,6 @@ 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, "{}", "{}"}},
@@ -172,7 +168,6 @@ 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}},
@@ -183,7 +178,6 @@ 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}},
@@ -201,22 +195,15 @@ 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, "stock", "stock", 0}},
{"ColorScheme", {PERSISTENT, STRING, "frog", "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}},
@@ -240,7 +227,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, "0", "0", 0}},
{"CustomThemes", {PERSISTENT, BOOL, "1", "0", 0}},
{"CustomUI", {PERSISTENT, BOOL, "1", "0", 1}},
{"DebugMode", {CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}},
{"DecelerationProfile", {PERSISTENT, INT, "1", "0", 2}},
@@ -287,7 +274,6 @@ 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"}},
@@ -315,12 +301,10 @@ 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}},
@@ -336,14 +320,12 @@ 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, "stock", "stock", 0}},
{"IconPack", {PERSISTENT, STRING, "frog-animated", "stock", 0}},
{"IconToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"IncreasedStoppedDistance", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
{"IncreasedStoppedDistanceLowVisibility", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
@@ -385,14 +367,12 @@ 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, "0", "0", 2}},
{"MainCruiseButtonControl", {PERSISTENT, INT, "9", "9", 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, "{}", "{}"}},
@@ -404,7 +384,6 @@ 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, "{}", "{}"}},
@@ -428,7 +407,6 @@ 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}},
@@ -437,7 +415,6 @@ 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}},
@@ -461,8 +438,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}},
{"GalaxyPaired", {PERSISTENT, BOOL, "0", "0", 0}},
{"GalaxyUploadPending", {PERSISTENT, BOOL, "0", "0", 0}},
{"PondPaired", {PERSISTENT, BOOL, "0", "0", 0}},
{"PondUploadPending", {PERSISTENT, BOOL, "0", "0", 0}},
{"PreferredSchedule", {PERSISTENT, INT, "2", "0", 0}},
{"PreviousSpeedLimit", {PERSISTENT, FLOAT, "0.0", "0.0"}},
{"PromptDistractedVolume", {PERSISTENT, INT, "101", "101", 2}},
@@ -470,7 +447,6 @@ 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, "0", "0", 2}},
{"RadarTracksUI", {PERSISTENT, BOOL, "0", "0", 3}},
{"RainbowPath", {PERSISTENT, BOOL, "0", "0", 1}},
{"RandomEvents", {PERSISTENT, BOOL, "0", "0", 1}},
@@ -509,7 +485,6 @@ 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}},
@@ -526,7 +501,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, "stock", "stock", 0}},
{"SignalAnimation", {PERSISTENT, STRING, "frog", "stock", 0}},
{"SignalMetrics", {PERSISTENT, BOOL, "0", "0", 3}},
{"SignalToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"SimpleMode", {PERSISTENT, BOOL, "0", "0", 0}},
@@ -544,7 +519,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, "stock", "stock", 0}},
{"SoundPack", {PERSISTENT, STRING, "frog", "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"}},
@@ -569,8 +544,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, "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}},
{"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}},
{"StaticPedalsOnUI", {PERSISTENT, BOOL, "0", "0", 1}},
{"SteerDelay", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"SteerDelayStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
@@ -584,7 +559,6 @@ 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}},
@@ -596,7 +570,6 @@ 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}},
@@ -605,7 +578,6 @@ 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}},
@@ -637,14 +609,12 @@ 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, "stock", "stock", 0}},
{"WheelIcon", {PERSISTENT, STRING, "frog", "stock", 0}},
{"WheelSpeed", {PERSISTENT, BOOL, "0", "0", 2}},
{"WheelToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
};
Binary file not shown.
-32
View File
@@ -1,40 +1,8 @@
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
+1 -2
View File
@@ -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.
# 326 Supported Cars
# 325 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>&nbsp;|Video|Setup Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
@@ -110,7 +110,6 @@ 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|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<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|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<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|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<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|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<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|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<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|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<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|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<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>|||
-152
View File
@@ -1,152 +0,0 @@
# 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.
+5 -3
View File
@@ -122,6 +122,7 @@ 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",
@@ -136,11 +137,12 @@ for mod in mods:
repo_root = Path.cwd().parents[1]
required_files = [
repo_root / "selfdrive/modeld/models/driving_tinygrad.pkl",
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/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
View File
@@ -21,7 +21,7 @@ fi
export QCOM_PRIORITY=12
if [ -z "$AGNOS_VERSION" ]; then
export AGNOS_VERSION="12.8.17"
export AGNOS_VERSION="12.8.16"
fi
export STAGING_ROOT="/data/safe_staging"
+19 -46
View File
@@ -34,11 +34,9 @@ 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 = 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]
API_HOST = os.getenv("COMMA_API_HOST", "https://api.commadotai.com").rstrip("/")
ROUTE_ID_RE = re.compile(r"([0-9a-f]{16})/([^/]+)")
@@ -148,12 +146,12 @@ def parse_route_id(raw: str) -> RouteId:
return RouteId(dongle_id=dongle_id, log_id=log_id)
def route_url(route: RouteId, api_host: str) -> str:
return f"{api_host}/v1/route/{quote(route.canonical_name, safe='')}/"
def route_url(route: RouteId) -> str:
return f"{API_HOST}/v1/route/{quote(route.canonical_name, safe='')}/"
def route_files_url(route: RouteId, api_host: str) -> str:
return f"{api_host}/v1/route/{quote(route.canonical_name, safe='')}/files"
def route_files_url(route: RouteId) -> str:
return f"{API_HOST}/v1/route/{quote(route.canonical_name, safe='')}/files"
def format_segments(segments: list[int]) -> str:
@@ -186,13 +184,8 @@ def relative_posix(path: Path, root: Path) -> str:
return path.relative_to(root).as_posix()
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)
def fetch_json(session: requests.Session, url: str, timeout: float) -> Any:
response = session.get(url, timeout=timeout, allow_redirects=True)
response.raise_for_status()
return response.json()
@@ -319,42 +312,24 @@ def filename_from_url(url: str) -> str:
def validate_route(route: RouteId, session: requests.Session, timeout: float) -> dict[str, Any]:
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)}."])
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
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 the route API."])
raise ValidationError(route, ["could not determine any route segments from comma connect."])
failures: list[str] = []
stream_urls: dict[str, list[Any]] = {}
@@ -409,7 +384,6 @@ 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,
@@ -558,7 +532,6 @@ 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', '')}")
+1 -1
View File
@@ -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, safety_param: int = None) -> structs.CarParams.SafetyConfig:
def get_safety_config(safety_model: structs.CarParams.SafetyModel, safety_param: int = None) -> structs.CarParams.SafetyConfig:
ret = structs.CarParams.SafetyConfig()
ret.safetyModel = safety_model
if safety_param is not None:
+6
View File
@@ -205,6 +205,11 @@ 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;
@@ -635,6 +640,7 @@ struct CarParams {
fcaGiorgio @32;
rivian @33;
volkswagenMeb @34;
teslaPreap @35;
}
enum SteerControlType {
-3
View File
@@ -334,9 +334,6 @@ 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, ChryslerStarPilotFlags
from opendbc.car.chrysler.values import RAM_CARS, RAM_DT, CarControllerParams, ChryslerFlags
from opendbc.car.interfaces import CarControllerBase
@@ -50,9 +50,7 @@ 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.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.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,7 +21,6 @@ class ChryslerFlags(IntFlag):
class ChryslerStarPilotFlags(IntFlag):
RAM_HD_ALT_BUTTONS = 1
NO_MIN_STEERING_SPEED = 2
@dataclass
+73 -455
View File
@@ -10,13 +10,11 @@ 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
@@ -30,42 +28,14 @@ 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):
@@ -81,13 +51,7 @@ 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)
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
return CS.out.cruiseState.standstill and (CS.out.standstill or CS.out.vEgo < launch_speed)
def should_spoof_dash_speed(CP, starpilot_toggles):
@@ -113,13 +77,6 @@ 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
@@ -135,6 +92,29 @@ 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,
@@ -170,56 +150,14 @@ 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 = bool(safety_param & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value)
stock_hold_safety_ready = CP.openpilotLongitudinalControl or bool(safety_param & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value)
return (
auto_hold_enabled and
stock_hold_safety_ready and
@@ -227,67 +165,19 @@ def supports_volt_auto_hold(CP, auto_hold_enabled: bool):
)
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:
def estimate_auto_hold_brake(driver_brake: float, op_brake: float) -> 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))
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
)
return int(round(np.clip(hold_brake, AUTO_HOLD_MIN_BRAKE, AUTO_HOLD_MAX_BRAKE)))
def should_activate_auto_hold(hold_ready: bool, auto_hold_armed: bool, auto_hold_engaged: bool,
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
brake_pressed: bool, standstill: bool, long_active: bool,
regen_braking: bool, v_ego: float) -> bool:
stopped = standstill or v_ego < 0.02
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
@@ -311,104 +201,6 @@ 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)
@@ -462,59 +254,10 @@ 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:
@@ -668,37 +411,7 @@ class CarController(CarControllerBase):
accel = actuators.accel
press_regen_paddle = False
auto_hold_enabled = supports_volt_auto_hold(self.CP, self.gm_auto_hold_enabled)
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)
stock_hold_apply_brake = self.apply_brake if self.CP.openpilotLongitudinalControl else 0
hold_ready = (
auto_hold_enabled and
@@ -708,8 +421,6 @@ 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)):
@@ -718,7 +429,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.CP)
self.auto_hold_brake = estimate_auto_hold_brake(CS.out.brake, stock_hold_apply_brake)
if self.frame % 25 == 0:
try:
@@ -809,23 +520,10 @@ 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)
@@ -880,7 +578,6 @@ 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
@@ -888,7 +585,7 @@ class CarController(CarControllerBase):
self.regen_release_counter = 0
self.regen_min_on_frames = 0
self.regen_min_off_frames = 0
elif should_use_fixed_stopping_brake(self.CP, near_stop, stopping, CC.cruiseControl.resume):
elif near_stop and stopping and not 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))
@@ -932,16 +629,7 @@ 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_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))
accel_cmd = float(np.clip(actuators.accel + accel_due_to_pitch, 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)
@@ -949,27 +637,9 @@ 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
@@ -980,19 +650,15 @@ 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 = get_interceptor_sng_gas_cmd(
self.CP, interceptor_gas_cmd, actuators.accel, self.params, 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])))
self.apply_brake = 0
self.apply_gas = self.params.INACTIVE_REGEN
@@ -1026,27 +692,6 @@ 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
@@ -1064,65 +709,57 @@ class CarController(CarControllerBase):
acc_engaged = CC.enabled
if auto_hold_active:
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_brake = self.auto_hold_brake or estimate_auto_hold_brake(CS.out.brake, self.apply_brake)
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
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))
self.packer_ch, friction_brake_bus, hold_brake, idx, False, hold_near_stop, hold_standstill, self.CP))
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,
allow_near_stop_mode=volt_one_pedal_braking))
idx, CC.enabled, near_stop, at_full_stop, self.CP))
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)
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))
can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN,
acc_dashboard_status, fcw_alert))
# Radar needs to know current speed and yaw rate (50hz),
# and that ADAS is alive (10hz)
if should_send_adas_status(self.CP, self.CP.carFingerprint in kaofui_cars):
tt = self.frame * DT_CTRL
if not self.CP.radarUnavailable:
send_adas = True
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))
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))
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:
@@ -1148,33 +785,14 @@ class CarController(CarControllerBase):
else:
if self.frame % 4 == 0 and auto_hold_active:
idx = (self.frame // 4) % 4
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_brake = self.auto_hold_brake or estimate_auto_hold_brake(CS.out.brake, stock_hold_apply_brake)
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))
self.packer_ch, get_friction_brake_bus(self.CP), hold_brake, idx, False, hold_near_stop, hold_standstill, self.CP))
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.
+30 -63
View File
@@ -33,13 +33,6 @@ 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 = {
@@ -52,19 +45,6 @@ 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)
@@ -84,14 +64,11 @@ 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
@@ -104,6 +81,12 @@ 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:
@@ -136,36 +119,21 @@ 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:
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.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"]
self.steering_button_ts_nanos = pt_cp.ts_nanos["ASCMSteeringButton"]["ACCButtons"]
acc_always_one = steering_button_msg["ACCAlwaysOne"]
acc_hidden_bit = steering_button_msg.get("ACCHiddenBit", 0)
acc_always_one = pt_cp.vl["ASCMSteeringButton"]["ACCAlwaysOne"]
acc_hidden_bit = pt_cp.vl["ASCMSteeringButton"].get("ACCHiddenBit", 0)
self.steering_button_prefix = (int(acc_always_one) & 1) | ((int(acc_hidden_bit) & 1) << 6)
else:
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.cruise_buttons = cam_cp.vl["ASCMSteeringButton"]["ACCButtons"]
self.distance_button = cam_cp.vl["ASCMSteeringButton"]["DistanceButton"]
self.buttons_counter = cam_cp.vl["ASCMSteeringButton"]["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)
@@ -210,10 +178,7 @@ 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 not in (SDGM_CAR | ASCM_INT | {CAR.CHEVROLET_BLAZER})
):
elif (self.CP.flags & GMFlags.FORCE_BRAKE_C9.value) or ((self.CP.networkLocation == NetworkLocation.fwdCamera) and (self.CP.carFingerprint != CAR.CHEVROLET_BLAZER)):
ret.brakePressed = pt_cp.vl["ECMEngineStatus"]["BrakePressed"] != 0
else:
# Some Volt 2016-17 have loose brake pedal push rod retainers which causes the ECM to believe
@@ -224,10 +189,13 @@ class CarState(CarStateBase):
ret.brakePressed = ret.brake >= analog_thresh
in_drive_for_hold = ret.gearShifter in (GearShifter.drive, GearShifter.low, GearShifter.manumatic)
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:
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_armed = False
self.auto_hold_engaged = False
@@ -312,6 +280,12 @@ 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"])
@@ -400,26 +374,19 @@ 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 or
self.hard_cruise_buttons != CruiseButtons.INIT or prev_hard_cruise_buttons != CruiseButtons.INIT):
if self.cruise_buttons != CruiseButtons.UNPRESS or prev_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,7 +7,6 @@ from opendbc.car.gm.values import CAR
CAMERA_DIAGNOSTIC_ADDRESS = 0x24b
CAMERA_DIAGNOSTIC_RX_ADDRESS = 0x64b
SASCM_ADDRESS = 0x2FF
FINGERPRINTS = {
@@ -211,7 +210,6 @@ 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],
+13 -18
View File
@@ -179,28 +179,22 @@ def create_ecm_cruise_control_command(packer, bus, enabled, target_speed_kph):
return CanData(0x3D1, bytes(dat), bus)
def get_friction_brake_mode(apply_brake, enabled, near_stop, at_full_stop, CP, allow_near_stop_mode=False):
def create_friction_brake_command(packer, bus, apply_brake, idx, enabled, near_stop, at_full_stop, CP):
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, CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL):
if enabled and CP.carFingerprint in (CAR.CHEVROLET_BOLT_ACC_2022_2023,):
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
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)
# 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
brake = (0x1000 - apply_brake) & 0xfff
checksum = (0x10000 - (mode << 12) - brake - idx) & 0xffff
@@ -215,17 +209,18 @@ 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, enabled, target_speed_kph, hud_control, fcw_alert):
target_speed = min(target_speed_kph, 255)
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)
values = {
"ACCAlwaysOne": 1,
"ACCResumeButton": 0,
"ACCCruiseState": int(status_values.get("ACCCruiseState", 0)) & 0x7,
"ACCResumeButton": int(status_values.get("ACCResumeButton", 0)) & 0x1,
"ACCSpeedSetpoint": target_speed,
"ACCGapLevel": hud_control.leadDistanceBars * enabled, # 3 "far", 0 "inactive"
"ACCCmdActive": enabled,
"ACCGapLevel": int(status_values.get("ACCGapLevel", 0)) & 0x3,
"ACCCmdActive": int(status_values.get("ACCCmdActive", 0)) & 0x1,
"ACCAlwaysOne2": 1,
"ACCLeadCar": hud_control.leadVisible,
"ACCLeadCar": int(status_values.get("ACCLeadCar", 0)) & 0x1,
"FCWAlert": int(fcw_alert) & 0x3,
}
+12 -59
View File
@@ -62,13 +62,9 @@ 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.525, 1.05, 0.155, 0.0],
"right": [1.525, 0.95, 0.150, 0.0],
"left": [1.5, 1.0, 0.155, 0.0],
"right": [1.5, 1.0, 0.155, 0.0],
},
}
@@ -133,11 +129,7 @@ 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 == 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:
if 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],
@@ -221,10 +213,6 @@ 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)]
@@ -432,7 +420,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, CAR.CADILLAC_ESCALADE_ESV_2019_ASCM):
elif candidate in (CAR.CADILLAC_ESCALADE_ESV, CAR.CADILLAC_ESCALADE_ESV_2019):
ret.minEnableSpeed = -1. # engage speed is decided by pcm
if candidate == CAR.CADILLAC_ESCALADE_ESV:
@@ -441,8 +429,7 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kf = 0.000045
else:
ret.steerActuatorDelay = 0.2
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)
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate in (
CAR.CHEVROLET_BOLT_ACC_2022_2023,
@@ -528,19 +515,7 @@ 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:
@@ -634,12 +609,6 @@ class CarInterface(CarInterfaceBase):
ret.startAccel = 1.15
ret.vEgoStarting = max(ret.vEgoStarting, 0.35)
if ret.openpilotLongitudinalControl and candidate in (CAR.CHEVROLET_SILVERADO, CAR.CHEVROLET_SILVERADO_CC) and not ret.enableGasInterceptorDEPRECATED:
ret.longitudinalTuning.kpBP = [0.0, 5.0, 15.0, 35.0]
ret.longitudinalTuning.kpV = [0.02, 0.03, 0.028, 0.022]
ret.longitudinalTuning.kiBP = [0.0, 5.0, 15.0, 35.0]
ret.longitudinalTuning.kiV = [0.28, 0.26, 0.20, 0.16]
elif candidate in CC_ONLY_CAR and not ret.enableGasInterceptorDEPRECATED:
ret.flags |= GMFlags.CC_LONG.value
ret.alphaLongitudinalAvailable = False
@@ -670,7 +639,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 (ASCM_INT | SDGM_CAR):
if (ret.networkLocation == NetworkLocation.fwdCamera or candidate in CC_ONLY_CAR) and missing_camera_msg and candidate not in SDGM_CAR:
ret.flags |= GMFlags.NO_CAMERA.value
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_CAMERA.value
@@ -688,8 +657,9 @@ class CarInterface(CarInterfaceBase):
if remote_start_boots_comma:
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_REMOTE_START_BOOTS_COMMA.value
volt_stock_friction_brake_safety = (
(gm_auto_hold or volt_one_pedal_mode) and
volt_stock_auto_hold_safety = (
gm_auto_hold and
not ret.openpilotLongitudinalControl and
candidate in {
CAR.CHEVROLET_VOLT,
CAR.CHEVROLET_VOLT_2019,
@@ -697,28 +667,11 @@ class CarInterface(CarInterfaceBase):
CAR.CHEVROLET_VOLT_CAMERA,
}
)
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.
if volt_stock_auto_hold_safety:
# Reuse the paddle-scheduler safety bit as a stock-Volt auto-hold marker on
# non-pedal paths. The scheduler logic remains inactive without pedal-long.
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,10 +1,6 @@
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")
@@ -37,40 +33,21 @@ 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.gmcan import get_friction_brake_mode
from opendbc.car.gm.values import AccState, CAR, CarControllerParams, GMFlags
from opendbc.car.gm.values import AccState, CAR, GMFlags
from opendbc.car.structs import CarParams
from opendbc.car.common.conversions import Conversions as CV
def _cs(enabled, pcm_acc_status):
@@ -104,7 +81,6 @@ 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
@@ -120,201 +96,12 @@ 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 get_stock_cc_active_for_cancel(CP, cs)
assert not get_stock_cc_active_for_cancel(CP, cs)
assert not should_send_stock_long_cancel(11, cs)
@@ -356,35 +143,11 @@ 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 not supports_volt_auto_hold(
assert supports_volt_auto_hold(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
openpilotLongitudinalControl=True,
@@ -402,15 +165,6 @@ 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,
@@ -454,60 +208,6 @@ 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():
@@ -516,7 +216,6 @@ def test_auto_hold_activation_allows_direct_entry_from_stopped_brake_press():
False,
False,
True,
False,
True,
False,
False,
@@ -530,7 +229,6 @@ def test_auto_hold_activation_stays_latched_after_brake_release():
False,
True,
False,
False,
True,
False,
False,
@@ -538,42 +236,12 @@ 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,
@@ -586,8 +254,6 @@ def test_auto_hold_activation_blocks_when_long_is_active_or_motion_is_above_thre
False,
False,
False,
False,
False,
0.03,
)
@@ -598,7 +264,6 @@ def test_auto_hold_activation_allows_standstill_even_if_speed_filter_is_slightly
True,
False,
False,
False,
True,
False,
False,
@@ -606,150 +271,6 @@ 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()
@@ -796,27 +317,6 @@ 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)
@@ -826,42 +326,6 @@ 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)
+63 -192
View File
@@ -1,18 +1,16 @@
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, get_hard_cruise_buttons, update_auto_hold_drive_timers
from opendbc.car.gm.carstate import CarState as GMCarState
from opendbc.car.gm.carcontroller import (
VisualAlert,
get_acc_dashboard_fcw_alert,
get_volt_one_pedal_lift_brake,
get_acc_dashboard_status_values,
should_send_acc_dashboard_status,
should_send_cc_button_spam,
should_spoof_dash_speed,
@@ -20,7 +18,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 ASCM_INT, CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, DBC, GM_RX_OFFSET, CarControllerParams, CruiseButtons, GMFlags, GMSafetyFlags
from opendbc.car.gm.values import CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, DBC, GM_RX_OFFSET, GMFlags, GMSafetyFlags
from opendbc.safety import ALTERNATIVE_EXPERIENCE
from openpilot.common.params import Params
@@ -65,52 +63,6 @@ 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]
@@ -132,15 +84,12 @@ 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])
@@ -168,42 +117,6 @@ class TestGMInterface:
assert car_params.flags & GMFlags.NO_CAMERA.value
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_CAMERA.value
def test_silverado_alpha_long_uses_trimmed_longitudinal_tune(self):
CarInterface = interfaces[CAR.CHEVROLET_SILVERADO]
fingerprint = _empty_fingerprint()
fingerprint[0] = FINGERPRINTS[CAR.CHEVROLET_SILVERADO][0].copy()
car_params = CarInterface.get_params(CAR.CHEVROLET_SILVERADO, fingerprint, [], alpha_long=True, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
assert car_params.openpilotLongitudinalControl
assert not car_params.enableGasInterceptorDEPRECATED
assert list(car_params.longitudinalTuning.kpBP) == pytest.approx([0.0, 5.0, 15.0, 35.0])
assert list(car_params.longitudinalTuning.kpV) == pytest.approx([0.02, 0.03, 0.028, 0.022])
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()
@@ -219,41 +132,6 @@ class TestGMInterface:
assert "ECMAcceleratorPos" not in pt_parser.vl
assert "EBCMBrakePedalPosition" in pt_parser.vl
def test_volt_auto_hold_sets_stock_hold_safety_bit_with_op_long_enabled(self):
CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM]
fingerprint = _empty_fingerprint()
fingerprint[0][0x2FF] = 8
params = Params()
try:
params.put_bool("GMAutoHold", 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")
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]
@@ -300,17 +178,14 @@ 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]
@@ -336,49 +211,6 @@ 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):
@@ -393,11 +225,6 @@ 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)
@@ -496,9 +323,14 @@ class TestGMCarController:
msg = gmcan.create_acc_dashboard_command(
packer,
0,
True,
100,
SimpleNamespace(leadDistanceBars=3, leadVisible=True),
{
"ACCCruiseState": 0,
"ACCLeadCar": 1,
"ACCResumeButton": 0,
"ACCSpeedSetpoint": 100,
"ACCGapLevel": 3,
"ACCCmdActive": 1,
},
0x2,
)
@@ -506,26 +338,23 @@ class TestGMCarController:
assert parser.vl["ASCMActiveCruiseControlStatus"]["FCWAlert"] == 2
def test_acc_dashboard_command_uses_openpilot_hud_when_disengaged(self):
def test_acc_dashboard_command_can_replay_stock_status_payload(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,
False,
50,
SimpleNamespace(leadDistanceBars=2, leadVisible=True),
{
"ACCCruiseState": 0,
"ACCLeadCar": 1,
"ACCResumeButton": 0,
"ACCSpeedSetpoint": 50,
"ACCGapLevel": 2,
"ACCCmdActive": 0,
},
0x3,
)
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
assert msg[1].hex() == "010023200113"
def test_acc_dashboard_fcw_alert_prefers_openpilot_alert(self):
cs = SimpleNamespace(
@@ -558,3 +387,45 @@ 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,5 +1,3 @@
from types import SimpleNamespace
from opendbc.can import CANPacker
from opendbc.car.gm import gmcan
from opendbc.car.gm.values import CAR, DBC
@@ -28,39 +26,6 @@ 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"])
@@ -77,3 +42,11 @@ 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"
+1 -12
View File
@@ -303,10 +303,6 @@ 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"),
@@ -580,14 +576,7 @@ 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.CADILLAC_ESCALADE_ESV_2019_ASCM,
CAR.BUICK_LACROSSE_ASCM,
}
ASCM_INT = {CAR.CHEVROLET_VOLT_ASCM, CAR.GMC_ACADIA_ASCM, CAR.CHEVROLET_MALIBU_ASCM, CAR.CADILLAC_ESCALADE_ASCM, CAR.BUICK_LACROSSE_ASCM}
STEER_THRESHOLD = 1.0
+28 -114
View File
@@ -2,14 +2,12 @@ from dataclasses import dataclass
import numpy as np
from opendbc.can import CANPacker
from opendbc.car import Bus, DT_CTRL, make_tester_present_msg, rate_limit, structs
from opendbc.car.common.filter_simple import FirstOrderFilter
from opendbc.car import Bus, DT_CTRL, make_tester_present_msg, structs
from opendbc.car.lateral import apply_driver_steer_torque_limits, apply_steer_angle_limits_vm, common_fault_avoidance
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, \
kia_ev6_gt_line_longitudinal_tuning
from opendbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR, CANFD_RADAR_LIVE_LONGITUDINAL_CAR
from opendbc.car.interfaces import CarControllerBase
from opendbc.car.vehicle_model import VehicleModel
from openpilot.common.params import Params
@@ -63,22 +61,6 @@ REDNECK_BUTTON_COPIES = 2
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
@@ -94,13 +76,6 @@ 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
@@ -220,40 +195,6 @@ def update_genesis_g90_longitudinal_tuning(state: GenesisG90LongitudinalTuningSt
return state
def get_baseline_safety_cp():
from opendbc.car.hyundai.interface import CarInterface
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])
shelf = np.interp(v_ego, [2.0, 11.0], [0.45, 0.6])
floor = np.interp(v_ego, [2.0, 22.0], [0.1, 0.3])
bp1 = np.interp(v_ego, [2.0, 11.0], [75.0, 125.0])
bp2 = np.interp(v_ego, [2.0, 11.0], [125.0, 150.0])
bp3 = np.interp(v_ego, [2.0, 11.0], [175.0, 275.0])
bp4 = np.interp(v_ego, [2.0, 22.0], [400.0, 700.0])
target = np.interp(abs(steering_torque), [bp1, bp2, bp3, bp4], [ceiling, shelf, shelf, floor])
else:
target = 0.0
gain = rate_limit(target, last_gain, -0.014, 0.004)
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))
@@ -286,8 +227,6 @@ class CarController(CarControllerBase):
self.packer = CANPacker(dbc_names[Bus.pt])
self.angle_limit_counter = 0
self.VM = VehicleModel(CP)
self.BASELINE_VM = VehicleModel(get_baseline_safety_cp()) if CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING else self.VM
self.angle_filter = FirstOrderFilter(0.0, 0.2, DT_CTRL)
self.accel_last = 0
self.apply_torque_last = 0
@@ -389,42 +328,32 @@ class CarController(CarControllerBase):
hud_control = CC.hudControl
lka_icon, lfa_icon = self._update_dash_icon_state(CC)
if not self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
self.params = CarControllerParams(self.CP, CS.out.vEgoRaw)
self.params = CarControllerParams(self.CP, CS.out.vEgoRaw)
apply_angle = CS.out.steeringAngleDeg
if self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
v_ego_raw = CS.out.vEgoRaw
desired_angle = float(np.clip(actuators.steeringAngleDeg,
-self.params.ANGLE_LIMITS.STEER_ANGLE_MAX,
self.params.ANGLE_LIMITS.STEER_ANGLE_MAX))
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,
apply_angle = apply_steer_angle_limits_vm(desired_angle, self.apply_angle_last, CS.out.vEgoRaw,
CS.out.steeringAngleDeg, CC.latActive, self.params, self.VM)
if str(self.CP.carFingerprint) != ANGLE_SAFETY_BASELINE_MODEL:
apply_angle = apply_steer_angle_limits_vm(apply_angle or desired_angle, self.apply_angle_last, v_ego_raw,
CS.out.steeringAngleDeg, CC.latActive, self.params, self.BASELINE_VM)
if CS.out.steeringPressed and abs(CS.out.steeringTorque) > self.params.STEER_THRESHOLD:
apply_torque = self.params.ANGLE_MIN_TORQUE_REDUCTION_GAIN
elif CC.latActive and CS.out.vEgoRaw < 0.3:
apply_torque = self.params.ANGLE_ACTIVE_TORQUE_REDUCTION_GAIN
else:
apply_torque = self.params.ANGLE_MAX_TORQUE_REDUCTION_GAIN if CC.latActive else 0.0
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
apply_steer_req = CC.latActive and apply_torque > 0.0
torque_fault = False
if apply_angle is None:
apply_torque = 0
apply_torque = 0.0
apply_angle = CS.out.steeringAngleDeg
apply_steer_req = False
self.apply_angle_last = apply_angle
if not CC.latActive:
self.apply_angle_last = float(np.clip(CS.out.steeringAngleDeg,
-self.params.ANGLE_LIMITS.STEER_ANGLE_MAX,
self.params.ANGLE_LIMITS.STEER_ANGLE_MAX))
self.angle_filter.x = self.apply_angle_last
else:
# steering torque
new_torque = int(round(actuators.torque * self.params.STEER_MAX))
@@ -462,25 +391,22 @@ 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_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:
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:
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_egmp_smoothed_accel = use_egmp_dynamic_long_tuning and (
use_ioniq_6_smoothed_accel = use_ioniq_6_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 use_egmp_dynamic_long_tuning:
if use_egmp_smoothed_accel:
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and self.long_active_ecu:
if use_ioniq_6_smoothed_accel:
accel = self._ioniq_6_long_tuning.actual_accel
stopping = self._ioniq_6_long_tuning.stopping
else:
elif use_ioniq_6_dynamic_long_tuning:
accel = float(np.clip(accel_cmd,
self.accel_last - IONIQ_6_CANFD_SCC_DECEL_STEP,
self.accel_last + IONIQ_6_CANFD_SCC_ACCEL_STEP))
@@ -605,31 +531,20 @@ 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_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
)
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
# steering control
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
preserve_stock_lkas = self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and not self.long_active_ecu
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled,
steering_msg_active, apply_torque, apply_angle,
apply_steer_req, 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
suppress_lfa = bool(lka_steering)
if self.frame % 5 == 0 and suppress_lfa:
if self.frame % 5 == 0 and lka_steering:
can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.lfa_block_msg,
self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT))
@@ -675,8 +590,7 @@ 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, self.CP.carFingerprint))
can_sends.append(hyundaicanfd.create_accelerator_brake_alt_spoof(0, self.frame // 4, CS.out.brakePressed, CS.out.gasPressed))
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:
@@ -707,8 +621,8 @@ class CarController(CarControllerBase):
"lead_rel_speed": lead_rel_speed,
"lead_visible": lead_visible,
}
if use_egmp_dynamic_long_tuning:
if use_egmp_smoothed_accel:
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
if use_ioniq_6_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,
+8 -48
View File
@@ -75,14 +75,7 @@ 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
@@ -181,20 +174,15 @@ class CarState(CarStateBase):
return False
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:
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)
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"]
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:
@@ -210,10 +198,8 @@ 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.
elif cp.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"] > 0:
if 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"])
@@ -222,32 +208,6 @@ 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]
@@ -388,7 +348,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 self.get_alt_bus_lda_button_raw_state(cp_alt)[1] > 0:
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:
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,14 +38,6 @@ 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',
@@ -615,17 +607,6 @@ 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.KIA_XCEED_PHEV,
CAR.HYUNDAI_SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED,
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,8 +96,6 @@ 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,
@@ -130,48 +128,6 @@ 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:
@@ -753,15 +709,11 @@ 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 templates captured from real ADAS broadcasts; only checksum, counter,
# brake, and accelerator bits are updated for the radar heartbeat.
# Byte template captured from a real ADAS broadcast; bytes 6-23 appear static / config.
_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,
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)
def create_accelerator_brake_alt_spoof(bus: int, counter: int, brake_pressed: bool, accelerator_pressed: bool) -> CanData:
d = bytearray(_ACCEL_BRAKE_ALT_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)
+11 -23
View File
@@ -4,15 +4,12 @@ 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, \
kia_ev6_gt_line_longitudinal_tuning
from opendbc.car.hyundai.radar_interface import get_radar_track_config, radar_tracks_available
hyundai_cancel_button_enables_cruise
from opendbc.car.hyundai.radar_interface import get_radar_track_config
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
@@ -42,12 +39,6 @@ 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
@@ -76,11 +67,6 @@ 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"
@@ -100,8 +86,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 and candidate not in CANFD_ANGLE_LONGITUDINAL_CAR:
# Most angle-steering LKA platforms still need stock longitudinal validation.
if lka_steering and ret.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
# Angle-steering LKA platforms still need stock longitudinal validation.
ret.alphaLongitudinalAvailable = False
ret.enableBsm = 0x1ba in fingerprint[CAN.ECAN]
@@ -153,7 +139,7 @@ class CarInterface(CarInterfaceBase):
else:
# Shared configuration for non CAN-FD cars
ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR or candidate in LEGACY_LONGITUDINAL_CAR
ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR
ret.enableBsm = 0x58b in fingerprint[CAN.ECAN]
# Send LFA message on cars with HDA
@@ -205,13 +191,13 @@ class CarInterface(CarInterfaceBase):
# Common longitudinal control setup
radar_config = get_radar_track_config(ret.carFingerprint, ret.flags)
radar_available = radar_tracks_available(radar_config, fingerprint)
ret.radarUnavailable = not radar_available
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
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_available):
if ret.openpilotLongitudinalControl and not (candidate in RADAR_LIVE_LONGITUDINAL_CAR and radar_tracks_available):
ret.radarUnavailable = True
ret.pcmCruise = not ret.openpilotLongitudinalControl
apply_platform_longitudinal_params(ret)
@@ -228,6 +214,8 @@ class CarInterface(CarInterfaceBase):
# Car specific configuration overrides
if candidate == CAR.GENESIS_G90:
ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON.value
ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
ret.stoppingDecelRate = 0.55
ret.vEgoStopping = 0.8
@@ -1,12 +1,12 @@
import math
from dataclasses import dataclass, replace
from dataclasses import dataclass
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, HyundaiFlags, HYUNDAI_MANDO_FRONT_RADAR_DBC, HYUNDAI_MRREVO14F_RADAR_DBC, \
from opendbc.car.hyundai.values import CAR, DBC, HYUNDAI_MANDO_FRONT_RADAR_DBC, HYUNDAI_MRREVO14F_RADAR_DBC, \
HYUNDAI_MRR30_RADAR_DBC, HYUNDAI_MRR35_RADAR_DBC
from openpilot.common.swaglog import cloudlog
@@ -29,7 +29,6 @@ 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:
@@ -39,37 +38,18 @@ 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, expected_length=32),
HYUNDAI_MRR35_RADAR_DBC: RadarTrackConfig(MRR35_RADAR_START_ADDR, MRR35_RADAR_MSG_COUNT, "mrr35", bus=0, frequency=20, expected_length=24),
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),
}
# POC for parsing corner radars: https://github.com/commaai/openpilot/pull/24221/
def get_radar_track_config(car_fingerprint, flags: int = 0) -> RadarTrackConfig | None:
def get_radar_track_config(car_fingerprint) -> 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)
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
return RADAR_TRACK_CONFIGS.get(radar_dbc)
def get_radar_can_parser(CP, radar_config):
@@ -84,7 +64,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, CP.flags)
self.radar_config = get_radar_track_config(CP.carFingerprint)
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,9 +9,7 @@ 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, 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
update_genesis_g90_longitudinal_tuning
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
@@ -21,8 +19,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, \
LEGACY_LONGITUDINAL_CAR, DBC, HyundaiFlags, get_platform_codes, HyundaiSafetyFlags, \
HyundaiStarPilotSafetyFlags, Buttons, kia_ev6_gt_line_longitudinal_tuning
CarControllerParams, DBC, HyundaiFlags, get_platform_codes, HyundaiSafetyFlags, \
HyundaiStarPilotSafetyFlags, Buttons, GENESIS_G90_STEER_MAX, HYUNDAI_PALISADE_2023_STEER_MAX
LongCtrlState = CarControl.Actuators.LongControlState
from opendbc.car.hyundai.fingerprints import FW_VERSIONS
@@ -46,7 +44,6 @@ 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,
@@ -94,7 +91,6 @@ 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,
@@ -134,7 +130,6 @@ 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,
@@ -156,7 +151,7 @@ class TestHyundaiFingerprint:
fingerprint = gen_empty_fingerprint()
fingerprint[1][RADAR_START_ADDR] = 8
for candidate in (CAR.HYUNDAI_SONATA, CAR.HYUNDAI_SONATA_HYBRID, CAR.KIA_XCEED_PHEV, CAR.GENESIS_G90):
for candidate in (CAR.HYUNDAI_SONATA, CAR.HYUNDAI_SONATA_HYBRID, CAR.GENESIS_G90):
CP = CarInterface.get_params(candidate, fingerprint, [], True, False, False, None)
assert CP.openpilotLongitudinalControl
assert not CP.radarUnavailable
@@ -169,58 +164,37 @@ 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] = radar_config.expected_length or 8
fingerprint[radar_config.bus][radar_addr] = 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
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
assert get_radar_track_config(CAR.HYUNDAI_IONIQ_6).start_addr == MRR35_RADAR_START_ADDR
fingerprint = gen_empty_fingerprint()
fingerprint[0][MRR35_RADAR_START_ADDR] = 8
fingerprint[1][MRR35_RADAR_START_ADDR] = 24
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[ioniq_6_hda1_radar_config.bus][MRR35_RADAR_START_ADDR] = 24
fingerprint[get_radar_track_config(CAR.HYUNDAI_IONIQ_6).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
@@ -229,22 +203,6 @@ 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)
@@ -279,26 +237,6 @@ 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
@@ -340,6 +278,7 @@ class TestHyundaiFingerprint:
g90 = CarInterface.get_params(CAR.GENESIS_G90, gen_empty_fingerprint(), [], False, False, False, None)
assert g90.safetyConfigs[-1].safetyParam & HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON
assert g90.safetyConfigs[-1].safetyParam & HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE
sonata_without_lda = CarInterface.get_params(CAR.HYUNDAI_SONATA, gen_empty_fingerprint(), [], False, False, False, None)
assert not (sonata_without_lda.safetyConfigs[-1].safetyParam & HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON)
@@ -509,54 +448,6 @@ 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)
@@ -567,47 +458,6 @@ 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)
@@ -813,7 +663,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_main_bus_lkas_parser(self):
def test_sonata_hybrid_uses_alt_bus_lkas_parser(self):
toggles = get_test_toggles()
fingerprint = gen_empty_fingerprint()
fingerprint[0][0x391] = 8
@@ -824,9 +674,9 @@ class TestHyundaiFingerprint:
car_state = CarState(CP, FPCP)
can_parsers = car_state.get_can_parsers(CP)
assert Bus.alt not in can_parsers
assert Bus.alt in can_parsers
def test_sonata_hybrid_bcm_lkas_button_event(self):
def test_sonata_hybrid_alt_bus_clu13_lkas_button_event(self):
toggles = get_test_toggles()
fingerprint = gen_empty_fingerprint()
fingerprint[0][0x391] = 8
@@ -838,139 +688,6 @@ 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,
@@ -1361,167 +1078,6 @@ 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
@@ -1612,11 +1168,11 @@ class TestHyundaiFingerprint:
assert parser.vl["FCA12"]["FCA_DrvSetState"] == 2
assert parser.vl["FCA12"]["FCA_USM"] == 2
def test_angle_steering_uses_lfa_and_adas_cmd_with_send_lfa(self):
def test_sportage_angle_steering_uses_lfa_and_adas_cmd_with_send_lfa(self):
fingerprint = gen_empty_fingerprint()
cam_can = CanBus(None, fingerprint).CAM
fingerprint[cam_can][0xCB] = 24
CP = CarInterface.get_params(CAR.HYUNDAI_SANTA_FE_HEV_5TH_GEN, fingerprint, [], False, False, False, None)
CP = CarInterface.get_params(CAR.KIA_SPORTAGE_HEV_2026, fingerprint, [], False, False, False, None)
assert CP.flags & HyundaiFlags.SEND_LFA
assert CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING
@@ -1691,84 +1247,6 @@ 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
@@ -1817,121 +1295,6 @@ 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
@@ -2112,6 +1475,44 @@ class TestHyundaiFingerprint:
]
assert hyundaicanfd.create_ioniq_6_cluster_lane_change_messages(can_bus, 5, "none") == []
def test_sportage_angle_jerk_override_is_scoped(self):
sportage = CarParams.new_message()
sportage.carFingerprint = CAR.KIA_SPORTAGE_HEV_2026
sportage.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CANFD_ANGLE_STEERING)
comparison_angle = CarParams.new_message()
comparison_angle.carFingerprint = CAR.KIA_EV6
comparison_angle.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CANFD_ANGLE_STEERING)
ioniq6 = CarParams.new_message()
ioniq6.carFingerprint = CAR.HYUNDAI_IONIQ_6
ioniq6.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT)
sportage_params = CarControllerParams(sportage)
sportage_low_speed_params = CarControllerParams(sportage, vEgoRaw=5.0)
sportage_high_speed_params = CarControllerParams(sportage, vEgoRaw=20.0)
comparison_params = CarControllerParams(comparison_angle)
ioniq6_params = CarControllerParams(ioniq6)
assert sportage_params.ANGLE_LIMITS.MAX_LATERAL_JERK < comparison_params.ANGLE_LIMITS.MAX_LATERAL_JERK
assert sportage_high_speed_params.ANGLE_LIMITS.MAX_LATERAL_JERK == sportage_params.ANGLE_LIMITS.MAX_LATERAL_JERK
assert sportage_low_speed_params.ANGLE_LIMITS.MAX_LATERAL_JERK > sportage_high_speed_params.ANGLE_LIMITS.MAX_LATERAL_JERK
assert sportage_low_speed_params.ANGLE_LIMITS.MAX_LATERAL_JERK < comparison_params.ANGLE_LIMITS.MAX_LATERAL_JERK
assert sportage_params.ANGLE_LIMITS.STEER_ANGLE_MAX > comparison_params.ANGLE_LIMITS.STEER_ANGLE_MAX
assert sportage_params.ANGLE_LIMITS.MAX_LATERAL_ACCEL > comparison_params.ANGLE_LIMITS.MAX_LATERAL_ACCEL
assert sportage_params.ANGLE_LIMITS.MAX_ANGLE_RATE > comparison_params.ANGLE_LIMITS.MAX_ANGLE_RATE
assert comparison_params.ANGLE_LIMITS.MAX_LATERAL_JERK == ioniq6_params.ANGLE_LIMITS.MAX_LATERAL_JERK
def test_g90_and_palisade_2023_steer_max_limits(self):
g90 = CarParams.new_message()
g90.carFingerprint = CAR.GENESIS_G90
assert CarControllerParams(g90).STEER_MAX == GENESIS_G90_STEER_MAX
palisade_2023 = CarParams.new_message()
palisade_2023.carFingerprint = CAR.HYUNDAI_PALISADE_2023
palisade_2023.flags = int(HyundaiFlags.CAN_CANFD_BLENDED)
assert CarControllerParams(palisade_2023).STEER_MAX == HYUNDAI_PALISADE_2023_STEER_MAX
def test_ioniq_5_canfd_aux_messages_are_optional(self):
toggles = get_test_toggles()
fingerprint = gen_empty_fingerprint()
+39 -36
View File
@@ -1,9 +1,9 @@
import re
from dataclasses import dataclass, field
from dataclasses import dataclass, field, replace
from enum import IntFlag
from opendbc.car import ACCELERATION_DUE_TO_GRAVITY, Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, uds
from opendbc.car.lateral import AngleSteeringLimits, ISO_LATERAL_ACCEL
from opendbc.car.lateral import AngleSteeringLimits, ISO_LATERAL_ACCEL, ISO_LATERAL_JERK
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.structs import CarParams
from opendbc.car.docs_definitions import CarHarness, CarDocs, CarParts, SupportType
@@ -11,23 +11,35 @@ from opendbc.car.fw_query_definitions import FwQueryConfig, Request, p16
Ecu = CarParams.Ecu
AVERAGE_ROAD_ROLL = 0.06 # conservative roll margin used by Hyundai CAN-FD angle steering safety
SPORTAGE_HEV_2026_MAX_LATERAL_ACCEL = 3.6
SPORTAGE_HEV_2026_BASE_LATERAL_JERK = 3.25
SPORTAGE_HEV_2026_LOW_SPEED_JERK_BOOST = 0.55
SPORTAGE_HEV_2026_LOW_SPEED_JERK_SPEED = 11.0
SPORTAGE_HEV_2026_LOW_SPEED_JERK_WIDTH = 5.0
SPORTAGE_HEV_2026_MAX_ANGLE_RATE = 6.5
SPORTAGE_HEV_2026_STEER_ANGLE_MAX = 220.0
HYUNDAI_MANDO_FRONT_RADAR_DBC = "hyundai_kia_mando_front_radar_generated"
HYUNDAI_MRREVO14F_RADAR_DBC = "hyundai_mrrevo14f_radar_generated"
HYUNDAI_MRR30_RADAR_DBC = "hyundai_mrr30_radar_generated"
HYUNDAI_MRR35_RADAR_DBC = "hyundai_mrr35_radar_generated"
GENESIS_G90_STEER_MAX = 461
HYUNDAI_PALISADE_2023_STEER_MAX = 485
class CarControllerParams:
ACCEL_MIN = -3.5 # m/s
ACCEL_MAX = 3.5 # m/s
ANGLE_LIMITS: AngleSteeringLimits = AngleSteeringLimits(
360,
180,
([], []),
([], []),
MAX_LATERAL_ACCEL=ISO_LATERAL_ACCEL + (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL),
MAX_LATERAL_JERK=3.0 + (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL),
MAX_LATERAL_JERK=ISO_LATERAL_JERK + (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL),
MAX_ANGLE_RATE=5,
)
ANGLE_MAX_TORQUE_REDUCTION_GAIN = 1.0
ANGLE_MIN_TORQUE_REDUCTION_GAIN = 0.6
ANGLE_ACTIVE_TORQUE_REDUCTION_GAIN = 0.6
def __init__(self, CP, vEgoRaw=100.):
self.ANGLE_LIMITS = self.ANGLE_LIMITS
@@ -54,8 +66,20 @@ class CarControllerParams:
if CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
self.STEER_THRESHOLD = 175
elif CP.flags & HyundaiFlags.CANFD:
pass
# The Sportage angle port still needs more authority in real turns than the
# fully calmed branch-wide ceiling allows, but the old low-speed jerk boost
# made the 3-20 degree band angry and ping-pongy as the car slowed down.
# Split the difference:
# - keep a calmer low-speed boost that fades out earlier
# - give the car a little more true turn headroom through accel/rate limits
if CP.carFingerprint == CAR.KIA_SPORTAGE_HEV_2026:
sportage_low_speed_weight = min(max((SPORTAGE_HEV_2026_LOW_SPEED_JERK_SPEED - vEgoRaw) / SPORTAGE_HEV_2026_LOW_SPEED_JERK_WIDTH, 0.0), 1.0)
sportage_lateral_jerk = SPORTAGE_HEV_2026_BASE_LATERAL_JERK + (SPORTAGE_HEV_2026_LOW_SPEED_JERK_BOOST * sportage_low_speed_weight)
self.ANGLE_LIMITS = replace(self.ANGLE_LIMITS,
STEER_ANGLE_MAX=SPORTAGE_HEV_2026_STEER_ANGLE_MAX,
MAX_LATERAL_ACCEL=SPORTAGE_HEV_2026_MAX_LATERAL_ACCEL + (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL),
MAX_LATERAL_JERK=sportage_lateral_jerk + (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL),
MAX_ANGLE_RATE=SPORTAGE_HEV_2026_MAX_ANGLE_RATE)
# 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.
@@ -77,12 +101,15 @@ class CarControllerParams:
self.STEER_DELTA_DOWN = 3
elif CP.flags & HyundaiFlags.CAN_CANFD_BLENDED:
self.STEER_MAX = 404
self.STEER_MAX = HYUNDAI_PALISADE_2023_STEER_MAX
self.STEER_DRIVER_ALLOWANCE = 50
self.STEER_THRESHOLD = 150
self.STEER_DELTA_UP = 2
self.STEER_DELTA_DOWN = 3
elif CP.carFingerprint == CAR.GENESIS_G90:
self.STEER_MAX = GENESIS_G90_STEER_MAX
# Default for most HKG
else:
self.STEER_MAX = 384
@@ -258,14 +285,6 @@ 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
@@ -736,18 +755,13 @@ 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=14.25, tireStiffnessFactor=0.65),
CarSpecs(mass=2055, wheelbase=2.9, steerRatio=16, tireStiffnessFactor=0.65),
flags=HyundaiFlags.EV,
radar_dbc=HYUNDAI_MRR30_RADAR_DBC,
)
@@ -755,7 +769,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=14.26, tireStiffnessFactor=0.65),
CarSpecs(mass=2055, wheelbase=2.9, steerRatio=16, tireStiffnessFactor=0.65),
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
radar_dbc=HYUNDAI_MRR30_RADAR_DBC,
)
@@ -922,22 +936,20 @@ 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,
})
@@ -945,11 +957,6 @@ 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)
@@ -1106,7 +1113,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_XCEED_PHEV, CAR.KIA_SELTOS],
CAR.KIA_CEED, CAR.KIA_SELTOS],
Ecu.fwdRadar: [CAR.HYUNDAI_KONA_NON_SCC],
},
extra_ecus=[
@@ -1137,7 +1144,6 @@ 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,
@@ -1147,7 +1153,6 @@ 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,
}
@@ -1165,6 +1170,4 @@ 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()
-13
View File
@@ -22,7 +22,6 @@ 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
@@ -134,7 +133,6 @@ 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
@@ -176,11 +174,8 @@ 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
@@ -216,9 +211,6 @@ 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
@@ -271,10 +263,6 @@ 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
@@ -509,7 +497,6 @@ 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, DT_CTRL, make_tester_present_msg
from opendbc.car import Bus, 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,9 +26,14 @@ 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.epb_resume_frames_remaining = -1
self.last_standstill_frame = 0
self.prev_cruise_state = 0
self.sng_acc_resume_cnt = 0
self.standstill_start = 0
def update(self, CC, CS, now_nanos, starpilot_toggles):
actuators = CC.actuators
@@ -65,9 +70,8 @@ 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, subaru_sng_manual_parking_brake)
throttle_cmd, speed_cmd = self.stop_and_go(CC, CS)
# *** longitudinal ***
@@ -106,11 +110,7 @@ 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))
if self.frame % 2 == 0:
can_sends.append(subarucan.create_preglobal_brake_pedal(self.packer, CS.brake_pedal_msg,
speed_cmd))
can_sends.append(subarucan.create_preglobal_throttle(self.packer, CS.throttle_msg["COUNTER"] + 1, CS.throttle_msg, throttle_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,11 +124,9 @@ 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:
@@ -168,37 +166,49 @@ class CarController(CarControllerBase):
self.frame += 1
return new_actuators, can_sends
def stop_and_go(self, CC, CS, manual_parking_brake=False):
throttle_cmd = False
speed_cmd = False
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
if not CC.enabled or not CC.hudControl.leadVisible:
return throttle_cmd, speed_cmd
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
close_distance = CS.close_distance
if not CS.out.standstill:
self.last_standstill_frame = self.frame
if not CS.out.standstill:
self.manual_hold = False
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
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
if manual_parking_brake or not (self.CP.flags & SubaruFlags.PREGLOBAL):
speed_cmd = in_standstill_hold
if trigger_resume:
self.sng_acc_resume = 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 CC.enabled and CS.car_follow == 1 and CS.out.standstill and self.frame > self.standstill_start + 50:
speed_cmd = True
throttle_cmd = self.epb_resume_frames_remaining > 0
if self.epb_resume_frames_remaining > 0:
self.epb_resume_frames_remaining -= 1
if CS.out.standstill and not self.prev_standstill:
self.standstill_start = self.frame
self.prev_close_distance = close_distance
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
return throttle_cmd, speed_cmd
@@ -358,19 +358,6 @@ 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,57 +1,4 @@
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,7 +59,6 @@ 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
fp_ret.pedalMaxRegen = cs.pccEvent == "pedalMaxRegen"
fp_ret.teslaCCEngaged = cs.pccEvent == "teslaCCEngaged"
fp_ret.teslaCCDisengaged = cs.pccEvent == "teslaCCDisengaged"
fp_ret.teslaCCNotArmed = (
ret.pedalMaxRegen = cs.pccEvent == "pedalMaxRegen"
ret.teslaCCEngaged = cs.pccEvent == "teslaCCEngaged"
ret.teslaCCDisengaged = cs.pccEvent == "teslaCCDisengaged"
ret.teslaCCNotArmed = (
not nap_conf.use_pedal and
cs.cruiseEnabled and
cs.enableLongControl and
cs.di_cruise_state not in ("STANDBY", "ENABLED")
)
fp_ret.pedalLongActive = cs.enableLongControl and nap_conf.use_pedal
ret.pedalLongActive = cs.enableLongControl and nap_conf.use_pedal
return ret, fp_ret
@@ -7,7 +7,6 @@ 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]:
@@ -30,7 +29,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(SAFETY_TESLA_PREAP, safety_flags)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.teslaPreap, safety_flags)]
ret.radarUnavailable = not nap_conf.radar_enabled
ret.steerControlType = structs.CarParams.SteerControlType.angle
ret.openpilotLongitudinalControl = use_pedal
-3
View File
@@ -22,14 +22,12 @@ 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,
@@ -165,7 +163,6 @@ 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,17 +4,9 @@ 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"""
@@ -31,12 +23,6 @@ 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,13 +8,9 @@ from collections.abc import Callable
from typing import Any
from cereal import custom
from opendbc.can import CANParser
from opendbc.car import Bus, DT_CTRL, CanData, structs
from opendbc.car import 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
@@ -78,7 +74,6 @@ 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,
@@ -165,53 +160,6 @@ 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,7 +17,6 @@ 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]
@@ -75,7 +74,6 @@ 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]
@@ -98,7 +96,6 @@ 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,7 +69,6 @@ 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"
@@ -25,8 +25,7 @@ ACCEL_WINDUP_LIMIT = 4.0 * DT_CTRL * 3 # m/s^2 / frame
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
PRIUS_POSITIVE_FEEDFORWARD_SCALE = 0.5
MAX_PITCH_COMPENSATION = 1.5 # m/s^2
TOYOTA_COAST_BRAKE_MIN_SPEED = 15.0 # m/s
@@ -44,7 +43,6 @@ 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"
@@ -67,11 +65,6 @@ 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:
@@ -149,25 +142,6 @@ def limit_interceptor_stopping_accel(pcm_accel_cmd: float, target_accel: float,
return max(pcm_accel_cmd, max(stop_floor, planner_floor))
def limit_prius_stopping_accel(pcm_accel_cmd: float, target_accel: float, stopping: bool, v_ego: float, lead_visible: bool) -> float:
if not stopping or pcm_accel_cmd >= 0.0 or v_ego >= 1.5:
return pcm_accel_cmd
# Prius can hold onto a stale full negative stop command at standstill even after the
# planner has already softened. Keep enough brake to hold the stop, but let the command
# unwind toward the live planner target so launches are not delayed and stop transitions
# are less abrupt.
if target_accel <= -1.8:
return pcm_accel_cmd
stop_floor = float(np.interp(v_ego,
[0.0, 0.2, 0.5, 0.9, 1.5],
[-0.96, -1.00, -1.08, -1.18, -1.35] if lead_visible else [-0.84, -0.88, -0.96, -1.08, -1.24]))
target_buffer = float(np.interp(v_ego, [0.0, 0.5, 1.5], [0.06, 0.10, 0.16]))
planner_floor = float(target_accel) - target_buffer
return max(pcm_accel_cmd, max(stop_floor, planner_floor))
class CarController(CarControllerBase):
def __init__(self, dbc_names, CP):
super().__init__(dbc_names, CP)
@@ -199,23 +173,18 @@ 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 CS.out.standstill:
return 0.12 if self.accel > 0.0 else 0.0
if self.CP.minEnableSpeed < 0.0:
return 0.12 if CS.out.standstill and 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 in (CAR.TOYOTA_COROLLA, CAR.TOYOTA_MATRIX_RETROFIT):
elif self.CP.carFingerprint == CAR.TOYOTA_COROLLA:
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]))
@@ -249,27 +218,6 @@ 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
@@ -363,9 +311,6 @@ 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
@@ -441,8 +386,9 @@ 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 *= get_prius_positive_feedforward_scale(CS.out.vEgo)
feedforward *= PRIUS_POSITIVE_FEEDFORWARD_SCALE
pcm_accel_cmd = self.long_pid.update(error_future,
speed=CS.out.vEgo,
@@ -464,8 +410,6 @@ class CarController(CarControllerBase):
if self.CP.enableGasInterceptorDEPRECATED:
pcm_accel_cmd = limit_interceptor_pcm_accel(pcm_accel_cmd, actuators.accel, stopping, CS.out.vEgo)
pcm_accel_cmd = limit_interceptor_stopping_accel(pcm_accel_cmd, actuators.accel, stopping, CS.out.vEgo, bool(hud_control.leadVisible))
elif self.CP.carFingerprint == CAR.TOYOTA_PRIUS:
pcm_accel_cmd = limit_prius_stopping_accel(pcm_accel_cmd, actuators.accel, stopping, CS.out.vEgo, lead)
pcm_accel_cmd = float(np.clip(pcm_accel_cmd, self.params.ACCEL_MIN, self.params.ACCEL_MAX))
@@ -80,8 +80,6 @@ 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]
@@ -213,9 +211,6 @@ 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,10 +4,6 @@ from opendbc.car.toyota.values import CAR
Ecu = CarParams.Ecu
FINGERPRINTS = {
CAR.TOYOTA_MATRIX_RETROFIT: [{}],
}
FW_VERSIONS = {
CAR.TOYOTA_AVALON: {
(Ecu.abs, 0x7b0, None): [
+3 -15
View File
@@ -2,13 +2,11 @@ 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, SECOC_CAR, NO_DSU_CAR, \
from opendbc.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_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
@@ -68,11 +66,10 @@ 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.14
ret.steerActuatorDelay = 0.25
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg=0.3)
elif candidate in (CAR.LEXUS_RX, CAR.LEXUS_RX_TSS2):
@@ -140,13 +137,6 @@ 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
@@ -155,9 +145,7 @@ 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
prius_long_defaults = candidate == CAR.TOYOTA_PRIUS and ret.openpilotLongitudinalControl
if candidate in TSS2_CAR or ret.enableGasInterceptorDEPRECATED or prius_long_defaults:
if candidate in TSS2_CAR or ret.enableGasInterceptorDEPRECATED:
ret.flags |= ToyotaFlags.RAISED_ACCEL_LIMIT.value
ret.vEgoStopping = 0.25
@@ -2,21 +2,18 @@ from types import SimpleNamespace
from hypothesis import given, settings, strategies as st
from opendbc.car import Bus, structs
from opendbc.car import Bus
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, get_prius_positive_feedforward_scale, limit_interceptor_pcm_accel, \
limit_interceptor_stopping_accel, limit_prius_stopping_accel, update_permit_braking
from opendbc.car.toyota.carcontroller import CarController, limit_interceptor_pcm_accel, limit_interceptor_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, \
ToyotaFlags, ToyotaSafetyFlags, get_platform_codes
from opendbc.safety import ALTERNATIVE_EXPERIENCE
from openpilot.common.params import Params
get_platform_codes
Ecu = CarParams.Ecu
@@ -42,43 +39,6 @@ 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}
@@ -292,22 +252,6 @@ class TestToyotaCarController:
assert update_permit_braking(False, 0.10, True, True, 25.0, False) is True
assert update_permit_braking(False, 0.10, False, False, 25.0, False) is True
def test_prius_stopping_accel_unwinds_stale_stop_hold(self):
limited = limit_prius_stopping_accel(-3.28, -0.05, True, 0.0, True)
assert -1.5 < limited < 0.0
def test_prius_stopping_accel_keeps_hard_stop_commands(self):
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)
@@ -344,33 +288,6 @@ 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
@@ -397,20 +314,6 @@ 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
@@ -489,7 +392,6 @@ 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,38 +86,6 @@ 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,
+2 -10
View File
@@ -57,7 +57,6 @@ class ToyotaSafetyFlags(IntFlag):
LTA = (4 << 8)
SECOC = (8 << 8)
LONG_FILTER = (16 << 8)
GAS_INTERCEPTOR = (32 << 8)
class ToyotaFlags(IntFlag):
@@ -76,7 +75,6 @@ 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
@@ -203,11 +201,6 @@ 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(
[
@@ -555,7 +548,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_MATRIX_RETROFIT, CAR.TOYOTA_HIGHLANDER, CAR.TOYOTA_SIENNA, CAR.LEXUS_IS, CAR.TOYOTA_ALPHARD_TSS2],
Ecu.abs: [CAR.TOYOTA_RAV4, CAR.TOYOTA_COROLLA, 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],
@@ -596,8 +589,7 @@ 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.TOYOTA_MATRIX_RETROFIT: 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.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,12 +62,6 @@ 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
@@ -152,7 +146,6 @@ 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
@@ -180,14 +173,9 @@ 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,24 +37,11 @@ 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,12 +82,6 @@ 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
@@ -172,7 +166,6 @@ 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
@@ -200,14 +193,9 @@ 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,24 +650,11 @@ 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,24 +650,11 @@ 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,24 +650,11 @@ 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";
+6 -35
View File
@@ -61,7 +61,6 @@ 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;
@@ -366,10 +365,9 @@ 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 && 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 stock_auto_hold_brake_allowed = gm_volt_auto_hold && !vehicle_moving && !gas_pressed_prev;
bool violation = false;
violation |= !(get_longitudinal_allowed() || stock_auto_hold_brake_allowed || stock_one_pedal_brake_allowed) && (brake != 0);
violation |= !(get_longitudinal_allowed() || stock_auto_hold_brake_allowed) && (brake != 0);
if (stock_auto_hold_brake_allowed && !get_longitudinal_allowed()) {
violation |= brake > GM_VOLT_AUTO_HOLD_MAX_BRAKE;
} else {
@@ -614,11 +612,6 @@ 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},
@@ -642,12 +635,6 @@ 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
@@ -712,10 +699,6 @@ 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;
@@ -747,11 +730,6 @@ 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) {
@@ -762,10 +740,9 @@ 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_stock_brake) {
if (gm_volt_auto_hold) {
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);
@@ -787,22 +764,16 @@ static safety_config gm_init(uint16_t param) {
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_LONG_TX_MSGS);
}
} else {
if (gm_volt_stock_brake && gm_sdgm) {
if (gm_volt_auto_hold && gm_sdgm) {
ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_SDGM_VOLT_AUTO_HOLD_TX_MSGS);
} else if (gm_no_camera) {
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) {
if (gm_volt_auto_hold) {
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_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) {
if (gm_volt_auto_hold) {
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);
+14 -11
View File
@@ -70,13 +70,6 @@ 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) {
@@ -246,9 +239,10 @@ static void hyundai_rx_hook(const CANPacket_t *msg) {
static bool hyundai_tx_hook(const CANPacket_t *msg) {
const TorqueSteeringLimits HYUNDAI_STEERING_LIMITS = HYUNDAI_LIMITS(384, 3, 7);
const TorqueSteeringLimits HYUNDAI_STEERING_LIMITS_G90 = HYUNDAI_LIMITS(461, 3, 7);
const TorqueSteeringLimits HYUNDAI_STEERING_LIMITS_ALT = HYUNDAI_LIMITS(270, 2, 3);
const TorqueSteeringLimits HYUNDAI_STEERING_LIMITS_ALT_2 = HYUNDAI_LIMITS(170, 2, 3);
const TorqueSteeringLimits HYUNDAI_STEERING_LIMITS_CAN_CANFD_BLENDED = HYUNDAI_LIMITS(404, 2, 3);
const TorqueSteeringLimits HYUNDAI_STEERING_LIMITS_CAN_CANFD_BLENDED = HYUNDAI_LIMITS(485, 2, 3);
bool tx = true;
@@ -297,7 +291,9 @@ static bool hyundai_tx_hook(const CANPacket_t *msg) {
int desired_torque = ((GET_BYTES(msg, 0, 4) >> 16) & 0x7ffU) - 1024U;
bool steer_req = GET_BIT(msg, 27U);
const TorqueSteeringLimits limits = hyundai_can_canfd_blended ? HYUNDAI_STEERING_LIMITS_CAN_CANFD_BLENDED :
const bool hyundai_g90_limits = hyundai_has_lda_button && hyundai_aol_lkas_on_engage; // G90 path sets both bits
const TorqueSteeringLimits limits = hyundai_g90_limits ? HYUNDAI_STEERING_LIMITS_G90 :
hyundai_can_canfd_blended ? HYUNDAI_STEERING_LIMITS_CAN_CANFD_BLENDED :
hyundai_alt_limits_2 ? HYUNDAI_STEERING_LIMITS_ALT_2 :
hyundai_alt_limits ? HYUNDAI_STEERING_LIMITS_ALT : HYUNDAI_STEERING_LIMITS;
@@ -329,6 +325,13 @@ 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 +559,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 hyundai_longitudinal ? BUILD_SAFETY_CFG(hyundai_legacy_rx_checks, HYUNDAI_LONG_TX_MSGS) :
BUILD_SAFETY_CFG(hyundai_legacy_rx_checks, HYUNDAI_TX_MSGS);
return BUILD_SAFETY_CFG(hyundai_legacy_rx_checks, HYUNDAI_TX_MSGS);
}
const safety_hooks hyundai_hooks = {
@@ -190,7 +190,7 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
.has_steer_req_tolerance = true,
};
const AngleSteeringLimits HYUNDAI_CANFD_ANGLE_STEERING_LIMITS = {
.max_angle = 3600,
.max_angle = 1800,
.angle_deg_to_can = 10,
.frequency = 100U,
};
@@ -221,8 +221,7 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
}
// steering
const unsigned int steer_addr = (hyundai_canfd_lka_steering && (hyundai_canfd_angle_steering || !hyundai_longitudinal)) ?
hyundai_canfd_get_lka_addr() : 0x12aU;
const unsigned int steer_addr = (hyundai_canfd_lka_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;
@@ -231,16 +230,9 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
int desired_angle = (msg->data[11] << 6U) | (msg->data[10] >> 2U);
desired_angle = to_signed(desired_angle, 14);
// ADAS_ACIAnglTqRedcGainVal: bit 96, 8 bits, unsigned. Raw 0-250 valid, 251-255 reserved.
const uint8_t gain_raw = msg->data[12];
bool gain_violation = gain_raw > 250U;
if (!steer_angle_req && (gain_raw != 0U)) {
gain_violation = true;
}
if (steer_angle_cmd_checks_vm(desired_angle, steer_angle_req,
HYUNDAI_CANFD_ANGLE_STEERING_LIMITS,
HYUNDAI_CANFD_ANGLE_STEERING_PARAMS) || gain_violation) {
HYUNDAI_CANFD_ANGLE_STEERING_PARAMS)) {
tx = false;
}
} else {
@@ -335,21 +327,6 @@ 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)
@@ -398,11 +375,7 @@ static safety_config hyundai_canfd_init(uint16_t param) {
};
SET_RX_CHECKS(hyundai_canfd_lka_steering_long_rx_checks, 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);
}
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS, ret);
} else {
// Longitudinal checks for LFA steering
@@ -24,7 +24,6 @@
#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
@@ -64,10 +63,6 @@
{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 }}}, \
@@ -77,7 +72,6 @@
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];
@@ -233,12 +227,6 @@ 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)
};
@@ -251,9 +239,6 @@ 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);
@@ -265,7 +250,6 @@ 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,16 +17,7 @@
#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) {
@@ -90,12 +81,8 @@ 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[] = {
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()
{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}
};
// TODO: do checksum and counter checks after adding the signals to the outback dbc file
@@ -108,14 +95,9 @@ 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);
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;
return BUILD_SAFETY_CFG(subaru_preglobal_rx_checks, SUBARU_PG_TX_MSGS);
}
const safety_hooks subaru_preglobal_hooks = {
+3 -85
View File
@@ -69,9 +69,6 @@
{.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;
@@ -93,12 +90,6 @@ 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;
@@ -159,9 +150,7 @@ 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);
if (!enable_gas_interceptor) {
gas_pressed = !GET_BIT(msg, 4U); // PCM_CRUISE.GAS_RELEASED
}
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)
@@ -192,14 +181,6 @@ 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;
}
}
}
@@ -370,17 +351,6 @@ 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
@@ -414,16 +384,6 @@ 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
};
@@ -436,7 +396,6 @@ 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;
@@ -447,13 +406,8 @@ 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) {
@@ -464,12 +418,6 @@ 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);
@@ -490,16 +438,8 @@ 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
};
if (enable_gas_interceptor) {
SET_RX_CHECKS(toyota_lta_interceptor_rx_checks, ret);
} else {
SET_RX_CHECKS(toyota_lta_rx_checks, ret);
}
SET_RX_CHECKS(toyota_lta_rx_checks, ret);
} else {
static RxCheck toyota_lka_rx_checks[] = {
TOYOTA_RX_CHECKS(false)
@@ -507,20 +447,8 @@ 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 (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) {
if (!toyota_alt_brake) {
SET_RX_CHECKS(toyota_lka_rx_checks, ret);
} else {
SET_RX_CHECKS(toyota_lka_alt_brake_rx_checks, ret);
@@ -530,20 +458,10 @@ 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,
+4 -6
View File
@@ -973,8 +973,8 @@ class SafetyTest(SafetyTestBase):
continue
if {attr, current_test}.issubset({'TestGmCameraSafety', 'TestGmCameraLongitudinalSafety', 'TestGmAscmSafety',
'TestGmCameraEVSafety', 'TestGmCameraLongitudinalEVSafety', 'TestGmAscmEVSafety',
'TestGmInterceptorSafety', 'TestGmBolt2022PedalFrictionSafety',
'TestGmCcLongitudinalSafety', 'TestGmCcLongitudinalPandaSchedSafety'}):
'TestGmInterceptorSafety', 'TestGmCcLongitudinalSafety',
'TestGmCcLongitudinalPandaSchedSafety'}):
continue
if attr.startswith('TestFord') and current_test.startswith('TestFord'):
continue
@@ -984,8 +984,7 @@ class SafetyTest(SafetyTestBase):
continue
if {attr, current_test}.issubset({'TestHyundaiLongitudinalSafety', 'TestHyundaiLongitudinalSafetyCameraSCC',
'TestHyundaiSafetyFCEVLong', 'TestHyundaiLongitudinalAolLkasOnEngageSafety',
'TestHyundaiCanCanfdBlendedLongitudinalSafety',
'TestHyundaiLegacyLongitudinalSafetyHEV'}):
'TestHyundaiCanCanfdBlendedLongitudinalSafety'}):
continue
volkswagen_shared = ('TestVolkswagenMqb', 'TestVolkswagenMlb')
if attr.startswith(volkswagen_shared) and current_test.startswith(volkswagen_shared):
@@ -1018,8 +1017,7 @@ class SafetyTest(SafetyTestBase):
if attr.startswith('TestHyundaiLongitudinal') or attr in ('TestHyundaiSafetyFCEVLong',
'TestHyundaiLongitudinalAolLkasOnEngageSafety',
'TestHyundaiCanCanfdBlendedLongitudinalSafety',
'TestHyundaiLegacyLongitudinalSafetyHEV'):
'TestHyundaiCanCanfdBlendedLongitudinalSafety'):
# 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])
+2 -141
View File
@@ -307,28 +307,6 @@ 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
@@ -469,71 +447,6 @@ 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
@@ -633,62 +546,18 @@ class TestGmVoltAutoHoldCameraSafety(TestGmCameraSafetyBase):
values = {"FrictionBrakeCmd": -brake}
return self.packer_chassis.make_can_msg_safety("EBCMFrictionBrakeCmd", 0, values)
def test_standstill_brake_allowed_without_controls_when_main_on(self):
def test_standstill_brake_allowed_without_controls(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)))
@@ -709,21 +578,13 @@ class TestGmVoltAutoHoldSdgmSafety(TestGmSafetyBase):
values = {"FrictionBrakeCmd": -brake}
return self.packer_chassis.make_can_msg_safety("EBCMFrictionBrakeCmd", 2, values)
def test_standstill_brake_allowed_without_controls_when_main_on(self):
def test_standstill_brake_allowed_without_controls(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)))
@@ -151,6 +151,17 @@ class TestHyundaiSafetyAltLimits2(TestHyundaiSafety):
self.safety.init_tests()
class TestHyundaiSafetyGenesisG90(TestHyundaiSafety):
MAX_TORQUE_LOOKUP = [0], [461]
def setUp(self):
self.packer = CANPackerSafety("hyundai_kia_generic")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai,
HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON | HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE)
self.safety.init_tests()
class TestHyundaiSafetyCameraSCC(TestHyundaiSafety):
BUTTONS_TX_BUS = 2 # tx on 2, rx on 0
SCC_BUS = 2 # rx on 2
@@ -213,7 +224,7 @@ class TestHyundaiCanCanfdBlendedSafety(TestHyundaiSafety):
FWD_BLACKLISTED_ADDRS = {2: [0x340, 0x485, 0x364]}
MAX_RATE_UP = 2
MAX_RATE_DOWN = 3
MAX_TORQUE_LOOKUP = [0], [404]
MAX_TORQUE_LOOKUP = [0], [485]
def setUp(self):
self.packer = CANPackerSafety("hyundai_palisade_2023_generated")
@@ -416,14 +427,6 @@ 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")
@@ -174,7 +174,7 @@ class TestHyundaiCanfdAngleSteering(HyundaiButtonBase, common.CarSafetyTest):
BUTTONS_TX_BUS = 2
LATERAL_FREQUENCY = 100
STANDSTILL_THRESHOLD = 12
STEER_ANGLE_MAX = 360
STEER_ANGLE_MAX = 180
DEG_TO_CAN = 10
GAS_MSG = ("ACCELERATOR_ALT", "ACCELERATOR_PEDAL")
SAFETY_PARAM = HyundaiSafetyFlags.CANFD_ANGLE_STEERING | HyundaiSafetyFlags.CAMERA_SCC | HyundaiSafetyFlags.HYBRID_GAS
@@ -248,7 +248,7 @@ class TestHyundaiCanfdAngleSteering(HyundaiButtonBase, common.CarSafetyTest):
checksum = sig_checksum.calc_checksum(addr, sig_checksum, dat)
_set_value(dat, sig_checksum, checksum)
def _angle_cmd_msg(self, angle, enabled, increment_timer=True, gain_raw=250):
def _angle_cmd_msg(self, angle, enabled, increment_timer=True):
if increment_timer:
self.safety.set_timer(self.angle_cmd_cnt * int(1e6 / self.LATERAL_FREQUENCY))
self.angle_cmd_cnt += 1
@@ -272,7 +272,7 @@ class TestHyundaiCanfdAngleSteering(HyundaiButtonBase, common.CarSafetyTest):
dat[9] = (dat[9] & ~0x30) | (((2 if enabled else 1) & 0x3) << 4)
dat[10] = (dat[10] & 0x03) | ((desired_angle & 0x3F) << 2)
dat[11] = (desired_angle >> 6) & 0xFF
dat[12] = gain_raw if enabled or gain_raw != 250 else 0
dat[12] = 250 if enabled else 0
self._update_checksum(addr, dat)
return libsafety_py.make_CANPacket(addr, 0, bytes(dat))
@@ -335,19 +335,6 @@ class TestHyundaiCanfdAngleSteering(HyundaiButtonBase, common.CarSafetyTest):
self.assertFalse(self._tx(self._angle_cmd_msg(0, True, increment_timer=False)))
self.assertTrue(self._tx(self._angle_cmd_msg(0, True, increment_timer=False)))
def test_angle_torque_reduction_gain_limits(self):
if self.__class__.__name__ != "TestHyundaiCanfdAngleSteering":
return
self.safety.set_controls_allowed(True)
self._reset_speed_measurement(1)
self._set_prev_desired_angle(0)
self.assertTrue(self._tx(self._angle_cmd_msg(0, True, gain_raw=250)))
self._set_prev_desired_angle(0)
self.assertFalse(self._tx(self._angle_cmd_msg(0, True, gain_raw=251)))
self._set_prev_desired_angle(0)
self.assertFalse(self._tx(self._angle_cmd_msg(0, False, gain_raw=1)))
class TestHyundaiCanfdAngleSteeringLfaAlt(TestHyundaiCanfdAngleSteering):
@@ -559,61 +546,6 @@ 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,7 +16,6 @@ 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
@@ -183,12 +182,6 @@ 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,10 +70,5 @@ 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.tesla.preap.interface import SAFETY_TESLA_PREAP
from opendbc.car.structs import CarParams
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(SAFETY_TESLA_PREAP, param)
self.safety.set_safety_hooks(CarParams.SafetyModel.teslaPreap, param)
self.safety.init_tests()
@staticmethod
@@ -9,7 +9,6 @@ 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
@@ -17,8 +16,6 @@ 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):
@@ -97,30 +94,6 @@ 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],
@@ -298,47 +271,6 @@ 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
@@ -466,5 +398,7 @@ 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()
-4
View File
@@ -169,10 +169,6 @@ 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 = [
+1 -13
View File
@@ -27,21 +27,9 @@
#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) {
@@ -188,7 +176,7 @@ static void tick_handler(void) {
const bool recent_heartbeat = heartbeat_counter == 0U;
// tick drivers at 1Hz
bool started = panda_ignition_line() || ignition_can;
bool started = harness_check_ignition() || ignition_can;
bootkick_tick(started, recent_heartbeat);
// increase heartbeat counter and cap it at the uint32 limit
+1 -1
View File
@@ -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)(panda_ignition_line());
health->ignition_line_pkt = (uint8_t)(harness_check_ignition());
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1,2 +1,2 @@
extern const uint8_t gitversion[19];
const uint8_t gitversion[19] = "DEV-40b54686-DEBUG";
const uint8_t gitversion[19] = "DEV-2486728e-DEBUG";
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More