FrogPilot setup

This commit is contained in:
FrogAi
2024-01-12 22:39:30 -07:00
parent 9d97e0ecc1
commit 7308c1b35c
60 changed files with 1660 additions and 49 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -0,0 +1,47 @@
import cereal.messaging as messaging
from openpilot.common.conversions import Conversions as CV
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX
class FrogPilotPlanner:
def __init__(self, params):
self.v_cruise = 0
self.update_frogpilot_params(params)
def update(self, sm, mpc):
carState, controlsState, modelData = sm['carState'], sm['controlsState'], sm['modelV2']
enabled = controlsState.enabled
v_cruise_kph = min(controlsState.vCruise, V_CRUISE_MAX)
v_cruise = v_cruise_kph * CV.KPH_TO_MS
v_ego = carState.vEgo
self.v_cruise = self.update_v_cruise(carState, controlsState, modelData, enabled, v_cruise, v_ego)
def update_v_cruise(self, carState, controlsState, modelData, enabled, v_cruise, v_ego):
v_ego_diff = max(carState.vEgoRaw - carState.vEgoCluster, 0)
return v_cruise - v_ego_diff
def publish_lateral(self, sm, pm, DH):
frogpilot_lateral_plan_send = messaging.new_message('frogpilotLateralPlan')
frogpilot_lateral_plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState', 'modelV2'])
frogpilotLateralPlan = frogpilot_lateral_plan_send.frogpilotLateralPlan
pm.send('frogpilotLateralPlan', frogpilot_lateral_plan_send)
def publish_longitudinal(self, sm, pm, mpc):
frogpilot_longitudinal_plan_send = messaging.new_message('frogpilotLongitudinalPlan')
frogpilot_longitudinal_plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState'])
frogpilotLongitudinalPlan = frogpilot_longitudinal_plan_send.frogpilotLongitudinalPlan
pm.send('frogpilotLongitudinalPlan', frogpilot_longitudinal_plan_send)
def update_frogpilot_params(self, params):
self.is_metric = params.get_bool("IsMetric")
lateral_tune = params.get_bool("LateralTune")
longitudinal_tune = params.get_bool("LongitudinalTune")

View File

