mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-06-24 01:22:05 +08:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e4ec9f288 | |||
| 025a930ce8 | |||
| 523c92c6fe | |||
| 72282f2d2e | |||
| 2825c00fcc | |||
| 063aa994d2 | |||
| 50462a1d01 | |||
| 437726b348 | |||
| 9e6af5ba74 | |||
| 99bd9075d5 | |||
| c438aeb5a5 | |||
| f1ca81debf | |||
| d7e1c42c2b | |||
| 6d51d64285 | |||
| e0ccc175e4 | |||
| 734151f59b | |||
| 9a14baac4d | |||
| d3e3628a95 | |||
| fec6382b96 | |||
| 4bd020e92b | |||
| 7f5342f378 | |||
| 339bc0b8b3 | |||
| 59c64acc29 | |||
| 7229c7541e | |||
| 39e73cc46e | |||
| 285fd97606 | |||
| e5f1f86ac2 | |||
| 09cb350d6f |
+47
-5
@@ -69,6 +69,48 @@ struct LeadData {
|
||||
struct SelfdriveStateSP @0x81c2f05a394cf4af {
|
||||
mads @0 :ModularAssistiveDrivingSystem;
|
||||
intelligentCruiseButtonManagement @1 :IntelligentCruiseButtonManagement;
|
||||
|
||||
enum AudibleAlert {
|
||||
none @0;
|
||||
|
||||
engage @1;
|
||||
disengage @2;
|
||||
refuse @3;
|
||||
|
||||
warningSoft @4;
|
||||
warningImmediate @5;
|
||||
|
||||
prompt @6;
|
||||
promptRepeat @7;
|
||||
promptDistracted @8;
|
||||
|
||||
# unused, these are reserved for upstream events so we don't collide
|
||||
reserved9 @9;
|
||||
reserved10 @10;
|
||||
reserved11 @11;
|
||||
reserved12 @12;
|
||||
reserved13 @13;
|
||||
reserved14 @14;
|
||||
reserved15 @15;
|
||||
reserved16 @16;
|
||||
reserved17 @17;
|
||||
reserved18 @18;
|
||||
reserved19 @19;
|
||||
reserved20 @20;
|
||||
reserved21 @21;
|
||||
reserved22 @22;
|
||||
reserved23 @23;
|
||||
reserved24 @24;
|
||||
reserved25 @25;
|
||||
reserved26 @26;
|
||||
reserved27 @27;
|
||||
reserved28 @28;
|
||||
reserved29 @29;
|
||||
reserved30 @30;
|
||||
|
||||
promptSingleLow @31;
|
||||
promptSingleHigh @32;
|
||||
}
|
||||
}
|
||||
|
||||
struct ModelManagerSP @0xaedffd8f31e7b55d {
|
||||
@@ -404,12 +446,12 @@ struct LiveMapDataSP @0xf416ec09499d9d19 {
|
||||
|
||||
struct ModelDataV2SP @0xa1680744031fdb2d {
|
||||
laneTurnDirection @0 :TurnDirection;
|
||||
}
|
||||
|
||||
enum TurnDirection {
|
||||
none @0;
|
||||
turnLeft @1;
|
||||
turnRight @2;
|
||||
enum TurnDirection {
|
||||
none @0;
|
||||
turnLeft @1;
|
||||
turnRight @2;
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomReserved10 @0xcb9fd56c7057593a {
|
||||
|
||||
@@ -160,9 +160,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"ModelRunnerTypeCache", {CLEAR_ON_ONROAD_TRANSITION, INT}},
|
||||
{"OffroadMode", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"Offroad_TiciSupport", {CLEAR_ON_MANAGER_START, JSON}},
|
||||
{"OnroadScreenOffBrightness", {PERSISTENT | BACKUP, INT, "100"}},
|
||||
{"OnroadScreenOffBrightness", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
{"OnroadScreenOffControl", {PERSISTENT | BACKUP, BOOL}},
|
||||
{"OnroadScreenOffTimer", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
{"OnroadScreenOffTimer", {PERSISTENT | BACKUP, INT, "15"}},
|
||||
{"OnroadUploads", {PERSISTENT | BACKUP, BOOL, "1"}},
|
||||
{"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
@@ -205,6 +205,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
|
||||
// sunnypilot car specific params
|
||||
{"HyundaiLongitudinalTuning", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
{"SubaruStopAndGo", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"SubaruStopAndGoManualParkingBrake", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
|
||||
{"DynamicExperimentalControl", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"BlindSpot", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
|
||||
+1
-1
Submodule opendbc_repo updated: b592ecdd3b...e9ae857746
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:dbfa5858c0a672411ffdc691efdecb06d01ae458cc1df409bcf3fdeaa4756f72
|
||||
size 34638
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:db9671bb03e01f119bba1eb6cc0507e0f039ac4e5b7f9f839a87071c52e86e56
|
||||
size 44416
|
||||
@@ -99,7 +99,6 @@ class Controls(ControlsExt, ModelStateBase):
|
||||
|
||||
self.LaC.extension.update_model_v2(self.sm['modelV2'])
|
||||
|
||||
self.lat_delay = get_lat_delay(self.params, self.sm["liveDelay"].lateralDelay)
|
||||
self.LaC.extension.update_lateral_lag(self.lat_delay)
|
||||
|
||||
long_plan = self.sm['longitudinalPlan']
|
||||
@@ -234,6 +233,9 @@ class Controls(ControlsExt, ModelStateBase):
|
||||
while not evt.is_set():
|
||||
self.get_params_sp()
|
||||
|
||||
if self.CP.lateralTuning.which() == 'torque':
|
||||
self.lat_delay = get_lat_delay(self.params, self.sm["liveDelay"].lateralDelay)
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
def run(self):
|
||||
|
||||
@@ -6,6 +6,7 @@ from openpilot.sunnypilot.selfdrive.controls.lib.lane_turn_desire import LaneTur
|
||||
|
||||
LaneChangeState = log.LaneChangeState
|
||||
LaneChangeDirection = log.LaneChangeDirection
|
||||
TurnDirection = custom.ModelDataV2SP.TurnDirection
|
||||
|
||||
LANE_CHANGE_SPEED_MIN = 20 * CV.MPH_TO_MS
|
||||
LANE_CHANGE_TIME_MAX = 10.
|
||||
@@ -32,9 +33,9 @@ DESIRES = {
|
||||
}
|
||||
|
||||
TURN_DESIRES = {
|
||||
custom.TurnDirection.none: log.Desire.none,
|
||||
custom.TurnDirection.turnLeft: log.Desire.turnLeft,
|
||||
custom.TurnDirection.turnRight: log.Desire.turnRight,
|
||||
TurnDirection.none: log.Desire.none,
|
||||
TurnDirection.turnLeft: log.Desire.turnLeft,
|
||||
TurnDirection.turnRight: log.Desire.turnRight,
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +50,7 @@ class DesireHelper:
|
||||
self.desire = log.Desire.none
|
||||
self.alc = AutoLaneChangeController(self)
|
||||
self.lane_turn_controller = LaneTurnController(self)
|
||||
self.lane_turn_direction = custom.TurnDirection.none
|
||||
self.lane_turn_direction = TurnDirection.none
|
||||
|
||||
@staticmethod
|
||||
def get_lane_change_direction(CS):
|
||||
@@ -126,7 +127,7 @@ class DesireHelper:
|
||||
|
||||
self.prev_one_blinker = one_blinker
|
||||
|
||||
if self.lane_turn_direction != custom.TurnDirection.none:
|
||||
if self.lane_turn_direction != TurnDirection.none:
|
||||
self.desire = TURN_DESIRES[self.lane_turn_direction]
|
||||
else:
|
||||
self.desire = DESIRES[self.lane_change_direction][self.lane_change_state]
|
||||
|
||||
@@ -24,6 +24,7 @@ from openpilot.selfdrive.selfdrived.alertmanager import AlertManager, set_offroa
|
||||
from openpilot.system.version import get_build_metadata
|
||||
|
||||
from openpilot.sunnypilot.mads.mads import ModularAssistiveDrivingSystem
|
||||
from openpilot.sunnypilot import get_sanitize_int_param
|
||||
from openpilot.sunnypilot.selfdrive.car.car_specific import CarSpecificEventsSP
|
||||
from openpilot.sunnypilot.selfdrive.car.cruise_helpers import CruiseHelper
|
||||
from openpilot.sunnypilot.selfdrive.car.intelligent_cruise_button_management.controller import IntelligentCruiseButtonManagement
|
||||
@@ -43,6 +44,7 @@ LaneChangeDirection = log.LaneChangeDirection
|
||||
EventName = log.OnroadEvent.EventName
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
SafetyModel = car.CarParams.SafetyModel
|
||||
TurnDirection = custom.ModelDataV2SP.TurnDirection
|
||||
|
||||
IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput)
|
||||
|
||||
@@ -130,7 +132,12 @@ class SelfdriveD(CruiseHelper):
|
||||
self.logged_comm_issue = None
|
||||
self.not_running_prev = None
|
||||
self.experimental_mode = False
|
||||
self.personality = self.params.get("LongitudinalPersonality", return_default=True)
|
||||
self.personality = get_sanitize_int_param(
|
||||
"LongitudinalPersonality",
|
||||
min(log.LongitudinalPersonality.schema.enumerants.values()),
|
||||
max(log.LongitudinalPersonality.schema.enumerants.values()),
|
||||
self.params
|
||||
)
|
||||
self.recalibrating_seen = False
|
||||
self.state_machine = StateMachine()
|
||||
self.rk = Ratekeeper(100, print_delay_threshold=None)
|
||||
@@ -299,9 +306,9 @@ class SelfdriveD(CruiseHelper):
|
||||
|
||||
# Handle lane turn
|
||||
lane_turn_direction = self.sm['modelDataV2SP'].laneTurnDirection
|
||||
if lane_turn_direction == custom.TurnDirection.turnLeft:
|
||||
if lane_turn_direction == TurnDirection.turnLeft:
|
||||
self.events_sp.add(custom.OnroadEventSP.EventName.laneTurnLeft)
|
||||
elif lane_turn_direction == custom.TurnDirection.turnRight:
|
||||
elif lane_turn_direction == TurnDirection.turnRight:
|
||||
self.events_sp.add(custom.OnroadEventSP.EventName.laneTurnRight)
|
||||
|
||||
for i, pandaState in enumerate(self.sm['pandaStates']):
|
||||
|
||||
@@ -33,13 +33,6 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
"../assets/icons/experimental_white.svg",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"DynamicExperimentalControl",
|
||||
tr("Enable Dynamic Experimental Control"),
|
||||
tr("Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"DisengageOnAccelerator",
|
||||
tr("Disengage on Accelerator Pedal"),
|
||||
|
||||
@@ -22,7 +22,7 @@ void ModelRenderer::draw(QPainter &painter, const QRect &surface_rect) {
|
||||
|
||||
update_model(model, lead_one);
|
||||
drawLaneLines(painter);
|
||||
drawPath(painter, model, surface_rect);
|
||||
drawPath(painter, model, surface_rect.height());
|
||||
|
||||
if (longitudinal_control && sm.alive("radarState")) {
|
||||
update_leads(radar_state, model.getPosition());
|
||||
@@ -173,7 +173,6 @@ QColor ModelRenderer::blendColors(const QColor &start, const QColor &end, float
|
||||
(1 - t) * start.alphaF() + t * end.alphaF());
|
||||
}
|
||||
|
||||
|
||||
void ModelRenderer::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data,
|
||||
const QPointF &vd, const QRect &surface_rect) {
|
||||
const float speedBuff = 10.;
|
||||
|
||||
@@ -39,9 +39,6 @@ protected:
|
||||
virtual void update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead);
|
||||
void drawLaneLines(QPainter &painter);
|
||||
void drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, int height);
|
||||
virtual void drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, const QRect &surface_rect) {;
|
||||
drawPath(painter, model, surface_rect.height());
|
||||
}
|
||||
void updatePathGradient(QLinearGradient &bg);
|
||||
QColor blendColors(const QColor &start, const QColor &end, float t);
|
||||
|
||||
@@ -58,5 +55,4 @@ protected:
|
||||
QPointF lead_vertices[2] = {};
|
||||
Eigen::Matrix3f car_space_transform = Eigen::Matrix3f::Zero();
|
||||
QRectF clip_region;
|
||||
|
||||
};
|
||||
|
||||
+10
-1
@@ -4,7 +4,7 @@ import time
|
||||
import wave
|
||||
|
||||
|
||||
from cereal import car, messaging
|
||||
from cereal import car, messaging, custom
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from openpilot.common.realtime import Ratekeeper
|
||||
@@ -26,8 +26,15 @@ AMBIENT_DB = 30 # DB where MIN_VOLUME is applied
|
||||
DB_SCALE = 30 # AMBIENT_DB + DB_SCALE is where MAX_VOLUME is applied
|
||||
|
||||
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
|
||||
AudibleAlertSP = custom.SelfdriveStateSP.AudibleAlert
|
||||
|
||||
|
||||
sound_list_sp: dict[int, tuple[str, int | None, float]] = {
|
||||
# AudibleAlertSP, file name, play count (none for infinite)
|
||||
AudibleAlertSP.promptSingleLow: ("prompt_single_low.wav", 1, MAX_VOLUME),
|
||||
AudibleAlertSP.promptSingleHigh: ("prompt_single_high.wav", 1, MAX_VOLUME),
|
||||
}
|
||||
|
||||
sound_list: dict[int, tuple[str, int | None, float]] = {
|
||||
# AudibleAlert, file name, play count (none for infinite)
|
||||
AudibleAlert.engage: ("engage.wav", 1, MAX_VOLUME),
|
||||
@@ -40,6 +47,8 @@ sound_list: dict[int, tuple[str, int | None, float]] = {
|
||||
|
||||
AudibleAlert.warningSoft: ("warning_soft.wav", None, MAX_VOLUME),
|
||||
AudibleAlert.warningImmediate: ("warning_immediate.wav", None, MAX_VOLUME),
|
||||
|
||||
**sound_list_sp,
|
||||
}
|
||||
|
||||
def check_selfdrive_timeout_alert(sm):
|
||||
|
||||
@@ -29,7 +29,7 @@ OnroadScreenBrightnessControl::OnroadScreenBrightnessControl(const QString ¶
|
||||
"Onroad Brightness",
|
||||
"",
|
||||
"",
|
||||
{0, 100}, 10, true);
|
||||
{0, 90}, 10, true);
|
||||
|
||||
connect(onroadScreenOffTimer, &OptionControlSP::updateLabels, this, &OnroadScreenBrightnessControl::refresh);
|
||||
connect(onroadScreenBrightness, &OptionControlSP::updateLabels, this, &OnroadScreenBrightnessControl::refresh);
|
||||
|
||||
@@ -13,9 +13,9 @@ enum class SpeedLimitOffsetType {
|
||||
};
|
||||
|
||||
inline const QString SpeedLimitOffsetTypeTexts[]{
|
||||
QObject::tr("None"),
|
||||
QObject::tr("Fixed"),
|
||||
QObject::tr("Percent"),
|
||||
QT_TRANSLATE_NOOP("SpeedLimitSettings", "None"),
|
||||
QT_TRANSLATE_NOOP("SpeedLimitSettings", "Fixed"),
|
||||
QT_TRANSLATE_NOOP("SpeedLimitSettings", "Percent"),
|
||||
};
|
||||
|
||||
enum class SpeedLimitSourcePolicy {
|
||||
@@ -27,11 +27,11 @@ enum class SpeedLimitSourcePolicy {
|
||||
};
|
||||
|
||||
inline const QString SpeedLimitSourcePolicyTexts[]{
|
||||
QObject::tr("Car\nOnly"),
|
||||
QObject::tr("Map\nOnly"),
|
||||
QObject::tr("Car\nFirst"),
|
||||
QObject::tr("Map\nFirst"),
|
||||
QObject::tr("Combined\nData")
|
||||
QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Car\nOnly"),
|
||||
QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Map\nOnly"),
|
||||
QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Car\nFirst"),
|
||||
QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Map\nFirst"),
|
||||
QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Combined\nData")
|
||||
};
|
||||
|
||||
enum class SpeedLimitMode {
|
||||
@@ -42,8 +42,8 @@ enum class SpeedLimitMode {
|
||||
};
|
||||
|
||||
inline const QString SpeedLimitModeTexts[]{
|
||||
QObject::tr("Off"),
|
||||
QObject::tr("Information"),
|
||||
QObject::tr("Warning"),
|
||||
QObject::tr("Assist"),
|
||||
QT_TRANSLATE_NOOP("SpeedLimitSettings", "Off"),
|
||||
QT_TRANSLATE_NOOP("SpeedLimitSettings", "Information"),
|
||||
QT_TRANSLATE_NOOP("SpeedLimitSettings", "Warning"),
|
||||
QT_TRANSLATE_NOOP("SpeedLimitSettings", "Assist"),
|
||||
};
|
||||
|
||||
+5
-5
@@ -23,11 +23,11 @@ SpeedLimitPolicy::SpeedLimitPolicy(QWidget *parent) : QWidget(parent) {
|
||||
ListWidgetSP *list = new ListWidgetSP(this);
|
||||
|
||||
std::vector<QString> speed_limit_policy_texts{
|
||||
SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::CAR_ONLY)],
|
||||
SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::MAP_ONLY)],
|
||||
SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::CAR_FIRST)],
|
||||
SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::MAP_FIRST)],
|
||||
SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::COMBINED)]
|
||||
tr(SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::CAR_ONLY)].toStdString().c_str()),
|
||||
tr(SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::MAP_ONLY)].toStdString().c_str()),
|
||||
tr(SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::CAR_FIRST)].toStdString().c_str()),
|
||||
tr(SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::MAP_FIRST)].toStdString().c_str()),
|
||||
tr(SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::COMBINED)].toStdString().c_str())
|
||||
};
|
||||
speed_limit_policy = new ButtonParamControlSP(
|
||||
"SpeedLimitPolicy",
|
||||
|
||||
+21
-12
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h"
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/util.h"
|
||||
|
||||
SpeedLimitSettings::SpeedLimitSettings(QWidget *parent) : QStackedWidget(parent) {
|
||||
subPanelFrame = new QFrame();
|
||||
QVBoxLayout *subPanelLayout = new QVBoxLayout(subPanelFrame);
|
||||
@@ -25,10 +27,10 @@ SpeedLimitSettings::SpeedLimitSettings(QWidget *parent) : QStackedWidget(parent)
|
||||
speedLimitPolicyScreen = new SpeedLimitPolicy(this);
|
||||
|
||||
std::vector<QString> speed_limit_mode_texts{
|
||||
SpeedLimitModeTexts[static_cast<int>(SpeedLimitMode::OFF)],
|
||||
SpeedLimitModeTexts[static_cast<int>(SpeedLimitMode::INFORMATION)],
|
||||
SpeedLimitModeTexts[static_cast<int>(SpeedLimitMode::WARNING)],
|
||||
SpeedLimitModeTexts[static_cast<int>(SpeedLimitMode::ASSIST)],
|
||||
tr(SpeedLimitModeTexts[static_cast<int>(SpeedLimitMode::OFF)].toStdString().c_str()),
|
||||
tr(SpeedLimitModeTexts[static_cast<int>(SpeedLimitMode::INFORMATION)].toStdString().c_str()),
|
||||
tr(SpeedLimitModeTexts[static_cast<int>(SpeedLimitMode::WARNING)].toStdString().c_str()),
|
||||
tr(SpeedLimitModeTexts[static_cast<int>(SpeedLimitMode::ASSIST)].toStdString().c_str())
|
||||
};
|
||||
speed_limit_mode_settings = new ButtonParamControlSP(
|
||||
"SpeedLimitMode",
|
||||
@@ -64,9 +66,9 @@ SpeedLimitSettings::SpeedLimitSettings(QWidget *parent) : QStackedWidget(parent)
|
||||
QVBoxLayout *offsetLayout = new QVBoxLayout(offsetFrame);
|
||||
|
||||
std::vector<QString> speed_limit_offset_texts{
|
||||
SpeedLimitOffsetTypeTexts[static_cast<int>(SpeedLimitOffsetType::NONE)],
|
||||
SpeedLimitOffsetTypeTexts[static_cast<int>(SpeedLimitOffsetType::FIXED)],
|
||||
SpeedLimitOffsetTypeTexts[static_cast<int>(SpeedLimitOffsetType::PERCENT)]
|
||||
tr(SpeedLimitOffsetTypeTexts[static_cast<int>(SpeedLimitOffsetType::NONE)].toStdString().c_str()),
|
||||
tr(SpeedLimitOffsetTypeTexts[static_cast<int>(SpeedLimitOffsetType::FIXED)].toStdString().c_str()),
|
||||
tr(SpeedLimitOffsetTypeTexts[static_cast<int>(SpeedLimitOffsetType::PERCENT)].toStdString().c_str())
|
||||
};
|
||||
speed_limit_offset_settings = new ButtonParamControlSP(
|
||||
"SpeedLimitOffsetType",
|
||||
@@ -109,7 +111,7 @@ void SpeedLimitSettings::refresh() {
|
||||
QString offsetLabel = QString::fromStdString(params.get("SpeedLimitValueOffset"));
|
||||
|
||||
bool has_longitudinal_control;
|
||||
bool intelligent_cruise_button_management_available;
|
||||
bool has_icbm;
|
||||
auto cp_bytes = params.get("CarParamsPersistent");
|
||||
auto cp_sp_bytes = params.get("CarParamsSPPersistent");
|
||||
if (!cp_bytes.empty() && !cp_sp_bytes.empty()) {
|
||||
@@ -121,10 +123,16 @@ void SpeedLimitSettings::refresh() {
|
||||
cereal::CarParamsSP::Reader CP_SP = cmsg_sp.getRoot<cereal::CarParamsSP>();
|
||||
|
||||
has_longitudinal_control = hasLongitudinalControl(CP);
|
||||
intelligent_cruise_button_management_available = CP_SP.getIntelligentCruiseButtonManagementAvailable();
|
||||
has_icbm = hasIntelligentCruiseButtonManagement(CP_SP);
|
||||
|
||||
if (!has_longitudinal_control && !has_icbm) {
|
||||
if (speed_limit_mode_param == SpeedLimitMode::ASSIST) {
|
||||
params.put("SpeedLimitMode", std::to_string(static_cast<int>(SpeedLimitMode::WARNING)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
has_longitudinal_control = false;
|
||||
intelligent_cruise_button_management_available = false;
|
||||
has_icbm = false;
|
||||
}
|
||||
|
||||
speed_limit_mode_settings->setDescription(modeDescription(speed_limit_mode_param));
|
||||
@@ -144,13 +152,14 @@ void SpeedLimitSettings::refresh() {
|
||||
speed_limit_offset->showDescription();
|
||||
}
|
||||
|
||||
if (has_longitudinal_control || intelligent_cruise_button_management_available) {
|
||||
if (has_longitudinal_control || has_icbm) {
|
||||
speed_limit_mode_settings->setEnableSelectedButtons(true, convertSpeedLimitModeValues(getSpeedLimitModeValues()));
|
||||
} else {
|
||||
speed_limit_mode_settings->setEnableSelectedButtons(true, convertSpeedLimitModeValues(
|
||||
{SpeedLimitMode::OFF,SpeedLimitMode::INFORMATION, SpeedLimitMode::WARNING}));
|
||||
{SpeedLimitMode::OFF, SpeedLimitMode::INFORMATION, SpeedLimitMode::WARNING}));
|
||||
}
|
||||
|
||||
speed_limit_mode_settings->refresh();
|
||||
speed_limit_mode_settings->showDescription();
|
||||
speed_limit_offset->showDescription();
|
||||
}
|
||||
|
||||
+1
@@ -35,6 +35,7 @@ private:
|
||||
SpeedLimitPolicy *speedLimitPolicyScreen;
|
||||
ButtonParamControlSP *speed_limit_offset_settings;
|
||||
OptionControlSP *speed_limit_offset;
|
||||
bool icbm_available = false;
|
||||
|
||||
static QString offsetDescription(SpeedLimitOffsetType type = SpeedLimitOffsetType::NONE) {
|
||||
QString none_str = tr("⦿ None: No Offset");
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h"
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/util.h"
|
||||
|
||||
LongitudinalPanel::LongitudinalPanel(QWidget *parent) : QWidget(parent) {
|
||||
setStyleSheet(R"(
|
||||
#back_btn {
|
||||
@@ -40,9 +42,20 @@ LongitudinalPanel::LongitudinalPanel(QWidget *parent) : QWidget(parent) {
|
||||
"",
|
||||
this
|
||||
);
|
||||
intelligentCruiseButtonManagement->setConfirmation(true, false);
|
||||
QObject::connect(intelligentCruiseButtonManagement, &ParamControlSP::toggleFlipped, this, [=](bool) {
|
||||
refresh(offroad);
|
||||
});
|
||||
list->addItem(intelligentCruiseButtonManagement);
|
||||
|
||||
dynamicExperimentalControl = new ParamControlSP(
|
||||
"DynamicExperimentalControl",
|
||||
tr("Dynamic Experimental Control (DEC)"),
|
||||
tr("Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal."),
|
||||
"",
|
||||
this
|
||||
);
|
||||
list->addItem(dynamicExperimentalControl);
|
||||
|
||||
SmartCruiseControlVision = new ParamControl(
|
||||
"SmartCruiseControlVision",
|
||||
tr("Smart Cruise Control - Vision"),
|
||||
@@ -103,11 +116,41 @@ void LongitudinalPanel::refresh(bool _offroad) {
|
||||
|
||||
has_longitudinal_control = hasLongitudinalControl(CP);
|
||||
is_pcm_cruise = CP.getPcmCruise();
|
||||
intelligent_cruise_button_management_available = CP_SP.getIntelligentCruiseButtonManagementAvailable();
|
||||
has_icbm = hasIntelligentCruiseButtonManagement(CP_SP);
|
||||
|
||||
if (CP_SP.getIntelligentCruiseButtonManagementAvailable() && !has_longitudinal_control) {
|
||||
intelligentCruiseButtonManagement->setEnabled(offroad);
|
||||
} else {
|
||||
params.remove("IntelligentCruiseButtonManagement");
|
||||
intelligentCruiseButtonManagement->setEnabled(false);
|
||||
}
|
||||
|
||||
if (has_longitudinal_control || has_icbm) {
|
||||
// enable Custom ACC Increments when long is available and is not PCM cruise
|
||||
customAccIncrement->setEnabled(((has_longitudinal_control && !is_pcm_cruise) || has_icbm) && offroad);
|
||||
dynamicExperimentalControl->setEnabled(has_longitudinal_control);
|
||||
SmartCruiseControlVision->setEnabled(true);
|
||||
SmartCruiseControlMap->setEnabled(true);
|
||||
} else {
|
||||
params.remove("CustomAccIncrementsEnabled");
|
||||
params.remove("DynamicExperimentalControl");
|
||||
params.remove("SmartCruiseControlVision");
|
||||
params.remove("SmartCruiseControlMap");
|
||||
customAccIncrement->setEnabled(false);
|
||||
dynamicExperimentalControl->setEnabled(false);
|
||||
SmartCruiseControlVision->setEnabled(false);
|
||||
SmartCruiseControlMap->setEnabled(false);
|
||||
}
|
||||
|
||||
intelligentCruiseButtonManagement->refresh();
|
||||
customAccIncrement->refresh();
|
||||
dynamicExperimentalControl->refresh();
|
||||
SmartCruiseControlVision->refresh();
|
||||
SmartCruiseControlMap->refresh();
|
||||
} else {
|
||||
has_longitudinal_control = false;
|
||||
is_pcm_cruise = false;
|
||||
intelligent_cruise_button_management_available = false;
|
||||
has_icbm = false;
|
||||
}
|
||||
|
||||
QString accEnabledDescription = tr("Enable custom Short & Long press increments for cruise speed increase/decrease.");
|
||||
@@ -119,33 +162,19 @@ void LongitudinalPanel::refresh(bool _offroad) {
|
||||
customAccIncrement->setDescription(onroadOnlyDescription);
|
||||
customAccIncrement->showDescription();
|
||||
} else {
|
||||
if (has_longitudinal_control || intelligent_cruise_button_management_available) {
|
||||
if (is_pcm_cruise) {
|
||||
if (has_longitudinal_control || has_icbm) {
|
||||
if (has_longitudinal_control && is_pcm_cruise) {
|
||||
customAccIncrement->setDescription(accPcmCruiseDisabledDescription);
|
||||
customAccIncrement->showDescription();
|
||||
} else {
|
||||
customAccIncrement->setDescription(accEnabledDescription);
|
||||
}
|
||||
} else {
|
||||
params.remove("CustomAccIncrementsEnabled");
|
||||
customAccIncrement->toggleFlipped(false);
|
||||
customAccIncrement->setDescription(accNoLongDescription);
|
||||
customAccIncrement->showDescription();
|
||||
params.remove("IntelligentCruiseButtonManagement");
|
||||
intelligentCruiseButtonManagement->toggleFlipped(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool icbm_allowed = intelligent_cruise_button_management_available && !has_longitudinal_control;
|
||||
intelligentCruiseButtonManagement->setEnabled(icbm_allowed && offroad);
|
||||
|
||||
// enable toggle when long is available and is not PCM cruise
|
||||
bool cai_allowed = (has_longitudinal_control && !is_pcm_cruise) || icbm_allowed;
|
||||
customAccIncrement->setEnabled(cai_allowed && !offroad);
|
||||
customAccIncrement->refresh();
|
||||
|
||||
SmartCruiseControlVision->setEnabled(has_longitudinal_control || icbm_allowed);
|
||||
SmartCruiseControlMap->setEnabled(has_longitudinal_control || icbm_allowed);
|
||||
|
||||
offroad = _offroad;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ private:
|
||||
Params params;
|
||||
bool has_longitudinal_control = false;
|
||||
bool is_pcm_cruise = false;
|
||||
bool intelligent_cruise_button_management_available = false;;
|
||||
bool has_icbm = false;
|
||||
bool offroad = false;
|
||||
|
||||
QStackedLayout *main_layout = nullptr;
|
||||
@@ -35,6 +35,7 @@ private:
|
||||
ParamControl *SmartCruiseControlVision;
|
||||
ParamControl *SmartCruiseControlMap;
|
||||
ParamControl *intelligentCruiseButtonManagement = nullptr;
|
||||
ParamControl *dynamicExperimentalControl = nullptr;
|
||||
SpeedLimitSettings *speedLimitScreen;
|
||||
PushButtonSP *speedLimitSettings;
|
||||
};
|
||||
|
||||
@@ -8,7 +8,52 @@
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.h"
|
||||
|
||||
SubaruSettings::SubaruSettings(QWidget *parent) : BrandSettingsInterface(parent) {
|
||||
stopAndGoToggle = new ParamControl("SubaruStopAndGo", tr("Stop and Go (Beta)"), "", "");
|
||||
stopAndGoToggle->setConfirmation(true, false);
|
||||
list->addItem(stopAndGoToggle);
|
||||
|
||||
stopAndGoManualParkingBrakeToggle = new ParamControl(
|
||||
"SubaruStopAndGoManualParkingBrake",
|
||||
tr("Stop and Go for Manual Parking Brake (Beta)"),
|
||||
"",
|
||||
""
|
||||
);
|
||||
stopAndGoManualParkingBrakeToggle->setConfirmation(true, false);
|
||||
list->addItem(stopAndGoManualParkingBrakeToggle);
|
||||
}
|
||||
|
||||
void SubaruSettings::updateSettings() {
|
||||
auto cp_bytes = params.get("CarParamsPersistent");
|
||||
if (!cp_bytes.empty()) {
|
||||
AlignedBuffer aligned_buf;
|
||||
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size()));
|
||||
cereal::CarParams::Reader CP = cmsg.getRoot<cereal::CarParams>();
|
||||
|
||||
is_subaru = CP.getBrand() == "subaru";
|
||||
|
||||
if (is_subaru) {
|
||||
if (!(CP.getFlags() & (SUBARU_FLAG_GLOBAL_GEN2 | SUBARU_FLAG_HYBRID))) {
|
||||
has_stop_and_go = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
is_subaru = false;
|
||||
has_stop_and_go = false;
|
||||
}
|
||||
|
||||
bool stop_and_go_disabled = !offroad || !has_stop_and_go;
|
||||
QString stop_and_go_desc = stopAndGoDescriptionBuilder(stopAndGoDesc);
|
||||
QString stop_and_go_manual_parking_brake_desc = stopAndGoDescriptionBuilder(stopAndGoManualParkingBrakeDesc);
|
||||
if (stop_and_go_disabled) {
|
||||
stop_and_go_desc = stopAndGoDescriptionBuilder(stopAndGoDesc, stopAndGoDisabledMsg());
|
||||
stop_and_go_manual_parking_brake_desc = stopAndGoDescriptionBuilder(stopAndGoManualParkingBrakeDesc, stopAndGoDisabledMsg());
|
||||
}
|
||||
|
||||
stopAndGoToggle->setEnabled(has_stop_and_go);
|
||||
stopAndGoToggle->setDescription(stop_and_go_desc);
|
||||
stopAndGoToggle->showDescription();
|
||||
|
||||
stopAndGoManualParkingBrakeToggle->setEnabled(has_stop_and_go);
|
||||
stopAndGoManualParkingBrakeToggle->setDescription(stop_and_go_manual_parking_brake_desc);
|
||||
stopAndGoManualParkingBrakeToggle->showDescription();
|
||||
}
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
|
||||
const int SUBARU_FLAG_GLOBAL_GEN2 = 4;
|
||||
const int SUBARU_FLAG_HYBRID = 32;
|
||||
|
||||
class SubaruSettings : public BrandSettingsInterface {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -23,4 +26,32 @@ public:
|
||||
|
||||
private:
|
||||
bool offroad = false;
|
||||
bool is_subaru;
|
||||
bool has_stop_and_go;
|
||||
|
||||
ParamControl* stopAndGoToggle;
|
||||
ParamControl* stopAndGoManualParkingBrakeToggle;
|
||||
|
||||
QString stopAndGoDesc = tr("Experimental feature to enable auto-resume during stop-and-go for certain supported Subaru platforms.");
|
||||
QString stopAndGoManualParkingBrakeDesc = tr("Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation!");
|
||||
|
||||
QString stopAndGoDisabledMsg() const {
|
||||
if (is_subaru && !has_stop_and_go) {
|
||||
return tr("This feature is currently not available on this platform.");
|
||||
}
|
||||
|
||||
if (!is_subaru) {
|
||||
return tr("Start the car to check car compatibility.");
|
||||
}
|
||||
|
||||
if (!offroad) {
|
||||
return tr("Enable \"Always Offroad\" in Device panel, or turn vehicle off to toggle.");
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
static QString stopAndGoDescriptionBuilder(const QString &base_description, const QString &custom_description = "") {
|
||||
return "<b>" + custom_description + "</b><br><br>" + base_description;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -12,43 +12,65 @@
|
||||
|
||||
|
||||
HudRendererSP::HudRendererSP() {
|
||||
plus_arrow_up_img = loadPixmap("../../sunnypilot/selfdrive/assets/img_plus_arrow_up", {105, 105});
|
||||
minus_arrow_down_img = loadPixmap("../../sunnypilot/selfdrive/assets/img_minus_arrow_down", {105, 105});
|
||||
plus_arrow_up_img = loadPixmap("../../sunnypilot/selfdrive/assets/img_plus_arrow_up", {90, 90});
|
||||
minus_arrow_down_img = loadPixmap("../../sunnypilot/selfdrive/assets/img_minus_arrow_down", {90, 90});
|
||||
|
||||
int small_max = e2e_alert_small * 2 - 40;
|
||||
int large_max = e2e_alert_large * 2 - 40;
|
||||
green_light_alert_small_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/green_light.png", {small_max, small_max});
|
||||
green_light_alert_large_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/green_light.png", {large_max, large_max});
|
||||
lead_depart_alert_small_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/lead_depart.png", {small_max, small_max});
|
||||
lead_depart_alert_large_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/lead_depart.png", {large_max, large_max});
|
||||
int size = e2e_alert_size * 2 - 40;
|
||||
green_light_alert_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/green_light.png", {size, size});
|
||||
lead_depart_alert_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/lead_depart.png", {size, size});
|
||||
}
|
||||
|
||||
void HudRendererSP::updateState(const UIState &s) {
|
||||
HudRenderer::updateState(s);
|
||||
|
||||
float speedConv = is_metric ? MS_TO_KPH : MS_TO_MPH;
|
||||
devUiInfo = s.scene.dev_ui_info;
|
||||
roadName = s.scene.road_name;
|
||||
showTurnSignals = s.scene.turn_signals;
|
||||
speedLimitMode = static_cast<SpeedLimitMode>(s.scene.speed_limit_mode);
|
||||
speedUnit = is_metric ? tr("km/h") : tr("mph");
|
||||
standstillTimer = s.scene.standstill_timer;
|
||||
|
||||
const SubMaster &sm = *(s.sm);
|
||||
const auto cs = sm["controlsState"].getControlsState();
|
||||
const auto car_state = sm["carState"].getCarState();
|
||||
const auto car_control = sm["carControl"].getCarControl();
|
||||
const auto radar_state = sm["radarState"].getRadarState();
|
||||
const auto is_gps_location_external = sm.rcv_frame("gpsLocationExternal") > 1;
|
||||
const auto gpsLocation = is_gps_location_external ? sm["gpsLocationExternal"].getGpsLocationExternal() : sm["gpsLocation"].getGpsLocation();
|
||||
const char *gps_source = is_gps_location_external ? "gpsLocationExternal" : "gpsLocation";
|
||||
const auto gpsLocation = is_gps_location_external ? sm[gps_source].getGpsLocationExternal() : sm[gps_source].getGpsLocation();
|
||||
const auto ltp = sm["liveTorqueParameters"].getLiveTorqueParameters();
|
||||
const auto car_params = sm["carParams"].getCarParams();
|
||||
const auto car_params_sp = sm["carParamsSP"].getCarParamsSP();
|
||||
const auto lp_sp = sm["longitudinalPlanSP"].getLongitudinalPlanSP();
|
||||
const auto lmd = sm["liveMapDataSP"].getLiveMapDataSP();
|
||||
|
||||
float speedConv = is_metric ? MS_TO_KPH : MS_TO_MPH;
|
||||
speedLimit = lp_sp.getSpeedLimit().getResolver().getSpeedLimit() * speedConv;
|
||||
speedLimitLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLast() * speedConv;
|
||||
speedLimitOffset = lp_sp.getSpeedLimit().getResolver().getSpeedLimitOffset() * speedConv;
|
||||
speedLimitValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitValid();
|
||||
speedLimitLastValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLastValid();
|
||||
speedLimitFinalLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitFinalLast() * speedConv;
|
||||
speedLimitMode = static_cast<SpeedLimitMode>(s.scene.speed_limit_mode);
|
||||
speedLimitAssistState = lp_sp.getSpeedLimit().getAssist().getState();
|
||||
speedLimitAssistActive = lp_sp.getSpeedLimit().getAssist().getActive();
|
||||
roadName = s.scene.road_name;
|
||||
if (sm.updated("carParams")) {
|
||||
steerControlType = car_params.getSteerControlType();
|
||||
}
|
||||
|
||||
if (sm.updated("carParamsSP")) {
|
||||
pcmCruiseSpeed = car_params_sp.getPcmCruiseSpeed();
|
||||
}
|
||||
|
||||
if (sm.updated("longitudinalPlanSP")) {
|
||||
speedLimit = lp_sp.getSpeedLimit().getResolver().getSpeedLimit() * speedConv;
|
||||
speedLimitLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLast() * speedConv;
|
||||
speedLimitOffset = lp_sp.getSpeedLimit().getResolver().getSpeedLimitOffset() * speedConv;
|
||||
speedLimitValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitValid();
|
||||
speedLimitLastValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLastValid();
|
||||
speedLimitFinalLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitFinalLast() * speedConv;
|
||||
speedLimitSource = lp_sp.getSpeedLimit().getResolver().getSource();
|
||||
speedLimitAssistState = lp_sp.getSpeedLimit().getAssist().getState();
|
||||
speedLimitAssistActive = lp_sp.getSpeedLimit().getAssist().getActive();
|
||||
smartCruiseControlVisionEnabled = lp_sp.getSmartCruiseControl().getVision().getEnabled();
|
||||
smartCruiseControlVisionActive = lp_sp.getSmartCruiseControl().getVision().getActive();
|
||||
smartCruiseControlMapEnabled = lp_sp.getSmartCruiseControl().getMap().getEnabled();
|
||||
smartCruiseControlMapActive = lp_sp.getSmartCruiseControl().getMap().getActive();
|
||||
}
|
||||
greenLightAlert = lp_sp.getE2eAlerts().getGreenLightAlert();
|
||||
leadDepartAlert = lp_sp.getE2eAlerts().getLeadDepartAlert();
|
||||
|
||||
if (sm.updated("liveMapDataSP")) {
|
||||
roadNameStr = QString::fromStdString(lmd.getRoadName());
|
||||
speedLimitAheadValid = lmd.getSpeedLimitAheadValid();
|
||||
@@ -64,7 +86,7 @@ void HudRendererSP::updateState(const UIState &s) {
|
||||
|
||||
static int reverse_delay = 0;
|
||||
bool reverse_allowed = false;
|
||||
if (int(car_state.getGearShifter()) != 4) {
|
||||
if (car_state.getGearShifter() != cereal::CarState::GearShifter::REVERSE) {
|
||||
reverse_delay = 0;
|
||||
reverse_allowed = false;
|
||||
} else {
|
||||
@@ -76,46 +98,47 @@ void HudRendererSP::updateState(const UIState &s) {
|
||||
|
||||
reversing = reverse_allowed;
|
||||
|
||||
if (sm.updated("liveParameters")) {
|
||||
roll = sm["liveParameters"].getLiveParameters().getRoll();
|
||||
}
|
||||
|
||||
if (sm.updated("deviceState")) {
|
||||
memoryUsagePercent = sm["deviceState"].getDeviceState().getMemoryUsagePercent();
|
||||
}
|
||||
|
||||
if (sm.updated(gps_source)) {
|
||||
gpsAccuracy = is_gps_location_external ? gpsLocation.getHorizontalAccuracy() : 1.0; // External reports accuracy, internal does not.
|
||||
altitude = gpsLocation.getAltitude();
|
||||
bearingAccuracyDeg = gpsLocation.getBearingAccuracyDeg();
|
||||
bearingDeg = gpsLocation.getBearingDeg();
|
||||
}
|
||||
|
||||
if (sm.updated("liveTorqueParameters")) {
|
||||
torquedUseParams = ltp.getUseParams();
|
||||
latAccelFactorFiltered = ltp.getLatAccelFactorFiltered();
|
||||
frictionCoefficientFiltered = ltp.getFrictionCoefficientFiltered();
|
||||
liveValid = ltp.getLiveValid();
|
||||
}
|
||||
|
||||
latActive = car_control.getLatActive();
|
||||
actuators = car_control.getActuators();
|
||||
longOverride = car_control.getCruiseControl().getOverride();
|
||||
carControlEnabled = car_control.getEnabled();
|
||||
|
||||
steerOverride = car_state.getSteeringPressed();
|
||||
|
||||
devUiInfo = s.scene.dev_ui_info;
|
||||
|
||||
speedUnit = is_metric ? tr("km/h") : tr("mph");
|
||||
lead_d_rel = radar_state.getLeadOne().getDRel();
|
||||
lead_v_rel = radar_state.getLeadOne().getVRel();
|
||||
lead_status = radar_state.getLeadOne().getStatus();
|
||||
steerControlType = car_params.getSteerControlType();
|
||||
actuators = car_control.getActuators();
|
||||
torqueLateral = steerControlType == cereal::CarParams::SteerControlType::TORQUE;
|
||||
angleSteers = car_state.getSteeringAngleDeg();
|
||||
desiredCurvature = cs.getDesiredCurvature();
|
||||
curvature = cs.getCurvature();
|
||||
roll = sm["liveParameters"].getLiveParameters().getRoll();
|
||||
memoryUsagePercent = sm["deviceState"].getDeviceState().getMemoryUsagePercent();
|
||||
gpsAccuracy = is_gps_location_external ? gpsLocation.getHorizontalAccuracy() : 1.0; // External reports accuracy, internal does not.
|
||||
altitude = gpsLocation.getAltitude();
|
||||
vEgo = car_state.getVEgo();
|
||||
aEgo = car_state.getAEgo();
|
||||
steeringTorqueEps = car_state.getSteeringTorqueEps();
|
||||
bearingAccuracyDeg = gpsLocation.getBearingAccuracyDeg();
|
||||
bearingDeg = gpsLocation.getBearingDeg();
|
||||
torquedUseParams = ltp.getUseParams();
|
||||
latAccelFactorFiltered = ltp.getLatAccelFactorFiltered();
|
||||
frictionCoefficientFiltered = ltp.getFrictionCoefficientFiltered();
|
||||
liveValid = ltp.getLiveValid();
|
||||
|
||||
standstillTimer = s.scene.standstill_timer;
|
||||
isStandstill = car_state.getStandstill();
|
||||
if (not s.scene.started) standstillElapsedTime = 0.0;
|
||||
longOverride = car_control.getCruiseControl().getOverride();
|
||||
smartCruiseControlVisionEnabled = lp_sp.getSmartCruiseControl().getVision().getEnabled();
|
||||
smartCruiseControlVisionActive = lp_sp.getSmartCruiseControl().getVision().getActive();
|
||||
smartCruiseControlMapEnabled = lp_sp.getSmartCruiseControl().getMap().getEnabled();
|
||||
smartCruiseControlMapActive = lp_sp.getSmartCruiseControl().getMap().getActive();
|
||||
|
||||
greenLightAlert = lp_sp.getE2eAlerts().getGreenLightAlert();
|
||||
leadDepartAlert = lp_sp.getE2eAlerts().getLeadDepartAlert();
|
||||
if (!s.scene.started) standstillElapsedTime = 0.0;
|
||||
|
||||
// override stock current speed values
|
||||
float v_ego = (v_ego_cluster_seen && !s.scene.trueVEgoUI) ? car_state.getVEgoCluster() : car_state.getVEgo();
|
||||
@@ -126,10 +149,11 @@ void HudRendererSP::updateState(const UIState &s) {
|
||||
rightBlinkerOn = car_state.getRightBlinker();
|
||||
leftBlindspot = car_state.getLeftBlindspot();
|
||||
rightBlindspot = car_state.getRightBlindspot();
|
||||
showTurnSignals = s.scene.turn_signals;
|
||||
|
||||
carControlEnabled = car_control.getEnabled();
|
||||
speedCluster = car_state.getCruiseState().getSpeedCluster() * speedConv;
|
||||
|
||||
allow_e2e_alerts = sm["selfdriveState"].getSelfdriveState().getAlertSize() == cereal::SelfdriveState::AlertSize::NONE &&
|
||||
sm.rcv_frame("driverStateV2") > s.scene.started_frame && !reversing;
|
||||
}
|
||||
|
||||
void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) {
|
||||
@@ -222,7 +246,7 @@ void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) {
|
||||
drawRoadName(p, surface_rect);
|
||||
|
||||
// Green Light & Lead Depart Alerts
|
||||
if (greenLightAlert or leadDepartAlert) {
|
||||
if (greenLightAlert || leadDepartAlert) {
|
||||
e2eAlertDisplayTimer = 3 * UI_FREQ;
|
||||
// reset onroad sleep timer for e2e alerts
|
||||
uiStateSP()->reset_onroad_sleep_timer();
|
||||
@@ -232,11 +256,11 @@ void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) {
|
||||
e2eAlertFrame++;
|
||||
if (greenLightAlert) {
|
||||
alert_text = tr("GREEN\nLIGHT");
|
||||
alert_img = devUiInfo > 0 ? green_light_alert_small_img : green_light_alert_large_img;
|
||||
alert_img = green_light_alert_img;
|
||||
}
|
||||
else if (leadDepartAlert) {
|
||||
alert_text = tr("LEAD VEHICLE\nDEPARTING");
|
||||
alert_img = devUiInfo > 0 ? lead_depart_alert_small_img : lead_depart_alert_large_img;
|
||||
alert_img = lead_depart_alert_img;
|
||||
}
|
||||
drawE2eAlert(p, surface_rect);
|
||||
}
|
||||
@@ -254,7 +278,7 @@ void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) {
|
||||
// No Alerts displayed
|
||||
else {
|
||||
e2eAlertFrame = 0;
|
||||
if (not isStandstill) standstillElapsedTime = 0.0;
|
||||
if (!isStandstill) standstillElapsedTime = 0.0;
|
||||
}
|
||||
|
||||
// Blinker
|
||||
@@ -545,7 +569,8 @@ void HudRendererSP::drawSpeedLimitSigns(QPainter &p, QRect &sign_rect) {
|
||||
}
|
||||
|
||||
void HudRendererSP::drawUpcomingSpeedLimit(QPainter &p) {
|
||||
bool speed_limit_ahead = speedLimitAheadValid && speedLimitAhead > 0 && speedLimitAhead != speedLimit && speedLimitAheadValidFrame > 0;
|
||||
bool speed_limit_ahead = speedLimitAheadValid && speedLimitAhead > 0 && speedLimitAhead != speedLimit && speedLimitAheadValidFrame > 0 &&
|
||||
speedLimitSource == cereal::LongitudinalPlanSP::SpeedLimit::Source::MAP;
|
||||
if (!speed_limit_ahead) {
|
||||
return;
|
||||
}
|
||||
@@ -639,7 +664,7 @@ void HudRendererSP::drawRoadName(QPainter &p, const QRect &surface_rect) {
|
||||
|
||||
void HudRendererSP::drawSpeedLimitPreActiveArrow(QPainter &p, QRect &sign_rect) {
|
||||
const int sign_margin = 12;
|
||||
const int arrow_spacing = sign_margin * 3;
|
||||
const int arrow_spacing = sign_margin * 1.4;
|
||||
int arrow_x = sign_rect.right() + arrow_spacing;
|
||||
|
||||
int _set_speed = std::nearbyint(set_speed);
|
||||
@@ -689,7 +714,7 @@ void HudRendererSP::drawSetSpeedSP(QPainter &p, const QRect &surface_rect) {
|
||||
}
|
||||
|
||||
// Draw "MAX" or carState.cruiseState.speedCluster (when ICBM is active) text
|
||||
if (carControlEnabled) {
|
||||
if (!pcmCruiseSpeed && carControlEnabled) {
|
||||
if (std::nearbyint(set_speed) != std::nearbyint(speedCluster)) {
|
||||
icbm_active_counter = 3 * UI_FREQ;
|
||||
} else if (icbm_active_counter > 0) {
|
||||
@@ -714,26 +739,26 @@ void HudRendererSP::drawSetSpeedSP(QPainter &p, const QRect &surface_rect) {
|
||||
}
|
||||
|
||||
void HudRendererSP::drawE2eAlert(QPainter &p, const QRect &surface_rect, const QString &alert_alt_text) {
|
||||
int size = devUiInfo > 0 ? e2e_alert_small : e2e_alert_large;
|
||||
int x = surface_rect.center().x() + surface_rect.width() / 4;
|
||||
if (!allow_e2e_alerts) return;
|
||||
|
||||
int x = surface_rect.right() - e2e_alert_size - (devUiInfo > 0 ? 180 : 100) - (UI_BORDER_SIZE * 3);
|
||||
int y = surface_rect.center().y() + 20;
|
||||
x += devUiInfo > 0 ? 0 : 50;
|
||||
QRect alertRect(x - size, y - size, size * 2, size * 2);
|
||||
QRect alertRect(x - e2e_alert_size, y - e2e_alert_size, e2e_alert_size * 2, e2e_alert_size * 2);
|
||||
|
||||
// Alert Circle
|
||||
QPoint center = alertRect.center();
|
||||
QColor frameColor;
|
||||
if (not alert_alt_text.isEmpty()) frameColor = QColor(255, 255, 255, 75);
|
||||
if (!alert_alt_text.isEmpty()) frameColor = QColor(255, 255, 255, 75);
|
||||
else frameColor = pulseElement(e2eAlertFrame) ? QColor(255, 255, 255, 75) : QColor(0, 255, 0, 75);
|
||||
p.setPen(QPen(frameColor, 15));
|
||||
p.setBrush(QColor(0, 0, 0, 190));
|
||||
p.drawEllipse(center, size, size);
|
||||
p.drawEllipse(center, e2e_alert_size, e2e_alert_size);
|
||||
|
||||
// Alert Text
|
||||
QColor txtColor;
|
||||
QFont font;
|
||||
int alert_bottom_adjustment;
|
||||
if (not alert_alt_text.isEmpty()) {
|
||||
if (!alert_alt_text.isEmpty()) {
|
||||
font = InterFont(100, QFont::Bold);
|
||||
alert_bottom_adjustment = 5;
|
||||
txtColor = QColor(255, 255, 255, 255);
|
||||
@@ -750,7 +775,7 @@ void HudRendererSP::drawE2eAlert(QPainter &p, const QRect &surface_rect, const Q
|
||||
textRect.moveBottom(alertRect.bottom() - alertRect.height() / alert_bottom_adjustment);
|
||||
p.drawText(textRect, Qt::AlignCenter, alert_text);
|
||||
|
||||
if (not alert_alt_text.isEmpty()) {
|
||||
if (!alert_alt_text.isEmpty()) {
|
||||
// Alert Alternate Text
|
||||
p.setFont(InterFont(80, QFont::Bold));
|
||||
p.setPen(QColor(255, 175, 3, 240));
|
||||
@@ -779,7 +804,7 @@ void HudRendererSP::drawCurrentSpeedSP(QPainter &p, const QRect &surface_rect) {
|
||||
|
||||
void HudRendererSP::drawBlinker(QPainter &p, const QRect &surface_rect) {
|
||||
const bool hazard = leftBlinkerOn && rightBlinkerOn;
|
||||
int blinkerStatus = hazard ? 2 : (leftBlinkerOn or rightBlinkerOn) ? 1 : 0;
|
||||
int blinkerStatus = hazard ? 2 : (leftBlinkerOn || rightBlinkerOn) ? 1 : 0;
|
||||
|
||||
if (!leftBlinkerOn && !rightBlinkerOn) {
|
||||
blinkerFrameCounter = 0;
|
||||
|
||||
@@ -83,6 +83,7 @@ private:
|
||||
bool speedLimitValid;
|
||||
bool speedLimitLastValid;
|
||||
float speedLimitFinalLast;
|
||||
cereal::LongitudinalPlanSP::SpeedLimit::Source speedLimitSource;
|
||||
bool speedLimitAheadValid;
|
||||
float speedLimitAhead;
|
||||
float speedLimitAheadDistance;
|
||||
@@ -96,16 +97,14 @@ private:
|
||||
int speedLimitAssistFrame;
|
||||
QPixmap plus_arrow_up_img;
|
||||
QPixmap minus_arrow_down_img;
|
||||
int e2e_alert_small = 250;
|
||||
int e2e_alert_large = 300;
|
||||
QPixmap green_light_alert_small_img;
|
||||
QPixmap green_light_alert_large_img;
|
||||
int e2e_alert_size = 250;
|
||||
QPixmap green_light_alert_img;
|
||||
bool greenLightAlert;
|
||||
int e2eAlertFrame;
|
||||
int e2eAlertDisplayTimer = 0;
|
||||
bool allow_e2e_alerts;
|
||||
bool leadDepartAlert;
|
||||
QPixmap lead_depart_alert_small_img;
|
||||
QPixmap lead_depart_alert_large_img;
|
||||
QPixmap lead_depart_alert_img;
|
||||
QString alert_text;
|
||||
QPixmap alert_img;
|
||||
bool hideVEgoUI;
|
||||
@@ -120,4 +119,5 @@ private:
|
||||
bool carControlEnabled;
|
||||
float speedCluster = 0;
|
||||
int icbm_active_counter = 0;
|
||||
bool pcmCruiseSpeed = true;
|
||||
};
|
||||
|
||||
@@ -21,74 +21,73 @@ void ModelRendererSP::update_model(const cereal::ModelDataV2::Reader &model, con
|
||||
mapLineToPolygon(model.getLaneLines()[2], 0.2, -0.05, &right_blindspot_vertices, max_idx_barrier);
|
||||
}
|
||||
|
||||
void ModelRendererSP::drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, const QRect &surface_rect) {
|
||||
void ModelRendererSP::draw(QPainter &painter, const QRect &surface_rect) {
|
||||
auto *s = uiState();
|
||||
auto &sm = *(s->sm);
|
||||
bool blindspot = s->scene.blindspot_ui;
|
||||
|
||||
if (blindspot) {
|
||||
bool left_blindspot = sm["carState"].getCarState().getLeftBlindspot();
|
||||
bool right_blindspot = sm["carState"].getCarState().getRightBlindspot();
|
||||
|
||||
//painter.setBrush(QColor::fromRgbF(1.0, 0.0, 0.0, 0.4)); // Red with alpha for blind spot
|
||||
|
||||
if (left_blindspot && !left_blindspot_vertices.isEmpty()) {
|
||||
QLinearGradient gradient(0, 0, surface_rect.width(), 0); // Horizontal gradient from left to right
|
||||
gradient.setColorAt(0.0, QColor(255, 165, 0, 102)); // Orange with alpha
|
||||
gradient.setColorAt(1.0, QColor(255, 255, 0, 102)); // Yellow with alpha
|
||||
painter.setBrush(gradient);
|
||||
painter.drawPolygon(left_blindspot_vertices);
|
||||
}
|
||||
|
||||
if (right_blindspot && !right_blindspot_vertices.isEmpty()) {
|
||||
QLinearGradient gradient(surface_rect.width(), 0, 0, 0); // Horizontal gradient from right to left
|
||||
gradient.setColorAt(0.0, QColor(255, 165, 0, 102)); // Orange with alpha
|
||||
gradient.setColorAt(1.0, QColor(255, 255, 0, 102)); // Yellow with alpha
|
||||
painter.setBrush(gradient);
|
||||
painter.drawPolygon(right_blindspot_vertices);
|
||||
}
|
||||
if (sm.rcv_frame("liveCalibration") < s->scene.started_frame ||
|
||||
sm.rcv_frame("modelV2") < s->scene.started_frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool rainbow = s->scene.rainbow_mode;
|
||||
//float v_ego = sm["carState"].getCarState().getVEgo();
|
||||
clip_region = surface_rect.adjusted(-CLIP_MARGIN, -CLIP_MARGIN, CLIP_MARGIN, CLIP_MARGIN);
|
||||
experimental_mode = sm["selfdriveState"].getSelfdriveState().getExperimentalMode();
|
||||
longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl();
|
||||
path_offset_z = sm["liveCalibration"].getLiveCalibration().getHeight()[0];
|
||||
|
||||
if (rainbow) {
|
||||
// Simple time-based animation
|
||||
float time_offset = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch()).count() / 1000.0f;
|
||||
painter.save();
|
||||
|
||||
// simple linear gradient from bottom to top
|
||||
QLinearGradient bg(0, surface_rect.height(), 0, 0);
|
||||
const auto &model = sm["modelV2"].getModelV2();
|
||||
const auto &radar_state = sm["radarState"].getRadarState();
|
||||
const auto &lead_one = radar_state.getLeadOne();
|
||||
const auto &car_state = sm["carState"].getCarState();
|
||||
|
||||
// evenly spaced colors across the spectrum
|
||||
// The animation shifts the entire spectrum smoothly
|
||||
float animation_speed = 40.0f; // speed vroom vroom
|
||||
float hue_offset = fmod(time_offset * animation_speed, 360.0f);
|
||||
update_model(model, lead_one);
|
||||
drawLaneLines(painter);
|
||||
|
||||
// 6-8 color stops for smooth transitions more color makes it laggy
|
||||
const int num_stops = 7;
|
||||
for (int i = 0; i < num_stops; i++) {
|
||||
float position = static_cast<float>(i) / (num_stops - 1);
|
||||
|
||||
float hue = fmod(hue_offset + position * 360.0f, 360.0f);
|
||||
float saturation = 0.9f;
|
||||
float lightness = 0.6f;
|
||||
|
||||
// Alpha fades out towards the far end of the path
|
||||
float alpha = 0.8f * (1.0f - position * 0.3f);
|
||||
|
||||
QColor color = QColor::fromHslF(hue / 360.0f, saturation, lightness, alpha);
|
||||
bg.setColorAt(position, color);
|
||||
}
|
||||
|
||||
painter.setBrush(bg);
|
||||
painter.drawPolygon(track_vertices);
|
||||
if (s->scene.rainbow_mode) {
|
||||
drawRainbowPath(painter, surface_rect);
|
||||
} else {
|
||||
// Normal path rendering
|
||||
ModelRenderer::drawPath(painter, model, surface_rect.height());
|
||||
}
|
||||
|
||||
if (longitudinal_control && sm.alive("radarState")) {
|
||||
update_leads(radar_state, model.getPosition());
|
||||
const auto &lead_two = radar_state.getLeadTwo();
|
||||
if (lead_one.getStatus()) {
|
||||
drawLead(painter, lead_one, lead_vertices[0], surface_rect);
|
||||
}
|
||||
if (lead_two.getStatus() && (std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0)) {
|
||||
drawLead(painter, lead_two, lead_vertices[1], surface_rect);
|
||||
}
|
||||
}
|
||||
|
||||
if (s->scene.blindspot_ui) {
|
||||
const bool left_blindspot = car_state.getLeftBlindspot();
|
||||
const bool right_blindspot = car_state.getRightBlindspot();
|
||||
drawBlindspot(painter, surface_rect, left_blindspot, right_blindspot);
|
||||
}
|
||||
drawLeadStatus(painter, surface_rect.height(), surface_rect.width());
|
||||
|
||||
painter.restore();
|
||||
}
|
||||
|
||||
void ModelRendererSP::drawBlindspot(QPainter &painter, const QRect &surface_rect, bool left_blindspot, bool right_blindspot) {
|
||||
if (left_blindspot && !left_blindspot_vertices.isEmpty()) {
|
||||
QLinearGradient gradient(0, 0, surface_rect.width(), 0); // Horizontal gradient from left to right
|
||||
gradient.setColorAt(0.0, QColor(255, 165, 0, 102)); // Orange with alpha
|
||||
gradient.setColorAt(1.0, QColor(255, 255, 0, 102)); // Yellow with alpha
|
||||
painter.setBrush(gradient);
|
||||
painter.drawPolygon(left_blindspot_vertices);
|
||||
}
|
||||
|
||||
if (right_blindspot && !right_blindspot_vertices.isEmpty()) {
|
||||
QLinearGradient gradient(surface_rect.width(), 0, 0, 0); // Horizontal gradient from right to left
|
||||
gradient.setColorAt(0.0, QColor(255, 165, 0, 102)); // Orange with alpha
|
||||
gradient.setColorAt(1.0, QColor(255, 255, 0, 102)); // Yellow with alpha
|
||||
painter.setBrush(gradient);
|
||||
painter.drawPolygon(right_blindspot_vertices);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelRendererSP::drawLeadStatus(QPainter &painter, int height, int width) {
|
||||
@@ -121,19 +120,16 @@ void ModelRendererSP::drawLeadStatus(QPainter &painter, int height, int width) {
|
||||
}
|
||||
|
||||
if (has_lead_one) {
|
||||
drawLeadStatusAtPosition(painter, lead_one, lead_vertices[0], height, width, "L1");
|
||||
drawLeadStatusPosition(painter, lead_one, lead_vertices[0], height, width);
|
||||
}
|
||||
|
||||
if (has_lead_two && std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0) {
|
||||
drawLeadStatusAtPosition(painter, lead_two, lead_vertices[1], height, width, "L2");
|
||||
drawLeadStatusPosition(painter, lead_two, lead_vertices[1], height, width);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelRendererSP::drawLeadStatusAtPosition(QPainter &painter,
|
||||
const cereal::RadarState::LeadData::Reader &lead_data,
|
||||
const QPointF &chevron_pos,
|
||||
int height, int width,
|
||||
const QString &label) {
|
||||
void ModelRendererSP::drawLeadStatusPosition(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data,
|
||||
const QPointF &chevron_pos, int height, int width) {
|
||||
float d_rel = lead_data.getDRel();
|
||||
float v_rel = lead_data.getVRel();
|
||||
auto *s = uiState();
|
||||
@@ -223,3 +219,36 @@ void ModelRendererSP::drawLeadStatusAtPosition(QPainter &painter,
|
||||
|
||||
painter.setPen(Qt::NoPen);
|
||||
}
|
||||
|
||||
void ModelRendererSP::drawRainbowPath(QPainter &painter, const QRect &surface_rect) {
|
||||
// Simple time-based animation
|
||||
float time_offset = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch()).count() / 1000.0f;
|
||||
|
||||
// simple linear gradient from bottom to top
|
||||
QLinearGradient bg(0, surface_rect.height(), 0, 0);
|
||||
|
||||
// evenly spaced colors across the spectrum
|
||||
// The animation shifts the entire spectrum smoothly
|
||||
float animation_speed = 40.0f; // speed vroom vroom
|
||||
float hue_offset = fmod(time_offset * animation_speed, 360.0f);
|
||||
|
||||
// 6-8 color stops for smooth transitions more color makes it laggy
|
||||
const int num_stops = 7;
|
||||
for (int i = 0; i < num_stops; i++) {
|
||||
float position = static_cast<float>(i) / (num_stops - 1);
|
||||
|
||||
float hue = fmod(hue_offset + position * 360.0f, 360.0f);
|
||||
float saturation = 0.9f;
|
||||
float lightness = 0.6f;
|
||||
|
||||
// Alpha fades out towards the far end of the path
|
||||
float alpha = 0.8f * (1.0f - position * 0.3f);
|
||||
|
||||
QColor color = QColor::fromHslF(hue / 360.0f, saturation, lightness, alpha);
|
||||
bg.setColorAt(position, color);
|
||||
}
|
||||
|
||||
painter.setBrush(bg);
|
||||
painter.drawPolygon(track_vertices);
|
||||
}
|
||||
|
||||
@@ -13,17 +13,15 @@ class ModelRendererSP : public ModelRenderer {
|
||||
public:
|
||||
ModelRendererSP() = default;
|
||||
|
||||
void draw(QPainter &painter, const QRect &surface_rect);
|
||||
|
||||
private:
|
||||
void update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead) override;
|
||||
void drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, const QRect &rect) override;
|
||||
|
||||
// Lead status display methods
|
||||
void drawLeadStatus(QPainter &painter, int height, int width);
|
||||
void drawLeadStatusAtPosition(QPainter &painter,
|
||||
const cereal::RadarState::LeadData::Reader &lead_data,
|
||||
const QPointF &chevron_pos,
|
||||
int height, int width,
|
||||
const QString &label);
|
||||
void drawLeadStatusPosition(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data,
|
||||
const QPointF &chevron_pos, int height, int width);
|
||||
void drawBlindspot(QPainter &painter, const QRect &surface_rect, bool left_blindspot, bool right_blindspot);
|
||||
void drawRainbowPath(QPainter &painter, const QRect &surface_rect);
|
||||
|
||||
QPolygonF left_blindspot_vertices;
|
||||
QPolygonF right_blindspot_vertices;
|
||||
|
||||
@@ -122,3 +122,7 @@ std::optional<cereal::Event::Reader> loadCerealEvent(Params& params, const std::
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasIntelligentCruiseButtonManagement(const cereal::CarParamsSP::Reader &car_params_sp) {
|
||||
return car_params_sp.getIntelligentCruiseButtonManagementAvailable() && Params().getBool("IntelligentCruiseButtonManagement");
|
||||
}
|
||||
|
||||
@@ -23,3 +23,4 @@ std::optional<QString> getParamIgnoringDefault(const std::string ¶m_name, co
|
||||
QMap<QString, QVariantMap> loadPlatformList();
|
||||
QStringList searchFromList(const QString &query, const QStringList &list);
|
||||
std::optional<cereal::Event::Reader> loadCerealEvent(Params& params, const std::string& _param);
|
||||
bool hasIntelligentCruiseButtonManagement(const cereal::CarParamsSP::Reader &car_params_sp);
|
||||
|
||||
@@ -29,7 +29,7 @@ UIStateSP::UIStateSP(QObject *parent) : UIState(parent) {
|
||||
"wideRoadCameraState", "managerState", "selfdriveState", "longitudinalPlan",
|
||||
"modelManagerSP", "selfdriveStateSP", "longitudinalPlanSP", "backupManagerSP",
|
||||
"carControl", "gpsLocationExternal", "gpsLocation", "liveTorqueParameters",
|
||||
"carStateSP", "liveParameters", "liveMapDataSP"
|
||||
"carStateSP", "liveParameters", "liveMapDataSP", "carParamsSP"
|
||||
});
|
||||
|
||||
// update timer
|
||||
|
||||
@@ -1778,62 +1778,6 @@ Warning: You are on a metered connection!</source>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>None</source>
|
||||
<translation>없음</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fixed</source>
|
||||
<translation>고정</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Percent</source>
|
||||
<translation>비율</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Car
|
||||
Only</source>
|
||||
<translation>차량만</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Map
|
||||
Only</source>
|
||||
<translation>지도만</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Car
|
||||
First</source>
|
||||
<translation>차량
|
||||
우선</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Map
|
||||
First</source>
|
||||
<translation>지도
|
||||
우선</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Combined
|
||||
Data</source>
|
||||
<translation>결합
|
||||
데이터</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Off</source>
|
||||
<translation>끄기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Information</source>
|
||||
<translation>정보</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning</source>
|
||||
<translation>경고</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Assist</source>
|
||||
<translation>보조</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindow</name>
|
||||
@@ -2198,6 +2142,34 @@ Data</source>
|
||||
<source>⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps</source>
|
||||
<translation>⦿ 결합: 차량 및 OpenStreetMaps의 속도 제한 결합 데이터 사용</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Car
|
||||
Only</source>
|
||||
<translation>차량만</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Map
|
||||
Only</source>
|
||||
<translation>지도만</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Car
|
||||
First</source>
|
||||
<translation>차량
|
||||
우선</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Map
|
||||
First</source>
|
||||
<translation>지도
|
||||
우선</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Combined
|
||||
Data</source>
|
||||
<translation>결합
|
||||
데이터</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SpeedLimitSettings</name>
|
||||
@@ -2245,6 +2217,34 @@ Data</source>
|
||||
<source>⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons.</source>
|
||||
<translation>⦿ 보조: +/- 버튼을 조작할 때 현재 도로의 제한 속도를 기준으로 차량의 크루즈 속도를 조정합니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>None</source>
|
||||
<translation>없음</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fixed</source>
|
||||
<translation>고정</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Percent</source>
|
||||
<translation>비율</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Off</source>
|
||||
<translation>끄기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Information</source>
|
||||
<translation>정보</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning</source>
|
||||
<translation>경고</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Assist</source>
|
||||
<translation>보조</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
|
||||
@@ -5,6 +5,7 @@ This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
|
||||
from enum import IntEnum
|
||||
import hashlib
|
||||
|
||||
PARAMS_UPDATE_PERIOD = 3 # seconds
|
||||
@@ -16,3 +17,23 @@ def get_file_hash(path: str) -> str:
|
||||
for byte_block in iter(lambda: f.read(4096), b""):
|
||||
sha256_hash.update(byte_block)
|
||||
return sha256_hash.hexdigest()
|
||||
|
||||
|
||||
class IntEnumBase(IntEnum):
|
||||
@classmethod
|
||||
def min(cls):
|
||||
return min(cls)
|
||||
|
||||
@classmethod
|
||||
def max(cls):
|
||||
return max(cls)
|
||||
|
||||
|
||||
def get_sanitize_int_param(key: str, min_val: int, max_val: int, params) -> int:
|
||||
val: int = params.get(key, return_default=True)
|
||||
clipped_val = max(min_val, min(max_val, val))
|
||||
|
||||
if clipped_val != val:
|
||||
params.put(key, clipped_val)
|
||||
|
||||
return clipped_val
|
||||
|
||||
@@ -8,8 +8,12 @@ from abc import abstractmethod, ABC
|
||||
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.constants import CV
|
||||
from openpilot.selfdrive.car.cruise import V_CRUISE_UNSET
|
||||
from openpilot.sunnypilot.navd.helpers import coordinate_from_param
|
||||
|
||||
MAX_SPEED_LIMIT = V_CRUISE_UNSET * CV.KPH_TO_MS
|
||||
|
||||
|
||||
class BaseMapData(ABC):
|
||||
def __init__(self):
|
||||
@@ -46,9 +50,9 @@ class BaseMapData(ABC):
|
||||
mapd_sp_send.valid = self.sm['liveLocationKalman'].gpsOK
|
||||
live_map_data = mapd_sp_send.liveMapDataSP
|
||||
|
||||
live_map_data.speedLimitValid = bool(speed_limit > 0)
|
||||
live_map_data.speedLimitValid = bool(MAX_SPEED_LIMIT > speed_limit > 0)
|
||||
live_map_data.speedLimit = speed_limit
|
||||
live_map_data.speedLimitAheadValid = bool(next_speed_limit > 0)
|
||||
live_map_data.speedLimitAheadValid = bool(MAX_SPEED_LIMIT > next_speed_limit > 0)
|
||||
live_map_data.speedLimitAhead = next_speed_limit
|
||||
live_map_data.speedLimitAheadDistance = next_speed_limit_distance
|
||||
live_map_data.roadName = self.get_current_road_name()
|
||||
|
||||
@@ -11,6 +11,7 @@ from opendbc.car.interfaces import CarInterfaceBase
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.nnlc.helpers import get_nn_model_path
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.common import Mode as SpeedLimitMode
|
||||
|
||||
import openpilot.system.sentry as sentry
|
||||
|
||||
@@ -66,6 +67,30 @@ def _initialize_torque_lateral_control(CI: CarInterfaceBase, CP: structs.CarPara
|
||||
CI.configure_torque_tune(CP.carFingerprint, CP.lateralTuning)
|
||||
|
||||
|
||||
def _cleanup_unsupported_params(CP: structs.CarParams, CP_SP: structs.CarParamsSP, params: Params = None) -> None:
|
||||
if params is None:
|
||||
params = Params()
|
||||
|
||||
if CP.steerControlType == structs.CarParams.SteerControlType.angle:
|
||||
cloudlog.warning("SteerControlType is angle, cleaning up params")
|
||||
params.remove("NeuralNetworkLateralControl")
|
||||
params.remove("EnforceTorqueControl")
|
||||
|
||||
if not CP_SP.intelligentCruiseButtonManagementAvailable or CP.openpilotLongitudinalControl:
|
||||
cloudlog.warning("ICBM not available or openpilot Longitudinal Control enabled, cleaning up params")
|
||||
params.remove("IntelligentCruiseButtonManagement")
|
||||
|
||||
if not CP.openpilotLongitudinalControl and CP_SP.pcmCruiseSpeed:
|
||||
cloudlog.warning("openpilot Longitudinal Control and ICBM not available, cleaning up params")
|
||||
params.remove("DynamicExperimentalControl")
|
||||
params.remove("CustomAccIncrementsEnabled")
|
||||
params.remove("SmartCruiseControlVision")
|
||||
params.remove("SmartCruiseControlMap")
|
||||
|
||||
if params.get("SpeedLimitMode", return_default=True) == SpeedLimitMode.assist:
|
||||
params.put("SpeedLimitMode", int(SpeedLimitMode.warning))
|
||||
|
||||
|
||||
def setup_interfaces(CI: CarInterfaceBase, params: Params = None) -> None:
|
||||
CP = CI.CP
|
||||
CP_SP = CI.CP_SP
|
||||
@@ -74,6 +99,7 @@ def setup_interfaces(CI: CarInterfaceBase, params: Params = None) -> None:
|
||||
nnlc_enabled = _initialize_neural_network_lateral_control(CP, CP_SP, params)
|
||||
_initialize_intelligent_cruise_button_management(CP, CP_SP, params)
|
||||
_initialize_torque_lateral_control(CI, CP, enforce_torque, nnlc_enabled)
|
||||
_cleanup_unsupported_params(CP, CP_SP)
|
||||
|
||||
|
||||
def initialize_params(params) -> list[dict[str, Any]]:
|
||||
@@ -84,4 +110,10 @@ def initialize_params(params) -> list[dict[str, Any]]:
|
||||
"HyundaiLongitudinalTuning"
|
||||
])
|
||||
|
||||
# subaru
|
||||
keys.extend([
|
||||
"SubaruStopAndGo",
|
||||
"SubaruStopAndGoManualParkingBrake",
|
||||
])
|
||||
|
||||
return [{k: params.get(k, return_default=True)} for k in keys]
|
||||
|
||||
@@ -12,47 +12,159 @@ from openpilot.common.realtime import DT_MDL
|
||||
from openpilot.sunnypilot import PARAMS_UPDATE_PERIOD
|
||||
from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
|
||||
|
||||
TRIGGER_THRESHOLD = 30
|
||||
GREEN_LIGHT_X_THRESHOLD = 30
|
||||
LEAD_DEPART_DIST_THRESHOLD = 1.0
|
||||
TRIGGER_TIMER_THRESHOLD = 0.3
|
||||
|
||||
|
||||
class E2EStates:
|
||||
INACTIVE = 0
|
||||
ARMED = 1
|
||||
CONSUMED = 2
|
||||
|
||||
|
||||
class E2EAlertsHelper:
|
||||
def __init__(self):
|
||||
self._params = Params()
|
||||
self._frame = -1
|
||||
self.frame = -1
|
||||
self.green_light_state = E2EStates.INACTIVE
|
||||
self.prev_green_light_state = E2EStates.INACTIVE
|
||||
self.lead_depart_state = E2EStates.INACTIVE
|
||||
self.prev_lead_depart_state = E2EStates.INACTIVE
|
||||
|
||||
self.green_light_alert = False
|
||||
self.green_light_alert_enabled = self._params.get_bool("GreenLightAlert")
|
||||
self.lead_depart_alert = False
|
||||
self.lead_depart_alert_enabled = self._params.get_bool("LeadDepartAlert")
|
||||
|
||||
self.green_light_trigger_timer = 0
|
||||
self.lead_depart_trigger_timer = 0
|
||||
self.last_lead_distance = -1
|
||||
self.last_moving_frame = -1
|
||||
|
||||
self.allowed = False
|
||||
self.last_allowed = False
|
||||
self.has_lead = False
|
||||
|
||||
self.lead_depart_arm_timer = 0
|
||||
self.lead_depart_confirmed_lead = False
|
||||
self.lead_depart_armed = False
|
||||
|
||||
def _read_params(self) -> None:
|
||||
if self._frame % int(PARAMS_UPDATE_PERIOD / DT_MDL) == 0:
|
||||
if self.frame % int(PARAMS_UPDATE_PERIOD / DT_MDL) == 0:
|
||||
self.green_light_alert_enabled = self._params.get_bool("GreenLightAlert")
|
||||
self.lead_depart_alert_enabled = self._params.get_bool("LeadDepartAlert")
|
||||
|
||||
self._frame += 1
|
||||
|
||||
def update(self, sm: messaging.SubMaster, events_sp: EventsSP) -> None:
|
||||
self._read_params()
|
||||
|
||||
if not (self.green_light_alert_enabled or self.lead_depart_alert_enabled):
|
||||
return
|
||||
|
||||
def update_alert_trigger(self, sm: messaging.SubMaster):
|
||||
CS = sm['carState']
|
||||
CC = sm['carControl']
|
||||
|
||||
model_x = sm['modelV2'].position.x
|
||||
max_idx = len(model_x) - 1
|
||||
has_lead = sm['radarState'].leadOne.status
|
||||
lead_vRel: float = sm['radarState'].leadOne.vRel
|
||||
self.has_lead = sm['radarState'].leadOne.status
|
||||
lead_dRel = sm['radarState'].leadOne.dRel
|
||||
|
||||
# Green light alert
|
||||
self.green_light_alert = (self.green_light_alert_enabled and model_x[max_idx] > TRIGGER_THRESHOLD
|
||||
and not has_lead and CS.standstill and not CS.gasPressed and not CC.enabled)
|
||||
standstill = CS.standstill
|
||||
moving = not standstill and CS.vEgo > 0.1
|
||||
|
||||
if moving:
|
||||
self.last_moving_frame = self.frame
|
||||
recent_moving = self.last_moving_frame == -1 or (self.frame - self.last_moving_frame) * DT_MDL < 2.0
|
||||
|
||||
self.allowed = not moving and not CS.gasPressed and not CC.enabled and not recent_moving
|
||||
|
||||
# Green Light Alert
|
||||
green_light_trigger = False
|
||||
if self.green_light_state == E2EStates.ARMED:
|
||||
if model_x[max_idx] > GREEN_LIGHT_X_THRESHOLD:
|
||||
self.green_light_trigger_timer += 1
|
||||
else:
|
||||
self.green_light_trigger_timer = 0
|
||||
|
||||
if self.green_light_trigger_timer * DT_MDL > TRIGGER_TIMER_THRESHOLD:
|
||||
green_light_trigger = True
|
||||
elif self.green_light_state != E2EStates.ARMED:
|
||||
self.green_light_trigger_timer = 0
|
||||
|
||||
# Lead Departure Alert
|
||||
self.lead_depart_alert = (self.lead_depart_alert_enabled and CS.standstill and model_x[max_idx] > 30
|
||||
and has_lead and lead_vRel > 1 and not CS.gasPressed)
|
||||
close_lead_valid = self.has_lead and lead_dRel < 8.0
|
||||
if self.allowed and not self.last_allowed and close_lead_valid:
|
||||
self.lead_depart_confirmed_lead = True
|
||||
elif not self.allowed:
|
||||
self.lead_depart_confirmed_lead = False
|
||||
|
||||
if self.allowed and self.lead_depart_confirmed_lead and close_lead_valid:
|
||||
self.lead_depart_arm_timer += 1
|
||||
|
||||
if self.lead_depart_arm_timer * DT_MDL >= 1.0:
|
||||
self.lead_depart_armed = True
|
||||
else:
|
||||
self.lead_depart_arm_timer = 0
|
||||
self.lead_depart_armed = False
|
||||
|
||||
lead_depart_trigger = False
|
||||
if self.lead_depart_state == E2EStates.ARMED:
|
||||
if self.last_lead_distance == -1 or lead_dRel < self.last_lead_distance:
|
||||
self.last_lead_distance = lead_dRel
|
||||
|
||||
if self.last_lead_distance != -1 and (lead_dRel - self.last_lead_distance > LEAD_DEPART_DIST_THRESHOLD):
|
||||
self.lead_depart_trigger_timer += 1
|
||||
else:
|
||||
self.lead_depart_trigger_timer = 0
|
||||
|
||||
if self.lead_depart_trigger_timer * DT_MDL > TRIGGER_TIMER_THRESHOLD:
|
||||
lead_depart_trigger = True
|
||||
elif self.lead_depart_state != E2EStates.ARMED:
|
||||
self.last_lead_distance = -1
|
||||
self.lead_depart_trigger_timer = 0
|
||||
|
||||
self.last_allowed = self.allowed
|
||||
|
||||
return green_light_trigger, lead_depart_trigger
|
||||
|
||||
@staticmethod
|
||||
def update_state_machine(state: int, enabled: bool, allowed: bool, triggered: bool) -> tuple[int, bool]:
|
||||
if state != E2EStates.INACTIVE:
|
||||
if not allowed or not enabled:
|
||||
state = E2EStates.INACTIVE
|
||||
|
||||
else:
|
||||
if state == E2EStates.ARMED:
|
||||
if triggered:
|
||||
state = E2EStates.CONSUMED
|
||||
|
||||
elif state == E2EStates.CONSUMED:
|
||||
pass
|
||||
|
||||
elif state == E2EStates.INACTIVE:
|
||||
if allowed and enabled:
|
||||
state = E2EStates.ARMED
|
||||
|
||||
return state, triggered
|
||||
|
||||
def update(self, sm: messaging.SubMaster, events_sp: EventsSP) -> None:
|
||||
self._read_params()
|
||||
|
||||
green_light_trigger, lead_depart_trigger = self.update_alert_trigger(sm)
|
||||
|
||||
self.prev_green_light_state = self.green_light_state
|
||||
self.prev_lead_depart_state = self.lead_depart_state
|
||||
|
||||
self.green_light_state, self.green_light_alert = self.update_state_machine(
|
||||
self.green_light_state,
|
||||
self.green_light_alert_enabled,
|
||||
self.allowed and not self.has_lead,
|
||||
green_light_trigger
|
||||
)
|
||||
|
||||
self.lead_depart_state, self.lead_depart_alert = self.update_state_machine(
|
||||
self.lead_depart_state,
|
||||
self.lead_depart_alert_enabled,
|
||||
self.allowed and self.lead_depart_armed,
|
||||
lead_depart_trigger
|
||||
)
|
||||
|
||||
if self.green_light_alert or self.lead_depart_alert:
|
||||
events_sp.add(custom.OnroadEventSP.EventName.e2eChime)
|
||||
|
||||
self.frame += 1
|
||||
|
||||
@@ -9,13 +9,15 @@ from cereal import custom
|
||||
from openpilot.common.constants import CV
|
||||
from openpilot.common.params import Params
|
||||
|
||||
TurnDirection = custom.ModelDataV2SP.TurnDirection
|
||||
|
||||
LANE_CHANGE_SPEED_MIN = 20 * CV.MPH_TO_MS
|
||||
|
||||
|
||||
class LaneTurnController:
|
||||
def __init__(self, desire_helper):
|
||||
self.DH = desire_helper
|
||||
self.turn_direction = custom.TurnDirection.none
|
||||
self.turn_direction = TurnDirection.none
|
||||
self.params = Params()
|
||||
self.lane_turn_value = float(self.params.get("LaneTurnValue", return_default=True)) * CV.MPH_TO_MS
|
||||
self.param_read_counter = 0
|
||||
@@ -33,13 +35,13 @@ class LaneTurnController:
|
||||
|
||||
def update_lane_turn(self, blindspot_left: bool, blindspot_right: bool, left_blinker: bool, right_blinker: bool, v_ego: float) -> None:
|
||||
if left_blinker and not right_blinker and v_ego < self.lane_turn_value and not blindspot_left:
|
||||
self.turn_direction = custom.TurnDirection.turnLeft
|
||||
self.turn_direction = TurnDirection.turnLeft
|
||||
elif right_blinker and not left_blinker and v_ego < self.lane_turn_value and not blindspot_right:
|
||||
self.turn_direction = custom.TurnDirection.turnRight
|
||||
self.turn_direction = TurnDirection.turnRight
|
||||
else:
|
||||
self.turn_direction = custom.TurnDirection.none
|
||||
self.turn_direction = TurnDirection.none
|
||||
|
||||
def get_turn_direction(self):
|
||||
if not self.enabled:
|
||||
return custom.TurnDirection.none
|
||||
return TurnDirection.none
|
||||
return self.turn_direction
|
||||
|
||||
@@ -4,10 +4,11 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
from enum import IntEnum
|
||||
|
||||
from openpilot.sunnypilot import IntEnumBase
|
||||
|
||||
|
||||
class Policy(IntEnum):
|
||||
class Policy(IntEnumBase):
|
||||
car_state_only = 0
|
||||
map_data_only = 1
|
||||
car_state_priority = 2
|
||||
@@ -15,13 +16,13 @@ class Policy(IntEnum):
|
||||
combined = 4
|
||||
|
||||
|
||||
class OffsetType(IntEnum):
|
||||
class OffsetType(IntEnumBase):
|
||||
off = 0
|
||||
fixed = 1
|
||||
percentage = 2
|
||||
|
||||
|
||||
class Mode(IntEnum):
|
||||
class Mode(IntEnumBase):
|
||||
off = 0
|
||||
information = 1
|
||||
warning = 2
|
||||
|
||||
@@ -27,7 +27,11 @@ ACTIVE_STATES = (SpeedLimitAssistState.active, SpeedLimitAssistState.adapting)
|
||||
ENABLED_STATES = (SpeedLimitAssistState.preActive, SpeedLimitAssistState.pending, *ACTIVE_STATES)
|
||||
|
||||
DISABLED_GUARD_PERIOD = 0.5 # secs.
|
||||
PRE_ACTIVE_GUARD_PERIOD = 15 # secs. Time to wait after activation before considering temp deactivation signal.
|
||||
# secs. Time to wait after activation before considering temp deactivation signal.
|
||||
PRE_ACTIVE_GUARD_PERIOD = {
|
||||
True: 15,
|
||||
False: 5,
|
||||
}
|
||||
SPEED_LIMIT_CHANGED_HOLD_PERIOD = 1 # secs. Time to wait after speed limit change before switching to preActive.
|
||||
|
||||
LIMIT_MIN_ACC = -1.5 # m/s^2 Maximum deceleration allowed for limit controllers to provide.
|
||||
@@ -109,6 +113,16 @@ class SpeedLimitAssist:
|
||||
def target_set_speed_confirmed(self) -> bool:
|
||||
return bool(self.v_cruise_cluster_conv == self.target_set_speed_conv)
|
||||
|
||||
@property
|
||||
def v_cruise_cluster_below_confirm_speed_threshold(self) -> bool:
|
||||
return bool(self.v_cruise_cluster_conv < CONFIRM_SPEED_THRESHOLD[self.is_metric])
|
||||
|
||||
def update_active_event(self, events_sp: EventsSP) -> None:
|
||||
if self.v_cruise_cluster_below_confirm_speed_threshold:
|
||||
events_sp.add(EventNameSP.speedLimitChanged)
|
||||
else:
|
||||
events_sp.add(EventNameSP.speedLimitActive)
|
||||
|
||||
def get_v_target_from_control(self) -> float:
|
||||
if self._has_speed_limit:
|
||||
if self.pcm_op_long and self.is_enabled:
|
||||
@@ -175,7 +189,7 @@ class SpeedLimitAssist:
|
||||
@property
|
||||
def apply_confirm_speed_threshold(self) -> bool:
|
||||
# below CST: always require user confirmation
|
||||
if self.v_cruise_cluster_conv < CONFIRM_SPEED_THRESHOLD[self.is_metric]:
|
||||
if self.v_cruise_cluster_below_confirm_speed_threshold:
|
||||
return True
|
||||
|
||||
# at/above CST:
|
||||
@@ -231,7 +245,7 @@ class SpeedLimitAssist:
|
||||
self.state = SpeedLimitAssistState.inactive
|
||||
elif self.speed_limit_changed and self.apply_confirm_speed_threshold:
|
||||
self.state = SpeedLimitAssistState.preActive
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL)
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL)
|
||||
elif self._has_speed_limit and self.v_offset < LIMIT_SPEED_OFFSET_TH:
|
||||
self.state = SpeedLimitAssistState.adapting
|
||||
|
||||
@@ -241,7 +255,7 @@ class SpeedLimitAssist:
|
||||
self.state = SpeedLimitAssistState.inactive
|
||||
elif self.speed_limit_changed and self.apply_confirm_speed_threshold:
|
||||
self.state = SpeedLimitAssistState.preActive
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL)
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL)
|
||||
elif self.v_offset >= LIMIT_SPEED_OFFSET_TH:
|
||||
self.state = SpeedLimitAssistState.active
|
||||
|
||||
@@ -251,7 +265,7 @@ class SpeedLimitAssist:
|
||||
self._update_confirmed_state()
|
||||
elif self.speed_limit_changed:
|
||||
self.state = SpeedLimitAssistState.preActive
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL)
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL)
|
||||
|
||||
# PRE_ACTIVE
|
||||
elif self.state == SpeedLimitAssistState.preActive:
|
||||
@@ -277,7 +291,7 @@ class SpeedLimitAssist:
|
||||
self._update_confirmed_state()
|
||||
elif self._has_speed_limit:
|
||||
self.state = SpeedLimitAssistState.preActive
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL)
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL)
|
||||
else:
|
||||
self.state = SpeedLimitAssistState.pending
|
||||
|
||||
@@ -303,7 +317,7 @@ class SpeedLimitAssist:
|
||||
|
||||
elif self.speed_limit_changed and self.apply_confirm_speed_threshold:
|
||||
self.state = SpeedLimitAssistState.preActive
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL)
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL)
|
||||
|
||||
# PRE_ACTIVE
|
||||
elif self.state == SpeedLimitAssistState.preActive:
|
||||
@@ -317,7 +331,7 @@ class SpeedLimitAssist:
|
||||
elif self.state == SpeedLimitAssistState.inactive:
|
||||
if self.speed_limit_changed:
|
||||
self.state = SpeedLimitAssistState.preActive
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL)
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL)
|
||||
elif self._update_non_pcm_long_confirmed_state():
|
||||
self.state = SpeedLimitAssistState.active
|
||||
|
||||
@@ -333,7 +347,7 @@ class SpeedLimitAssist:
|
||||
self.state = SpeedLimitAssistState.active
|
||||
elif self._has_speed_limit:
|
||||
self.state = SpeedLimitAssistState.preActive
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL)
|
||||
self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL)
|
||||
else:
|
||||
self.state = SpeedLimitAssistState.inactive
|
||||
|
||||
@@ -351,15 +365,15 @@ class SpeedLimitAssist:
|
||||
|
||||
if self.is_active:
|
||||
if self._state_prev not in ACTIVE_STATES:
|
||||
events_sp.add(EventNameSP.speedLimitActive)
|
||||
self.update_active_event(events_sp)
|
||||
|
||||
# only notify if we acquire a valid speed limit
|
||||
# do not check has_speed_limit here
|
||||
elif self._speed_limit != self.speed_limit_prev:
|
||||
if self.speed_limit_prev <= 0:
|
||||
events_sp.add(EventNameSP.speedLimitActive)
|
||||
self.update_active_event(events_sp)
|
||||
elif self.speed_limit_prev > 0 and self._speed_limit > 0:
|
||||
events_sp.add(EventNameSP.speedLimitChanged)
|
||||
self.update_active_event(events_sp)
|
||||
|
||||
def update(self, long_enabled: bool, long_override: bool, v_ego: float, a_ego: float, v_cruise_cluster: float, speed_limit: float,
|
||||
speed_limit_final_last: float, has_speed_limit: bool, distance: float, events_sp: EventsSP) -> None:
|
||||
|
||||
@@ -12,7 +12,7 @@ from openpilot.common.constants import CV
|
||||
from openpilot.common.gps import get_gps_location_service
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_MDL
|
||||
from openpilot.sunnypilot import PARAMS_UPDATE_PERIOD
|
||||
from openpilot.sunnypilot import PARAMS_UPDATE_PERIOD, get_sanitize_int_param
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit import LIMIT_MAX_MAP_DATA_AGE, LIMIT_ADAPT_ACC
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.common import Policy, OffsetType
|
||||
|
||||
@@ -42,6 +42,12 @@ class SpeedLimitResolver:
|
||||
self.distance_solutions = {} # Store for distance to current speed limit start for different sources
|
||||
|
||||
self.policy = self.params.get("SpeedLimitPolicy", return_default=True)
|
||||
self.policy = get_sanitize_int_param(
|
||||
"SpeedLimitPolicy",
|
||||
Policy.min().value,
|
||||
Policy.max().value,
|
||||
self.params
|
||||
)
|
||||
self._policy_to_sources_map = {
|
||||
Policy.car_state_only: [SpeedLimitSource.car],
|
||||
Policy.map_data_only: [SpeedLimitSource.map],
|
||||
@@ -54,7 +60,12 @@ class SpeedLimitResolver:
|
||||
self._reset_limit_sources(source)
|
||||
|
||||
self.is_metric = self.params.get_bool("IsMetric")
|
||||
self.offset_type = self.params.get("SpeedLimitOffsetType", return_default=True)
|
||||
self.offset_type = get_sanitize_int_param(
|
||||
"SpeedLimitOffsetType",
|
||||
OffsetType.min().value,
|
||||
OffsetType.max().value,
|
||||
self.params
|
||||
)
|
||||
self.offset_value = self.params.get("SpeedLimitValueOffset", return_default=True)
|
||||
|
||||
self.speed_limit = 0.
|
||||
@@ -131,6 +142,7 @@ class SpeedLimitResolver:
|
||||
self.limit_solutions[SpeedLimitSource.map] = speed_limit
|
||||
self.distance_solutions[SpeedLimitSource.map] = 0.
|
||||
|
||||
# FIXME-SP: this is not working as expected
|
||||
if 0. < next_speed_limit < self.v_ego:
|
||||
adapt_time = (next_speed_limit - self.v_ego) / LIMIT_ADAPT_ACC
|
||||
adapt_distance = self.v_ego * adapt_time + 0.5 * LIMIT_ADAPT_ACC * adapt_time ** 2
|
||||
|
||||
@@ -39,7 +39,7 @@ class TestSpeedLimitAssist:
|
||||
self.events_sp = EventsSP()
|
||||
CI = self._setup_platform(TOYOTA.TOYOTA_RAV4_TSS2)
|
||||
self.sla = SpeedLimitAssist(CI.CP)
|
||||
self.sla.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL)
|
||||
self.sla.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.sla.pcm_op_long] / DT_MDL)
|
||||
self.pcm_long_max_set_speed = PCM_LONG_REQUIRED_MAX_SET_SPEED[self.sla.is_metric][1] # use 80 MPH for now
|
||||
self.speed_conv = CV.MS_TO_KPH if self.sla.is_metric else CV.MS_TO_MPH
|
||||
|
||||
@@ -114,7 +114,7 @@ class TestSpeedLimitAssist:
|
||||
self.sla.state = SpeedLimitAssistState.preActive
|
||||
self.sla.update(True, False, SPEED_LIMITS['city'], 0, SPEED_LIMITS['highway'], SPEED_LIMITS['city'], SPEED_LIMITS['city'], True, 0, self.events_sp)
|
||||
|
||||
for _ in range(int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL)):
|
||||
for _ in range(int(PRE_ACTIVE_GUARD_PERIOD[self.sla.pcm_op_long] / DT_MDL)):
|
||||
self.sla.update(True, False, SPEED_LIMITS['city'], 0, SPEED_LIMITS['highway'], SPEED_LIMITS['city'], SPEED_LIMITS['city'], True, 0, self.events_sp)
|
||||
assert self.sla.state == SpeedLimitAssistState.inactive
|
||||
|
||||
|
||||
@@ -1,113 +1,113 @@
|
||||
import pytest
|
||||
from cereal import log
|
||||
from cereal import log, custom
|
||||
from openpilot.common.params import Params
|
||||
|
||||
from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.lane_turn_desire import LaneTurnController, LANE_CHANGE_SPEED_MIN
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.auto_lane_change import AutoLaneChangeMode
|
||||
|
||||
|
||||
class TurnDirection:
|
||||
none = 0
|
||||
turnLeft = 1
|
||||
turnRight = 2
|
||||
TurnDirection = custom.ModelDataV2SP.TurnDirection
|
||||
|
||||
|
||||
@pytest.mark.parametrize("left_blinker,right_blinker,v_ego,blindspot_left,blindspot_right,expected", [
|
||||
(True, False, 5, False, False, TurnDirection.turnLeft),
|
||||
(False, True, 6, False, False, TurnDirection.turnRight),
|
||||
(True, False, 9, False, False, TurnDirection.none),
|
||||
(True, False, 7, True, False, TurnDirection.none),
|
||||
(False, True, 6, False, True, TurnDirection.none),
|
||||
(False, False, 5, False, False, TurnDirection.none),
|
||||
(True, True, 5, False, False, TurnDirection.none),
|
||||
(True, False, 5, False, False, TurnDirection.turnLeft),
|
||||
(False, True, 6, False, False, TurnDirection.turnRight),
|
||||
(True, False, 9, False, False, TurnDirection.none),
|
||||
(True, False, 7, True, False, TurnDirection.none),
|
||||
(False, True, 6, False, True, TurnDirection.none),
|
||||
(False, False, 5, False, False, TurnDirection.none),
|
||||
(True, True, 5, False, False, TurnDirection.none),
|
||||
])
|
||||
def test_lane_turn_desire_conditions(left_blinker, right_blinker, v_ego, blindspot_left, blindspot_right, expected):
|
||||
dh = DesireHelper()
|
||||
controller = LaneTurnController(dh)
|
||||
controller.enabled = True
|
||||
controller.lane_turn_value = LANE_CHANGE_SPEED_MIN
|
||||
controller.turn_direction = TurnDirection.none
|
||||
controller.update_lane_turn(blindspot_left, blindspot_right, left_blinker, right_blinker, v_ego)
|
||||
assert controller.get_turn_direction() == expected
|
||||
dh = DesireHelper()
|
||||
controller = LaneTurnController(dh)
|
||||
controller.enabled = True
|
||||
controller.lane_turn_value = LANE_CHANGE_SPEED_MIN
|
||||
controller.turn_direction = TurnDirection.none
|
||||
controller.update_lane_turn(blindspot_left, blindspot_right, left_blinker, right_blinker, v_ego)
|
||||
assert controller.get_turn_direction() == expected
|
||||
|
||||
|
||||
def test_lane_turn_desire_disabled():
|
||||
dh = DesireHelper()
|
||||
controller = LaneTurnController(dh)
|
||||
controller.enabled = False
|
||||
controller.lane_turn_value = LANE_CHANGE_SPEED_MIN
|
||||
controller.turn_direction = TurnDirection.none
|
||||
controller.update_lane_turn(False, False, True, False, 7)
|
||||
assert controller.get_turn_direction() == TurnDirection.none
|
||||
dh = DesireHelper()
|
||||
controller = LaneTurnController(dh)
|
||||
controller.enabled = False
|
||||
controller.lane_turn_value = LANE_CHANGE_SPEED_MIN
|
||||
controller.turn_direction = TurnDirection.none
|
||||
controller.update_lane_turn(False, False, True, False, 7)
|
||||
assert controller.get_turn_direction() == TurnDirection.none
|
||||
|
||||
|
||||
def test_lane_turn_overrides_lane_change():
|
||||
dh = DesireHelper()
|
||||
controller = LaneTurnController(dh)
|
||||
controller.enabled = True
|
||||
controller.lane_turn_value = LANE_CHANGE_SPEED_MIN
|
||||
controller.turn_direction = TurnDirection.none
|
||||
# left turn desire
|
||||
controller.update_lane_turn(False, False, True, False, 5)
|
||||
assert controller.get_turn_direction() == TurnDirection.turnLeft
|
||||
# right turn desire
|
||||
controller.update_lane_turn(False, False, False, True, 6)
|
||||
assert controller.get_turn_direction() == TurnDirection.turnRight
|
||||
# no turn
|
||||
controller.update_lane_turn(False, False, False, False, 7)
|
||||
assert controller.get_turn_direction() == TurnDirection.none
|
||||
dh = DesireHelper()
|
||||
controller = LaneTurnController(dh)
|
||||
controller.enabled = True
|
||||
controller.lane_turn_value = LANE_CHANGE_SPEED_MIN
|
||||
controller.turn_direction = TurnDirection.none
|
||||
# left turn desire
|
||||
controller.update_lane_turn(False, False, True, False, 5)
|
||||
assert controller.get_turn_direction() == TurnDirection.turnLeft
|
||||
# right turn desire
|
||||
controller.update_lane_turn(False, False, False, True, 6)
|
||||
assert controller.get_turn_direction() == TurnDirection.turnRight
|
||||
# no turn
|
||||
controller.update_lane_turn(False, False, False, False, 7)
|
||||
assert controller.get_turn_direction() == TurnDirection.none
|
||||
|
||||
|
||||
@pytest.mark.parametrize("v_ego,expected", [
|
||||
(8.93, TurnDirection.turnLeft), # just below threshold
|
||||
(8.96, TurnDirection.none), # above threshold
|
||||
(8.95, TurnDirection.none), # just above threshold
|
||||
(8.93, TurnDirection.turnLeft), # just below threshold
|
||||
(8.96, TurnDirection.none), # above threshold
|
||||
(8.95, TurnDirection.none), # just above threshold
|
||||
])
|
||||
def test_lane_turn_desire_speed_boundary(v_ego, expected):
|
||||
dh = DesireHelper()
|
||||
controller = LaneTurnController(dh)
|
||||
controller.enabled = True
|
||||
controller.lane_turn_value = LANE_CHANGE_SPEED_MIN
|
||||
controller.turn_direction = TurnDirection.none
|
||||
controller.update_lane_turn(False, True, True, False, v_ego)
|
||||
assert controller.get_turn_direction() == expected
|
||||
dh = DesireHelper()
|
||||
controller = LaneTurnController(dh)
|
||||
controller.enabled = True
|
||||
controller.lane_turn_value = LANE_CHANGE_SPEED_MIN
|
||||
controller.turn_direction = TurnDirection.none
|
||||
controller.update_lane_turn(False, True, True, False, v_ego)
|
||||
assert controller.get_turn_direction() == expected
|
||||
|
||||
|
||||
class DummyCarState:
|
||||
def __init__(self, vEgo=0, leftBlinker=False, rightBlinker=False, leftBlindspot=False, rightBlindspot=False,
|
||||
steeringPressed=False, steeringTorque=0, brakePressed=False):
|
||||
self.vEgo = vEgo
|
||||
self.leftBlinker = leftBlinker
|
||||
self.rightBlinker = rightBlinker
|
||||
self.leftBlindspot = leftBlindspot
|
||||
self.rightBlindspot = rightBlindspot
|
||||
self.steeringPressed = steeringPressed
|
||||
self.steeringTorque = steeringTorque
|
||||
self.brakePressed = brakePressed
|
||||
def __init__(self, vEgo=0, leftBlinker=False, rightBlinker=False, leftBlindspot=False, rightBlindspot=False,
|
||||
steeringPressed=False, steeringTorque=0, brakePressed=False):
|
||||
self.vEgo = vEgo
|
||||
self.leftBlinker = leftBlinker
|
||||
self.rightBlinker = rightBlinker
|
||||
self.leftBlindspot = leftBlindspot
|
||||
self.rightBlindspot = rightBlindspot
|
||||
self.steeringPressed = steeringPressed
|
||||
self.steeringTorque = steeringTorque
|
||||
self.brakePressed = brakePressed
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def set_lane_turn_params():
|
||||
params = Params()
|
||||
params.put("LaneTurnDesire", True)
|
||||
params.put("LaneTurnValue", 20.0)
|
||||
params = Params()
|
||||
params.put("LaneTurnDesire", True)
|
||||
params.put("LaneTurnValue", 20.0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("carstate, lateral_active, lane_change_prob, expected_desire", [
|
||||
# Lane turn desire overrides lane change desire
|
||||
(DummyCarState(vEgo=5, leftBlinker=True, rightBlinker=False, leftBlindspot=False, rightBlindspot=False), True, 1.0, log.Desire.turnLeft),
|
||||
(DummyCarState(vEgo=7, leftBlinker=False, rightBlinker=True, leftBlindspot=False, rightBlindspot=False), True, 1.0, log.Desire.turnRight),
|
||||
# Lane change desire only (no turn desires)
|
||||
(DummyCarState(vEgo=9, leftBlinker=True, rightBlinker=False, leftBlindspot=False, rightBlindspot=False,
|
||||
steeringPressed=True, steeringTorque=1), True, 1.0, log.Desire.laneChangeLeft),
|
||||
(DummyCarState(vEgo=9, leftBlinker=False, rightBlinker=True, leftBlindspot=False, rightBlindspot=False,
|
||||
steeringPressed=True, steeringTorque=-1), True, 1.0, log.Desire.laneChangeRight),
|
||||
# No desire (inactive)
|
||||
(DummyCarState(vEgo=9, leftBlinker=False, rightBlinker=False), False, 1.0, log.Desire.none),
|
||||
(DummyCarState(vEgo=4, leftBlinker=False, rightBlinker=False), True, 1.0, log.Desire.none), # No blinkers? no desire!
|
||||
# Lane turn desire overrides lane change desire
|
||||
(DummyCarState(vEgo=5, leftBlinker=True, rightBlinker=False, leftBlindspot=False, rightBlindspot=False), True, 1.0,
|
||||
log.Desire.turnLeft),
|
||||
(DummyCarState(vEgo=7, leftBlinker=False, rightBlinker=True, leftBlindspot=False, rightBlindspot=False), True, 1.0,
|
||||
log.Desire.turnRight),
|
||||
# Lane change desire only (no turn desires)
|
||||
(DummyCarState(vEgo=9, leftBlinker=True, rightBlinker=False, leftBlindspot=False, rightBlindspot=False,
|
||||
steeringPressed=True, steeringTorque=1), True, 1.0, log.Desire.laneChangeLeft),
|
||||
(DummyCarState(vEgo=9, leftBlinker=False, rightBlinker=True, leftBlindspot=False, rightBlindspot=False,
|
||||
steeringPressed=True, steeringTorque=-1), True, 1.0, log.Desire.laneChangeRight),
|
||||
# No desire (inactive)
|
||||
(DummyCarState(vEgo=9, leftBlinker=False, rightBlinker=False), False, 1.0, log.Desire.none),
|
||||
(DummyCarState(vEgo=4, leftBlinker=False, rightBlinker=False), True, 1.0, log.Desire.none), # No blinkers? no desire!
|
||||
])
|
||||
def test_desire_helper_integration(carstate, lateral_active, lane_change_prob, expected_desire, set_lane_turn_params):
|
||||
dh = DesireHelper()
|
||||
dh.alc.lane_change_set_timer = AutoLaneChangeMode.NUDGE
|
||||
for _ in range(10):
|
||||
dh.update(carstate, lateral_active, lane_change_prob)
|
||||
assert dh.desire == expected_desire # The first four tests were unit tests to test the controller, where this tests the integration in desire helpers
|
||||
dh = DesireHelper()
|
||||
dh.alc.lane_change_set_timer = AutoLaneChangeMode.NUDGE
|
||||
for _ in range(10):
|
||||
dh.update(carstate, lateral_active, lane_change_prob)
|
||||
assert dh.desire == expected_desire # The first four tests were unit tests to test the controller, where this tests the integration in desire helpers
|
||||
|
||||
@@ -4,13 +4,13 @@ from openpilot.common.constants import CV
|
||||
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \
|
||||
NoEntryAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, AlertCallbackType, wrong_car_mode_alert
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit import PCM_LONG_REQUIRED_MAX_SET_SPEED, CONFIRM_SPEED_THRESHOLD
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.helpers import compare_cluster_target
|
||||
|
||||
|
||||
AlertSize = log.SelfdriveState.AlertSize
|
||||
AlertStatus = log.SelfdriveState.AlertStatus
|
||||
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
|
||||
AudibleAlertSP = custom.SelfdriveStateSP.AudibleAlert
|
||||
EventNameSP = custom.OnroadEventSP.EventName
|
||||
|
||||
|
||||
@@ -33,6 +33,9 @@ def speed_limit_pre_active_alert(CP: car.CarParams, CS: car.CarState, sm: messag
|
||||
speed_conv = CV.MS_TO_KPH if metric else CV.MS_TO_MPH
|
||||
speed_limit_final_last = sm['longitudinalPlanSP'].speedLimit.resolver.speedLimitFinalLast
|
||||
speed_limit_final_last_conv = round(speed_limit_final_last * speed_conv)
|
||||
alert_1_str = ""
|
||||
alert_2_str = ""
|
||||
alert_size = AlertSize.none
|
||||
|
||||
if CP.openpilotLongitudinalControl and CP.pcmCruise:
|
||||
# PCM long
|
||||
@@ -40,25 +43,16 @@ def speed_limit_pre_active_alert(CP: car.CarParams, CS: car.CarState, sm: messag
|
||||
pcm_long_required_max = cst_low if speed_limit_final_last_conv < CONFIRM_SPEED_THRESHOLD[metric] else cst_high
|
||||
pcm_long_required_max_set_speed_conv = round(pcm_long_required_max * speed_conv)
|
||||
speed_unit = "km/h" if metric else "mph"
|
||||
|
||||
alert_1_str = "Speed Limit Assist: Activation Required"
|
||||
alert_2_str = f"Manually change set speed to {pcm_long_required_max_set_speed_conv} {speed_unit} to activate"
|
||||
else:
|
||||
# Non PCM long
|
||||
v_cruise_cluster = CS.vCruiseCluster * CV.KPH_TO_MS
|
||||
|
||||
req_plus, req_minus = compare_cluster_target(v_cruise_cluster, speed_limit_final_last, metric)
|
||||
arrow_str = ""
|
||||
if req_plus:
|
||||
arrow_str = "RES/+"
|
||||
elif req_minus:
|
||||
arrow_str = "SET/-"
|
||||
|
||||
alert_2_str = f"Operate the {arrow_str} cruise control button to activate"
|
||||
alert_size = AlertSize.mid
|
||||
|
||||
return Alert(
|
||||
"Speed Limit Assist: Activation Required",
|
||||
alert_1_str,
|
||||
alert_2_str,
|
||||
AlertStatus.normal, AlertSize.mid,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1)
|
||||
AlertStatus.normal, alert_size,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlertSP.promptSingleLow, .1)
|
||||
|
||||
|
||||
class EventsSP(EventsBase):
|
||||
@@ -202,7 +196,7 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
"Automatically adjusting to the posted speed limit",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.small,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 5.),
|
||||
Priority.LOW, VisualAlert.none, AudibleAlertSP.promptSingleHigh, 5.),
|
||||
},
|
||||
|
||||
EventNameSP.speedLimitChanged: {
|
||||
@@ -210,7 +204,7 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
"Set speed changed",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.small,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 5.),
|
||||
Priority.LOW, VisualAlert.none, AudibleAlertSP.promptSingleHigh, 5.),
|
||||
},
|
||||
|
||||
EventNameSP.speedLimitPreActive: {
|
||||
@@ -222,7 +216,7 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
"Automatically adjusting to the last speed limit",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.small,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 5.),
|
||||
Priority.LOW, VisualAlert.none, AudibleAlertSP.promptSingleHigh, 5.),
|
||||
},
|
||||
|
||||
EventNameSP.e2eChime: {
|
||||
@@ -230,6 +224,6 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
"",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.none,
|
||||
Priority.MID, VisualAlert.none, AudibleAlert.prompt, 0.1),
|
||||
Priority.MID, VisualAlert.none, AudibleAlert.prompt, 3.),
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user