mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-06-10 11:14:19 +08:00
Compare commits
19 Commits
master-dev
...
archive/dr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14bceeb172 | ||
|
|
124d1bb12f | ||
|
|
8ee80deb96 | ||
|
|
d4b79ff36a | ||
|
|
7ea4096155 | ||
|
|
5cda10e74a | ||
|
|
0570833ad3 | ||
|
|
bbbeb93cc2 | ||
|
|
32ce8e58e9 | ||
|
|
0084010d55 | ||
|
|
8f173083c2 | ||
|
|
524a5f2f24 | ||
|
|
44349a829a | ||
|
|
8c04dcde59 | ||
|
|
d7ec35a986 | ||
|
|
e26a805476 | ||
|
|
51d862921b | ||
|
|
8e8463a996 | ||
|
|
306df5935a |
@@ -5,16 +5,9 @@ sunnypilot - 0.9.8.0 (2024-xx-xx)
|
||||
* UPDATED: Synced with commaai's openpilot
|
||||
* master commit 4ef757c (July 06, 2024)
|
||||
* NEW❗: Default Driving Model: Notre Dame (July 01, 2024)
|
||||
* NEW❗: Longitudinal: Acceleration Personality thanks to kegman, rav4kumar, and arne1282! (CTV 2.0: GlideTech)
|
||||
* NEW❗: Longitudinal: Acceleration Personality thanks to kegman, rav4kumar, and arne1282!
|
||||
* Select from three distinct acceleration personalities: Eco, Normal, and Sport
|
||||
* Acceleration personalities are integrated directly into the model's acceleration matrix and can be activated in real-time!
|
||||
* NEW❗: Toyota - Drive Mode Selector
|
||||
* When enabled you can control acceleration personality just with press of button!
|
||||
* UPDATED: Dynamic Experimental Control
|
||||
* Switched to weighted moving averages to enhance responsiveness to recent data.
|
||||
* Goal is to improve real-time detection accuracy in dynamic conditions.
|
||||
* Capable of handling the increased complexity that comes with this approach.
|
||||
* Particularly beneficial in environments where recent changes are critical to performance.
|
||||
* NEW❗: Longitudinal: Dynamic Personality thanks to rav4kumar!
|
||||
* Dynamically adjusts following distance and reaction based on your "Driving Personality" setting
|
||||
* Personalities adapt in real-time to your speed and the distance to the lead car
|
||||
@@ -33,14 +26,11 @@ sunnypilot - 0.9.8.0 (2024-xx-xx)
|
||||
* Toyota TSS1/1.5, equipped with factory Blind Spot Monitoring (BSM)
|
||||
* Prius TSS2, equipped with factory Blind Spot Monitoring (BSM)
|
||||
* NOTE: Only enable this feature if your Toyota/Lexus vehicle has factory Blind Spot Monitor equipped, and mentioned in the supported platforms list
|
||||
* UPDATED: Toyota: TSS2 longitudinal: Custom Tuning (CTV 2.0: GlideTech)
|
||||
* Re-tuned and tested by the community (September 29, 2024)
|
||||
* UPDATED: Toyota: TSS2 longitudinal: Custom Tuning
|
||||
* Re-tuned and tested by the community (July 1, 2024)
|
||||
* UPDATED: Driving Model Selector v5
|
||||
* NEW❗: Driving Model additions
|
||||
* Notre Dame (July 01, 2024) - NDv3
|
||||
* UPDATED: Neural Network Lateral Control (NNLC)
|
||||
* NEW❗: Remove Lateral Jerk Response (Alpha)
|
||||
* FIXED: Hotfix for "lazy" steering performance in tighter curves thanks to twilsonco!
|
||||
* UPDATED: Toyota: Continued support for Smart DSU (SDSU) and Radar CAN Filter
|
||||
* In response to the official deprecation of support for Smart DSU (SDSU) and Radar CAN Filter in the upstream ([commaai/openpilot#32777](https://github.com/commaai/openpilot/pull/32777)), sunnypilot will continue maintaining software support for Smart DSU (SDSU) and Radar CAN Filter
|
||||
* UPDATED: Continued support for Mapbox navigation
|
||||
@@ -58,10 +48,6 @@ sunnypilot - 0.9.8.0 (2024-xx-xx)
|
||||
* NEW❗: Time to Lead Car
|
||||
* Displays the time to reach the position previously occupied by the lead car
|
||||
* NEW❗: Display Distance, Speed, and Time to Lead Car simultaneously
|
||||
* Ford F-150 2022-23 support
|
||||
* Ford F-150 Lightning 2021-23 support
|
||||
* Ford Mustang Mach-E 2021-23 support
|
||||
* Hyundai Kona Electric Non-SCC 2019 support thanks to NikitaNekrasov!
|
||||
* Kia Ceed Plug-in Hybrid Non-SCC 2022 support thanks to TerminatorNL!
|
||||
|
||||
sunnypilot - 0.9.7.1 (2024-06-13)
|
||||
@@ -99,8 +85,6 @@ sunnypilot - 0.9.7.1 (2024-06-13)
|
||||
* Force sunnypilot in the offroad state even when the car is on
|
||||
* When Forced Offroad mode is on, allows changing offroad-only settings even when the car is turned on
|
||||
* To engage/disengage Force Offroad, go to Settings -> Device panel
|
||||
* NEW❗: Ford CAN-FD longitudinal
|
||||
* NEW❗: Parse speed limit sign recognition from camera for certain supported platforms
|
||||
* UPDATED: Auto Lane Change Timer -> Auto Lane Change by Blinker
|
||||
* NEW❗: New "Off" option to disable lane change by blinker
|
||||
* UPDATED: Pause Lateral Below Speed with Blinker
|
||||
@@ -108,8 +92,6 @@ sunnypilot - 0.9.7.1 (2024-06-13)
|
||||
* Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h.
|
||||
* UPDATED: Hyundai CAN Longitudinal
|
||||
* Auto-enable radar tracks on platforms with applicable Mando radar
|
||||
* UPDATED: Hyundai CAN-FD Radar-based SCC
|
||||
* Longitudinal support for CAN-FD Radar-based SCC cars
|
||||
* UPDATED: Hyundai CAN-FD Camera-based SCC
|
||||
* NEW❗: Parse lead info for camera-based SCC platforms with longitudinal support
|
||||
* Improve lead tracking when using openpilot longitudinal
|
||||
|
||||
35
README.md
35
README.md
@@ -48,7 +48,6 @@ Join the official sunnypilot Discord server to stay up to date with all the late
|
||||
To use sunnypilot in a car, you need the following:
|
||||
* A supported device to run this software
|
||||
* a [comma three](https://comma.ai/shop/products/three), or
|
||||
* a comma two (only with older versions below 0.8.13)
|
||||
* This software
|
||||
* One of [the 250+ supported cars](https://github.com/commaai/openpilot/blob/master/docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run sunnypilot.
|
||||
* A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car
|
||||
@@ -115,40 +114,12 @@ Please refer to [Recommended Branches](#-recommended-branches) to find your pref
|
||||
|
||||
Requires further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel.
|
||||
|
||||
comma two
|
||||
------
|
||||
|
||||
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
|
||||
2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option.
|
||||
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```https://smiskol.com/fork/sunnyhaibin/0.8.12-4-prod```
|
||||
4. Complete the rest of the installation following the onscreen instructions.
|
||||
|
||||
Requires further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>SSH (More Versatile)</summary>
|
||||
<br>
|
||||
|
||||
Prerequisites: [How to SSH](https://github.com/commaai/openpilot/wiki/SSH)
|
||||
|
||||
If you are looking to install sunnypilot via SSH, run the following command in an SSH terminal after connecting to your device:
|
||||
|
||||
comma three:
|
||||
------
|
||||
* [`release-c3`](https://github.com/sunnyhaibin/openpilot/tree/release-c3):
|
||||
|
||||
```
|
||||
cd /data; rm -rf ./openpilot; git clone -b release-c3 --recurse-submodules https://github.com/sunnyhaibin/sunnypilot.git openpilot; cd openpilot; sudo reboot
|
||||
```
|
||||
|
||||
comma two:
|
||||
------
|
||||
* [`0.8.12-prod-personal-hkg`](https://github.com/sunnyhaibin/openpilot/tree/0.8.12-prod-personal-hkg):
|
||||
|
||||
```
|
||||
cd /data; rm -rf ./openpilot; git clone -b 0.8.12-prod-personal-hkg --recurse-submodules https://github.com/sunnyhaibin/sunnypilot.git openpilot; cd openpilot; sudo reboot
|
||||
cd /data && rm -rf ./openpilot && git clone -b release-c3 --recurse-submodules https://github.com/sunnyhaibin/sunnypilot.git openpilot && cd openpilot && sudo reboot
|
||||
```
|
||||
|
||||
After running the command to install the desired branch, your comma device should reboot.
|
||||
@@ -223,7 +194,7 @@ The goal of Modified Assistive Driving Safety (MADS) is to enhance the user driv
|
||||
* `SET-` button enables ACC/SCC
|
||||
* `CANCEL` button only disables ACC/SCC
|
||||
* `CRUISE (MAIN)` must be `ON` to use ACC/SCC
|
||||
* `CRUISE (MAIN)` button disables ACC/SCC completely when `OFF` **(strictly enforced in panda safety code)**
|
||||
* `CRUISE (MAIN)` button disables sunnypilot completely when `OFF` **(strictly enforced in panda safety code)**
|
||||
|
||||
### Disengage Lateral ALC on Brake Press Mode toggle
|
||||
Dedicated toggle to handle Lateral state on brake pedal press and release:
|
||||
@@ -355,7 +326,7 @@ Example:
|
||||
|
||||
---
|
||||
|
||||
How-To instructions can be found in [HOW-TOS.md](https://github.com/sunnyhaibin/openpilot/blob/(!)README/HOW-TOS.md).
|
||||
How-To instructions can be found in [HOW-TOS.md](HOW-TOS.md).
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ enum LongitudinalPersonalitySP {
|
||||
moderate @1;
|
||||
standard @2;
|
||||
relaxed @3;
|
||||
overtake @4;
|
||||
}
|
||||
|
||||
enum AccelerationPersonality {
|
||||
@@ -33,11 +32,8 @@ enum ModelGeneration {
|
||||
three @3;
|
||||
four @4;
|
||||
five @5;
|
||||
}
|
||||
|
||||
enum MpcSource {
|
||||
acc @0;
|
||||
blended @1;
|
||||
six @6;
|
||||
seven @7;
|
||||
}
|
||||
|
||||
struct ControlsStateSP @0x81c2f05a394cf4af {
|
||||
@@ -45,7 +41,6 @@ struct ControlsStateSP @0x81c2f05a394cf4af {
|
||||
personality @8 :LongitudinalPersonalitySP;
|
||||
dynamicPersonality @9 :Bool;
|
||||
accelPersonality @10 :AccelerationPersonality;
|
||||
overtakingAccelerationAssist @11 :Bool;
|
||||
|
||||
lateralControlState :union {
|
||||
indiState @1 :LateralINDIState;
|
||||
@@ -97,10 +92,8 @@ struct LongitudinalPlanSP @0xaedffd8f31e7b55d {
|
||||
desiredTF @13 :Float32;
|
||||
notSpeedLimit @14 :Int16;
|
||||
e2eX @15 :List(Float32);
|
||||
e2eBlendedDEPRECATED @18 :Text;
|
||||
e2eBlended @18 :Text;
|
||||
e2eStatus @22 :Bool;
|
||||
mpcSource @23 :MpcSource;
|
||||
dynamicExperimentalControl @24 :Bool;
|
||||
|
||||
distToTurn @7 :Float32;
|
||||
turnSpeed @8 :Float32;
|
||||
|
||||
@@ -871,6 +871,7 @@ struct DrivingModelData {
|
||||
frameId @0 :UInt32;
|
||||
frameIdExtra @1 :UInt32;
|
||||
frameDropPerc @6 :Float32;
|
||||
modelExecutionTime @7 :Float32;
|
||||
|
||||
action @2 :ModelDataV2.Action;
|
||||
|
||||
@@ -1010,6 +1011,8 @@ struct ModelDataV2 {
|
||||
brake3MetersPerSecondSquaredProbs @4 :List(Float32);
|
||||
brake4MetersPerSecondSquaredProbs @5 :List(Float32);
|
||||
brake5MetersPerSecondSquaredProbs @6 :List(Float32);
|
||||
gasPressProbs @7 :List(Float32);
|
||||
brakePressProbs @8 :List(Float32);
|
||||
}
|
||||
|
||||
struct Pose {
|
||||
|
||||
@@ -232,7 +232,6 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"CustomMapboxTokenSk", PERSISTENT | BACKUP},
|
||||
{"CustomOffsets", PERSISTENT | BACKUP},
|
||||
{"CustomStockLong", PERSISTENT | BACKUP},
|
||||
{"CustomStockLongPlanner", PERSISTENT | BACKUP},
|
||||
{"CustomTorqueLateral", PERSISTENT | BACKUP},
|
||||
{"DevUIInfo", PERSISTENT | BACKUP},
|
||||
{"DisableOnroadUploads", PERSISTENT | BACKUP},
|
||||
@@ -240,6 +239,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"DrivingModelGeneration", PERSISTENT},
|
||||
{"DrivingModelMetadataText", PERSISTENT},
|
||||
{"DrivingModelName", PERSISTENT},
|
||||
{"DrivingModelSelectorVersion", CLEAR_ON_MANAGER_START},
|
||||
{"DrivingModelText", PERSISTENT},
|
||||
{"DrivingModelUrl", PERSISTENT},
|
||||
{"DynamicExperimentalControl", PERSISTENT | BACKUP},
|
||||
@@ -263,9 +263,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"HasAcceptedTermsSP", PERSISTENT},
|
||||
{"HideVEgoUi", PERSISTENT | BACKUP},
|
||||
{"HyundaiCruiseMainDefault", PERSISTENT | BACKUP},
|
||||
{"HkgCustomLongTuning", PERSISTENT | BACKUP},
|
||||
{"HkgSmoothStop", PERSISTENT | BACKUP},
|
||||
{"HyundaiCruiseMainDefault", PERSISTENT | BACKUP},
|
||||
{"HotspotOnBoot", PERSISTENT},
|
||||
{"HotspotOnBootConfirmed", PERSISTENT},
|
||||
{"HyundaiRadarTracksAvailable", PERSISTENT},
|
||||
@@ -287,7 +285,6 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"NavModelUrl", PERSISTENT | BACKUP},
|
||||
{"NNFF", PERSISTENT | BACKUP},
|
||||
{"NNFFCarModel", PERSISTENT | BACKUP},
|
||||
{"NNFFNoLateralJerk", PERSISTENT | BACKUP},
|
||||
{"OnroadScreenOff", PERSISTENT | BACKUP},
|
||||
{"OnroadScreenOffBrightness", PERSISTENT | BACKUP},
|
||||
{"OnroadScreenOffEvent", PERSISTENT | BACKUP},
|
||||
@@ -298,11 +295,8 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"OsmLocationUrl", PERSISTENT},
|
||||
{"OsmWayTest", PERSISTENT},
|
||||
{"OsmDownloadedDate", PERSISTENT},
|
||||
{"OvertakingAccelerationAssist", PERSISTENT},
|
||||
{"PathOffset", PERSISTENT | BACKUP},
|
||||
{"PauseLateralSpeed", PERSISTENT | BACKUP},
|
||||
{"PCMVCruiseOverride", PERSISTENT | BACKUP},
|
||||
{"PCMVCruiseOverrideSpeed", PERSISTENT | BACKUP},
|
||||
{"QuietDrive", PERSISTENT | BACKUP},
|
||||
{"RoadEdge", PERSISTENT | BACKUP},
|
||||
{"ReverseAccChange", PERSISTENT | BACKUP},
|
||||
@@ -327,12 +321,10 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"TermsVersionSunnypilot", PERSISTENT},
|
||||
{"TorqueDeadzoneDeg", PERSISTENT | BACKUP},
|
||||
{"TorqueFriction", PERSISTENT | BACKUP},
|
||||
{"TorqueLateralJerk", PERSISTENT | BACKUP},
|
||||
{"TorqueMaxLatAccel", PERSISTENT | BACKUP},
|
||||
{"TorquedOverride", PERSISTENT | BACKUP},
|
||||
{"ToyotaAutoLockBySpeed", PERSISTENT | BACKUP},
|
||||
{"ToyotaAutoUnlockByShifter", PERSISTENT | BACKUP},
|
||||
{"ToyotaDriveMode", PERSISTENT | BACKUP},
|
||||
{"ToyotaEnhancedBsm", PERSISTENT | BACKUP},
|
||||
{"ToyotaSnG", PERSISTENT | BACKUP},
|
||||
{"ToyotaTSS2Long", PERSISTENT | BACKUP},
|
||||
|
||||
2
panda
2
panda
Submodule panda updated: 55018eafc2...6a6cd44519
@@ -1,4 +0,0 @@
|
||||
third_party/libyuv/x86_64/**
|
||||
third_party/snpe/x86_64/**
|
||||
third_party/snpe/x86_64-linux-clang/**
|
||||
third_party/acados/x86_64/**
|
||||
@@ -1,15 +0,0 @@
|
||||
third_party/libyuv/larch64/**
|
||||
third_party/snpe/larch64**
|
||||
third_party/snpe/aarch64-ubuntu-gcc7.5/*
|
||||
third_party/acados/larch64/**
|
||||
|
||||
system/camerad/cameras/camera_qcom2.cc
|
||||
system/camerad/cameras/camera_qcom2.h
|
||||
system/camerad/cameras/camera_util.cc
|
||||
system/camerad/cameras/camera_util.h
|
||||
system/camerad/cameras/process_raw.cl
|
||||
|
||||
system/qcomgpsd/*
|
||||
|
||||
selfdrive/ui/qt/spinner_larch64
|
||||
selfdrive/ui/qt/text_larch64
|
||||
@@ -3,7 +3,7 @@ from opendbc.can.packer import CANPacker
|
||||
from openpilot.common.numpy_fast import clip
|
||||
from openpilot.selfdrive.car import apply_std_steer_angle_limits
|
||||
from openpilot.selfdrive.car.ford import fordcan
|
||||
from openpilot.selfdrive.car.ford.values import CarControllerParams, FordFlags, FordFlagsSP
|
||||
from openpilot.selfdrive.car.ford.values import CarControllerParams, FordFlags
|
||||
from openpilot.selfdrive.car.interfaces import CarControllerBase
|
||||
|
||||
LongCtrlState = car.CarControl.Actuators.LongControlState
|
||||
@@ -35,9 +35,6 @@ class CarController(CarControllerBase):
|
||||
self.lkas_enabled_last = False
|
||||
self.steer_alert_last = False
|
||||
self.lead_distance_bars_last = None
|
||||
self.path_angle = 0.
|
||||
self.path_offset = 0.
|
||||
self.curvature_rate = 0.
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
can_sends = []
|
||||
@@ -77,10 +74,7 @@ class CarController(CarControllerBase):
|
||||
# TODO: extended mode
|
||||
mode = 1 if CC.latActive else 0
|
||||
counter = (self.frame // CarControllerParams.STEER_STEP) % 0x10
|
||||
if self.CP.spFlags & FordFlagsSP.SP_ENHANCED_LAT_CONTROL.value:
|
||||
can_sends.append(fordcan.create_lat_ctl2_msg(self.packer, self.CAN, mode, self.path_offset, self.path_angle, -apply_curvature, self.curvature_rate, counter))
|
||||
else:
|
||||
can_sends.append(fordcan.create_lat_ctl2_msg(self.packer, self.CAN, mode, 0., 0., -apply_curvature, 0., counter))
|
||||
can_sends.append(fordcan.create_lat_ctl2_msg(self.packer, self.CAN, mode, 0., 0., -apply_curvature, 0., counter))
|
||||
else:
|
||||
can_sends.append(fordcan.create_lat_ctl_msg(self.packer, self.CAN, CC.latActive, 0., 0., -apply_curvature, 0.))
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ class CarState(CarStateBase):
|
||||
|
||||
self.lkas_enabled = None
|
||||
self.prev_lkas_enabled = None
|
||||
self.v_limit = 0
|
||||
|
||||
self.button_states = {button.event_type: False for button in BUTTONS}
|
||||
|
||||
@@ -73,10 +72,6 @@ class CarState(CarStateBase):
|
||||
ret.cruiseState.nonAdaptive = cp.vl["Cluster_Info1_FD1"]["AccEnbl_B_RqDrv"] == 0
|
||||
ret.cruiseState.standstill = cp.vl["EngBrakeData"]["AccStopMde_D_Rq"] == 3
|
||||
ret.accFaulted = cp.vl["EngBrakeData"]["CcStat_D_Actl"] in (1, 2)
|
||||
|
||||
if self.CP.flags & FordFlags.CANFD:
|
||||
ret.cruiseState.speedLimit = self.update_traffic_signals(cp_cam)
|
||||
|
||||
if not self.CP.openpilotLongitudinalControl:
|
||||
ret.accFaulted = ret.accFaulted or cp_cam.vl["ACCDATA"]["CmbbDeny_B_Actl"] == 1
|
||||
|
||||
@@ -134,16 +129,6 @@ class CarState(CarStateBase):
|
||||
|
||||
return ret
|
||||
|
||||
def update_traffic_signals(self, cp_cam):
|
||||
# TODO: Check if CAN platforms have the same signals
|
||||
if self.CP.flags & FordFlags.CANFD:
|
||||
self.v_limit = cp_cam.vl["Traffic_RecognitnData"]["TsrVLim1MsgTxt_D_Rq"]
|
||||
v_limit_unit = cp_cam.vl["Traffic_RecognitnData"]["TsrVlUnitMsgTxt_D_Rq"]
|
||||
|
||||
speed_factor = CV.MPH_TO_MS if v_limit_unit == 2 else CV.KPH_TO_MS if v_limit_unit == 1 else 0
|
||||
|
||||
return self.v_limit * speed_factor if self.v_limit not in (0, 255) else 0
|
||||
|
||||
@staticmethod
|
||||
def get_can_parser(CP):
|
||||
messages = [
|
||||
@@ -200,11 +185,6 @@ class CarState(CarStateBase):
|
||||
("IPMA_Data", 1),
|
||||
]
|
||||
|
||||
if CP.flags & FordFlags.CANFD:
|
||||
messages += [
|
||||
("Traffic_RecognitnData", 1),
|
||||
]
|
||||
|
||||
if CP.enableBsm and CP.flags & FordFlags.CANFD:
|
||||
messages += [
|
||||
("Side_Detect_L_Stat", 5),
|
||||
|
||||
@@ -3,8 +3,7 @@ from panda import Panda
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
from openpilot.selfdrive.car.ford.fordcan import CanBus
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.car.ford.values import Ecu, FordFlags, FordFlagsSP
|
||||
from openpilot.selfdrive.car.ford.values import Ecu, FordFlags
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
@@ -19,15 +18,13 @@ class CarInterface(CarInterfaceBase):
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "ford"
|
||||
ret.dashcamOnly = bool(ret.flags & FordFlags.CANFD)
|
||||
|
||||
ret.radarUnavailable = True
|
||||
ret.steerControlType = car.CarParams.SteerControlType.angle
|
||||
ret.steerActuatorDelay = 0.2
|
||||
ret.steerLimitTimer = 1.0
|
||||
|
||||
if Params().get("DongleId", encoding='utf8') in ("4fde83db16dc0802", "112e4d6e0cad05e1", "e36b272d5679115f", "24574459dd7fb3e0", "83a4e056c7072678"):
|
||||
ret.spFlags |= FordFlagsSP.SP_ENHANCED_LAT_CONTROL.value
|
||||
|
||||
CAN = CanBus(fingerprint=fingerprint)
|
||||
cfgs = [get_safety_config(car.CarParams.SafetyModel.ford)]
|
||||
if CAN.main >= 4:
|
||||
@@ -54,13 +51,6 @@ class CarInterface(CarInterfaceBase):
|
||||
if config_tja != 0xFF or config_lca != 0xFF:
|
||||
ret.dashcamOnly = True
|
||||
|
||||
if ret.spFlags & FordFlagsSP.SP_ENHANCED_LAT_CONTROL:
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_FORD_ENHANCED_LAT_CONTROL
|
||||
|
||||
ret.longitudinalTuning.kpBP = [0.]
|
||||
ret.longitudinalTuning.kpV = [0.5]
|
||||
ret.longitudinalTuning.kiV = [0.]
|
||||
|
||||
# Auto Transmission: 0x732 ECU or Gear_Shift_by_Wire_FD1
|
||||
found_ecus = [fw.ecu for fw in car_fw]
|
||||
if Ecu.shiftByWire in found_ecus or 0x5A in fingerprint[CAN.main] or docs:
|
||||
|
||||
@@ -11,7 +11,6 @@ DELPHI_ESR_RADAR_MSGS = list(range(0x500, 0x540))
|
||||
DELPHI_MRR_RADAR_START_ADDR = 0x120
|
||||
DELPHI_MRR_RADAR_MSG_COUNT = 64
|
||||
|
||||
STEER_ASSIST_DATA_MSGS = 0x3d7
|
||||
|
||||
def _create_delphi_esr_radar_can_parser(CP) -> CANParser:
|
||||
msg_n = len(DELPHI_ESR_RADAR_MSGS)
|
||||
@@ -29,9 +28,6 @@ def _create_delphi_mrr_radar_can_parser(CP) -> CANParser:
|
||||
|
||||
return CANParser(RADAR.DELPHI_MRR, messages, CanBus(CP).radar)
|
||||
|
||||
def _create_steer_assist_data(CP) -> CANParser:
|
||||
messages = [("Steer_Assist_Data", 20)]
|
||||
return CANParser(RADAR.STEER_ASSIST_DATA, messages, CanBus(CP).camera)
|
||||
|
||||
class RadarInterface(RadarInterfaceBase):
|
||||
def __init__(self, CP):
|
||||
@@ -49,10 +45,6 @@ class RadarInterface(RadarInterfaceBase):
|
||||
elif self.radar == RADAR.DELPHI_MRR:
|
||||
self.rcp = _create_delphi_mrr_radar_can_parser(CP)
|
||||
self.trigger_msg = DELPHI_MRR_RADAR_START_ADDR + DELPHI_MRR_RADAR_MSG_COUNT - 1
|
||||
elif self.radar == RADAR.STEER_ASSIST_DATA:
|
||||
self.rcp = _create_steer_assist_data(CP)
|
||||
self.trigger_msg = STEER_ASSIST_DATA_MSGS
|
||||
|
||||
else:
|
||||
raise ValueError(f"Unsupported radar: {self.radar}")
|
||||
|
||||
@@ -76,67 +68,11 @@ class RadarInterface(RadarInterfaceBase):
|
||||
self._update_delphi_esr()
|
||||
elif self.radar == RADAR.DELPHI_MRR:
|
||||
self._update_delphi_mrr()
|
||||
elif self.radar == RADAR.STEER_ASSIST_DATA:
|
||||
self._update_steer_assist_data()
|
||||
|
||||
ret.points = list(self.pts.values())
|
||||
self.updated_messages.clear()
|
||||
return ret
|
||||
|
||||
def _update_steer_assist_data(self):
|
||||
msg = self.rcp.vl["Steer_Assist_Data"]
|
||||
updated_msg = self.updated_messages
|
||||
|
||||
dRel = msg['CmbbObjDistLong_L_Actl']
|
||||
confidence = msg['CmbbObjConfdnc_D_Stat']
|
||||
new_track = False
|
||||
|
||||
# if dRel < 1022:
|
||||
if confidence > 0:
|
||||
if 0 not in self.pts:
|
||||
self.pts[0] = car.RadarData.RadarPoint.new_message()
|
||||
self.pts[0].trackId = self.track_id
|
||||
self.vRelCol[0] = collections.deque(maxlen=20)
|
||||
self.track_id += 1
|
||||
new_track = True
|
||||
|
||||
yRel = msg['CmbbObjDistLat_L_Actl']
|
||||
vRel = msg['CmbbObjRelLong_V_Actl']
|
||||
yvRel = msg['CmbbObjRelLat_V_Actl']
|
||||
calc = 0
|
||||
if not new_track:
|
||||
# if this is a newly created track - we don't have historical data so skip it
|
||||
# if we are on the same track
|
||||
# Let's see if we are moving:
|
||||
# positive gap - lead is moving faster than us
|
||||
# negative gap - lead is moving slower than us
|
||||
dDiff = dRel - self.pts[0].dRel
|
||||
if (abs(vRel) < 1.0e-2):
|
||||
self.vRelCol[0].append(dDiff)
|
||||
vRel = sum(self.vRelCol[0])
|
||||
calc = 1
|
||||
else:
|
||||
if len(self.vRelCol[0]) > 0:
|
||||
self.vRelCol[0].clear()
|
||||
|
||||
if abs(self.pts[0].vRel - vRel) > 2 or abs(self.pts[0].dRel - dRel) > 5:
|
||||
self.pts[0].trackId = self.track_id
|
||||
if len(self.vRelCol[0]) > 0:
|
||||
self.vRelCol[0].clear()
|
||||
self.track_id += 1
|
||||
|
||||
self.pts[0].dRel = dRel # from front of car
|
||||
self.pts[0].yRel = yRel # in car frame's y axis, left is positive
|
||||
self.pts[0].vRel = vRel
|
||||
self.pts[0].aRel = float('nan')
|
||||
self.pts[0].yvRel = yvRel
|
||||
self.pts[0].measured = True
|
||||
else:
|
||||
if 0 in self.pts:
|
||||
del self.pts[0]
|
||||
del self.vRelCol[0]
|
||||
|
||||
|
||||
def _update_delphi_esr(self):
|
||||
for ii in sorted(self.updated_messages):
|
||||
cpt = self.rcp.vl[ii]
|
||||
|
||||
@@ -48,14 +48,9 @@ class FordFlags(IntFlag):
|
||||
CANFD = 1
|
||||
|
||||
|
||||
class FordFlagsSP(IntFlag):
|
||||
SP_ENHANCED_LAT_CONTROL = 1
|
||||
|
||||
|
||||
class RADAR:
|
||||
DELPHI_ESR = 'ford_fusion_2018_adas'
|
||||
DELPHI_MRR = 'FORD_CADS'
|
||||
STEER_ASSIST_DATA = 'ford_lincoln_base_pt'
|
||||
|
||||
|
||||
class Footnote(Enum):
|
||||
@@ -96,7 +91,7 @@ class FordPlatformConfig(PlatformConfig):
|
||||
|
||||
@dataclass
|
||||
class FordCANFDPlatformConfig(FordPlatformConfig):
|
||||
dbc_dict: DbcDict = field(default_factory=lambda: dbc_dict('ford_lincoln_base_pt', RADAR.STEER_ASSIST_DATA))
|
||||
dbc_dict: DbcDict = field(default_factory=lambda: dbc_dict('ford_lincoln_base_pt', None))
|
||||
|
||||
def init(self):
|
||||
super().init()
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
from cereal import car
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.numpy_fast import interp
|
||||
from opendbc.can.packer import CANPacker
|
||||
@@ -8,7 +6,6 @@ from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits
|
||||
from openpilot.selfdrive.car.gm import gmcan
|
||||
from openpilot.selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons
|
||||
from openpilot.selfdrive.car.interfaces import CarControllerBase
|
||||
from selfdrive.controls.lib.drive_helpers import GM_V_CRUISE_MIN
|
||||
|
||||
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||
NetworkLocation = car.CarParams.NetworkLocation
|
||||
@@ -40,36 +37,6 @@ class CarController(CarControllerBase):
|
||||
self.packer_obj = CANPacker(DBC[self.CP.carFingerprint]['radar'])
|
||||
self.packer_ch = CANPacker(DBC[self.CP.carFingerprint]['chassis'])
|
||||
|
||||
self.sm = messaging.SubMaster(['longitudinalPlanSP'])
|
||||
self.param_s = Params()
|
||||
self.is_metric = self.param_s.get_bool("IsMetric")
|
||||
self.speed_limit_control_enabled = False
|
||||
self.last_speed_limit_sign_tap = False
|
||||
self.last_speed_limit_sign_tap_prev = False
|
||||
self.speed_limit = 0.
|
||||
self.speed_limit_offset = 0
|
||||
self.timer = 0
|
||||
self.final_speed_kph = 0
|
||||
self.init_speed = 0
|
||||
self.current_speed = 0
|
||||
self.v_set_dis = 0
|
||||
self.v_cruise_min = 0
|
||||
self.button_type = 0
|
||||
self.button_select = 0
|
||||
self.button_count = 0
|
||||
self.target_speed = 0
|
||||
self.t_interval = 7
|
||||
self.slc_active_stock = False
|
||||
self.sl_force_active_timer = 0
|
||||
self.v_tsc_state = 0
|
||||
self.slc_state = 0
|
||||
self.m_tsc_state = 0
|
||||
self.cruise_button = None
|
||||
self.speed_diff = 0
|
||||
self.v_tsc = 0
|
||||
self.m_tsc = 0
|
||||
self.steady_speed = 0
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
actuators = CC.actuators
|
||||
hud_control = CC.hudControl
|
||||
@@ -78,40 +45,9 @@ class CarController(CarControllerBase):
|
||||
if hud_v_cruise > 70:
|
||||
hud_v_cruise = 0
|
||||
|
||||
if not self.CP.pcmCruiseSpeed:
|
||||
self.sm.update(0)
|
||||
|
||||
if self.sm.updated['longitudinalPlanSP']:
|
||||
self.v_tsc_state = self.sm['longitudinalPlanSP'].visionTurnControllerState
|
||||
self.slc_state = self.sm['longitudinalPlanSP'].speedLimitControlState
|
||||
self.m_tsc_state = self.sm['longitudinalPlanSP'].turnSpeedControlState
|
||||
self.speed_limit = self.sm['longitudinalPlanSP'].speedLimit
|
||||
self.speed_limit_offset = self.sm['longitudinalPlanSP'].speedLimitOffset
|
||||
self.v_tsc = self.sm['longitudinalPlanSP'].visionTurnSpeed
|
||||
self.m_tsc = self.sm['longitudinalPlanSP'].turnSpeed
|
||||
|
||||
if self.frame % 200 == 0:
|
||||
self.speed_limit_control_enabled = self.param_s.get_bool("EnableSlc")
|
||||
self.is_metric = self.param_s.get_bool("IsMetric")
|
||||
self.last_speed_limit_sign_tap = self.param_s.get_bool("LastSpeedLimitSignTap")
|
||||
self.v_cruise_min = GM_V_CRUISE_MIN[self.is_metric] * (CV.KPH_TO_MPH if not self.is_metric else 1)
|
||||
|
||||
# Send CAN commands.
|
||||
can_sends = []
|
||||
|
||||
if not self.CP.pcmCruiseSpeed:
|
||||
if not self.last_speed_limit_sign_tap_prev and self.last_speed_limit_sign_tap:
|
||||
self.sl_force_active_timer = self.frame
|
||||
self.param_s.put_bool_nonblocking("LastSpeedLimitSignTap", False)
|
||||
self.last_speed_limit_sign_tap_prev = self.last_speed_limit_sign_tap
|
||||
|
||||
sl_force_active = self.speed_limit_control_enabled and (self.frame < (self.sl_force_active_timer * DT_CTRL + 2.0))
|
||||
sl_inactive = not sl_force_active and (not self.speed_limit_control_enabled or (True if self.slc_state == 0 else False))
|
||||
sl_temp_inactive = not sl_force_active and (self.speed_limit_control_enabled and (True if self.slc_state == 1 else False))
|
||||
slc_active = not sl_inactive and not sl_temp_inactive
|
||||
|
||||
self.slc_active_stock = slc_active
|
||||
|
||||
# Steering (Active: 50Hz, inactive: 10Hz)
|
||||
steer_step = self.params.STEER_STEP if CC.latActive else self.params.INACTIVE_STEER_STEP
|
||||
|
||||
@@ -212,15 +148,6 @@ class CarController(CarControllerBase):
|
||||
self.last_button_frame = self.frame
|
||||
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL))
|
||||
|
||||
if not (CC.cruiseControl.cancel or CC.cruiseControl.resume) and not self.CP.pcmCruiseSpeed and CS.out.cruiseState.enabled:
|
||||
self.cruise_button = self.get_cruise_buttons(CS, CC.vCruise)
|
||||
if self.cruise_button is not None:
|
||||
send_freq = 1
|
||||
if not (self.v_tsc_state != 0 or self.m_tsc_state > 1) and abs(self.target_speed - self.v_set_dis) <= 2:
|
||||
send_freq = 3
|
||||
if self.frame % 12 < 6: # thanks to mochi86420 for the magic numbers
|
||||
can_sends.extend([gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, (CS.buttons_counter + 2) % 4, self.cruise_button)] * 3)
|
||||
|
||||
if self.CP.networkLocation == NetworkLocation.fwdCamera:
|
||||
# Silence "Take Steering" alert sent by camera, forward PSCMStatus with HandsOffSWlDetectionStatus=1
|
||||
if self.frame % 10 == 0:
|
||||
@@ -234,120 +161,3 @@ class CarController(CarControllerBase):
|
||||
|
||||
self.frame += 1
|
||||
return new_actuators, can_sends
|
||||
|
||||
# multikyd methods, sunnyhaibin logic
|
||||
def get_cruise_buttons_status(self, CS):
|
||||
if not CS.out.cruiseState.enabled or CS.cruise_buttons != CruiseButtons.UNPRESS:
|
||||
self.timer = 40
|
||||
elif self.timer:
|
||||
self.timer -= 1
|
||||
else:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def get_target_speed(self, v_cruise_kph_prev):
|
||||
v_cruise_kph = v_cruise_kph_prev
|
||||
if self.slc_state > 1:
|
||||
v_cruise_kph = (self.speed_limit + self.speed_limit_offset) * CV.MS_TO_KPH
|
||||
if not self.slc_active_stock:
|
||||
v_cruise_kph = v_cruise_kph_prev
|
||||
return v_cruise_kph
|
||||
|
||||
def get_button_type(self, button_type):
|
||||
self.type_status = "type_" + str(button_type)
|
||||
self.button_picker = getattr(self, self.type_status, lambda: "default")
|
||||
return self.button_picker()
|
||||
|
||||
def reset_button(self):
|
||||
if self.button_type != 3:
|
||||
self.button_type = 0
|
||||
|
||||
def type_default(self):
|
||||
self.button_type = 0
|
||||
return None
|
||||
|
||||
def type_0(self):
|
||||
self.button_count = 0
|
||||
self.target_speed = self.init_speed
|
||||
self.speed_diff = self.target_speed - self.v_set_dis
|
||||
if self.target_speed > self.v_set_dis:
|
||||
self.button_type = 1
|
||||
elif self.target_speed < self.v_set_dis and self.v_set_dis > self.v_cruise_min:
|
||||
self.button_type = 2
|
||||
return None
|
||||
|
||||
def type_1(self):
|
||||
cruise_button = CruiseButtons.RES_ACCEL
|
||||
self.button_count += 1
|
||||
if self.target_speed <= self.v_set_dis:
|
||||
self.button_count = 0
|
||||
self.button_type = 3
|
||||
elif self.button_count > 5:
|
||||
self.button_count = 0
|
||||
self.button_type = 3
|
||||
return cruise_button
|
||||
|
||||
def type_2(self):
|
||||
cruise_button = CruiseButtons.DECEL_SET
|
||||
self.button_count += 1
|
||||
if self.target_speed >= self.v_set_dis or self.v_set_dis <= self.v_cruise_min:
|
||||
self.button_count = 0
|
||||
self.button_type = 3
|
||||
elif self.button_count > 5:
|
||||
self.button_count = 0
|
||||
self.button_type = 3
|
||||
return cruise_button
|
||||
|
||||
def type_3(self):
|
||||
cruise_button = CruiseButtons.UNPRESS
|
||||
self.button_count += 1
|
||||
if self.button_count > self.t_interval:
|
||||
self.button_type = 0
|
||||
return cruise_button
|
||||
|
||||
def get_curve_speed(self, target_speed_kph, v_cruise_kph_prev):
|
||||
if self.v_tsc_state != 0:
|
||||
vision_v_cruise_kph = self.v_tsc * CV.MS_TO_KPH
|
||||
if int(vision_v_cruise_kph) == int(v_cruise_kph_prev):
|
||||
vision_v_cruise_kph = 255
|
||||
else:
|
||||
vision_v_cruise_kph = 255
|
||||
if self.m_tsc_state > 1:
|
||||
map_v_cruise_kph = self.m_tsc * CV.MS_TO_KPH
|
||||
if int(map_v_cruise_kph) == 0.0:
|
||||
map_v_cruise_kph = 255
|
||||
else:
|
||||
map_v_cruise_kph = 255
|
||||
curve_speed = self.curve_speed_hysteresis(min(vision_v_cruise_kph, map_v_cruise_kph) + 2 * CV.MPH_TO_KPH)
|
||||
return min(target_speed_kph, curve_speed)
|
||||
|
||||
def get_button_control(self, CS, final_speed, v_cruise_kph_prev):
|
||||
self.init_speed = round(min(final_speed, v_cruise_kph_prev) * (CV.KPH_TO_MPH if not self.is_metric else 1))
|
||||
self.v_set_dis = round(CS.out.cruiseState.speed * (CV.MS_TO_MPH if not self.is_metric else CV.MS_TO_KPH))
|
||||
cruise_button = self.get_button_type(self.button_type)
|
||||
return cruise_button
|
||||
|
||||
def curve_speed_hysteresis(self, cur_speed: float, hyst=(0.75 * CV.MPH_TO_KPH)):
|
||||
if cur_speed > self.steady_speed:
|
||||
self.steady_speed = cur_speed
|
||||
elif cur_speed < self.steady_speed - hyst:
|
||||
self.steady_speed = cur_speed
|
||||
return self.steady_speed
|
||||
|
||||
def get_cruise_buttons(self, CS, v_cruise_kph_prev):
|
||||
cruise_button = None
|
||||
if not self.get_cruise_buttons_status(CS):
|
||||
pass
|
||||
elif CS.out.cruiseState.enabled:
|
||||
set_speed_kph = self.get_target_speed(v_cruise_kph_prev)
|
||||
if self.slc_state > 1:
|
||||
target_speed_kph = set_speed_kph
|
||||
else:
|
||||
target_speed_kph = min(v_cruise_kph_prev, set_speed_kph)
|
||||
if self.v_tsc_state != 0 or self.m_tsc_state > 1:
|
||||
self.final_speed_kph = self.get_curve_speed(target_speed_kph, v_cruise_kph_prev)
|
||||
else:
|
||||
self.final_speed_kph = target_speed_kph
|
||||
|
||||
cruise_button = self.get_button_control(CS, self.final_speed_kph, v_cruise_kph_prev) # MPH/KPH based button presses
|
||||
return cruise_button
|
||||
|
||||
@@ -119,7 +119,6 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.pcmCruise = False
|
||||
ret.openpilotLongitudinalControl = True
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG
|
||||
ret.customStockLongAvailable = True
|
||||
|
||||
else: # ASCM, OBD-II harness
|
||||
ret.openpilotLongitudinalControl = True
|
||||
@@ -237,7 +236,7 @@ class CarInterface(CarInterfaceBase):
|
||||
else:
|
||||
self.CS.madsEnabled = False
|
||||
|
||||
if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0) or not self.CP.pcmCruiseSpeed:
|
||||
if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0):
|
||||
if any(b.type == ButtonType.cancel for b in self.CS.button_events):
|
||||
self.get_sp_cancel_cruise_state()
|
||||
if self.get_sp_pedal_disengage(ret):
|
||||
@@ -278,8 +277,6 @@ class CarInterface(CarInterfaceBase):
|
||||
if ret.vEgo < self.CP.minSteerSpeed and self.CS.madsEnabled:
|
||||
events.add(EventName.belowSteerSpeed)
|
||||
|
||||
ret.customStockLong = self.update_custom_stock_long()
|
||||
|
||||
ret.events = events.to_msg()
|
||||
|
||||
return ret
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from cereal import car
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.numpy_fast import clip, interp
|
||||
from openpilot.common.numpy_fast import clip
|
||||
from openpilot.common.params import Params
|
||||
from opendbc.can.packer import CANPacker
|
||||
from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, common_fault_avoidance, make_tester_present_msg
|
||||
@@ -62,7 +62,7 @@ class CarController(CarControllerBase):
|
||||
self.lat_disengage_init = False
|
||||
self.lat_active_last = False
|
||||
|
||||
sub_services = ['longitudinalPlan', 'longitudinalPlanSP']
|
||||
sub_services = ['longitudinalPlanSP']
|
||||
if CP.openpilotLongitudinalControl:
|
||||
sub_services.append('radarState')
|
||||
# TODO: Always true, prep for future conditional refactoring
|
||||
@@ -94,24 +94,9 @@ class CarController(CarControllerBase):
|
||||
self.v_tsc = 0
|
||||
self.m_tsc = 0
|
||||
self.steady_speed = 0
|
||||
self.speeds = 0
|
||||
self.v_target_plan = 0
|
||||
self.custom_stock_planner_speed = self.param_s.get_bool("CustomStockLongPlanner")
|
||||
self.hkg_can_smooth_stop = self.param_s.get_bool("HkgSmoothStop")
|
||||
self.lead_distance = 0
|
||||
|
||||
self.jerk = 0.0
|
||||
self.jerk_l = 0.0
|
||||
self.jerk_u = 0.0
|
||||
self.jerkStartLimit = 2.0
|
||||
self.cb_upper = 0.0
|
||||
self.cb_lower = 0.0
|
||||
self.jerk_count = 0.0
|
||||
|
||||
self.accel_raw = 0
|
||||
self.accel_val = 0
|
||||
self.accel_last_jerk = 0
|
||||
self.hkg_custom_long_tuning = self.param_s.get_bool("HkgCustomLongTuning")
|
||||
|
||||
def calculate_lead_distance(self, hud_control: car.CarControl.HUDControl) -> float:
|
||||
lead_one = self.sm["radarState"].leadOne
|
||||
lead_two = self.sm["radarState"].leadTwo
|
||||
@@ -128,10 +113,6 @@ class CarController(CarControllerBase):
|
||||
self.sm.update(0)
|
||||
|
||||
if not self.CP.pcmCruiseSpeed:
|
||||
if self.sm.updated['longitudinalPlan']:
|
||||
_speeds = self.sm['longitudinalPlan'].speeds
|
||||
self.speeds = _speeds[-1] if len(_speeds) else 0
|
||||
|
||||
if self.sm.updated['longitudinalPlanSP']:
|
||||
self.v_tsc_state = self.sm['longitudinalPlanSP'].visionTurnControllerState
|
||||
self.slc_state = self.sm['longitudinalPlanSP'].speedLimitControlState
|
||||
@@ -141,21 +122,14 @@ class CarController(CarControllerBase):
|
||||
self.v_tsc = self.sm['longitudinalPlanSP'].visionTurnSpeed
|
||||
self.m_tsc = self.sm['longitudinalPlanSP'].turnSpeed
|
||||
|
||||
if self.frame % 200 == 0:
|
||||
self.custom_stock_planner_speed = self.param_s.get_bool("CustomStockLongPlanner")
|
||||
self.v_cruise_min = HYUNDAI_V_CRUISE_MIN[CS.params_list.is_metric] * (CV.KPH_TO_MPH if not CS.params_list.is_metric else 1)
|
||||
self.v_target_plan = min(CC.vCruise * CV.KPH_TO_MS, self.speeds)
|
||||
|
||||
actuators = CC.actuators
|
||||
hud_control = CC.hudControl
|
||||
|
||||
# steering torque
|
||||
if self.CP.spFlags & HyundaiFlagsSP.SP_UPSTREAM_TACO.value:
|
||||
self.params = CarControllerParams(self.CP, CS.out.vEgoRaw)
|
||||
new_steer = int(round(actuators.steer * self.params.STEER_MAX))
|
||||
apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params)
|
||||
if self.CP.spFlags & HyundaiFlagsSP.SP_UPSTREAM_TACO.value:
|
||||
apply_steer = clip(apply_steer, -self.params.STEER_MAX, self.params.STEER_MAX)
|
||||
|
||||
# >90 degree steering fault prevention
|
||||
self.angle_limit_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringAngleDeg) >= MAX_ANGLE, CC.latActive,
|
||||
@@ -216,7 +190,7 @@ class CarController(CarControllerBase):
|
||||
if self.frame % 100 == 0 and not ((self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) or escc) and \
|
||||
self.CP.carFingerprint not in CAMERA_SCC_CAR and self.CP.openpilotLongitudinalControl:
|
||||
# for longitudinal control, either radar or ADAS driving ECU
|
||||
addr, bus = 0x7d0, self.CAN.ECAN if self.CP.carFingerprint in CANFD_CAR else 0
|
||||
addr, bus = 0x7d0, 0
|
||||
if self.CP.flags & HyundaiFlags.CANFD_HDA2.value:
|
||||
addr, bus = 0x730, self.CAN.ECAN
|
||||
can_sends.append(make_tester_present_msg(addr, bus, suppress_response=True))
|
||||
@@ -225,9 +199,6 @@ class CarController(CarControllerBase):
|
||||
if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||
can_sends.append(make_tester_present_msg(0x7b1, self.CAN.ECAN, suppress_response=True))
|
||||
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
self.make_jerk(CS, accel, actuators)
|
||||
|
||||
# CAN-FD platforms
|
||||
if self.CP.carFingerprint in CANFD_CAR:
|
||||
hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
|
||||
@@ -254,11 +225,9 @@ class CarController(CarControllerBase):
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
if hda2:
|
||||
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
|
||||
else:
|
||||
can_sends.extend(hyundaicanfd.create_fca_warning_light(self.packer, self.CAN, self.frame))
|
||||
if self.frame % 2 == 0:
|
||||
can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CS, CC.enabled and CS.out.cruiseState.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
|
||||
set_speed_in_units, hud_control, self.jerk_u, self.jerk_l))
|
||||
set_speed_in_units, hud_control))
|
||||
self.accel_last = accel
|
||||
else:
|
||||
# button presses
|
||||
@@ -302,13 +271,15 @@ class CarController(CarControllerBase):
|
||||
self.lead_distance = self.calculate_lead_distance(hud_control)
|
||||
|
||||
if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
|
||||
if self.hkg_can_smooth_stop:
|
||||
stopping = stopping and CS.out.vEgoRaw < 0.05
|
||||
|
||||
# TODO: unclear if this is needed
|
||||
jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
|
||||
use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
|
||||
self.make_accel(CS, actuators)
|
||||
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled and CS.out.cruiseState.enabled, self.accel_raw, self.accel_val, self.jerk_l, self.jerk_u, int(self.frame / 2),
|
||||
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled and CS.out.cruiseState.enabled, accel, jerk, int(self.frame / 2),
|
||||
hud_control, set_speed_in_units, stopping,
|
||||
CC.cruiseControl.override, use_fca, CS, escc, self.CP, self.lead_distance, self.cb_lower, self.cb_upper))
|
||||
CC.cruiseControl.override, use_fca, CS, escc, self.CP, self.lead_distance))
|
||||
|
||||
# 20 Hz LFA MFA message
|
||||
if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
|
||||
@@ -475,8 +446,6 @@ class CarController(CarControllerBase):
|
||||
target_speed_kph = set_speed_kph
|
||||
else:
|
||||
target_speed_kph = min(v_cruise_kph_prev, set_speed_kph)
|
||||
if self.custom_stock_planner_speed:
|
||||
target_speed_kph = self.curve_speed_hysteresis(self.v_target_plan * CV.MS_TO_KPH)
|
||||
if self.v_tsc_state != 0 or self.m_tsc_state > 1:
|
||||
self.final_speed_kph = self.get_curve_speed(target_speed_kph, v_cruise_kph_prev)
|
||||
else:
|
||||
@@ -484,66 +453,3 @@ class CarController(CarControllerBase):
|
||||
|
||||
cruise_button = self.get_button_control(CS, self.final_speed_kph, v_cruise_kph_prev) # MPH/KPH based button presses
|
||||
return cruise_button
|
||||
|
||||
# jerk calculations thanks to apilot!
|
||||
def cal_jerk(self, accel, actuators):
|
||||
self.accel_raw = accel
|
||||
if actuators.longControlState == LongCtrlState.off:
|
||||
accel_diff = 0.0
|
||||
elif actuators.longControlState == LongCtrlState.stopping:# or hud_control.softHold > 0:
|
||||
accel_diff = 0.0
|
||||
else:
|
||||
accel_diff = self.accel_raw - self.accel_last_jerk
|
||||
|
||||
accel_diff /= DT_CTRL
|
||||
self.jerk = self.jerk * 0.9 + accel_diff * 0.1
|
||||
return self.jerk
|
||||
|
||||
def make_jerk(self, CS, accel, actuators):
|
||||
jerk = self.cal_jerk(accel, actuators)
|
||||
a_error = accel - CS.out.aEgo
|
||||
jerk = jerk + (a_error * 2.0)
|
||||
|
||||
if not self.hkg_custom_long_tuning:
|
||||
self.jerk_u = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
|
||||
self.jerk_l = 5.0
|
||||
elif True: #self.CP.carFingerprint in CANFD_CAR or self.CP.carFingerprint == CAR.HYUNDAI_KONA_EV_2022:
|
||||
startingJerk = 0.5
|
||||
jerkLimit = 5.0
|
||||
self.jerk_count += DT_CTRL
|
||||
jerk_max = interp(self.jerk_count, [0, 1.5, 2.5], [startingJerk, startingJerk, jerkLimit])
|
||||
if actuators.longControlState == LongCtrlState.off:
|
||||
self.jerk_u = jerkLimit
|
||||
self.jerk_l = jerkLimit
|
||||
self.jerk_count = 0
|
||||
else:
|
||||
self.jerk_u = min(max(0.5, jerk * 2.0), jerk_max)
|
||||
self.jerk_l = min(max(1.0, -jerk * 3.0), jerkLimit)
|
||||
else:
|
||||
startingJerk = self.jerkStartLimit
|
||||
jerkLimit = 5.0
|
||||
self.jerk_count += DT_CTRL
|
||||
jerk_max = interp(self.jerk_count, [0, 1.5, 2.5], [startingJerk, startingJerk, jerkLimit])
|
||||
self.cb_upper = self.cb_lower = 0
|
||||
if actuators.longControlState == LongCtrlState.off:
|
||||
self.jerk_u = jerkLimit
|
||||
self.jerk_l = jerkLimit
|
||||
self.jerk_count = 0
|
||||
else:
|
||||
self.jerk_u = min(max(0.5, jerk * 2.0), jerk_max)
|
||||
self.jerk_l = min(max(0.5, -jerk * 2.0), jerkLimit)
|
||||
self.cb_upper = clip(0.9 + accel * 0.2, 0, 1.2)
|
||||
self.cb_lower = clip(0.8 + accel * 0.2, 0, 1.2)
|
||||
|
||||
def make_accel(self, CS, actuators):
|
||||
long_control = actuators.longControlState
|
||||
is_ice = not self.CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV)
|
||||
rate_up = 0.1
|
||||
rate_down = 0.1
|
||||
if long_control == LongCtrlState.off or (long_control == LongCtrlState.stopping and CS.out.standstill):
|
||||
self.accel_raw, self.accel_val = 0, 0
|
||||
else:
|
||||
#self.accel_val = clip(self.accel_raw, self.accel_last - rate_down, self.accel_last + rate_up)
|
||||
self.accel_val = self.accel_raw
|
||||
self.accel_last = self.accel_val
|
||||
self.accel_last_jerk = self.accel_val
|
||||
|
||||
@@ -1171,17 +1171,6 @@ FW_VERSIONS = {
|
||||
b'\xf1\x006T6J0_C2\x00\x006T6K1051\x00\x00TOS4N20NS2\x00\x00\x00\x00',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_KONA_EV_NON_SCC: {
|
||||
(Ecu.abs, 0x7d1, None): [
|
||||
b'\xf1\x00OS IEB \x02 212 \x11\x13 58520-K4000',
|
||||
],
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00OS MDPS C 1.00 1.04 56310K4000\x00 4OEDC104',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00OSE LKAS AT USA LHD 1.00 1.00 95740-K4100 W40',
|
||||
],
|
||||
},
|
||||
CAR.KIA_CEED_PHEV_2022_NON_SCC: {
|
||||
(Ecu.eps, 0x7D4, None): [
|
||||
b'\xf1\x00CD MDPS C 1.00 1.01 56310-XX000 4CPHC101',
|
||||
|
||||
@@ -130,8 +130,8 @@ def create_lfahda_mfc(packer, enabled, lat_active, lateral_paused, blinking_icon
|
||||
}
|
||||
return packer.make_can_msg("LFAHDA_MFC", 0, values)
|
||||
|
||||
def create_acc_commands(packer, enabled, accel_raw, accel_val, lower_jerk, upper_jerk, idx, hud_control, set_speed, stopping, long_override, use_fca,
|
||||
CS, escc, CP, lead_distance, cb_lower, cb_upper):
|
||||
def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, set_speed, stopping, long_override, use_fca,
|
||||
CS, escc, CP, lead_distance):
|
||||
commands = []
|
||||
|
||||
scc11_values = {
|
||||
@@ -150,8 +150,8 @@ def create_acc_commands(packer, enabled, accel_raw, accel_val, lower_jerk, upper
|
||||
scc12_values = {
|
||||
"ACCMode": 2 if enabled and long_override else 1 if enabled else 0,
|
||||
"StopReq": 1 if stopping else 0,
|
||||
"aReqRaw": accel_raw,
|
||||
"aReqValue": accel_val, # stock ramps up and down respecting jerk limit until it reaches aReqRaw
|
||||
"aReqRaw": accel,
|
||||
"aReqValue": accel, # stock ramps up and down respecting jerk limit until it reaches aReqRaw
|
||||
"CR_VSM_Alive": idx % 0xF,
|
||||
}
|
||||
|
||||
@@ -172,10 +172,10 @@ def create_acc_commands(packer, enabled, accel_raw, accel_val, lower_jerk, upper
|
||||
commands.append(packer.make_can_msg("SCC12", 0, scc12_values))
|
||||
|
||||
scc14_values = {
|
||||
"ComfortBandUpper": cb_upper, # stock usually is 0 but sometimes uses higher values
|
||||
"ComfortBandLower": cb_lower, # stock usually is 0 but sometimes uses higher values
|
||||
"ComfortBandUpper": 0.0, # stock usually is 0 but sometimes uses higher values
|
||||
"ComfortBandLower": 0.0, # stock usually is 0 but sometimes uses higher values
|
||||
"JerkUpperLimit": upper_jerk, # stock usually is 1.0 but sometimes uses higher values
|
||||
"JerkLowerLimit": lower_jerk, # stock usually is 0.5 but sometimes uses higher values
|
||||
"JerkLowerLimit": 5.0, # stock usually is 0.5 but sometimes uses higher values
|
||||
"ACCMode": 2 if enabled and long_override else 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage
|
||||
"ObjGap": get_object_gap(lead_distance), # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
|
||||
}
|
||||
@@ -207,7 +207,7 @@ def create_acc_opt(packer, escc, CS, CP):
|
||||
commands = []
|
||||
|
||||
scc13_values = {
|
||||
"SCCDrvModeRValue": 3,
|
||||
"SCCDrvModeRValue": 2,
|
||||
"SCC_Equip": 1,
|
||||
"Lead_Veh_Dep_Alert_USM": 2,
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ def create_lfahda_cluster(packer, CAN, enabled, lat_active, lateral_paused, blin
|
||||
return packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values)
|
||||
|
||||
|
||||
def create_acc_control(packer, CAN, CS, enabled, accel_last, accel, stopping, gas_override, set_speed, hud_control, upper_jerk, lower_jerk):
|
||||
def create_acc_control(packer, CAN, CS, enabled, accel_last, accel, stopping, gas_override, set_speed, hud_control):
|
||||
jerk = 5
|
||||
jn = jerk / 50
|
||||
if not enabled or gas_override:
|
||||
@@ -137,8 +137,8 @@ def create_acc_control(packer, CAN, CS, enabled, accel_last, accel, stopping, ga
|
||||
"aReqValue": a_val,
|
||||
"aReqRaw": a_raw,
|
||||
"VSetDis": set_speed,
|
||||
"JerkLowerLimit": lower_jerk,
|
||||
"JerkUpperLimit": upper_jerk,
|
||||
"JerkLowerLimit": jerk if enabled else 1,
|
||||
"JerkUpperLimit": 3.0,
|
||||
|
||||
"ACC_ObjDist": 1,
|
||||
"ObjValid": 0,
|
||||
@@ -172,20 +172,6 @@ def create_spas_messages(packer, CAN, frame, left_blink, right_blink):
|
||||
return ret
|
||||
|
||||
|
||||
def create_fca_warning_light(packer, CAN, frame):
|
||||
ret = []
|
||||
if frame % 2 == 0:
|
||||
values = {
|
||||
'AEB_SETTING': 0x1, # show AEB disabled icon
|
||||
'SET_ME_2': 0x2,
|
||||
'SET_ME_FF': 0xff,
|
||||
'SET_ME_FC': 0xfc,
|
||||
'SET_ME_9': 0x9,
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x160", CAN.ECAN, values))
|
||||
return ret
|
||||
|
||||
|
||||
def create_adrv_messages(packer, CAN, frame):
|
||||
# messages needed to car happy after disabling
|
||||
# the ADAS Driving ECU to do longitudinal control
|
||||
@@ -196,7 +182,15 @@ def create_adrv_messages(packer, CAN, frame):
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values))
|
||||
|
||||
ret.extend(create_fca_warning_light(packer, CAN, frame))
|
||||
if frame % 2 == 0:
|
||||
values = {
|
||||
'AEB_SETTING': 0x1, # show AEB disabled icon
|
||||
'SET_ME_2': 0x2,
|
||||
'SET_ME_FF': 0xff,
|
||||
'SET_ME_FC': 0xfc,
|
||||
'SET_ME_9': 0x9,
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x160", CAN.ECAN, values))
|
||||
|
||||
if frame % 5 == 0:
|
||||
values = {
|
||||
|
||||
@@ -93,7 +93,7 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
# *** longitudinal control ***
|
||||
if candidate in CANFD_CAR:
|
||||
ret.experimentalLongitudinalAvailable = candidate not in (CANFD_UNSUPPORTED_LONGITUDINAL_CAR | NON_SCC_CAR)
|
||||
ret.experimentalLongitudinalAvailable = candidate not in (CANFD_UNSUPPORTED_LONGITUDINAL_CAR | CANFD_RADAR_SCC_CAR | NON_SCC_CAR)
|
||||
if ret.flags & HyundaiFlags.CANFD_CAMERA_SCC and not hda2:
|
||||
ret.spFlags |= HyundaiFlagsSP.SP_CAMERA_SCC_LEAD.value
|
||||
else:
|
||||
@@ -104,17 +104,11 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.pcmCruise = not ret.openpilotLongitudinalControl
|
||||
|
||||
ret.stoppingControl = True
|
||||
ret.startingState = True
|
||||
ret.vEgoStarting = 0.1
|
||||
ret.startAccel = 1.6
|
||||
ret.startAccel = 1.0
|
||||
ret.longitudinalActuatorDelay = 0.5
|
||||
|
||||
if ret.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV):
|
||||
ret.startingState = False
|
||||
ret.stopAccel = -2.0
|
||||
else:
|
||||
ret.startingState = True
|
||||
ret.stopAccel = -1.0
|
||||
|
||||
if DBC[ret.carFingerprint]["radar"] is None:
|
||||
if ret.spFlags & (HyundaiFlagsSP.SP_ENHANCED_SCC | HyundaiFlagsSP.SP_CAMERA_SCC_LEAD):
|
||||
ret.radarTimeStep = 0.02
|
||||
@@ -126,8 +120,6 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
if 0x1fa in fingerprint[CAN.ECAN]:
|
||||
ret.spFlags |= HyundaiFlagsSP.SP_NAV_MSG.value
|
||||
if Params().get("DongleId", encoding='utf8') in ("012c95f06918eca4", "68d6a96e703c00c9", "11c1f1909ca37bca"):
|
||||
ret.spFlags |= HyundaiFlagsSP.SP_UPSTREAM_TACO.value
|
||||
else:
|
||||
ret.enableBsm = 0x58b in fingerprint[0]
|
||||
|
||||
@@ -154,8 +146,6 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_ALT_BUTTONS
|
||||
if ret.flags & HyundaiFlags.CANFD_CAMERA_SCC:
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC
|
||||
if ret.spFlags & HyundaiFlagsSP.SP_UPSTREAM_TACO:
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_UPSTREAM_TACO
|
||||
else:
|
||||
if candidate in LEGACY_SAFETY_MODE_CAR:
|
||||
# these cars require a special panda safety mode due to missing counters and checksums in the messages
|
||||
@@ -181,8 +171,7 @@ class CarInterface(CarInterfaceBase):
|
||||
elif ret.flags & HyundaiFlags.EV:
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_EV_GAS
|
||||
|
||||
if candidate in (CAR.HYUNDAI_KONA, CAR.HYUNDAI_KONA_EV, CAR.HYUNDAI_KONA_HEV, CAR.HYUNDAI_KONA_EV_2022,
|
||||
CAR.HYUNDAI_KONA_NON_SCC, CAR.HYUNDAI_KONA_EV_NON_SCC):
|
||||
if candidate in (CAR.HYUNDAI_KONA, CAR.HYUNDAI_KONA_EV, CAR.HYUNDAI_KONA_HEV, CAR.HYUNDAI_KONA_EV_2022, CAR.HYUNDAI_KONA_NON_SCC):
|
||||
ret.flags |= HyundaiFlags.ALT_LIMITS.value
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_ALT_LIMITS
|
||||
|
||||
@@ -192,13 +181,16 @@ class CarInterface(CarInterfaceBase):
|
||||
if 0x2AA in fingerprint[0]:
|
||||
ret.minSteerSpeed = 0.
|
||||
|
||||
if Params().get_bool("HkgSmoothStop"):
|
||||
ret.vEgoStopping = 0.1
|
||||
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def init(CP, logcan, sendcan):
|
||||
if CP.openpilotLongitudinalControl and not ((CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) or (CP.spFlags & HyundaiFlagsSP.SP_ENHANCED_SCC)) and \
|
||||
CP.carFingerprint not in CAMERA_SCC_CAR:
|
||||
addr, bus = 0x7d0, CanBus(CP).ECAN if CP.carFingerprint in CANFD_CAR else 0
|
||||
addr, bus = 0x7d0, 0
|
||||
if CP.flags & HyundaiFlags.CANFD_HDA2.value:
|
||||
addr, bus = 0x730, CanBus(CP).ECAN
|
||||
disable_ecu(logcan, sendcan, bus=bus, addr=addr, com_cont_req=b'\x28\x83\x01')
|
||||
|
||||
@@ -3,7 +3,7 @@ from dataclasses import dataclass, field
|
||||
from enum import Enum, IntFlag
|
||||
|
||||
from cereal import car
|
||||
from panda.python import uds, Panda
|
||||
from panda.python import uds
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict
|
||||
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column
|
||||
@@ -16,7 +16,7 @@ class CarControllerParams:
|
||||
ACCEL_MIN = -3.5 # m/s
|
||||
ACCEL_MAX = 2.0 # m/s
|
||||
|
||||
def __init__(self, CP, vEgoRaw=100.):
|
||||
def __init__(self, CP):
|
||||
self.STEER_DELTA_UP = 3
|
||||
self.STEER_DELTA_DOWN = 7
|
||||
self.STEER_DRIVER_ALLOWANCE = 50
|
||||
@@ -26,13 +26,12 @@ class CarControllerParams:
|
||||
self.STEER_STEP = 1 # 100 Hz
|
||||
|
||||
if CP.carFingerprint in CANFD_CAR:
|
||||
upstream_taco = CP.safetyConfigs[-1].safetyParam & Panda.FLAG_HYUNDAI_UPSTREAM_TACO
|
||||
self.STEER_MAX = 270 if not upstream_taco else 384 if vEgoRaw < 11. else 330
|
||||
self.STEER_DRIVER_ALLOWANCE = 250 if not upstream_taco else 350
|
||||
self.STEER_MAX = 270
|
||||
self.STEER_DRIVER_ALLOWANCE = 250
|
||||
self.STEER_DRIVER_MULTIPLIER = 2
|
||||
self.STEER_THRESHOLD = 250 if not upstream_taco else 350
|
||||
self.STEER_DELTA_UP = 2 if not upstream_taco else 10 if vEgoRaw < 11. else 2
|
||||
self.STEER_DELTA_DOWN = 3 if not upstream_taco else 10 if vEgoRaw < 11. else 3
|
||||
self.STEER_THRESHOLD = 250
|
||||
self.STEER_DELTA_UP = 2
|
||||
self.STEER_DELTA_DOWN = 3
|
||||
|
||||
# To determine the limit for your car, find the maximum value that the stock LKAS will request.
|
||||
# If the max stock LKAS request is <384, add your car to this list.
|
||||
@@ -109,7 +108,6 @@ class HyundaiFlagsSP(IntFlag):
|
||||
SP_CAMERA_SCC_LEAD = 2 ** 6
|
||||
SP_LKAS12 = 2 ** 7
|
||||
SP_RADAR_TRACKS = 2 ** 8
|
||||
SP_UPSTREAM_TACO = 2 ** 9
|
||||
|
||||
|
||||
class Footnote(Enum):
|
||||
@@ -576,12 +574,6 @@ class CAR(Platforms):
|
||||
HYUNDAI_KONA.specs,
|
||||
spFlags=HyundaiFlagsSP.SP_NON_SCC | HyundaiFlagsSP.SP_NON_SCC_FCA,
|
||||
)
|
||||
HYUNDAI_KONA_EV_NON_SCC = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Kona Electric Non-SCC 2019", "No Smart Cruise Control (SCC)", car_parts=CarParts.common([CarHarness.hyundai_g]))],
|
||||
HYUNDAI_KONA.specs,
|
||||
flags=HyundaiFlags.EV,
|
||||
spFlags=HyundaiFlagsSP.SP_NON_SCC | HyundaiFlagsSP.SP_NON_SCC_FCA,
|
||||
)
|
||||
KIA_CEED_PHEV_2022_NON_SCC = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia Ceed PHEV Non-SCC 2022", "No Smart Cruise Control (SCC)", car_parts=CarParts.common([CarHarness.hyundai_i]))],
|
||||
CarSpecs(mass=1650, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5),
|
||||
|
||||
@@ -406,7 +406,7 @@ class CarInterfaceBase(ABC):
|
||||
|
||||
@staticmethod
|
||||
def sp_configure_custom_torque_tune(ret, params):
|
||||
ret.lateralTuning.torque.friction = float(params.get("TorqueFriction", encoding="utf8")) * 0.001
|
||||
ret.lateralTuning.torque.friction = float(params.get("TorqueFriction", encoding="utf8")) * 0.01
|
||||
ret.lateralTuning.torque.latAccelFactor = float(params.get("TorqueMaxLatAccel", encoding="utf8")) * 0.01
|
||||
return ret
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ class CarControllerParams:
|
||||
self.STEER_DRIVER_FACTOR = 1 # from dbc
|
||||
|
||||
if CP.flags & SubaruFlags.GLOBAL_GEN2:
|
||||
self.STEER_MAX = 1600
|
||||
self.STEER_MAX = 1000
|
||||
self.STEER_DELTA_UP = 40
|
||||
self.STEER_DELTA_DOWN = 40
|
||||
elif CP.carFingerprint == CAR.SUBARU_IMPREZA_2020:
|
||||
|
||||
@@ -29,9 +29,6 @@
|
||||
"Ford Escape Plug-in Hybrid 2020-22": "FORD_ESCAPE_MK4",
|
||||
"Ford Explorer 2020-23": "FORD_EXPLORER_MK6",
|
||||
"Ford Explorer Hybrid 2020-23": "FORD_EXPLORER_MK6",
|
||||
"Ford F-150 2022-23": "FORD_F_150_MK14",
|
||||
"Ford F-150 Hybrid 2022-23": "FORD_F_150_MK14",
|
||||
"Ford F-150 Lightning 2021-23": "FORD_F_150_LIGHTNING_MK1",
|
||||
"Ford Focus 2018": "FORD_FOCUS_MK4",
|
||||
"Ford Focus Hybrid 2018": "FORD_FOCUS_MK4",
|
||||
"Ford Kuga 2020-22": "FORD_ESCAPE_MK4",
|
||||
@@ -41,8 +38,6 @@
|
||||
"Ford Maverick 2023-24": "FORD_MAVERICK_MK1",
|
||||
"Ford Maverick Hybrid 2022": "FORD_MAVERICK_MK1",
|
||||
"Ford Maverick Hybrid 2023-24": "FORD_MAVERICK_MK1",
|
||||
"Ford Mustang Mach-E 2021-23": "FORD_MUSTANG_MACH_E_MK1",
|
||||
"Ford Ranger 2024": "FORD_RANGER_MK2",
|
||||
"Genesis G70 2018": "GENESIS_G70",
|
||||
"Genesis G70 2019-21": "GENESIS_G70_2020",
|
||||
"Genesis G70 2022-23": "GENESIS_G70_2020",
|
||||
@@ -106,7 +101,6 @@
|
||||
"Hyundai Kona Electric 2018-21": "HYUNDAI_KONA_EV",
|
||||
"Hyundai Kona Electric 2022-23": "HYUNDAI_KONA_EV_2022",
|
||||
"Hyundai Kona Electric (with HDA II, Korea only) 2023": "HYUNDAI_KONA_EV_2ND_GEN",
|
||||
"Hyundai Kona Electric Non-SCC 2019": "HYUNDAI_KONA_EV_NON_SCC",
|
||||
"Hyundai Kona Hybrid 2020": "HYUNDAI_KONA_HEV",
|
||||
"Hyundai Kona Non-SCC 2019": "HYUNDAI_KONA_NON_SCC",
|
||||
"Hyundai Palisade 2020-22": "HYUNDAI_PALISADE",
|
||||
|
||||
@@ -17,6 +17,7 @@ from openpilot.selfdrive.car.body.values import CAR as COMMA
|
||||
|
||||
# TODO: add routes for these cars
|
||||
non_tested_cars = [
|
||||
FORD.FORD_F_150_MK14,
|
||||
GM.CADILLAC_ATS,
|
||||
GM.HOLDEN_ASTRA,
|
||||
GM.CHEVROLET_MALIBU,
|
||||
@@ -53,7 +54,6 @@ routes = [
|
||||
CarTestRoute("e886087f430e7fe7|2023-06-16--23-06-36", FORD.FORD_FOCUS_MK4),
|
||||
CarTestRoute("bd37e43731e5964b|2023-04-30--10-42-26", FORD.FORD_MAVERICK_MK1),
|
||||
CarTestRoute("112e4d6e0cad05e1|2023-11-14--08-21-43", FORD.FORD_F_150_LIGHTNING_MK1),
|
||||
CarTestRoute("24574459dd7fb3e0|2023-11-06--06-23-44", FORD.FORD_F_150_MK14),
|
||||
CarTestRoute("83a4e056c7072678|2023-11-13--16-51-33", FORD.FORD_MUSTANG_MACH_E_MK1),
|
||||
CarTestRoute("37998aa0fade36ab/00000000--48f927c4f5", FORD.FORD_RANGER_MK2),
|
||||
#TestRoute("f1b4c567731f4a1b|2018-04-30--10-15-35", FORD.FUSION),
|
||||
|
||||
@@ -86,7 +86,6 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"KIA_FORTE_2021_NON_SCC" = "HYUNDAI_SONATA"
|
||||
"KIA_SELTOS_2023_NON_SCC" = "HYUNDAI_SONATA"
|
||||
"HYUNDAI_KONA_NON_SCC" = "HYUNDAI_KONA_EV"
|
||||
"HYUNDAI_KONA_EV_NON_SCC" = "HYUNDAI_KONA_EV"
|
||||
"HYUNDAI_ELANTRA_2022_NON_SCC" = "HYUNDAI_ELANTRA_2021"
|
||||
"GENESIS_G70_2021_NON_SCC" = "HYUNDAI_SONATA"
|
||||
"KIA_CEED_PHEV_2022_NON_SCC" = "HYUNDAI_SONATA"
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import copy
|
||||
|
||||
from cereal import car, custom
|
||||
from cereal import car
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.numpy_fast import mean
|
||||
from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from opendbc.can.can_define import CANDefine
|
||||
from opendbc.can.parser import CANParser
|
||||
from openpilot.selfdrive.car import DT_CTRL
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.car.interfaces import CarStateBase
|
||||
from openpilot.selfdrive.car.toyota.values import ToyotaFlags, ToyotaFlagsSP, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \
|
||||
TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR
|
||||
|
||||
SteerControlType = car.CarParams.SteerControlType
|
||||
AccelPersonality = custom.AccelerationPersonality
|
||||
|
||||
# These steering fault definitions seem to be common across LKA (torque) and LTA (angle):
|
||||
# - high steer rate fault: goes to 21 or 25 for 1 frame, then 9 for 2 seconds
|
||||
# - lka/lta msg drop out: goes to 9 then 11 for a combined total of 2 seconds, then 3.
|
||||
@@ -80,13 +79,6 @@ class CarState(CarStateBase):
|
||||
self._right_blindspot_d2 = 0
|
||||
self._right_blindspot_counter = 0
|
||||
|
||||
self.signals_checked = False
|
||||
self.sport_signal_seen = False
|
||||
self.eco_signal_seen = False
|
||||
self.accel_profile = None
|
||||
self.prev_accel_profile = None
|
||||
self.accel_profile_init = False
|
||||
self.toyota_drive_mode = Params().get_bool('ToyotaDriveMode')
|
||||
self.frame = 0
|
||||
|
||||
def update(self, cp, cp_cam):
|
||||
@@ -184,51 +176,6 @@ class CarState(CarStateBase):
|
||||
ret.leftBlinker = ret.leftBlinkerOn = cp.vl["BLINKERS_STATE"]["TURN_SIGNALS"] == 1
|
||||
ret.rightBlinker = ret.rightBlinkerOn = cp.vl["BLINKERS_STATE"]["TURN_SIGNALS"] == 2
|
||||
|
||||
if self.toyota_drive_mode:
|
||||
# Determine sport signal based on car model
|
||||
sport_signal = 'SPORT_ON_2' if self.CP.carFingerprint in (CAR.TOYOTA_RAV4_TSS2, CAR.LEXUS_ES_TSS2, CAR.TOYOTA_HIGHLANDER_TSS2) else 'SPORT_ON'
|
||||
|
||||
# Check signals once
|
||||
if not self.signals_checked:
|
||||
self.signals_checked = True
|
||||
|
||||
# Try to detect sport mode signal, handle missing signal with a fallback
|
||||
try:
|
||||
sport_mode = cp.vl["GEAR_PACKET"][sport_signal]
|
||||
self.sport_signal_seen = True
|
||||
except KeyError:
|
||||
sport_mode = 0
|
||||
self.sport_signal_seen = False
|
||||
|
||||
# Try to detect eco mode signal, handle missing signal with a fallback
|
||||
try:
|
||||
eco_mode = cp.vl["GEAR_PACKET"]['ECON_ON']
|
||||
self.eco_signal_seen = True
|
||||
except KeyError:
|
||||
eco_mode = 0
|
||||
self.eco_signal_seen = False
|
||||
else:
|
||||
# Always re-check the signals to account for mode changes
|
||||
sport_mode = cp.vl["GEAR_PACKET"][sport_signal] if self.sport_signal_seen else 0
|
||||
eco_mode = cp.vl["GEAR_PACKET"]['ECON_ON'] if self.eco_signal_seen else 0
|
||||
|
||||
# Set acceleration profile based on detected modes, with sport mode having higher priority
|
||||
if sport_mode == 1:
|
||||
self.accel_profile = AccelPersonality.sport
|
||||
elif eco_mode == 1:
|
||||
self.accel_profile = AccelPersonality.eco
|
||||
else:
|
||||
self.accel_profile = AccelPersonality.normal
|
||||
|
||||
print(f"Accel profile set to: {self.accel_profile}")
|
||||
|
||||
# If not initialized, sync profile with the current mode on the car
|
||||
if not self.accel_profile_init or self.accel_profile != self.prev_accel_profile:
|
||||
Params().put_nonblocking('AccelPersonality', str(self.accel_profile))
|
||||
self.accel_profile_init = True
|
||||
# Update the previous profile to prevent unnecessary re-syncing
|
||||
self.prev_accel_profile = self.accel_profile
|
||||
|
||||
if self.CP.carFingerprint != CAR.TOYOTA_MIRAI:
|
||||
ret.engineRpm = cp.vl["ENGINE_RPM"]["RPM"]
|
||||
|
||||
|
||||
@@ -160,26 +160,26 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
sp_tss2_long_tune = Params().get_bool("ToyotaTSS2Long")
|
||||
|
||||
# Last updated: September 29, 2024
|
||||
def custom_tss2_longitudinal_tuning(): # hand tuned
|
||||
ret.vEgoStopping = 0.25
|
||||
# hand tuned (July 1, 2024)
|
||||
def custom_tss2_longitudinal_tuning():
|
||||
ret.vEgoStopping = 0.01
|
||||
ret.vEgoStarting = 0.01
|
||||
ret.stoppingDecelRate = 0.006
|
||||
ret.stoppingDecelRate = 0.35
|
||||
|
||||
def default_tss2_longitudinal_tuning(): # stock comma
|
||||
def default_tss2_longitudinal_tuning():
|
||||
ret.vEgoStopping = 0.25
|
||||
ret.vEgoStarting = 0.10
|
||||
ret.stoppingDecelRate = 0.007 # reach stopping target smoothly
|
||||
ret.vEgoStarting = 0.25
|
||||
ret.stoppingDecelRate = 0.3 # reach stopping target smoothly
|
||||
|
||||
def default_longitudinal_tuning(): # stock comma
|
||||
def default_longitudinal_tuning():
|
||||
tune.kiBP = [0., 5., 35.]
|
||||
tune.kiV = [3.6, 2.4, 1.5]
|
||||
|
||||
tune = ret.longitudinalTuning
|
||||
if candidate in TSS2_CAR or ret.enableGasInterceptorDEPRECATED:
|
||||
if sp_tss2_long_tune:
|
||||
tune.kiBP = [0., 5., 12., 20., 27., 36., 40.]
|
||||
tune.kiV = [0.34, 0.234, 0.20, 0.17, 0.105, 0.09, 0.08]
|
||||
tune.kiBP = [0., 5., 12., 20., 27., 36., 50]
|
||||
tune.kiV = [0.35, 0.23, 0.20, 0.17, 0.10, 0.07, 0.01]
|
||||
custom_tss2_longitudinal_tuning()
|
||||
else:
|
||||
tune.kpV = [0.0]
|
||||
|
||||
@@ -174,13 +174,10 @@ class Controls:
|
||||
|
||||
self.live_torque = self.params.get_bool("LiveTorque")
|
||||
self.torqued_override = self.params.get_bool("TorquedOverride")
|
||||
self.custom_stock_planner_speed = self.params.get_bool("CustomStockLongPlanner")
|
||||
|
||||
self.enable_mads = self.params.get_bool("EnableMads")
|
||||
self.mads_disengage_lateral_on_brake = self.params.get_bool("DisengageLateralOnBrake")
|
||||
self.mads_ndlob = self.enable_mads and not self.mads_disengage_lateral_on_brake
|
||||
self.pcm_v_cruise_override = self.params.get_bool("PCMVCruiseOverride")
|
||||
self.pcm_v_cruise_override_speed = int(self.params.get("PCMVCruiseOverrideSpeed", encoding="utf-8"))
|
||||
self.process_not_running = False
|
||||
self.experimental_mode_update = False
|
||||
|
||||
@@ -189,12 +186,6 @@ class Controls:
|
||||
self.custom_model_metadata.capabilities & ModelCapabilities.LateralPlannerSolution
|
||||
|
||||
self.dynamic_personality = self.params.get_bool("DynamicPersonality")
|
||||
self.overtaking_accel = self.params.get_bool("OvertakingAccelerationAssist")
|
||||
self.overtaking_accel_engaged = False
|
||||
self.prev_overtaking_accel_engaged = False
|
||||
self.overtaking_accel_allowed = False
|
||||
self.prev_overtaking_accel_allowed = False
|
||||
self.overtaking_accel_blocked = False
|
||||
|
||||
self.accel_personality = self.read_accel_personality_param()
|
||||
|
||||
@@ -499,9 +490,7 @@ class Controls:
|
||||
def state_transition(self, CS):
|
||||
"""Compute conditional state transitions and execute actions on state transitions"""
|
||||
|
||||
# sp - PCM speed override
|
||||
sp_override_speed = self.pcm_v_cruise_override_speed if self.pcm_v_cruise_override else False
|
||||
self.v_cruise_helper.update_v_cruise(CS, self.enabled_long, self.is_metric, self.reverse_acc_change, sp_override_speed, self.sm['longitudinalPlanSP'])
|
||||
self.v_cruise_helper.update_v_cruise(CS, self.enabled_long, self.is_metric, self.reverse_acc_change, self.sm['longitudinalPlanSP'])
|
||||
|
||||
# decrement the soft disable timer at every step, as it's reset on
|
||||
# entrance in SOFT_DISABLING state
|
||||
@@ -650,15 +639,9 @@ class Controls:
|
||||
self.LoC.reset()
|
||||
|
||||
if not self.joystick_mode:
|
||||
speeds = long_plan.speeds
|
||||
a_lead = self.sm['radarState'].leadOne.aLeadK
|
||||
resume = False
|
||||
if len(speeds):
|
||||
resume = self.enabled_long and CS.standstill and self.CP.carName == "hyundai" and speeds[-1] > 0.1 and a_lead > 0.1
|
||||
|
||||
# accel PID loop
|
||||
pid_accel_limits = self.CI.get_pid_accel_limits(self.CP, CS.vEgo, self.v_cruise_helper.v_cruise_kph * CV.KPH_TO_MS)
|
||||
actuators.accel = self.LoC.update(CC.longActive, CS, long_plan.aTarget, long_plan.shouldStop, pid_accel_limits, resume)
|
||||
actuators.accel = self.LoC.update(CC.longActive, CS, long_plan.aTarget, long_plan.shouldStop, pid_accel_limits)
|
||||
|
||||
# Steering PID loop and lateral MPC
|
||||
if self.model_use_lateral_planner:
|
||||
@@ -834,36 +817,11 @@ class Controls:
|
||||
|
||||
# Curvature & Steering angle
|
||||
lp = self.sm['liveParameters']
|
||||
dh = 'lateralPlanDEPRECATED' if self.model_use_lateral_planner else 'modelV2'
|
||||
lp_mono_time_svs = 'lateralPlanDEPRECATED' if self.model_use_lateral_planner else 'modelV2'
|
||||
|
||||
steer_angle_without_offset = math.radians(CS.steeringAngleDeg - lp.angleOffsetDeg)
|
||||
curvature = -self.VM.calc_curvature(steer_angle_without_offset, CS.vEgo, lp.roll)
|
||||
|
||||
lat_plan = self.sm['lateralPlanDEPRECATED']
|
||||
long_plan = self.sm['longitudinalPlan']
|
||||
dm_state = self.sm['driverMonitoringState']
|
||||
blinker_svs = lat_plan if self.model_use_lateral_planner else model_v2.meta
|
||||
self.prev_overtaking_accel_allowed = self.overtaking_accel_allowed
|
||||
if not self.overtaking_accel_allowed and not self.prev_overtaking_accel_allowed:
|
||||
self.overtaking_accel_blocked = False
|
||||
self.overtaking_accel_allowed = ((blinker_svs.laneChangeDirection == LaneChangeDirection.right and dm_state.isRHD) or
|
||||
(blinker_svs.laneChangeDirection == LaneChangeDirection.left and not dm_state.isRHD)) and \
|
||||
(blinker_svs.laneChangeState in (LaneChangeState.preLaneChange, LaneChangeState.laneChangeStarting)) and \
|
||||
not self.overtaking_accel_blocked
|
||||
self.prev_overtaking_accel_engaged = self.overtaking_accel_engaged
|
||||
ttc = self.sm['radarState'].leadOne.dRel / CS.vEgo if CS.vEgo > 0 else 255
|
||||
overtaking_accel_engaged = self.overtaking_accel and self.overtaking_accel_allowed and \
|
||||
(CS.vEgo > ((60 * CV.KPH_TO_MS) if self.is_metric else (40 * CV.MPH_TO_MS))) and \
|
||||
not (CS.leftBlinker and CS.rightBlinker)
|
||||
if ttc < 0.75 and self.prev_overtaking_accel_engaged and overtaking_accel_engaged:
|
||||
overtaking_accel_engaged = False
|
||||
self.overtaking_accel_blocked = True
|
||||
if overtaking_accel_engaged and not self.prev_overtaking_accel_engaged and \
|
||||
long_plan.hasLead and long_plan.aTarget > -0.1 and (0.75 < ttc < 3.0):
|
||||
self.overtaking_accel_engaged = True
|
||||
elif not overtaking_accel_engaged:
|
||||
self.overtaking_accel_engaged = False
|
||||
|
||||
# controlsState
|
||||
dat = messaging.new_message('controlsState')
|
||||
dat.valid = CS.canValid
|
||||
@@ -878,7 +836,7 @@ class Controls:
|
||||
controlsState.alertSound = current_alert.audible_alert
|
||||
|
||||
controlsState.longitudinalPlanMonoTime = self.sm.logMonoTime['longitudinalPlan']
|
||||
controlsState.lateralPlanMonoTime = self.sm.logMonoTime[dh]
|
||||
controlsState.lateralPlanMonoTime = self.sm.logMonoTime[lp_mono_time_svs]
|
||||
controlsState.enabled = not (CS.brakePressed and (not self.CS_prev.brakePressed or not CS.standstill)) and (self.enabled or CS.cruiseState.enabled) and CS.gearShifter not in [GearShifter.park, GearShifter.reverse]
|
||||
controlsState.active = not (CS.brakePressed and (not self.CS_prev.brakePressed or not CS.standstill)) and (self.active or CS.cruiseState.enabled)
|
||||
controlsState.curvature = curvature
|
||||
@@ -916,7 +874,6 @@ class Controls:
|
||||
controlsStateSP.personality = self.personality
|
||||
controlsStateSP.dynamicPersonality = self.dynamic_personality
|
||||
controlsStateSP.accelPersonality = self.accel_personality
|
||||
controlsStateSP.overtakingAccelerationAssist = self.overtaking_accel_engaged
|
||||
|
||||
if self.enable_nnff and lat_tuning == 'torque':
|
||||
controlsStateSP.lateralControlState.torqueState = self.LaC.pid_long_sp
|
||||
@@ -974,8 +931,7 @@ class Controls:
|
||||
def params_thread(self, evt):
|
||||
while not evt.is_set():
|
||||
self.is_metric = self.params.get_bool("IsMetric")
|
||||
self.experimental_mode = self.params.get_bool("ExperimentalMode") and (self.CP.openpilotLongitudinalControl or
|
||||
(not self.CP.pcmCruiseSpeed and self.custom_stock_planner_speed))
|
||||
self.experimental_mode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl
|
||||
self.personality = self.read_personality_param()
|
||||
self.dynamic_personality = self.params.get_bool("DynamicPersonality")
|
||||
self.accel_personality = self.read_accel_personality_param()
|
||||
@@ -984,11 +940,9 @@ class Controls:
|
||||
|
||||
self.reverse_acc_change = self.params.get_bool("ReverseAccChange")
|
||||
self.dynamic_experimental_control = self.params.get_bool("DynamicExperimentalControl")
|
||||
self.overtaking_accel = self.params.get_bool("OvertakingAccelerationAssist")
|
||||
|
||||
if self.sm.frame % int(2.5 / DT_CTRL) == 0:
|
||||
self.live_torque = self.params.get_bool("LiveTorque")
|
||||
self.custom_stock_planner_speed = self.params.get_bool("CustomStockLongPlanner")
|
||||
time.sleep(0.1)
|
||||
|
||||
def controlsd_thread(self):
|
||||
|
||||
@@ -65,10 +65,6 @@ VOLKSWAGEN_V_CRUISE_MIN = {
|
||||
True: 30,
|
||||
False: int(20 * CV.MPH_TO_KPH),
|
||||
}
|
||||
GM_V_CRUISE_MIN = {
|
||||
True: 30,
|
||||
False: int(20 * CV.MPH_TO_KPH),
|
||||
}
|
||||
|
||||
SpeedLimitControlState = custom.LongitudinalPlanSP.SpeedLimitControlState
|
||||
|
||||
@@ -88,20 +84,12 @@ class VCruiseHelper:
|
||||
self.slc_state_prev = SpeedLimitControlState.inactive
|
||||
self.slc_speed_limit_offsetted = 0
|
||||
|
||||
# sp: PCM speed override
|
||||
self.sp_override_v_cruise_kph = V_CRUISE_UNSET
|
||||
self.sp_override_cruise_speed_last = V_CRUISE_UNSET
|
||||
self.sp_override_enabled_last = False
|
||||
|
||||
self.experimental_mode_update = False
|
||||
|
||||
@property
|
||||
def v_cruise_initialized(self):
|
||||
return self.v_cruise_kph != V_CRUISE_UNSET
|
||||
|
||||
def update_v_cruise(self, CS, enabled, is_metric, reverse_acc, sp_override_speed, long_plan_sp):
|
||||
def update_v_cruise(self, CS, enabled, is_metric, reverse_acc, long_plan_sp):
|
||||
self.v_cruise_kph_last = self.v_cruise_kph
|
||||
self.slc_state_prev = self.slc_state
|
||||
self.slc_state = long_plan_sp.speedLimitControlState
|
||||
|
||||
if not self.CP.pcmCruiseSpeed:
|
||||
@@ -114,32 +102,12 @@ class VCruiseHelper:
|
||||
self._update_v_cruise_slc(long_plan_sp)
|
||||
self.v_cruise_cluster_kph = self.v_cruise_kph
|
||||
else:
|
||||
if enabled and sp_override_speed and CS.cruiseState.speed * CV.MS_TO_KPH < sp_override_speed:
|
||||
if self.sp_override_v_cruise_kph == V_CRUISE_UNSET:
|
||||
self.sp_override_v_cruise_kph = max(CS.vEgo * CV.MS_TO_KPH, V_CRUISE_MIN)
|
||||
else:
|
||||
self.sp_override_v_cruise_kph = V_CRUISE_UNSET
|
||||
|
||||
# when we have an override_speed, use it
|
||||
if self.sp_override_v_cruise_kph != V_CRUISE_UNSET:
|
||||
self.v_cruise_kph = self.sp_override_v_cruise_kph
|
||||
self.v_cruise_cluster_kph = self.sp_override_v_cruise_kph
|
||||
else:
|
||||
self.v_cruise_kph = CS.cruiseState.speed * CV.MS_TO_KPH
|
||||
self.v_cruise_cluster_kph = CS.cruiseState.speedCluster * CV.MS_TO_KPH
|
||||
|
||||
#print("sp_override_v_cruise_kph:", self.sp_override_v_cruise_kph)
|
||||
#print("v_cruise_kph:", self.v_cruise_kph)
|
||||
#print("v_cruise_cluster_kph:", self.v_cruise_cluster_kph)
|
||||
|
||||
self.sp_override_cruise_speed_last = CS.cruiseState.speed
|
||||
self.sp_override_enabled_last = enabled
|
||||
self.v_cruise_kph = CS.cruiseState.speed * CV.MS_TO_KPH
|
||||
self.v_cruise_cluster_kph = CS.cruiseState.speedCluster * CV.MS_TO_KPH
|
||||
self.update_button_timers(CS, enabled)
|
||||
else:
|
||||
self.sp_override_v_cruise_kph = V_CRUISE_UNSET
|
||||
self.v_cruise_kph = V_CRUISE_UNSET
|
||||
self.v_cruise_cluster_kph = V_CRUISE_UNSET
|
||||
self.experimental_mode_update = False
|
||||
|
||||
def _update_v_cruise_non_pcm(self, CS, enabled, is_metric, reverse_acc):
|
||||
# handle button presses. TODO: this should be in state_control, but a decelCruise press
|
||||
@@ -234,8 +202,6 @@ class VCruiseHelper:
|
||||
initial = MAZDA_V_CRUISE_MIN[is_metric]
|
||||
elif self.CP.carName == "volkswagen":
|
||||
initial = VOLKSWAGEN_V_CRUISE_MIN[is_metric]
|
||||
elif self.CP.carName == "gm":
|
||||
initial = GM_V_CRUISE_MIN[is_metric]
|
||||
|
||||
# 250kph or above probably means we never had a set speed
|
||||
if any(b.type in resume_buttons for b in CS.buttonEvents) and self.v_cruise_kph_last < 250:
|
||||
@@ -254,6 +220,8 @@ class VCruiseHelper:
|
||||
if self.slc_state == SpeedLimitControlState.active and self.slc_state_prev == SpeedLimitControlState.preActive:
|
||||
self.v_cruise_kph = clip(round(self.slc_speed_limit_offsetted, 1), self.v_cruise_min, V_CRUISE_MAX)
|
||||
|
||||
self.slc_state_prev = self.slc_state
|
||||
|
||||
def _update_v_cruise_min(self, is_metric):
|
||||
if is_metric != self.is_metric_prev:
|
||||
if self.CP.carName == "honda":
|
||||
@@ -266,8 +234,6 @@ class VCruiseHelper:
|
||||
self.v_cruise_min = MAZDA_V_CRUISE_MIN[is_metric]
|
||||
elif self.CP.carName == "volkswagen":
|
||||
self.v_cruise_min = VOLKSWAGEN_V_CRUISE_MIN[is_metric]
|
||||
elif self.CP.carName == "gm":
|
||||
self.v_cruise_min = GM_V_CRUISE_MIN[is_metric]
|
||||
self.is_metric_prev = is_metric
|
||||
|
||||
|
||||
|
||||
@@ -83,8 +83,7 @@ class LatControlTorque(LatControl):
|
||||
self.torqued_override = self.param_s.get_bool("TorquedOverride")
|
||||
self._frame = 0
|
||||
|
||||
self.use_lateral_jerk = self.param_s.get_bool("TorqueLateralJerk") # TODO: make this a parameter in the UI
|
||||
self.nnff_no_lateral_jerk = self.param_s.get_bool("NNFFNoLateralJerk") # TODO: make this a parameter in the UI
|
||||
self.use_lateral_jerk = False # TODO: make this a parameter in the UI
|
||||
|
||||
# Twilsonco's Lateral Neural Network Feedforward
|
||||
self.use_nn = CI.has_lateral_torque_nn
|
||||
@@ -141,13 +140,11 @@ class LatControlTorque(LatControl):
|
||||
if self._frame % 250 == 0:
|
||||
self._frame = 0
|
||||
self.torqued_override = self.param_s.get_bool("TorquedOverride")
|
||||
self.use_lateral_jerk = self.param_s.get_bool("TorqueLateralJerk")
|
||||
self.nnff_no_lateral_jerk = self.param_s.get_bool("NNFFNoLateralJerk")
|
||||
if not self.torqued_override:
|
||||
return
|
||||
|
||||
self.torque_params.latAccelFactor = float(self.param_s.get("TorqueMaxLatAccel", encoding="utf8")) * 0.01
|
||||
self.torque_params.friction = float(self.param_s.get("TorqueFriction", encoding="utf8")) * 0.001
|
||||
self.torque_params.friction = float(self.param_s.get("TorqueFriction", encoding="utf8")) * 0.01
|
||||
|
||||
@property
|
||||
def pid_long_sp(self):
|
||||
@@ -200,7 +197,7 @@ class LatControlTorque(LatControl):
|
||||
predicted_lateral_jerk = get_predicted_lateral_jerk(model_data.acceleration.y, self.t_diffs)
|
||||
desired_lateral_jerk = (interp(self.desired_lat_jerk_time, ModelConstants.T_IDXS, model_data.acceleration.y) - desired_lateral_accel) / self.desired_lat_jerk_time
|
||||
lookahead_lateral_jerk = get_lookahead_value(predicted_lateral_jerk[LAT_PLAN_MIN_IDX:friction_upper_idx], desired_lateral_jerk)
|
||||
if self.nnff_no_lateral_jerk or self.use_steering_angle or lookahead_lateral_jerk == 0.0:
|
||||
if self.use_steering_angle or lookahead_lateral_jerk == 0.0:
|
||||
lookahead_lateral_jerk = 0.0
|
||||
actual_lateral_jerk = 0.0
|
||||
self.lat_accel_friction_factor = 1.0
|
||||
@@ -209,7 +206,6 @@ class LatControlTorque(LatControl):
|
||||
|
||||
if self.use_nn and model_good:
|
||||
# update past data
|
||||
pitch = 0
|
||||
roll = params.roll
|
||||
if len(llk.calibratedOrientationNED.value) > 1:
|
||||
pitch = self.pitch.update(llk.calibratedOrientationNED.value[1])
|
||||
@@ -235,14 +231,7 @@ class LatControlTorque(LatControl):
|
||||
+ past_rolls + future_rolls
|
||||
torque_from_setpoint = self.torque_from_nn(nnff_setpoint_input)
|
||||
torque_from_measurement = self.torque_from_nn(nnff_measurement_input)
|
||||
|
||||
pid_log.error = torque_from_setpoint - torque_from_measurement
|
||||
error_blend_factor = interp(abs(desired_lateral_accel), [1.0, 2.0], [0.0, 1.0])
|
||||
if error_blend_factor > 0.0: # blend in stronger error response when in high lat accel
|
||||
nnff_error_input = [CS.vEgo, setpoint - measurement, lateral_jerk_setpoint - lateral_jerk_measurement, 0.0]
|
||||
torque_from_error = self.torque_from_nn(nnff_error_input)
|
||||
if sign(pid_log.error) == sign(torque_from_error) and abs(pid_log.error) < abs(torque_from_error):
|
||||
pid_log.error = pid_log.error * (1.0 - error_blend_factor) + torque_from_error * error_blend_factor
|
||||
|
||||
# compute feedforward (same as nn setpoint output)
|
||||
error = setpoint - measurement
|
||||
|
||||
@@ -11,11 +11,11 @@ LongCtrlState = car.CarControl.Actuators.LongControlState
|
||||
|
||||
|
||||
def long_control_state_trans(CP, active, long_control_state, v_ego,
|
||||
should_stop, brake_pressed, cruise_standstill, resume):
|
||||
should_stop, brake_pressed, cruise_standstill):
|
||||
# Ignore cruise standstill if car has a gas interceptor
|
||||
cruise_standstill = cruise_standstill and not CP.enableGasInterceptorDEPRECATED
|
||||
stopping_condition = should_stop and not resume
|
||||
starting_condition = ((not should_stop or resume) and
|
||||
stopping_condition = should_stop
|
||||
starting_condition = (not should_stop and
|
||||
not cruise_standstill and
|
||||
not brake_pressed)
|
||||
started_condition = v_ego > CP.vEgoStarting
|
||||
@@ -58,14 +58,14 @@ class LongControl:
|
||||
def reset(self):
|
||||
self.pid.reset()
|
||||
|
||||
def update(self, active, CS, a_target, should_stop, accel_limits, resume):
|
||||
def update(self, active, CS, a_target, should_stop, accel_limits):
|
||||
"""Update longitudinal control. This updates the state machine and runs a PID loop"""
|
||||
self.pid.neg_limit = accel_limits[0]
|
||||
self.pid.pos_limit = accel_limits[1]
|
||||
|
||||
self.long_control_state = long_control_state_trans(self.CP, active, self.long_control_state, CS.vEgo,
|
||||
should_stop, CS.brakePressed,
|
||||
CS.cruiseState.standstill, resume)
|
||||
CS.cruiseState.standstill)
|
||||
if self.long_control_state == LongCtrlState.off:
|
||||
self.reset()
|
||||
output_accel = 0.
|
||||
|
||||
@@ -63,11 +63,9 @@ def get_jerk_factor(personality=custom.LongitudinalPersonalitySP.standard):
|
||||
elif personality==custom.LongitudinalPersonalitySP.standard:
|
||||
return 1.0
|
||||
elif personality==custom.LongitudinalPersonalitySP.moderate:
|
||||
return 0.9
|
||||
elif personality==custom.LongitudinalPersonalitySP.aggressive:
|
||||
return 0.8
|
||||
elif personality==custom.LongitudinalPersonalitySP.overtake:
|
||||
return 0.1
|
||||
elif personality==custom.LongitudinalPersonalitySP.aggressive:
|
||||
return 0.6
|
||||
else:
|
||||
raise NotImplementedError("Longitudinal personality not supported")
|
||||
|
||||
@@ -81,27 +79,26 @@ def get_T_FOLLOW(personality=custom.LongitudinalPersonalitySP.standard):
|
||||
return 1.25
|
||||
elif personality==custom.LongitudinalPersonalitySP.aggressive:
|
||||
return 1.0
|
||||
elif personality==custom.LongitudinalPersonalitySP.overtake:
|
||||
return 0.25
|
||||
else:
|
||||
raise NotImplementedError("Longitudinal personality not supported")
|
||||
|
||||
# Last updated: September 29, 2024
|
||||
|
||||
def get_dynamic_personality(v_ego, personality=custom.LongitudinalPersonalitySP.standard):
|
||||
if personality==custom.LongitudinalPersonalitySP.relaxed:
|
||||
x_vel = [0, 14., 27.7]
|
||||
y_dist = [1.75, 1.75, 2.00]
|
||||
x_vel = [0, 11, 14.5, 15, 20, 20.01, 25, 25.01, 36, 36.01]
|
||||
y_dist = [1.5, 1.5, 1.5, 1.6, 1.76, 1.76, 1.78, 1.78, 1.8, 1.8]
|
||||
elif personality==custom.LongitudinalPersonalitySP.standard:
|
||||
x_vel = [0, 14., 27.7]
|
||||
y_dist = [1.75, 1.75, 1.70]
|
||||
x_vel = [0, 11, 14.5, 15, 20, 20.01, 25, 25.01, 36, 36.01]
|
||||
y_dist = [1.40, 1.40, 1.40, 1.50, 1.60, 1.76, 1.76, 1.78, 1.8, 1.8]
|
||||
elif personality==custom.LongitudinalPersonalitySP.moderate:
|
||||
x_vel = [0, 14., 27.7]
|
||||
y_dist = [1.45, 1.45, 1.48]
|
||||
x_vel = [0, 11, 14.5, 15, 20, 20.01, 25, 25.01, 36, 36.01]
|
||||
y_dist = [1.3, 1.3, 1.3, 1.35, 1.35, 1.385, 1.385, 1.4, 1.4, 1.45]
|
||||
elif personality==custom.LongitudinalPersonalitySP.aggressive:
|
||||
x_vel = [0, 14., 27.7]
|
||||
y_dist = [1.25, 1.25, 1.28]
|
||||
x_vel = [0, 5, 5.01, 11, 14.5, 15, 20, 20.01, 25, 25.01, 36, 36.01]
|
||||
y_dist = [1.12, 1.12, 1.12, 1.12, 1.12, 1.105, 1.105, 1.15, 1.15, 1.18, 1.20, 1.23]
|
||||
else:
|
||||
raise NotImplementedError("Dynamic personality not supported")
|
||||
|
||||
return np.interp(v_ego, x_vel, y_dist)
|
||||
|
||||
|
||||
@@ -361,11 +358,9 @@ class LongitudinalMpc:
|
||||
self.cruise_min_a = min_a
|
||||
self.max_a = max_a
|
||||
|
||||
def update(self, radarstate, v_cruise, x, v, a, j, personality=custom.LongitudinalPersonalitySP.standard,
|
||||
dynamic_personality=False, overtaking_acceleration_assist=False):
|
||||
def update(self, radarstate, v_cruise, x, v, a, j, personality=custom.LongitudinalPersonalitySP.standard, dynamic_personality=False):
|
||||
v_ego = self.x0[1]
|
||||
t_follow = get_dynamic_personality(v_ego, personality) if dynamic_personality else get_T_FOLLOW(personality)
|
||||
t_follow = get_T_FOLLOW(custom.LongitudinalPersonalitySP.overtake) if overtaking_acceleration_assist else t_follow
|
||||
self.status = radarstate.leadOne.status or radarstate.leadTwo.status
|
||||
|
||||
lead_xv_0 = self.process_lead(radarstate.leadOne)
|
||||
|
||||
@@ -3,7 +3,7 @@ import math
|
||||
import numpy as np
|
||||
from openpilot.common.numpy_fast import clip, interp
|
||||
from openpilot.common.params import Params
|
||||
from cereal import car, log, custom
|
||||
from cereal import car
|
||||
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
@@ -12,7 +12,6 @@ from openpilot.common.realtime import DT_MDL
|
||||
from openpilot.selfdrive.modeld.constants import ModelConstants
|
||||
from openpilot.selfdrive.controls.lib.sunnypilot.common import Source
|
||||
from openpilot.selfdrive.controls.lib.sunnypilot.speed_limit_controller import SpeedLimitController
|
||||
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags
|
||||
from openpilot.selfdrive.car.interfaces import ACCEL_MIN, ACCEL_MAX
|
||||
from openpilot.selfdrive.controls.lib.longcontrol import LongCtrlState
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc
|
||||
@@ -36,7 +35,6 @@ _A_TOTAL_MAX_V = [1.7, 3.2]
|
||||
_A_TOTAL_MAX_BP = [20., 40.]
|
||||
|
||||
|
||||
MpcSource = custom.MpcSource
|
||||
EventName = car.CarEvent.EventName
|
||||
|
||||
|
||||
@@ -84,8 +82,7 @@ class LongitudinalPlanner:
|
||||
self.dt = dt
|
||||
|
||||
self.a_desired = init_a
|
||||
v_ego_sec = 0.6 if CP.carName == "hyundai" and not CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV) else 2.0
|
||||
self.v_desired_filter = FirstOrderFilter(init_v, v_ego_sec, self.dt)
|
||||
self.v_desired_filter = FirstOrderFilter(init_v, 2.0, self.dt)
|
||||
self.v_model_error = 0.0
|
||||
|
||||
self.v_desired_trajectory = np.zeros(CONTROL_N)
|
||||
@@ -132,13 +129,10 @@ class LongitudinalPlanner:
|
||||
self.read_param()
|
||||
self.param_read_counter += 1
|
||||
if self.dynamic_experimental_controller.is_enabled() and sm['controlsState'].experimentalMode:
|
||||
self.dynamic_experimental_controller.set_mpc_fcw_crash_cnt(self.mpc.crash_cnt)
|
||||
self.dynamic_experimental_controller.update(self.CP.radarUnavailable, sm['carState'], sm['radarState'].leadOne, sm['modelV2'], sm['controlsState'], sm['navInstruction'].maneuverDistance)
|
||||
self.mpc.mode = self.dynamic_experimental_controller.get_mpc_mode()
|
||||
self.mpc.mode = self.dynamic_experimental_controller.get_mpc_mode(self.CP.radarUnavailable, sm['carState'], sm['radarState'].leadOne, sm['modelV2'], sm['controlsState'], sm['navInstruction'].maneuverDistance)
|
||||
else:
|
||||
self.mpc.mode = 'blended' if sm['controlsState'].experimentalMode else 'acc'
|
||||
|
||||
|
||||
v_ego = sm['carState'].vEgo
|
||||
v_cruise_kph = min(sm['controlsState'].vCruise, V_CRUISE_MAX)
|
||||
v_cruise = v_cruise_kph * CV.KPH_TO_MS
|
||||
@@ -159,10 +153,8 @@ class LongitudinalPlanner:
|
||||
accel_limits = [ACCEL_MIN, ACCEL_MAX]
|
||||
accel_limits_turns = [ACCEL_MIN, ACCEL_MAX]
|
||||
|
||||
overtaking_accel_engaged = sm['controlsStateSP'].overtakingAccelerationAssist
|
||||
# override accel using Accel Controller
|
||||
if self.accel_controller.is_enabled(accel_personality=custom.AccelerationPersonality.sport if overtaking_accel_engaged else
|
||||
sm['controlsStateSP'].accelPersonality):
|
||||
if self.accel_controller.is_enabled(accel_personality=sm['controlsStateSP'].accelPersonality):
|
||||
# get min, max from accel controller
|
||||
min_limit, max_limit = self.accel_controller.get_accel_limits(v_ego, accel_limits)
|
||||
if self.mpc.mode == 'acc':
|
||||
@@ -197,12 +189,11 @@ class LongitudinalPlanner:
|
||||
accel_limits_turns[0] = min(accel_limits_turns[0], self.a_desired + 0.05)
|
||||
accel_limits_turns[1] = max(accel_limits_turns[1], self.a_desired - 0.05)
|
||||
|
||||
self.mpc.set_weights(prev_accel_constraint, personality=custom.LongitudinalPersonalitySP.overtake if overtaking_accel_engaged else sm['controlsStateSP'].personality)
|
||||
self.mpc.set_weights(prev_accel_constraint, personality=sm['controlsStateSP'].personality)
|
||||
self.mpc.set_accel_limits(accel_limits_turns[0], accel_limits_turns[1])
|
||||
self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired)
|
||||
x, v, a, j = self.parse_model(sm['modelV2'], self.v_model_error)
|
||||
self.mpc.update(sm['radarState'], v_cruise, x, v, a, j, personality=sm['controlsStateSP'].personality,
|
||||
dynamic_personality=sm['controlsStateSP'].dynamicPersonality, overtaking_acceleration_assist=overtaking_accel_engaged)
|
||||
self.mpc.update(sm['radarState'], v_cruise, x, v, a, j, personality=sm['controlsStateSP'].personality, dynamic_personality=sm['controlsStateSP'].dynamicPersonality)
|
||||
|
||||
self.v_desired_trajectory = np.interp(CONTROL_N_T_IDX, T_IDXS_MPC, self.mpc.v_solution)
|
||||
self.a_desired_trajectory = np.interp(CONTROL_N_T_IDX, T_IDXS_MPC, self.mpc.a_solution)
|
||||
@@ -271,8 +262,7 @@ class LongitudinalPlanner:
|
||||
longitudinalPlanSP.turnSpeedControlState = self.turn_speed_controller.state
|
||||
longitudinalPlanSP.turnSpeed = float(self.turn_speed_controller.v_target)
|
||||
|
||||
longitudinalPlanSP.mpcSource = MpcSource.blended if self.mpc.mode == 'blended' else MpcSource.acc
|
||||
longitudinalPlanSP.dynamicExperimentalControl = self.dynamic_experimental_controller.is_enabled()
|
||||
longitudinalPlanSP.e2eBlended = self.mpc.mode
|
||||
|
||||
pm.send('longitudinalPlanSP', plan_sp_send)
|
||||
|
||||
|
||||
@@ -21,23 +21,23 @@
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
# Last updated: September 29, 2024
|
||||
# Last updated: July 1, 2024
|
||||
|
||||
from cereal import custom
|
||||
from openpilot.common.numpy_fast import interp
|
||||
|
||||
AccelPersonality = custom.AccelerationPersonality
|
||||
|
||||
# accel personality by @arne182 modified by cgw and kumar
|
||||
_DP_CRUISE_MIN_V = [-1.0, -1.0, -0.88]
|
||||
_DP_CRUISE_MIN_V_ECO = [-1.0, -1.0, -0.76]
|
||||
_DP_CRUISE_MIN_V_SPORT = [-1.0, -1.0, -1.0]
|
||||
_DP_CRUISE_MIN_BP = [0., 11.1, 20.]
|
||||
# accel personality by @arne182 modified by cgw
|
||||
_DP_CRUISE_MIN_V = [-1.03, -0.79, -0.77, -0.77, -0.75, -0.75, -0.88, -0.82]
|
||||
_DP_CRUISE_MIN_V_ECO = [-1.02, -0.78, -0.75, -0.75, -0.73, -0.73, -0.80, -0.80]
|
||||
_DP_CRUISE_MIN_V_SPORT = [-1.04, -0.81, -0.79, -0.79, -0.77, -0.77, -0.90, -0.84]
|
||||
_DP_CRUISE_MIN_BP = [0., 0.05, 0.1, 0.5, 8.33, 16., 30., 40.]
|
||||
|
||||
_DP_CRUISE_MAX_V = [2.0, 2.0, 2.0, 1.75, 1.03, .72, .53, .42, .13]
|
||||
_DP_CRUISE_MAX_V_ECO = [2.0, 2.0, 2.0, 1.50, 0.92, .54, .43, .32, .088]
|
||||
_DP_CRUISE_MAX_V_SPORT = [2.0, 2.0, 2.0, 2.00, 1.25, .96, .78, .60, .4]
|
||||
_DP_CRUISE_MAX_BP = [0., 1., 6., 8., 11., 20., 25., 30., 55.]
|
||||
_DP_CRUISE_MAX_V = [2.5, 2.5, 2.5, 1.70, 1.05, .81, .625, .42, .348, .12]
|
||||
_DP_CRUISE_MAX_V_ECO = [2.0, 2.0, 2.0, 1.4, .80, .68, .53, .32, .20, .085]
|
||||
_DP_CRUISE_MAX_V_SPORT = [3.5, 3.5, 2.8, 2.4, 1.4, 1.0, .89, .75, .50, .2]
|
||||
_DP_CRUISE_MAX_BP = [0., 1., 6., 8., 11., 15., 20., 25., 30., 55.]
|
||||
|
||||
|
||||
class AccelController:
|
||||
|
||||
@@ -21,39 +21,33 @@
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
# Version = 2024-9-28
|
||||
# Version = 2024-1-29
|
||||
from common.numpy_fast import interp
|
||||
import numpy as np
|
||||
from openpilot.selfdrive.controls.lib.lateral_planner import TRAJECTORY_SIZE
|
||||
|
||||
# d-e2e, from modeldata.h
|
||||
TRAJECTORY_SIZE = 33
|
||||
|
||||
LEAD_WINDOW_SIZE = 4
|
||||
LEAD_WINDOW_SIZE = 5
|
||||
LEAD_PROB = 0.6
|
||||
|
||||
SLOW_DOWN_WINDOW_SIZE = 4
|
||||
SLOW_DOWN_WINDOW_SIZE = 5
|
||||
SLOW_DOWN_PROB = 0.6
|
||||
|
||||
SLOW_DOWN_BP = [0., 10., 20., 30., 40., 50., 55., 60.]
|
||||
SLOW_DOWN_DIST = [25., 38., 55., 75., 95., 115., 130., 150.]
|
||||
SLOW_DOWN_DIST = [20, 30., 50., 70., 80., 90., 105., 120.]
|
||||
|
||||
SLOWNESS_WINDOW_SIZE = 12
|
||||
SLOWNESS_PROB = 0.5
|
||||
SLOWNESS_WINDOW_SIZE = 20
|
||||
SLOWNESS_PROB = 0.6
|
||||
SLOWNESS_CRUISE_OFFSET = 1.05
|
||||
|
||||
DANGEROUS_TTC_WINDOW_SIZE = 3
|
||||
DANGEROUS_TTC = 2.3
|
||||
DANGEROUS_TTC_WINDOW_SIZE = 5
|
||||
DANGEROUS_TTC = 2.0
|
||||
|
||||
HIGHWAY_CRUISE_KPH = 70
|
||||
HIGHWAY_CRUISE_KPH = 75
|
||||
|
||||
STOP_AND_GO_FRAME = 60
|
||||
|
||||
SET_MODE_TIMEOUT = 10
|
||||
|
||||
MPC_FCW_WINDOW_SIZE = 10
|
||||
MPC_FCW_PROB = 0.5
|
||||
|
||||
V_ACC_MIN = 9.72
|
||||
MPC_FCW_WINDOW_SIZE = 5
|
||||
MPC_FCW_PROB = 0.6
|
||||
|
||||
|
||||
class SNG_State:
|
||||
@@ -83,51 +77,29 @@ class GenericMovingAverageCalculator:
|
||||
self.data = []
|
||||
self.total = 0
|
||||
|
||||
class WeightedMovingAverageCalculator:
|
||||
def __init__(self, window_size):
|
||||
self.window_size = window_size
|
||||
self.data = []
|
||||
self.weights = np.linspace(1, 3, window_size) # Linear weights, adjust as needed
|
||||
|
||||
def add_data(self, value):
|
||||
if len(self.data) == self.window_size:
|
||||
self.data.pop(0)
|
||||
self.data.append(value)
|
||||
|
||||
def get_weighted_average(self):
|
||||
if len(self.data) == 0:
|
||||
return None
|
||||
weighted_sum = np.dot(self.data, self.weights[-len(self.data):])
|
||||
weight_total = np.sum(self.weights[-len(self.data):])
|
||||
return weighted_sum / weight_total
|
||||
|
||||
def reset_data(self):
|
||||
self.data = []
|
||||
|
||||
class DynamicExperimentalController:
|
||||
def __init__(self):
|
||||
self._is_enabled = False
|
||||
self._mode = 'acc'
|
||||
self._mode_prev = 'acc'
|
||||
self._mode_changed = False
|
||||
self._frame = 0
|
||||
|
||||
# Use weighted moving average for filtering leads
|
||||
self._lead_gmac = WeightedMovingAverageCalculator(window_size=LEAD_WINDOW_SIZE)
|
||||
self._lead_gmac = GenericMovingAverageCalculator(window_size=LEAD_WINDOW_SIZE)
|
||||
self._has_lead_filtered = False
|
||||
self._has_lead_filtered_prev = False
|
||||
|
||||
self._slow_down_gmac = WeightedMovingAverageCalculator(window_size=SLOW_DOWN_WINDOW_SIZE)
|
||||
self._slow_down_gmac = GenericMovingAverageCalculator(window_size=SLOW_DOWN_WINDOW_SIZE)
|
||||
self._has_slow_down = False
|
||||
|
||||
self._has_blinkers = False
|
||||
|
||||
self._slowness_gmac = WeightedMovingAverageCalculator(window_size=SLOWNESS_WINDOW_SIZE)
|
||||
self._slowness_gmac = GenericMovingAverageCalculator(window_size=SLOWNESS_WINDOW_SIZE)
|
||||
self._has_slowness = False
|
||||
|
||||
self._has_nav_instruction = False
|
||||
|
||||
self._dangerous_ttc_gmac = WeightedMovingAverageCalculator(window_size=DANGEROUS_TTC_WINDOW_SIZE)
|
||||
self._dangerous_ttc_gmac = GenericMovingAverageCalculator(window_size=DANGEROUS_TTC_WINDOW_SIZE)
|
||||
self._has_dangerous_ttc = False
|
||||
|
||||
self._v_ego_kph = 0.
|
||||
@@ -141,50 +113,13 @@ class DynamicExperimentalController:
|
||||
self._sng_transit_frame = 0
|
||||
self._sng_state = SNG_State.off
|
||||
|
||||
self._mpc_fcw_gmac = WeightedMovingAverageCalculator(window_size=MPC_FCW_WINDOW_SIZE)
|
||||
self._mpc_fcw_gmac = GenericMovingAverageCalculator(window_size=MPC_FCW_WINDOW_SIZE)
|
||||
self._has_mpc_fcw = False
|
||||
self._mpc_fcw_crash_cnt = 0
|
||||
|
||||
self._set_mode_timeout = 0
|
||||
pass
|
||||
|
||||
|
||||
def _adaptive_slowdown_threshold(self):
|
||||
"""
|
||||
Adapts the slow down threshold based on vehicle speed and recent behavior.
|
||||
"""
|
||||
return interp(self._v_ego_kph, SLOW_DOWN_BP, SLOW_DOWN_DIST) * (1.0 + 0.03 * np.log(1 + len(self._slow_down_gmac.data)))
|
||||
|
||||
def _anomaly_detection(self, recent_data, threshold=2.0, context_check=True):
|
||||
"""
|
||||
Basic anomaly detection using standard deviation.
|
||||
"""
|
||||
if len(recent_data) < 5:
|
||||
return False
|
||||
mean = np.mean(recent_data)
|
||||
std_dev = np.std(recent_data)
|
||||
anomaly = recent_data[-1] > mean + threshold * std_dev
|
||||
|
||||
# Context check to ensure repeated anomaly
|
||||
if context_check:
|
||||
return np.count_nonzero(np.array(recent_data) > mean + threshold * std_dev) > 1
|
||||
return anomaly
|
||||
|
||||
def _smoothed_lead_detection(self, lead_prob, smoothing_factor=0.2):
|
||||
"""
|
||||
Smoothing the lead detection to avoid erratic behavior.
|
||||
"""
|
||||
self._has_lead_filtered = (1 - smoothing_factor) * self._has_lead_filtered + smoothing_factor * lead_prob
|
||||
return self._has_lead_filtered > LEAD_PROB
|
||||
|
||||
def _adaptive_lead_prob_threshold(self):
|
||||
"""
|
||||
Adapts lead probability threshold based on driving conditions.
|
||||
"""
|
||||
if self._v_ego_kph > HIGHWAY_CRUISE_KPH:
|
||||
return LEAD_PROB + 0.1 # Increase the threshold on highways
|
||||
return LEAD_PROB
|
||||
|
||||
def _update(self, car_state, lead_one, md, controls_state, maneuver_distance):
|
||||
self._v_ego_kph = car_state.vEgo * 3.6
|
||||
self._v_cruise_kph = controls_state.vCruise
|
||||
@@ -193,27 +128,18 @@ class DynamicExperimentalController:
|
||||
|
||||
# fcw detection
|
||||
self._mpc_fcw_gmac.add_data(self._mpc_fcw_crash_cnt > 0)
|
||||
self._has_mpc_fcw = self._mpc_fcw_gmac.get_weighted_average() > MPC_FCW_PROB
|
||||
self._has_mpc_fcw = self._mpc_fcw_gmac.get_moving_average() >= MPC_FCW_PROB
|
||||
|
||||
# nav enable detection
|
||||
self._has_nav_instruction = md.navEnabledDEPRECATED and maneuver_distance / max(car_state.vEgo, 1) < 13
|
||||
|
||||
# lead detection with smoothing
|
||||
# lead detection
|
||||
self._lead_gmac.add_data(lead_one.status)
|
||||
self._has_lead_filtered = self._lead_gmac.get_weighted_average() > LEAD_PROB
|
||||
#lead_prob = self._lead_gmac.get_weighted_average() or 0
|
||||
#self._has_lead_filtered = self._smoothed_lead_detection(lead_prob)
|
||||
self._has_lead_filtered = self._lead_gmac.get_moving_average() >= LEAD_PROB
|
||||
|
||||
# adaptive slow down detection
|
||||
adaptive_threshold = self._adaptive_slowdown_threshold()
|
||||
slow_down_trigger = len(md.orientation.x) == len(md.position.x) == TRAJECTORY_SIZE and md.position.x[TRAJECTORY_SIZE - 1] < adaptive_threshold
|
||||
self._slow_down_gmac.add_data(slow_down_trigger)
|
||||
self._has_slow_down = self._slow_down_gmac.get_weighted_average() > SLOW_DOWN_PROB
|
||||
|
||||
# anomaly detection for slow down events
|
||||
if self._anomaly_detection(self._slow_down_gmac.data):
|
||||
# Handle anomaly: potentially log it, adjust behavior, or issue a warning
|
||||
self._has_slow_down = False # Reset slow down if anomaly detected
|
||||
# slow down detection
|
||||
self._slow_down_gmac.add_data(len(md.orientation.x) == len(md.position.x) == TRAJECTORY_SIZE and md.position.x[TRAJECTORY_SIZE - 1] < interp(self._v_ego_kph, SLOW_DOWN_BP, SLOW_DOWN_DIST))
|
||||
self._has_slow_down = self._slow_down_gmac.get_moving_average() >= SLOW_DOWN_PROB
|
||||
|
||||
# blinker detection
|
||||
self._has_blinkers = car_state.leftBlinker or car_state.rightBlinker
|
||||
@@ -235,7 +161,7 @@ class DynamicExperimentalController:
|
||||
# slowness detection
|
||||
if not self._has_standstill:
|
||||
self._slowness_gmac.add_data(self._v_ego_kph <= (self._v_cruise_kph*SLOWNESS_CRUISE_OFFSET))
|
||||
self._has_slowness = self._slowness_gmac.get_weighted_average() > SLOWNESS_PROB
|
||||
self._has_slowness = self._slowness_gmac.get_moving_average() >= SLOWNESS_PROB
|
||||
|
||||
# dangerous TTC detection
|
||||
if not self._has_lead_filtered and self._has_lead_filtered_prev:
|
||||
@@ -245,14 +171,14 @@ class DynamicExperimentalController:
|
||||
if self._has_lead and car_state.vEgo >= 0.01:
|
||||
self._dangerous_ttc_gmac.add_data(lead_one.dRel/car_state.vEgo)
|
||||
|
||||
self._has_dangerous_ttc = self._dangerous_ttc_gmac.get_weighted_average() is not None and self._dangerous_ttc_gmac.get_weighted_average() <= DANGEROUS_TTC
|
||||
self._has_dangerous_ttc = self._dangerous_ttc_gmac.get_moving_average() is not None and self._dangerous_ttc_gmac.get_moving_average() <= DANGEROUS_TTC
|
||||
|
||||
# keep prev values
|
||||
self._has_standstill_prev = self._has_standstill
|
||||
self._has_lead_filtered_prev = self._has_lead_filtered
|
||||
self._frame += 1
|
||||
|
||||
def _radarless_mode(self):
|
||||
def _blended_priority_mode(self):
|
||||
# when mpc fcw crash prob is high
|
||||
# use blended to slow down quickly
|
||||
if self._has_mpc_fcw:
|
||||
@@ -264,21 +190,21 @@ class DynamicExperimentalController:
|
||||
self._set_mode('blended')
|
||||
return
|
||||
|
||||
# when blinker is on and speed is driving below V_ACC_MIN: blended
|
||||
# when blinker is on and speed is driving below highway cruise speed: blended
|
||||
# we dont want it to switch mode at higher speed, blended may trigger hard brake
|
||||
#if self._has_blinkers and self._v_ego_kph < V_ACC_MIN:
|
||||
# self._set_mode('blended')
|
||||
# return
|
||||
if self._has_blinkers and self._v_ego_kph < HIGHWAY_CRUISE_KPH:
|
||||
self._set_mode('blended')
|
||||
return
|
||||
|
||||
# when at highway cruise and SNG: blended
|
||||
# ensuring blended mode is used because acc is bad at catching SNG lead car
|
||||
# especially those who accel very fast and then brake very hard.
|
||||
#if self._sng_state == SNG_State.going and self._v_cruise_kph >= V_ACC_MIN:
|
||||
# self._set_mode('blended')
|
||||
# return
|
||||
if self._sng_state == SNG_State.going and self._v_cruise_kph >= HIGHWAY_CRUISE_KPH:
|
||||
self._set_mode('blended')
|
||||
return
|
||||
|
||||
# when standstill: blended
|
||||
# in case of lead car suddenly move away under traffic light, acc mode won't brake at traffic light.
|
||||
# in case of lead car suddenly move away under traffic light, acc mode wont brake at traffic light.
|
||||
if self._has_standstill:
|
||||
self._set_mode('blended')
|
||||
return
|
||||
@@ -300,9 +226,9 @@ class DynamicExperimentalController:
|
||||
self._set_mode('acc')
|
||||
return
|
||||
|
||||
self._set_mode('acc')
|
||||
self._set_mode('blended')
|
||||
|
||||
def _radar_mode(self):
|
||||
def _acc_priority_mode(self):
|
||||
# when mpc fcw crash prob is high
|
||||
# use blended to slow down quickly
|
||||
if self._has_mpc_fcw:
|
||||
@@ -310,18 +236,18 @@ class DynamicExperimentalController:
|
||||
return
|
||||
|
||||
# If there is a filtered lead, the vehicle is not in standstill, and the lead vehicle's yRel meets the condition,
|
||||
if self._has_lead_filtered and not self._has_standstill:
|
||||
self._set_mode('acc')
|
||||
return
|
||||
|
||||
# when blinker is on and speed is driving below V_ACC_MIN: blended
|
||||
# we dont want it to switch mode at higher speed, blended may trigger hard brake
|
||||
#if self._has_blinkers and self._v_ego_kph < V_ACC_MIN:
|
||||
# self._set_mode('blended')
|
||||
#if self._has_lead_filtered and not self._has_standstill:
|
||||
# self._set_mode('acc')
|
||||
# return
|
||||
|
||||
# when blinker is on and speed is driving below highway cruise speed: blended
|
||||
# we dont want it to switch mode at higher speed, blended may trigger hard brake
|
||||
if self._has_blinkers and self._v_ego_kph < HIGHWAY_CRUISE_KPH:
|
||||
self._set_mode('blended')
|
||||
return
|
||||
|
||||
# when standstill: blended
|
||||
# in case of lead car suddenly move away under traffic light, acc mode won't brake at traffic light.
|
||||
# in case of lead car suddenly move away under traffic light, acc mode wont brake at traffic light.
|
||||
if self._has_standstill:
|
||||
self._set_mode('blended')
|
||||
return
|
||||
@@ -344,22 +270,17 @@ class DynamicExperimentalController:
|
||||
|
||||
self._set_mode('acc')
|
||||
|
||||
def update(self, radar_unavailable, car_state, lead_one, md, controls_state, maneuver_distance):
|
||||
def get_mpc_mode(self, radar_unavailable, car_state, lead_one, md, controls_state, maneuver_distance):
|
||||
if self._is_enabled:
|
||||
self._update(car_state, lead_one, md, controls_state, maneuver_distance)
|
||||
if radar_unavailable:
|
||||
self._radarless_mode()
|
||||
self._blended_priority_mode()
|
||||
else:
|
||||
self._radar_mode()
|
||||
self._mode_changed = self._mode != self._mode_prev
|
||||
self._acc_priority_mode()
|
||||
|
||||
self._mode_prev = self._mode
|
||||
|
||||
def get_mpc_mode(self):
|
||||
return self._mode
|
||||
|
||||
def has_changed(self):
|
||||
return self._mode_changed
|
||||
|
||||
def set_enabled(self, enabled):
|
||||
self._is_enabled = enabled
|
||||
|
||||
@@ -376,4 +297,4 @@ class DynamicExperimentalController:
|
||||
self._set_mode_timeout = SET_MODE_TIMEOUT
|
||||
|
||||
if self._set_mode_timeout > 0:
|
||||
self._set_mode_timeout -= 1
|
||||
self._set_mode_timeout -= 1
|
||||
|
||||
@@ -32,7 +32,7 @@ def plannerd_thread():
|
||||
pm = messaging.PubMaster(['longitudinalPlan', 'longitudinalPlanSP'] + lateral_planner_svs)
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'radarState', 'modelV2',
|
||||
'longitudinalPlan', 'navInstruction', 'longitudinalPlanSP',
|
||||
'liveMapDataSP', 'e2eLongStateSP', 'controlsStateSP', 'driverMonitoringState'] + lateral_planner_svs,
|
||||
'liveMapDataSP', 'e2eLongStateSP', 'controlsStateSP'] + lateral_planner_svs,
|
||||
poll='modelV2', ignore_avg_freq=['radarState'])
|
||||
|
||||
while True:
|
||||
|
||||
@@ -255,8 +255,8 @@ class RadarD:
|
||||
self.radar_state.radarErrors = list(radar_errors)
|
||||
self.radar_state.carStateMonoTime = sm.logMonoTime['carState']
|
||||
|
||||
if len(sm['modelV2'].temporalPose.trans):
|
||||
model_v_ego = sm['modelV2'].temporalPose.trans[0]
|
||||
if len(sm['modelV2'].velocity.x):
|
||||
model_v_ego = sm['modelV2'].velocity.x[0]
|
||||
else:
|
||||
model_v_ego = self.v_ego
|
||||
leads_v3 = sm['modelV2'].leadsV3
|
||||
|
||||
@@ -83,7 +83,7 @@ class TorqueEstimator(ParameterEstimator):
|
||||
params = Params()
|
||||
if params.get_bool("EnforceTorqueLateral"):
|
||||
if params.get_bool("CustomTorqueLateral"):
|
||||
self.offline_friction = float(params.get("TorqueFriction", encoding="utf8")) * 0.001
|
||||
self.offline_friction = float(params.get("TorqueFriction", encoding="utf8")) * 0.01
|
||||
self.offline_latAccelFactor = float(params.get("TorqueMaxLatAccel", encoding="utf8")) * 0.01
|
||||
if params.get_bool("LiveTorqueRelaxed"):
|
||||
self.min_bucket_points = np.array([0, 200, 300, 500, 500, 300, 200, 0]) / (10 if decimated else 1)
|
||||
|
||||
@@ -76,13 +76,14 @@ class Plan:
|
||||
class Meta:
|
||||
ENGAGED = slice(0, 1)
|
||||
# next 2, 4, 6, 8, 10 seconds
|
||||
GAS_DISENGAGE = slice(1, 36, 7)
|
||||
BRAKE_DISENGAGE = slice(2, 36, 7)
|
||||
STEER_OVERRIDE = slice(3, 36, 7)
|
||||
HARD_BRAKE_3 = slice(4, 36, 7)
|
||||
HARD_BRAKE_4 = slice(5, 36, 7)
|
||||
HARD_BRAKE_5 = slice(6, 36, 7)
|
||||
GAS_PRESS = slice(7, 36, 7)
|
||||
GAS_DISENGAGE = slice(1, 31, 6)
|
||||
BRAKE_DISENGAGE = slice(2, 31, 6)
|
||||
STEER_OVERRIDE = slice(3, 31, 6)
|
||||
HARD_BRAKE_3 = slice(4, 31, 6)
|
||||
HARD_BRAKE_4 = slice(5, 31, 6)
|
||||
HARD_BRAKE_5 = slice(6, 31, 6)
|
||||
# next 0, 2, 4, 6, 8, 10 seconds
|
||||
LEFT_BLINKER = slice(36, 48, 2)
|
||||
RIGHT_BLINKER = slice(37, 48, 2)
|
||||
GAS_PRESS = slice(31, 55, 4)
|
||||
BRAKE_PRESS = slice(32, 55, 4)
|
||||
LEFT_BLINKER = slice(33, 55, 4)
|
||||
RIGHT_BLINKER = slice(34, 55, 4)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from enum import IntFlag
|
||||
import os
|
||||
import os, sys
|
||||
|
||||
from cereal import custom
|
||||
from openpilot.common.params import Params
|
||||
|
||||
DRIVING_MODEL_SELECTOR_VERSION = 6
|
||||
SIMULATION = "SIMULATION" in os.environ
|
||||
|
||||
ModelGeneration = custom.ModelGeneration
|
||||
@@ -33,6 +34,10 @@ class ModelCapabilities(IntFlag):
|
||||
In V2, 'prev_desired_curv' (no plural) is used as the input for the same 'desired_curvature' output.
|
||||
"""
|
||||
|
||||
PlanVelocity = 2 ** 5
|
||||
|
||||
ModelOutputSlicesV1 = 2 ** 6
|
||||
|
||||
|
||||
class CustomModelMetadata:
|
||||
def __init__(self, params=None, init_only=False) -> None:
|
||||
@@ -45,13 +50,19 @@ class CustomModelMetadata:
|
||||
self.capabilities: ModelCapabilities = self.get_model_capabilities()
|
||||
self.valid: bool = self.params.get_bool("CustomDrivingModel") and not SIMULATION and \
|
||||
self.capabilities != ModelCapabilities.Default
|
||||
self.initialized = False
|
||||
|
||||
def read_model_generation_param(self) -> ModelGeneration:
|
||||
return int(self.params.get('DrivingModelGeneration') or ModelGeneration.default)
|
||||
|
||||
def get_model_capabilities(self) -> ModelCapabilities:
|
||||
"""Returns the model capabilities for a given generation."""
|
||||
if self.generation == ModelGeneration.five:
|
||||
if self.generation == ModelGeneration.seven:
|
||||
return ModelCapabilities.DesiredCurvatureV2 | ModelCapabilities.PlanVelocity | \
|
||||
ModelCapabilities.ModelOutputSlicesV1
|
||||
elif self.generation == ModelGeneration.six:
|
||||
return ModelCapabilities.DesiredCurvatureV2 | ModelCapabilities.PlanVelocity
|
||||
elif self.generation == ModelGeneration.five:
|
||||
return ModelCapabilities.DesiredCurvatureV2
|
||||
elif self.generation == ModelGeneration.four:
|
||||
return ModelCapabilities.DesiredCurvatureV2
|
||||
@@ -64,3 +75,29 @@ class CustomModelMetadata:
|
||||
else:
|
||||
# Default model is meant to represent the capabilities of the prebuilt model
|
||||
return ModelCapabilities.Default
|
||||
|
||||
def custom_meta(self):
|
||||
if not self.initialized:
|
||||
if self.capabilities & ModelCapabilities.ModelOutputSlicesV1:
|
||||
class Meta:
|
||||
ENGAGED = slice(0, 1)
|
||||
# next 2, 4, 6, 8, 10 seconds
|
||||
GAS_DISENGAGE = slice(1, 41, 8)
|
||||
BRAKE_DISENGAGE = slice(2, 41, 8)
|
||||
STEER_OVERRIDE = slice(3, 41, 8)
|
||||
HARD_BRAKE_3 = slice(4, 41, 8)
|
||||
HARD_BRAKE_4 = slice(5, 41, 8)
|
||||
HARD_BRAKE_5 = slice(6, 41, 8)
|
||||
GAS_PRESS = slice(7, 41, 8)
|
||||
BRAKE_PRESS = slice(8, 41, 8)
|
||||
# next 0, 2, 4, 6, 8, 10 seconds
|
||||
LEFT_BLINKER = slice(41, 53, 2)
|
||||
RIGHT_BLINKER = slice(42, 53, 2)
|
||||
|
||||
module = 'openpilot.selfdrive.modeld.constants'
|
||||
if module in sys.modules:
|
||||
sys.modules[module].Meta = Meta
|
||||
else:
|
||||
raise ImportError(f"The module '{module}' is not imported yet or does not exist.")
|
||||
|
||||
self.initialized = True
|
||||
|
||||
@@ -14,7 +14,7 @@ from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import set_realtime_priority
|
||||
from openpilot.selfdrive.modeld.runners import ModelRunner, Runtime
|
||||
from openpilot.selfdrive.modeld.models.commonmodel_pyx import sigmoid
|
||||
from openpilot.selfdrive.modeld.parse_model_outputs import sigmoid
|
||||
|
||||
CALIB_LEN = 3
|
||||
REG_SCALE = 0.25
|
||||
@@ -88,15 +88,15 @@ def fill_driver_state(msg, ds_result: DriverStateResult):
|
||||
msg.faceOrientationStd = [math.exp(x) for x in ds_result.face_orientation_std]
|
||||
msg.facePosition = [x * REG_SCALE for x in ds_result.face_position[:2]]
|
||||
msg.facePositionStd = [math.exp(x) for x in ds_result.face_position_std[:2]]
|
||||
msg.faceProb = sigmoid(ds_result.face_prob)
|
||||
msg.leftEyeProb = sigmoid(ds_result.left_eye_prob)
|
||||
msg.rightEyeProb = sigmoid(ds_result.right_eye_prob)
|
||||
msg.leftBlinkProb = sigmoid(ds_result.left_blink_prob)
|
||||
msg.rightBlinkProb = sigmoid(ds_result.right_blink_prob)
|
||||
msg.sunglassesProb = sigmoid(ds_result.sunglasses_prob)
|
||||
msg.occludedProb = sigmoid(ds_result.occluded_prob)
|
||||
msg.readyProb = [sigmoid(x) for x in ds_result.ready_prob]
|
||||
msg.notReadyProb = [sigmoid(x) for x in ds_result.not_ready_prob]
|
||||
msg.faceProb = float(sigmoid(ds_result.face_prob))
|
||||
msg.leftEyeProb = float(sigmoid(ds_result.left_eye_prob))
|
||||
msg.rightEyeProb = float(sigmoid(ds_result.right_eye_prob))
|
||||
msg.leftBlinkProb = float(sigmoid(ds_result.left_blink_prob))
|
||||
msg.rightBlinkProb = float(sigmoid(ds_result.right_blink_prob))
|
||||
msg.sunglassesProb = float(sigmoid(ds_result.sunglasses_prob))
|
||||
msg.occludedProb = float(sigmoid(ds_result.occluded_prob))
|
||||
msg.readyProb = [float(sigmoid(x)) for x in ds_result.ready_prob]
|
||||
msg.notReadyProb = [float(sigmoid(x)) for x in ds_result.not_ready_prob]
|
||||
|
||||
def get_driverstate_packet(model_output: np.ndarray, frame_id: int, location_ts: int, execution_time: float, dsp_execution_time: float):
|
||||
model_result = ctypes.cast(model_output.ctypes.data, ctypes.POINTER(DMonitoringModelResult)).contents
|
||||
@@ -105,8 +105,8 @@ def get_driverstate_packet(model_output: np.ndarray, frame_id: int, location_ts:
|
||||
ds.frameId = frame_id
|
||||
ds.modelExecutionTime = execution_time
|
||||
ds.dspExecutionTime = dsp_execution_time
|
||||
ds.poorVisionProb = sigmoid(model_result.poor_vision_prob)
|
||||
ds.wheelOnRightProb = sigmoid(model_result.wheel_on_right_prob)
|
||||
ds.poorVisionProb = float(sigmoid(model_result.poor_vision_prob))
|
||||
ds.wheelOnRightProb = float(sigmoid(model_result.wheel_on_right_prob))
|
||||
ds.rawPredictions = model_output.tobytes() if SEND_RAW_PRED else b''
|
||||
fill_driver_state(ds.leftDriverData, model_result.driver_state_lhd)
|
||||
fill_driver_state(ds.rightDriverData, model_result.driver_state_rhd)
|
||||
|
||||
@@ -3,7 +3,7 @@ import capnp
|
||||
import numpy as np
|
||||
from cereal import log
|
||||
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan, Meta
|
||||
from openpilot.selfdrive.modeld.custom_model_metadata import ModelCapabilities
|
||||
from openpilot.selfdrive.modeld.custom_model_metadata import CustomModelMetadata, ModelCapabilities
|
||||
|
||||
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
|
||||
|
||||
@@ -55,7 +55,8 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
vipc_frame_id: int, vipc_frame_id_extra: int, frame_id: int, frame_drop: float,
|
||||
timestamp_eof: int, timestamp_llk: int, model_execution_time: float,
|
||||
nav_enabled: bool, valid: bool,
|
||||
custom_model_valid: bool, custom_model_capabilities: ModelCapabilities) -> None:
|
||||
custom_model: CustomModelMetadata) -> None:
|
||||
custom_model.custom_meta()
|
||||
frame_age = frame_id - vipc_frame_id if frame_id > vipc_frame_id else 0
|
||||
frame_drop_perc = frame_drop * 100
|
||||
extended_msg.valid = valid
|
||||
@@ -66,9 +67,10 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
driving_model_data.frameId = vipc_frame_id
|
||||
driving_model_data.frameIdExtra = vipc_frame_id_extra
|
||||
driving_model_data.frameDropPerc = frame_drop_perc
|
||||
driving_model_data.modelExecutionTime = model_execution_time
|
||||
|
||||
action = driving_model_data.action
|
||||
model_use_lateral_planner = custom_model_valid and custom_model_capabilities & ModelCapabilities.LateralPlannerSolution
|
||||
model_use_lateral_planner = custom_model.valid and custom_model.capabilities & ModelCapabilities.LateralPlannerSolution
|
||||
if not model_use_lateral_planner:
|
||||
action.desiredCurvature = float(net_output_data['desired_curvature'][0,0])
|
||||
|
||||
@@ -78,7 +80,7 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
modelV2.frameAge = frame_age
|
||||
modelV2.frameDropPerc = frame_drop_perc
|
||||
modelV2.timestampEof = timestamp_eof
|
||||
model_use_nav = custom_model_valid and custom_model_capabilities & ModelCapabilities.NoO
|
||||
model_use_nav = custom_model.valid and custom_model.capabilities & ModelCapabilities.NoO
|
||||
if model_use_nav:
|
||||
modelV2.locationMonoTimeDEPRECATED = timestamp_llk
|
||||
modelV2.modelExecutionTime = model_execution_time
|
||||
@@ -172,6 +174,8 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
disengage_predictions.brake3MetersPerSecondSquaredProbs = net_output_data['meta'][0,Meta.HARD_BRAKE_3].tolist()
|
||||
disengage_predictions.brake4MetersPerSecondSquaredProbs = net_output_data['meta'][0,Meta.HARD_BRAKE_4].tolist()
|
||||
disengage_predictions.brake5MetersPerSecondSquaredProbs = net_output_data['meta'][0,Meta.HARD_BRAKE_5].tolist()
|
||||
disengage_predictions.gasPressProbs = net_output_data['meta'][0,Meta.GAS_PRESS].tolist()
|
||||
disengage_predictions.brakePressProbs = net_output_data['meta'][0,Meta.BRAKE_PRESS].tolist()
|
||||
|
||||
publish_state.prev_brake_5ms2_probs[:-1] = publish_state.prev_brake_5ms2_probs[1:]
|
||||
publish_state.prev_brake_5ms2_probs[-1] = net_output_data['meta'][0,Meta.HARD_BRAKE_5][0]
|
||||
@@ -183,10 +187,22 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
|
||||
# temporal pose
|
||||
temporal_pose = modelV2.temporalPose
|
||||
temporal_pose.trans = net_output_data['sim_pose'][0,:3].tolist()
|
||||
temporal_pose.transStd = net_output_data['sim_pose_stds'][0,:3].tolist()
|
||||
temporal_pose.rot = net_output_data['sim_pose'][0,3:].tolist()
|
||||
temporal_pose.rotStd = net_output_data['sim_pose_stds'][0,3:].tolist()
|
||||
if custom_model.valid:
|
||||
if custom_model.capabilities & ModelCapabilities.PlanVelocity:
|
||||
temporal_pose.trans = net_output_data['plan'][0,0,Plan.VELOCITY].tolist()
|
||||
temporal_pose.transStd = net_output_data['plan_stds'][0,0,Plan.VELOCITY].tolist()
|
||||
temporal_pose.rot = net_output_data['plan'][0,0,Plan.ORIENTATION_RATE].tolist()
|
||||
temporal_pose.rotStd = net_output_data['plan_stds'][0,0,Plan.ORIENTATION_RATE].tolist()
|
||||
else:
|
||||
temporal_pose.trans = net_output_data['sim_pose'][0,:3].tolist()
|
||||
temporal_pose.transStd = net_output_data['sim_pose_stds'][0,:3].tolist()
|
||||
temporal_pose.rot = net_output_data['sim_pose'][0,3:].tolist()
|
||||
temporal_pose.rotStd = net_output_data['sim_pose_stds'][0,3:].tolist()
|
||||
else:
|
||||
temporal_pose.trans = net_output_data['plan'][0,0,Plan.VELOCITY].tolist()
|
||||
temporal_pose.transStd = net_output_data['plan_stds'][0,0,Plan.VELOCITY].tolist()
|
||||
temporal_pose.rot = net_output_data['plan'][0,0,Plan.ORIENTATION_RATE].tolist()
|
||||
temporal_pose.rotStd = net_output_data['plan_stds'][0,0,Plan.ORIENTATION_RATE].tolist()
|
||||
|
||||
# confidence
|
||||
if vipc_frame_id % (2*ModelConstants.MODEL_FREQ) == 0:
|
||||
|
||||
@@ -377,7 +377,7 @@ def main(demo=False):
|
||||
posenet_send = messaging.new_message('cameraOdometry')
|
||||
fill_model_msg(drivingdata_send, modelv2_send, model_output, publish_state, meta_main.frame_id, meta_extra.frame_id, frame_id,
|
||||
frame_drop_ratio, meta_main.timestamp_eof, timestamp_llk, model_execution_time, nav_enabled, live_calib_seen,
|
||||
custom_model_metadata.valid, custom_model_metadata.capabilities)
|
||||
custom_model_metadata)
|
||||
|
||||
if not (custom_model_metadata.valid and custom_model_metadata.capabilities & ModelCapabilities.LateralPlannerSolution):
|
||||
desire_state = modelv2_send.modelV2.meta.desireState
|
||||
|
||||
@@ -47,8 +47,4 @@ ModelFrame::~ModelFrame() {
|
||||
CL_CHECK(clReleaseMemObject(u_cl));
|
||||
CL_CHECK(clReleaseMemObject(y_cl));
|
||||
CL_CHECK(clReleaseCommandQueue(q));
|
||||
}
|
||||
|
||||
float sigmoid(float input) {
|
||||
return 1 / (1 + expf(-input));
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,6 @@
|
||||
#include "selfdrive/modeld/transforms/loadyuv.h"
|
||||
#include "selfdrive/modeld/transforms/transform.h"
|
||||
|
||||
float sigmoid(float input);
|
||||
|
||||
class ModelFrame {
|
||||
public:
|
||||
ModelFrame(cl_device_id device_id, cl_context context);
|
||||
|
||||
@@ -12,8 +12,6 @@ cdef extern from "common/clutil.h":
|
||||
cl_context cl_create_context(cl_device_id)
|
||||
|
||||
cdef extern from "selfdrive/modeld/models/commonmodel.h":
|
||||
float sigmoid(float)
|
||||
|
||||
cppclass ModelFrame:
|
||||
int buf_size
|
||||
ModelFrame(cl_device_id, cl_context)
|
||||
|
||||
@@ -8,10 +8,8 @@ from libc.string cimport memcpy
|
||||
from msgq.visionipc.visionipc cimport cl_mem
|
||||
from msgq.visionipc.visionipc_pyx cimport VisionBuf, CLContext as BaseCLContext
|
||||
from .commonmodel cimport CL_DEVICE_TYPE_DEFAULT, cl_get_device_id, cl_create_context
|
||||
from .commonmodel cimport mat3, sigmoid as cppSigmoid, ModelFrame as cppModelFrame
|
||||
from .commonmodel cimport mat3, ModelFrame as cppModelFrame
|
||||
|
||||
def sigmoid(x):
|
||||
return cppSigmoid(x)
|
||||
|
||||
cdef class CLContext(BaseCLContext):
|
||||
def __cinit__(self):
|
||||
|
||||
Binary file not shown.
@@ -1,15 +1,19 @@
|
||||
import numpy as np
|
||||
from openpilot.selfdrive.modeld.constants import ModelConstants
|
||||
|
||||
def safe_exp(x, out=None):
|
||||
# -11 is around 10**14, more causes float16 overflow
|
||||
return np.exp(np.clip(x, -np.inf, 11), out=out)
|
||||
|
||||
def sigmoid(x):
|
||||
return 1. / (1. + np.exp(-x))
|
||||
return 1. / (1. + safe_exp(-x))
|
||||
|
||||
def softmax(x, axis=-1):
|
||||
x -= np.max(x, axis=axis, keepdims=True)
|
||||
if x.dtype == np.float32 or x.dtype == np.float64:
|
||||
np.exp(x, out=x)
|
||||
safe_exp(x, out=x)
|
||||
else:
|
||||
x = np.exp(x)
|
||||
x = safe_exp(x)
|
||||
x /= np.sum(x, axis=axis, keepdims=True)
|
||||
return x
|
||||
|
||||
@@ -44,7 +48,7 @@ class Parser:
|
||||
|
||||
n_values = (raw.shape[2] - out_N)//2
|
||||
pred_mu = raw[:,:,:n_values]
|
||||
pred_std = np.exp(raw[:,:,n_values: 2*n_values])
|
||||
pred_std = safe_exp(raw[:,:,n_values: 2*n_values])
|
||||
|
||||
if in_N > 1:
|
||||
weights = np.zeros((raw.shape[0], in_N, out_N), dtype=raw.dtype)
|
||||
@@ -87,7 +91,8 @@ class Parser:
|
||||
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_mdn('pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
||||
self.parse_mdn('road_transform', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
||||
self.parse_mdn('sim_pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
||||
if 'sim_pose' in outs:
|
||||
self.parse_mdn('sim_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('lead', outs, in_N=ModelConstants.LEAD_MHP_N, out_N=ModelConstants.LEAD_MHP_SELECTION,
|
||||
out_shape=(ModelConstants.LEAD_TRAJ_LEN,ModelConstants.LEAD_WIDTH))
|
||||
|
||||
@@ -14,8 +14,12 @@ def attributeproto_fp16_to_fp32(attr):
|
||||
attr.data_type = 1
|
||||
attr.raw_data = float32_list.astype(np.float32).tobytes()
|
||||
|
||||
def convert_fp16_to_fp32(path):
|
||||
model = onnx.load(path)
|
||||
def convert_fp16_to_fp32(onnx_path_or_bytes):
|
||||
if isinstance(onnx_path_or_bytes, bytes):
|
||||
model = onnx.load_from_string(onnx_path_or_bytes)
|
||||
elif isinstance(onnx_path_or_bytes, str):
|
||||
model = onnx.load(onnx_path_or_bytes)
|
||||
|
||||
for i in model.graph.initializer:
|
||||
if i.data_type == 10:
|
||||
attributeproto_fp16_to_fp32(i)
|
||||
@@ -23,6 +27,8 @@ def convert_fp16_to_fp32(path):
|
||||
if i.type.tensor_type.elem_type == 10:
|
||||
i.type.tensor_type.elem_type = 1
|
||||
for i in model.graph.node:
|
||||
if i.op_type == 'Cast' and i.attribute[0].i == 10:
|
||||
i.attribute[0].i = 1
|
||||
for a in i.attribute:
|
||||
if hasattr(a, 't'):
|
||||
if a.t.data_type == 10:
|
||||
|
||||
@@ -130,6 +130,7 @@ if __name__ == "__main__":
|
||||
ignore = [
|
||||
'logMonoTime',
|
||||
'drivingModelData.frameDropPerc',
|
||||
'drivingModelData.modelExecutionTime',
|
||||
'modelV2.frameDropPerc',
|
||||
'modelV2.modelExecutionTime',
|
||||
'driverStateV2.modelExecutionTime',
|
||||
|
||||
@@ -1 +1 @@
|
||||
01e8432830805165527d1dbadd5f009d19430b39
|
||||
9d4d653d8cc361fe2ba53f74fd8fcfe1f1d559ed
|
||||
|
||||
@@ -566,7 +566,7 @@ CONFIGS = [
|
||||
proc_name="modeld",
|
||||
pubs=["deviceState", "roadCameraState", "wideRoadCameraState", "liveCalibration", "driverMonitoringState"],
|
||||
subs=["modelV2", "drivingModelData", "cameraOdometry"],
|
||||
ignore=["logMonoTime", "modelV2.frameDropPerc", "modelV2.modelExecutionTime"],
|
||||
ignore=["logMonoTime", "modelV2.frameDropPerc", "modelV2.modelExecutionTime", "drivingModelData.frameDropPerc", "drivingModelData.modelExecutionTime"],
|
||||
should_recv_callback=ModeldCameraSyncRcvCallback(),
|
||||
tolerance=NUMPY_TOLERANCE,
|
||||
processing_time=0.020,
|
||||
|
||||
@@ -145,4 +145,4 @@ void HttpRequest::requestFinished() {
|
||||
QNetworkAccessManager *HttpRequest::nam() {
|
||||
static QNetworkAccessManager *networkAccessManager = new QNetworkAccessManager(qApp);
|
||||
return networkAccessManager;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class HttpRequest : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class Method { GET, DELETE, POST, PUT };
|
||||
enum class Method {GET, DELETE, POST, PUT};
|
||||
|
||||
explicit HttpRequest(QObject* parent, bool create_jwt = true, int timeout = 20000);
|
||||
virtual void sendRequest(const QString &requestURL, Method method);
|
||||
@@ -47,4 +47,4 @@ protected:
|
||||
protected slots:
|
||||
void requestTimeout();
|
||||
void requestFinished();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -86,8 +86,7 @@ void HomeWindow::mousePressEvent(QMouseEvent* e) {
|
||||
}
|
||||
|
||||
void HomeWindow::mouseDoubleClickEvent(QMouseEvent* e) {
|
||||
// By removing the static call to HomeWindow::mousePressEvent, we can now rely on child classes to handle the event
|
||||
mousePressEvent(e);
|
||||
HomeWindow::mousePressEvent(e);
|
||||
const SubMaster &sm = *(uiState()->sm);
|
||||
if (sm["carParams"].getCarParams().getNotCar()) {
|
||||
if (onroad->isVisible()) {
|
||||
|
||||
@@ -47,7 +47,7 @@ protected:
|
||||
void mouseDoubleClickEvent(QMouseEvent* e) override;
|
||||
|
||||
Sidebar *sidebar;
|
||||
OffroadHome* home;
|
||||
OffroadHome *home;
|
||||
OnroadWindow *onroad;
|
||||
BodyWindow *body;
|
||||
DriverViewWindow *driver_view;
|
||||
@@ -55,4 +55,4 @@ protected:
|
||||
|
||||
protected slots:
|
||||
virtual void updateState(const UIState &s);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "selfdrive/ui/qt/widgets/ssh_keys.h"
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/sunnypilot_main.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
RETURN_IF_SUNNYPILOT
|
||||
|
||||
@@ -91,7 +91,6 @@ protected:
|
||||
virtual void updateToggles();
|
||||
};
|
||||
|
||||
|
||||
class SoftwarePanel : public ListWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
|
||||
void SoftwarePanel::checkForUpdates() {
|
||||
std::system("pkill -SIGUSR1 -f updated");
|
||||
std::system("pkill -SIGUSR1 -f system.updated.updated");
|
||||
}
|
||||
|
||||
SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) {
|
||||
@@ -45,7 +45,7 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) {
|
||||
if (downloadBtn->text() == tr("CHECK")) {
|
||||
checkForUpdates();
|
||||
} else {
|
||||
std::system("pkill -SIGHUP -f updated");
|
||||
std::system("pkill -SIGHUP -f system.updated.updated");
|
||||
}
|
||||
});
|
||||
addItem(downloadBtn);
|
||||
@@ -162,4 +162,4 @@ void SoftwarePanel::updateLabels() {
|
||||
installBtn->setDescription(QString::fromStdString(params.get("UpdaterNewReleaseNotes")));
|
||||
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QMouseEvent>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "selfdrive/ui/qt/offroad/experimental_mode.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QStackedLayout>
|
||||
#include <QStackedWidget>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "common/params.h"
|
||||
#include "selfdrive/ui/qt/offroad/driverview.h"
|
||||
#include "selfdrive/ui/qt/body.h"
|
||||
#include "selfdrive/ui/qt/onroad/onroad_home.h"
|
||||
#include "selfdrive/ui/qt/widgets/offroad_alerts.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
|
||||
@@ -385,4 +385,4 @@ void AnnotatedCameraWidget::showEvent(QShowEvent *event) {
|
||||
|
||||
ui_update_params(uiState());
|
||||
prev_draw_t = millis_since_boot();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,4 +50,4 @@ protected:
|
||||
|
||||
double prev_draw_t = 0;
|
||||
FirstOrderFilter fps_filter;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -26,8 +26,7 @@ ExperimentalButton::ExperimentalButton(QWidget *parent) : experimental_mode(fals
|
||||
|
||||
void ExperimentalButton::changeMode() {
|
||||
const auto cp = (*uiState()->sm)["carParams"].getCarParams();
|
||||
bool can_change = (hasLongitudinalControl(cp) || (!cp.getPcmCruiseSpeed() && params.getBool("CustomStockLongPlanner")))
|
||||
&& params.getBool("ExperimentalModeConfirmed");
|
||||
bool can_change = hasLongitudinalControl(cp) && params.getBool("ExperimentalModeConfirmed");
|
||||
if (can_change) {
|
||||
params.putBool("ExperimentalMode", !experimental_mode);
|
||||
}
|
||||
|
||||
@@ -31,4 +31,4 @@ private:
|
||||
QPixmap experimental_img;
|
||||
};
|
||||
|
||||
void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity);
|
||||
void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity);
|
||||
|
||||
@@ -66,4 +66,4 @@ void OnroadWindow::offroadTransition(bool offroad) {
|
||||
void OnroadWindow::paintEvent(QPaintEvent *event) {
|
||||
QPainter p(this);
|
||||
p.fillRect(rect(), QColor(bg.red(), bg.green(), bg.blue(), 255));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,4 @@ protected:
|
||||
protected slots:
|
||||
virtual void offroadTransition(bool offroad);
|
||||
virtual void updateState(const UIState &s);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -20,4 +20,4 @@ private:
|
||||
Params params;
|
||||
QTimer *timer;
|
||||
QString prevResp;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -65,4 +65,4 @@ protected:
|
||||
|
||||
private:
|
||||
std::unique_ptr<PubMaster> pm;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -61,4 +61,4 @@ int main(int argc, char *argv[]) {
|
||||
)");
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,4 +59,4 @@ private:
|
||||
QFileSystemWatcher *watcher;
|
||||
QHash<QString, QString> params_hash;
|
||||
Params params;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -35,4 +35,4 @@ private:
|
||||
|
||||
void refresh();
|
||||
void getUserKeys(const QString &username);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -30,7 +30,7 @@ sp_maps_widgets_src = [
|
||||
]
|
||||
|
||||
sp_qt_util = [
|
||||
# "#selfdrive/ui/sunnypilot/qt/api.cc",
|
||||
# "#selfdrive/ui/sunnypilot/qt/api.cc",
|
||||
"#selfdrive/ui/sunnypilot/qt/util.cc",
|
||||
]
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ Last updated: July 29, 2024
|
||||
#include <QApplication>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <common/swaglog.h>
|
||||
|
||||
|
||||
@@ -26,11 +26,6 @@ Last updated: July 29, 2024
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
|
||||
#include "selfdrive/ui/qt/api.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/util.h"
|
||||
#include "common/util.h"
|
||||
|
||||
@@ -28,13 +28,10 @@ Last updated: July 29, 2024
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QMouseEvent>
|
||||
#include <QStackedWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <common/swaglog.h>
|
||||
|
||||
#include "selfdrive/ui/qt/offroad/experimental_mode.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/widgets/prime.h"
|
||||
|
||||
// HomeWindowSP: the container for the offroad and onroad UIs
|
||||
HomeWindowSP::HomeWindowSP(QWidget* parent) : HomeWindow(parent){
|
||||
|
||||
@@ -27,14 +27,9 @@ Last updated: July 29, 2024
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QStackedLayout>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "common/params.h"
|
||||
#include "selfdrive/ui/qt/offroad/driverview.h"
|
||||
#include "selfdrive/ui/qt/body.h"
|
||||
#include "selfdrive/ui/qt/widgets/offroad_alerts.h"
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
@@ -42,7 +37,6 @@ Last updated: July 29, 2024
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/sidebar.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h"
|
||||
#define OnroadWindow OnroadWindowSP
|
||||
#else
|
||||
#include "selfdrive/ui/qt/sidebar.h"
|
||||
|
||||
@@ -30,7 +30,6 @@ Last updated: July 29, 2024
|
||||
#include <vector>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "common/watchdog.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
#include "selfdrive/ui/qt/widgets/prime.h"
|
||||
|
||||
|
||||
@@ -28,11 +28,9 @@ Last updated: July 29, 2024
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||
|
||||
class MonitoringPanel : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -177,5 +177,18 @@ std::vector<Model> ModelsFetcher::getModelsFromURL(const QString&url) {
|
||||
}
|
||||
|
||||
std::vector<Model> ModelsFetcher::getModelsFromURL() {
|
||||
return getModelsFromURL("https://docs.sunnypilot.ai/models_v5.json");
|
||||
return getModelsFromURL("https://docs.sunnypilot.ai/driving_models.json");
|
||||
}
|
||||
|
||||
std::vector<Model> ModelsFetcher::getCompatibleModels(const QString &selector_version) {
|
||||
std::vector<Model> allModels = getModelsFromURL();
|
||||
std::vector<Model> compatibleModels;
|
||||
|
||||
for (const auto &model : allModels) {
|
||||
if (model.isCompatible(selector_version)) {
|
||||
compatibleModels.push_back(model);
|
||||
}
|
||||
}
|
||||
|
||||
return compatibleModels;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ Last updated: July 29, 2024
|
||||
#include <QDir>
|
||||
#include <QJsonObject>
|
||||
#include <QTimer>
|
||||
#include <QVersionNumber>
|
||||
|
||||
#include "common/swaglog.h"
|
||||
#include "common/util.h"
|
||||
@@ -86,6 +87,8 @@ public:
|
||||
index = json["index"].toString();
|
||||
environment = json["environment"].toString();
|
||||
generation = json["generation"].toString();
|
||||
|
||||
minDrivingModelSelectorVersion = json["minimum_selector_version"].toString();
|
||||
}
|
||||
|
||||
// Method to convert model back to QJsonObject, if needed
|
||||
@@ -117,6 +120,9 @@ public:
|
||||
json["index"] = index;
|
||||
json["environment"] = environment;
|
||||
json["generation"] = generation;
|
||||
|
||||
json["minimum_selector_version"] = minDrivingModelSelectorVersion;
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@@ -134,6 +140,13 @@ public:
|
||||
QString index;
|
||||
QString environment;
|
||||
QString generation;
|
||||
|
||||
QString minDrivingModelSelectorVersion;
|
||||
|
||||
bool isCompatible(const QString &selector_version) const {
|
||||
return QVersionNumber::fromString(selector_version) >=
|
||||
QVersionNumber::fromString(minDrivingModelSelectorVersion);
|
||||
}
|
||||
};
|
||||
|
||||
class ModelsFetcher : public QObject {
|
||||
@@ -145,6 +158,7 @@ public:
|
||||
static std::vector<Model> getModelsFromURL(const QUrl&url);
|
||||
static std::vector<Model> getModelsFromURL(const QString&url);
|
||||
static std::vector<Model> getModelsFromURL();
|
||||
static std::vector<Model> getCompatibleModels(const QString &selector_version);
|
||||
|
||||
signals:
|
||||
void downloadProgress(double percentage);
|
||||
|
||||
@@ -57,12 +57,6 @@ TogglesPanelSP::TogglesPanelSP(SettingsWindow *parent) : TogglesPanel(parent) {
|
||||
tr("When enabled, sunnypilot will attempt to control stock longitudinal control with ACC button presses.\nThis feature must be used along with SLC, and/or V-TSC, and/or M-TSC."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"CustomStockLongPlanner",
|
||||
tr("Use Planner Speed"),
|
||||
"",
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"ExperimentalMode",
|
||||
tr("Experimental Mode"),
|
||||
@@ -229,7 +223,6 @@ void TogglesPanelSP::updateToggles() {
|
||||
auto custom_stock_long_toggle = toggles["CustomStockLong"];
|
||||
auto dec_toggle = toggles["DynamicExperimentalControl"];
|
||||
auto dynamic_personality_toggle = toggles["DynamicPersonality"];
|
||||
auto custom_stock_long_planner = toggles["CustomStockLongPlanner"];
|
||||
const QString e2e_description = QString("%1<br>"
|
||||
"<h4>%2</h4><br>"
|
||||
"%3<br>"
|
||||
@@ -268,22 +261,16 @@ void TogglesPanelSP::updateToggles() {
|
||||
accel_personality_setting->setEnabled(true);
|
||||
op_long_toggle->setEnabled(true);
|
||||
custom_stock_long_toggle->setEnabled(false);
|
||||
custom_stock_long_planner->setEnabled(false);
|
||||
params.remove("CustomStockLong");
|
||||
dec_toggle->setEnabled(true);
|
||||
dynamic_personality_toggle->setEnabled(true);
|
||||
} else if (custom_stock_long_toggle->isToggled()) {
|
||||
op_long_toggle->setEnabled(false);
|
||||
experimental_mode_toggle->setEnabled(custom_stock_long_planner->isToggled());
|
||||
experimental_mode_toggle->setDescription(e2e_description);
|
||||
custom_stock_long_planner->setEnabled(true);
|
||||
long_personality_setting->setEnabled(custom_stock_long_planner->isToggled());
|
||||
accel_personality_setting->setEnabled(custom_stock_long_planner->isToggled());
|
||||
dec_toggle->setEnabled(experimental_mode_toggle->isToggled());
|
||||
if (!custom_stock_long_planner->isToggled()) {
|
||||
params.remove("ExperimentalMode");
|
||||
}
|
||||
experimental_mode_toggle->setEnabled(false);
|
||||
long_personality_setting->setEnabled(false);
|
||||
accel_personality_setting->setEnabled(false);
|
||||
params.remove("ExperimentalLongitudinalEnabled");
|
||||
params.remove("ExperimentalMode");
|
||||
} else {
|
||||
// no long for now
|
||||
experimental_mode_toggle->setEnabled(false);
|
||||
@@ -308,7 +295,6 @@ void TogglesPanelSP::updateToggles() {
|
||||
custom_stock_long_toggle->setEnabled(CP.getCustomStockLongAvailable());
|
||||
dec_toggle->setEnabled(false);
|
||||
dynamic_personality_toggle->setEnabled(false);
|
||||
custom_stock_long_planner->setEnabled(false);
|
||||
params.remove("DynamicExperimentalControl");
|
||||
params.remove("DynamicPersonality");
|
||||
}
|
||||
@@ -316,7 +302,6 @@ void TogglesPanelSP::updateToggles() {
|
||||
experimental_mode_toggle->refresh();
|
||||
op_long_toggle->refresh();
|
||||
custom_stock_long_toggle->refresh();
|
||||
custom_stock_long_planner->refresh();
|
||||
dec_toggle->refresh();
|
||||
dynamic_personality_toggle->refresh();
|
||||
} else {
|
||||
@@ -325,7 +310,6 @@ void TogglesPanelSP::updateToggles() {
|
||||
custom_stock_long_toggle->setVisible(false);
|
||||
dec_toggle->setVisible(false);
|
||||
dynamic_personality_toggle->setVisible(false);
|
||||
custom_stock_long_planner->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -210,12 +210,13 @@ void SoftwarePanelSP::handleCurrentModelLblBtnClicked() {
|
||||
checkNetwork();
|
||||
const auto currentModelName = QString::fromStdString(params.get("DrivingModelName"));
|
||||
const bool is_release_sp = params.getBool("IsReleaseSPBranch");
|
||||
const auto models = ModelsFetcher::getModelsFromURL();
|
||||
const QString selector_version = QString::fromStdString(params.get("DrivingModelSelectorVersion"));
|
||||
const auto compatible_models = ModelsFetcher::getCompatibleModels(selector_version);
|
||||
|
||||
QMap<QString, QString> index_to_model;
|
||||
|
||||
// Collecting indices with display names
|
||||
for (const auto &model : models) {
|
||||
for (const auto &model : compatible_models) {
|
||||
if ((is_release_sp && model.environment == "release") || !is_release_sp) {
|
||||
index_to_model.insert(model.index, model.displayName);
|
||||
}
|
||||
@@ -243,7 +244,7 @@ void SoftwarePanelSP::handleCurrentModelLblBtnClicked() {
|
||||
}
|
||||
|
||||
// Finding and setting the selected model
|
||||
for (auto &model : models) {
|
||||
for (auto &model : compatible_models) {
|
||||
if (model.displayName == selectedModelName) {
|
||||
selectedModelToDownload = model;
|
||||
selectedNavModelToDownload = model;
|
||||
|
||||
@@ -49,12 +49,6 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) {
|
||||
tr("While in Auto Lane, switch to Laneless for current/future curves."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"OvertakingAccelerationAssist",
|
||||
tr("Overtaking Acceleration Assist"),
|
||||
tr("Overtaking Acceleration Assist will operate when the turn signal indicator is turned on to the left (left-hand drive) or turned on to the right (right-hand drive) while openpilot Longitudinal Control is operating."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"EnableSlc",
|
||||
tr("Speed Limit Control (SLC)"),
|
||||
@@ -97,24 +91,12 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) {
|
||||
"",
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"NNFFNoLateralJerk",
|
||||
tr("NNLC: Remove Lateral Jerk Response (Alpha)"),
|
||||
tr("When NNLC is active, enable this to disables the use of lateral jerk in steering torque calculations, focusing solely on lateral acceleration for a simplified control response."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"EnforceTorqueLateral",
|
||||
tr("Enforce Torque Lateral Control"),
|
||||
tr("Enable this to enforce sunnypilot to steer with Torque lateral control."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"TorqueLateralJerk",
|
||||
tr("Lateral Jerk with Torque Lateral Control (Alpha)"),
|
||||
tr("Utilizes limited lateral jerk control for improved steering response, leveraging stock torque lateral controller capabilities. Designed to mimic NNLC behavior without training models or data collection."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"LiveTorque",
|
||||
tr("Enable Self-Tune"),
|
||||
@@ -316,7 +298,7 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) {
|
||||
list->addItem(dlp_settings);
|
||||
}
|
||||
|
||||
if (param == "OvertakingAccelerationAssist") {
|
||||
if (param == "VisionCurveLaneless") {
|
||||
list->addItem(laneChangeSettingsLayout);
|
||||
list->addItem(horizontal_line());
|
||||
|
||||
@@ -363,17 +345,6 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) {
|
||||
}
|
||||
});
|
||||
|
||||
connect(toggles["EnforceTorqueLateral"], &ToggleControlSP::toggleFlipped, [=](bool state) {
|
||||
if (state) {
|
||||
toggles["NNFF"]->setEnabled(false);
|
||||
params.putBool("NNFF", false);
|
||||
toggles["NNFF"]->refresh();
|
||||
} else {
|
||||
toggles["NNFF"]->setEnabled(true);
|
||||
toggles["NNFF"]->refresh();
|
||||
}
|
||||
});
|
||||
|
||||
// trigger updateToggles() when toggleFlipped
|
||||
for (const auto& updateToggleName : updateTogglesNames) {
|
||||
if (toggles.find(updateToggleName) != toggles.end()) {
|
||||
@@ -395,7 +366,6 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) {
|
||||
toggles["EnableMads"]->setConfirmation(true, false);
|
||||
toggles["EndToEndLongAlertLight"]->setConfirmation(true, false);
|
||||
toggles["CustomOffsets"]->showDescription();
|
||||
toggles["OvertakingAccelerationAssist"]->setConfirmation(true, false);
|
||||
|
||||
connect(toggles["EnableMads"], &ToggleControlSP::toggleFlipped, mads_settings, &MadsSettings::updateToggles);
|
||||
connect(toggles["EnableMads"], &ToggleControlSP::toggleFlipped, [=](bool state) {
|
||||
@@ -500,8 +470,6 @@ void SunnypilotPanel::updateToggles() {
|
||||
toggles["VisionCurveLaneless"]->setEnabled(dynamic_lane_profile_param == "2");
|
||||
toggles["VisionCurveLaneless"]->refresh();
|
||||
|
||||
auto overtaking_acceleration_assist = toggles["OvertakingAccelerationAssist"];
|
||||
|
||||
bool custom_driving_model_valid = params.getBool("CustomDrivingModel");
|
||||
auto driving_model_generation = QString::fromStdString(params.get("DrivingModelGeneration"));
|
||||
bool model_use_lateral_planner = custom_driving_model_valid && driving_model_generation == "1";
|
||||
@@ -581,7 +549,6 @@ void SunnypilotPanel::updateToggles() {
|
||||
if (!slcSettings->isVisible() && enable_slc_param) {
|
||||
slcSettings->setVisible(true);
|
||||
}
|
||||
overtaking_acceleration_assist->setEnabled(hasLongitudinalControl(CP));
|
||||
} else {
|
||||
v_tsc->setEnabled(false);
|
||||
m_tsc->setEnabled(false);
|
||||
@@ -589,21 +556,18 @@ void SunnypilotPanel::updateToggles() {
|
||||
slc_toggle->setEnabled(false);
|
||||
params.remove("EnableSlc");
|
||||
slcSettings->setEnabled(false);
|
||||
overtaking_acceleration_assist->setEnabled(false);
|
||||
}
|
||||
|
||||
enforce_torque_lateral->refresh();
|
||||
slc_toggle->refresh();
|
||||
nnff_toggle->refresh();
|
||||
m_tsc->refresh();
|
||||
overtaking_acceleration_assist->refresh();
|
||||
} else {
|
||||
v_tsc->setEnabled(false);
|
||||
m_tsc->setEnabled(false);
|
||||
reverse_acc->setEnabled(false);
|
||||
slc_toggle->setEnabled(false);
|
||||
slcSettings->setEnabled(false);
|
||||
overtaking_acceleration_assist->setEnabled(false);
|
||||
|
||||
nnff_toggle->setDescription(nnff_toggle->isToggled() ? nnffDescriptionBuilder(nnff_status_init) : nnff_description);
|
||||
}
|
||||
@@ -613,7 +577,7 @@ void SunnypilotPanel::updateToggles() {
|
||||
}
|
||||
|
||||
// toggle names to update when EnforceTorqueLateral is flipped
|
||||
std::vector<std::string> torqueLateralGroup{"CustomTorqueLateral", "TorqueLateralJerk", "LiveTorque", "LiveTorqueRelaxed", "TorquedOverride"};
|
||||
std::vector<std::string> torqueLateralGroup{"CustomTorqueLateral", "LiveTorque", "LiveTorqueRelaxed", "TorquedOverride"};
|
||||
for (const auto& torqueLateralToggle : torqueLateralGroup) {
|
||||
if (toggles.find(torqueLateralToggle) != toggles.end()) {
|
||||
if (nnff_toggle->isToggled()) {
|
||||
@@ -630,24 +594,6 @@ void SunnypilotPanel::updateToggles() {
|
||||
}
|
||||
}
|
||||
|
||||
// toggle names to update when EnforceTorqueLateral is flipped
|
||||
std::vector<std::string> nnffGroup{"NNFFNoLateralJerk"};
|
||||
for (const auto& nnffToggle : nnffGroup) {
|
||||
if (toggles.find(nnffToggle) != toggles.end()) {
|
||||
if (enforce_torque_lateral->isToggled()) {
|
||||
toggles[nnffToggle]->setVisible(false);
|
||||
toggles[nnffToggle]->setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& nnffToggle : nnffGroup) {
|
||||
if (toggles.find(nnffToggle) != toggles.end()) {
|
||||
toggles[nnffToggle]->setVisible(nnff_toggle->isToggled());
|
||||
toggles[nnffToggle]->setEnabled(nnff_toggle->isToggled());
|
||||
}
|
||||
}
|
||||
|
||||
if (enforce_torque_lateral->isToggled()) {
|
||||
live_torque_relaxed->setVisible(live_torque->isToggled());
|
||||
torqued_override->setVisible(custom_torque_lateral->isToggled());
|
||||
@@ -676,14 +622,13 @@ TorqueFriction::TorqueFriction() : OptionControlSP(
|
||||
tr("FRICTION"),
|
||||
tr("Adjust Friction for the Torque Lateral Controller. <b>Live</b>: Override self-tune values; <b>Offline</b>: Override self-tune offline values at car restart."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
{0, 500},
|
||||
5) {
|
||||
{0, 50}) {
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void TorqueFriction::refresh() {
|
||||
float torqueFrictionVal = QString::fromStdString(params.get("TorqueFriction")).toInt() * 0.001;
|
||||
float torqueFrictionVal = QString::fromStdString(params.get("TorqueFriction")).toInt() * 0.01;
|
||||
setTitle("FRICTION - " + (params.getBool("TorquedOverride") ? tr("Real-time and Offline") : tr("Offline Only")));
|
||||
setLabel(QString::number(torqueFrictionVal));
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ Last updated: July 29, 2024
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "common/model.h"
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/custom_offsets_settings.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnypilot/lane_change_settings.h"
|
||||
|
||||
@@ -101,14 +101,13 @@ SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(VehiclePanel *parent) : ListWidge
|
||||
|
||||
// Hyundai/Kia/Genesis
|
||||
addItem(new LabelControlSP(tr("Hyundai/Kia/Genesis")));
|
||||
auto hkgCustomLongTuning = new ParamControlSP(
|
||||
"HkgCustomLongTuning",
|
||||
tr("HKG: Custom Tuning for New Longitudinal API"),
|
||||
tr(""),
|
||||
"../assets/offroad/icon_blank.png"
|
||||
);
|
||||
hkgCustomLongTuning->setConfirmation(true, false);
|
||||
addItem(hkgCustomLongTuning);
|
||||
auto hkgSmoothStop = new ParamControlSP(
|
||||
"HkgSmoothStop",
|
||||
tr("HKG CAN: Smoother Stopping Performance (Beta)"),
|
||||
tr("Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control."),
|
||||
"../assets/offroad/icon_blank.png");
|
||||
hkgSmoothStop->setConfirmation(true, false);
|
||||
addItem(hkgSmoothStop);
|
||||
|
||||
hyundaiCruiseMainDefault = new ParamControlSP(
|
||||
"HyundaiCruiseMainDefault",
|
||||
@@ -191,14 +190,6 @@ SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(VehiclePanel *parent) : ListWidge
|
||||
toyotaAutoUnlock->setConfirmation(true, false);
|
||||
addItem(toyotaAutoUnlock);
|
||||
|
||||
auto toyotaDriveMode = new ParamControlSP(
|
||||
"ToyotaDriveMode",
|
||||
tr("Enable Toyota Drive Mode Button"),
|
||||
tr("Sunnypilot will link the Acceleration Personality to the car's physical drive mode selector.\nReboot Required."),
|
||||
"../assets/offroad/icon_blank.png");
|
||||
toyotaDriveMode->setConfirmation(true, false);
|
||||
addItem(toyotaDriveMode);
|
||||
|
||||
// Volkswagen
|
||||
addItem(new LabelControlSP(tr("Volkswagen")));
|
||||
auto volkswagenCCOnly = new ParamControlSP(
|
||||
@@ -212,7 +203,7 @@ SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(VehiclePanel *parent) : ListWidge
|
||||
// trigger offroadTransition when going onroad/offroad
|
||||
connect(uiStateSP(), &UIStateSP::offroadTransition, [=](bool offroad) {
|
||||
is_onroad = !offroad;
|
||||
hkgCustomLongTuning->setEnabled(offroad);
|
||||
hkgSmoothStop->setEnabled(offroad);
|
||||
hyundaiCruiseMainDefault->setEnabled(offroad);
|
||||
toyotaTss2LongTune->setEnabled(offroad);
|
||||
toyotaEnhancedBsm->setEnabled(offroad);
|
||||
|
||||
@@ -28,10 +28,8 @@ Last updated: July 29, 2024
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "common/watchdog.h"
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||
|
||||
class VehiclePanel : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -30,7 +30,6 @@ Last updated: July 29, 2024
|
||||
|
||||
#include "selfdrive/ui/qt/offroad/experimental_mode.h"
|
||||
#include "selfdrive/ui/qt/widgets/prime.h"
|
||||
#include <QStackedWidget>
|
||||
#include "selfdrive/ui/sunnypilot/sunnypilot_main.h"
|
||||
|
||||
#ifdef ENABLE_MAPS
|
||||
|
||||
@@ -31,7 +31,6 @@ Last updated: July 29, 2024
|
||||
#include "selfdrive/ui/qt/maps/map_settings.h"
|
||||
#endif
|
||||
|
||||
|
||||
class OffroadHomeSP : public OffroadHome {
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -320,8 +320,8 @@ void AnnotatedCameraWidgetSP::updateState(const UIStateSP &s) {
|
||||
// TODO: Add toggle variables to cereal, and parse from cereal
|
||||
longitudinalPersonality = s.scene.longitudinal_personality;
|
||||
dynamicLaneProfile = s.scene.dynamic_lane_profile;
|
||||
const auto mpc_source = lp_sp.getMpcSource();
|
||||
mpcSource = mpc_source == cereal::MpcSource::BLENDED ? QString(tr("blended")) : QString(tr("acc"));
|
||||
mpcMode = QString::fromStdString(lp_sp.getE2eBlended());
|
||||
mpcMode = (mpcMode == "blended") ? mpcMode.replace(0, 1, mpcMode[0].toUpper()) : mpcMode.toUpper();
|
||||
|
||||
static int reverse_delay = 0;
|
||||
bool reverse_allowed = false;
|
||||
@@ -1061,7 +1061,7 @@ void AnnotatedCameraWidgetSP::drawFeatureStatusText(QPainter &p, int x, int y) {
|
||||
p.setBrush(dec_color);
|
||||
p.drawEllipse(dec_btn);
|
||||
QString dec_status_text;
|
||||
dec_status_text.sprintf("DEC: %s\n", dynamicExperimentalControlToggle ? (experimentalMode ? QString(mpcSource).toStdString().c_str() : QString("Inactive").toStdString().c_str()) : "OFF");
|
||||
dec_status_text.sprintf("DEC: %s\n", dynamicExperimentalControlToggle ? (experimentalMode ? QString(mpcMode).toStdString().c_str() : QString("Inactive").toStdString().c_str()) : "OFF");
|
||||
p.setPen(QPen(shadow_color, 2));
|
||||
p.drawText(x + drop_shadow_size, y + drop_shadow_size, dec_status_text);
|
||||
p.setPen(QPen(text_color, 2));
|
||||
@@ -1177,10 +1177,6 @@ void AnnotatedCameraWidgetSP::drawLaneLines(QPainter &painter, const UIStateSP *
|
||||
|
||||
// paint path
|
||||
QLinearGradient bg(0, height(), 0, 0);
|
||||
const auto long_plan_sp = sm["longitudinalPlanSP"].getLongitudinalPlanSP();
|
||||
bool exp_mode_path = (long_plan_sp.getDynamicExperimentalControl() && long_plan_sp.getMpcSource() == cereal::MpcSource::BLENDED) ||
|
||||
(!long_plan_sp.getDynamicExperimentalControl() && sm["controlsState"].getControlsState().getExperimentalMode());
|
||||
|
||||
if (madsEnabled || car_state.getCruiseState().getEnabled()) {
|
||||
if (steerOverride && latActive) {
|
||||
bg.setColorAt(0.0, QColor::fromHslF(20 / 360., 0.94, 0.51, 0.17));
|
||||
@@ -1189,7 +1185,7 @@ void AnnotatedCameraWidgetSP::drawLaneLines(QPainter &painter, const UIStateSP *
|
||||
} else if (!(latActive || car_state.getCruiseState().getEnabled())) {
|
||||
bg.setColorAt(0, whiteColor());
|
||||
bg.setColorAt(1, whiteColor(0));
|
||||
} else if (exp_mode_path) {
|
||||
} else if (sm["controlsState"].getControlsState().getExperimentalMode()) {
|
||||
// The first half of track_vertices are the points for the right side of the path
|
||||
const auto &acceleration = sm["modelV2"].getModelV2().getAcceleration().getX();
|
||||
const int max_len = std::min<int>(scene.track_vertices.length() / 2, acceleration.size());
|
||||
@@ -1290,25 +1286,46 @@ void AnnotatedCameraWidgetSP::drawDriverState(QPainter &painter, const UIStateSP
|
||||
}
|
||||
|
||||
void AnnotatedCameraWidgetSP::rocketFuel(QPainter &p) {
|
||||
UIState *s = uiState();
|
||||
float accel = (*s->sm)["carControl"].getCarControl().getActuators().getAccel();
|
||||
int widgetHeight = rect().height();
|
||||
float halfHeightAbs = std::abs(accel) * widgetHeight / 2.0f;
|
||||
const float scannerWidth = 15;
|
||||
QRect scannerRect;
|
||||
|
||||
if (accel > 0) {
|
||||
static const int ct_n = 1;
|
||||
static float ct;
|
||||
|
||||
int rect_w = rect().width();
|
||||
int rect_h = rect().height();
|
||||
|
||||
const int n = 15 + 1; //Add one off screen due to timing issues
|
||||
static float t[n];
|
||||
int dim_n = (sin(ct / 5) + 1) * (n - 0.01);
|
||||
t[dim_n] = 1.0;
|
||||
t[(int)(ct/ct_n)] = 1.0;
|
||||
|
||||
UIStateSP *s = uiStateSP();
|
||||
float vc_accel0 = (*s->sm)["carState"].getCarState().getAEgo();
|
||||
static float vc_accel;
|
||||
vc_accel = vc_accel + (vc_accel0 - vc_accel) / 5;
|
||||
float hha = 0;
|
||||
if (vc_accel > 0) {
|
||||
hha = 0.85 - 0.1 / vc_accel; // only extend up to 85%
|
||||
p.setBrush(QColor(0, 245, 0, 200));
|
||||
scannerRect = QRect(0, widgetHeight / 2 - halfHeightAbs, scannerWidth, halfHeightAbs);
|
||||
} else {
|
||||
p.setBrush(QColor(245, 0, 0, 200));
|
||||
scannerRect = QRect(0, widgetHeight / 2, scannerWidth, halfHeightAbs);
|
||||
}
|
||||
|
||||
p.drawRect(scannerRect);
|
||||
if (vc_accel < 0) {
|
||||
hha = 0.85 + 0.1 / vc_accel; // only extend up to 85%
|
||||
p.setBrush(QColor(245, 0, 0, 200));
|
||||
}
|
||||
if (hha < 0) {
|
||||
hha = 0;
|
||||
}
|
||||
hha = hha * rect_h;
|
||||
float wp = 28;
|
||||
if (vc_accel > 0) {
|
||||
QRect ra = QRect(rect_w - wp, rect_h / 2 - hha / 2, wp, hha / 2);
|
||||
p.drawRect(ra);
|
||||
} else {
|
||||
QRect ra = QRect(rect_w - wp, rect_h / 2, wp, hha / 2);
|
||||
p.drawRect(ra);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AnnotatedCameraWidgetSP::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd,
|
||||
int num, const cereal::CarState::Reader &car_data, int chevron_data) {
|
||||
painter.save();
|
||||
|
||||
@@ -192,7 +192,7 @@ private:
|
||||
cereal::LongitudinalPlanSP::SpeedLimitControlState slcState;
|
||||
int longitudinalPersonality;
|
||||
int dynamicLaneProfile;
|
||||
QString mpcSource;
|
||||
QString mpcMode;
|
||||
|
||||
int speed_limit_frame;
|
||||
bool slcShowSign = true;
|
||||
|
||||
@@ -26,8 +26,6 @@ Last updated: July 29, 2024
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_home.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStackedLayout>
|
||||
|
||||
#ifdef ENABLE_MAPS
|
||||
#include "selfdrive/ui/sunnypilot/qt/maps/map_helpers.h"
|
||||
|
||||
@@ -29,9 +29,6 @@ Last updated: July 29, 2024
|
||||
#include "selfdrive/ui/qt/onroad/onroad_home.h"
|
||||
|
||||
#include "common/params.h"
|
||||
#include "selfdrive/ui/qt/onroad/alerts.h"
|
||||
// #include "selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h"
|
||||
|
||||
|
||||
class OnroadWindowSP : public OnroadWindow {
|
||||
Q_OBJECT
|
||||
@@ -62,7 +59,6 @@ private:
|
||||
void createMapWidget();
|
||||
void createOnroadSettingsWidget();
|
||||
void mousePressEvent(QMouseEvent* e) override;
|
||||
// AnnotatedCameraWidgetSP *nvg;
|
||||
QWidget *map = nullptr;
|
||||
QWidget *onroad_settings = nullptr;
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ void OnroadSettings::changeDynamicPersonality() {
|
||||
void OnroadSettings::changeDynamicExperimentalControl() {
|
||||
UISceneSP &scene = uiStateSP()->scene;
|
||||
const auto cp = (*uiStateSP()->sm)["carParams"].getCarParams();
|
||||
bool can_change = hasLongitudinalControl(cp) || (!cp.getPcmCruiseSpeed() && params.getBool("CustomStockLongPlanner"));
|
||||
bool can_change = hasLongitudinalControl(cp);
|
||||
if (can_change) {
|
||||
scene.dynamic_experimental_control = !scene.dynamic_experimental_control;
|
||||
params.putBool("DynamicExperimentalControl", scene.dynamic_experimental_control);
|
||||
|
||||
@@ -26,7 +26,6 @@ Last updated: July 29, 2024
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_settings_panel.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/onroad/onroad_settings.h"
|
||||
|
||||
@@ -34,7 +34,6 @@ Last updated: July 29, 2024
|
||||
#include "selfdrive/ui/sunnypilot/qt/util.h"
|
||||
#include "common/params.h"
|
||||
|
||||
|
||||
SidebarSP::SidebarSP(QWidget *parent) : Sidebar(parent) {
|
||||
// Because I know that stock sidebar makes this connection, I will disconnect it and connect it to the new updateState function
|
||||
QObject::disconnect(uiState(), &UIState::uiUpdate, this, &Sidebar::updateState);
|
||||
@@ -123,7 +122,6 @@ void SidebarSP::updateState(const UIStateSP &s) {
|
||||
setProperty("sunnylinkStatus", QVariant::fromValue(sunnylinkStatus));
|
||||
}
|
||||
|
||||
|
||||
void SidebarSP::DrawSidebar(QPainter &p){
|
||||
Sidebar::DrawSidebar(p);
|
||||
// metrics
|
||||
|
||||
@@ -28,8 +28,6 @@ Last updated: July 29, 2024
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QFrame>
|
||||
#include <QMap>
|
||||
#include "selfdrive/ui/qt/sidebar.h"
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
|
||||
@@ -25,7 +25,6 @@ Last updated: July 29, 2024
|
||||
***/
|
||||
|
||||
#pragma once
|
||||
#include "selfdrive/ui/ui.h"
|
||||
|
||||
const float DRIVING_PATH_WIDE = 0.9;
|
||||
const float DRIVING_PATH_NARROW = 0.25;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user