@@ -0,0 +1,128 @@
#include "selfdrive/frogpilot/ui/control_settings.h"
#include "selfdrive/ui/ui.h"
FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) {
const std::vector<std::tuple<QString, QString, QString, QString>> controlToggles {
{"LateralTune", "Lateral Tuning", "Modify openpilot's steering behavior.", "../frogpilot/assets/toggle_icons/icon_lateral_tune.png"},
{"LongitudinalTune", "Longitudinal Tuning", "Modify openpilot's acceleration and braking behavior.", "../frogpilot/assets/toggle_icons/icon_longitudinal_tune.png"},
};
for (const auto &[param, title, desc, icon] : controlToggles) {
ParamControl *toggle;
if (param == "LateralTune") {
FrogPilotParamManageControl *lateralTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
QObject::connect(lateralTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
parentToggleClicked();
for (auto &[key, toggle] : toggles) {
toggle->setVisible(lateralTuneKeys.find(key.c_str()) != lateralTuneKeys.end());
}
});
toggle = lateralTuneToggle;
} else if (param == "LongitudinalTune") {
FrogPilotParamManageControl *longitudinalTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
QObject::connect(longitudinalTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
parentToggleClicked();
for (auto &[key, toggle] : toggles) {
toggle->setVisible(longitudinalTuneKeys.find(key.c_str()) != longitudinalTuneKeys.end());
}
});
toggle = longitudinalTuneToggle;
} else {
toggle = new ParamControl(param, title, desc, icon, this);
}
addItem(toggle);
toggles[param.toStdString()] = toggle;
QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() {
updateToggles();
});
QObject::connect(static_cast<FrogPilotParamValueControl*>(toggle), &FrogPilotParamValueControl::buttonPressed, [this]() {
updateToggles();
});
QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() {
update();
});
QObject::connect(static_cast<FrogPilotParamManageControl*>(toggle), &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
update();
});
}
std::set<std::string> rebootKeys = {};
for (const std::string &key : rebootKeys) {
QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() {
if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) {
Hardware::reboot();
}
});
}
conditionalExperimentalKeys = {};
fireTheBabysitterKeys = {};
laneChangeKeys = {};
lateralTuneKeys = {};
longitudinalTuneKeys = {};
speedLimitControllerKeys = {};
visionTurnControlKeys = {};
QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotControlsPanel::hideSubToggles);
QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotControlsPanel::hideSubToggles);
QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotControlsPanel::updateMetric);
hideSubToggles();
updateMetric();
}
void FrogPilotControlsPanel::updateToggles() {
std::thread([this]() {
paramsMemory.putBool("FrogPilotTogglesUpdated", true);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
paramsMemory.putBool("FrogPilotTogglesUpdated", false);
}).detach();
}
void FrogPilotControlsPanel::updateMetric() {
bool previousIsMetric = isMetric;
isMetric = params.getBool("IsMetric");
if (isMetric != previousIsMetric) {
double distanceConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT;
double speedConversion = isMetric ? MILE_TO_KM : KM_TO_MILE;
}
if (isMetric) {
} else {
}
previousIsMetric = isMetric;
}
void FrogPilotControlsPanel::parentToggleClicked() {
this->openParentToggle();
}
void FrogPilotControlsPanel::hideSubToggles() {
for (auto &[key, toggle] : toggles) {
const bool subToggles = conditionalExperimentalKeys.find(key.c_str()) != conditionalExperimentalKeys.end() ||
fireTheBabysitterKeys.find(key.c_str()) != fireTheBabysitterKeys.end() ||
laneChangeKeys.find(key.c_str()) != laneChangeKeys.end() ||
lateralTuneKeys.find(key.c_str()) != lateralTuneKeys.end() ||
longitudinalTuneKeys.find(key.c_str()) != longitudinalTuneKeys.end() ||
speedLimitControllerKeys.find(key.c_str()) != speedLimitControllerKeys.end() ||
visionTurnControlKeys.find(key.c_str()) != visionTurnControlKeys.end();
toggle->setVisible(!subToggles);
}
this->closeParentToggle();
}
void FrogPilotControlsPanel::hideEvent(QHideEvent *event) {
hideSubToggles();
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include <set>
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
#include "selfdrive/ui/qt/offroad/settings.h"
class FrogPilotControlsPanel : public FrogPilotListWidget {
Q_OBJECT
public:
explicit FrogPilotControlsPanel(SettingsWindow *parent);
signals:
void closeParentToggle();
void openParentToggle();
private:
void hideEvent(QHideEvent *event);
void hideSubToggles();
void parentToggleClicked();
void updateMetric();
void updateToggles();
std::set<QString> conditionalExperimentalKeys;
std::set<QString> fireTheBabysitterKeys;
std::set<QString> laneChangeKeys;
std::set<QString> lateralTuneKeys;
std::set<QString> longitudinalTuneKeys;
std::set<QString> speedLimitControllerKeys;
std::set<QString> visionTurnControlKeys;
std::map<std::string, ParamControl*> toggles;
Params params;
Params paramsMemory{"/dev/shm/params"};
bool isMetric = params.getBool("IsMetric");
};

View File

@@ -0,0 +1,166 @@
#include <filesystem>
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
#include "selfdrive/ui/ui.h"
bool FrogPilotConfirmationDialog::toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent) {
ConfirmationDialog d = ConfirmationDialog(prompt_text, confirm_text, tr("Reboot Later"), false, parent);
return d.exec();
}
bool FrogPilotConfirmationDialog::toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent) {
ConfirmationDialog d = ConfirmationDialog(prompt_text, button_text, "", false, parent);
return d.exec();
}
bool FrogPilotConfirmationDialog::yesorno(const QString &prompt_text, QWidget *parent) {
ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Yes"), tr("No"), false, parent);
return d.exec();
}
FrogPilotButtonIconControl::FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc, const QString &icon, QWidget *parent) : AbstractControl(title, desc, icon, parent) {
btn.setText(text);
btn.setStyleSheet(R"(
QPushButton {
padding: 0;
border-radius: 50px;
font-size: 35px;
font-weight: 500;
color: #E4E4E4;
background-color: #393939;
}
QPushButton:pressed {
background-color: #4a4a4a;
}
QPushButton:disabled {
color: #33E4E4E4;
}
)");
btn.setFixedSize(250, 100);
QObject::connect(&btn, &QPushButton::clicked, this, &FrogPilotButtonIconControl::clicked);
hlayout->addWidget(&btn);
}
void setDefaultParams() {
Params params = Params();
bool FrogsGoMoo = params.get("DongleId").substr(0, 3) == "be6";
std::map<std::string, std::string> defaultValues {
{"AccelerationPath", FrogsGoMoo ? "1" : "0"},
{"AccelerationProfile", FrogsGoMoo ? "3" : "2"},
{"AdjacentPath", FrogsGoMoo ? "1" : "0"},
{"AdjustablePersonalities", "3"},
{"AggressiveAcceleration", "1"},
{"AggressiveFollow", FrogsGoMoo ? "10" : "12"},
{"AggressiveJerk", FrogsGoMoo ? "6" : "5"},
{"AlwaysOnLateral", "1"},
{"AlwaysOnLateralMain", FrogsGoMoo ? "1" : "0"},
{"AverageCurvature", FrogsGoMoo ? "1" : "0"},
{"BlindSpotPath", "1"},
{"CameraView", FrogsGoMoo ? "1" : "0"},
{"CECurves", "1"},
{"CECurvesLead", "0"},
{"CENavigation", "1"},
{"CESignal", "1"},
{"CESlowerLead", "0"},
{"CESpeed", "0"},
{"CESpeedLead", "0"},
{"CEStopLights", "1"},
{"CEStopLightsLead", FrogsGoMoo ? "0" : "1"},
{"Compass", FrogsGoMoo ? "1" : "0"},
{"ConditionalExperimental", "1"},
{"CurveSensitivity", FrogsGoMoo ? "125" : "100"},
{"CustomColors", "1"},
{"CustomIcons", "1"},
{"CustomPersonalities", "1"},
{"CustomSignals", "1"},
{"CustomSounds", "1"},
{"CustomTheme", "1"},
{"CustomUI", "1"},
{"DeviceShutdown", "9"},
{"DriverCamera", "0"},
{"EVTable", FrogsGoMoo ? "0" : "1"},
{"ExperimentalModeViaPress", "1"},
{"Fahrenheit", "0"},
{"FireTheBabysitter", FrogsGoMoo ? "1" : "0"},
{"GasRegenCmd", "0"},
{"GoatScream", "1"},
{"GreenLightAlert", "0"},
{"HideSpeed", "0"},
{"LaneChangeTime", "0"},
{"LaneDetection", "1"},
{"LaneLinesWidth", "4"},
{"LateralTune", "1"},
{"LeadInfo", FrogsGoMoo ? "1" : "0"},
{"LockDoors", "0"},
{"LongitudinalTune", "1"},
{"LongPitch", FrogsGoMoo ? "0" : "1"},
{"LowerVolt", FrogsGoMoo ? "0" : "1"},
{"Model", "0"},
{"ModelUI", "1"},
{"MTSCEnabled", "1"},
{"MuteDM", FrogsGoMoo ? "1" : "0"},
{"MuteDoor", FrogsGoMoo ? "1" : "0"},
{"MuteOverheated", FrogsGoMoo ? "1" : "0"},
{"MuteSeatbelt", FrogsGoMoo ? "1" : "0"},
{"NNFF", FrogsGoMoo ? "1" : "0"},
{"NoLogging", "0"},
{"NudgelessLaneChange", "1"},
{"NumericalTemp", FrogsGoMoo ? "1" : "0"},
{"Offset1", "5"},
{"Offset2", FrogsGoMoo ? "7" : "5"},
{"Offset3", "5"},
{"Offset4", FrogsGoMoo ? "20" : "10"},
{"OneLaneChange", "1"},
{"PathEdgeWidth", "20"},
{"PathWidth", "61"},
{"PauseLateralOnSignal", "0"},
{"PreferredSchedule", "0"},
{"RandomEvents", FrogsGoMoo ? "1" : "0"},
{"RelaxedFollow", "30"},
{"RelaxedJerk", "50"},
{"ReverseCruise", "0"},
{"RoadEdgesWidth", "2"},
{"RoadNameUI", "1"},
{"RotatingWheel", "1"},
{"ScreenBrightness", "101"},
{"SearchInput", "0"},
{"ShowCPU", FrogsGoMoo ? "1" : "0"},
{"ShowFPS", FrogsGoMoo ? "1" : "0"},
{"ShowGPU", "0"},
{"ShowMemoryUsage", FrogsGoMoo ? "1" : "0"},
{"Sidebar", FrogsGoMoo ? "1" : "0"},
{"SilentMode", "0"},
{"SLCFallback", "2"},
{"SLCOverride", FrogsGoMoo ? "2" : "1"},
{"SLCPriority", "1"},
{"SmoothBraking", "1"},
{"SNGHack", FrogsGoMoo ? "0" : "1"},
{"SpeedLimitController", "1"},
{"StandardFollow", "15"},
{"StandardJerk", "10"},
{"StoppingDistance", FrogsGoMoo ? "6" : "0"},
{"TSS2Tune", "1"},
{"TurnAggressiveness", FrogsGoMoo ? "150" : "100"},
{"TurnDesires", "1"},
{"UnlimitedLength", "1"},
{"UseSI", FrogsGoMoo ? "1" : "0"},
{"VisionTurnControl", "1"},
{"WheelIcon", FrogsGoMoo ? "1" : "0"}
};
bool rebootRequired = false;
for (const auto &[key, value] : defaultValues) {
if (params.get(key).empty()) {
params.put(key, value);
rebootRequired = true;
}
}
if (rebootRequired) {
while (!std::filesystem::exists("/data/openpilot/prebuilt")) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
Hardware::reboot();
}
}

