mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-08-23 02:23:47 +08:00
Merge branch 'master-priv' into nnlc-lateral-jerk
This commit is contained in:
+7
-1
@@ -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
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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 ¶ms) {
|
||||
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");
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, }
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)):
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -103,6 +103,7 @@ def manager_init() -> None:
|
||||
("OsmDbUpdatesCheck", "0"),
|
||||
("OsmDownloadedDate", "0"),
|
||||
("OSMDownloadProgress", "{}"),
|
||||
("SidebarTemperatureOptions", "0"),
|
||||
("SunnylinkEnabled", "1"),
|
||||
]
|
||||
if not PC:
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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 &&
|
||||
|
||||
Reference in New Issue
Block a user