Merge branch 'lt' into lt

This commit is contained in:
Kumar
2024-08-06 21:42:26 -07:00
committed by GitHub
97 changed files with 22501 additions and 317 deletions
+11
View File
@@ -28,6 +28,9 @@ sunnypilot - 0.9.8.0 (2024-xx-xx)
* 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
@@ -45,6 +48,10 @@ 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)
@@ -82,6 +89,8 @@ 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
@@ -89,6 +98,8 @@ 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
+32 -3
View File
@@ -48,6 +48,7 @@ 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
@@ -114,12 +115,40 @@ 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
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
```
After running the command to install the desired branch, your comma device should reboot.
@@ -194,7 +223,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 sunnypilot completely when `OFF` **(strictly enforced in panda safety code)**
* `CRUISE (MAIN)` button disables ACC/SCC 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:
@@ -326,7 +355,7 @@ Example:
---
How-To instructions can be found in [HOW-TOS.md](HOW-TOS.md).
How-To instructions can be found in [HOW-TOS.md](https://github.com/sunnyhaibin/openpilot/blob/(!)README/HOW-TOS.md).
</details>
+2
View File
@@ -16,6 +16,7 @@ enum LongitudinalPersonalitySP {
moderate @1;
standard @2;
relaxed @3;
overtake @4;
}
enum AccelerationPersonality {
@@ -44,6 +45,7 @@ struct ControlsStateSP @0x81c2f05a394cf4af {
personality @8 :LongitudinalPersonalitySP;
dynamicPersonality @9 :Bool;
accelPersonality @10 :AccelerationPersonality;
overtakingAccelerationAssist @11 :Bool;
lateralControlState :union {
indiState @1 :LateralINDIState;
+7
View File
@@ -232,6 +232,7 @@ 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},
@@ -263,6 +264,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"HideVEgoUi", PERSISTENT | BACKUP},
{"HkgCustomLongTuning", PERSISTENT | BACKUP},
{"HkgSmoothStop", PERSISTENT | BACKUP},
{"HyundaiCruiseMainDefault", PERSISTENT | BACKUP},
{"HotspotOnBoot", PERSISTENT},
{"HotspotOnBootConfirmed", PERSISTENT},
{"LastCarModel", PERSISTENT | BACKUP},
@@ -281,6 +283,7 @@ 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},
@@ -291,8 +294,11 @@ 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},
@@ -317,6 +323,7 @@ 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},
{"ToyotaAutoHold", PERSISTENT | BACKUP},
+4
View File
@@ -0,0 +1,4 @@
third_party/libyuv/x86_64/**
third_party/snpe/x86_64/**
third_party/snpe/x86_64-linux-clang/**
third_party/acados/x86_64/**
+15
View File
@@ -0,0 +1,15 @@
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
+1 -1
View File
@@ -218,7 +218,7 @@ def create_gas_interceptor_command(packer, gas_amount, idx):
values["GAS_COMMAND"] = gas_amount * 255.
values["GAS_COMMAND2"] = gas_amount * 255.
dat = packer.make_can_msg("GAS_COMMAND", 0, values)[2]
dat = packer.make_can_msg("GAS_COMMAND", 0, values)[1]
checksum = crc8_pedal(dat[:-1])
values["CHECKSUM_PEDAL"] = checksum
+8 -2
View File
@@ -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
from openpilot.selfdrive.car.ford.values import CarControllerParams, FordFlags, FordFlagsSP
from openpilot.selfdrive.car.interfaces import CarControllerBase
LongCtrlState = car.CarControl.Actuators.LongControlState
@@ -35,6 +35,9 @@ 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 = []
@@ -74,7 +77,10 @@ class CarController(CarControllerBase):
# TODO: extended mode
mode = 1 if CC.latActive else 0
counter = (self.frame // CarControllerParams.STEER_STEP) % 0x10
can_sends.append(fordcan.create_lat_ctl2_msg(self.packer, self.CAN, mode, 0., 0., -apply_curvature, 0., counter))
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))
else:
can_sends.append(fordcan.create_lat_ctl_msg(self.packer, self.CAN, CC.latActive, 0., 0., -apply_curvature, 0.))
+20
View File
@@ -24,6 +24,7 @@ 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}
@@ -72,6 +73,10 @@ 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
@@ -129,6 +134,16 @@ 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 = [
@@ -185,6 +200,11 @@ 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),
+12 -2
View File
@@ -3,7 +3,8 @@ 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.selfdrive.car.ford.values import Ecu, FordFlags
from openpilot.common.params import Params
from openpilot.selfdrive.car.ford.values import Ecu, FordFlags, FordFlagsSP
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
ButtonType = car.CarState.ButtonEvent.Type
@@ -18,13 +19,15 @@ 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:
@@ -51,6 +54,13 @@ 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:
+64
View File
@@ -11,6 +11,7 @@ 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)
@@ -28,6 +29,9 @@ 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):
@@ -45,6 +49,10 @@ 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}")
@@ -68,11 +76,67 @@ 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]
+6 -1
View File
@@ -48,9 +48,14 @@ 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):
@@ -91,7 +96,7 @@ class FordPlatformConfig(PlatformConfig):
@dataclass
class FordCANFDPlatformConfig(FordPlatformConfig):
dbc_dict: DbcDict = field(default_factory=lambda: dbc_dict('ford_lincoln_base_pt', None))
dbc_dict: DbcDict = field(default_factory=lambda: dbc_dict('ford_lincoln_base_pt', RADAR.STEER_ASSIST_DATA))
def init(self):
super().init()
+190
View File
@@ -1,4 +1,6 @@
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
@@ -6,6 +8,7 @@ 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
@@ -37,6 +40,36 @@ 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
@@ -45,9 +78,40 @@ 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
@@ -148,6 +212,15 @@ 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:
@@ -161,3 +234,120 @@ 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
+6 -1
View File
@@ -119,6 +119,7 @@ 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
@@ -240,7 +241,7 @@ class CarInterface(CarInterfaceBase):
else:
self.CS.madsEnabled = False
if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0):
if not self.CP.pcmCruise or (self.CP.pcmCruise and self.CP.minEnableSpeed > 0) or not self.CP.pcmCruiseSpeed:
if any(b.type == ButtonType.cancel for b in self.CS.button_events):
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
if self.get_sp_pedal_disengage(ret):
@@ -281,6 +282,10 @@ class CarInterface(CarInterfaceBase):
if ret.vEgo < self.CP.minSteerSpeed and self.CS.madsEnabled:
events.add(EventName.belowSteerSpeed)
ret.customStockLong = self.CS.update_custom_stock_long(self.CC.cruise_button, self.CC.final_speed_kph,
self.CC.target_speed, self.CC.v_set_dis,
self.CC.speed_diff, self.CC.button_type)
ret.events = events.to_msg()
return ret
+20 -2
View File
@@ -62,7 +62,7 @@ class CarController(CarControllerBase):
self.lat_disengage_init = False
self.lat_active_last = False
sub_services = ['longitudinalPlanSP']
sub_services = ['longitudinalPlan', 'longitudinalPlanSP']
if CP.openpilotLongitudinalControl:
sub_services.append('radarState')
# TODO: Always true, prep for future conditional refactoring
@@ -94,7 +94,10 @@ class CarController(CarControllerBase):
self.v_tsc = 0
self.m_tsc = 0
self.steady_speed = 0
self.speeds = 0
self.v_target_plan = 0
self.hkg_can_smooth_stop = self.param_s.get_bool("HkgSmoothStop")
self.custom_stock_planner_speed = self.param_s.get_bool("CustomStockLongPlanner")
self.lead_distance = 0
self.jerk = 0.0
@@ -126,6 +129,10 @@ 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
@@ -135,14 +142,21 @@ 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,
@@ -203,7 +217,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, 0
addr, bus = 0x7d0, self.CAN.ECAN if self.CP.carFingerprint in CANFD_CAR else 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))
@@ -241,6 +255,8 @@ 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))
@@ -463,6 +479,8 @@ 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:
+11
View File
@@ -1171,6 +1171,17 @@ 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',
+15 -9
View File
@@ -172,6 +172,20 @@ 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
@@ -182,15 +196,7 @@ def create_adrv_messages(packer, CAN, frame):
}
ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values))
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))
ret.extend(create_fca_warning_light(packer, CAN, frame))
if frame % 5 == 0:
values = {
+19 -6
View File
@@ -91,7 +91,7 @@ class CarInterface(CarInterfaceBase):
# *** longitudinal control ***
if candidate in CANFD_CAR:
ret.experimentalLongitudinalAvailable = candidate not in (CANFD_UNSUPPORTED_LONGITUDINAL_CAR | CANFD_RADAR_SCC_CAR | NON_SCC_CAR)
ret.experimentalLongitudinalAvailable = candidate not in (CANFD_UNSUPPORTED_LONGITUDINAL_CAR | NON_SCC_CAR)
if ret.flags & HyundaiFlags.CANFD_CAMERA_SCC and not hda2:
ret.spFlags |= HyundaiFlagsSP.SP_CAMERA_SCC_LEAD.value
else:
@@ -102,12 +102,16 @@ class CarInterface(CarInterfaceBase):
ret.pcmCruise = not ret.openpilotLongitudinalControl
ret.stoppingControl = True
ret.startingState = True
ret.vEgoStarting = 0.1
ret.startAccel = 1.6
ret.vEgoStarting = 0.5
ret.startAccel = 1.0
ret.stopAccel = -1.0
ret.longitudinalActuatorDelay = 0.5
if ret.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV):
ret.startingState = False
else:
ret.startingState = True
if DBC[ret.carFingerprint]["radar"] is None:
if ret.spFlags & (HyundaiFlagsSP.SP_ENHANCED_SCC | HyundaiFlagsSP.SP_CAMERA_SCC_LEAD):
ret.radarUnavailable = False
@@ -118,6 +122,8 @@ 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]
@@ -143,6 +149,8 @@ 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
@@ -168,7 +176,8 @@ 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):
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):
ret.flags |= HyundaiFlags.ALT_LIMITS.value
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_ALT_LIMITS
@@ -187,7 +196,7 @@ class CarInterface(CarInterfaceBase):
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, 0
addr, bus = 0x7d0, CanBus(CP).ECAN if CP.carFingerprint in CANFD_CAR else 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')
@@ -203,6 +212,10 @@ class CarInterface(CarInterfaceBase):
enable_radar_tracks(logcan, sendcan, bus=0, addr=0x7d0, config_data_id=b'\x01\x42')
def _update(self, c):
if not self.CS.control_initialized:
can_cruise_main_default = self.CP.spFlags & HyundaiFlagsSP.SP_CAN_LFA_BTN and not self.CP.flags & HyundaiFlags.CANFD and self.CS.params_list.hyundai_cruise_main_default
self.CS.mainEnabled = True if can_cruise_main_default or self.CP.carFingerprint in CANFD_CAR else False
ret = self.CS.update(self.cp, self.cp_cam)
self.CS.button_events = [
+15 -7
View File
@@ -3,7 +3,7 @@ from dataclasses import dataclass, field
from enum import Enum, IntFlag
from cereal import car
from panda.python import uds
from panda.python import uds, Panda
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):
def __init__(self, CP, vEgoRaw=100.):
self.STEER_DELTA_UP = 3
self.STEER_DELTA_DOWN = 7
self.STEER_DRIVER_ALLOWANCE = 50
@@ -26,12 +26,13 @@ class CarControllerParams:
self.STEER_STEP = 1 # 100 Hz
if CP.carFingerprint in CANFD_CAR:
self.STEER_MAX = 270
self.STEER_DRIVER_ALLOWANCE = 250
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_DRIVER_MULTIPLIER = 2
self.STEER_THRESHOLD = 250
self.STEER_DELTA_UP = 2
self.STEER_DELTA_DOWN = 3
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
# 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.
@@ -108,6 +109,7 @@ 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):
@@ -574,6 +576,12 @@ 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),
+1 -1
View File
@@ -408,7 +408,7 @@ class CarInterfaceBase(ABC):
@staticmethod
def sp_configure_custom_torque_tune(ret, params):
ret.lateralTuning.torque.friction = float(params.get("TorqueFriction", encoding="utf8")) * 0.01
ret.lateralTuning.torque.friction = float(params.get("TorqueFriction", encoding="utf8")) * 0.001
ret.lateralTuning.torque.latAccelFactor = float(params.get("TorqueMaxLatAccel", encoding="utf8")) * 0.01
return ret
+2
View File
@@ -11,6 +11,7 @@ class ParamManager:
"experimental_mode": False,
"is_metric": False,
"last_speed_limit_sign_tap": False,
"hyundai_cruise_main_default": False,
"mads_main_toggle": False,
"pause_lateral_speed": 0,
"reverse_acc_change": False,
@@ -37,6 +38,7 @@ class ParamManager:
"experimental_mode": params.get_bool("ExperimentalMode"),
"is_metric": params.get_bool("IsMetric"),
"last_speed_limit_sign_tap": params.get_bool("LastSpeedLimitSignTap"),
"hyundai_cruise_main_default": params.get_bool("HyundaiCruiseMainDefault"),
"mads_main_toggle": params.get_bool("MadsCruiseMain"),
"pause_lateral_speed": int(params.get("PauseLateralSpeed", encoding="utf8")),
"reverse_acc_change": params.get_bool("ReverseAccChange"),
+1 -1
View File
@@ -21,7 +21,7 @@ class CarControllerParams:
self.STEER_DRIVER_FACTOR = 1 # from dbc
if CP.flags & SubaruFlags.GLOBAL_GEN2:
self.STEER_MAX = 1000
self.STEER_MAX = 1600
self.STEER_DELTA_UP = 40
self.STEER_DELTA_DOWN = 40
elif CP.carFingerprint == CAR.SUBARU_IMPREZA_2020:
+6
View File
@@ -29,6 +29,9 @@
"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",
@@ -38,6 +41,8 @@
"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",
@@ -101,6 +106,7 @@
"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",
+1 -1
View File
@@ -17,7 +17,6 @@ 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,
@@ -54,6 +53,7 @@ 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,6 +86,7 @@ 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"
+30 -5
View File
@@ -174,10 +174,13 @@ 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.custom_model_metadata = CustomModelMetadata(params=self.params, init_only=True)
@@ -185,6 +188,7 @@ 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.accel_personality = self.read_accel_personality_param()
@@ -489,7 +493,9 @@ class Controls:
def state_transition(self, CS):
"""Compute conditional state transitions and execute actions on state transitions"""
self.v_cruise_helper.update_v_cruise(CS, self.enabled_long, self.is_metric, self.reverse_acc_change, self.sm['longitudinalPlanSP'])
# 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'])
# decrement the soft disable timer at every step, as it's reset on
# entrance in SOFT_DISABLING state
@@ -638,9 +644,14 @@ class Controls:
self.LoC.reset()
if not self.joystick_mode:
speeds = long_plan.speeds
resume = False
if len(speeds):
resume = self.enabled_long and CS.standstill and speeds[-1] > 0.1 and self.CP.carName == "hyundai"
# 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)
actuators.accel = self.LoC.update(CC.longActive, CS, long_plan.aTarget, long_plan.shouldStop, pid_accel_limits, resume)
# Steering PID loop and lateral MPC
if self.model_use_lateral_planner:
@@ -806,11 +817,21 @@ class Controls:
# Curvature & Steering angle
lp = self.sm['liveParameters']
lp_mono_time_svs = 'lateralPlanDEPRECATED' if self.model_use_lateral_planner else 'modelV2'
dh = '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)
lc_svs = self.sm[dh]
long_plan = self.sm['longitudinalPlan'].hasLead
dm_state = self.sm['driverMonitoringState']
overtaking_accel_allowed = ((lc_svs.laneChangeDirection == LaneChangeDirection.right and dm_state.isRHD) or
(lc_svs.laneChangeDirection == LaneChangeDirection.left and not dm_state.isRHD)) and \
(lc_svs.laneChangeState in (LaneChangeState.preLaneChange, LaneChangeState.laneChangeStarting))
overtaking_accel_engaged = self.overtaking_accel and overtaking_accel_allowed and \
CS.vEgo > (60 * CV.KPH_TO_MS) if self.is_metric else (40 * CV.MPH_TO_MS) and long_plan.hasLead and \
long_plan.aTarget > -0.2 and not (CS.leftBlinker and CS.rightBlinker)
# controlsState
dat = messaging.new_message('controlsState')
dat.valid = CS.canValid
@@ -825,7 +846,7 @@ class Controls:
controlsState.alertSound = current_alert.audible_alert
controlsState.longitudinalPlanMonoTime = self.sm.logMonoTime['longitudinalPlan']
controlsState.lateralPlanMonoTime = self.sm.logMonoTime[lp_mono_time_svs]
controlsState.lateralPlanMonoTime = self.sm.logMonoTime[dh]
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
@@ -863,6 +884,7 @@ class Controls:
controlsStateSP.personality = self.personality
controlsStateSP.dynamicPersonality = self.dynamic_personality
controlsStateSP.accelPersonality = self.accel_personality
controlsStateSP.overtakingAccelerationAssist = overtaking_accel_engaged
if self.enable_nnff and lat_tuning == 'torque':
controlsStateSP.lateralControlState.torqueState = self.LaC.pid_long_sp
@@ -920,7 +942,8 @@ 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
self.experimental_mode = self.params.get_bool("ExperimentalMode") and (self.CP.openpilotLongitudinalControl or
(not self.CP.pcmCruiseSpeed and self.custom_stock_planner_speed))
self.personality = self.read_personality_param()
self.dynamic_personality = self.params.get_bool("DynamicPersonality")
self.accel_personality = self.read_accel_personality_param()
@@ -929,9 +952,11 @@ 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):
+35 -3
View File
@@ -65,6 +65,10 @@ 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
@@ -84,11 +88,16 @@ 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
@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, long_plan_sp):
def update_v_cruise(self, CS, enabled, is_metric, reverse_acc, sp_override_speed, long_plan_sp):
self.v_cruise_kph_last = self.v_cruise_kph
self.slc_state = long_plan_sp.speedLimitControlState
@@ -103,9 +112,28 @@ class VCruiseHelper:
self.v_cruise_cluster_kph = self.v_cruise_kph
self.update_button_timers(CS, enabled)
else:
self.v_cruise_kph = CS.cruiseState.speed * CV.MS_TO_KPH
self.v_cruise_cluster_kph = CS.cruiseState.speedCluster * CV.MS_TO_KPH
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
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
@@ -202,6 +230,8 @@ 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:
@@ -234,6 +264,8 @@ 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
+14 -3
View File
@@ -83,7 +83,8 @@ class LatControlTorque(LatControl):
self.torqued_override = self.param_s.get_bool("TorquedOverride")
self._frame = 0
self.use_lateral_jerk = False # TODO: make this a parameter in the UI
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
# Twilsonco's Lateral Neural Network Feedforward
self.use_nn = CI.has_lateral_torque_nn
@@ -140,11 +141,13 @@ 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.01
self.torque_params.friction = float(self.param_s.get("TorqueFriction", encoding="utf8")) * 0.001
@property
def pid_long_sp(self):
@@ -197,7 +200,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.use_steering_angle or lookahead_lateral_jerk == 0.0:
if self.nnff_no_lateral_jerk or 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
@@ -206,6 +209,7 @@ 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])
@@ -231,7 +235,14 @@ 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
+5 -5
View File
@@ -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):
should_stop, brake_pressed, cruise_standstill, resume):
# Ignore cruise standstill if car has a gas interceptor
cruise_standstill = cruise_standstill and not CP.enableGasInterceptorDEPRECATED
stopping_condition = should_stop
starting_condition = (not should_stop and
stopping_condition = should_stop and not resume
starting_condition = ((not should_stop or resume) 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):
def update(self, active, CS, a_target, should_stop, accel_limits, resume):
"""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)
CS.cruiseState.standstill, resume)
if self.long_control_state == LongCtrlState.off:
self.reset()
output_accel = 0.
@@ -3,8 +3,7 @@ import os
import time
import numpy as np
from cereal import custom
from openpilot.common.numpy_fast import clip, interp
from openpilot.common.conversions import Conversions as CV
from openpilot.common.numpy_fast import clip
from openpilot.common.realtime import DT_MDL
from openpilot.common.swaglog import cloudlog
# WARNING: imports outside of constants will not trigger a rebuild
@@ -67,6 +66,8 @@ def get_jerk_factor(personality=custom.LongitudinalPersonalitySP.standard):
return 0.8
elif personality==custom.LongitudinalPersonalitySP.aggressive:
return 0.65
elif personality==custom.LongitudinalPersonalitySP.overtake:
return 0.1
else:
raise NotImplementedError("Longitudinal personality not supported")
@@ -80,6 +81,8 @@ 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.5
else:
raise NotImplementedError("Longitudinal personality not supported")
@@ -101,61 +104,6 @@ def get_dynamic_personality(v_ego, personality=custom.LongitudinalPersonalitySP.
raise NotImplementedError("Dynamic personality not supported")
return np.interp(v_ego, x_vel, y_dist)
# multiplier for A_CHANGE_COST = 200.
def get_a_change_cost_multiplier(v_ego, v_lead0, v_lead1, personality=custom.LongitudinalPersonalitySP.standard):
if personality==custom.LongitudinalPersonalitySP.relaxed:
a_change_cost_multiplier_follow_distance = 1.0
elif personality==custom.LongitudinalPersonalitySP.standard:
a_change_cost_multiplier_follow_distance = 0.5
elif personality==custom.LongitudinalPersonalitySP.moderate:
a_change_cost_multiplier_follow_distance = 0.5
elif personality==custom.LongitudinalPersonalitySP.aggressive:
a_change_cost_multiplier_follow_distance = 0.1
else:
raise NotImplementedError("Longitudinal personality not supported")
# stolen from @KRKeegan
# values used for interpolation
# start with a small a_change_multiplier_values during interpolation to allow for faster change in accel
A_CHANGE_COST_MULTIPLIER_BP = [0., 10.] # vEgo, in m/s
A_CHANGE_COST_MULTIPLIER_V = [.05, 1.] # multiplier values
# when lead is pulling away, and speed is between 0 and 10 m/s, interpolate a_change_cost_multiplier_v_ego
a_change_cost_multiplier_v_ego = 1.
if (v_lead0 - v_ego > 1e-3) and (v_lead1 - v_ego > 1e-3):
a_change_cost_multiplier_v_ego = interp(v_ego, A_CHANGE_COST_MULTIPLIER_BP, A_CHANGE_COST_MULTIPLIER_V)
# get the minimum between a_change_multiplier based on driving personality, and a_change_multiplier based
# on v_ego
a_change_multiplier = min(a_change_cost_multiplier_follow_distance, a_change_cost_multiplier_v_ego)
# and pass it on as the final result
return a_change_multiplier
# multiplier for DANGER_ZONE_COST = 100.
def get_danger_zone_cost_multiplier(personality=custom.LongitudinalPersonalitySP.standard):
if personality==custom.LongitudinalPersonalitySP.relaxed:
return 1.6
elif personality==custom.LongitudinalPersonalitySP.standard:
return 1.3
elif personality==custom.LongitudinalPersonalitySP.moderate:
return 1.3
elif personality==custom.LongitudinalPersonalitySP.aggressive:
return 1.0
else:
raise NotImplementedError("Longitudinal personality not supported")
#def get_STOP_DISTANCE(personality=custom.LongitudinalPersonalitySP.standard):
# if personality==log.LongitudinalPersonality.relaxed:
# return 6.0
# elif personality==log.LongitudinalPersonality.standard:
# return 5.5
# elif personality==log.LongitudinalPersonality.aggressive:
# return 4.5
# else:
# raise NotImplementedError("dynamic stop distance not supported")
def get_stopped_equivalence_factor(v_lead):
return (v_lead**2) / (2 * COMFORT_BRAKE)
@@ -354,16 +302,12 @@ class LongitudinalMpc:
for i in range(N):
self.solver.cost_set(i, 'Zl', Zl)
def set_weights(self, prev_accel_constraint=True, v_lead0 = 0., v_lead1 = 0., personality=custom.LongitudinalPersonalitySP.standard):
v_ego = self.x0[1]
def set_weights(self, prev_accel_constraint=True, personality=custom.LongitudinalPersonalitySP.standard):
jerk_factor = get_jerk_factor(personality)
a_change_cost_multiplier = get_a_change_cost_multiplier(v_ego, v_lead0, v_lead1, personality)
danger_zone_cost_multiplier = get_danger_zone_cost_multiplier(personality)
if self.mode == 'acc':
a_change_cost = A_CHANGE_COST if prev_accel_constraint else 0
cost_weights = [X_EGO_OBSTACLE_COST, X_EGO_COST, V_EGO_COST, A_EGO_COST, jerk_factor * a_change_cost_multiplier \
* a_change_cost, jerk_factor * J_EGO_COST]
constraint_cost_weights = [LIMIT_COST, LIMIT_COST, LIMIT_COST, DANGER_ZONE_COST * danger_zone_cost_multiplier]
cost_weights = [X_EGO_OBSTACLE_COST, X_EGO_COST, V_EGO_COST, A_EGO_COST, jerk_factor * a_change_cost, jerk_factor * J_EGO_COST]
constraint_cost_weights = [LIMIT_COST, LIMIT_COST, LIMIT_COST, DANGER_ZONE_COST]
elif self.mode == 'blended':
a_change_cost = 40.0 if prev_accel_constraint else 0
cost_weights = [0., 0.1, 0.2, 5.0, a_change_cost, 1.0]
@@ -417,16 +361,16 @@ class LongitudinalMpc:
self.cruise_min_a = min_a
self.max_a = max_a
def update(self, radarstate, v_cruise, prev_accel_constraint, x, v, a, j, personality=custom.LongitudinalPersonalitySP.standard, dynamic_personality=False):
def update(self, radarstate, v_cruise, x, v, a, j, personality=custom.LongitudinalPersonalitySP.standard,
dynamic_personality=False, overtaking_acceleration_assist=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)
lead_xv_1 = self.process_lead(radarstate.leadTwo)
self.set_weights(prev_accel_constraint=prev_accel_constraint, v_lead0=lead_xv_0[0, 1], v_lead1=lead_xv_1[0, 1], personality=personality)
# To estimate a safe distance from a moving lead, we calculate how much stopping
# distance that lead needs as a minimum. We can add that to the current distance
# and then treat that as a stopped car/obstacle at this new distance.
@@ -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, custom
from cereal import car, log, custom
import cereal.messaging as messaging
from openpilot.common.conversions import Conversions as CV
@@ -83,7 +83,8 @@ class LongitudinalPlanner:
self.dt = dt
self.a_desired = init_a
self.v_desired_filter = FirstOrderFilter(init_v, 2.0, self.dt)
v_ego_sec = 0.6 if CP.carName == "hyundai" else 2.0
self.v_desired_filter = FirstOrderFilter(init_v, v_ego_sec, self.dt)
self.v_model_error = 0.0
self.v_desired_trajectory = np.zeros(CONTROL_N)
@@ -157,8 +158,10 @@ 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=sm['controlsStateSP'].accelPersonality):
if self.accel_controller.is_enabled(accel_personality=custom.AccelerationPersonality.sport if overtaking_accel_engaged else
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':
@@ -193,11 +196,12 @@ 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=sm['controlsStateSP'].personality)
self.mpc.set_weights(prev_accel_constraint, personality=custom.LongitudinalPersonalitySP.overtake if overtaking_accel_engaged else 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, prev_accel_constraint, x, v, a, j, personality=sm['controlsStateSP'].personality, dynamic_personality=sm['controlsStateSP'].dynamicPersonality)
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.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)
+1 -1
View File
@@ -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'] + lateral_planner_svs,
'liveMapDataSP', 'e2eLongStateSP', 'controlsStateSP', 'driverMonitoringState'] + lateral_planner_svs,
poll='modelV2', ignore_avg_freq=['radarState'])
while True:
+1 -1
View File
@@ -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.01
self.offline_friction = float(params.get("TorqueFriction", encoding="utf8")) * 0.001
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)
+1 -1
View File
@@ -145,4 +145,4 @@ void HttpRequest::requestFinished() {
QNetworkAccessManager *HttpRequest::nam() {
static QNetworkAccessManager *networkAccessManager = new QNetworkAccessManager(qApp);
return networkAccessManager;
}
}
+2 -2
View File
@@ -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();
};
};
+2 -1
View File
@@ -86,7 +86,8 @@ void HomeWindow::mousePressEvent(QMouseEvent* e) {
}
void HomeWindow::mouseDoubleClickEvent(QMouseEvent* e) {
HomeWindow::mousePressEvent(e);
// By removing the static call to HomeWindow::mousePressEvent, we can now rely on child classes to handle the event
mousePressEvent(e);
const SubMaster &sm = *(uiState()->sm);
if (sm["carParams"].getCarParams().getNotCar()) {
if (onroad->isVisible()) {
+2 -2
View File
@@ -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);
};
};
+1 -1
View File
@@ -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
+1
View File
@@ -91,6 +91,7 @@ protected:
virtual void updateToggles();
};
class SoftwarePanel : public ListWidget {
Q_OBJECT
public:
+3 -3
View File
@@ -26,7 +26,7 @@
void SoftwarePanel::checkForUpdates() {
std::system("pkill -SIGUSR1 -f system.updated.updated");
std::system("pkill -SIGUSR1 -f 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 system.updated.updated");
std::system("pkill -SIGHUP -f updated");
}
});
addItem(downloadBtn);
@@ -162,4 +162,4 @@ void SoftwarePanel::updateLabels() {
installBtn->setDescription(QString::fromStdString(params.get("UpdaterNewReleaseNotes")));
update();
}
}
+1
View File
@@ -2,6 +2,7 @@
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QVBoxLayout>
#include "selfdrive/ui/qt/offroad/experimental_mode.h"
#include "selfdrive/ui/qt/util.h"
+7
View File
@@ -1,12 +1,19 @@
#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"
+1 -1
View File
@@ -385,4 +385,4 @@ void AnnotatedCameraWidget::showEvent(QShowEvent *event) {
ui_update_params(uiState());
prev_draw_t = millis_since_boot();
}
}
+1 -1
View File
@@ -50,4 +50,4 @@ protected:
double prev_draw_t = 0;
FirstOrderFilter fps_filter;
};
};
+2 -1
View File
@@ -26,7 +26,8 @@ ExperimentalButton::ExperimentalButton(QWidget *parent) : experimental_mode(fals
void ExperimentalButton::changeMode() {
const auto cp = (*uiState()->sm)["carParams"].getCarParams();
bool can_change = hasLongitudinalControl(cp) && params.getBool("ExperimentalModeConfirmed");
bool can_change = (hasLongitudinalControl(cp) || (!cp.getPcmCruiseSpeed() && params.getBool("CustomStockLongPlanner")))
&& params.getBool("ExperimentalModeConfirmed");
if (can_change) {
params.putBool("ExperimentalMode", !experimental_mode);
}
+1 -1
View File
@@ -31,4 +31,4 @@ private:
QPixmap experimental_img;
};
void drawIcon(QPainter &p, const QPoint &center, const QPixmap &img, const QBrush &bg, float opacity);
void drawIcon(QPainter &p, const QPoint &center, const QPixmap &img, const QBrush &bg, float opacity);
+1 -1
View File
@@ -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));
}
}
+1 -1
View File
@@ -26,4 +26,4 @@ protected:
protected slots:
virtual void offroadTransition(bool offroad);
virtual void updateState(const UIState &s);
};
};
+1 -1
View File
@@ -20,4 +20,4 @@ private:
Params params;
QTimer *timer;
QString prevResp;
};
};
+1 -1
View File
@@ -65,4 +65,4 @@ protected:
private:
std::unique_ptr<PubMaster> pm;
};
};
+1 -1
View File
@@ -61,4 +61,4 @@ int main(int argc, char *argv[]) {
)");
return a.exec();
}
}
+1 -1
View File
@@ -59,4 +59,4 @@ private:
QFileSystemWatcher *watcher;
QHash<QString, QString> params_hash;
Params params;
};
};
+1 -1
View File
@@ -35,4 +35,4 @@ private:
void refresh();
void getUserKeys(const QString &username);
};
};
+1 -1
View File
@@ -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",
]
+1
View File
@@ -33,6 +33,7 @@ Last updated: July 29, 2024
#include <QApplication>
#include <QJsonDocument>
#include <memory>
#include <string>
#include <common/swaglog.h>
+5
View File
@@ -26,6 +26,11 @@ 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"
+3
View File
@@ -28,10 +28,13 @@ 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){
+6
View File
@@ -27,9 +27,14 @@ 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"
@@ -37,6 +42,7 @@ 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,6 +30,7 @@ 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,9 +28,11 @@ 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
@@ -57,6 +57,12 @@ 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"),
@@ -223,6 +229,7 @@ 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>"
@@ -261,16 +268,22 @@ 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(false);
long_personality_setting->setEnabled(false);
accel_personality_setting->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");
}
params.remove("ExperimentalLongitudinalEnabled");
params.remove("ExperimentalMode");
} else {
// no long for now
experimental_mode_toggle->setEnabled(false);
@@ -295,6 +308,7 @@ 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");
}
@@ -302,6 +316,7 @@ 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 {
@@ -310,6 +325,7 @@ void TogglesPanelSP::updateToggles() {
custom_stock_long_toggle->setVisible(false);
dec_toggle->setVisible(false);
dynamic_personality_toggle->setVisible(false);
custom_stock_long_planner->setVisible(false);
}
}
@@ -49,6 +49,12 @@ 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 Smart Cruise Control is operating."),
"../assets/offroad/icon_blank.png",
},
{
"EnableSlc",
tr("Speed Limit Control (SLC)"),
@@ -91,12 +97,24 @@ 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"),
@@ -298,7 +316,7 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) {
list->addItem(dlp_settings);
}
if (param == "VisionCurveLaneless") {
if (param == "OvertakingAccelerationAssist") {
list->addItem(laneChangeSettingsLayout);
list->addItem(horizontal_line());
@@ -345,6 +363,17 @@ 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()) {
@@ -366,6 +395,7 @@ 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) {
@@ -577,7 +607,7 @@ void SunnypilotPanel::updateToggles() {
}
// toggle names to update when EnforceTorqueLateral is flipped
std::vector<std::string> torqueLateralGroup{"CustomTorqueLateral", "LiveTorque", "LiveTorqueRelaxed", "TorquedOverride"};
std::vector<std::string> torqueLateralGroup{"CustomTorqueLateral", "TorqueLateralJerk", "LiveTorque", "LiveTorqueRelaxed", "TorquedOverride"};
for (const auto& torqueLateralToggle : torqueLateralGroup) {
if (toggles.find(torqueLateralToggle) != toggles.end()) {
if (nnff_toggle->isToggled()) {
@@ -594,6 +624,24 @@ 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());
@@ -622,13 +670,14 @@ 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, 50}) {
{0, 500},
5) {
refresh();
}
void TorqueFriction::refresh() {
float torqueFrictionVal = QString::fromStdString(params.get("TorqueFriction")).toInt() * 0.01;
float torqueFrictionVal = QString::fromStdString(params.get("TorqueFriction")).toInt() * 0.001;
setTitle("FRICTION - " + (params.getBool("TorquedOverride") ? tr("Real-time and Offline") : tr("Offline Only")));
setLabel(QString::number(torqueFrictionVal));
}
@@ -29,6 +29,7 @@ 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"
@@ -110,6 +110,13 @@ SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(VehiclePanel *parent) : ListWidge
hkgCustomLongTuning->setConfirmation(true, false);
addItem(hkgCustomLongTuning);
hyundaiCruiseMainDefault = new ParamControlSP(
"HyundaiCruiseMainDefault",
tr("HKG CAN: Enable Cruise Main By Default"),
tr("Enabling this toggle sets CRUISE MAIN to ON by default when the car starts, without engaging MADS. The user still needs to manually engage MADS"),
"../assets/offroad/icon_blank.png");
addItem(hyundaiCruiseMainDefault);
// Subaru
addItem(new LabelControlSP(tr("Subaru")));
auto subaruManualParkingBrakeSng = new ParamControlSP(
@@ -207,6 +214,7 @@ SPVehiclesTogglesPanel::SPVehiclesTogglesPanel(VehiclePanel *parent) : ListWidge
connect(uiStateSP(), &UIStateSP::offroadTransition, [=](bool offroad) {
is_onroad = !offroad;
hkgCustomLongTuning->setEnabled(offroad);
hyundaiCruiseMainDefault->setEnabled(offroad);
toyotaTss2LongTune->setEnabled(offroad);
toyotaAbh->setEnabled(offroad);
toyotaEnhancedBsm->setEnabled(offroad);
@@ -237,6 +245,17 @@ void SPVehiclesTogglesPanel::updateToggles() {
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size()));
cereal::CarParams::Reader CP = cmsg.getRoot<cereal::CarParams>();
// Hyundai/Kia/Genesis
{
if (CP.getCarName() == "hyundai") {
if ((CP.getSpFlags() & 2) and !(CP.getFlags() & 8192)) {
hyundaiCruiseMainDefault->setEnabled(true);
} else {
hyundaiCruiseMainDefault->setEnabled(false);
}
}
}
// Toyota: Enhanced Blind Spot Monitor
{
if (CP.getCarName() == "toyota") {
@@ -28,8 +28,10 @@ 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
@@ -67,6 +69,7 @@ private:
Params params;
bool is_onroad = false;
ParamControlSP *hyundaiCruiseMainDefault;
ParamControlSP *stockLongToyota;
ParamControlSP *toyotaEnhancedBsm;
@@ -30,6 +30,7 @@ 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,6 +31,7 @@ Last updated: July 29, 2024
#include "selfdrive/ui/qt/maps/map_settings.h"
#endif
class OffroadHomeSP : public OffroadHome {
Q_OBJECT
@@ -1290,46 +1290,25 @@ 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;
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%
if (accel > 0) {
p.setBrush(QColor(0, 245, 0, 200));
}
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);
scannerRect = QRect(0, widgetHeight / 2 - halfHeightAbs, scannerWidth, halfHeightAbs);
} else {
QRect ra = QRect(rect_w - wp, rect_h / 2, wp, hha / 2);
p.drawRect(ra);
p.setBrush(QColor(245, 0, 0, 200));
scannerRect = QRect(0, widgetHeight / 2, scannerWidth, halfHeightAbs);
}
p.drawRect(scannerRect);
}
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();
@@ -26,6 +26,8 @@ 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,6 +29,9 @@ 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
@@ -59,6 +62,7 @@ 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);
bool can_change = hasLongitudinalControl(cp) || (!cp.getPcmCruiseSpeed() && params.getBool("CustomStockLongPlanner"));
if (can_change) {
scene.dynamic_experimental_control = !scene.dynamic_experimental_control;
params.putBool("DynamicExperimentalControl", scene.dynamic_experimental_control);
@@ -26,6 +26,7 @@ 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"
+2
View File
@@ -34,6 +34,7 @@ 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);
@@ -122,6 +123,7 @@ void SidebarSP::updateState(const UIStateSP &s) {
setProperty("sunnylinkStatus", QVariant::fromValue(sunnylinkStatus));
}
void SidebarSP::DrawSidebar(QPainter &p){
Sidebar::DrawSidebar(p);
// metrics
+2
View File
@@ -28,6 +28,8 @@ Last updated: July 29, 2024
#include <memory>
#include <QFrame>
#include <QMap>
#include "selfdrive/ui/qt/sidebar.h"
#include "selfdrive/ui/sunnypilot/ui.h"
+1
View File
@@ -25,6 +25,7 @@ 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;
@@ -31,6 +31,13 @@ Last updated: July 29, 2024
#include <string>
#include <vector>
#include <QButtonGroup>
#include <QFrame>
#include <QHBoxLayout>
#include <QLabel>
#include <QPainter>
#include <QPushButton>
#include "common/params.h"
#include "selfdrive/ui/qt/widgets/controls.h"
#include "selfdrive/ui/qt/widgets/input.h"
@@ -36,6 +36,7 @@ Last updated: July 29, 2024
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/software_settings.h"
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_settings.h"
inline void ReplaceWidget(QWidget* old_widget, QWidget* new_widget) {
if (old_widget && old_widget->parentWidget() && old_widget->parentWidget()->layout()) {
old_widget->parentWidget()->layout()->replaceWidget(old_widget, new_widget);
+1
View File
@@ -34,6 +34,7 @@ Last updated: July 29, 2024
#include "common/transformations/orientation.hpp"
#include "common/params.h"
#include "common/swaglog.h"
#include "common/util.h"
#include "common/watchdog.h"
#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h"
+2
View File
@@ -33,9 +33,11 @@ Last updated: July 29, 2024
#include "selfdrive/ui/ui.h"
#include "cereal/messaging/messaging.h"
#include "common/timing.h"
#include "qt/network/sunnylink/models/role_model.h"
#include "qt/network/sunnylink/models/sponsor_role_model.h"
#include "qt/network/sunnylink/models/user_model.h"
#include "selfdrive/ui/sunnypilot/qt/ui_scene.h"
#include "system/hardware/hw.h"
const int UI_ROAD_NAME_MARGIN_X = 14;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+56 -8
View File
@@ -207,6 +207,14 @@
<source>LIMIT</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>blended</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>acc</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>AutoLaneChangeTimer</name>
@@ -1445,14 +1453,6 @@ Esto puede tardar un minuto.</translation>
<source>Hyundai/Kia/Genesis</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>HKG CAN: Smoother Stopping Performance (Beta)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Smoother stopping behind a stopped car or desired stopping event. This is only applicable to HKG CAN platforms using openpilot longitudinal control.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Subaru</source>
<translation type="unfinished"></translation>
@@ -1563,6 +1563,34 @@ Reboot Required.</source>
<source>Tested on RAV4 TSS1, Lexus LSS1, Toyota TSS1/1.5, and Prius TSS2.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>HKG CAN: Enable Cruise Main By Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enabling this toggle sets CRUISE MAIN to ON by default when the car starts, without engaging MADS. The user still needs to manually engage MADS</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>HKG: Custom Tuning for New Longitudinal API</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable Automatic Brake Hold (AHB)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WARNING: Only for Toyota/Lexus vehicles with TSS2/LSS2. USE AT YOUR OWN RISK.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Changing this setting takes effect when the car is powered off.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsWindow</name>
@@ -2669,6 +2697,22 @@ Reboot Required.</source>
<source>Default is Laneless. In Auto mode, sunnnypilot dynamically chooses between Laneline or Laneless model based on lane recognition confidence level on road and certain conditions.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>NNLC: Remove Lateral Jerk Response (Alpha)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>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.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Lateral Jerk with Torque Lateral Control (Alpha)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>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.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TermsPage</name>
@@ -3034,6 +3078,10 @@ This feature must be used along with SLC, and/or V-TSC, and/or M-TSC.</source>
<source>Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use Planner Speed</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TorqueFriction</name>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -59,6 +59,8 @@ typedef enum UIStatus {
EXTRA_UI_STATES
} UIStatus;
enum PrimeType {
UNKNOWN = -2,
UNPAIRED = -1,
@@ -152,7 +154,7 @@ protected:
QTimer *timer;
PrimeType prime_type = PrimeType::UNKNOWN;
private:
private:
bool started_prev = false;
};
#undef UIScene
+6 -3
View File
@@ -5,6 +5,7 @@ from __future__ import annotations
import base64
import gzip
import os
import ssl
import threading
import time
@@ -29,7 +30,8 @@ SUNNYLINK_RECONNECT_TIMEOUT_S = 70 # FYI changing this will also would require
DISALLOW_LOG_UPLOAD = threading.Event()
params = Params()
sunnylink_api = SunnylinkApi(params.get("SunnylinkDongleId", encoding='utf-8'))
sunnylink_dongle_id = params.get("SunnylinkDongleId", encoding='utf-8')
sunnylink_api = SunnylinkApi(sunnylink_dongle_id)
def handle_long_poll(ws: WebSocket, exit_event: threading.Event | None) -> None:
cloudlog.info("sunnylinkd.handle_long_poll started")
sm = messaging.SubMaster(['deviceState'])
@@ -204,7 +206,7 @@ def main(exit_event: threading.Event = None):
UploadQueueCache.initialize(upload_queue)
ws_uri = SUNNYLINK_ATHENA_HOST
ws_uri = f"{SUNNYLINK_ATHENA_HOST}"
conn_start = None
conn_retries = 0
while (exit_event is None or not exit_event.is_set()) and sunnylink_ready(params):
@@ -214,8 +216,9 @@ def main(exit_event: threading.Event = None):
cloudlog.event("sunnylinkd.main.connecting_ws", ws_uri=ws_uri, retries=conn_retries)
ws = create_connection(ws_uri,
cookie="jwt=" + sunnylink_api.get_token(),
header={"Authorization": f"Bearer {sunnylink_api.get_token()}"},
enable_multithread=True,
sslopt={"cert_reqs": ssl.CERT_NONE if "localhost" in ws_uri else ssl.CERT_REQUIRED},
timeout=SUNNYLINK_RECONNECT_TIMEOUT_S)
cloudlog.event("sunnylinkd.main.connected_ws", ws_uri=ws_uri, retries=conn_retries,
duration=time.monotonic() - conn_start)
+6 -2
View File
@@ -147,15 +147,19 @@ int main(int argc, char* argv[]) {
ret = util::set_core_affinity({3});
assert(ret == 0);
}
bool no_dcam = Params().getBool("DriverCameraHardwareMissing");
if (argc > 1) {
std::string arg1(argv[1]);
if (arg1 == "--stream") {
encoderd_thread(stream_cameras_logged);
encoderd_thread(no_dcam ? stream_cameras_logged_no_dcam :
stream_cameras_logged);
} else {
LOGE("Argument '%s' is not supported", arg1.c_str());
}
} else {
encoderd_thread(cameras_logged);
encoderd_thread(no_dcam ? cameras_logged_no_dcam :
cameras_logged);
}
return 0;
}
+2 -1
View File
@@ -234,8 +234,9 @@ void loggerd_thread() {
logger_rotate(&s);
Params().put("CurrentRoute", s.logger.routeName());
bool no_dcam = Params().getBool("DriverCameraHardwareMissing");
std::map<std::string, EncoderInfo> encoder_infos_dict;
for (const auto &cam : cameras_logged) {
for (const auto &cam : (no_dcam ? cameras_logged_no_dcam : cameras_logged)) {
for (const auto &encoder_info : cam.encoder_infos) {
encoder_infos_dict[encoder_info.publish_name] = encoder_info;
s.max_waiting++;
+3
View File
@@ -154,3 +154,6 @@ const LogCameraInfo stream_driver_camera_info{
const LogCameraInfo cameras_logged[] = {road_camera_info, wide_road_camera_info, driver_camera_info};
const LogCameraInfo stream_cameras_logged[] = {stream_road_camera_info, stream_wide_road_camera_info, stream_driver_camera_info};
const LogCameraInfo cameras_logged_no_dcam[] = {road_camera_info, wide_road_camera_info, driver_camera_info};
const LogCameraInfo stream_cameras_logged_no_dcam[] = {stream_road_camera_info, stream_wide_road_camera_info, stream_driver_camera_info};
+4 -1
View File
@@ -71,6 +71,7 @@ def manager_init() -> None:
("FeatureStatus", "1"),
("HandsOnWheelMonitoring", "0"),
("HasAcceptedTermsSP", "0"),
("HyundaiCruiseMainDefault", "0"),
("HideVEgoUi", "0"),
("LastSpeedLimitSignTap", "0"),
("LkasToggle", "0"),
@@ -84,6 +85,8 @@ def manager_init() -> None:
("OnroadSettings", "1"),
("PathOffset", "0"),
("PauseLateralSpeed", "0"),
("PCMVCruiseOverride", "0"),
("PCMVCruiseOverrideSpeed", "30"),
("ReverseAccChange", "0"),
("ScreenRecorder", "1"),
("ShowDebugUI", "1"),
@@ -97,7 +100,7 @@ def manager_init() -> None:
("StandStillTimer", "0"),
("StockLongToyota", "0"),
("TorqueDeadzoneDeg", "0"),
("TorqueFriction", "1"),
("TorqueFriction", "10"),
("TorqueMaxLatAccel", "250"),
("ToyotaAutoHold", "0"),
("ToyotaAutoLockBySpeed", "0"),
+1 -1
View File
@@ -102,7 +102,7 @@ procs = [
PythonProcess("radard", "selfdrive.controls.radard", only_onroad),
PythonProcess("hardwared", "system.hardware.hardwared", always_run),
PythonProcess("tombstoned", "system.tombstoned", always_run, enabled=not PC),
PythonProcess("updated", "system.updated.updated", only_offroad, enabled=not PC),
NativeProcess("updated", "system/updated", ["./updated.py"], only_offroad, enabled=not PC),
PythonProcess("uploader", "system.loggerd.uploader", always_run),
PythonProcess("statsd", "system.statsd", always_run),