View File

@@ -0,0 +1,545 @@
#pragma once
#include "selfdrive/ui/qt/widgets/controls.h"
class FrogPilotConfirmationDialog : public ConfirmationDialog {
Q_OBJECT
public:
explicit FrogPilotConfirmationDialog(const QString &prompt_text, const QString &confirm_text,
const QString &cancel_text, const bool rich, QWidget* parent);
static bool toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent);
static bool toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent);
static bool yesorno(const QString &prompt_text, QWidget *parent);
};
class FrogPilotListWidget : public QWidget {
Q_OBJECT
public:
explicit FrogPilotListWidget(QWidget *parent = 0) : QWidget(parent), outer_layout(this) {
outer_layout.setMargin(0);
outer_layout.setSpacing(0);
outer_layout.addLayout(&inner_layout);
inner_layout.setMargin(0);
inner_layout.setSpacing(25); // default spacing is 25
outer_layout.addStretch();
}
inline void addItem(QWidget *w) { inner_layout.addWidget(w); }
inline void addItem(QLayout *layout) { inner_layout.addLayout(layout); }
inline void setSpacing(int spacing) { inner_layout.setSpacing(spacing); }
private:
void paintEvent(QPaintEvent *) override {
QPainter p(this);
p.setPen(Qt::gray);
int visibleWidgetCount = 0;
std::vector<QRect> visibleRects;
for (int i = 0; i < inner_layout.count(); ++i) {
QWidget *widget = inner_layout.itemAt(i)->widget();
if (widget && widget->isVisible()) {
visibleWidgetCount++;
visibleRects.push_back(inner_layout.itemAt(i)->geometry());
}
}
for (int i = 0; i < visibleWidgetCount - 1; ++i) {
int bottom = visibleRects[i].bottom() + inner_layout.spacing() / 2;
p.drawLine(visibleRects[i].left() + 40, bottom, visibleRects[i].right() - 40, bottom);
}
}
QVBoxLayout outer_layout;
QVBoxLayout inner_layout;
};
class FrogPilotButtonIconControl : public AbstractControl {
Q_OBJECT
public:
FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr);
inline void setText(const QString &text) { btn.setText(text); }
inline QString text() const { return btn.text(); }
signals:
void clicked();
public slots:
void setEnabled(bool enabled) { btn.setEnabled(enabled); }
private:
QPushButton btn;
};
class FrogPilotButtonParamControl : public ParamControl {
Q_OBJECT
public:
FrogPilotButtonParamControl(const QString &param, const QString &title, const QString &desc, const QString &icon,
const std::vector<QString> &button_texts, const int minimum_button_width = 225)
: ParamControl(param, title, desc, icon) {
const QString style = R"(
QPushButton {
border-radius: 50px;
font-size: 40px;
font-weight: 500;
height:100px;
padding: 0 25 0 25;
color: #E4E4E4;
background-color: #393939;
}
QPushButton:pressed {
background-color: #4a4a4a;
}
QPushButton:checked:enabled {
background-color: #33Ab4C;
}
QPushButton:disabled {
color: #33E4E4E4;
}
)";
key = param.toStdString();
int value = atoi(params.get(key).c_str());
button_group = new QButtonGroup(this);
button_group->setExclusive(true);
for (size_t i = 0; i < button_texts.size(); i++) {
QPushButton *button = new QPushButton(button_texts[i], this);
button->setCheckable(true);
button->setChecked(i == value);
button->setStyleSheet(style);
button->setMinimumWidth(minimum_button_width);
hlayout->addWidget(button);
button_group->addButton(button, i);
}
QObject::connect(button_group, QOverload<int, bool>::of(&QButtonGroup::buttonToggled), [=](int id, bool checked) {
if (checked) {
params.put(key, std::to_string(id));
refresh();
emit buttonClicked(id);
}
});
toggle.hide();
}
void setEnabled(bool enable) {
for (auto btn : button_group->buttons()) {
btn->setEnabled(enable);
}
}
signals:
void buttonClicked(int id);
private:
std::string key;
Params params;
QButtonGroup *button_group;
};
class FrogPilotParamManageControl : public ParamControl {
Q_OBJECT
public:
FrogPilotParamManageControl(const QString &param, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr)
: ParamControl(param, title, desc, icon, parent),
key(param.toStdString()),
manageButton(new ButtonControl(tr(""), tr("MANAGE"), tr(""))) {
hlayout->insertWidget(hlayout->indexOf(&toggle) - 1, manageButton);
connect(this, &ToggleControl::toggleFlipped, this, [this](bool state) {
refresh();
});
connect(manageButton, &ButtonControl::clicked, this, &FrogPilotParamManageControl::manageButtonClicked);
}
void refresh() {
ParamControl::refresh();
manageButton->setVisible(params.getBool(key));
}
void showEvent(QShowEvent *event) override {
ParamControl::showEvent(event);
refresh();
}
signals:
void manageButtonClicked();
private:
std::string key;
Params params;
ButtonControl *manageButton;
};
class FrogPilotParamToggleControl : public ParamControl {
Q_OBJECT
public:
FrogPilotParamToggleControl(const QString &param, const QString &title, const QString &desc,
const QString &icon, const std::vector<QString> &button_params,
const std::vector<QString> &button_texts, QWidget *parent = nullptr,
const int minimum_button_width = 225)
: ParamControl(param, title, desc, icon, parent) {
connect(this, &ToggleControl::toggleFlipped, this, [this](bool state) {
refreshButtons(state);
});
const QString style = R"(
QPushButton {
border-radius: 50px;
font-size: 40px;
font-weight: 500;
height:100px;
padding: 0 25 0 25;
color: #E4E4E4;
background-color: #393939;
}
QPushButton:pressed {
background-color: #4a4a4a;
}
QPushButton:checked:enabled {
background-color: #33Ab4C;
}
QPushButton:disabled {
color: #33E4E4E4;
}
)";
button_group = new QButtonGroup(this);
button_group->setExclusive(false);
std::map<QString, bool> paramState;
for (const QString &button_param : button_params) {
paramState[button_param] = params.getBool(button_param.toStdString());
}
for (int i = 0; i < button_texts.size(); ++i) {
QPushButton *button = new QPushButton(button_texts[i], this);
button->setCheckable(true);
button->setChecked(paramState[button_params[i]]);
button->setStyleSheet(style);
button->setMinimumWidth(minimum_button_width);
button_group->addButton(button, i);
connect(button, &QPushButton::clicked, [this, button_params, i](bool checked) {
params.putBool(button_params[i].toStdString(), checked);
button_group->button(i)->setChecked(checked);
emit buttonClicked(checked);
});
hlayout->insertWidget(hlayout->indexOf(&toggle), button);
}
}
void refreshButtons(bool state) {
for (QAbstractButton *button : button_group->buttons()) {
button->setVisible(state);
}
}
signals:
void buttonClicked(const bool checked);
private:
Params params;
QButtonGroup *button_group;
};
class FrogPilotParamValueControl : public ParamControl {
Q_OBJECT
public:
FrogPilotParamValueControl(const QString &param, const QString &title, const QString &desc, const QString &icon,
const int &minValue, const int &maxValue, const std::map<int, QString> &valueLabels,
QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const int &division = 1)
: ParamControl(param, title, desc, icon, parent),
minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) {
key = param.toStdString();
valueLabel = new QLabel(this);
hlayout->addWidget(valueLabel);
QPushButton *decrementButton = createButton("-", this);
QPushButton *incrementButton = createButton("+", this);
hlayout->addWidget(decrementButton);
hlayout->addWidget(incrementButton);
connect(decrementButton, &QPushButton::clicked, this, [=]() {
updateValue(-1);
});
connect(incrementButton, &QPushButton::clicked, this, [=]() {
updateValue(1);
});
toggle.hide();
}
void updateValue(int increment) {
value = value + increment;
if (loop) {
if (value < minValue) value = maxValue;
else if (value > maxValue) value = minValue;
} else {
value = std::max(minValue, std::min(maxValue, value));
}
params.putInt(key, value);
refresh();
emit buttonPressed();
emit valueChanged(value);
}
void refresh() {
value = params.getInt(key);
QString text;
auto it = valueLabelMappings.find(value);
if (division > 1) {
text = QString::number(value / (division * 1.0), 'g');
} else {
text = it != valueLabelMappings.end() ? it->second : QString::number(value);
}
if (!labelText.isEmpty()) {
text += labelText;
}
valueLabel->setText(text);
valueLabel->setStyleSheet("QLabel { color: #E0E879; }");
}
void updateControl(int newMinValue, int newMaxValue, const QString &newLabel) {
minValue = newMinValue;
maxValue = newMaxValue;
labelText = newLabel;
}
void showEvent(QShowEvent *event) override {
refresh();
}
signals:
void buttonPressed();
void valueChanged(int value);
private:
bool loop;
int division;
int maxValue;
int minValue;
int value;
QLabel *valueLabel;
QString labelText;
std::map<int, QString> valueLabelMappings;
std::string key;
Params params;
QPushButton *createButton(const QString &text, QWidget *parent) {
QPushButton *button = new QPushButton(text, parent);
button->setFixedSize(150, 100);
button->setAutoRepeat(true);
button->setAutoRepeatInterval(150);
button->setStyleSheet(R"(
QPushButton {
border-radius: 50px;
font-size: 50px;
font-weight: 500;
height: 100px;
padding: 0 25 0 25;
color: #E4E4E4;
background-color: #393939;
}
QPushButton:pressed {
background-color: #4a4a4a;
}
)");
return button;
}
};
class FrogPilotDualParamControl : public QFrame {
Q_OBJECT
public:
FrogPilotDualParamControl(ParamControl *control1, ParamControl *control2, QWidget *parent = nullptr, bool split=false)
: QFrame(parent) {
QHBoxLayout *hlayout = new QHBoxLayout(this);
control1->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
control1->setMaximumWidth(split ? 800 : 700);
control2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
control2->setMaximumWidth(800);
hlayout->addWidget(control1);
hlayout->addWidget(control2);
}
};
class FrogPilotParamValueToggleControl : public ParamControl {
Q_OBJECT
public:
FrogPilotParamValueToggleControl(const QString &param, const QString &title, const QString &desc, const QString &icon,
const int &minValue, const int &maxValue, const std::map<int, QString> &valueLabels,
QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const int &division = 1,
const std::vector<QString> &button_params = std::vector<QString>(), const std::vector<QString> &button_texts = std::vector<QString>(),
const int minimum_button_width = 225)
: ParamControl(param, title, desc, icon, parent),
minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) {
key = param.toStdString();
const QString style = R"(
QPushButton {
border-radius: 50px;
font-size: 40px;
font-weight: 500;
height:100px;
padding: 0 25 0 25;
color: #E4E4E4;
background-color: #393939;
}
QPushButton:pressed {
background-color: #4a4a4a;
}
QPushButton:checked:enabled {
background-color: #33Ab4C;
}
QPushButton:disabled {
color: #33E4E4E4;
}
)";
button_group = new QButtonGroup(this);
button_group->setExclusive(false);
std::map<QString, bool> paramState;
for (const QString &button_param : button_params) {
paramState[button_param] = params.getBool(button_param.toStdString());
}
for (int i = 0; i < button_texts.size(); ++i) {
QPushButton *button = new QPushButton(button_texts[i], this);
button->setCheckable(true);
button->setChecked(paramState[button_params[i]]);
button->setStyleSheet(style);
button->setMinimumWidth(minimum_button_width);
button_group->addButton(button, i);
connect(button, &QPushButton::clicked, [this, button_params, i](bool checked) {
params.putBool(button_params[i].toStdString(), checked);
button_group->button(i)->setChecked(checked);
});
hlayout->addWidget(button);
}
valueLabel = new QLabel(this);
hlayout->addWidget(valueLabel);
QPushButton *decrementButton = createButton("-", this);
QPushButton *incrementButton = createButton("+", this);
hlayout->addWidget(decrementButton);
hlayout->addWidget(incrementButton);
connect(decrementButton, &QPushButton::clicked, this, [=]() {
updateValue(-1);
});
connect(incrementButton, &QPushButton::clicked, this, [=]() {
updateValue(1);
});
toggle.hide();
}
void updateValue(int increment) {
value = value + increment;
if (loop) {
if (value < minValue) value = maxValue;
else if (value > maxValue) value = minValue;
} else {
value = std::max(minValue, std::min(maxValue, value));
}
params.putInt(key, value);
refresh();
emit buttonPressed();
emit valueChanged(value);
}
void refresh() {
value = params.getInt(key);
QString text;
auto it = valueLabelMappings.find(value);
if (division > 1) {
text = QString::number(value / (division * 1.0), 'g');
} else {
text = it != valueLabelMappings.end() ? it->second : QString::number(value);
}
if (!labelText.isEmpty()) {
text += labelText;
}
valueLabel->setText(text);
valueLabel->setStyleSheet("QLabel { color: #E0E879; }");
}
void updateControl(int newMinValue, int newMaxValue, const QString &newLabel) {
minValue = newMinValue;
maxValue = newMaxValue;
labelText = newLabel;
}
void showEvent(QShowEvent *event) override {
refresh();
}
signals:
void buttonPressed();
void valueChanged(int value);
private:
bool loop;
int division;
int maxValue;
int minValue;
int value;
QButtonGroup *button_group;
QLabel *valueLabel;
QString labelText;
std::map<int, QString> valueLabelMappings;
std::string key;
Params params;
QPushButton *createButton(const QString &text, QWidget *parent) {
QPushButton *button = new QPushButton(text, parent);
button->setFixedSize(150, 100);
button->setAutoRepeat(true);
button->setAutoRepeatInterval(150);
button->setStyleSheet(R"(
QPushButton {
border-radius: 50px;
font-size: 50px;
font-weight: 500;
height: 100px;
padding: 0 25 0 25;
color: #E4E4E4;
background-color: #393939;
}
QPushButton:pressed {
background-color: #4a4a4a;
}
)");
return button;
}
};
void setDefaultParams();

