Merge branch 'master-priv' into nnlc-lateral-jerk

This commit is contained in:
Jason Wen
2024-05-17 13:17:08 -04:00
27 changed files with 151 additions and 99 deletions
+7 -1
View File
@@ -24,6 +24,12 @@ sunnypilot - 0.9.7.0 (2024-05-xx)
* comma Prime support
* Personal Mapbox/Amap/Google Maps token support
* Instructions on how to set up your iOS Siri Shortcuts: https://routinehub.co/shortcut/17677/
* NEW❗: Forced Offroad mode
* 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
* 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
* RE-ENABLED: Map-based Turn Speed Control (M-TSC) for supported platforms
* openpilot Longitudianl Control available cars
* Custom Stock Longitudinal Control available cars
@@ -41,7 +47,7 @@ sunnypilot - 0.9.7.0 (2024-05-xx)
* UPDATED: Neural Network Lateral Control (NNLC)
* FIXED: Hotfix for "lazy" steering performance in tighter curves thanks to twilsonco!
* Due to upstream changes with platform simplifications, most platforms will match and fallback to combined platform model
* This will be updated when the new mapping of platforms are restructured (thanks @twilsconso 😉)
* This will be updated when the new mapping of platforms are restructured (thanks @twilsonco 😉)
* UI Updates
* Display Metrics Below Chevron
* NEW❗: Metrics is now being displayed below the chevron instead of above
+2
View File
@@ -255,6 +255,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"EnhancedScc", PERSISTENT | BACKUP},
{"FeatureStatus", PERSISTENT | BACKUP},
{"FleetManagerPin", PERSISTENT},
{"ForceOffroad", CLEAR_ON_MANAGER_START},
{"GmapKey", PERSISTENT | BACKUP},
{"HandsOnWheelMonitoring", PERSISTENT | BACKUP},
{"HideVEgoUi", PERSISTENT | BACKUP},
@@ -324,6 +325,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"VisionCurveLaneless", PERSISTENT | BACKUP},
{"VwAccType", PERSISTENT | BACKUP},
{"VwCCOnly", PERSISTENT | BACKUP},
{"Offroad_ForceStatus", CLEAR_ON_MANAGER_START},
{"Offroad_SupersededUpdate", PERSISTENT},
{"SunnylinkCache_Users", PERSISTENT},
+3 -3
View File
@@ -229,7 +229,7 @@ void can_recv_thread(std::vector<Panda *> pandas) {
}
}
std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *> &pandas, bool spoofing_started) {
std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *> &pandas, bool spoofing_started, Params &params) {
bool ignition_local = false;
const uint32_t pandas_cnt = pandas.size();
@@ -277,7 +277,7 @@ std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *>
health.ignition_line_pkt = 0;
}
ignition_local |= ((health.ignition_line_pkt != 0) || (health.ignition_can_pkt != 0));
ignition_local |= ((health.ignition_line_pkt != 0) || (health.ignition_can_pkt != 0)) && !params.getBool("ForceOffroad");
pandaStates.push_back(health);
}
@@ -432,7 +432,7 @@ void panda_state_thread(std::vector<Panda *> pandas, bool spoofing_started) {
send_peripheral_state(&pm, peripheral_panda);
}
auto ignition_opt = send_panda_states(&pm, pandas, spoofing_started);
auto ignition_opt = send_panda_states(&pm, pandas, spoofing_started, params);
if (!ignition_opt) {
LOGE("Failed to get ignition_opt");
+1 -1
View File
@@ -141,7 +141,7 @@ class CarInterface(CarInterfaceBase):
self.CS.accEnabled = False
self.CS.accEnabled = ret.cruiseState.enabled or self.CS.accEnabled
ret, self.CS = self.get_sp_common_state(ret, self.CS)
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.distance_button))
# MADS BUTTON
if self.CS.out.madsEnabled != self.CS.madsEnabled:
+1 -1
View File
@@ -104,7 +104,7 @@ class CarInterface(CarInterfaceBase):
self.CS.accEnabled = False
self.CS.accEnabled = ret.cruiseState.enabled or self.CS.accEnabled
ret, self.CS = self.get_sp_common_state(ret, self.CS)
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.distance_button))
if self.CS.out.madsEnabled != self.CS.madsEnabled:
if self.mads_event_lock:
+1 -1
View File
@@ -251,7 +251,7 @@ class CarInterface(CarInterfaceBase):
self.CS.accEnabled = False
self.CS.accEnabled = ret.cruiseState.enabled or self.CS.accEnabled
ret, self.CS = self.get_sp_common_state(ret, self.CS)
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(distance_button))
# MADS BUTTON
if self.CS.out.madsEnabled != self.CS.madsEnabled:
+9 -9
View File
@@ -28,7 +28,7 @@ def get_can_messages(CP, gearbox_msg):
("STEER_MOTOR_TORQUE", 0), # TODO: not on every car
]
if CP.carFingerprint in (SERIAL_STEERING | (CAR.HONDA_ODYSSEY_CHN, )):
if CP.carFingerprint in (SERIAL_STEERING | {CAR.HONDA_ODYSSEY_CHN, }):
messages += [
("SCM_FEEDBACK", 25),
("SCM_BUTTONS", 50),
@@ -58,7 +58,7 @@ def get_can_messages(CP, gearbox_msg):
("ACC_CONTROL", 50),
]
else: # Nidec signals
if CP.carFingerprint in (SERIAL_STEERING | (CAR.HONDA_ODYSSEY_CHN, )):
if CP.carFingerprint in (SERIAL_STEERING | {CAR.HONDA_ODYSSEY_CHN, }):
messages.append(("CRUISE_PARAMS", 10))
else:
messages.append(("CRUISE_PARAMS", 50))
@@ -78,7 +78,7 @@ def get_can_messages(CP, gearbox_msg):
if CP.carFingerprint in HONDA_BOSCH_RADARLESS:
messages.append(("CRUISE_FAULT_STATUS", 50))
elif CP.carFingerprint == CAR.CLARITY:
elif CP.carFingerprint == CAR.HONDA_CLARITY:
messages.append(("BRAKE_ERROR", 100)),
elif CP.openpilotLongitudinalControl:
messages.append(("STANDSTILL", 50))
@@ -150,7 +150,7 @@ class CarState(CarStateBase):
if self.CP.carFingerprint in HONDA_BOSCH_RADARLESS:
ret.accFaulted = bool(cp.vl["CRUISE_FAULT_STATUS"]["CRUISE_FAULT"])
elif self.CP.carFingerprint == CAR.CLARITY:
elif self.CP.carFingerprint == CAR.HONDA_CLARITY:
ret.accFaulted = bool(cp.vl["BRAKE_ERROR"]["BRAKE_ERROR_1"] or cp.vl["BRAKE_ERROR"]["BRAKE_ERROR_2"])
else:
# On some cars, these two signals are always 1, this flag is masking a bug in release
@@ -250,12 +250,12 @@ class CarState(CarStateBase):
if ret.brake > 0.1:
ret.brakePressed = True
if self.CP.carFingerprint in (CAR.CIVIC, CAR.ODYSSEY, CAR.ODYSSEY_CHN, CAR.CRV_5G, CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH,
CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E):
if self.CP.carFingerprint in (CAR.HONDA_CIVIC, CAR.HONDA_ODYSSEY, CAR.HONDA_ODYSSEY_CHN, CAR.HONDA_CRV_5G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC_BOSCH,
CAR.HONDA_CIVIC_BOSCH_DIESEL, CAR.HONDA_CRV_HYBRID, CAR.ACURA_RDX_3G, CAR.HONDA_E):
ret.brakeLightsDEPRECATED = bool(cp.vl["ACC_CONTROL"]['BRAKE_LIGHTS'] != 0 or ret.brake > 0.4) if not self.CP.openpilotLongitudinalControl else \
bool(ret.brake > 0.4)
elif self.CP.carFingerprint in HONDA_BOSCH and self.CP.carFingerprint not in (CAR.CIVIC, CAR.ODYSSEY, CAR.ODYSSEY_CHN, CAR.CRV_5G, CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH,
CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E) and self.CP.carFingerprint not in HONDA_BOSCH_RADARLESS:
elif self.CP.carFingerprint in HONDA_BOSCH and self.CP.carFingerprint not in (CAR.HONDA_CIVIC, CAR.HONDA_ODYSSEY, CAR.HONDA_ODYSSEY_CHN, CAR.HONDA_CRV_5G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC_BOSCH,
CAR.HONDA_CIVIC_BOSCH_DIESEL, CAR.HONDA_CRV_HYBRID, CAR.ACURA_RDX_3G, CAR.HONDA_E) and self.CP.carFingerprint not in HONDA_BOSCH_RADARLESS:
ret.brakeLightsDEPRECATED = bool(cp.vl["ACC_CONTROL"]['BRAKE_LIGHTS'] != 0 or ret.brake > 0.4) if not self.CP.openpilotLongitudinalControl else \
bool(ret.brake > 0.4)
@@ -264,7 +264,7 @@ class CarState(CarStateBase):
if self.CP.carFingerprint not in HONDA_BOSCH_RADARLESS:
ret.stockAeb = (not self.CP.openpilotLongitudinalControl) and bool(cp.vl["ACC_CONTROL"]["AEB_STATUS"] and cp.vl["ACC_CONTROL"]["ACCEL_COMMAND"] < -1e-5)
else:
aeb_sig = "COMPUTER_BRAKE_ALT" if self.CP.carFingerprint == CAR.CLARITY else "COMPUTER_BRAKE"
aeb_sig = "COMPUTER_BRAKE_ALT" if self.CP.carFingerprint == CAR.HONDA_CLARITY else "COMPUTER_BRAKE"
ret.stockAeb = bool(cp_cam.vl["BRAKE_COMMAND"]["AEB_REQ_1"] and cp_cam.vl["BRAKE_COMMAND"][aeb_sig] > 1e-5)
self.acc_hud = False
-2
View File
@@ -348,5 +348,3 @@ SERIAL_STEERING = {CAR.HONDA_ACCORD_4CYL_9TH_GEN, }
DBC = CAR.create_dbc_map()
SERIAL_STEERING = {CAR.HONDA_ACCORD_4CYL_9TH_GEN, }
+2 -2
View File
@@ -269,11 +269,11 @@ class CarController(CarControllerBase):
# send resume at a max freq of 10Hz
if (self.frame - self.last_button_frame) * DT_CTRL > 0.1 * send_freq:
# send 25 messages at a time to increases the likelihood of cruise buttons being accepted
can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, self.cruise_button, self.CP)] * 25)
if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15 * send_freq:
self.last_button_frame = self.frame
elif self.frame % 2 == 0:
can_sends.extend([hyundaican.create_clu11(self.packer, (self.frame // 2) + 1, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
can_sends.extend([hyundaican.create_clu11(self.packer, (self.frame // 2) + 1, CS.clu11, self.cruise_button, self.CP)] * 25)
# Parse lead distance from radarState and display the corresponding distance in the car's cluster
if self.CP.openpilotLongitudinalControl and self.sm.updated['radarState'] and self.frame % 5 == 0:
+4 -1
View File
@@ -97,6 +97,9 @@ class CarInterface(CarInterfaceBase):
ret.longitudinalTuning.kpV = [0.1]
ret.longitudinalTuning.kiV = [0.0]
ret.experimentalLongitudinalAvailable = candidate not in (CANFD_UNSUPPORTED_LONGITUDINAL_CAR | CANFD_RADAR_SCC_CAR | NON_SCC_CAR)
if ret.flags & HyundaiFlags.CANFD_CAMERA_SCC and not hda2:
ret.spFlags |= HyundaiFlagsSP.SP_CAMERA_SCC_LEAD.value
ret.radarUnavailable = False
else:
ret.longitudinalTuning.kpV = [0.5]
ret.longitudinalTuning.kiV = [0.0]
@@ -239,7 +242,7 @@ class CarInterface(CarInterfaceBase):
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
ret.cruiseState.enabled = False if self.CP.pcmCruise else self.CS.accEnabled
ret, self.CS = self.get_sp_common_state(ret, self.CS)
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=(self.CS.cruise_buttons[-1] == 3))
# MADS BUTTON
if self.CS.out.madsEnabled != self.CS.madsEnabled:
+20 -8
View File
@@ -3,7 +3,8 @@ import math
from cereal import car
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car.interfaces import RadarInterfaceBase
from openpilot.selfdrive.car.hyundai.values import DBC, HyundaiFlagsSP
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
from openpilot.selfdrive.car.hyundai.values import DBC, HyundaiFlagsSP, CANFD_CAR
RADAR_START_ADDR = 0x500
RADAR_MSG_COUNT = 32
@@ -12,12 +13,18 @@ RADAR_MSG_COUNT = 32
def get_radar_can_parser(CP):
if DBC[CP.carFingerprint]['radar'] is None:
if CP.spFlags & HyundaiFlagsSP.SP_ENHANCED_SCC:
lead_src, bus = "ESCC", 0
elif CP.spFlags & HyundaiFlagsSP.SP_CAMERA_SCC_LEAD:
lead_src, bus = "SCC11", 2
if CP.carFingerprint in CANFD_CAR:
if CP.spFlags & HyundaiFlagsSP.SP_CAMERA_SCC_LEAD:
lead_src, bus = "SCC_CONTROL", CanBus(CP).CAM
else:
return None
else:
return None
if CP.spFlags & HyundaiFlagsSP.SP_ENHANCED_SCC:
lead_src, bus = "ESCC", 0
elif CP.spFlags & HyundaiFlagsSP.SP_CAMERA_SCC_LEAD:
lead_src, bus = "SCC11", 2
else:
return None
messages = [(lead_src, 50)]
return CANParser(DBC[CP.carFingerprint]['pt'], messages, bus)
@@ -28,10 +35,12 @@ def get_radar_can_parser(CP):
class RadarInterface(RadarInterfaceBase):
def __init__(self, CP):
super().__init__(CP)
self.CP = CP
self.enhanced_scc = (CP.spFlags & HyundaiFlagsSP.SP_ENHANCED_SCC) and DBC[CP.carFingerprint]['radar'] is None
self.camera_scc = CP.spFlags & HyundaiFlagsSP.SP_CAMERA_SCC_LEAD
self.updated_messages = set()
self.trigger_msg = 0x2AB if self.enhanced_scc else \
0x1A0 if self.camera_scc and CP.carFingerprint in CANFD_CAR else \
0x420 if self.camera_scc else \
(RADAR_START_ADDR + RADAR_MSG_COUNT - 1)
self.track_id = 0
@@ -68,9 +77,12 @@ class RadarInterface(RadarInterfaceBase):
ret.errors = errors
if self.enhanced_scc or self.camera_scc:
msg_src = "ESCC" if self.enhanced_scc else "SCC11"
msg_src = "ESCC" if self.enhanced_scc else \
"SCC_CONTROL" if self.CP.carFingerprint in CANFD_CAR else \
"SCC11"
msg = self.rcp.vl[msg_src]
valid = msg['ACC_ObjStatus']
valid = msg['ACC_ObjDist'] < 204.6 if self.CP.carFingerprint in CANFD_CAR else \
msg['ACC_ObjStatus']
for ii in range(1):
if valid:
if ii not in self.pts:
+17 -1
View File
@@ -593,7 +593,7 @@ class CarInterfaceBase(ABC):
else:
return CS.madsEnabled
def get_sp_common_state(self, cs_out, CS, min_enable_speed_pcm=False, gear_allowed=True):
def get_sp_common_state(self, cs_out, CS, min_enable_speed_pcm=False, gear_allowed=True, gap_button=False):
cs_out.cruiseState.enabled = CS.accEnabled if not self.CP.pcmCruise or not self.CP.pcmCruiseSpeed or min_enable_speed_pcm else \
cs_out.cruiseState.enabled
@@ -603,6 +603,9 @@ class CarInterfaceBase(ABC):
elif not cs_out.cruiseState.enabled and CS.out.cruiseState.enabled:
CS.madsEnabled = False
if self.CP.openpilotLongitudinalControl:
self.toggle_exp_mode(gap_button)
cs_out.belowLaneChangeSpeed = cs_out.vEgo < LANE_CHANGE_SPEED_MIN and self.below_speed_pause
if cs_out.gearShifter in [GearShifter.park, GearShifter.reverse] or cs_out.doorOpen or \
@@ -628,6 +631,19 @@ class CarInterfaceBase(ABC):
return cs_out, CS
# TODO: SP: use upstream's buttonEvents counter checks from controlsd
def toggle_exp_mode(self, gap_pressed):
if gap_pressed:
if not self.experimental_mode_hold:
self.gap_button_counter += 1
if self.gap_button_counter > 50:
self.gap_button_counter = 0
self.experimental_mode_hold = True
self.param_s.put_bool_nonblocking("ExperimentalMode", not self.experimental_mode)
else:
self.gap_button_counter = 0
self.experimental_mode_hold = False
def create_sp_events(self, CS, cs_out, events, main_enabled=False, allow_enable=True, enable_pressed=False,
enable_from_brake=False, enable_pressed_long=False,
enable_buttons=(ButtonType.accelCruise, ButtonType.decelCruise)):
+1 -1
View File
@@ -77,7 +77,7 @@ class CarInterface(CarInterfaceBase):
self.CS.accEnabled = False
self.CS.accEnabled = ret.cruiseState.enabled or self.CS.accEnabled
ret, self.CS = self.get_sp_common_state(ret, self.CS)
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.distance_button))
# MADS BUTTON
if self.CS.out.madsEnabled != self.CS.madsEnabled:
+1 -1
View File
@@ -51,7 +51,7 @@ class CarInterface(CarInterfaceBase):
self.CS.madsEnabled, self.CS.accEnabled = self.get_sp_cancel_cruise_state(self.CS.madsEnabled)
ret.cruiseState.enabled = False if self.CP.pcmCruise else self.CS.accEnabled
ret, self.CS = self.get_sp_common_state(ret, self.CS)
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(self.CS.distance_button))
# CANCEL
if self.CS.out.cruiseState.enabled and not ret.cruiseState.enabled:
+2 -2
View File
@@ -104,7 +104,7 @@ class CarState(CarStateBase):
ret.standstill = abs(ret.vEgoRaw) < 1e-3
if self.CP.carFingerprint != CAR.PRIUS_V:
if self.CP.carFingerprint != CAR.TOYOTA_PRIUS_V:
self.lta_status = cp_cam.vl["LKAS_HUD"]["SET_ME_X02"]
if ((self.prev_lta_status == 16 and self.lta_status == 0) or
(self.prev_lta_status == 0 and self.lta_status == 16)) and not self.lta_status_active:
@@ -113,7 +113,7 @@ class CarState(CarStateBase):
self.prev_lta_status = self.lta_status
if self.lta_status_active:
self.lkas_enabled = self.lta_status
elif self.CP.carFingerprint != CAR.PRIUS_V:
elif self.CP.carFingerprint != CAR.TOYOTA_PRIUS_V:
self.lkas_enabled = cp_cam.vl["LKAS_HUD"]["LKAS_STATUS"]
if self.prev_lkas_enabled is None:
self.prev_lkas_enabled = self.lkas_enabled
+1 -1
View File
@@ -224,7 +224,7 @@ class CarInterface(CarInterfaceBase):
if not self.CP.pcmCruise:
ret.cruiseState.enabled = self.CS.accEnabled
ret, self.CS = self.get_sp_common_state(ret, self.CS)
ret, self.CS = self.get_sp_common_state(ret, self.CS, gap_button=bool(distance_button))
# CANCEL
if self.CS.out.cruiseState.enabled and not ret.cruiseState.enabled:
+1 -1
View File
@@ -130,7 +130,7 @@ class CarState(CarStateBase):
ret.cruiseState.available = pt_cp.vl["TSK_06"]["TSK_Status"] in (2, 3, 4, 5)
ret.cruiseState.enabled = pt_cp.vl["TSK_06"]["TSK_Status"] in (3, 4, 5)
if self.CP.pcmCruise:
if self.CP.pcmCruise and not self.CP.spFlags & VolkswagenFlagsSP.SP_CC_ONLY_NO_RADAR:
# Cruise Control mode; check for distance UI setting from the radar.
# ECM does not manage this, so do not need to check for openpilot longitudinal
ret.cruiseState.nonAdaptive = ext_cp.vl["ACC_02"]["ACC_Gesetzte_Zeitluecke"] == 0
+2 -33
View File
@@ -209,34 +209,6 @@ class Controls:
if any(ps.controlsAllowed for ps in self.sm['pandaStates']):
self.state = State.enabled
def get_road_edge(self, carstate, model_v2):
# Lane detection by FrogAi
one_blinker = carstate.leftBlinker != carstate.rightBlinker
if not self.edge_toggle:
self.road_edge = False
elif one_blinker:
# Set the minimum lane threshold to 3.0 meters
min_lane_threshold = 3.0
# Set the blinker index based on which signal is on
blinker_index = 0 if carstate.leftBlinker else 1
desired_edge = model_v2.roadEdges[blinker_index]
current_lane = model_v2.laneLines[blinker_index + 1]
# Check if both the desired lane and the current lane have valid x and y values
if all([desired_edge.x, desired_edge.y, current_lane.x, current_lane.y]) and len(desired_edge.x) == len(current_lane.x):
# Interpolate the x and y values to the same length
x = np.linspace(desired_edge.x[0], desired_edge.x[-1], num=len(desired_edge.x))
lane_y = np.interp(x, current_lane.x, current_lane.y)
desired_y = np.interp(x, desired_edge.x, desired_edge.y)
# Calculate the width of the lane we're wanting to change into
lane_width = np.abs(desired_y - lane_y)
# Set road_edge to False if the lane width is not larger than the threshold
self.road_edge = not (np.amax(lane_width) > min_lane_threshold)
else:
self.road_edge = True
else:
# Default to setting "road_edge" to False
self.road_edge = False
def update_events(self, CS):
"""Compute onroadEvents from carState"""
@@ -760,12 +732,9 @@ class Controls:
# decrement personality on distance button press
if self.CP.openpilotLongitudinalControl:
if self.v_cruise_helper.update_personality:
if any(not be.pressed and be.type == ButtonType.gapAdjustCruise for be in CS.buttonEvents):
self.personality = (self.personality - 1) % 3
self.params.put_nonblocking('LongitudinalPersonality', str(self.personality))
if self.v_cruise_helper.update_experimental_mode:
self.experimental_mode = not self.experimental_mode
self.params.put_bool_nonblocking('ExperimentalMode', self.experimental_mode)
return CC, lac_log
@@ -798,7 +767,7 @@ class Controls:
hudControl.speedVisible = self.enabled_long
hudControl.lanesVisible = self.enabled
hudControl.leadVisible = self.sm['longitudinalPlan'].hasLead
hudControl.leadDistanceBars = self.personality + 1
hudControl.leadDistanceBars = PERSONALITY_MAPPING.get(self.personality, log.LongitudinalPersonality.standard) + 1
hudControl.rightLaneVisible = True
hudControl.leftLaneVisible = True
@@ -52,5 +52,9 @@
"Offroad_OSMUpdateRequired": {
"text": "OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display.\n\n%1",
"severity": 0
},
"Offroad_ForceStatus": {
"text": "sunnypilot is now in Forced Offroad mode. sunnypilot won't start until Forced Offroad mode is disabled. Go to \"Settings\" -> \"Device\" -> \"Unforce Offroad\" to exit Force Offroad mode.",
"severity": 1
}
}
+1 -18
View File
@@ -75,7 +75,7 @@ class VCruiseHelper:
self.v_cruise_kph = V_CRUISE_UNSET
self.v_cruise_cluster_kph = V_CRUISE_UNSET
self.v_cruise_kph_last = 0
self.button_timers = {ButtonType.decelCruise: 0, ButtonType.accelCruise: 0, ButtonType.gapAdjustCruise: 0}
self.button_timers = {ButtonType.decelCruise: 0, ButtonType.accelCruise: 0}
self.button_change_states = {btn: {"standstill": False, "enabled": False} for btn in self.button_timers}
self.is_metric_prev = None
@@ -84,9 +84,6 @@ class VCruiseHelper:
self.slc_state_prev = SpeedLimitControlState.inactive
self.slc_speed_limit_offsetted = 0
self.update_personality = False
self.update_experimental_mode = False
@property
def v_cruise_initialized(self):
return self.v_cruise_kph != V_CRUISE_UNSET
@@ -123,8 +120,6 @@ class VCruiseHelper:
long_press = False
button_type = None
update_personality = False
update_experimental_mode = False
v_cruise_delta = 1. if is_metric else IMPERIAL_INCREMENT
v_cruise_delta_mltplr = 10 if is_metric else 5
@@ -145,15 +140,6 @@ class VCruiseHelper:
if button_type is None:
return
if button_type == ButtonType.gapAdjustCruise and self.button_timers[ButtonType.gapAdjustCruise]:
if self.button_timers[ButtonType.gapAdjustCruise] < 50:
update_personality = True
elif self.button_timers[ButtonType.gapAdjustCruise] == 50:
update_experimental_mode = True
self.update_personality = update_personality
self.update_experimental_mode = update_experimental_mode
resume_button = ButtonType.accelCruise
if not self.CP.pcmCruiseSpeed:
if self.CP.carName == "chrysler":
@@ -168,9 +154,6 @@ class VCruiseHelper:
if not self.button_change_states[button_type]["enabled"]:
return
if button_type == ButtonType.gapAdjustCruise:
return
pressed_value = (1 if long_press else v_cruise_delta_mltplr) if reverse_acc else (v_cruise_delta_mltplr if long_press else 1)
long_press_state = not long_press if reverse_acc else long_press
v_cruise_delta = v_cruise_delta * pressed_value
+1
View File
@@ -103,6 +103,7 @@ def manager_init() -> None:
("OsmDbUpdatesCheck", "0"),
("OsmDownloadedDate", "0"),
("OSMDownloadProgress", "{}"),
("SidebarTemperatureOptions", "0"),
("SunnylinkEnabled", "1"),
]
if not PC:
+1 -1
View File
@@ -45,7 +45,7 @@ def only_offroad(started, params, CP: car.CarParams) -> bool:
def model_use_nav(started, params, CP: car.CarParams) -> bool:
custom_model, model_gen = get_model_generation(params)
return started and custom_model and model_gen != 4
return started and custom_model and model_gen not in (0, 4)
procs = [
DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"),
+6
View File
@@ -311,6 +311,12 @@ def thermald_thread(end_event, hw_queue) -> None:
# ensure device is fully booted
startup_conditions["device_booted"] = startup_conditions.get("device_booted", False) or HARDWARE.booted()
# user-forced status
force_offroad = params.get_bool("ForceOffroad")
startup_conditions["not_force_offroad"] = not force_offroad
onroad_conditions["not_force_offroad"] = not force_offroad
set_offroad_alert("Offroad_ForceStatus", force_offroad)
# if the temperature enters the danger zone, go offroad to cool down
onroad_conditions["device_temp_good"] = thermal_status < ThermalStatus.danger
extra_text = f"{offroad_comp_temp:.1f}C"
+54 -1
View File
@@ -420,13 +420,24 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
connect(uiState(), &UIState::offroadTransition, poweroff_btn, &QPushButton::setVisible);
}
offroad_btn = new QPushButton(tr("Toggle Onroad/Offroad"));
offroad_btn->setObjectName("offroad_btn");
QObject::connect(offroad_btn, &QPushButton::clicked, this, &DevicePanel::forceoffroad);
QVBoxLayout *buttons_layout = new QVBoxLayout();
buttons_layout->setSpacing(24);
buttons_layout->addLayout(power_layout);
buttons_layout->addWidget(offroad_btn);
setStyleSheet(R"(
#reboot_btn { height: 120px; border-radius: 15px; background-color: #393939; }
#reboot_btn:pressed { background-color: #4a4a4a; }
#poweroff_btn { height: 120px; border-radius: 15px; background-color: #E22C2C; }
#poweroff_btn:pressed { background-color: #FF2424; }
)");
addItem(power_layout);
addItem(buttons_layout);
updateLabels();
}
void DevicePanel::onPinFileChanged(const QString &file_path) {
@@ -501,9 +512,51 @@ void DevicePanel::poweroff() {
}
}
void DevicePanel::forceoffroad() {
if (!uiState()->engaged()) {
if (params.getBool("ForceOffroad")) {
if (ConfirmationDialog::confirm(tr("Are you sure you want to unforce offroad?"), tr("Unforce"), this)) {
// Check engaged again in case it changed while the dialog was open
if (!uiState()->engaged()) {
params.remove("ForceOffroad");
}
}
} else {
if (ConfirmationDialog::confirm(tr("Are you sure you want to force offroad?"), tr("Force"), this)) {
// Check engaged again in case it changed while the dialog was open
if (!uiState()->engaged()) {
params.putBool("ForceOffroad", true);
}
}
}
} else {
ConfirmationDialog::alert(tr("Disengage to Force Offroad"), this);
}
updateLabels();
}
void DevicePanel::showEvent(QShowEvent *event) {
pair_device->setVisible(uiState()->primeType() == PrimeType::UNPAIRED);
ListWidget::showEvent(event);
updateLabels();
}
void DevicePanel::updateLabels() {
if (!isVisible()) {
return;
}
bool force_offroad_param = params.getBool("ForceOffroad");
QString offroad_btn_style = force_offroad_param ? "#393939" : "#E22C2C";
QString offroad_btn_pressed_style = force_offroad_param ? "#4a4a4a" : "#FF2424";
QString btn_common_style = QString("QPushButton { height: 120px; border-radius: 15px; background-color: %1; }"
"QPushButton:pressed { background-color: %2; }")
.arg(offroad_btn_style,
offroad_btn_pressed_style);
offroad_btn->setText(force_offroad_param ? tr("Unforce Offroad") : tr("Force Offroad"));
offroad_btn->setStyleSheet(btn_common_style + offroad_btn_style + offroad_btn_pressed_style);
}
void SettingsWindow::showEvent(QShowEvent *event) {
+5
View File
@@ -63,6 +63,9 @@ private slots:
void updateCalibDescription();
void onPinFileChanged(const QString &file_path);
void refreshPin();
void forceoffroad();
void updateLabels();
private:
Params params;
@@ -72,6 +75,8 @@ private:
QString pin_title = tr("Fleet Manager PIN:") + " ";
QString pin = "OFF";
QFileSystemWatcher *fs_watch;
QPushButton *offroad_btn;
};
class TogglesPanel : public ListWidget {
@@ -107,16 +107,9 @@ SunnylinkPanel::SunnylinkPanel(QWidget* parent) : QFrame(parent) {
connect(restoreSettings, &QPushButton::clicked, [=]() {
is_restore = true;
backup_settings->started();
if (uiState()->isSunnylinkSponsor()) {
if (ConfirmationDialog::confirm(tr("Are you sure you want to restore the last backed up sunnypilot settings?"), tr("Restore"), this)) {
backup_settings->getParams();
} else {
backup_settings->finished();
}
if (ConfirmationDialog::confirm(tr("Are you sure you want to restore the last backed up sunnypilot settings?"), tr("Restore"), this)) {
backup_settings->getParams();
} else {
if (ConfirmationDialog::confirm(tr("Early alpha access only. Become a sponsor to get early access to sunnylink features."), tr("Become a Sponsor"), this)) {
status_popup->exec();
}
backup_settings->finished();
}
is_restore = false;
+2 -1
View File
@@ -165,6 +165,7 @@ static void update_sockets(UIState *s) {
static void update_state(UIState *s) {
SubMaster &sm = *(s->sm);
UIScene &scene = s->scene;
auto params = Params();
if (sm.updated("liveCalibration")) {
auto live_calib = sm["liveCalibration"].getLiveCalibration();
@@ -214,7 +215,7 @@ static void update_state(UIState *s) {
float scale = (cam_state.getSensor() == cereal::FrameData::ImageSensor::AR0231) ? 6.0f : 1.0f;
scene.light_sensor = std::max(100.0f - scale * cam_state.getExposureValPercent(), 0.0f);
}
scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition;
scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition && !params.getBool("ForceOffroad");
scene.world_objects_visible = scene.world_objects_visible ||
(scene.started &&