comma body
- -body
+you
+Play Sounds
-diff --git a/.vscode/launch.json b/.vscode/launch.json index f090061c42..151b757dab 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -52,6 +52,9 @@ "type": "lldb", "request": "attach", "pid": "${command:pickMyProcess}", + "sourceMap": { + ".": "${workspaceFolder}/opendbc/safety" + }, "initCommands": [ "script import time; time.sleep(3)" ] diff --git a/cereal/SConscript b/cereal/SConscript index 73dc61844b..de7ca0d721 100644 --- a/cereal/SConscript +++ b/cereal/SConscript @@ -4,7 +4,7 @@ cereal_dir = Dir('.') gen_dir = Dir('gen') # Build cereal -schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp', 'custom.capnp'] +schema_files = ['log.capnp', 'car.capnp', 'deprecated.capnp', 'custom.capnp'] env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files], schema_files, f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/") diff --git a/cereal/legacy.capnp b/cereal/deprecated.capnp similarity index 71% rename from cereal/legacy.capnp rename to cereal/deprecated.capnp index a8fa5e4a1f..45ce25c682 100644 --- a/cereal/legacy.capnp +++ b/cereal/deprecated.capnp @@ -3,7 +3,7 @@ $Cxx.namespace("cereal"); @0x80ef1ec4889c2a63; -# legacy.capnp: a home for deprecated structs +# deprecated.capnp: a home for deprecated structs struct LogRotate @0x9811e1f38f62f2d1 { segmentNum @0 :Int32; @@ -571,4 +571,219 @@ struct LidarPts @0xe3d6685d4e9d8f7a { pkt @4 :Data; } +struct LiveTracksDEPRECATED @0xb16f60103159415a { + trackId @0 :Int32; + dRel @1 :Float32; + yRel @2 :Float32; + vRel @3 :Float32; + aRel @4 :Float32; + timeStamp @5 :Float32; + status @6 :Float32; + currentTime @7 :Float32; + stationary @8 :Bool; + oncoming @9 :Bool; +} +struct LiveMpcData @0x92a5e332a85f32a0 { + x @0 :List(Float32); + y @1 :List(Float32); + psi @2 :List(Float32); + curvature @3 :List(Float32); + qpIterations @4 :UInt32; + calculationTime @5 :UInt64; + cost @6 :Float64; +} + +struct LiveLongitudinalMpcData @0xe7e17c434f865ae2 { + xEgo @0 :List(Float32); + vEgo @1 :List(Float32); + aEgo @2 :List(Float32); + xLead @3 :List(Float32); + vLead @4 :List(Float32); + aLead @5 :List(Float32); + aLeadTau @6 :Float32; # lead accel time constant + qpIterations @7 :UInt32; + mpcId @8 :UInt32; + calculationTime @9 :UInt64; + cost @10 :Float64; +} + +struct DriverStateDEPRECATED @0xb83c6cc593ed0a00 { + frameId @0 :UInt32; + modelExecutionTime @14 :Float32; + dspExecutionTime @16 :Float32; + rawPredictions @15 :Data; + + faceOrientation @3 :List(Float32); + facePosition @4 :List(Float32); + faceProb @5 :Float32; + leftEyeProb @6 :Float32; + rightEyeProb @7 :Float32; + leftBlinkProb @8 :Float32; + rightBlinkProb @9 :Float32; + faceOrientationStd @11 :List(Float32); + facePositionStd @12 :List(Float32); + sunglassesProb @13 :Float32; + poorVision @17 :Float32; + partialFace @18 :Float32; + distractedPose @19 :Float32; + distractedEyes @20 :Float32; + eyesOnRoad @21 :Float32; + phoneUse @22 :Float32; + occludedProb @23 :Float32; + + readyProb @24 :List(Float32); + notReadyProb @25 :List(Float32); + + irPwrDEPRECATED @10 :Float32; + descriptorDEPRECATED @1 :List(Float32); + stdDEPRECATED @2 :Float32; +} + +struct NavModelData @0xac3de5c437be057a { + frameId @0 :UInt32; + locationMonoTime @6 :UInt64; + modelExecutionTime @1 :Float32; + dspExecutionTime @2 :Float32; + features @3 :List(Float32); + # predicted future position + position @4 :XYData; + desirePrediction @5 :List(Float32); + + # All SI units and in device frame + struct XYData @0xbe09e615b2507e26 { + x @0 :List(Float32); + y @1 :List(Float32); + xStd @2 :List(Float32); + yStd @3 :List(Float32); + } +} + +struct AndroidBuildInfo @0xfe2919d5c21f426c { + board @0 :Text; + bootloader @1 :Text; + brand @2 :Text; + device @3 :Text; + display @4 :Text; + fingerprint @5 :Text; + hardware @6 :Text; + host @7 :Text; + id @8 :Text; + manufacturer @9 :Text; + model @10 :Text; + product @11 :Text; + radioVersion @12 :Text; + serial @13 :Text; + supportedAbis @14 :List(Text); + tags @15 :Text; + time @16 :Int64; + type @17 :Text; + user @18 :Text; + + versionCodename @19 :Text; + versionRelease @20 :Text; + versionSdk @21 :Int32; + versionSecurityPatch @22 :Text; +} + +struct AndroidSensor @0x9b513b93a887dbcd { + id @0 :Int32; + name @1 :Text; + vendor @2 :Text; + version @3 :Int32; + handle @4 :Int32; + type @5 :Int32; + maxRange @6 :Float32; + resolution @7 :Float32; + power @8 :Float32; + minDelay @9 :Int32; + fifoReservedEventCount @10 :UInt32; + fifoMaxEventCount @11 :UInt32; + stringType @12 :Text; + maxDelay @13 :Int32; +} + +struct IosBuildInfo @0xd97e3b28239f5580 { + appVersion @0 :Text; + appBuild @1 :UInt32; + osVersion @2 :Text; + deviceModel @3 :Text; +} + +enum FrameTypeDEPRECATED @0xa37f0d8558e193fd { + unknown @0; + neo @1; + chffrAndroid @2; + front @3; +} + +struct AndroidCaptureResult @0xbcc3efbac41d2048 { + sensitivity @0 :Int32; + frameDuration @1 :Int64; + exposureTime @2 :Int64; + rollingShutterSkew @3 :UInt64; + colorCorrectionTransform @4 :List(Int32); + colorCorrectionGains @5 :List(Float32); + displayRotation @6 :Int8; +} + +enum UsbPowerModeDEPRECATED @0xa8883583b32c9877 { + none @0; + client @1; + cdp @2; + dcp @3; +} + +struct LateralINDIState @0x939463348632375e { + active @0 :Bool; + steeringAngleDeg @1 :Float32; + steeringRateDeg @2 :Float32; + steeringAccelDeg @3 :Float32; + rateSetPoint @4 :Float32; + accelSetPoint @5 :Float32; + accelError @6 :Float32; + delayedOutput @7 :Float32; + delta @8 :Float32; + output @9 :Float32; + saturated @10 :Bool; + steeringAngleDesiredDeg @11 :Float32; + steeringRateDesiredDeg @12 :Float32; +} + +struct LateralLQRState @0x9024e2d790c82ade { + active @0 :Bool; + steeringAngleDeg @1 :Float32; + i @2 :Float32; + output @3 :Float32; + lqrOutput @4 :Float32; + saturated @5 :Bool; + steeringAngleDesiredDeg @6 :Float32; +} + +struct LateralCurvatureState @0xad9d8095c06f7c61 { + active @0 :Bool; + actualCurvature @1 :Float32; + desiredCurvature @2 :Float32; + error @3 :Float32; + p @4 :Float32; + i @5 :Float32; + f @6 :Float32; + output @7 :Float32; + saturated @8 :Bool; +} + +struct LateralPlannerSolution @0x84caeca5a6b4acfe { + x @0 :List(Float32); + y @1 :List(Float32); + yaw @2 :List(Float32); + yawRate @3 :List(Float32); + xStd @4 :List(Float32); + yStd @5 :List(Float32); + yawStd @6 :List(Float32); + yawRateStd @7 :List(Float32); +} + +struct GpsTrajectory @0x8cfeb072f5301000 { + x @0 :List(Float32); + y @1 :List(Float32); +} diff --git a/cereal/log.capnp b/cereal/log.capnp index 1ad9430db8..cf91e017e6 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -2,7 +2,7 @@ using Cxx = import "./include/c++.capnp"; $Cxx.namespace("cereal"); using Car = import "car.capnp"; -using Legacy = import "legacy.capnp"; +using Deprecated = import "deprecated.capnp"; using Custom = import "custom.capnp"; @0xf3b1f17e25a4285b; @@ -68,12 +68,12 @@ struct OnroadEvent @0xc4fa6047f024e718 { longitudinalManeuver @30; steerTempUnavailableSilent @31; resumeRequired @32; - preDriverDistracted @33; - promptDriverDistracted @34; - driverDistracted @35; - preDriverUnresponsive @36; - promptDriverUnresponsive @37; - driverUnresponsive @38; + driverDistracted1 @33; + driverDistracted2 @34; + driverDistracted3 @35; + driverUnresponsive1 @36; + driverUnresponsive2 @37; + driverUnresponsive3 @38; belowSteerSpeed @39; lowBattery @40; accFaulted @41; @@ -192,66 +192,16 @@ struct InitData { espVersion @3 :Text; } - # ***** deprecated stuff ***** - gctxDEPRECATED @1 :Text; - androidBuildInfo @5 :AndroidBuildInfo; - androidSensorsDEPRECATED @6 :List(AndroidSensor); - chffrAndroidExtraDEPRECATED @7 :ChffrAndroidExtra; - iosBuildInfoDEPRECATED @14 :IosBuildInfo; - - struct AndroidBuildInfo { - board @0 :Text; - bootloader @1 :Text; - brand @2 :Text; - device @3 :Text; - display @4 :Text; - fingerprint @5 :Text; - hardware @6 :Text; - host @7 :Text; - id @8 :Text; - manufacturer @9 :Text; - model @10 :Text; - product @11 :Text; - radioVersion @12 :Text; - serial @13 :Text; - supportedAbis @14 :List(Text); - tags @15 :Text; - time @16 :Int64; - type @17 :Text; - user @18 :Text; - - versionCodename @19 :Text; - versionRelease @20 :Text; - versionSdk @21 :Int32; - versionSecurityPatch @22 :Text; - } - - struct AndroidSensor { - id @0 :Int32; - name @1 :Text; - vendor @2 :Text; - version @3 :Int32; - handle @4 :Int32; - type @5 :Int32; - maxRange @6 :Float32; - resolution @7 :Float32; - power @8 :Float32; - minDelay @9 :Int32; - fifoReservedEventCount @10 :UInt32; - fifoMaxEventCount @11 :UInt32; - stringType @12 :Text; - maxDelay @13 :Int32; - } - struct ChffrAndroidExtra { allCameraCharacteristics @0 :Map(Text, Text); } - struct IosBuildInfo { - appVersion @0 :Text; - appBuild @1 :UInt32; - osVersion @2 :Text; - deviceModel @3 :Text; + deprecated :group { + gctx @1 :Text; + androidBuildInfo @5 :Deprecated.AndroidBuildInfo; + androidSensors @6 :List(Deprecated.AndroidSensor); + chffrAndroidExtra @7 :ChffrAndroidExtra; + iosBuildInfo @14 :Deprecated.IosBuildInfo; } } @@ -280,13 +230,6 @@ struct FrameData { temperaturesC @24 :List(Float32); - enum FrameTypeDEPRECATED { - unknown @0; - neo @1; - chffrAndroid @2; - front @3; - } - sensor @26 :ImageSensor; enum ImageSensor { unknown @0; @@ -295,26 +238,19 @@ struct FrameData { os04c10 @3; } - frameLengthDEPRECATED @3 :Int32; - globalGainDEPRECATED @5 :Int32; - frameTypeDEPRECATED @7 :FrameTypeDEPRECATED; - androidCaptureResultDEPRECATED @9 :AndroidCaptureResult; - lensPosDEPRECATED @11 :Int32; - lensSagDEPRECATED @12 :Float32; - lensErrDEPRECATED @13 :Float32; - lensTruePosDEPRECATED @14 :Float32; - focusValDEPRECATED @16 :List(Int16); - focusConfDEPRECATED @17 :List(UInt8); - sharpnessScoreDEPRECATED @18 :List(UInt16); - recoverStateDEPRECATED @19 :Int32; - struct AndroidCaptureResult { - sensitivity @0 :Int32; - frameDuration @1 :Int64; - exposureTime @2 :Int64; - rollingShutterSkew @3 :UInt64; - colorCorrectionTransform @4 :List(Int32); - colorCorrectionGains @5 :List(Float32); - displayRotation @6 :Int8; + deprecated :group { + frameLength @3 :Int32; + globalGain @5 :Int32; + frameType @7 :Deprecated.FrameTypeDEPRECATED; + androidCaptureResult @9 :Deprecated.AndroidCaptureResult; + lensPos @11 :Int32; + lensSag @12 :Float32; + lensErr @13 :Float32; + lensTruePos @14 :Float32; + focusVal @16 :List(Int16); + focusConf @17 :List(UInt8); + sharpnessScore @18 :List(UInt16); + recoverState @19 :Int32; } } @@ -343,7 +279,6 @@ struct SensorEventData { sensor @1 :Int32; type @2 :Int32; timestamp @3 :Int64; - uncalibratedDEPRECATED @10 :Bool; union { acceleration @4 :SensorVec; @@ -378,6 +313,10 @@ struct SensorEventData { lsm6ds3trc @10; mmc5603nj @11; } + + deprecated :group { + uncalibrated @10 :Bool; + } } # android struct GpsLocation @@ -463,7 +402,10 @@ struct CanData { address @0 :UInt32; dat @2 :Data; src @3 :UInt8; - busTimeDEPRECATED @1 :UInt16; + + deprecated :group { + busTime @1 :UInt16; + } } struct DeviceState @0xa4d8b5af2aa492eb { @@ -553,26 +495,27 @@ struct DeviceState @0xa4d8b5af2aa492eb { wwanRx @1 :Int64; } - # deprecated - cpu0DEPRECATED @0 :UInt16; - cpu1DEPRECATED @1 :UInt16; - cpu2DEPRECATED @2 :UInt16; - cpu3DEPRECATED @3 :UInt16; - memDEPRECATED @4 :UInt16; - gpuDEPRECATED @5 :UInt16; - batDEPRECATED @6 :UInt32; - pa0DEPRECATED @21 :UInt16; - cpuUsagePercentDEPRECATED @20 :Int8; - batteryStatusDEPRECATED @9 :Text; - batteryVoltageDEPRECATED @16 :Int32; - batteryTempCDEPRECATED @29 :Float32; - batteryPercentDEPRECATED @8 :Int16; - batteryCurrentDEPRECATED @15 :Int32; - chargingErrorDEPRECATED @17 :Bool; - chargingDisabledDEPRECATED @18 :Bool; - usbOnlineDEPRECATED @12 :Bool; - ambientTempCDEPRECATED @30 :Float32; - nvmeTempCDEPRECATED @35 :List(Float32); + deprecated :group { + cpu0 @0 :UInt16; + cpu1 @1 :UInt16; + cpu2 @2 :UInt16; + cpu3 @3 :UInt16; + mem @4 :UInt16; + gpu @5 :UInt16; + bat @6 :UInt32; + pa0 @21 :UInt16; + cpuUsagePercent @20 :Int8; + batteryStatus @9 :Text; + batteryVoltage @16 :Int32; + batteryTempC @29 :Float32; + batteryPercent @8 :Int16; + batteryCurrent @15 :Int32; + chargingError @17 :Bool; + chargingDisabled @18 :Bool; + usbOnline @12 :Bool; + ambientTempC @30 :Float32; + nvmeTempC @35 :List(Float32); + } } struct PandaState @0xa7649e2575e4591e { @@ -613,6 +556,11 @@ struct PandaState @0xa7649e2575e4591e { voltage @0 :UInt32; current @1 :UInt32; + # these fields are not used by openpilot, but they're + # reserved for forks building alternate experiences. + controlsAllowedLateral @38 :Bool; + controlsAllowedLongitudinal @39 :Bool; + enum FaultStatus { none @0; faultTemp @1; @@ -709,15 +657,17 @@ struct PandaState @0xa7649e2575e4591e { } } - gasInterceptorDetectedDEPRECATED @4 :Bool; - startedSignalDetectedDEPRECATED @5 :Bool; - hasGpsDEPRECATED @6 :Bool; - gmlanSendErrsDEPRECATED @9 :UInt32; - fanSpeedRpmDEPRECATED @11 :UInt16; - usbPowerModeDEPRECATED @12 :PeripheralState.UsbPowerModeDEPRECATED; - safetyParamDEPRECATED @20 :Int16; - safetyParam2DEPRECATED @26 :UInt32; - fanStallCountDEPRECATED @34 :UInt8; + deprecated :group { + gasInterceptorDetected @4 :Bool; + startedSignalDetected @5 :Bool; + hasGps @6 :Bool; + gmlanSendErrs @9 :UInt32; + fanSpeedRpm @11 :UInt16; + usbPowerMode @12 :Deprecated.UsbPowerModeDEPRECATED; + safetyParam @20 :Int16; + safetyParam2 @26 :UInt32; + fanStallCount @34 :UInt8; + } } struct PeripheralState { @@ -726,12 +676,8 @@ struct PeripheralState { current @2 :UInt32; fanSpeedRpm @3 :UInt16; - usbPowerModeDEPRECATED @4 :UsbPowerModeDEPRECATED; - enum UsbPowerModeDEPRECATED @0xa8883583b32c9877 { - none @0; - client @1; - cdp @2; - dcp @3; + deprecated :group { + usbPowerMode @4 :Deprecated.UsbPowerModeDEPRECATED; } } @@ -760,19 +706,22 @@ struct RadarState @0x9a185389d6fdd05f { radar @14 :Bool; radarTrackId @15 :Int32 = -1; - aLeadDEPRECATED @5 :Float32; + deprecated :group { + aLead @5 :Float32; + } } - # deprecated - ftMonoTimeDEPRECATED @7 :UInt64; - warpMatrixDEPRECATED @0 :List(Float32); - angleOffsetDEPRECATED @1 :Float32; - calStatusDEPRECATED @2 :Int8; - calCycleDEPRECATED @8 :Int32; - calPercDEPRECATED @9 :Int8; - canMonoTimesDEPRECATED @10 :List(UInt64); - cumLagMsDEPRECATED @5 :Float32; - radarErrorsDEPRECATED @12 :List(Car.RadarData.ErrorDEPRECATED); + deprecated :group { + ftMonoTime @7 :UInt64; + warpMatrix @0 :List(Float32); + angleOffset @1 :Float32; + calStatus @2 :Int8; + calCycle @8 :Int32; + calPerc @9 :Int8; + canMonoTimes @10 :List(UInt64); + cumLagMs @5 :Float32; + radarErrors @12 :List(Car.RadarData.ErrorDEPRECATED); + } } struct LiveCalibrationData { @@ -790,10 +739,6 @@ struct LiveCalibrationData { wideFromDeviceEuler @10 :List(Float32); height @12 :List(Float32); - warpMatrixDEPRECATED @0 :List(Float32); - calStatusDEPRECATED @1 :Int8; - warpMatrix2DEPRECATED @5 :List(Float32); - warpMatrixBigDEPRECATED @6 :List(Float32); enum Status { uncalibrated @0; @@ -801,19 +746,13 @@ struct LiveCalibrationData { invalid @2; recalibrating @3; } -} -struct LiveTracksDEPRECATED { - trackId @0 :Int32; - dRel @1 :Float32; - yRel @2 :Float32; - vRel @3 :Float32; - aRel @4 :Float32; - timeStamp @5 :Float32; - status @6 :Float32; - currentTime @7 :Float32; - stationary @8 :Bool; - oncoming @9 :Bool; + deprecated :group { + warpMatrix @0 :List(Float32); + calStatus @1 :Int8; + warpMatrix2 @5 :List(Float32); + warpMatrixBig @6 :List(Float32); + } } struct SelfdriveState { @@ -876,25 +815,9 @@ struct ControlsState @0x97ff69c53601abf1 { debugState @59 :LateralDebugState; torqueState @60 :LateralTorqueState; - curvatureStateDEPRECATED @65 :LateralCurvatureState; - lqrStateDEPRECATED @55 :LateralLQRState; - indiStateDEPRECATED @52 :LateralINDIState; - } - - struct LateralINDIState { - active @0 :Bool; - steeringAngleDeg @1 :Float32; - steeringRateDeg @2 :Float32; - steeringAccelDeg @3 :Float32; - rateSetPoint @4 :Float32; - accelSetPoint @5 :Float32; - accelError @6 :Float32; - delayedOutput @7 :Float32; - delta @8 :Float32; - output @9 :Float32; - saturated @10 :Bool; - steeringAngleDesiredDeg @11 :Float32; - steeringRateDesiredDeg @12 :Float32; + curvatureStateDEPRECATED @65 :Deprecated.LateralCurvatureState; + lqrStateDEPRECATED @55 :Deprecated.LateralLQRState; + indiStateDEPRECATED @52 :Deprecated.LateralINDIState; } struct LateralPIDState { @@ -926,16 +849,6 @@ struct ControlsState @0x97ff69c53601abf1 { version @12 :Int32; } - struct LateralLQRState { - active @0 :Bool; - steeringAngleDeg @1 :Float32; - i @2 :Float32; - output @3 :Float32; - lqrOutput @4 :Float32; - saturated @5 :Bool; - steeringAngleDesiredDeg @6 :Float32; - } - struct LateralAngleState { active @0 :Bool; steeringAngleDeg @1 :Float32; @@ -944,18 +857,6 @@ struct ControlsState @0x97ff69c53601abf1 { steeringAngleDesiredDeg @4 :Float32; } - struct LateralCurvatureState { - active @0 :Bool; - actualCurvature @1 :Float32; - desiredCurvature @2 :Float32; - error @3 :Float32; - p @4 :Float32; - i @5 :Float32; - f @6 :Float32; - output @7 :Float32; - saturated @8 :Bool; - } - struct LateralDebugState { active @0 :Bool; steeringAngleDeg @1 :Float32; @@ -963,58 +864,59 @@ struct ControlsState @0x97ff69c53601abf1 { saturated @3 :Bool; } - # deprecated - vEgoDEPRECATED @0 :Float32; - vEgoRawDEPRECATED @32 :Float32; - aEgoDEPRECATED @1 :Float32; - canMonoTimeDEPRECATED @16 :UInt64; - radarStateMonoTimeDEPRECATED @17 :UInt64; - mdMonoTimeDEPRECATED @18 :UInt64; - yActualDEPRECATED @6 :Float32; - yDesDEPRECATED @7 :Float32; - upSteerDEPRECATED @8 :Float32; - uiSteerDEPRECATED @9 :Float32; - ufSteerDEPRECATED @34 :Float32; - aTargetMinDEPRECATED @10 :Float32; - aTargetMaxDEPRECATED @11 :Float32; - rearViewCamDEPRECATED @23 :Bool; - driverMonitoringOnDEPRECATED @43 :Bool; - hudLeadDEPRECATED @14 :Int32; - alertSoundDEPRECATED @45 :Text; - angleModelBiasDEPRECATED @27 :Float32; - gpsPlannerActiveDEPRECATED @40 :Bool; - decelForTurnDEPRECATED @47 :Bool; - decelForModelDEPRECATED @54 :Bool; - awarenessStatusDEPRECATED @26 :Float32; - angleSteersDEPRECATED @13 :Float32; - vCurvatureDEPRECATED @46 :Float32; - mapValidDEPRECATED @49 :Bool; - jerkFactorDEPRECATED @12 :Float32; - steerOverrideDEPRECATED @20 :Bool; - steeringAngleDesiredDegDEPRECATED @29 :Float32; - canMonoTimesDEPRECATED @21 :List(UInt64); - desiredCurvatureRateDEPRECATED @62 :Float32; - canErrorCounterDEPRECATED @57 :UInt32; - vPidDEPRECATED @2 :Float32; - alertBlinkingRateDEPRECATED @42 :Float32; - alertText1DEPRECATED @24 :Text; - alertText2DEPRECATED @25 :Text; - alertStatusDEPRECATED @38 :SelfdriveState.AlertStatus; - alertSizeDEPRECATED @39 :SelfdriveState.AlertSize; - alertTypeDEPRECATED @44 :Text; - alertSound2DEPRECATED @56 :Car.CarControl.HUDControl.AudibleAlert; - engageableDEPRECATED @41 :Bool; # can OP be engaged? - stateDEPRECATED @31 :SelfdriveState.OpenpilotState; - enabledDEPRECATED @19 :Bool; - activeDEPRECATED @36 :Bool; - experimentalModeDEPRECATED @64 :Bool; - personalityDEPRECATED @66 :LongitudinalPersonality; - vCruiseDEPRECATED @22 :Float32; # actual set speed - vCruiseClusterDEPRECATED @63 :Float32; # set speed to display in the UI - startMonoTimeDEPRECATED @48 :UInt64; - cumLagMsDEPRECATED @15 :Float32; - aTargetDEPRECATED @35 :Float32; - vTargetLeadDEPRECATED @3 :Float32; + deprecated :group { + vEgo @0 :Float32; + vEgoRaw @32 :Float32; + aEgo @1 :Float32; + canMonoTime @16 :UInt64; + radarStateMonoTime @17 :UInt64; + mdMonoTime @18 :UInt64; + yActual @6 :Float32; + yDes @7 :Float32; + upSteer @8 :Float32; + uiSteer @9 :Float32; + ufSteer @34 :Float32; + aTargetMin @10 :Float32; + aTargetMax @11 :Float32; + rearViewCam @23 :Bool; + driverMonitoringOn @43 :Bool; + hudLead @14 :Int32; + alertSound @45 :Text; + angleModelBias @27 :Float32; + gpsPlannerActive @40 :Bool; + decelForTurn @47 :Bool; + decelForModel @54 :Bool; + awarenessStatus @26 :Float32; + angleSteers @13 :Float32; + vCurvature @46 :Float32; + mapValid @49 :Bool; + jerkFactor @12 :Float32; + steerOverride @20 :Bool; + steeringAngleDesiredDeg @29 :Float32; + canMonoTimes @21 :List(UInt64); + desiredCurvatureRate @62 :Float32; + canErrorCounter @57 :UInt32; + vPid @2 :Float32; + alertBlinkingRate @42 :Float32; + alertText1 @24 :Text; + alertText2 @25 :Text; + alertStatus @38 :SelfdriveState.AlertStatus; + alertSize @39 :SelfdriveState.AlertSize; + alertType @44 :Text; + alertSound2 @56 :Car.CarControl.HUDControl.AudibleAlert; + engageable @41 :Bool; # can OP be engaged? + state @31 :SelfdriveState.OpenpilotState; + enabled @19 :Bool; + active @36 :Bool; + experimentalMode @64 :Bool; + personality @66 :LongitudinalPersonality; + vCruise @22 :Float32; # actual set speed + vCruiseCluster @63 :Float32; # set speed to display in the UI + startMonoTime @48 :UInt64; + cumLagMs @15 :Float32; + aTarget @35 :Float32; + vTargetLead @3 :Float32; + } } struct DrivingModelData { @@ -1090,16 +992,10 @@ struct ModelDataV2 { meta @12 :MetaData; confidence @23: ConfidenceClass; - # Model perceived motion - temporalPoseDEPRECATED @21 :Pose; - # e2e lateral planner action @26: Action; - gpuExecutionTimeDEPRECATED @17 :Float32; - navEnabledDEPRECATED @22 :Bool; - locationMonoTimeDEPRECATED @24 :UInt64; - lateralPlannerSolutionDEPRECATED @25: LateralPlannerSolution; + lateralPlannerSolutionDEPRECATED @25: Deprecated.LateralPlannerSolution; struct LeadDataV2 { prob @0 :Float32; # probability that car is your lead at time t @@ -1141,10 +1037,11 @@ struct ModelDataV2 { laneChangeDirection @9 :LaneChangeDirection; - # deprecated - brakeDisengageProbDEPRECATED @2 :Float32; - gasDisengageProbDEPRECATED @3 :Float32; - steerOverrideProbDEPRECATED @4 :Float32; + deprecated :group { + brakeDisengageProb @2 :Float32; + gasDisengageProb @3 :Float32; + steerOverrideProb @4 :Float32; + } } enum ConfidenceClass { @@ -1172,22 +1069,18 @@ struct ModelDataV2 { rotStd @3 :List(Float32); # std rad/s in device frame } - struct LateralPlannerSolution { - x @0 :List(Float32); - y @1 :List(Float32); - yaw @2 :List(Float32); - yawRate @3 :List(Float32); - xStd @4 :List(Float32); - yStd @5 :List(Float32); - yawStd @6 :List(Float32); - yawRateStd @7 :List(Float32); - } - struct Action { desiredCurvature @0 :Float32; desiredAcceleration @1 :Float32; shouldStop @2 :Bool; } + + deprecated :group { + temporalPose @21 :Pose; + gpuExecutionTime @17 :Float32; + navEnabled @22 :Bool; + locationMonoTime @24 :UInt64; + } } struct EncodeIndex { @@ -1273,38 +1166,35 @@ struct LongitudinalPlan @0xe00b5b3eba12876c { e2e @4; } - # deprecated - vCruiseDEPRECATED @16 :Float32; - aCruiseDEPRECATED @17 :Float32; - vTargetDEPRECATED @3 :Float32; - vTargetFutureDEPRECATED @14 :Float32; - vStartDEPRECATED @26 :Float32; - aStartDEPRECATED @27 :Float32; - vMaxDEPRECATED @20 :Float32; - radarStateMonoTimeDEPRECATED @10 :UInt64; - jerkFactorDEPRECATED @6 :Float32; - hasLeftLaneDEPRECATED @23 :Bool; - hasRightLaneDEPRECATED @24 :Bool; - aTargetMinDEPRECATED @4 :Float32; - aTargetMaxDEPRECATED @5 :Float32; - lateralValidDEPRECATED @0 :Bool; - longitudinalValidDEPRECATED @2 :Bool; - dPolyDEPRECATED @1 :List(Float32); - laneWidthDEPRECATED @11 :Float32; - vCurvatureDEPRECATED @21 :Float32; - decelForTurnDEPRECATED @22 :Bool; - mapValidDEPRECATED @25 :Bool; - radarValidDEPRECATED @28 :Bool; - radarCanErrorDEPRECATED @30 :Bool; - commIssueDEPRECATED @31 :Bool; - eventsDEPRECATED @13 :List(Car.OnroadEventDEPRECATED); - gpsTrajectoryDEPRECATED @12 :GpsTrajectory; - gpsPlannerActiveDEPRECATED @19 :Bool; - personalityDEPRECATED @36 :LongitudinalPersonality; - struct GpsTrajectory { - x @0 :List(Float32); - y @1 :List(Float32); + deprecated :group { + vCruise @16 :Float32; + aCruise @17 :Float32; + vTarget @3 :Float32; + vTargetFuture @14 :Float32; + vStart @26 :Float32; + aStart @27 :Float32; + vMax @20 :Float32; + radarStateMonoTime @10 :UInt64; + jerkFactor @6 :Float32; + hasLeftLane @23 :Bool; + hasRightLane @24 :Bool; + aTargetMin @4 :Float32; + aTargetMax @5 :Float32; + lateralValid @0 :Bool; + longitudinalValid @2 :Bool; + dPoly @1 :List(Float32); + laneWidth @11 :Float32; + vCurvature @21 :Float32; + decelForTurn @22 :Bool; + mapValid @25 :Bool; + radarValid @28 :Bool; + radarCanError @30 :Bool; + commIssue @31 :Bool; + events @13 :List(Car.OnroadEventDEPRECATED); + gpsTrajectory @12 :Deprecated.GpsTrajectory; + gpsPlannerActive @19 :Bool; + personality @36 :LongitudinalPersonality; } } struct UiPlan { @@ -1315,11 +1205,7 @@ struct UiPlan { struct LateralPlan @0xe1e9318e2ae8b51e { modelMonoTime @31 :UInt64; - laneWidthDEPRECATED @0 :Float32; - lProbDEPRECATED @5 :Float32; - rProbDEPRECATED @7 :Float32; dPathPoints @20 :List(Float32); - dProbDEPRECATED @21 :Float32; mpcSolutionValid @9 :Bool; desire @17 :Desire; @@ -1341,24 +1227,29 @@ struct LateralPlan @0xe1e9318e2ae8b51e { u @1 :List(Float32); } - # deprecated - curvatureDEPRECATED @22 :Float32; - curvatureRateDEPRECATED @23 :Float32; - rawCurvatureDEPRECATED @24 :Float32; - rawCurvatureRateDEPRECATED @25 :Float32; - cProbDEPRECATED @3 :Float32; - dPolyDEPRECATED @1 :List(Float32); - cPolyDEPRECATED @2 :List(Float32); - lPolyDEPRECATED @4 :List(Float32); - rPolyDEPRECATED @6 :List(Float32); - modelValidDEPRECATED @12 :Bool; - commIssueDEPRECATED @15 :Bool; - posenetValidDEPRECATED @16 :Bool; - sensorValidDEPRECATED @14 :Bool; - paramsValidDEPRECATED @10 :Bool; - steeringAngleDegDEPRECATED @8 :Float32; # deg - steeringRateDegDEPRECATED @13 :Float32; # deg/s - angleOffsetDegDEPRECATED @11 :Float32; + deprecated :group { + laneWidth @0 :Float32; + lProb @5 :Float32; + rProb @7 :Float32; + dProb @21 :Float32; + curvature @22 :Float32; + curvatureRate @23 :Float32; + rawCurvature @24 :Float32; + rawCurvatureRate @25 :Float32; + cProb @3 :Float32; + dPoly @1 :List(Float32); + cPoly @2 :List(Float32); + lPoly @4 :List(Float32); + rPoly @6 :List(Float32); + modelValid @12 :Bool; + commIssue @15 :Bool; + posenetValid @16 :Bool; + sensorValid @14 :Bool; + paramsValid @10 :Bool; + steeringAngleDeg @8 :Float32; # deg + steeringRateDeg @13 :Float32; # deg/s + angleOffsetDeg @11 :Float32; + } } struct LiveLocationKalman { @@ -1553,7 +1444,10 @@ struct GnssMeasurements { # Satellite position and velocity [x,y,z] satPos @7 :List(Float64); satVel @8 :List(Float64); - ephemerisSourceDEPRECATED @9 :EphemerisSourceDEPRECATED; + + deprecated :group { + ephemerisSource @9 :EphemerisSourceDEPRECATED; + } } struct EphemerisSourceDEPRECATED { @@ -1708,7 +1602,6 @@ struct UbloxGnss { iDot @26 :Float64; codesL2 @27 :Float64; - gpsWeekDEPRECATED @28 :Float64; l2 @29 :Float64; svAcc @30 :Float64; @@ -1728,6 +1621,10 @@ struct UbloxGnss { towCount @40 :UInt32; toeWeek @41 :UInt16; tocWeek @42 :UInt16; + + deprecated :group { + gpsWeek @28 :Float64; + } } struct IonoData { @@ -1806,7 +1703,6 @@ struct UbloxGnss { age @17 :UInt8; svHealth @18 :UInt8; - tkDEPRECATED @19 :UInt16; tb @20 :UInt16; tauN @21 :Float64; @@ -1818,12 +1714,16 @@ struct UbloxGnss { p3 @26 :UInt8; p4 @27 :UInt8; - freqNumDEPRECATED @28 :UInt32; n4 @29 :UInt8; nt @30 :UInt16; freqNum @31 :Int16; tkSeconds @32 :UInt32; + + deprecated :group { + tk @19 :UInt16; + freqNum @28 :UInt32; + } } } @@ -2124,34 +2024,12 @@ struct QcomGnss @0xde94674b07ae51c1 { struct Clocks { wallTimeNanos @3 :UInt64; # unix epoch time - bootTimeNanosDEPRECATED @0 :UInt64; - monotonicNanosDEPRECATED @1 :UInt64; - monotonicRawNanosDEPRECATD @2 :UInt64; - modemUptimeMillisDEPRECATED @4 :UInt64; -} - -struct LiveMpcData { - x @0 :List(Float32); - y @1 :List(Float32); - psi @2 :List(Float32); - curvature @3 :List(Float32); - qpIterations @4 :UInt32; - calculationTime @5 :UInt64; - cost @6 :Float64; -} - -struct LiveLongitudinalMpcData { - xEgo @0 :List(Float32); - vEgo @1 :List(Float32); - aEgo @2 :List(Float32); - xLead @3 :List(Float32); - vLead @4 :List(Float32); - aLead @5 :List(Float32); - aLeadTau @6 :Float32; # lead accel time constant - qpIterations @7 :UInt32; - mpcId @8 :UInt32; - calculationTime @9 :UInt64; - cost @10 :Float64; + deprecated :group { + bootTimeNanos @0 :UInt64; + monotonicNanos @1 :UInt64; + monotonicRawNanos @2 :UInt64; + modemUptimeMillis @4 :UInt64; + } } struct Joystick { @@ -2179,50 +2057,23 @@ struct DriverStateV2 { eyesVisibleProb @14 :Float32; eyesClosedProb @15 :Float32; phoneProb @13 :Float32; - leftEyeProbDEPRECATED @5 :Float32; - rightEyeProbDEPRECATED @6 :Float32; - leftBlinkProbDEPRECATED @7 :Float32; - rightBlinkProbDEPRECATED @8 :Float32; - sunglassesProbDEPRECATED @9 :Float32; - notReadyProbDEPRECATED @12 :List(Float32); - occludedProbDEPRECATED @10 :Float32; - readyProbDEPRECATED @11 :List(Float32); + + deprecated :group { + leftEyeProb @5 :Float32; + rightEyeProb @6 :Float32; + leftBlinkProb @7 :Float32; + rightBlinkProb @8 :Float32; + sunglassesProb @9 :Float32; + notReadyProb @12 :List(Float32); + occludedProb @10 :Float32; + readyProb @11 :List(Float32); + } } - dspExecutionTimeDEPRECATED @2 :Float32; - poorVisionProbDEPRECATED @4 :Float32; -} - -struct DriverStateDEPRECATED @0xb83c6cc593ed0a00 { - frameId @0 :UInt32; - modelExecutionTime @14 :Float32; - dspExecutionTime @16 :Float32; - rawPredictions @15 :Data; - - faceOrientation @3 :List(Float32); - facePosition @4 :List(Float32); - faceProb @5 :Float32; - leftEyeProb @6 :Float32; - rightEyeProb @7 :Float32; - leftBlinkProb @8 :Float32; - rightBlinkProb @9 :Float32; - faceOrientationStd @11 :List(Float32); - facePositionStd @12 :List(Float32); - sunglassesProb @13 :Float32; - poorVision @17 :Float32; - partialFace @18 :Float32; - distractedPose @19 :Float32; - distractedEyes @20 :Float32; - eyesOnRoad @21 :Float32; - phoneUse @22 :Float32; - occludedProb @23 :Float32; - - readyProb @24 :List(Float32); - notReadyProb @25 :List(Float32); - - irPwrDEPRECATED @10 :Float32; - descriptorDEPRECATED @1 :List(Float32); - stdDEPRECATED @2 :Float32; + deprecated :group { + dspExecutionTime @2 :Float32; + poorVisionProb @4 :Float32; + } } struct DriverMonitoringState @0xb83cda094a1da284 { @@ -2244,11 +2095,13 @@ struct DriverMonitoringState @0xb83cda094a1da284 { isRHD @4 :Bool; uncertainCount @19 :UInt32; - phoneProbOffsetDEPRECATED @20 :Float32; - phoneProbValidCountDEPRECATED @21 :UInt32; - isPreviewDEPRECATED @15 :Bool; - rhdCheckedDEPRECATED @5 :Bool; - eventsDEPRECATED @0 :List(Car.OnroadEventDEPRECATED); + deprecated :group { + phoneProbOffset @20 :Float32; + phoneProbValidCount @21 :UInt32; + isPreview @15 :Bool; + rhdChecked @5 :Bool; + events @0 :List(Car.OnroadEventDEPRECATED); + } } struct Boot { @@ -2257,8 +2110,10 @@ struct Boot { commands @5 :Map(Text, Data); launchLog @3 :Text; - lastKmsgDEPRECATED @1 :Data; - lastPmsgDEPRECATED @2 :Data; + deprecated :group { + lastKmsg @1 :Data; + lastPmsg @2 :Data; + } } struct LiveParametersData { @@ -2283,13 +2138,16 @@ struct LiveParametersData { steerRatioValid @19 :Bool = true; stiffnessFactorValid @20 :Bool = true; - yawRateDEPRECATED @7 :Float32; - filterStateDEPRECATED @15 :LiveLocationKalman.Measurement; struct FilterState { value @0 : List(Float64); std @1 : List(Float64); } + + deprecated :group { + yawRate @7 :Float32; + filterState @15 :LiveLocationKalman.Measurement; + } } struct LiveTorqueParametersData { @@ -2459,25 +2317,6 @@ struct MapRenderState { frameId @2: UInt32; } -struct NavModelData { - frameId @0 :UInt32; - locationMonoTime @6 :UInt64; - modelExecutionTime @1 :Float32; - dspExecutionTime @2 :Float32; - features @3 :List(Float32); - # predicted future position - position @4 :XYData; - desirePrediction @5 :List(Float32); - - # All SI units and in device frame - struct XYData { - x @0 :List(Float32); - y @1 :List(Float32); - xStd @2 :List(Float32); - yStd @3 :List(Float32); - } -} - struct EncodeData { idx @0 :EncodeIndex; data @1 :Data; @@ -2502,7 +2341,9 @@ struct SoundPressure @0xdc24138990726023 { soundPressureWeighted @3 :Float32; soundPressureWeightedDb @1 :Float32; - filteredSoundPressureWeightedDbDEPRECATED @2 :Float32; + deprecated :group { + filteredSoundPressureWeightedDb @2 :Float32; + } } struct AudioData { @@ -2666,48 +2507,48 @@ struct Event { customReserved19 @145 :Custom.CustomReserved19; # *********** legacy + deprecated *********** - model @9 :Legacy.ModelData; # TODO: rename modelV2 and mark this as deprecated - liveMpcDEPRECATED @36 :LiveMpcData; - liveLongitudinalMpcDEPRECATED @37 :LiveLongitudinalMpcData; - liveLocationKalmanLegacyDEPRECATED @51 :Legacy.LiveLocationData; - orbslamCorrectionDEPRECATED @45 :Legacy.OrbslamCorrection; - liveUIDEPRECATED @14 :Legacy.LiveUI; + model @9 :Deprecated.ModelData; # TODO: rename modelV2 and mark this as deprecated + liveMpcDEPRECATED @36 :Deprecated.LiveMpcData; + liveLongitudinalMpcDEPRECATED @37 :Deprecated.LiveLongitudinalMpcData; + liveLocationKalmanDeprecatedDEPRECATED @51 :Deprecated.LiveLocationData; + orbslamCorrectionDEPRECATED @45 :Deprecated.OrbslamCorrection; + liveUIDEPRECATED @14 :Deprecated.LiveUI; sensorEventDEPRECATED @4 :SensorEventData; - liveEventDEPRECATED @8 :List(Legacy.LiveEventData); - liveLocationDEPRECATED @25 :Legacy.LiveLocationData; - ethernetDataDEPRECATED @26 :List(Legacy.EthernetPacket); - cellInfoDEPRECATED @28 :List(Legacy.CellInfo); - wifiScanDEPRECATED @29 :List(Legacy.WifiScan); - uiNavigationEventDEPRECATED @50 :Legacy.UiNavigationEvent; + liveEventDEPRECATED @8 :List(Deprecated.LiveEventData); + liveLocationDEPRECATED @25 :Deprecated.LiveLocationData; + ethernetDataDEPRECATED @26 :List(Deprecated.EthernetPacket); + cellInfoDEPRECATED @28 :List(Deprecated.CellInfo); + wifiScanDEPRECATED @29 :List(Deprecated.WifiScan); + uiNavigationEventDEPRECATED @50 :Deprecated.UiNavigationEvent; liveMapDataDEPRECATED @62 :LiveMapDataDEPRECATED; - gpsPlannerPointsDEPRECATED @40 :Legacy.GPSPlannerPoints; - gpsPlannerPlanDEPRECATED @41 :Legacy.GPSPlannerPlan; + gpsPlannerPointsDEPRECATED @40 :Deprecated.GPSPlannerPoints; + gpsPlannerPlanDEPRECATED @41 :Deprecated.GPSPlannerPlan; applanixRawDEPRECATED @42 :Data; - androidGnssDEPRECATED @30 :Legacy.AndroidGnss; - lidarPtsDEPRECATED @32 :Legacy.LidarPts; - navStatusDEPRECATED @38 :Legacy.NavStatus; - trafficEventsDEPRECATED @43 :List(Legacy.TrafficEvent); - liveLocationTimingDEPRECATED @44 :Legacy.LiveLocationData; - liveLocationCorrectedDEPRECATED @46 :Legacy.LiveLocationData; - navUpdateDEPRECATED @27 :Legacy.NavUpdate; - orbObservationDEPRECATED @47 :List(Legacy.OrbObservation); - locationDEPRECATED @49 :Legacy.LiveLocationData; - orbOdometryDEPRECATED @53 :Legacy.OrbOdometry; - orbFeaturesDEPRECATED @54 :Legacy.OrbFeatures; - applanixLocationDEPRECATED @55 :Legacy.LiveLocationData; - orbKeyFrameDEPRECATED @56 :Legacy.OrbKeyFrame; - orbFeaturesSummaryDEPRECATED @58 :Legacy.OrbFeaturesSummary; - featuresDEPRECATED @10 :Legacy.CalibrationFeatures; - kalmanOdometryDEPRECATED @65 :Legacy.KalmanOdometry; - uiLayoutStateDEPRECATED @57 :Legacy.UiLayoutState; + androidGnssDEPRECATED @30 :Deprecated.AndroidGnss; + lidarPtsDEPRECATED @32 :Deprecated.LidarPts; + navStatusDEPRECATED @38 :Deprecated.NavStatus; + trafficEventsDEPRECATED @43 :List(Deprecated.TrafficEvent); + liveLocationTimingDEPRECATED @44 :Deprecated.LiveLocationData; + liveLocationCorrectedDEPRECATED @46 :Deprecated.LiveLocationData; + navUpdateDEPRECATED @27 :Deprecated.NavUpdate; + orbObservationDEPRECATED @47 :List(Deprecated.OrbObservation); + locationDEPRECATED @49 :Deprecated.LiveLocationData; + orbOdometryDEPRECATED @53 :Deprecated.OrbOdometry; + orbFeaturesDEPRECATED @54 :Deprecated.OrbFeatures; + applanixLocationDEPRECATED @55 :Deprecated.LiveLocationData; + orbKeyFrameDEPRECATED @56 :Deprecated.OrbKeyFrame; + orbFeaturesSummaryDEPRECATED @58 :Deprecated.OrbFeaturesSummary; + featuresDEPRECATED @10 :Deprecated.CalibrationFeatures; + kalmanOdometryDEPRECATED @65 :Deprecated.KalmanOdometry; + uiLayoutStateDEPRECATED @57 :Deprecated.UiLayoutState; pandaStateDEPRECATED @12 :PandaState; - driverStateDEPRECATED @59 :DriverStateDEPRECATED; + driverStateDEPRECATED @59 :Deprecated.DriverStateDEPRECATED; sensorEventsDEPRECATED @11 :List(SensorEventData); lateralPlanDEPRECATED @64 :LateralPlan; - navModelDEPRECATED @104 :NavModelData; + navModelDEPRECATED @104 :Deprecated.NavModelData; uiPlanDEPRECATED @106 :UiPlan; liveLocationKalman @72 :LiveLocationKalman; - liveTracksDEPRECATED @16 :List(LiveTracksDEPRECATED); + liveTracksDEPRECATED @16 :List(Deprecated.LiveTracksDEPRECATED); onroadEventsDEPRECATED @68: List(Car.OnroadEventDEPRECATED); gyroscope2DEPRECATED @100 :SensorEventData; accelerometer2DEPRECATED @101 :SensorEventData; diff --git a/cereal/services.py b/cereal/services.py index 46ee0a33e3..9d64f67f2f 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -39,8 +39,8 @@ _services: dict[str, tuple] = { "roadEncodeIdx": (False, 20., 1), "liveTracks": (True, 20.), "sendcan": (True, 100., 139, QueueSize.MEDIUM), - "logMessage": (True, 0.), - "errorLogMessage": (True, 0., 1), + "logMessage": (True, 0., None, QueueSize.BIG), + "errorLogMessage": (True, 0., 1, QueueSize.BIG), "liveCalibration": (True, 4., 4), "liveTorqueParameters": (True, 4., 1), "liveDelay": (True, 4., 1), diff --git a/common/model.h b/common/model.h index b482499c74..d134ebd15e 100644 --- a/common/model.h +++ b/common/model.h @@ -1 +1 @@ -#define DEFAULT_MODEL "OP Model (Default)" +#define DEFAULT_MODEL "POP model (Default)" diff --git a/common/utils.py b/common/utils.py index faaa96ecbc..28b9274d82 100644 --- a/common/utils.py +++ b/common/utils.py @@ -131,11 +131,11 @@ def get_upload_stream(filepath: str, should_compress: bool) -> tuple[io.Buffered return compressed_stream, compressed_size -# remove all keys that end in DEPRECATED +# remove all keys that end in DEPRECATED, plus any "deprecated" group def strip_deprecated_keys(d): for k in list(d.keys()): if isinstance(k, str): - if k.endswith('DEPRECATED'): + if k.endswith('DEPRECATED') or k == 'deprecated': d.pop(k) elif isinstance(d[k], dict): strip_deprecated_keys(d[k]) diff --git a/opendbc_repo b/opendbc_repo index d7260245ff..ded068839b 160000 --- a/opendbc_repo +++ b/opendbc_repo @@ -1 +1 @@ -Subproject commit d7260245ffcbc7f6bb7524d8db102226b3220be7 +Subproject commit ded068839b7b84708f35b07ad207601f36652f4e diff --git a/panda b/panda index 80846cff66..c0cc96fbad 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 80846cff66e0241adee27ec026f2e5cbcb15c5b4 +Subproject commit c0cc96fbad1d11445c34141d7626703fc13a9938 diff --git a/scripts/reporter.py b/scripts/reporter.py index 64f6cb99b8..93b71761a9 100755 --- a/scripts/reporter.py +++ b/scripts/reporter.py @@ -33,16 +33,7 @@ if __name__ == "__main__": print("|-| ----- | --------- |") for f in glob.glob(BASEDIR + MODEL_PATH + "/*.onnx"): - # TODO: add checkpoint to DM - if "dmonitoring" in f: - continue - fn = os.path.basename(f) - master_path = MASTER_PATH + MODEL_PATH + fn - if os.path.exists(master_path): - master = get_checkpoint(master_path) - master_col = f"[{master}](https://reporter.comma.life/experiment/{master})" - else: - master_col = "N/A (new model)" + master = get_checkpoint(MASTER_PATH + MODEL_PATH + fn) pr = get_checkpoint(BASEDIR + MODEL_PATH + fn) - print("|", fn, "|", master_col, "|", f"[{pr}](https://reporter.comma.life/experiment/{pr})", "|") + print("|", fn, "|", f"[{master}](https://reporterv2.comma.life/{master})", "|", f"[{pr}](https://reporterv2.comma.life/{pr})", "|") diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index bf6dd04f60..1e2fb27b51 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -39,19 +39,17 @@ def clip_curvature(v_ego, prev_curvature, new_curvature, roll) -> tuple[float, b return float(new_curvature), limited_accel or limited_max_curv -def get_accel_from_plan(speeds, accels, t_idxs, action_t=DT_MDL, vEgoStopping=0.05): +def get_accel_from_plan(speeds, accels, t_idxs, action_t=DT_MDL, vEgoStopping=0.3): if len(speeds) == len(t_idxs): v_now = speeds[0] a_now = accels[0] v_target = np.interp(action_t, t_idxs, speeds) a_target = 2 * (v_target - v_now) / (action_t) - a_now - v_target_1sec = np.interp(action_t + 1.0, t_idxs, speeds) else: + v_now = 0.0 v_target = 0.0 - v_target_1sec = 0.0 a_target = 0.0 - should_stop = (v_target < vEgoStopping and - v_target_1sec < vEgoStopping) + should_stop = (v_now < vEgoStopping and a_target < 0.1) return a_target, should_stop def curv_from_psis(psi_target, psi_rate, vego, action_t): diff --git a/selfdrive/debug/cycle_alerts.py b/selfdrive/debug/cycle_alerts.py index 00fa33ac63..4b1def4fc6 100755 --- a/selfdrive/debug/cycle_alerts.py +++ b/selfdrive/debug/cycle_alerts.py @@ -30,9 +30,9 @@ def cycle_alerts(duration=200, is_metric=False): (EventName.accFaulted, ET.IMMEDIATE_DISABLE), # DM sequence - (EventName.preDriverDistracted, ET.WARNING), - (EventName.promptDriverDistracted, ET.WARNING), - (EventName.driverDistracted, ET.WARNING), + (EventName.driverDistracted1, ET.WARNING), + (EventName.driverDistracted2, ET.WARNING), + (EventName.driverDistracted3, ET.WARNING), ] # debug alerts diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index 78c329b394..f02e667228 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -17,11 +17,11 @@ def estimate_pickle_max_size(onnx_size): # THREADS=0 is need to prevent bug: https://github.com/tinygrad/tinygrad/issues/14689 tg_flags = { 'larch64': 'DEV=QCOM FLOAT16=1 NOLOCALS=1 JIT_BATCH_SIZE=0', - 'Darwin': f'DEV=CPU THREADS=0 HOME={os.path.expanduser("~")} IMAGE=0', # tinygrad calls brew which needs a $HOME in the env -}.get(arch, 'DEV=CPU CPU_LLVM=1 THREADS=0 IMAGE=0') + 'Darwin': f'DEV=CPU THREADS=0 HOME={os.path.expanduser("~")}', # tinygrad calls brew which needs a $HOME in the env +}.get(arch, 'DEV=CPU CPU_LLVM=1 THREADS=0') # Get model metadata -for model_name in ['driving_vision', 'driving_off_policy', 'driving_on_policy', 'dmonitoring_model']: +for model_name in ['driving_vision', 'driving_policy', 'dmonitoring_model']: fn = File(f"models/{model_name}").abspath script_files = [File(Dir("#selfdrive/modeld").File("get_model_metadata.py").abspath)] cmd = f'{tg_flags} python3 {Dir("#selfdrive/modeld").abspath}/get_model_metadata.py {fn}.onnx' @@ -59,5 +59,6 @@ def tg_compile(flags, model_name): ) # Compile small models -for model_name in ['driving_vision', 'driving_off_policy', 'driving_on_policy', 'dmonitoring_model']: +for model_name in ['driving_vision', 'driving_policy', 'dmonitoring_model']: tg_compile(tg_flags, model_name) + diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 3f32506a06..d774e475d7 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -40,10 +40,8 @@ SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') MODELS_DIR = Path(__file__).parent / 'models' VISION_PKL_PATH = MODELS_DIR / 'driving_vision_tinygrad.pkl' VISION_METADATA_PATH = MODELS_DIR / 'driving_vision_metadata.pkl' -ON_POLICY_PKL_PATH = MODELS_DIR / 'driving_on_policy_tinygrad.pkl' -ON_POLICY_METADATA_PATH = MODELS_DIR / 'driving_on_policy_metadata.pkl' -OFF_POLICY_PKL_PATH = MODELS_DIR / 'driving_off_policy_tinygrad.pkl' -OFF_POLICY_METADATA_PATH = MODELS_DIR / 'driving_off_policy_metadata.pkl' +POLICY_PKL_PATH = MODELS_DIR / 'driving_policy_tinygrad.pkl' +POLICY_METADATA_PATH = MODELS_DIR / 'driving_policy_metadata.pkl' LAT_SMOOTH_SECONDS = 0.0 LONG_SMOOTH_SECONDS = 0.3 @@ -158,13 +156,7 @@ class ModelState(ModelStateBase): self.vision_output_slices = vision_metadata['output_slices'] vision_output_size = vision_metadata['output_shapes']['outputs'][1] - with open(OFF_POLICY_METADATA_PATH, 'rb') as f: - off_policy_metadata = pickle.load(f) - self.off_policy_input_shapes = off_policy_metadata['input_shapes'] - self.off_policy_output_slices = off_policy_metadata['output_slices'] - off_policy_output_size = off_policy_metadata['output_shapes']['outputs'][1] - - with open(ON_POLICY_METADATA_PATH, 'rb') as f: + with open(POLICY_METADATA_PATH, 'rb') as f: policy_metadata = pickle.load(f) self.policy_input_shapes = policy_metadata['input_shapes'] self.policy_output_slices = policy_metadata['output_slices'] @@ -188,13 +180,11 @@ class ModelState(ModelStateBase): self.vision_output = np.zeros(vision_output_size, dtype=np.float32) self.policy_inputs = {k: Tensor(v, device='NPY').realize() for k,v in self.numpy_inputs.items()} self.policy_output = np.zeros(policy_output_size, dtype=np.float32) - self.off_policy_output = np.zeros(off_policy_output_size, dtype=np.float32) self.parser = Parser() self.frame_buf_params : dict[str, tuple[int, int, int, int]] = {} self.update_imgs = None self.vision_run = pickle.loads(read_file_chunked(str(VISION_PKL_PATH))) - self.policy_run = pickle.loads(read_file_chunked(str(ON_POLICY_PKL_PATH))) - self.off_policy_run = pickle.loads(read_file_chunked(str(OFF_POLICY_PKL_PATH))) + self.policy_run = pickle.loads(read_file_chunked(str(POLICY_PKL_PATH))) def slice_outputs(self, model_outputs: np.ndarray, output_slices: dict[str, slice]) -> dict[str, np.ndarray]: parsed_model_outputs = {k: model_outputs[np.newaxis, v] for k,v in output_slices.items()} @@ -243,17 +233,9 @@ class ModelState(ModelStateBase): self.policy_output = self.policy_run(**self.policy_inputs).contiguous().realize().uop.base.buffer.numpy().flatten() policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(self.policy_output, self.policy_output_slices)) - - self.off_policy_output = self.off_policy_run(**self.policy_inputs).contiguous().realize().uop.base.buffer.numpy() - off_policy_outputs_dict = self.parser.parse_off_policy_outputs(self.slice_outputs(self.off_policy_output, self.off_policy_output_slices)) - off_policy_outputs_dict.pop('plan') - - - combined_outputs_dict = {**vision_outputs_dict, **off_policy_outputs_dict, **policy_outputs_dict} - if 'planplus' in combined_outputs_dict and 'plan' in combined_outputs_dict: - combined_outputs_dict['plan'] = combined_outputs_dict['plan'] + combined_outputs_dict['planplus'] + combined_outputs_dict = {**vision_outputs_dict, **policy_outputs_dict} if SEND_RAW_PRED: - combined_outputs_dict['raw_pred'] = np.concatenate([self.vision_output.copy(), self.policy_output.copy(), self.off_policy_output.copy()]) + combined_outputs_dict['raw_pred'] = np.concatenate([self.vision_output.copy(), self.policy_output.copy()]) return combined_outputs_dict @@ -414,7 +396,9 @@ def main(demo=False): posenet_send = messaging.new_message('cameraOdometry') mdv2sp_send = messaging.new_message('modelDataV2SP') - action = get_action_from_model(model_output, prev_action, lat_delay + DT_MDL, long_delay + DT_MDL, v_ego) + frame_delay = DT_MDL # compensate for time passed since the frame was captured: current_time - timestamp_eof is 50ms on average + action_delay = DT_MDL / 2 # middle of the interval between model output (current state) and next frame (expected state) + action = get_action_from_model(model_output, prev_action, lat_delay + frame_delay + action_delay, long_delay + frame_delay + action_delay, v_ego) prev_action = action fill_model_msg(drivingdata_send, modelv2_send, model_output, action, publish_state, meta_main.frame_id, meta_extra.frame_id, frame_id, diff --git a/selfdrive/modeld/models/big_driving_policy.onnx b/selfdrive/modeld/models/big_driving_policy.onnx new file mode 120000 index 0000000000..e1b653a14a --- /dev/null +++ b/selfdrive/modeld/models/big_driving_policy.onnx @@ -0,0 +1 @@ +driving_policy.onnx \ No newline at end of file diff --git a/selfdrive/modeld/models/big_driving_vision.onnx b/selfdrive/modeld/models/big_driving_vision.onnx new file mode 120000 index 0000000000..28ee71dd74 --- /dev/null +++ b/selfdrive/modeld/models/big_driving_vision.onnx @@ -0,0 +1 @@ +driving_vision.onnx \ No newline at end of file diff --git a/selfdrive/modeld/models/driving_off_policy.onnx b/selfdrive/modeld/models/driving_off_policy.onnx deleted file mode 100644 index 33f6e0a2c1..0000000000 --- a/selfdrive/modeld/models/driving_off_policy.onnx +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:eb6992bd60bada6162fea298e1a414b6b3d6a326db4eda46b9de62bcd8554754 -size 13393859 diff --git a/selfdrive/modeld/models/driving_on_policy.onnx b/selfdrive/modeld/models/driving_on_policy.onnx deleted file mode 100644 index cbc072409a..0000000000 --- a/selfdrive/modeld/models/driving_on_policy.onnx +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:86680a657bbb34f997034d1930bb2cb65c38b9222cea199732f72bd45791cfad -size 13022803 diff --git a/selfdrive/modeld/models/driving_policy.onnx b/selfdrive/modeld/models/driving_policy.onnx new file mode 100644 index 0000000000..7c71bc9471 --- /dev/null +++ b/selfdrive/modeld/models/driving_policy.onnx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:853c6634746ff439a848349d00e4d5581cd941f13f7c1862c31b72a31cc24858 +size 14061595 diff --git a/selfdrive/modeld/models/driving_vision.onnx b/selfdrive/modeld/models/driving_vision.onnx index 383cde35e4..afd617667c 100644 --- a/selfdrive/modeld/models/driving_vision.onnx +++ b/selfdrive/modeld/models/driving_vision.onnx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7af05e03fd170653ff5771baf373a2c57b363da12c4c411cd416dee067b4cf58 -size 23266366 +oid sha256:940e9006a25f27f0b6e85da798e6a8fd1f6dd492dd7d0b9ff1a9436460f46129 +size 46887794 diff --git a/selfdrive/modeld/parse_model_outputs.py b/selfdrive/modeld/parse_model_outputs.py index 802f0ad859..a0b45d2a98 100644 --- a/selfdrive/modeld/parse_model_outputs.py +++ b/selfdrive/modeld/parse_model_outputs.py @@ -96,17 +96,11 @@ class Parser: self.parse_mdn('pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,)) self.parse_mdn('wide_from_device_euler', outs, in_N=0, out_N=0, out_shape=(ModelConstants.WIDE_FROM_DEVICE_WIDTH,)) self.parse_mdn('road_transform', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,)) - self.parse_categorical_crossentropy('desire_pred', outs, out_shape=(ModelConstants.DESIRE_PRED_LEN,ModelConstants.DESIRE_PRED_WIDTH)) - self.parse_binary_crossentropy('meta', outs) - return outs - - def parse_off_policy_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]: - plan_mhp = self.is_mhp(outs, 'plan', ModelConstants.IDX_N * ModelConstants.PLAN_WIDTH) - plan_in_N, plan_out_N = (ModelConstants.PLAN_MHP_N, ModelConstants.PLAN_MHP_SELECTION) if plan_mhp else (0, 0) - self.parse_mdn('plan', outs, in_N=plan_in_N, out_N=plan_out_N, out_shape=(ModelConstants.IDX_N, ModelConstants.PLAN_WIDTH)) self.parse_mdn('lane_lines', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_LANE_LINES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH)) self.parse_mdn('road_edges', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_ROAD_EDGES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH)) self.parse_binary_crossentropy('lane_lines_prob', outs) + self.parse_categorical_crossentropy('desire_pred', outs, out_shape=(ModelConstants.DESIRE_PRED_LEN,ModelConstants.DESIRE_PRED_WIDTH)) + self.parse_binary_crossentropy('meta', outs) self.parse_binary_crossentropy('lead_prob', outs) lead_mhp = self.is_mhp(outs, 'lead', ModelConstants.LEAD_MHP_SELECTION * ModelConstants.LEAD_TRAJ_LEN * ModelConstants.LEAD_WIDTH) lead_in_N, lead_out_N = (ModelConstants.LEAD_MHP_N, ModelConstants.LEAD_MHP_SELECTION) if lead_mhp else (0, 0) @@ -116,7 +110,7 @@ class Parser: return outs def parse_policy_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]: - plan_mhp = self.is_mhp(outs, 'plan', ModelConstants.IDX_N * ModelConstants.PLAN_WIDTH) + plan_mhp = self.is_mhp(outs, 'plan', ModelConstants.IDX_N * ModelConstants.PLAN_WIDTH) plan_in_N, plan_out_N = (ModelConstants.PLAN_MHP_N, ModelConstants.PLAN_MHP_SELECTION) if plan_mhp else (0, 0) self.parse_mdn('plan', outs, in_N=plan_in_N, out_N=plan_out_N, out_shape=(ModelConstants.IDX_N, ModelConstants.PLAN_WIDTH)) if 'planplus' in outs: @@ -126,6 +120,5 @@ class Parser: def parse_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]: outs = self.parse_vision_outputs(outs) - outs = self.parse_off_policy_outputs(outs) outs = self.parse_policy_outputs(outs) return outs diff --git a/selfdrive/monitoring/helpers.py b/selfdrive/monitoring/helpers.py index f0c921924d..6c81fac7f0 100644 --- a/selfdrive/monitoring/helpers.py +++ b/selfdrive/monitoring/helpers.py @@ -345,10 +345,14 @@ class DriverMonitoring: self._reset_awareness() return - driver_attentive = self.driver_distraction_filter.x < 0.37 awareness_prev = self.awareness + _reaching_pre = self.awareness - self.step_change <= self.threshold_pre + _reaching_terminal = self.awareness - self.step_change <= 0 + standstill_orange_exemption = standstill and _reaching_pre + always_on_red_exemption = always_on_valid and not op_engaged and _reaching_terminal - if (driver_attentive and self.face_detected and self.pose.low_std and self.awareness > 0): + if self.awareness > 0 and \ + ((self.driver_distraction_filter.x < 0.37 and self.face_detected and self.pose.low_std) or standstill_orange_exemption): if driver_engaged: self._reset_awareness() return @@ -361,34 +365,28 @@ class DriverMonitoring: if self.awareness > self.threshold_prompt: return - _reaching_pre = self.awareness - self.step_change <= self.threshold_pre - _reaching_audible = self.awareness - self.step_change <= self.threshold_prompt - _reaching_terminal = self.awareness - self.step_change <= 0 - standstill_exemption = standstill and _reaching_pre - always_on_red_exemption = always_on_valid and not op_engaged and _reaching_terminal - certainly_distracted = self.driver_distraction_filter.x > 0.63 and self.driver_distracted and self.face_detected maybe_distracted = self.hi_stds > self.settings._HI_STD_FALLBACK_TIME or not self.face_detected if certainly_distracted or maybe_distracted: # should always be counting if distracted unless at standstill and reaching green # also will not be reaching 0 if DM is active when not engaged - if not (standstill_exemption or always_on_red_exemption): + if not (standstill_orange_exemption or always_on_red_exemption): self.awareness = max(self.awareness - self.step_change, -0.1) alert = None if self.awareness <= 0.: # terminal red alert: disengagement required - alert = EventName.driverDistracted if self.active_monitoring_mode else EventName.driverUnresponsive + alert = EventName.driverDistracted3 if self.active_monitoring_mode else EventName.driverUnresponsive3 self.terminal_time += 1 if awareness_prev > 0.: self.terminal_alert_cnt += 1 elif self.awareness <= self.threshold_prompt: # prompt orange alert - alert = EventName.promptDriverDistracted if self.active_monitoring_mode else EventName.promptDriverUnresponsive + alert = EventName.driverDistracted2 if self.active_monitoring_mode else EventName.driverUnresponsive2 elif self.awareness <= self.threshold_pre: # pre green alert - alert = EventName.preDriverDistracted if self.active_monitoring_mode else EventName.preDriverUnresponsive + alert = EventName.driverDistracted1 if self.active_monitoring_mode else EventName.driverUnresponsive1 if alert is not None: self.current_events.add(alert) diff --git a/selfdrive/monitoring/test_monitoring.py b/selfdrive/monitoring/test_monitoring.py index daa10dd83c..ee6028d609 100644 --- a/selfdrive/monitoring/test_monitoring.py +++ b/selfdrive/monitoring/test_monitoring.py @@ -76,11 +76,11 @@ class TestMonitoring: assert len(events[int((d_status.settings._DISTRACTED_TIME-d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL)/2/DT_DMON)]) == 0 assert events[int((d_status.settings._DISTRACTED_TIME-d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL + \ ((d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL-d_status.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0] == \ - EventName.preDriverDistracted + EventName.driverDistracted1 assert events[int((d_status.settings._DISTRACTED_TIME-d_status.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL + \ - ((d_status.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0] == EventName.promptDriverDistracted + ((d_status.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0] == EventName.driverDistracted2 assert events[int((d_status.settings._DISTRACTED_TIME + \ - ((TEST_TIMESPAN-10-d_status.settings._DISTRACTED_TIME)/2))/DT_DMON)].names[0] == EventName.driverDistracted + ((TEST_TIMESPAN-10-d_status.settings._DISTRACTED_TIME)/2))/DT_DMON)].names[0] == EventName.driverDistracted3 assert isinstance(d_status.awareness, float) # engaged, no face detected the whole time, no action @@ -89,11 +89,11 @@ class TestMonitoring: assert len(events[int((d_status.settings._AWARENESS_TIME-d_status.settings._AWARENESS_PRE_TIME_TILL_TERMINAL)/2/DT_DMON)]) == 0 assert events[int((d_status.settings._AWARENESS_TIME-d_status.settings._AWARENESS_PRE_TIME_TILL_TERMINAL + \ ((d_status.settings._AWARENESS_PRE_TIME_TILL_TERMINAL-d_status.settings._AWARENESS_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0] == \ - EventName.preDriverUnresponsive + EventName.driverUnresponsive1 assert events[int((d_status.settings._AWARENESS_TIME-d_status.settings._AWARENESS_PROMPT_TIME_TILL_TERMINAL + \ - ((d_status.settings._AWARENESS_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0] == EventName.promptDriverUnresponsive + ((d_status.settings._AWARENESS_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0] == EventName.driverUnresponsive2 assert events[int((d_status.settings._AWARENESS_TIME + \ - ((TEST_TIMESPAN-10-d_status.settings._AWARENESS_TIME)/2))/DT_DMON)].names[0] == EventName.driverUnresponsive + ((TEST_TIMESPAN-10-d_status.settings._AWARENESS_TIME)/2))/DT_DMON)].names[0] == EventName.driverUnresponsive3 # engaged, down to orange, driver pays attention, back to normal; then down to orange, driver touches wheel # - should have short orange recovery time and no green afterwards; wheel touch only recovers when paying attention @@ -106,10 +106,10 @@ class TestMonitoring: [car_interaction_DETECTED] * (int(TEST_TIMESPAN/DT_DMON)-int(DISTRACTED_SECONDS_TO_ORANGE*3/DT_DMON)) events, _ = self._run_seq(ds_vector, interaction_vector, always_true, always_false) assert len(events[int(DISTRACTED_SECONDS_TO_ORANGE*0.5/DT_DMON)]) == 0 - assert events[int((DISTRACTED_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0] == EventName.promptDriverDistracted + assert events[int((DISTRACTED_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0] == EventName.driverDistracted2 assert len(events[int(DISTRACTED_SECONDS_TO_ORANGE*1.5/DT_DMON)]) == 0 - assert events[int((DISTRACTED_SECONDS_TO_ORANGE*3-0.1)/DT_DMON)].names[0] == EventName.promptDriverDistracted - assert events[int((DISTRACTED_SECONDS_TO_ORANGE*3+0.1)/DT_DMON)].names[0] == EventName.promptDriverDistracted + assert events[int((DISTRACTED_SECONDS_TO_ORANGE*3-0.1)/DT_DMON)].names[0] == EventName.driverDistracted2 + assert events[int((DISTRACTED_SECONDS_TO_ORANGE*3+0.1)/DT_DMON)].names[0] == EventName.driverDistracted2 assert len(events[int((DISTRACTED_SECONDS_TO_ORANGE*3+2.5)/DT_DMON)]) == 0 # engaged, down to orange, driver dodges camera, then comes back still distracted, down to red, \ @@ -129,9 +129,9 @@ class TestMonitoring: op_vector[int((DISTRACTED_SECONDS_TO_RED+2*_invisible_time+2.5)/DT_DMON):int((DISTRACTED_SECONDS_TO_RED+2*_invisible_time+3)/DT_DMON)] \ = [False] * int(0.5/DT_DMON) events, _ = self._run_seq(ds_vector, interaction_vector, op_vector, always_false) - assert events[int((DISTRACTED_SECONDS_TO_ORANGE+0.5*_invisible_time)/DT_DMON)].names[0] == EventName.promptDriverDistracted - assert events[int((DISTRACTED_SECONDS_TO_RED+1.5*_invisible_time)/DT_DMON)].names[0] == EventName.driverDistracted - assert events[int((DISTRACTED_SECONDS_TO_RED+2*_invisible_time+1.5)/DT_DMON)].names[0] == EventName.driverDistracted + assert events[int((DISTRACTED_SECONDS_TO_ORANGE+0.5*_invisible_time)/DT_DMON)].names[0] == EventName.driverDistracted2 + assert events[int((DISTRACTED_SECONDS_TO_RED+1.5*_invisible_time)/DT_DMON)].names[0] == EventName.driverDistracted3 + assert events[int((DISTRACTED_SECONDS_TO_RED+2*_invisible_time+1.5)/DT_DMON)].names[0] == EventName.driverDistracted3 assert len(events[int((DISTRACTED_SECONDS_TO_RED+2*_invisible_time+3.5)/DT_DMON)]) == 0 # engaged, invisible driver, down to orange, driver touches wheel; then down to orange again, driver appears @@ -145,13 +145,13 @@ class TestMonitoring: interaction_vector[int((INVISIBLE_SECONDS_TO_ORANGE)/DT_DMON):int((INVISIBLE_SECONDS_TO_ORANGE+1)/DT_DMON)] = [True] * int(1/DT_DMON) events, _ = self._run_seq(ds_vector, interaction_vector, 2*always_true, 2*always_false) assert len(events[int(INVISIBLE_SECONDS_TO_ORANGE*0.5/DT_DMON)]) == 0 - assert events[int((INVISIBLE_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0] == EventName.promptDriverUnresponsive + assert events[int((INVISIBLE_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0] == EventName.driverUnresponsive2 assert len(events[int((INVISIBLE_SECONDS_TO_ORANGE+0.1)/DT_DMON)]) == 0 if _visible_time == 0.5: - assert events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1-0.1)/DT_DMON)].names[0] == EventName.promptDriverUnresponsive - assert events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1+0.1+_visible_time)/DT_DMON)].names[0] == EventName.preDriverUnresponsive + assert events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1-0.1)/DT_DMON)].names[0] == EventName.driverUnresponsive2 + assert events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1+0.1+_visible_time)/DT_DMON)].names[0] == EventName.driverUnresponsive1 elif _visible_time == 10: - assert events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1-0.1)/DT_DMON)].names[0] == EventName.promptDriverUnresponsive + assert events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1-0.1)/DT_DMON)].names[0] == EventName.driverUnresponsive2 assert len(events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1+0.1+_visible_time)/DT_DMON)]) == 0 # engaged, invisible driver, down to red, driver appears and then touches wheel, then disengages/reengages @@ -166,10 +166,10 @@ class TestMonitoring: op_vector[int((INVISIBLE_SECONDS_TO_RED+_visible_time+1)/DT_DMON):int((INVISIBLE_SECONDS_TO_RED+_visible_time+0.5)/DT_DMON)] = [False] * int(0.5/DT_DMON) events, _ = self._run_seq(ds_vector, interaction_vector, op_vector, always_false) assert len(events[int(INVISIBLE_SECONDS_TO_ORANGE*0.5/DT_DMON)]) == 0 - assert events[int((INVISIBLE_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0] == EventName.promptDriverUnresponsive - assert events[int((INVISIBLE_SECONDS_TO_RED-0.1)/DT_DMON)].names[0] == EventName.driverUnresponsive - assert events[int((INVISIBLE_SECONDS_TO_RED+0.5*_visible_time)/DT_DMON)].names[0] == EventName.driverUnresponsive - assert events[int((INVISIBLE_SECONDS_TO_RED+_visible_time+0.5)/DT_DMON)].names[0] == EventName.driverUnresponsive + assert events[int((INVISIBLE_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0] == EventName.driverUnresponsive2 + assert events[int((INVISIBLE_SECONDS_TO_RED-0.1)/DT_DMON)].names[0] == EventName.driverUnresponsive3 + assert events[int((INVISIBLE_SECONDS_TO_RED+0.5*_visible_time)/DT_DMON)].names[0] == EventName.driverUnresponsive3 + assert events[int((INVISIBLE_SECONDS_TO_RED+_visible_time+0.5)/DT_DMON)].names[0] == EventName.driverUnresponsive3 assert len(events[int((INVISIBLE_SECONDS_TO_RED+_visible_time+1+0.1)/DT_DMON)]) == 0 # disengaged, always distracted driver @@ -187,8 +187,19 @@ class TestMonitoring: events, d_status = self._run_seq(always_distracted, always_false, always_true, standstill_vector) assert len(events[int((_redlight_time-0.1)/DT_DMON)]) == 0 _pre_to_prompt = d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL - d_status.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL - assert events[int((_redlight_time+0.5)/DT_DMON)].names[0] == EventName.preDriverDistracted - assert events[int((_redlight_time+_pre_to_prompt+0.5)/DT_DMON)].names[0] == EventName.promptDriverDistracted + assert events[int((_redlight_time+0.5)/DT_DMON)].names[0] == EventName.driverDistracted1 + assert events[int((_redlight_time+_pre_to_prompt+0.5)/DT_DMON)].names[0] == EventName.driverDistracted2 + + # engaged, distracted while moving, then car stops after reaching orange + # - should reset timer to pre green at standstill + def test_distracted_then_stops(self): + _stop_time = DISTRACTED_SECONDS_TO_ORANGE + 1 # stop 1 second after reaching orange + standstill_vector = always_false[:] + standstill_vector[int(_stop_time/DT_DMON):] = [True] * int((TEST_TIMESPAN-_stop_time)/DT_DMON) + events, _ = self._run_seq(always_distracted, always_false, always_true, standstill_vector) + # just before and briefly after stopping: orange alert; goes away quickly after stopped + assert events[int((_stop_time+0.1)/DT_DMON)].names[0] == EventName.driverDistracted2 + assert len(events[int((_stop_time+0.5)/DT_DMON)]) == 0 # engaged, model is somehow uncertain and driver is distracted # - should fall back to wheel touch after uncertain alert @@ -196,11 +207,11 @@ class TestMonitoring: ds_vector = [msg_DISTRACTED_BUT_SOMEHOW_UNCERTAIN] * int(TEST_TIMESPAN/DT_DMON) interaction_vector = always_false[:] events, d_status = self._run_seq(ds_vector, interaction_vector, always_true, always_false) - assert EventName.preDriverUnresponsive in \ + assert EventName.driverUnresponsive1 in \ events[int((INVISIBLE_SECONDS_TO_ORANGE-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME-0.1)/DT_DMON)].names - assert EventName.promptDriverUnresponsive in \ + assert EventName.driverUnresponsive2 in \ events[int((INVISIBLE_SECONDS_TO_ORANGE-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME+0.1)/DT_DMON)].names - assert EventName.driverUnresponsive in \ + assert EventName.driverUnresponsive3 in \ events[int((INVISIBLE_SECONDS_TO_RED-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME+0.1)/DT_DMON)].names @@ -265,4 +276,3 @@ def test_enabled_states(enabled_state, lat_active_state, expected): actual_enabled = captured_args[0] assert actual_enabled == expected, f"Expected op_engaged={expected}, but got {actual_enabled}" - diff --git a/selfdrive/pandad/pandad.cc b/selfdrive/pandad/pandad.cc index 3d0a551d80..cafc3e1225 100644 --- a/selfdrive/pandad/pandad.cc +++ b/selfdrive/pandad/pandad.cc @@ -21,8 +21,6 @@ #define CUTOFF_IL 400 #define SATURATE_IL 1000 -#define ALT_EXP_MADS_DISENGAGE_LATERAL_ON_BRAKE 2048 - ExitHandler do_exit; bool check_connected(Panda *panda) { @@ -34,15 +32,8 @@ bool check_connected(Panda *panda) { } bool process_mads_heartbeat(SubMaster *sm) { - const int &alt_exp = (*sm)["carParams"].getCarParams().getAlternativeExperience(); - const bool disengage_lateral_on_brake = (alt_exp & ALT_EXP_MADS_DISENGAGE_LATERAL_ON_BRAKE) != 0; - const auto &mads = (*sm)["selfdriveStateSP"].getSelfdriveStateSP().getMads(); - const bool heartbeat_type = disengage_lateral_on_brake ? mads.getActive() : mads.getEnabled(); - - const bool engaged = sm->allAliveAndValid({"selfdriveStateSP"}) && heartbeat_type; - - return engaged; + return sm->allAliveAndValid({"selfdriveStateSP"}) && mads.getEnabled(); } Panda *connect(std::string serial) { @@ -152,6 +143,8 @@ void fill_panda_state(cereal::PandaState::Builder &ps, cereal::PandaState::Panda ps.setSbu1Voltage(health.sbu1_voltage_mV / 1000.0f); ps.setSbu2Voltage(health.sbu2_voltage_mV / 1000.0f); ps.setSoundOutputLevel(health.sound_output_level_pkt); + ps.setControlsAllowedLateral(health.controls_allowed_lateral_pkt); + ps.setControlsAllowedLongitudinal(health.controls_allowed_longitudinal_pkt); } void fill_panda_can_state(cereal::PandaState::PandaCanState::Builder &cs, const can_health_t &can_health) { @@ -380,7 +373,7 @@ void pandad_run(Panda *panda) { Params params; RateKeeper rk("pandad", 100); - SubMaster sm({"selfdriveState", "selfdriveStateSP", "carParams"}); + SubMaster sm({"selfdriveState", "selfdriveStateSP"}); PubMaster pm({"can", "pandaStates", "peripheralState"}); PandaSafety panda_safety(panda); bool engaged = false; diff --git a/selfdrive/selfdrived/events.py b/selfdrive/selfdrived/events.py index 0597aa9f17..c9b281436c 100755 --- a/selfdrive/selfdrived/events.py +++ b/selfdrive/selfdrived/events.py @@ -338,7 +338,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { Priority.LOW, VisualAlert.steerRequired, AudibleAlert.prompt, 1.8), }, - EventName.preDriverDistracted: { + EventName.driverDistracted1: { ET.PERMANENT: Alert( "Pay Attention", "", @@ -346,7 +346,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { Priority.LOW, VisualAlert.none, AudibleAlert.none, .1), }, - EventName.promptDriverDistracted: { + EventName.driverDistracted2: { ET.PERMANENT: Alert( "Pay Attention", "Driver Distracted", @@ -354,7 +354,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, .1), }, - EventName.driverDistracted: { + EventName.driverDistracted3: { ET.PERMANENT: Alert( "DISENGAGE IMMEDIATELY", "Driver Distracted", @@ -362,7 +362,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1), }, - EventName.preDriverUnresponsive: { + EventName.driverUnresponsive1: { ET.PERMANENT: Alert( "Touch Steering Wheel: No Face Detected", "", @@ -370,7 +370,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .1), }, - EventName.promptDriverUnresponsive: { + EventName.driverUnresponsive2: { ET.PERMANENT: Alert( "Touch Steering Wheel", "Driver Unresponsive", @@ -378,7 +378,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, .1), }, - EventName.driverUnresponsive: { + EventName.driverUnresponsive3: { ET.PERMANENT: Alert( "DISENGAGE IMMEDIATELY", "Driver Unresponsive", @@ -858,14 +858,14 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { if HARDWARE.get_device_type() == 'mici': EVENTS.update({ - EventName.preDriverDistracted: { + EventName.driverDistracted1: { ET.PERMANENT: Alert( "Pay Attention", "", AlertStatus.normal, AlertSize.small, Priority.LOW, VisualAlert.none, AudibleAlert.none, 2), }, - EventName.promptDriverDistracted: { + EventName.driverDistracted2: { ET.PERMANENT: Alert( "Pay Attention", "Driver Distracted", diff --git a/selfdrive/test/fuzzy_generation.py b/selfdrive/test/fuzzy_generation.py index 131dab47b2..9f028a8fc8 100644 --- a/selfdrive/test/fuzzy_generation.py +++ b/selfdrive/test/fuzzy_generation.py @@ -46,8 +46,8 @@ class FuzzyGenerator: def generate_struct(self, schema: capnp.lib.capnp._StructSchema, event: str | None = None) -> st.SearchStrategy[dict[str, Any]]: single_fill: tuple[str, ...] = (event,) if event else (self.draw(st.sampled_from(schema.union_fields)),) if schema.union_fields else () - fields_to_generate = schema.non_union_fields + single_fill - return st.fixed_dictionaries({field: self.generate_field(schema.fields[field]) for field in fields_to_generate if not field.endswith('DEPRECATED')}) + fields_to_generate = [f for f in schema.non_union_fields + single_fill if not f.endswith('DEPRECATED') and f != 'deprecated'] + return st.fixed_dictionaries({field: self.generate_field(schema.fields[field]) for field in fields_to_generate}) @staticmethod @cache diff --git a/selfdrive/test/process_replay/migration.py b/selfdrive/test/process_replay/migration.py index d41664040a..278c366609 100644 --- a/selfdrive/test/process_replay/migration.py +++ b/selfdrive/test/process_replay/migration.py @@ -100,6 +100,17 @@ def migration(inputs: list[str], product: str|None=None): return decorator +def migrate_onroad_event(event: capnp.lib.capnp._DynamicStructReader): + event_dict = event.to_dict() + try: + return log.OnroadEvent(**event_dict) + except capnp.lib.capnp.KjException as e: + # Ignore legacy events the current schema no longer defines. + if "enum has no such enumerant" in str(e): + return None + raise + + @migration(inputs=["longitudinalPlan", "carParams"]) def migrate_longitudinalPlan(msgs): ops = [] @@ -216,7 +227,7 @@ def migrate_controlsState(msgs): for field in ("enabled", "active", "state", "engageable", "alertText1", "alertText2", "alertStatus", "alertSize", "alertType", "experimentalMode", "personality"): - setattr(ss, field, getattr(msg.controlsState, field+"DEPRECATED")) + setattr(ss, field, getattr(msg.controlsState.deprecated, field)) add_ops.append(m.as_reader()) return [], add_ops, [] @@ -229,10 +240,10 @@ def migrate_carState(msgs): if msg.which() == 'controlsState': last_cs = msg elif msg.which() == 'carState' and last_cs is not None: - if last_cs.controlsState.vCruiseDEPRECATED - msg.carState.vCruise > 0.1: + if last_cs.controlsState.deprecated.vCruise - msg.carState.vCruise > 0.1: msg = msg.as_builder() - msg.carState.vCruise = last_cs.controlsState.vCruiseDEPRECATED - msg.carState.vCruiseCluster = last_cs.controlsState.vCruiseClusterDEPRECATED + msg.carState.vCruise = last_cs.controlsState.deprecated.vCruise + msg.carState.vCruiseCluster = last_cs.controlsState.deprecated.vCruiseCluster ops.append((index, msg.as_reader())) return ops, [], [] @@ -458,12 +469,13 @@ def migrate_onroadEvents(msgs): for event in msg.onroadEventsDEPRECATED: try: if not str(event.name).endswith('DEPRECATED'): - # dict converts name enum into string representation - onroadEvents.append(log.OnroadEvent(**event.to_dict())) + migrated_event = migrate_onroad_event(event) + if migrated_event is not None: + onroadEvents.append(migrated_event) except RuntimeError: # Member was null traceback.print_exc() - new_msg = messaging.new_message('onroadEvents', len(msg.onroadEventsDEPRECATED)) + new_msg = messaging.new_message('onroadEvents', len(onroadEvents)) new_msg.valid = msg.valid new_msg.logMonoTime = msg.logMonoTime new_msg.onroadEvents = onroadEvents @@ -478,11 +490,12 @@ def migrate_driverMonitoringState(msgs): for index, msg in msgs: msg = msg.as_builder() events = [] - for event in msg.driverMonitoringState.eventsDEPRECATED: + for event in msg.driverMonitoringState.deprecated.events: try: if not str(event.name).endswith('DEPRECATED'): - # dict converts name enum into string representation - events.append(log.OnroadEvent(**event.to_dict())) + migrated_event = migrate_onroad_event(event) + if migrated_event is not None: + events.append(migrated_event) except RuntimeError: # Member was null traceback.print_exc() diff --git a/selfdrive/ui/installer/installer.cc b/selfdrive/ui/installer/installer.cc index fb661b966d..0832fbb628 100644 --- a/selfdrive/ui/installer/installer.cc +++ b/selfdrive/ui/installer/installer.cc @@ -144,6 +144,7 @@ int cachedFetch(const std::string &cache) { LOGD("Fetching with cache: %s", cache.c_str()); run(util::string_format("cp -rp %s %s", cache.c_str(), TMP_INSTALL_PATH).c_str()); + run(util::string_format("cd %s && git remote set-url origin %s", TMP_INSTALL_PATH, GIT_URL.c_str()).c_str()); run(util::string_format("cd %s && git remote set-branches --add origin %s", TMP_INSTALL_PATH, migrated_branch.c_str()).c_str()); renderProgress(10); diff --git a/selfdrive/ui/mici/layouts/main.py b/selfdrive/ui/mici/layouts/main.py index 2f41e1f172..e7dfd34101 100644 --- a/selfdrive/ui/mici/layouts/main.py +++ b/selfdrive/ui/mici/layouts/main.py @@ -13,7 +13,6 @@ from openpilot.system.ui.lib.application import gui_app if gui_app.sunnypilot_ui(): from openpilot.selfdrive.ui.sunnypilot.mici.layouts.settings import SettingsLayoutSP as SettingsLayout - ONROAD_DELAY = 2.5 # seconds diff --git a/selfdrive/ui/mici/onroad/hud_renderer.py b/selfdrive/ui/mici/onroad/hud_renderer.py index 307e3cc17b..76724244d0 100644 --- a/selfdrive/ui/mici/onroad/hud_renderer.py +++ b/selfdrive/ui/mici/onroad/hud_renderer.py @@ -153,7 +153,7 @@ class HudRenderer(Widget): v_cruise_cluster = car_state.vCruiseCluster set_speed = ( - controls_state.vCruiseDEPRECATED if v_cruise_cluster == 0.0 else v_cruise_cluster + controls_state.deprecated.vCruise if v_cruise_cluster == 0.0 else v_cruise_cluster ) engaged = sm['selfdriveState'].enabled if (set_speed != self.set_speed and engaged) or (engaged and not self._engaged): diff --git a/selfdrive/ui/onroad/hud_renderer.py b/selfdrive/ui/onroad/hud_renderer.py index 79f150deea..73df8b3961 100644 --- a/selfdrive/ui/onroad/hud_renderer.py +++ b/selfdrive/ui/onroad/hud_renderer.py @@ -86,7 +86,7 @@ class HudRenderer(Widget): v_cruise_cluster = car_state.vCruiseCluster self.set_speed = ( - controls_state.vCruiseDEPRECATED if v_cruise_cluster == 0.0 else v_cruise_cluster + controls_state.deprecated.vCruise if v_cruise_cluster == 0.0 else v_cruise_cluster ) self.is_cruise_set = 0 < self.set_speed < SET_SPEED_NA self.is_cruise_available = self.set_speed != -1 diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index cea22655b1..6b64289766 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -20,6 +20,7 @@ SAMPLE_RATE = 48000 SAMPLE_BUFFER = 4096 # (approx 100ms) MAX_VOLUME = 1.0 MIN_VOLUME = 0.1 +ALERT_RAMP_TIME = 4 # seconds to ramp to max volume for warningImmediate SELFDRIVE_STATE_TIMEOUT = 5 # 5 seconds FILTER_DT = 1. / (micd.SAMPLE_RATE / micd.FFT_SAMPLES) @@ -82,6 +83,9 @@ class Soundd(QuietMode): self.current_volume = MIN_VOLUME self.current_sound_frame = 0 + self.ramp_start_volume = MIN_VOLUME + self.ramp_start_time = 0. + self.selfdrive_timeout_alert = False self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False) @@ -130,6 +134,9 @@ class Soundd(QuietMode): def update_alert(self, new_alert): current_alert_played_once = self.current_alert == AudibleAlert.none or self.current_sound_frame > len(self.loaded_sounds[self.current_alert]) if self.current_alert != new_alert and (new_alert != AudibleAlert.none or current_alert_played_once): + if new_alert == AudibleAlert.warningImmediate: + self.ramp_start_volume = self.current_volume + self.ramp_start_time = time.monotonic() self.current_alert = new_alert self.current_sound_frame = 0 @@ -170,12 +177,19 @@ class Soundd(QuietMode): self.load_param() - if sm.updated['soundPressure'] and self.current_alert == AudibleAlert.none: # only update volume filter when not playing alert + # Always update volume, even when alert is playing + if sm.updated['soundPressure']: self.spl_filter_weighted.update(sm["soundPressure"].soundPressureWeightedDb) self.current_volume = self.calculate_volume(float(self.spl_filter_weighted.x)) self.get_audible_alert(sm) + # Ramp up immediate warning sound over 4s + if self.current_alert == AudibleAlert.warningImmediate: + elapsed = time.monotonic() - self.ramp_start_time + ramp_vol = float(np.interp(elapsed, [0, ALERT_RAMP_TIME], [self.ramp_start_volume, MAX_VOLUME])) + self.current_volume = max(self.current_volume, ramp_vol) + rk.keep_time() assert stream.active diff --git a/selfdrive/ui/sunnypilot/layouts/settings/display.py b/selfdrive/ui/sunnypilot/layouts/settings/display.py index acd7b52dcc..8ba5663662 100644 --- a/selfdrive/ui/sunnypilot/layouts/settings/display.py +++ b/selfdrive/ui/sunnypilot/layouts/settings/display.py @@ -6,12 +6,10 @@ See the LICENSE.md file in the root directory for more details. """ from enum import IntEnum -from openpilot.common.params import Params -from openpilot.system.ui.sunnypilot.widgets.option_control import OptionControlSP from openpilot.system.ui.widgets import Widget from openpilot.system.ui.lib.multilang import tr from openpilot.system.ui.widgets.scroller_tici import Scroller -from openpilot.system.ui.sunnypilot.widgets.list_view import option_item_sp, ToggleActionSP +from openpilot.system.ui.sunnypilot.widgets.list_view import option_item_sp from openpilot.sunnypilot.system.params_migration import ONROAD_BRIGHTNESS_TIMER_VALUES @@ -25,7 +23,6 @@ class DisplayLayout(Widget): def __init__(self): super().__init__() - self._params = Params() items = self._initialize_items() self._scroller = Scroller(items, line_separator=True, spacing=0) @@ -87,17 +84,7 @@ class DisplayLayout(Widget): def _update_state(self): super()._update_state() - for _item in self._scroller._items: - if isinstance(_item.action_item, ToggleActionSP) and _item.action_item.toggle.param_key is not None: - _item.action_item.set_state(self._params.get_bool(_item.action_item.toggle.param_key)) - elif isinstance(_item.action_item, OptionControlSP) and _item.action_item.param_key is not None: - raw_value = self._params.get(_item.action_item.param_key, return_default=True) - if _item.action_item.value_map: - reverse_map = {v: k for k, v in _item.action_item.value_map.items()} - raw_value = reverse_map.get(raw_value, _item.action_item.current_value) - _item.action_item.set_value(raw_value) - - brightness_val = self._params.get("OnroadScreenOffBrightness", return_default=True) + brightness_val = self._onroad_brightness.action_item.current_value self._onroad_brightness_timer.action_item.set_enabled(brightness_val not in (OnroadBrightness.AUTO, OnroadBrightness.AUTO_DARK)) def _render(self, rect): diff --git a/selfdrive/ui/sunnypilot/layouts/settings/models.py b/selfdrive/ui/sunnypilot/layouts/settings/models.py index b34604af0c..adbd99f1f3 100644 --- a/selfdrive/ui/sunnypilot/layouts/settings/models.py +++ b/selfdrive/ui/sunnypilot/layouts/settings/models.py @@ -41,7 +41,7 @@ class ModelsLayout(Widget): self._initialize_items() - self.clear_cache_item.action_item.set_value(f"{self._calculate_cache_size():.2f} MB") + self.clear_cache_item.action_item.set_value(f"{self.calculate_cache_size():.2f} MB") for ctrl, key in [(self.lane_turn_value_control, "LaneTurnValue"), (self.delay_control, "LagdToggleDelay")]: ctrl.action_item.set_value(int(float(ui_state.params.get(key, return_default=True)) * 100)) @@ -112,7 +112,7 @@ class ModelsLayout(Widget): self.model_manager.selectedBundle.status == custom.ModelManagerSP.DownloadStatus.downloading) @staticmethod - def _calculate_cache_size(): + def calculate_cache_size(): cache_size = 0.0 if os.path.exists(CUSTOM_MODEL_PATH): cache_size = sum(os.path.getsize(os.path.join(CUSTOM_MODEL_PATH, file)) for file in os.listdir(CUSTOM_MODEL_PATH)) / (1024**2) @@ -122,7 +122,7 @@ class ModelsLayout(Widget): def _callback(response): if response == DialogResult.CONFIRM: ui_state.params.put_bool("ModelManager_ClearCache", True) - self.clear_cache_item.action_item.set_value(f"{self._calculate_cache_size():.2f} MB") + self.clear_cache_item.action_item.set_value(f"{self.calculate_cache_size():.2f} MB") dialog = ConfirmDialog(tr("This will delete ALL downloaded models from the cache except the currently active model. Are you sure?"), tr("Clear Cache"), callback=_callback) @@ -155,7 +155,7 @@ class ModelsLayout(Widget): if (current_time := time.monotonic()) - self.last_cache_calc_time > 0.5: self.last_cache_calc_time = current_time - self.clear_cache_item.action_item.set_value(f"{self._calculate_cache_size():.2f} MB") + self.clear_cache_item.action_item.set_value(f"{self.calculate_cache_size():.2f} MB") if self.download_status == custom.ModelManagerSP.DownloadStatus.downloading: device._reset_interactive_timeout() diff --git a/selfdrive/ui/sunnypilot/mici/layouts/models.py b/selfdrive/ui/sunnypilot/mici/layouts/models.py index d8da750fe1..331743416f 100644 --- a/selfdrive/ui/sunnypilot/mici/layouts/models.py +++ b/selfdrive/ui/sunnypilot/mici/layouts/models.py @@ -5,13 +5,45 @@ This file is part of sunnypilot and is licensed under the MIT License. See the LICENSE.md file in the root directory for more details. """ from collections.abc import Callable +import pyray as rl from cereal import custom from openpilot.selfdrive.ui.mici.widgets.button import BigButton -from openpilot.selfdrive.ui.ui_state import ui_state +from openpilot.selfdrive.ui.sunnypilot.layouts.settings.models import ModelsLayout +from openpilot.selfdrive.ui.ui_state import ui_state, device +from openpilot.system.ui.lib.application import FontWeight, gui_app from openpilot.system.ui.lib.multilang import tr +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.label import UnifiedLabel from openpilot.system.ui.widgets.scroller import NavScroller +class CurrentModelInfo(Widget): + def __init__(self): + super().__init__() + + self.set_rect(rl.Rectangle(0, 0, 360, 180)) + + header_color = rl.Color(255, 255, 255, int(255 * 0.9)) + subheader_color = rl.Color(255, 255, 255, int(255 * 0.9 * 0.65)) + max_width = int(self._rect.width - 20) + self.current_model_header = UnifiedLabel(tr("active model"), 48, max_width=max_width, text_color=header_color, font_weight=FontWeight.DISPLAY) + self.current_model_text = UnifiedLabel(tr("default model"), 32, max_width=max_width, text_color=subheader_color, font_weight=FontWeight.ROMAN, scroll=True) + + self.info_header = UnifiedLabel("cache size", 48, max_width=max_width, text_color=header_color, font_weight=FontWeight.DISPLAY) + self.info_text = UnifiedLabel("0 mb", 32, max_width=max_width, text_color=subheader_color, font_weight=FontWeight.ROMAN) + + def _render(self, _): + self.current_model_header.set_position(self._rect.x + 20, self._rect.y - 10) + self.current_model_header.render() + + self.current_model_text.set_position(self._rect.x + 20, self._rect.y + 68 - 25) + self.current_model_text.render() + + self.info_header.set_position(self._rect.x + 20, self._rect.y + 114 - 30) + self.info_header.render() + + self.info_text.set_position(self._rect.x + 20, self._rect.y + 161 - 25) + self.info_text.render() class ModelsLayoutMici(NavScroller): def __init__(self, back_callback: Callable): @@ -20,25 +52,35 @@ class ModelsLayoutMici(NavScroller): self.original_back_callback = back_callback self.focused_widget = None - self.current_model_btn = BigButton(tr("current model")) - self.current_model_btn.set_click_callback(self._show_folders) + self.current_model_info = CurrentModelInfo() + self._download_progress = "." + self._download_frame = 0 + self._was_downloading = False + + self.select_model_btn = BigButton(tr("select model")) + self.select_model_btn.set_click_callback(self._show_folders) self.cancel_download_btn = BigButton(tr("cancel download")) self.cancel_download_btn.set_click_callback(lambda: ui_state.params.remove("ModelManager_DownloadIndex")) - self.main_items = [self.current_model_btn, self.cancel_download_btn] + self.main_items = [self.current_model_info, self.select_model_btn, self.cancel_download_btn] self._scroller.add_widgets(self.main_items) @property def model_manager(self): return ui_state.sm["modelManagerSP"] - def _get_grouped_bundles(self): + def _get_grouped_bundles(self, favorites = None): bundles = self.model_manager.availableBundles folders = {} for bundle in bundles: folder = next((override.value for override in bundle.overrides if override.key == "folder"), "") folders.setdefault(folder, []).append(bundle) + + if favorites: + for fav_bundle in [bundle for bundle in bundles if bundle.ref in favorites]: + folders.setdefault("favorites", []).append(fav_bundle) + return folders def _show_selection_view(self, items, back_callback: Callable): @@ -49,18 +91,25 @@ class ModelsLayoutMici(NavScroller): self.set_back_callback(back_callback) def _show_folders(self): - self.focused_widget = self.current_model_btn - folders = self._get_grouped_bundles() + self.focused_widget = self.select_model_btn + + favs = ui_state.params.get("ModelManager_Favs") + favorites = set(favs.split(';')) if favs else set() + + folders = self._get_grouped_bundles(favorites) folder_buttons = [] default_btn = BigButton(tr("default model")) default_btn.set_click_callback(self._select_default) folder_buttons.append(default_btn) for folder in sorted(folders.keys(), key=lambda f: max((bundle.index for bundle in folders[f]), default=-1), reverse=True): - if folder.lower() in ["release models", "master models"]: + if folder.lower() in ["release models", "master models", "favorites"]: btn = BigButton(folder.lower()) btn.set_click_callback(lambda f=folder: self._select_folder(f)) - folder_buttons.append(btn) + if folder.lower() == "favorites": + folder_buttons.insert(0, btn) + else: + folder_buttons.append(btn) self._show_selection_view(folder_buttons, self._reset_main_view) def _select_model(self, bundle): @@ -72,7 +121,10 @@ class ModelsLayoutMici(NavScroller): self._reset_main_view() def _select_folder(self, folder_name): - folders = self._get_grouped_bundles() + favs = ui_state.params.get("ModelManager_Favs") + favorites = set(favs.split(';')) if favs else set() + + folders = self._get_grouped_bundles(favorites) bundles = sorted(folders.get(folder_name, []), key=lambda b: b.index, reverse=True) btns = [] @@ -86,29 +138,62 @@ class ModelsLayoutMici(NavScroller): def _reset_main_view(self): self._scroller._items = self.main_items self.set_back_callback(self.original_back_callback) - if self.focused_widget and self.focused_widget in self.main_items: - x = self._scroller._pad - for item in self.main_items: - if not item.is_visible: - continue - if item == self.focused_widget: - break - x += item.rect.width + self._scroller._spacing - self._scroller.scroll_panel.set_offset(0) - self._scroller.scroll_to(x) - self.focused_widget = None - else: - self._scroller.scroll_panel.set_offset(0) + self._scroller.scroll_panel.set_offset(0) + self._scroller.scroll_to(0) + + def hide_event(self): + super().hide_event() + if self._was_downloading: + device.set_override_interactive_timeout(None) + self._was_downloading = False def _update_state(self): super()._update_state() + self.select_model_btn.set_enabled(ui_state.is_offroad()) + self.cancel_download_btn.set_visible(False) + self.current_model_info.current_model_header._shimmer = False + self.current_model_info.info_header._shimmer = False + manager = self.model_manager - if manager.selectedBundle and manager.selectedBundle.status == custom.ModelManagerSP.DownloadStatus.downloading: - self.current_model_btn.set_value("downloading...") + self._download_frame += 1 + should_update = self._download_frame % (gui_app.target_fps / 2) == 0 + if should_update: + self._download_progress = self._download_progress + "." if len(self._download_progress) < 3 else "" + + is_downloading = (manager.selectedBundle + and manager.selectedBundle.status == custom.ModelManagerSP.DownloadStatus.downloading) + if self._was_downloading and not is_downloading: + device.set_override_interactive_timeout(None) + self._was_downloading = is_downloading + + self.current_model_info.current_model_header.set_text(tr("active model")) + self.current_model_info.current_model_text.set_text(manager.activeBundle.displayName.lower() if manager.activeBundle.index > 0 else tr("default model")) + self.current_model_info.info_header.set_text(tr("cache size")) + self.current_model_info.info_text.set_text(f"{ModelsLayout.calculate_cache_size():.2f} MB") + + if manager.selectedBundle and manager.selectedBundle.status == custom.ModelManagerSP.DownloadStatus.failed: + self.current_model_info.info_header.set_text(tr("error") + self._download_progress) + self.current_model_info.info_text.set_text(tr("download failed")) + + elif manager.selectedBundle and manager.selectedBundle.status == custom.ModelManagerSP.DownloadStatus.downloading: self.cancel_download_btn.set_visible(True) - else: - self.current_model_btn.set_value(manager.activeBundle.internalName.lower() if manager.activeBundle else tr("default model")) - self.cancel_download_btn.set_visible(False) - self.current_model_btn.set_enabled(ui_state.is_offroad()) - self.current_model_btn.set_text(tr("current model")) + device.set_override_interactive_timeout(5) + progress = 0.0 + count = 0 + for model in manager.selectedBundle.models: + count += 1 + p = model.artifact.downloadProgress + if p.status == custom.ModelManagerSP.DownloadStatus.downloading: + progress += p.progress + elif p.status in (custom.ModelManagerSP.DownloadStatus.downloaded, + custom.ModelManagerSP.DownloadStatus.cached): + progress += 100.0 + + self.current_model_info.current_model_header.set_text(tr("downloading")) + self.current_model_info.current_model_header._shimmer = True + self.current_model_info.current_model_text.set_text(f"{manager.selectedBundle.internalName.lower()}") + self.current_model_info.info_header.set_text(tr("progress") + self._download_progress) + self.current_model_info.info_header._shimmer = True + self.current_model_info.info_text.set_text(f"{progress/count:.2f}%") + diff --git a/selfdrive/ui/sunnypilot/mici/layouts/settings.py b/selfdrive/ui/sunnypilot/mici/layouts/settings.py index 9e160521c7..85a782ecb7 100644 --- a/selfdrive/ui/sunnypilot/mici/layouts/settings.py +++ b/selfdrive/ui/sunnypilot/mici/layouts/settings.py @@ -5,18 +5,32 @@ This file is part of sunnypilot and is licensed under the MIT License. See the LICENSE.md file in the root directory for more details. """ from openpilot.selfdrive.ui.mici.layouts.settings import settings as OP -from openpilot.selfdrive.ui.mici.widgets.button import BigButton +from openpilot.selfdrive.ui.mici.layouts.settings.device import DeviceLayoutMici +from openpilot.selfdrive.ui.mici.widgets.button import BigButton, BigCircleButton +from openpilot.selfdrive.ui.mici.widgets.dialog import BigConfirmationDialog, BigDialog from openpilot.selfdrive.ui.sunnypilot.mici.layouts.sunnylink import SunnylinkLayoutMici from openpilot.selfdrive.ui.sunnypilot.mici.layouts.models import ModelsLayoutMici +from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.system.ui.lib.application import gui_app +from openpilot.system.ui.lib.multilang import tr ICON_SIZE = 70 +BIG_ICON_SIZE = 110 class SettingsLayoutSP(OP.SettingsLayout): def __init__(self): OP.SettingsLayout.__init__(self) + device_panel = DeviceLayoutMici() + self._scroller._items[2].set_click_callback(lambda: gui_app.push_widget(device_panel)) + + self.icon_offroad_enable = gui_app.texture("../../sunnypilot/selfdrive/assets/icons_mici/always_offroad.png", BIG_ICON_SIZE, + BIG_ICON_SIZE) + self.icon_offroad_disable = gui_app.texture("../../sunnypilot/selfdrive/assets/icons_mici/disable_offroad.png", BIG_ICON_SIZE, + BIG_ICON_SIZE) + self.icon_offroad_slider = gui_app.texture("icons_mici/settings/device/lkas.png", BIG_ICON_SIZE, BIG_ICON_SIZE) + sunnylink_panel = SunnylinkLayoutMici(back_callback=gui_app.pop_widget) sunnylink_btn = BigButton("sunnylink", "", gui_app.texture("icons_mici/settings/developer/ssh.png", ICON_SIZE, ICON_SIZE)) sunnylink_btn.set_click_callback(lambda: gui_app.push_widget(sunnylink_panel)) @@ -25,10 +39,53 @@ class SettingsLayoutSP(OP.SettingsLayout): models_btn = BigButton("models", "", gui_app.texture("../../sunnypilot/selfdrive/assets/offroad/icon_models.png", ICON_SIZE, ICON_SIZE)) models_btn.set_click_callback(lambda: gui_app.push_widget(models_panel)) + # onroad: enable button sits at the front (left of toggles) + self._enable_offroad_btn_onroad = BigCircleButton(self.icon_offroad_enable, red=True) + self._enable_offroad_btn_onroad.set_click_callback(lambda: self._handle_always_offroad(True)) + self._enable_offroad_btn_onroad.set_visible(lambda: ui_state.started and not ui_state.always_offroad) + + # offroad: enable button sits at the end (right of developer) + self._enable_offroad_btn_offroad = BigCircleButton(self.icon_offroad_enable, red=True) + self._enable_offroad_btn_offroad.set_click_callback(lambda: self._handle_always_offroad(True)) + self._enable_offroad_btn_offroad.set_visible(lambda: not ui_state.started and not ui_state.always_offroad) + + self._disable_offroad_btn = BigCircleButton(self.icon_offroad_disable, red=False) + self._disable_offroad_btn.set_click_callback(lambda: self._handle_always_offroad(False)) + self._disable_offroad_btn.set_visible(lambda: ui_state.always_offroad) + items = self._scroller._items.copy() items.insert(1, sunnylink_btn) items.insert(2, models_btn) + + # front slots (only one ever visible at a time): exit-always-offroad, then enable-onroad + items.insert(0, self._enable_offroad_btn_onroad) + items.insert(0, self._disable_offroad_btn) + # end slot: enable-offroad (right of developer) + items.append(self._enable_offroad_btn_offroad) + self._scroller._items.clear() for item in items: self._scroller.add_widget(item) + + def _update_state(self): + super()._update_state() + + def _handle_always_offroad(self, enable: bool): + + def _set_offroad_status(status: bool): + if not ui_state.engaged: + ui_state.params.put_bool("OffroadMode", status) + ui_state.always_offroad = status + + if not enable: + dlg = BigConfirmationDialog(tr("slide to exit always offroad"), self.icon_offroad_slider, red=False, + confirm_callback=lambda: _set_offroad_status(False)) + else: + if ui_state.engaged: + gui_app.push_widget(BigDialog(tr("disengage to enable always offroad"), "", )) + return + + dlg = BigConfirmationDialog(tr("slide to force offroad"), self.icon_offroad_slider, red=True, + confirm_callback=lambda: _set_offroad_status(True)) + gui_app.push_widget(dlg) diff --git a/selfdrive/ui/sunnypilot/ui_state.py b/selfdrive/ui/sunnypilot/ui_state.py index afd07d53a4..91c69b8fe3 100644 --- a/selfdrive/ui/sunnypilot/ui_state.py +++ b/selfdrive/ui/sunnypilot/ui_state.py @@ -148,6 +148,7 @@ class UIStateSP: self.true_v_ego_ui = self.params.get_bool("TrueVEgoUI") self.turn_signals = self.params.get_bool("ShowTurnSignals") self.boot_offroad_mode = self.params.get("DeviceBootMode", return_default=True) + self.always_offroad = self.params.get_bool("OffroadMode") def _enforce_sp_constraints(self) -> None: has_long = getattr(self, 'has_longitudinal_control', False) diff --git a/sunnypilot/mads/mads.py b/sunnypilot/mads/mads.py index 7eab55e6ea..0c87da4a2a 100644 --- a/sunnypilot/mads/mads.py +++ b/sunnypilot/mads/mads.py @@ -33,6 +33,7 @@ class ModularAssistiveDrivingSystem: self.enabled = False self.active = False self.available = False + self.lateral_mismatch_counter = 0 self.allow_always = False self.no_main_cruise = False self.selfdrive = selfdrive @@ -104,6 +105,17 @@ class ModularAssistiveDrivingSystem: self.events.remove(old_event) self.events_sp.add(new_event) + def data_sample(self): + # When the safety and selfdrived do not agree on controls_allowed_lateral + # we want to disengage sunnypilot. However the status from the panda goes through + # another socket other than the CAN messages and one can arrive earlier than the other. + # Therefore we allow a mismatch for two samples, then we trigger the disengagement. + if not self.active or self.selfdrive.enabled: + self.lateral_mismatch_counter = 0 + elif any(not ps.controlsAllowedLateral for ps in self.selfdrive.sm['pandaStates'] + if ps.safetyModel not in IGNORED_SAFETY_MODES): + self.lateral_mismatch_counter += 1 + def update_events(self, CS: structs.CarState): if not self.selfdrive.enabled and self.enabled: if CS.standstill: @@ -186,6 +198,9 @@ class ModularAssistiveDrivingSystem: if self.state_machine.state == State.paused: self.events_sp.add(EventNameSP.silentLkasEnable) + if self.lateral_mismatch_counter >= 200: + self.events_sp.add(EventNameSP.controlsMismatchLateral) + self.events.remove(EventName.pcmDisable) self.events.remove(EventName.buttonCancel) self.events.remove(EventName.pedalPressed) @@ -195,6 +210,8 @@ class ModularAssistiveDrivingSystem: if not self.enabled_toggle: return + self.data_sample() + self.update_events(CS) if not self.CP.passive and self.selfdrive.initialized: diff --git a/sunnypilot/modeld_v2/SConscript b/sunnypilot/modeld_v2/SConscript index ddf889c0c0..8526fd2729 100644 --- a/sunnypilot/modeld_v2/SConscript +++ b/sunnypilot/modeld_v2/SConscript @@ -13,7 +13,7 @@ if PC: model_dir = Dir("models").abspath cmd = f'python3 {Dir("#sunnypilot/modeld_v2").abspath}/install_models_pc.py {model_dir}' - for model_name in ['supercombo', 'driving_vision', 'driving_off_policy', 'driving_policy']: + for model_name in ['supercombo', 'driving_vision', 'driving_off_policy', 'driving_on_policy', 'driving_policy']: if File(f"models/{model_name}.onnx").exists(): inputs.append(File(f"models/{model_name}.onnx")) inputs.append(File(f"models/{model_name}_tinygrad.pkl")) @@ -42,7 +42,7 @@ def tg_compile(flags, model_name): ) # Compile models -for model_name in ['supercombo', 'driving_vision', 'driving_off_policy', 'driving_policy']: +for model_name in ['supercombo', 'driving_vision', 'driving_off_policy', 'driving_on_policy', 'driving_policy']: if File(f"models/{model_name}.onnx").exists(): tg_compile(tg_flags, model_name) diff --git a/sunnypilot/modeld_v2/fill_model_msg.py b/sunnypilot/modeld_v2/fill_model_msg.py index 57e968d02f..1f281258ba 100644 --- a/sunnypilot/modeld_v2/fill_model_msg.py +++ b/sunnypilot/modeld_v2/fill_model_msg.py @@ -100,7 +100,7 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D fill_xyzt(modelV2.orientationRate, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ORIENTATION_RATE].T) # temporal pose - temporal_pose = modelV2.temporalPoseDEPRECATED + temporal_pose = modelV2.deprecated.temporalPose if 'sim_pose' in net_output_data: temporal_pose.trans = net_output_data['sim_pose'][0,:ModelConstants.POSE_WIDTH//2].tolist() temporal_pose.transStd = net_output_data['sim_pose_stds'][0,:ModelConstants.POSE_WIDTH//2].tolist() diff --git a/sunnypilot/models/default_model.py b/sunnypilot/models/default_model.py index d540efbffd..0260a3c3bc 100755 --- a/sunnypilot/models/default_model.py +++ b/sunnypilot/models/default_model.py @@ -8,16 +8,14 @@ from openpilot.sunnypilot import get_file_hash DEFAULT_MODEL_NAME_PATH = os.path.join(BASEDIR, "common", "model.h") MODEL_HASH_PATH = os.path.join(BASEDIR, "sunnypilot", "models", "tests", "model_hash") VISION_ONNX_PATH = os.path.join(BASEDIR, "selfdrive", "modeld", "models", "driving_vision.onnx") -OFF_POLICY_ONNX_PATH = os.path.join(BASEDIR, "selfdrive", "modeld", "models", "driving_off_policy.onnx") -ON_POLICY_ONNX_PATH = os.path.join(BASEDIR, "selfdrive", "modeld", "models", "driving_on_policy.onnx") +POLICY_ONNX_PATH = os.path.join(BASEDIR, "selfdrive", "modeld", "models", "driving_policy.onnx") def update_model_hash(): vision_hash = get_file_hash(VISION_ONNX_PATH) - off_policy_hash = get_file_hash(OFF_POLICY_ONNX_PATH) - on_policy_hash = get_file_hash(ON_POLICY_ONNX_PATH) + policy_hash = get_file_hash(POLICY_ONNX_PATH) - combined_hash = hashlib.sha256((vision_hash + off_policy_hash + on_policy_hash).encode()).hexdigest() + combined_hash = hashlib.sha256((vision_hash + policy_hash).encode()).hexdigest() with open(MODEL_HASH_PATH, "w") as f: f.write(combined_hash) diff --git a/sunnypilot/models/tests/model_hash b/sunnypilot/models/tests/model_hash index 9a9ea5a968..eaf923358c 100644 --- a/sunnypilot/models/tests/model_hash +++ b/sunnypilot/models/tests/model_hash @@ -1 +1 @@ -adfcb5ccac9cfaf291af6091d12e71be3f543c7694fc29d80caa561dc32194d7 +5d4d21f1899de21137f69d74a4602c44cc5a6b04cf4e4aa9d0ec9206f8c30350 \ No newline at end of file diff --git a/sunnypilot/models/tests/test_default_model.py b/sunnypilot/models/tests/test_default_model.py index abe685c36a..7c2fde70a8 100644 --- a/sunnypilot/models/tests/test_default_model.py +++ b/sunnypilot/models/tests/test_default_model.py @@ -6,17 +6,16 @@ See the LICENSE.md file in the root directory for more details. """ from openpilot.sunnypilot import get_file_hash -from openpilot.sunnypilot.models.default_model import MODEL_HASH_PATH, VISION_ONNX_PATH, OFF_POLICY_ONNX_PATH, ON_POLICY_ONNX_PATH +from openpilot.sunnypilot.models.default_model import MODEL_HASH_PATH, VISION_ONNX_PATH, POLICY_ONNX_PATH import hashlib class TestDefaultModel: def test_compare_onnx_hashes(self): vision_hash = get_file_hash(VISION_ONNX_PATH) - off_policy_hash = get_file_hash(OFF_POLICY_ONNX_PATH) - on_policy_hash = get_file_hash(ON_POLICY_ONNX_PATH) + policy_hash = get_file_hash(POLICY_ONNX_PATH) - combined_hash = hashlib.sha256((vision_hash + off_policy_hash + on_policy_hash).encode()).hexdigest() + combined_hash = hashlib.sha256((vision_hash + policy_hash).encode()).hexdigest() with open(MODEL_HASH_PATH) as f: current_hash = f.read().strip() diff --git a/sunnypilot/selfdrive/assets/icons_mici/always_offroad.png b/sunnypilot/selfdrive/assets/icons_mici/always_offroad.png new file mode 100644 index 0000000000..56f35669c6 --- /dev/null +++ b/sunnypilot/selfdrive/assets/icons_mici/always_offroad.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e459241d896824f5e8207d568847acab3dedd41caae7af59d4c17e043663b0c9 +size 4035 diff --git a/sunnypilot/selfdrive/assets/icons_mici/disable_offroad.png b/sunnypilot/selfdrive/assets/icons_mici/disable_offroad.png new file mode 100644 index 0000000000..146734aafa --- /dev/null +++ b/sunnypilot/selfdrive/assets/icons_mici/disable_offroad.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27a0fca872d4586f578d246890b83674cdb7ecb03f58b2b0379b4b64a5816053 +size 3908 diff --git a/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_base.py b/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_base.py index c6658bdc78..df773889a9 100644 --- a/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_base.py +++ b/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_base.py @@ -14,11 +14,8 @@ from openpilot.selfdrive.modeld.constants import ModelConstants LAT_PLAN_MIN_IDX = 5 LATERAL_LAG_MOD = 0.0 # seconds, modifies how far in the future we look ahead for the lateral plan -# from selfdrive/controls/lib/latcontrol_torque.py -KP = 0.8 -KI = 0.15 -INTERP_SPEEDS = [1, 1.5, 2.0, 3.0, 5, 7.5, 10, 15, 30] -KP_INTERP = [250, 120, 65, 30, 11.5, 5.5, 3.5, 2.0, KP] +KP = 1.0 +KI = 0.3 def get_predicted_lateral_jerk(lat_accels, t_diffs): @@ -61,9 +58,10 @@ class LatControlTorqueExtBase: self.lookahead_lateral_jerk: float = 0.0 self.torque_from_lateral_accel_in_torque_space = CI.torque_from_lateral_accel_in_torque_space() + self.torque_params = lac_torque.torque_params self._ff = 0.0 - self._pid = PIDController([INTERP_SPEEDS, KP_INTERP], KI) + self._pid = PIDController(KP, KI) self._pid_log = None self._setpoint = 0.0 self._measurement = 0.0 diff --git a/sunnypilot/selfdrive/controls/lib/nnlc/nnlc.py b/sunnypilot/selfdrive/controls/lib/nnlc/nnlc.py index 2db88299ca..1738a11e49 100644 --- a/sunnypilot/selfdrive/controls/lib/nnlc/nnlc.py +++ b/sunnypilot/selfdrive/controls/lib/nnlc/nnlc.py @@ -75,14 +75,14 @@ class NeuralNetworkLateralControl(LatControlTorqueExtBase): def update_feedforward_torque_space(self, CS): torque_from_setpoint = self.torque_from_lateral_accel_in_torque_space(LatControlInputs(self._setpoint, self._roll_compensation, CS.vEgo, CS.aEgo), - self.lac_torque.torque_params, gravity_adjusted=False) + self.torque_params, gravity_adjusted=False) torque_from_measurement = self.torque_from_lateral_accel_in_torque_space(LatControlInputs(self._measurement, self._roll_compensation, CS.vEgo, CS.aEgo), - self.lac_torque.torque_params, gravity_adjusted=False) + self.torque_params, gravity_adjusted=False) self._pid_log.error = float(torque_from_setpoint - torque_from_measurement) self._ff = self.torque_from_lateral_accel_in_torque_space(LatControlInputs(self._gravity_adjusted_lateral_accel, self._roll_compensation, - CS.vEgo, CS.aEgo), self.lac_torque.torque_params, gravity_adjusted=True) + CS.vEgo, CS.aEgo), self.torque_params, gravity_adjusted=True) self._ff += get_friction_in_torque_space(self._desired_lateral_accel - self._actual_lateral_accel, self._lateral_accel_deadzone, - FRICTION_THRESHOLD, self.lac_torque.torque_params) + FRICTION_THRESHOLD, self.torque_params) def update_output_torque(self, CS): freeze_integrator = self._steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5 @@ -159,6 +159,6 @@ class NeuralNetworkLateralControl(LatControlTorqueExtBase): # apply friction override for cars with low NN friction response if self.model.friction_override: - self._pid_log.error += get_friction(friction_input, self._lateral_accel_deadzone, FRICTION_THRESHOLD, self.lac_torque.torque_params) + self._pid_log.error += get_friction(friction_input, self._lateral_accel_deadzone, FRICTION_THRESHOLD, self.torque_params) self.update_output_torque(CS) diff --git a/sunnypilot/tools/__init__.py b/sunnypilot/tools/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sunnypilot/tools/memory_profiler/__init__.py b/sunnypilot/tools/memory_profiler/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sunnypilot/tools/memory_profiler/mem_usage.py b/sunnypilot/tools/memory_profiler/mem_usage.py new file mode 100644 index 0000000000..20b4bb2d0f --- /dev/null +++ b/sunnypilot/tools/memory_profiler/mem_usage.py @@ -0,0 +1,164 @@ +""" +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +This file is part of sunnypilot and is licensed under the MIT License. +See the LICENSE.md file in the root directory for more details. +""" +import matplotlib.pyplot as plt +import os +import sys +import argparse +import numpy as np +import base64 +import io + +from openpilot.tools.lib.logreader import LogReader, ReadMode + + +def extract_mem_cpu_data(lr): + times, mems, cpus = [], [], [] + start_time = None + + for msg in lr: + if msg.which() == 'procLog': + if start_time is None: + start_time = msg.logMonoTime + mem = msg.procLog.mem + mem_usage = (mem.total - mem.available) / mem.total * 100 + cpu_usages = [(total - cpu.idle) / total * 100 for cpu in msg.procLog.cpuTimes + if (total := cpu.idle + cpu.user + cpu.system + cpu.nice + cpu.iowait + cpu.irq + cpu.softirq) > 0] + avg_cpu = sum(cpu_usages) / len(cpu_usages) if cpu_usages else 0 + times.append((msg.logMonoTime - start_time) / 1e9) + mems.append(mem_usage) + cpus.append(avg_cpu) + return times, mems, cpus + + +def process_segment(lr): + return [extract_mem_cpu_data(lr)] + + +def calculate_r_squared(y_true, y_pred): + ss_res = np.sum((y_true - y_pred) ** 2) + ss_tot = np.sum((y_true - np.mean(y_true)) ** 2) + return 1 - (ss_res / ss_tot) if ss_tot != 0 else 0 + + +def plot_results(segments, segment_data, route_name): + valid_data = [d for d in segment_data if d and d[0]] + if not valid_data: + print("No valid data to plot") + return + + avg_mems = [np.mean(d[1]) for d in valid_data] + avg_cpus = [np.mean(d[2]) for d in valid_data] + valid_segments = [segments[i] for i, d in enumerate(segment_data) if d and d[0]] + + height = max(10, 5 + len(valid_segments) * 0.4) + fig1, ax1 = plt.subplots(1, 1, figsize=(12, height), dpi=150) + + y_pos = range(len(valid_segments)) + ax1.barh([y - 0.2 for y in y_pos], avg_mems, height=0.4, color="dodgerblue", alpha=0.8, label="Avg Mem %") + ax1.barh([y + 0.2 for y in y_pos], avg_cpus, height=0.4, color="green", alpha=0.8, label="Avg CPU %") + + for i, (mem, cpu) in enumerate(zip(avg_mems, avg_cpus, strict=True)): + ax1.text(mem, i - 0.2, f"{mem:.1f}%", va="center", fontsize=8, color="#005a9e", fontweight="bold") + ax1.text(cpu, i + 0.2, f"{cpu:.1f}%", va="center", fontsize=8, color="#005a9e", fontweight="bold") + + ax1.set_yticks(y_pos) + ax1.set_yticklabels([f"Seg {s}" for s in valid_segments]) + ax1.set_xlabel("Usage (%)") + ax1.set_title("Average Memory and CPU Usage by Segment") + ax1.legend() + ax1.grid(axis="x", linestyle="--", alpha=0.5) + ax1.invert_yaxis() + + fig2, ax2 = plt.subplots(1, 1, figsize=(12, 8), dpi=150) + combined_times, combined_mems, combined_cpus = [], [], [] + time_offset = 0.0 + for times, mems, cpus in valid_data: + if times: + combined_times.extend([t + time_offset for t in times]) + combined_mems.extend(mems) + combined_cpus.extend(cpus) + time_offset += max(times) + + ax2.plot(combined_times, combined_mems, color="red", label="Memory Usage", alpha=0.6) + ax2.plot(combined_times, combined_cpus, color="blue", label="CPU Usage", alpha=0.6) + + warmup_sec = 60 + if len(combined_times) > 1 and combined_times[-1] > warmup_sec: + mask = np.array(combined_times) > warmup_sec + x_reg = np.array(combined_times)[mask] + + y_mem_reg = np.array(combined_mems)[mask] + slope_mem, intercept_mem = np.polyfit(x_reg, y_mem_reg, 1) + trend_mem = slope_mem * x_reg + intercept_mem + r2_mem = calculate_r_squared(y_mem_reg, trend_mem) + ax2.plot(x_reg, trend_mem, color="darkred", linestyle="--", linewidth=2.5, + label=f"Mem Trend (Slope: {slope_mem:.4f} %/s, R²: {r2_mem:.2f})") + + y_cpu_reg = np.array(combined_cpus)[mask] + slope_cpu, intercept_cpu = np.polyfit(x_reg, y_cpu_reg, 1) + trend_cpu = slope_cpu * x_reg + intercept_cpu + r2_cpu = calculate_r_squared(y_cpu_reg, trend_cpu) + ax2.plot(x_reg, trend_cpu, color="navy", linestyle="--", linewidth=2.5, + label=f"CPU Trend (Slope: {slope_cpu:.4f} %/s, R²: {r2_cpu:.2f})") + + ax2.set_xlabel("Time (s)") + ax2.set_ylabel("Usage (%)") + ax2.set_title("Memory and CPU Usage Over Time") + ax2.legend(loc='lower left', fontsize='small', framealpha=0.9) + ax2.grid(True, linestyle="--", alpha=0.5) + + buffer1 = io.BytesIO() + fig1.savefig(buffer1, format='webp', bbox_inches='tight', pad_inches=1.0) + buffer1.seek(0) + img1 = base64.b64encode(buffer1.getvalue()).decode() + + buffer2 = io.BytesIO() + fig2.savefig(buffer2, format='webp', bbox_inches='tight', pad_inches=1.0) + buffer2.seek(0) + img2 = base64.b64encode(buffer2.getvalue()).decode() + + filename = f"memory_usage_{route_name}.html" + save_path = os.path.join(os.path.dirname(__file__), "plots", filename) + os.makedirs(os.path.dirname(save_path), exist_ok=True) + + html_template = ( + "" + + f"
comma body
- -body
+you
+Play Sounds
-