View File

@@ -0,0 +1,56 @@
#include "selfdrive/frogpilot/ui/vehicle_settings.h"
#include "selfdrive/ui/ui.h"
FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) {
std::vector<std::tuple<QString, QString, QString, QString>> vehicleToggles {
};
for (auto &[param, title, desc, icon] : vehicleToggles) {
ParamControl *toggle = new ParamControl(param, title, desc, icon, this);
addItem(toggle);
toggle->setVisible(false);
toggles[param.toStdString()] = toggle;
QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() {
updateToggles();
});
}
gmKeys = {};
toyotaKeys = {};
std::set<std::string> rebootKeys = {};
for (const std::string &key : rebootKeys) {
QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() {
if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) {
Hardware::reboot();
}
});
}
}
void FrogPilotVehiclesPanel::updateToggles() {
std::thread([this]() {
paramsMemory.putBool("FrogPilotTogglesUpdated", true);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
paramsMemory.putBool("FrogPilotTogglesUpdated", false);
}).detach();
}
void FrogPilotVehiclesPanel::setToggles() {
bool gm = false;
bool toyota = false;
for (auto &[key, toggle] : toggles) {
toggle->setVisible(false);
if (gm) {
toggle->setVisible(gmKeys.find(key.c_str()) != gmKeys.end());
} else if (toyota) {
toggle->setVisible(toyotaKeys.find(key.c_str()) != toyotaKeys.end());
}
}
update();
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include <set>
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
#include "selfdrive/ui/qt/offroad/settings.h"
class FrogPilotVehiclesPanel : public FrogPilotListWidget {
Q_OBJECT
public:
explicit FrogPilotVehiclesPanel(SettingsWindow *parent);
private:
void setToggles();
void updateToggles();
std::map<std::string, ParamControl*> toggles;
std::set<QString> gmKeys;
std::set<QString> toyotaKeys;
Params params;
Params paramsMemory{"/dev/shm/params"};
};

View File

@@ -0,0 +1,86 @@
#include "selfdrive/frogpilot/ui/visual_settings.h"
#include "selfdrive/ui/ui.h"
FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) {
const std::vector<std::tuple<QString, QString, QString, QString>> visualToggles {
};
for (const auto &[param, title, desc, icon] : visualToggles) {
ParamControl *toggle;
toggle = new ParamControl(param, title, desc, icon, this);
addItem(toggle);
toggles[param.toStdString()] = toggle;
QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() {
updateToggles();
});
QObject::connect(static_cast<FrogPilotParamValueControl*>(toggle), &FrogPilotParamValueControl::buttonPressed, [this]() {
updateToggles();
});
QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() {
update();
});
QObject::connect(static_cast<FrogPilotParamManageControl*>(toggle), &FrogPilotParamManageControl::manageButtonClicked, [this]() {
update();
});
}
customOnroadUIKeys = {};
customThemeKeys = {};
modelUIKeys = {};
QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotVisualsPanel::hideSubToggles);
QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotVisualsPanel::hideSubToggles);
QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotVisualsPanel::updateMetric);
hideSubToggles();
updateMetric();
}
void FrogPilotVisualsPanel::updateToggles() {
std::thread([this]() {
paramsMemory.putBool("FrogPilotTogglesUpdated", true);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
paramsMemory.putBool("FrogPilotTogglesUpdated", false);
}).detach();
}
void FrogPilotVisualsPanel::updateMetric() {
bool previousIsMetric = isMetric;
isMetric = params.getBool("IsMetric");
if (isMetric != previousIsMetric) {
double distanceConversion = isMetric ? INCH_TO_CM : CM_TO_INCH;
double speedConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT;
}
if (isMetric) {
} else {
}
previousIsMetric = isMetric;
}
void FrogPilotVisualsPanel::parentToggleClicked() {
this->openParentToggle();
}
void FrogPilotVisualsPanel::hideSubToggles() {
for (auto &[key, toggle] : toggles) {
bool subToggles = modelUIKeys.find(key.c_str()) != modelUIKeys.end() ||
customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end() ||
customThemeKeys.find(key.c_str()) != customThemeKeys.end();
toggle->setVisible(!subToggles);
}
this->closeParentToggle();
}
void FrogPilotVisualsPanel::hideEvent(QHideEvent *event) {
hideSubToggles();
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include <set>
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
#include "selfdrive/ui/qt/offroad/settings.h"
class FrogPilotVisualsPanel : public FrogPilotListWidget {
Q_OBJECT
public:
explicit FrogPilotVisualsPanel(SettingsWindow *parent);
signals:
void closeParentToggle();
void openParentToggle();
private:
void hideEvent(QHideEvent *event);
void hideSubToggles();
void parentToggleClicked();
void updateMetric();
void updateToggles();
std::set<QString> customOnroadUIKeys;
std::set<QString> customThemeKeys;
std::set<QString> modelUIKeys;
std::map<std::string, ParamControl*> toggles;
Params params;
Params paramsMemory{"/dev/shm/params"};
bool isMetric = params.getBool("IsMetric");
};