From b00eb57bb735a8c533a28a22ee3aed534afd4a7c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 22 Feb 2023 15:59:07 -0800 Subject: [PATCH 01/45] Ford: adjust curvature rate limits (#27427) * fix up * Update ref_commit --- selfdrive/car/ford/values.py | 4 ++-- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 1c8917446a..3bc56eb9dd 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -28,8 +28,8 @@ class CarControllerParams: # Curvature rate limits # TODO: unify field names used by curvature and angle control cars - # ~2 m/s^3 up, -3 m/s^3 down - ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.004, 0.00044, 0.0002]) + # ~2 m/s^3 up, ~-3 m/s^3 down + ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.004, 0.00044, 0.00016]) ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.006, 0.00066, 0.00024]) ACCEL_MAX = 2.0 # m/s^s max acceleration diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 1d807d75cd..5e7a5c8c0a 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -5f45771d28c8e7112d474edcdd991689c6440acf +a38b267bd2d44945dcd664b2a84e6cd0a6163f91 From 90db46e7756e2eb6d61b1ff23f7cb4a7b356abb9 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 22 Feb 2023 17:26:37 -0800 Subject: [PATCH 02/45] setup: write installer URL to tmpfile (#27426) * setup: write installer URL to tmpfile * missed ptr type --- selfdrive/ui/qt/setup/setup.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/selfdrive/ui/qt/setup/setup.cc b/selfdrive/ui/qt/setup/setup.cc index 392be68a12..409d79796c 100644 --- a/selfdrive/ui/qt/setup/setup.cc +++ b/selfdrive/ui/qt/setup/setup.cc @@ -59,6 +59,11 @@ void Setup::download(QString url) { curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_status); if (ret == CURLE_OK && res_status == 200 && is_elf(tmpfile)) { rename(tmpfile, "/tmp/installer"); + + FILE *fp_url = fopen("/tmp/installer_url", "w"); + fprintf(fp_url, "%s", url.toStdString().c_str()); + fclose(fp_url); + emit finished(true); } else { emit finished(false); From c1be6d945bb2efd6564f80f153c0ff71c59a3505 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 23 Feb 2023 12:44:33 +0800 Subject: [PATCH 03/45] cabana: dispaly current FPS & cached minitues on statusbar (#27430) dispaly current FPS & cached minitues on statusbar --- tools/cabana/mainwin.cc | 17 +++++++++++++++++ tools/cabana/mainwin.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index bc090b2cc0..25e40e15aa 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -63,9 +63,11 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, center_widget, &CenterWidget::setMessage); QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); QObject::connect(can, &AbstractStream::streamStarted, this, &MainWindow::loadDBCFromFingerprint); + QObject::connect(can, &AbstractStream::eventsMerged, this, &MainWindow::updateStatus); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MainWindow::DBCFileChanged); QObject::connect(UndoStack::instance(), &QUndoStack::cleanChanged, this, &MainWindow::undoStackCleanChanged); QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &MainWindow::undoStackIndexChanged); + QObject::connect(&settings, &Settings::changed, this, &MainWindow::updateStatus); } void MainWindow::createActions() { @@ -179,6 +181,9 @@ void MainWindow::createStatusBar() { progress_bar->setVisible(false); statusBar()->addWidget(new QLabel(tr("For Help, Press F1"))); statusBar()->addPermanentWidget(progress_bar); + + statusBar()->addPermanentWidget(status_label = new QLabel(this)); + updateStatus(); } void MainWindow::createShortcuts() { @@ -403,6 +408,18 @@ void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool succe } } +void MainWindow::updateStatus() { + float cached_minutes = 0; + if (!can->liveStreaming()) { + if (auto events = can->events(); !events->empty()) { + cached_minutes = (events->back()->mono_time - events->front()->mono_time) / (1e9 * 60); + } + } else { + settings.max_cached_minutes = settings.max_cached_minutes; + } + status_label->setText(tr("Cached Minutes:%1 FPS:%2").arg(cached_minutes, 0, 'f', 1).arg(settings.fps)); +} + void MainWindow::dockCharts(bool dock) { if (dock && floating_window) { floating_window->removeEventFilter(charts_widget); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index dd53b1f213..2aeb20aea8 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -56,6 +56,7 @@ protected: void undoStackCleanChanged(bool clean); void undoStackIndexChanged(int index); void onlineHelp(); + void updateStatus(); VideoWidget *video_widget = nullptr; QDockWidget *video_dock; @@ -65,6 +66,7 @@ protected: QWidget *floating_window = nullptr; QVBoxLayout *charts_layout; QProgressBar *progress_bar; + QLabel *status_label; QJsonDocument fingerprint_to_dbc; QSplitter *video_splitter;; QString current_file = ""; From 7b43a69089fa862c492eb4d4d1706b19662ff8b4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 22 Feb 2023 21:04:40 -0800 Subject: [PATCH 04/45] Update RELEASES.md --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 0ea4241a35..f71810784a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2,7 +2,7 @@ Version 0.9.2 (2023-03-XX) ======================== * Draw MPC path instead of model predicted path, this is a more accurate representation of what the car will do. -Version 0.9.1 (2023-02-23) +Version 0.9.1 (2023-02-28) ======================== * New driving model * 30% improved height estimation resulting in better driving performance for tall cars From 4e0a3aa0d51c3abd96774bb12a6e28943082fa81 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 23 Feb 2023 19:44:53 +0100 Subject: [PATCH 05/45] cabana: show bus in own column (#27434) --- tools/cabana/messageswidget.cc | 33 +++++++++++++++++++++++---------- tools/cabana/messageswidget.h | 2 +- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index c880c61058..cda3069ad9 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -20,11 +20,15 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { table_widget = new QTableView(this); model = new MessageListModel(this); table_widget->setModel(model); - table_widget->setItemDelegateForColumn(4, new MessageBytesDelegate(table_widget)); + table_widget->setItemDelegateForColumn(5, new MessageBytesDelegate(table_widget)); table_widget->setSelectionBehavior(QAbstractItemView::SelectRows); table_widget->setSelectionMode(QAbstractItemView::SingleSelection); table_widget->setSortingEnabled(true); table_widget->sortByColumn(0, Qt::AscendingOrder); + table_widget->setColumnWidth(0, 150); + table_widget->setColumnWidth(1, 50); + table_widget->setColumnWidth(2, 50); + table_widget->setColumnWidth(3, 50); table_widget->horizontalHeader()->setStretchLastSection(true); table_widget->verticalHeader()->hide(); main_layout->addWidget(table_widget); @@ -108,7 +112,7 @@ void MessagesWidget::reset() { QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return (QString[]){"Name", "ID", "Freq", "Count", "Bytes"}[section]; + return (QString[]){"Name", "Bus", "ID", "Freq", "Count", "Bytes"}[section]; return {}; } @@ -119,12 +123,13 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { switch (index.column()) { case 0: return msgName(id); - case 1: return id.toString(); // TODO: put source and address in separate columns - case 2: return can_data.freq; - case 3: return can_data.count; - case 4: return toHex(can_data.dat); + case 1: return id.source; + case 2: return QString::number(id.address, 16);; + case 3: return can_data.freq; + case 4: return can_data.count; + case 5: return toHex(can_data.dat); } - } else if (role == Qt::UserRole && index.column() == 4) { + } else if (role == Qt::UserRole && index.column() == 5) { QVector colors = can_data.colors; if (!suppressed_bytes.empty()) { for (int i = 0; i < colors.size(); i++) { @@ -171,15 +176,23 @@ void MessageListModel::sortMessages() { }); } else if (sort_column == 1) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - return sort_order == Qt::AscendingOrder ? l < r : l > r; + auto ll = std::pair{l.source, l}; + auto rr = std::pair{r.source, r}; + return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr; }); } else if (sort_column == 2) { + std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { + auto ll = std::pair{l.address, l}; + auto rr = std::pair{r.address, r}; + return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr; + }); + } else if (sort_column == 3) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { auto ll = std::pair{can->lastMessage(l).freq, l}; auto rr = std::pair{can->lastMessage(r).freq, r}; return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr; }); - } else if (sort_column == 3) { + } else if (sort_column == 4) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { auto ll = std::pair{can->lastMessage(l).count, l}; auto rr = std::pair{can->lastMessage(r).count, r}; @@ -200,7 +213,7 @@ void MessageListModel::msgsReceived(const QHash *new_msgs) { } for (int i = 0; i < msgs.size(); ++i) { if (new_msgs->contains(msgs[i])) { - for (int col = 2; col < columnCount(); ++col) + for (int col = 3; col < columnCount(); ++col) emit dataChanged(index(i, col), index(i, col), {Qt::DisplayRole}); } } diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 926d131c8d..ed9e241b0c 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -16,7 +16,7 @@ Q_OBJECT public: MessageListModel(QObject *parent) : QAbstractTableModel(parent) {} QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override { return 5; } + int columnCount(const QModelIndex &parent = QModelIndex()) const override { return 6; } QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; int rowCount(const QModelIndex &parent = QModelIndex()) const override { return msgs.size(); } void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; From a5644faa3f1095c2aa36b12e534fbba1b2ac921d Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 23 Feb 2023 19:45:13 +0100 Subject: [PATCH 06/45] cabana: show units (#27433) * show units on chart y axis * show in signal list * show in historyview * use clear() --- tools/cabana/chartswidget.cc | 12 +++++++++++- tools/cabana/historylog.cc | 10 +++++++++- tools/cabana/signaledit.cc | 3 +++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 8a3a59d989..7f07490abd 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -542,9 +542,16 @@ void ChartView::updateAxisY() { double min = std::numeric_limits::max(); double max = std::numeric_limits::lowest(); + QString unit = sigs[0].sig->unit; + for (auto &s : sigs) { if (!s.series->isVisible()) continue; + // Only show unit when all signals have the same unit + if (unit != s.sig->unit) { + unit.clear(); + } + auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); for (auto it = first; it != last; ++it) { @@ -552,6 +559,8 @@ void ChartView::updateAxisY() { if (it->y() > max) max = it->y(); } } + axis_y->setTitleText(unit); + if (min == std::numeric_limits::max()) min = 0; if (max == std::numeric_limits::lowest()) max = 0; @@ -563,7 +572,8 @@ void ChartView::updateAxisY() { QFontMetrics fm(axis_y->labelsFont()); int n = qMax(int(-qFloor(std::log10((max_y - min_y) / (tick_count - 1)))), 0) + 1; - y_label_width = qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 15; // left margin 15 + int title_spacing = axis_y->titleText().isEmpty() ? 0 : 20; + y_label_width = title_spacing + qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 15; // left margin 15 axis_y->setLabelFormat(QString("%.%1f").arg(n)); emit axisYLabelWidthChanged(y_label_width); } diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index abf0b53af8..deee2f1724 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -48,7 +48,15 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i if (section == 0) { return "Time"; } - return show_signals ? sigs[section - 1]->name : "Data"; + if (show_signals) { + QString name = sigs[section - 1]->name; + if (!sigs[section - 1]->unit.isEmpty()) { + name += QString(" (%1)").arg(sigs[section - 1]->unit); + } + return name; + } else { + return "Data"; + } } else if (role == Qt::BackgroundRole && section > 0 && show_signals) { return QBrush(getColor(sigs[section - 1])); } diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index c614ecb247..5fcfc116c1 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -62,6 +62,9 @@ void SignalModel::updateState(const QHash *msgs) { int row = 0; for (auto item : root->children) { QString value = QString::number(get_raw_value((uint8_t *)dat.begin(), dat.size(), *item->sig)); + if (!item->sig->unit.isEmpty()){ + value += " " + item->sig->unit; + } if (value != item->sig_val) { item->sig_val = value; emit dataChanged(index(row, 1), index(row, 1), {Qt::DisplayRole}); From dc4ebeb29c569c2b3bc9c687778b6e4ed754d329 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 24 Feb 2023 02:45:59 +0800 Subject: [PATCH 07/45] cabana: added a new series type to chart: step line (#27422) * add step line series * create buttons in createToolButtons * add inline function clearTrackPoints * do not show tooltip if series is invisible * use QActionGroup --- tools/cabana/chartswidget.cc | 145 +++++++++++++++++++++-------------- tools/cabana/chartswidget.h | 19 +++-- tools/cabana/settings.cc | 2 +- 3 files changed, 103 insertions(+), 63 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 7f07490abd..d895191d86 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -1,5 +1,6 @@ #include "tools/cabana/chartswidget.h" +#include #include #include #include @@ -183,7 +184,7 @@ void ChartsWidget::settingChanged() { range_slider->setRange(1, settings.max_cached_minutes * 60); for (auto c : charts) { c->setFixedHeight(settings.chart_height); - c->setSeriesType(settings.chart_series_type == 0 ? QAbstractSeries::SeriesTypeLine : QAbstractSeries::SeriesTypeScatter); + c->setSeriesType((SeriesType)settings.chart_series_type); } } @@ -309,7 +310,7 @@ bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { // ChartView ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { - series_type = settings.chart_series_type == 0 ? QAbstractSeries::SeriesTypeLine : QAbstractSeries::SeriesTypeScatter; + series_type = (SeriesType)settings.chart_series_type; QChart *chart = new QChart(); chart->setBackgroundVisible(false); axis_x = new QValueAxis(this); @@ -325,40 +326,54 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { background->setPen(Qt::NoPen); background->setZValue(chart->zValue() - 1); - move_icon = new QGraphicsPixmapItem(utils::icon("grip-horizontal"), chart); + setChart(chart); + + createToolButtons(); + setRenderHint(QPainter::Antialiasing); + // TODO: enable zoomIn/seekTo in live streaming mode. + setRubberBand(can->liveStreaming() ? QChartView::NoRubberBand : QChartView::HorizontalRubberBand); + + QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartView::signalRemoved); + QObject::connect(dbc(), &DBCManager::signalUpdated, this, &ChartView::signalUpdated); + QObject::connect(dbc(), &DBCManager::msgRemoved, this, &ChartView::msgRemoved); + QObject::connect(dbc(), &DBCManager::msgUpdated, this, &ChartView::msgUpdated); +} + +void ChartView::createToolButtons() { + move_icon = new QGraphicsPixmapItem(utils::icon("grip-horizontal"), chart()); move_icon->setToolTip(tr("Drag and drop to combine charts")); QToolButton *remove_btn = toolButton("x", tr("Remove Chart")); - close_btn_proxy = new QGraphicsProxyWidget(chart); + close_btn_proxy = new QGraphicsProxyWidget(chart()); close_btn_proxy->setWidget(remove_btn); - close_btn_proxy->setZValue(chart->zValue() + 11); + close_btn_proxy->setZValue(chart()->zValue() + 11); - QToolButton *manage_btn = toolButton("list", ""); + // series types QMenu *menu = new QMenu(this); - line_series_action = menu->addAction(tr("Line"), [this]() { setSeriesType(QAbstractSeries::SeriesTypeLine); }); - line_series_action->setCheckable(true); - line_series_action->setChecked(series_type == QAbstractSeries::SeriesTypeLine); - scatter_series_action = menu->addAction(tr("Scatter"), [this]() { setSeriesType(QAbstractSeries::SeriesTypeScatter); }); - scatter_series_action->setCheckable(true); - scatter_series_action->setChecked(series_type == QAbstractSeries::SeriesTypeScatter); + auto change_series_group = new QActionGroup(menu); + change_series_group->setExclusive(true); + QStringList types{tr("line"), tr("Step Line"), tr("Scatter")}; + for (int i = 0; i < types.size(); ++i) { + QAction *act = new QAction(types[i], change_series_group); + act->setData(i); + act->setCheckable(true); + act->setChecked(i == (int)series_type); + menu->addAction(act); + } menu->addSeparator(); menu->addAction(tr("Manage series"), this, &ChartView::manageSeries); + + QToolButton *manage_btn = toolButton("list", ""); manage_btn->setMenu(menu); manage_btn->setPopupMode(QToolButton::InstantPopup); - manage_btn_proxy = new QGraphicsProxyWidget(chart); + manage_btn_proxy = new QGraphicsProxyWidget(chart()); manage_btn_proxy->setWidget(manage_btn); - manage_btn_proxy->setZValue(chart->zValue() + 11); + manage_btn_proxy->setZValue(chart()->zValue() + 11); - setChart(chart); - setRenderHint(QPainter::Antialiasing); - // TODO: enable zoomIn/seekTo in live streaming mode. - setRubberBand(can->liveStreaming() ? QChartView::NoRubberBand : QChartView::HorizontalRubberBand); - - QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartView::signalRemoved); - QObject::connect(dbc(), &DBCManager::signalUpdated, this, &ChartView::signalUpdated); - QObject::connect(dbc(), &DBCManager::msgRemoved, this, &ChartView::msgRemoved); - QObject::connect(dbc(), &DBCManager::msgUpdated, this, &ChartView::msgUpdated); QObject::connect(remove_btn, &QToolButton::clicked, this, &ChartView::remove); + QObject::connect(change_series_group, &QActionGroup::triggered, [this](QAction *action) { + setSeriesType((SeriesType)action->data().toInt()); + }); } void ChartView::addSeries(const MessageId &msg_id, const Signal *sig) { @@ -476,7 +491,7 @@ void ChartView::updateSeriesPoints() { int num_points = std::max(end - begin, 1); int pixels_per_point = width() / num_points; - if (series_type == QAbstractSeries::SeriesTypeScatter) { + if (series_type == SeriesType::Scatter) { ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 2, 8)); } else { s.series->setPointsVisible(pixels_per_point > 20); @@ -490,7 +505,9 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even if (!sig || s.sig == sig) { if (clear) { s.vals.clear(); + s.step_vals.clear(); s.vals.reserve(settings.max_cached_minutes * 60 * 100); // [n]seconds * 100hz + s.step_vals.reserve(settings.max_cached_minutes * 60 * 100 * 2); s.last_value_mono_time = 0; } s.series->setColor(getColor(s.sig)); @@ -498,6 +515,7 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even struct Chunk { std::vector::const_iterator first, second; QVector vals; + QVector step_vals; }; // split into one minitue chunks QVector chunks; @@ -510,6 +528,7 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even QtConcurrent::blockingMap(chunks, [&](Chunk &chunk) { chunk.vals.reserve(60 * 100); // 100 hz + chunk.step_vals.reserve(60 * 100 * 2); // 100 hz double route_start_time = can->routeStartTime(); for (auto it = chunk.first; it != chunk.second; ++it) { if ((*it)->which == cereal::Event::Which::CAN) { @@ -519,6 +538,10 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even double value = get_raw_value((uint8_t *)dat.begin(), dat.size(), *s.sig); double ts = ((*it)->mono_time / (double)1e9) - route_start_time; // seconds chunk.vals.push_back({ts, value}); + if (!chunk.step_vals.empty()) { + chunk.step_vals.push_back({ts, chunk.step_vals.back().y()}); + } + chunk.step_vals.push_back({ts,value}); } } } @@ -526,11 +549,12 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even }); for (auto &c : chunks) { s.vals.append(c.vals); + s.step_vals.append(c.step_vals); } if (events->size()) { s.last_value_mono_time = events->back()->mono_time; } - s.series->replace(s.vals); + s.series->replace(series_type == SeriesType::StepLine ? s.step_vals : s.vals); } } updateAxisY(); @@ -607,7 +631,7 @@ qreal ChartView::niceNumber(qreal x, bool ceiling) { } void ChartView::leaveEvent(QEvent *event) { - track_pts.clear(); + clearTrackPoints(); scene()->update(); QChartView::leaveEvent(event); } @@ -663,26 +687,31 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { auto rubber = findChild(); bool is_zooming = rubber && rubber->isVisible(); const auto plot_area = chart()->plotArea(); - track_pts.clear(); + clearTrackPoints(); + if (!is_zooming && plot_area.contains(ev->pos())) { - track_pts.resize(sigs.size()); QStringList text_list; const double sec = chart()->mapToValue(ev->pos()).x(); - for (int i = 0; i < sigs.size(); ++i) { - QString value = "--"; + qreal x = -1; + for (auto &s : sigs) { + if (!s.series->isVisible()) continue; + // use reverse iterator to find last item <= sec. - auto it = std::lower_bound(sigs[i].vals.rbegin(), sigs[i].vals.rend(), sec, [](auto &p, double x) { return p.x() > x; }); - if (it != sigs[i].vals.rend() && it->x() >= axis_x->min()) { - value = QString::number(it->y()); - track_pts[i] = chart()->mapToPosition(*it); + auto it = std::lower_bound(s.vals.rbegin(), s.vals.rend(), sec, [](auto &p, double x) { return p.x() > x; }); + if (it != s.vals.rend() && it->x() >= axis_x->min()) { + s.track_pt = chart()->mapToPosition(*it); + x = std::max(x, s.track_pt.x()); } - text_list.push_back(QString("%2: %3").arg(sigs[i].series->color().name(), sigs[i].sig->name, value)); + text_list.push_back(QString("%2: %3") + .arg(s.series->color().name(), s.sig->name, + s.track_pt.isNull() ? "--" : QString::number(s.track_pt.y()))); + } + if (x < 0) { + x = ev->pos().x(); } - auto max = std::max_element(track_pts.begin(), track_pts.end(), [](auto &a, auto &b) { return a.x() < b.x(); }); - auto pt = (max == track_pts.end()) ? ev->pos() : *max; - text_list.push_front(QString::number(chart()->mapToValue(pt).x(), 'f', 3)); - QPointF tooltip_pt(pt.x() + 12, plot_area.top() - 20); - QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), pt.isNull() ? "" : text_list.join("
"), this, plot_area.toRect()); + text_list.push_front(QString::number(chart()->mapToValue({x, 0}).x(), 'f', 3)); + QPointF tooltip_pt(x + 12, plot_area.top() - 20); + QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), text_list.join("
"), this, plot_area.toRect()); scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } else { QToolTip::hideText(); @@ -727,6 +756,7 @@ void ChartView::dropEvent(QDropEvent *event) { } void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { + // draw time line qreal x = chart()->mapToPosition(QPointF{cur_sec, 0}).x(); x = std::clamp(x, chart()->plotArea().left(), chart()->plotArea().right()); qreal y1 = chart()->plotArea().top() - 2; @@ -734,18 +764,20 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { painter->setPen(QPen(chart()->titleBrush().color(), 2)); painter->drawLine(QPointF{x, y1}, QPointF{x, y2}); - auto max = std::max_element(track_pts.begin(), track_pts.end(), [](auto &a, auto &b) { return a.x() < b.x(); }); - if (max != track_pts.end() && !max->isNull()) { - painter->setPen(QPen(Qt::darkGray, 1, Qt::DashLine)); - painter->drawLine(QPointF{max->x(), y1}, QPointF{max->x(), y2}); - painter->setPen(Qt::NoPen); - for (int i = 0; i < track_pts.size(); ++i) { - if (!track_pts[i].isNull() && i < sigs.size()) { - painter->setBrush(sigs[i].series->color().darker(125)); - painter->drawEllipse(track_pts[i], 5.5, 5.5); - } + // draw track points + painter->setPen(Qt::NoPen); + qreal track_line_x = -1; + for (auto &s : sigs) { + if (!s.track_pt.isNull() && s.series->isVisible()) { + painter->setBrush(s.series->color().darker(125)); + painter->drawEllipse(s.track_pt, 5.5, 5.5); + track_line_x = std::max(track_line_x, s.track_pt.x()); } } + if (track_line_x > 0) { + painter->setPen(QPen(Qt::darkGray, 1, Qt::DashLine)); + painter->drawLine(QPointF{track_line_x, y1}, QPointF{track_line_x, y2}); + } // paint points. OpenGL mode lacks certain features (such as showing points) painter->setPen(Qt::NoPen); @@ -761,11 +793,14 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { } } -QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type, QColor color) { +QXYSeries *ChartView::createSeries(SeriesType type, QColor color) { QXYSeries *series = nullptr; - if (type == QAbstractSeries::SeriesTypeLine) { + if (type == SeriesType::Line) { series = new QLineSeries(this); chart()->legend()->setMarkerShape(QLegend::MarkerShapeRectangle); + } else if (type == SeriesType::StepLine) { + series = new QLineSeries(this); + chart()->legend()->setMarkerShape(QLegend::MarkerShapeFromSeries); } else { series = new QScatterSeries(this); chart()->legend()->setMarkerShape(QLegend::MarkerShapeCircle); @@ -786,9 +821,7 @@ QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type, QColor colo return series; } -void ChartView::setSeriesType(QAbstractSeries::SeriesType type) { - line_series_action->setChecked(type == QAbstractSeries::SeriesTypeLine); - scatter_series_action->setChecked(type == QAbstractSeries::SeriesTypeScatter); +void ChartView::setSeriesType(SeriesType type) { if (type != series_type) { series_type = type; for (auto &s : sigs) { @@ -797,7 +830,7 @@ void ChartView::setSeriesType(QAbstractSeries::SeriesType type) { } for (auto &s : sigs) { auto series = createSeries(series_type, getColor(s.sig)); - series->replace(s.vals); + series->replace(series_type == SeriesType::StepLine ? s.step_vals : s.vals); s.series = series; } updateSeriesPoints(); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index a1dcf32513..76943c1fe9 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -20,6 +20,12 @@ using namespace QtCharts; const int CHART_MIN_WIDTH = 300; +enum class SeriesType { + Line = 0, + StepLine, + Scatter +}; + class ChartView : public QChartView { Q_OBJECT @@ -29,7 +35,7 @@ public: bool hasSeries(const MessageId &msg_id, const Signal *sig) const; void updateSeries(const Signal *sig = nullptr, const std::vector *events = nullptr, bool clear = true); void updatePlot(double cur, double min, double max); - void setSeriesType(QAbstractSeries::SeriesType type); + void setSeriesType(SeriesType type); void updatePlotArea(int left); struct SigItem { @@ -37,7 +43,9 @@ public: const Signal *sig = nullptr; QXYSeries *series = nullptr; QVector vals; + QVector step_vals; uint64_t last_value_mono_time = 0; + QPointF track_pt{}; }; signals: @@ -57,6 +65,7 @@ private slots: void signalRemoved(const Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); } private: + void createToolButtons(); void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *ev) override; @@ -70,15 +79,15 @@ private: void drawForeground(QPainter *painter, const QRectF &rect) override; std::tuple getNiceAxisNumbers(qreal min, qreal max, int tick_count); qreal niceNumber(qreal x, bool ceiling); - QXYSeries *createSeries(QAbstractSeries::SeriesType type, QColor color); + QXYSeries *createSeries(SeriesType type, QColor color); void updateSeriesPoints(); void removeIf(std::function predicate); + inline void clearTrackPoints() { for (auto &s : sigs) s.track_pt = {}; } int y_label_width = 0; int align_to = 0; QValueAxis *axis_x; QValueAxis *axis_y; - QVector track_pts; QGraphicsPixmapItem *move_icon; QGraphicsProxyWidget *close_btn_proxy; QGraphicsProxyWidget *manage_btn_proxy; @@ -86,9 +95,7 @@ private: QList sigs; double cur_sec = 0; const QString mime_type = "application/x-cabanachartview"; - QAbstractSeries::SeriesType series_type = QAbstractSeries::SeriesTypeLine; - QAction *line_series_action; - QAction *scatter_series_action; + SeriesType series_type = SeriesType::Line; friend class ChartsWidget; }; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 6cbd16cabf..23f001efff 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -65,7 +65,7 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { form_layout->addRow(tr("Max Cached Minutes"), cached_minutes); chart_series_type = new QComboBox(this); - chart_series_type->addItems({tr("Line"), tr("Scatter")}); + chart_series_type->addItems({tr("Line"), tr("Step Line"), tr("Scatter")}); chart_series_type->setCurrentIndex(settings.chart_series_type); form_layout->addRow(tr("Chart Default Series Type"), chart_series_type); From 7a3b3e8b567ea476088e6f3d7344c7220e35e398 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 23 Feb 2023 15:01:10 -0800 Subject: [PATCH 08/45] better main off alert (#27442) --- selfdrive/controls/lib/events.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 4e664d8cf0..e4ddfb5326 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -317,9 +317,9 @@ def modeld_lagging_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubM def wrong_car_mode_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: - text = "Cruise Mode Disabled" + text = "Enable Adaptive Cruise to Engage" if CP.carName == "honda": - text = "Main Switch Off" + text = "Enable Main Switch to Engage" return NoEntryAlert(text) From d5688ae49fd8652bf500ec145f2f3aa711c6bbf3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 23 Feb 2023 16:18:32 -0800 Subject: [PATCH 09/45] Angle control: fix limiting bug (#27428) * fix steer up bug * Update ref_commit --- selfdrive/car/__init__.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index c056f7ca3d..a90f023ed1 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -115,7 +115,7 @@ def apply_toyota_steer_torque_limits(apply_torque, apply_torque_last, motor_torq def apply_std_steer_angle_limits(apply_angle, apply_angle_last, v_ego, LIMITS): # pick angle rate limits based on wind up/down - steer_up = apply_angle_last * apply_angle > 0. and abs(apply_angle) > abs(apply_angle_last) + steer_up = apply_angle_last * apply_angle >= 0. and abs(apply_angle) > abs(apply_angle_last) rate_limits = LIMITS.ANGLE_RATE_LIMIT_UP if steer_up else LIMITS.ANGLE_RATE_LIMIT_DOWN angle_rate_lim = interp(v_ego, rate_limits.speed_bp, rate_limits.angle_v) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 5e7a5c8c0a..9991154b9a 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -a38b267bd2d44945dcd664b2a84e6cd0a6163f91 +772f30de36fc7f8421dabb779cc02f45eb83d7bb From 79e6910106de6ae25127613728332e8b743d962a Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 23 Feb 2023 19:45:48 -0800 Subject: [PATCH 10/45] setup: detailed error messages (#27429) * setup: specific error state for non-executable file * Result -> DownloadResult * complete -> finished * rename widgets to be more consistent * fix typos * fix setCurrentIndex This appears to have different behaviour on device than on PC (off by one) * load fonts * copy Co-authored-by: Adeeb Shihadeh * Revert "load fonts" This reverts commit e8756598ed99aea39ef5721453e97920a494051c. * font family * undo * less widgets more better * font size --------- Co-authored-by: Adeeb Shihadeh --- selfdrive/ui/qt/setup/setup.cc | 41 ++++++++++++++++-------- selfdrive/ui/qt/setup/setup.h | 5 +-- selfdrive/ui/translations/main_de.ts | 8 +++++ selfdrive/ui/translations/main_ja.ts | 8 +++++ selfdrive/ui/translations/main_ko.ts | 8 +++++ selfdrive/ui/translations/main_pt-BR.ts | 8 +++++ selfdrive/ui/translations/main_zh-CHS.ts | 8 +++++ selfdrive/ui/translations/main_zh-CHT.ts | 8 +++++ 8 files changed, 78 insertions(+), 16 deletions(-) diff --git a/selfdrive/ui/qt/setup/setup.cc b/selfdrive/ui/qt/setup/setup.cc index 409d79796c..3de6255521 100644 --- a/selfdrive/ui/qt/setup/setup.cc +++ b/selfdrive/ui/qt/setup/setup.cc @@ -34,7 +34,7 @@ bool is_elf(char *fname) { void Setup::download(QString url) { CURL *curl = curl_easy_init(); if (!curl) { - emit finished(false); + emit finished(url, tr("Something went wrong. Reboot the device.")); return; } @@ -57,16 +57,19 @@ void Setup::download(QString url) { int ret = curl_easy_perform(curl); long res_status = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_status); - if (ret == CURLE_OK && res_status == 200 && is_elf(tmpfile)) { + + if (ret != CURLE_OK || res_status != 200) { + emit finished(url, tr("Ensure the entered URL is valid, and the device’s internet connection is good.")); + } else if (!is_elf(tmpfile)) { + emit finished(url, tr("No custom software found at this URL.")); + } else { rename(tmpfile, "/tmp/installer"); FILE *fp_url = fopen("/tmp/installer_url", "w"); fprintf(fp_url, "%s", url.toStdString().c_str()); fclose(fp_url); - emit finished(true); - } else { - emit finished(false); + emit finished(url); } curl_slist_free_all(list); @@ -239,10 +242,10 @@ QWidget * Setup::downloading() { return widget; } -QWidget * Setup::download_failed() { +QWidget * Setup::download_failed(QLabel *url, QLabel *body) { QWidget *widget = new QWidget(); QVBoxLayout *main_layout = new QVBoxLayout(widget); - main_layout->setContentsMargins(55, 225, 55, 55); + main_layout->setContentsMargins(55, 185, 55, 55); main_layout->setSpacing(0); QLabel *title = new QLabel(tr("Download Failed")); @@ -251,7 +254,13 @@ QWidget * Setup::download_failed() { main_layout->addSpacing(67); - QLabel *body = new QLabel(tr("Ensure the entered URL is valid, and the device’s internet connection is good.")); + url->setWordWrap(true); + url->setAlignment(Qt::AlignTop | Qt::AlignLeft); + url->setStyleSheet("font-family: \"JetBrains Mono\"; font-size: 64px; font-weight: 400; margin-right: 100px;"); + main_layout->addWidget(url); + + main_layout->addSpacing(48); + body->setWordWrap(true); body->setAlignment(Qt::AlignTop | Qt::AlignLeft); body->setStyleSheet("font-size: 80px; font-weight: 300; margin-right: 100px;"); @@ -276,7 +285,7 @@ QWidget * Setup::download_failed() { restart->setProperty("primary", true); blayout->addWidget(restart); QObject::connect(restart, &QPushButton::clicked, this, [=]() { - setCurrentIndex(2); + setCurrentIndex(1); }); widget->setStyleSheet(R"( @@ -309,15 +318,19 @@ Setup::Setup(QWidget *parent) : QStackedWidget(parent) { downloading_widget = downloading(); addWidget(downloading_widget); - failed_widget = download_failed(); + QLabel *url_label = new QLabel(); + QLabel *body_label = new QLabel(); + failed_widget = download_failed(url_label, body_label); addWidget(failed_widget); - QObject::connect(this, &Setup::finished, [=](bool success) { - // hide setup on success - qDebug() << "finished" << success; - if (success) { + QObject::connect(this, &Setup::finished, [=](const QString &url, const QString &error) { + qDebug() << "finished" << url << error; + if (error.isEmpty()) { + // hide setup on success QTimer::singleShot(3000, this, &QWidget::hide); } else { + url_label->setText(url); + body_label->setText(error); setCurrentWidget(failed_widget); } }); diff --git a/selfdrive/ui/qt/setup/setup.h b/selfdrive/ui/qt/setup/setup.h index f990b5a6cb..bf5d97070d 100644 --- a/selfdrive/ui/qt/setup/setup.h +++ b/selfdrive/ui/qt/setup/setup.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -15,13 +16,13 @@ private: QWidget *getting_started(); QWidget *network_setup(); QWidget *downloading(); - QWidget *download_failed(); + QWidget *download_failed(QLabel *url, QLabel *body); QWidget *failed_widget; QWidget *downloading_widget; signals: - void finished(bool success); + void finished(const QString &url, const QString &error = ""); public slots: void nextPage(); diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 77670ede3b..5f3511d3cc 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -703,6 +703,14 @@ This may take up to a minute. Start over Von neuem beginnen + + No custom software found at this URL. + + + + Something went wrong. Reboot the device. + + SetupWidget diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 856beee7bc..1e0223606b 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -701,6 +701,14 @@ This may take up to a minute. Start over 最初からやり直す + + No custom software found at this URL. + + + + Something went wrong. Reboot the device. + + SetupWidget diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index ee5bb4fd36..5470e57ce5 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -701,6 +701,14 @@ This may take up to a minute. Start over 다시 시작 + + No custom software found at this URL. + + + + Something went wrong. Reboot the device. + + SetupWidget diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 156b6f16c1..5c4eab3327 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -705,6 +705,14 @@ This may take up to a minute. Start over Inicializar + + No custom software found at this URL. + + + + Something went wrong. Reboot the device. + + SetupWidget diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index f295a72938..cfc055ac98 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -699,6 +699,14 @@ This may take up to a minute. Start over 重来 + + No custom software found at this URL. + + + + Something went wrong. Reboot the device. + + SetupWidget diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index b7636c18c5..e4058ee0db 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -701,6 +701,14 @@ This may take up to a minute. Start over 重新開始 + + No custom software found at this URL. + + + + Something went wrong. Reboot the device. + + SetupWidget From f64fa07b0a42bb04d036f1280953dbbd27de41a0 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 23 Feb 2023 19:46:06 -0800 Subject: [PATCH 11/45] setup: set download timeout (#27441) --- selfdrive/ui/qt/setup/setup.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/ui/qt/setup/setup.cc b/selfdrive/ui/qt/setup/setup.cc index 3de6255521..de5021c8bc 100644 --- a/selfdrive/ui/qt/setup/setup.cc +++ b/selfdrive/ui/qt/setup/setup.cc @@ -53,6 +53,7 @@ void Setup::download(QString url) { curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_USERAGENT, (USER_AGENT + version).c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L); int ret = curl_easy_perform(curl); long res_status = 0; From 608ac253df5295187c6c7289b5b41a983482123e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 24 Feb 2023 12:02:46 +0800 Subject: [PATCH 12/45] cabana: right align signal values & fixed text overflow (#27444) right align the signal values --- tools/cabana/signaledit.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 5fcfc116c1..d5cd4ae825 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -338,6 +338,15 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op text = painter->fontMetrics().elidedText(text, Qt::ElideRight, text_rect.width()); painter->drawText(text_rect, option.displayAlignment, text); painter->restore(); + } else if (index.column() == 1 && item && item->type == SignalModel::Item::Sig) { + // draw signal value + if (option.state & QStyle::State_Selected) { + painter->fillRect(option.rect, option.palette.highlight()); + } + painter->setPen((option.state & QStyle::State_Selected ? option.palette.highlightedText() : option.palette.text()).color()); + QRect rc = option.rect.adjusted(0, 0, -70, 0); + auto text = painter->fontMetrics().elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, rc.width()); + painter->drawText(rc, Qt::AlignRight | Qt::AlignVCenter, text); } else { QStyledItemDelegate::paint(painter, option, index); } From c80bc583817991a47bdcb59cc9d88713b1322b88 Mon Sep 17 00:00:00 2001 From: Robbe Derks Date: Fri, 24 Feb 2023 17:01:12 +0100 Subject: [PATCH 13/45] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 9fe24bd368..1923b14189 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 9fe24bd3683377146b04c68ab94d0935f0bd9d78 +Subproject commit 1923b1418933e464ff7460a3e0a05d63aad0d53b From 78116029d33ab7724daa087201f1743fd34d6a19 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 26 Feb 2023 06:27:18 +0800 Subject: [PATCH 14/45] cabana: replace hardcoded margins, colors, spacing with values from style. (#27449) replace hardcoded margins, colors, spacing improve performance of MessageBytesDelegate --- tools/cabana/binaryview.cc | 7 ++----- tools/cabana/chartswidget.cc | 21 +++++++++++--------- tools/cabana/historylog.cc | 4 +++- tools/cabana/mainwin.cc | 5 +++++ tools/cabana/messageswidget.cc | 4 +++- tools/cabana/signaledit.cc | 20 ++++++++++++------- tools/cabana/util.cc | 36 ++++++++++++++++++++++------------ tools/cabana/util.h | 9 +++++++-- 8 files changed, 68 insertions(+), 38 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index d9b00f6882..120a85a330 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -293,7 +293,6 @@ void BinaryViewModel::updateState() { double max_f = 255.0; double factor = 0.25; double scaler = max_f / log2(1.0 + factor); - char hex[3] = {'\0'}; for (int i = 0; i < binary.size(); ++i) { for (int j = 0; j < 8; ++j) { auto &item = items[i * column_count + j]; @@ -305,9 +304,7 @@ void BinaryViewModel::updateState() { double alpha = std::clamp(offset + log2(1.0 + factor * (double)n / (double)last_msg.count) * scaler, min_f, max_f); item.bg_color.setAlpha(alpha); } - hex[0] = toHex(binary[i] >> 4); - hex[1] = toHex(binary[i] & 0xf); - items[i * column_count + 8].val = hex; + items[i * column_count + 8].val = toHex(binary[i]); items[i * column_count + 8].bg_color = last_msg.colors[i]; } for (int i = binary.size() * column_count; i < items.size(); ++i) { @@ -375,7 +372,7 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op bg.setAlpha(std::max(50, bg.alpha())); } painter->fillRect(option.rect, bg); - painter->setPen(Qt::black); + painter->setPen(option.palette.color(QPalette::Text)); } } diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index d895191d86..7982a5899c 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -25,11 +25,12 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { // toolbar QToolBar *toolbar = new QToolBar(tr("Charts"), this); - toolbar->setIconSize({16, 16}); + int icon_size = style()->pixelMetric(QStyle::PM_SmallIconSize); + toolbar->setIconSize({icon_size, icon_size}); QAction *new_plot_btn = toolbar->addAction(utils::icon("file-plus"), tr("New Plot")); toolbar->addWidget(title_label = new QLabel()); - title_label->setContentsMargins(0, 0, 12, 0); + title_label->setContentsMargins(0, 0, style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing), 0); QMenu *menu = new QMenu(this); for (int i = 0; i < MAX_COLUMN_COUNT; ++i) { @@ -77,8 +78,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { main_layout->addWidget(charts_scroll); // init settings - use_dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > - QApplication::style()->standardPalette().color(QPalette::Background).value(); + use_dark_theme = QApplication::palette().color(QPalette::WindowText).value() > + QApplication::palette().color(QPalette::Background).value(); column_count = std::clamp(settings.chart_column_count, 1, MAX_COLUMN_COUNT); max_chart_range = std::clamp(settings.chart_range, 1, settings.max_cached_minutes * 60); display_range = {0, max_chart_range}; @@ -322,7 +323,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { chart->setMargins({0, 0, 0, 0}); background = new QGraphicsRectItem(chart); - background->setBrush(Qt::white); + background->setBrush(QApplication::palette().color(QPalette::Base)); background->setPen(Qt::NoPen); background->setZValue(chart->zValue() - 1); @@ -443,10 +444,12 @@ void ChartView::manageSeries() { void ChartView::resizeEvent(QResizeEvent *event) { updatePlotArea(align_to); - int x = event->size().width() - close_btn_proxy->size().width() - 11; - close_btn_proxy->setPos(x, 8); - manage_btn_proxy->setPos(x - manage_btn_proxy->size().width() - 5, 8); - move_icon->setPos(11, 8); + int top_margin = style()->pixelMetric(QStyle::PM_LayoutTopMargin); + int spacing = style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); + int x = event->size().width() - close_btn_proxy->size().width() - style()->pixelMetric(QStyle::PM_LayoutRightMargin); + close_btn_proxy->setPos(x, top_margin); + manage_btn_proxy->setPos(x - manage_btn_proxy->size().width() - spacing, top_margin); + move_icon->setPos(style()->pixelMetric(QStyle::PM_LayoutLeftMargin), top_margin); QChartView::resizeEvent(event); } diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index deee2f1724..57f65b97d8 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -15,8 +15,10 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { return QString::number((m.mono_time / (double)1e9) - can->routeStartTime(), 'f', 2); } return show_signals ? QString::number(m.sig_values[index.column() - 1]) : toHex(m.data); - } else if (role == Qt::UserRole && index.column() == 1 && !show_signals) { + } else if (role == ColorsRole) { return QVariant::fromValue(m.colors); + } else if (role == BytesRole) { + return m.data; } return {}; } diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 25e40e15aa..282a541244 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -58,6 +58,11 @@ MainWindow::MainWindow() : QMainWindow() { fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); } + setStyleSheet(QString(R"(QMainWindow::separator { + width: %1px; /* when vertical */ + height: %1px; /* when horizontal */ + })").arg(style()->pixelMetric(QStyle::PM_SplitterWidth))); + QObject::connect(this, &MainWindow::showMessage, statusBar(), &QStatusBar::showMessage); QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, center_widget, &CenterWidget::setMessage); diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index cda3069ad9..b4a7ed7b34 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -129,7 +129,7 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { case 4: return can_data.count; case 5: return toHex(can_data.dat); } - } else if (role == Qt::UserRole && index.column() == 5) { + } else if (role == ColorsRole) { QVector colors = can_data.colors; if (!suppressed_bytes.empty()) { for (int i = 0; i < colors.size(); i++) { @@ -139,6 +139,8 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { } } return QVariant::fromValue(colors); + } else if (role == BytesRole) { + return can_data.dat; } return {}; } diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index d5cd4ae825..e425a13f82 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -322,19 +322,22 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op // color label auto bg_color = getColor(item->sig); - QRect rc{option.rect.left(), option.rect.top(), color_label_width, option.rect.height()}; + int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; + int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin); + QRect rc{option.rect.left() + h_margin, option.rect.top(), color_label_width, option.rect.height()}; painter->setPen(Qt::NoPen); painter->setBrush(item->highlight ? bg_color.darker(125) : bg_color); - painter->drawRoundedRect(rc.adjusted(0, 2, 0, -2), 3, 3); + painter->drawRoundedRect(rc.adjusted(0, v_margin, 0, -v_margin), 3, 3); painter->setPen(item->highlight ? Qt::white : Qt::black); painter->setFont(small_font); painter->drawText(rc, Qt::AlignCenter, QString::number(item->row() + 1)); // signal name painter->setFont(option.font); - painter->setPen((option.state & QStyle::State_Selected ? option.palette.highlightedText() : option.palette.text()).color()); + painter->setPen(option.palette.color(option.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text)); QString text = index.data(Qt::DisplayRole).toString(); - QRect text_rect = option.rect.adjusted(rc.width() + 6, 0, 0, 0); + QRect text_rect = option.rect; + text_rect.setLeft(rc.right() + h_margin * 2); text = painter->fontMetrics().elidedText(text, Qt::ElideRight, text_rect.width()); painter->drawText(text_rect, option.displayAlignment, text); painter->restore(); @@ -343,7 +346,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); } - painter->setPen((option.state & QStyle::State_Selected ? option.palette.highlightedText() : option.palette.text()).color()); + painter->setPen(option.palette.color(option.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text)); QRect rc = option.rect.adjusted(0, 0, -70, 0); auto text = painter->fontMetrics().elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, rc.width()); painter->drawText(rc, Qt::AlignRight | Qt::AlignVCenter, text); @@ -442,8 +445,11 @@ void SignalView::rowsChanged() { if (!tree->indexWidget(index)) { QWidget *w = new QWidget(this); QHBoxLayout *h = new QHBoxLayout(w); - h->setContentsMargins(0, 2, 0, 2); - h->addStretch(1); + int v_margin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin); + int h_margin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin); + h->setContentsMargins(0, v_margin, -h_margin, v_margin); + h->setSpacing(style()->pixelMetric(QStyle::PM_ToolBarItemSpacing)); + h->addStretch(0); auto remove_btn = toolButton("x", tr("Remove signal")); auto plot_btn = toolButton("graph-up", ""); diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 4f79f9a3ac..5e4f505d29 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -71,26 +71,26 @@ void ChangeTracker::clear() { MessageBytesDelegate::MessageBytesDelegate(QObject *parent) : QStyledItemDelegate(parent) { fixed_font = QFontDatabase::systemFont(QFontDatabase::FixedFont); + byte_width = QFontMetrics(fixed_font).width("00 "); } void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + auto colors = index.data(ColorsRole).value>(); + auto byte_list = index.data(BytesRole).toByteArray(); + + int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin); + int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); + QRect rc{option.rect.left() + h_margin, option.rect.top() + v_margin, byte_width, option.rect.height() - 2 * v_margin}; + auto color_role = option.state & QStyle::State_Selected ? QPalette::HighlightedText: QPalette::Text; painter->setPen(option.palette.color(color_role)); painter->setFont(fixed_font); - int space = painter->boundingRect(option.rect, option.displayAlignment, " ").width(); - QRect pos = painter->boundingRect(option.rect, option.displayAlignment, "00").adjusted(0, 0, 2, 0); - pos.moveLeft(pos.x() + space); - int m = space / 2; - const QMargins margins(m, m, m, m); - - auto colors = index.data(Qt::UserRole).value>(); - auto byte_list = index.data(Qt::DisplayRole).toString().split(" "); for (int i = 0; i < byte_list.size(); ++i) { if (i < colors.size() && colors[i].alpha() > 0) { - painter->fillRect(pos.marginsAdded(margins), colors[i]); + painter->fillRect(rc, colors[i]); } - painter->drawText(pos, Qt::AlignCenter, byte_list[i]); - pos.moveLeft(pos.right() + space); + painter->drawText(rc, Qt::AlignCenter, toHex(byte_list[i])); + rc.moveLeft(rc.right() + 1); } } @@ -114,8 +114,8 @@ QValidator::State NameValidator::validate(QString &input, int &pos) const { namespace utils { QPixmap icon(const QString &id) { - static bool dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > - QApplication::style()->standardPalette().color(QPalette::Background).value(); + static bool dark_theme = QApplication::palette().color(QPalette::WindowText).value() > + QApplication::palette().color(QPalette::Background).value(); QPixmap pm; QString key = "bootstrap_" % id % (dark_theme ? "1" : "0"); if (!QPixmapCache::find(key, &pm)) { @@ -138,3 +138,13 @@ QToolButton *toolButton(const QString &icon, const QString &tooltip) { btn->setAutoRaise(true); return btn; }; + + +QString toHex(uint8_t byte) { + static std::array hex = []() { + std::array ret; + for (int i = 0; i < 256; ++i) ret[i] = QStringLiteral("%1").arg(i, 2, 16, QLatin1Char('0')).toUpper(); + return ret; + }(); + return hex[byte]; +} diff --git a/tools/cabana/util.h b/tools/cabana/util.h index b72ddfcaa0..5eb5c3c5aa 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -14,7 +14,6 @@ #include "tools/cabana/dbcmanager.h" using namespace dbcmanager; - class ChangeTracker { public: void compute(const QByteArray &dat, double ts, uint32_t freq); @@ -31,16 +30,22 @@ private: QByteArray prev_dat; }; +enum { + ColorsRole = Qt::UserRole + 1, + BytesRole = Qt::UserRole + 2 +}; + class MessageBytesDelegate : public QStyledItemDelegate { Q_OBJECT public: MessageBytesDelegate(QObject *parent); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QFont fixed_font; + int byte_width; }; inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); } -inline char toHex(uint value) { return "0123456789ABCDEF"[value & 0xF]; } +QString toHex(uint8_t byte); QColor getColor(const dbcmanager::Signal *sig); class NameValidator : public QRegExpValidator { From 581fd62d2642629b23ac111112245a963202143f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 26 Feb 2023 17:32:52 -0800 Subject: [PATCH 15/45] steer limits: rename common dist to meas function (#27453) * rename function * make a wrapper function (ford uses dynamic up/down limits * make two functions consistent * make torque function convert to int --- selfdrive/car/__init__.py | 38 ++++++++++++++--------- selfdrive/car/chrysler/carcontroller.py | 4 +-- selfdrive/car/gm/carcontroller.py | 4 +-- selfdrive/car/hyundai/carcontroller.py | 4 +-- selfdrive/car/mazda/carcontroller.py | 6 ++-- selfdrive/car/subaru/carcontroller.py | 4 +-- selfdrive/car/toyota/carcontroller.py | 4 +-- selfdrive/car/volkswagen/carcontroller.py | 4 +-- 8 files changed, 38 insertions(+), 30 deletions(-) diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index a90f023ed1..58cde85817 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -73,7 +73,7 @@ def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None, body_dbc=None) -> Dict[str, st return {'pt': pt_dbc, 'radar': radar_dbc, 'chassis': chassis_dbc, 'body': body_dbc} -def apply_std_steer_torque_limits(apply_torque, apply_torque_last, driver_torque, LIMITS): +def apply_driver_steer_torque_limits(apply_torque, apply_torque_last, driver_torque, LIMITS): # limits due to driver torque driver_max_torque = LIMITS.STEER_MAX + (LIMITS.STEER_DRIVER_ALLOWANCE + driver_torque * LIMITS.STEER_DRIVER_FACTOR) * LIMITS.STEER_DRIVER_MULTIPLIER @@ -93,24 +93,32 @@ def apply_std_steer_torque_limits(apply_torque, apply_torque_last, driver_torque return int(round(float(apply_torque))) -def apply_toyota_steer_torque_limits(apply_torque, apply_torque_last, motor_torque, LIMITS): - # limits due to comparison of commanded torque VS motor reported torque - max_lim = min(max(motor_torque + LIMITS.STEER_ERROR_MAX, LIMITS.STEER_ERROR_MAX), LIMITS.STEER_MAX) - min_lim = max(min(motor_torque - LIMITS.STEER_ERROR_MAX, -LIMITS.STEER_ERROR_MAX), -LIMITS.STEER_MAX) +def apply_dist_to_meas_limits(val, val_last, val_meas, + STEER_DELTA_UP, STEER_DELTA_DOWN, + STEER_ERROR_MAX, STEER_MAX): + # limits due to comparison of commanded val VS measured val (torque/angle/curvature) + max_lim = min(max(val_meas + STEER_ERROR_MAX, STEER_ERROR_MAX), STEER_MAX) + min_lim = max(min(val_meas - STEER_ERROR_MAX, -STEER_ERROR_MAX), -STEER_MAX) - apply_torque = clip(apply_torque, min_lim, max_lim) + val = clip(val, min_lim, max_lim) - # slow rate if steer torque increases in magnitude - if apply_torque_last > 0: - apply_torque = clip(apply_torque, - max(apply_torque_last - LIMITS.STEER_DELTA_DOWN, -LIMITS.STEER_DELTA_UP), - apply_torque_last + LIMITS.STEER_DELTA_UP) + # slow rate if val increases in magnitude + if val_last > 0: + val = clip(val, + max(val_last - STEER_DELTA_DOWN, -STEER_DELTA_UP), + val_last + STEER_DELTA_UP) else: - apply_torque = clip(apply_torque, - apply_torque_last - LIMITS.STEER_DELTA_UP, - min(apply_torque_last + LIMITS.STEER_DELTA_DOWN, LIMITS.STEER_DELTA_UP)) + val = clip(val, + val_last - STEER_DELTA_UP, + min(val_last + STEER_DELTA_DOWN, STEER_DELTA_UP)) - return int(round(float(apply_torque))) + return float(val) + + +def apply_meas_steer_torque_limits(apply_torque, apply_torque_last, motor_torque, LIMITS): + return int(round(apply_dist_to_meas_limits(apply_torque, apply_torque_last, motor_torque, + LIMITS.STEER_DELTA_UP, LIMITS.STEER_DELTA_DOWN, + LIMITS.STEER_ERROR_MAX, LIMITS.STEER_MAX))) def apply_std_steer_angle_limits(apply_angle, apply_angle_last, v_ego, LIMITS): diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index 20a44bce21..b418179e0e 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -1,6 +1,6 @@ from opendbc.can.packer import CANPacker from common.realtime import DT_CTRL -from selfdrive.car import apply_toyota_steer_torque_limits +from selfdrive.car import apply_meas_steer_torque_limits from selfdrive.car.chrysler.chryslercan import create_lkas_hud, create_lkas_command, create_cruise_buttons from selfdrive.car.chrysler.values import RAM_CARS, CarControllerParams, ChryslerFlags @@ -67,7 +67,7 @@ class CarController: # steer torque new_steer = int(round(CC.actuators.steer * self.params.STEER_MAX)) - apply_steer = apply_toyota_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorqueEps, self.params) + apply_steer = apply_meas_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorqueEps, self.params) if not lkas_active or not lkas_control_bit: apply_steer = 0 self.apply_steer_last = apply_steer diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index 42eaf7e88a..2a996c0ff6 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -3,7 +3,7 @@ from common.conversions import Conversions as CV from common.numpy_fast import interp from common.realtime import DT_CTRL from opendbc.can.packer import CANPacker -from selfdrive.car import apply_std_steer_torque_limits +from selfdrive.car import apply_driver_steer_torque_limits from selfdrive.car.gm import gmcan from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons @@ -73,7 +73,7 @@ class CarController: if CC.latActive: new_steer = int(round(actuators.steer * self.params.STEER_MAX)) - apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) + apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) else: apply_steer = 0 diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 1e6f78af20..2572038492 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -3,7 +3,7 @@ from common.conversions import Conversions as CV from common.numpy_fast import clip from common.realtime import DT_CTRL from opendbc.can.packer import CANPacker -from selfdrive.car import apply_std_steer_torque_limits +from selfdrive.car import apply_driver_steer_torque_limits from selfdrive.car.hyundai import hyundaicanfd, hyundaican from selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR @@ -60,7 +60,7 @@ class CarController: # steering torque new_steer = int(round(actuators.steer * self.params.STEER_MAX)) - apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) + apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) if not CC.latActive: apply_steer = 0 diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py index 524a02a370..cb401a8abd 100644 --- a/selfdrive/car/mazda/carcontroller.py +++ b/selfdrive/car/mazda/carcontroller.py @@ -1,6 +1,6 @@ from cereal import car from opendbc.can.packer import CANPacker -from selfdrive.car import apply_std_steer_torque_limits +from selfdrive.car import apply_driver_steer_torque_limits from selfdrive.car.mazda import mazdacan from selfdrive.car.mazda.values import CarControllerParams, Buttons @@ -23,8 +23,8 @@ class CarController: if CC.latActive: # calculate steer and also set limits due to driver torque new_steer = int(round(CC.actuators.steer * CarControllerParams.STEER_MAX)) - apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, - CS.out.steeringTorque, CarControllerParams) + apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, + CS.out.steeringTorque, CarControllerParams) if CC.cruiseControl.cancel: # If brake is pressed, let us wait >70ms before trying to disable crz to avoid diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index 24d85877d7..a6dbf4a39e 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -1,5 +1,5 @@ from opendbc.can.packer import CANPacker -from selfdrive.car import apply_std_steer_torque_limits +from selfdrive.car import apply_driver_steer_torque_limits from selfdrive.car.subaru import subarucan from selfdrive.car.subaru.values import DBC, GLOBAL_GEN2, PREGLOBAL_CARS, CarControllerParams @@ -34,7 +34,7 @@ class CarController: # limits due to driver torque new_steer = int(round(apply_steer)) - apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.p) + apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.p) if not CC.latActive: apply_steer = 0 diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 2e0d7009c8..8004ea9dca 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -1,6 +1,6 @@ from cereal import car from common.numpy_fast import clip, interp -from selfdrive.car import apply_toyota_steer_torque_limits, create_gas_interceptor_command, make_can_msg +from selfdrive.car import apply_meas_steer_torque_limits, create_gas_interceptor_command, make_can_msg from selfdrive.car.toyota.toyotacan import create_steer_command, create_ui_command, \ create_accel_command, create_acc_cancel_command, \ create_fcw_command, create_lta_steer_command @@ -60,7 +60,7 @@ class CarController: # steer torque new_steer = int(round(actuators.steer * CarControllerParams.STEER_MAX)) - apply_steer = apply_toyota_steer_torque_limits(new_steer, self.last_steer, CS.out.steeringTorqueEps, self.torque_rate_limits) + apply_steer = apply_meas_steer_torque_limits(new_steer, self.last_steer, CS.out.steeringTorqueEps, self.torque_rate_limits) # Count up to MAX_STEER_RATE_FRAMES, at which point we need to cut torque to avoid a steering fault if lat_active and abs(CS.out.steeringRateDeg) >= MAX_STEER_RATE: diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index 5d00b5a52f..c17b632450 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -3,7 +3,7 @@ from opendbc.can.packer import CANPacker from common.numpy_fast import clip from common.conversions import Conversions as CV from common.realtime import DT_CTRL -from selfdrive.car import apply_std_steer_torque_limits +from selfdrive.car import apply_driver_steer_torque_limits from selfdrive.car.volkswagen import mqbcan, pqcan from selfdrive.car.volkswagen.values import CANBUS, PQ_CARS, CarControllerParams @@ -44,7 +44,7 @@ class CarController: if CC.latActive: new_steer = int(round(actuators.steer * self.CCP.STEER_MAX)) - apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.CCP) + apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.CCP) if apply_steer == 0: hcaEnabled = False self.hcaEnabledFrameCount = 0 From c995acda7c502bc14fff431ba4832faa9dbaec18 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Tue, 28 Feb 2023 03:01:55 +0800 Subject: [PATCH 16/45] driverview: use static icon (#27448) * fix alpha * prerender --- selfdrive/assets/img_driver_face.png | Bin 19875 -> 3769 bytes selfdrive/assets/img_driver_face_static.png | Bin 0 -> 4908 bytes selfdrive/ui/qt/offroad/driverview.cc | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 selfdrive/assets/img_driver_face_static.png diff --git a/selfdrive/assets/img_driver_face.png b/selfdrive/assets/img_driver_face.png index 03765a0376dc33e72f88fb68d0f3879bffff90ff..e2d943e537fb1cc489dbcfbb3dcfeb57258fb4b0 100644 GIT binary patch literal 3769 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 PNjdt3OOnnd7;OIrwou~J literal 19875 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 ami>RG56lgMCO}*O0000vK&AGLy2(^ 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 Us`>2_d Date: Mon, 27 Feb 2023 13:49:06 -0800 Subject: [PATCH 17/45] Update check-submodules.sh --- release/check-submodules.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/check-submodules.sh b/release/check-submodules.sh index 2585db6bd7..5f4e307e49 100755 --- a/release/check-submodules.sh +++ b/release/check-submodules.sh @@ -1,7 +1,7 @@ #!/bin/bash while read hash submodule ref; do - git -C $submodule fetch --depth 300 origin master + git -C $submodule fetch --depth 1000 origin master git -C $submodule branch -r --contains $hash | grep "origin/master" if [ "$?" -eq 0 ]; then echo "$submodule ok" From dc39a87543d61eb5d24ee5f27b661474f7f16598 Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Tue, 28 Feb 2023 08:50:32 +0900 Subject: [PATCH 18/45] Multilang: kor translation update (#27445) --- selfdrive/ui/translations/main_ko.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 5470e57ce5..be11f2efde 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -403,7 +403,7 @@ location set Waiting for GPS - GPS를 기다리는 중 + GPS 수신중 입니다 @@ -592,16 +592,17 @@ location set Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - + 데이터 파티션을 마운트할 수 없습니다. 파티션이 손상되었을 수 있습니다. 장치를 초기화하려면 확인을 누르세요. Press confirm to erase all content and settings. Press cancel to resume boot. - + 모든 콘텐츠와 설정을 지우려면 확인을 누르세요. 부팅을 재개하려면 취소를 누르세요. Resetting device... This may take up to a minute. - + 장치 초기화 중... +최대 1분이 소요될 수 있습니다. @@ -702,12 +703,12 @@ This may take up to a minute. 다시 시작 - No custom software found at this URL. - + Something went wrong. Reboot the device. + 문제가 발생했습니다. 장치를 재부팅하세요. - Something went wrong. Reboot the device. - + No custom software found at this URL. + 이 URL에서 커스텀 소프트웨어를 찾을 수 없습니다. From ce3e9d5649d930ea0daae2d2a1587cc6e69c158b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 28 Feb 2023 07:51:23 +0800 Subject: [PATCH 19/45] cabana: fix gaps in step line between chunks (#27447) --- tools/cabana/chartswidget.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 7982a5899c..42f8e4e06a 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -552,7 +552,12 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even }); for (auto &c : chunks) { s.vals.append(c.vals); - s.step_vals.append(c.step_vals); + if (!c.step_vals.empty()) { + if (!s.step_vals.empty()) { + s.step_vals.append({c.step_vals.first().x(), s.step_vals.back().y()}); + } + s.step_vals.append(c.step_vals); + } } if (events->size()) { s.last_value_mono_time = events->back()->mono_time; From 8d317ef51ce3518e6bd3bb1a97567f8686ca8c8d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 1 Mar 2023 07:50:30 +0800 Subject: [PATCH 20/45] cabana: press F11 to toggle fullscreen (#27455) --- tools/cabana/mainwin.cc | 15 +++++++++++++++ tools/cabana/mainwin.h | 1 + 2 files changed, 16 insertions(+) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 282a541244..abcb4948a9 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -194,6 +194,8 @@ void MainWindow::createStatusBar() { void MainWindow::createShortcuts() { auto shortcut = new QShortcut(QKeySequence(Qt::Key_Space), this, nullptr, nullptr, Qt::ApplicationShortcut); QObject::connect(shortcut, &QShortcut::activated, []() { can->pause(!can->isPaused()); }); + shortcut = new QShortcut(QKeySequence(QKeySequence::FullScreen), this, nullptr, nullptr, Qt::ApplicationShortcut); + QObject::connect(shortcut, &QShortcut::activated, this, &MainWindow::toggleFullScreen); // TODO: add more shortcuts here. } @@ -482,6 +484,19 @@ void MainWindow::onlineHelp() { } } +void MainWindow::toggleFullScreen() { + if (isFullScreen()) { + menuBar()->show(); + statusBar()->show(); + showNormal(); + showMaximized(); + } else { + menuBar()->hide(); + statusBar()->hide(); + showFullScreen(); + } +} + // HelpOverlay HelpOverlay::HelpOverlay(MainWindow *parent) : QWidget(parent) { setAttribute(Qt::WA_NoSystemBackground, true); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 2aeb20aea8..1c21d69370 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -56,6 +56,7 @@ protected: void undoStackCleanChanged(bool clean); void undoStackIndexChanged(int index); void onlineHelp(); + void toggleFullScreen(); void updateStatus(); VideoWidget *video_widget = nullptr; From b6881220426ac231215bbf4476f6fedd11e3e540 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Tue, 28 Feb 2023 21:40:54 -0800 Subject: [PATCH 21/45] laikad: reduce min satellite number (#27440) * bump laika * update laikad tests * update refs * bump laika * update refs --------- Co-authored-by: Kurt Nistelberger --- laika_repo | 2 +- selfdrive/locationd/laikad.py | 20 +++++++++++++------- selfdrive/locationd/test/test_laikad.py | 10 +++++----- selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/laika_repo b/laika_repo index 278b44ba8c..b740b71c82 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 278b44ba8c2dec28adc5b30cce13dabc195f15fc +Subproject commit b740b71c82a748e3520b1599487d9a7aaf728670 diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 2eb1e94526..10c5e1b7e5 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -97,19 +97,25 @@ class Laikad: def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: - min_measurements = 7 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 6 - position_solution, pr_residuals = calc_pos_fix(measurements, self.posfix_functions, min_measurements=min_measurements) + min_measurements = 5 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 4 + position_solution, pr_residuals, pos_std = calc_pos_fix(measurements, self.posfix_functions, min_measurements=min_measurements) if len(position_solution) < 3: return None position_estimate = position_solution[:3] - #TODO median abs residual is decent estimate of std, can be improved with measurements stds and/or DOP - position_std = np.median(np.abs(pr_residuals)) * np.ones(3) - velocity_solution, prr_residuals = calc_vel_fix(measurements, position_estimate, self.velfix_function, min_measurements=min_measurements) + + position_std_residual = np.median(np.abs(pr_residuals)) + position_std = np.median(np.abs(pos_std))/10 + position_std = max(position_std_residual, position_std) * np.ones(3) + + velocity_solution, prr_residuals, vel_std = calc_vel_fix(measurements, position_estimate, self.velfix_function, min_measurements=min_measurements) if len(velocity_solution) < 3: return None - velocity_estimate = velocity_solution[:3] - velocity_std = np.median(np.abs(prr_residuals)) * np.ones(3) + + velocity_std_residual = np.median(np.abs(prr_residuals)) + velocity_std = np.median(np.abs(vel_std))/10 + velocity_std = max(velocity_std, velocity_std_residual) * np.ones(3) + return position_estimate, position_std, velocity_estimate, velocity_std def is_good_report(self, gnss_msg): diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index d89f521228..10ac7790b6 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -160,7 +160,7 @@ class TestLaikad(unittest.TestCase): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT) correct_msgs = verify_messages(self.logs, laikad) - correct_msgs_expected = 554 + correct_msgs_expected = 559 self.assertEqual(correct_msgs_expected, len(correct_msgs)) self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) @@ -180,7 +180,7 @@ class TestLaikad(unittest.TestCase): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.NAV) # Disable fetch_orbits to test NAV only correct_msgs = verify_messages(self.logs, laikad) - correct_msgs_expected = 554 + correct_msgs_expected = 559 self.assertEqual(correct_msgs_expected, len(correct_msgs)) self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) @@ -195,8 +195,8 @@ class TestLaikad(unittest.TestCase): downloader_mock.side_effect = DownloadFailed laikad = Laikad(auto_update=False) correct_msgs = verify_messages(self.logs, laikad) - self.assertEqual(0, len(correct_msgs)) - self.assertEqual(0, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) + self.assertEqual(255, len(correct_msgs)) + self.assertEqual(255, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) def test_laika_get_orbits(self): laikad = Laikad(auto_update=False) @@ -282,7 +282,7 @@ class TestLaikad(unittest.TestCase): gm = msg.gnssMeasurements if len(gm.correctedMeasurements) != 0 and gm.positionECEF.valid: cnt += 1 - self.assertEqual(cnt, 554) + self.assertEqual(cnt, 559) def dict_has_values(self, dct): self.assertGreater(len(dct), 0) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 9991154b9a..b44c9c2f46 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -772f30de36fc7f8421dabb779cc02f45eb83d7bb +dfa8e947c4ef76a9d89974a434e94a078e1ccc6a \ No newline at end of file From 85a37d276c105494b97eee03aa6bb31a212f2f92 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 1 Mar 2023 15:41:28 +0800 Subject: [PATCH 22/45] cabana: recalc y-axis label width after unit change (#27466) recalc width --- tools/cabana/chartswidget.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 42f8e4e06a..2c27fbd8b9 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -591,11 +591,14 @@ void ChartView::updateAxisY() { if (it->y() > max) max = it->y(); } } - axis_y->setTitleText(unit); - if (min == std::numeric_limits::max()) min = 0; if (max == std::numeric_limits::lowest()) max = 0; + if (axis_y->titleText() != unit) { + axis_y->setTitleText(unit); + y_label_width = 0;// recalc width + } + double delta = std::abs(max - min) < 1e-3 ? 1 : (max - min) * 0.05; auto [min_y, max_y, tick_count] = getNiceAxisNumbers(min - delta, max + delta, axis_y->tickCount()); if (min_y != axis_y->min() || max_y != axis_y->max() || y_label_width == 0) { From d6abf1d5725e1de58d6f3dc23a238aa4bf65b642 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 1 Mar 2023 13:38:49 -0800 Subject: [PATCH 23/45] No disengage on gas by default (#27472) --- selfdrive/manager/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 865966d6c5..963d94066b 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -36,7 +36,7 @@ def manager_init() -> None: default_params: List[Tuple[str, Union[str, bytes]]] = [ ("CompletedTrainingVersion", "0"), - ("DisengageOnAccelerator", "1"), + ("DisengageOnAccelerator", "0"), ("GsmMetered", "1"), ("HasAcceptedTerms", "0"), ("LanguageSetting", "main_en"), From 9ce26b201104afd24fb20baeba22320473afc09d Mon Sep 17 00:00:00 2001 From: Iamz Date: Thu, 2 Mar 2023 06:35:28 +0700 Subject: [PATCH 24/45] Add missing Thai translations and remove obsolete messages. (#27469) Update Thai translations --- selfdrive/ui/translations/main_th.ts | 54 +++++++++++----------------- 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index ce394ecb97..45f91f1cdb 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -311,18 +311,6 @@ Installing... กำลังติดตั้ง... - - Receiving objects: - กำลังรับข้อมูล: - - - Resolving deltas: - การแก้ไขเดลต้า: - - - Updating files: - กำลังอัปเดตไฟล์: - MapETA @@ -586,18 +574,10 @@ location set Are you sure you want to reset your device? คุณแน่ใจหรือไม่ว่าต้องการรีเซ็ตอุปกรณ์? - - Resetting device... - กำลังรีเซ็ตอุปกรณ์... - System Reset รีเซ็ตระบบ - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - มีการสั่งรีเซ็ตระบบ กดยืนยันเพื่อลบข้อมูลและการตั้งค่าทั้งหมด กดยกเลิกเพื่อบูตเข้าระบบตามปกติ - Cancel ยกเลิก @@ -611,8 +591,18 @@ location set ยืนยัน - Unable to mount data partition. Press confirm to reset your device. - ไม่สามารถเมานต์พาร์ติชั่นข้อมูล กดยืนยันเพื่อรีเซ็ตอุปกรณ์ของคุณ + Resetting device... +This may take up to a minute. + กำลังรีเซ็ตอุปกรณ์... +อาจใช้เวลาถึงหนึ่งนาที + + + Press confirm to erase all content and settings. Press cancel to resume boot. + กดยืนยันเพื่อลบข้อมูลและการตั้งค่าทั้งหมด กดยกเลิกเพื่อบูตต่อ + + + Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. + ไม่สามารถเมานต์พาร์ติชั่นข้อมูลได้ พาร์ติชั่นอาจเสียหาย กดยืนยันเพื่อลบและรีเซ็ตอุปกรณ์ของคุณ @@ -684,18 +674,6 @@ location set Waiting for internet กำลังรอสัญญาณอินเตอร์เน็ต - - Choose Software to Install - เลือกซอฟต์แวร์ที่จะติดตั้ง - - - Dashcam - กล้องติดรถยนต์ - - - Custom Software - ซอฟต์แวร์ที่กำหนดเอง - Enter URL ป้อน URL @@ -724,6 +702,14 @@ location set Start over เริ่มต้นใหม่ + + Something went wrong. Reboot the device. + มีบางอย่างผิดพลาด รีบูตอุปกรณ์ + + + No custom software found at this URL. + ไม่พบซอฟต์แวร์ที่กำหนดเองที่ URL นี้ + SetupWidget From be42193a618c9133d9a3a3bd4ac33dd19f0209f5 Mon Sep 17 00:00:00 2001 From: koffee-bean <125648286+koffee-bean@users.noreply.github.com> Date: Wed, 1 Mar 2023 16:39:38 -0700 Subject: [PATCH 25/45] Hyundai: add missing 2022 Ioniq 5 fwdCamera version (#27471) Co-authored-by: srivastavasid91@gmail.com --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 4b7a295246..d81c98fbcd 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1566,6 +1566,7 @@ FW_VERSIONS = { b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.02 99211-GI010 211206', + b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.03 99211-GI010 220401', ], }, CAR.TUCSON_4TH_GEN: { From 7f10c736ab0e1f027738b5f64ca75308435a3ade Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 1 Mar 2023 15:57:11 -0800 Subject: [PATCH 26/45] test_fw_query_on_routes.py: don't print FW for logging --- selfdrive/debug/test_fw_query_on_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/debug/test_fw_query_on_routes.py b/selfdrive/debug/test_fw_query_on_routes.py index ba7d96dba0..dc6688324f 100755 --- a/selfdrive/debug/test_fw_query_on_routes.py +++ b/selfdrive/debug/test_fw_query_on_routes.py @@ -74,7 +74,7 @@ if __name__ == "__main__": elif msg.which() == "carParams": CP = msg.carParams - car_fw = CP.carFw + car_fw = [fw for fw in CP.carFw if not fw.logging] if len(car_fw) == 0: print("no fw") break From d50d8de63787a09b57c294c54b6f88a1236ec2bc Mon Sep 17 00:00:00 2001 From: javenzy <85425378+javenzy@users.noreply.github.com> Date: Thu, 2 Mar 2023 08:00:08 +0800 Subject: [PATCH 27/45] Add China HONDA ACCORD HYBRID 2018 finger (#27462) * Add China HONDA ACCORD HYBRID 2018 finger Add finger to support China HONDA ACCORD HYBRID 2018,use ACCORDH model. * remove FW for logging --------- Co-authored-by: Shane Smiskol --- selfdrive/car/honda/values.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index c085c3fe80..0737bea147 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -368,10 +368,12 @@ FW_VERSIONS = { b'57114-TWA-A050\x00\x00', b'57114-TWA-A530\x00\x00', b'57114-TWA-B520\x00\x00', + b'57114-TWB-H030\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TWA-A440\x00\x00', b'77959-TWA-L420\x00\x00', + b'77959-TWB-H220\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ b'78109-TWA-A010\x00\x00', @@ -385,6 +387,7 @@ FW_VERSIONS = { b'78109-TWA-A230\x00\x00', b'78109-TWA-L010\x00\x00', b'78109-TWA-L210\x00\x00', + b'78109-TWA-H210\x00\x00', ], (Ecu.shiftByWire, 0x18da0bf1, None): [ b'54008-TWA-A910\x00\x00', @@ -396,16 +399,19 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x18dab5f1, None): [ b'36161-TWA-A070\x00\x00', b'36161-TWA-A330\x00\x00', + b'36161-TWB-H040\x00\x00', ], (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36802-TWA-A070\x00\x00', b'36802-TWA-A080\x00\x00', b'36802-TWA-A330\x00\x00', + b'36802-TWB-H060\x00\x00', ], (Ecu.eps, 0x18da30f1, None): [ b'39990-TVA-A160\x00\x00', b'39990-TVA-A150\x00\x00', b'39990-TVA-A340\x00\x00', + b'39990-TWB-H120\x00\x00', ], }, CAR.CIVIC: { From e6240d6ba20c187183ac5a26e3135cb5cedaa4c3 Mon Sep 17 00:00:00 2001 From: Andrei Radulescu Date: Thu, 2 Mar 2023 02:01:39 +0200 Subject: [PATCH 28/45] =?UTF-8?q?VW=20MQB:=20Add=20FW=20for=202018=20?= =?UTF-8?q?=C5=A0koda=20Kodiaq=20(#27460)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Shane Smiskol --- selfdrive/car/volkswagen/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 158a178b03..b23742b50d 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1049,6 +1049,7 @@ FW_VERSIONS = { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8704E906027DD\xf1\x893123', b'\xf1\x8704L906026DE\xf1\x895418', + b'\xf1\x8704L906026HT\xf1\x893617', b'\xf1\x875NA907115E \xf1\x890003', b'\xf1\x875NA907115E \xf1\x890005', ], @@ -1060,17 +1061,20 @@ FW_VERSIONS = { ], (Ecu.srs, 0x715, None): [ b'\xf1\x873Q0959655BJ\xf1\x890703\xf1\x82\x0e1213001211001205212111052100', + b'\xf1\x873Q0959655BK\xf1\x890703\xf1\x82\x0e1213001211001244212111442100', b'\xf1\x873Q0959655CN\xf1\x890720\xf1\x82\x0e1213001211001205212112052100', b'\xf1\x873Q0959655CQ\xf1\x890720\xf1\x82\x0e1213111211001205212112052111', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6050405', b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6060405', + b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6070405', b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567T600G600', ], (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572Q \xf1\x890342', b'\xf1\x872Q0907572R \xf1\x890372', + b'\xf1\x872Q0907572AA\xf1\x890396', ], }, CAR.SKODA_OCTAVIA_MK3: { From 3fbdddb2fb7c79f0c03e5e76edb11f778608e7a5 Mon Sep 17 00:00:00 2001 From: humza2000 <111622889+humza2000@users.noreply.github.com> Date: Wed, 1 Mar 2023 16:10:00 -0800 Subject: [PATCH 29/45] Added new transmission firmware for Hyundai Sonata 2022 (#27456) * Added new transmission firmware for Hyundai Sonata 2020-2023 b'\xf1\x00T02601BL T02900A1 VDN8T25XXX900NSCF\xe4!Y', b'\xf1\x87954A02N060\x00\x00\x00\x00\x00\xf1\x81T02900A1 \xf1\x00T02601BL T02900A1 VDN8T25XXX900NSCF\xe4!Y', Dongle ID: ba75a2db7d699895 Route: ba75a2db7d699895|2023-02-27--18-07-15 * Update selfdrive/car/hyundai/values.py * we can clean these up --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index d81c98fbcd..cf0143543a 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -512,7 +512,6 @@ FW_VERSIONS = { b'\xf1\x00DN8_ SCC FHCUP 1.00 1.01 99110-L1000 ', b'\xf1\x00DN89110-L0000 \xaa\xaa\xaa\xaa\xaa\xaa\xaa ', b'\xf1\x8799110L0000\xf1\x00DN8_ SCC F-CUP 1.00 1.00 99110-L0000 ', - b'\xf1\x8799110L0000\xf1\x00DN8_ SCC FHCUP 1.00 1.00 99110-L0000 ', ], (Ecu.abs, 0x7d1, None): [ b'\xf1\x00DN ESC \x07 106 \x07\x01 58910-L0100', @@ -525,7 +524,6 @@ FW_VERSIONS = { b'\xf1\x8758910-L0100\xf1\x00DN ESC \x06 104\x19\x08\x01 58910-L0100', b'\xf1\x8758910-L0100\xf1\x00DN ESC \x06 106 \x07\x01 58910-L0100', b'\xf1\x8758910-L0100\xf1\x00DN ESC \x07 104\x19\x08\x01 58910-L0100', - b'\xf1\x8758910-L0300\xf1\x00DN ESC \x03 100 \x08\x01 58910-L0300', b'\xf1\x00DN ESC \x06 106 \x07\x01 58910-L0100', ], (Ecu.engine, 0x7e0, None): [ @@ -587,6 +585,7 @@ FW_VERSIONS = { b'\xf1\x00HT6WA280BLHT6WAD10A1SDN8G25NB4\x00\x00\x00\x00\x00\x00g!l[', b'\xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5', b'\xf1\x00T02601BL T02832A1 VDN8T25XXX832NS8G\x0e\xfeE', + b'\xf1\x00T02601BL T02900A1 VDN8T25XXX900NSCF\xe4!Y', b'\xf1\x87954A02N060\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5', b'\xf1\x87SAKFBA2926554GJ2VefVww\x87xwwwww\x88\x87xww\x87wTo\xfb\xffvUo\xff\x8d\x16\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v', b'\xf1\x87SAKFBA3030524GJ2UVugww\x97yx\x88\x87\x88vw\x87gww\x87wto\xf9\xfffUo\xff\xa2\x0c\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v', From 1483fc32dcb0e44d07909562a3d1c10a37b648b8 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Wed, 1 Mar 2023 19:49:11 -0500 Subject: [PATCH 30/45] VW MQB: Add FW for 2023 Volkswagen Tiguan (#27475) --- selfdrive/car/volkswagen/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index b23742b50d..b53820a32e 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -739,12 +739,14 @@ FW_VERSIONS = { b'\xf1\x8783A907115B \xf1\x890005', b'\xf1\x8783A907115F \xf1\x890002', b'\xf1\x8783A907115G \xf1\x890001', + b'\xf1\x8783A907115K \xf1\x890001', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x8709G927158DT\xf1\x893698', b'\xf1\x8709G927158FM\xf1\x893757', b'\xf1\x8709G927158GC\xf1\x893821', b'\xf1\x8709G927158GD\xf1\x893820', + b'\xf1\x8709G927158GM\xf1\x893936', b'\xf1\x870D9300043 \xf1\x895202', b'\xf1\x870DL300011N \xf1\x892001', b'\xf1\x870DL300011N \xf1\x892012', @@ -775,6 +777,7 @@ FW_VERSIONS = { b'\xf1\x875QM909144B \xf1\x891081\xf1\x82\x0521A60604A1', b'\xf1\x875QM909144C \xf1\x891082\xf1\x82\x0521A60604A1', b'\xf1\x875QM909144C \xf1\x891082\xf1\x82\00521A60804A1', + b'\xf1\x875QM907144D \xf1\x891063\xf1\x82\x002SA6092SOM', ], (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572AA\xf1\x890396', From 437ca99fcd5bddfd2f73701d48919ef4afea3ca3 Mon Sep 17 00:00:00 2001 From: Miniz199922 <124948595+Miniz199922@users.noreply.github.com> Date: Wed, 1 Mar 2023 19:56:01 -0500 Subject: [PATCH 31/45] Chrysler: Add missing FP for 2020 Jeep Grand Cherokee (#27464) Need to add fingerprint 1538: 8 for my 2020 jeep grand cherokee. Tested and working --- selfdrive/car/chrysler/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 2a5daf440c..2af5246b88 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -135,7 +135,7 @@ FINGERPRINTS = { }], CAR.JEEP_CHEROKEE_2019: [{ # Jeep Grand Cherokee 2019, including most 2020 models - 55: 8, 168: 8, 179: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 341: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 530: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 640: 1, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 840: 8, 844: 5, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 874: 2, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 960: 4, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 8, 1225: 8, 1227: 8, 1235: 8, 1242: 8, 1250: 8, 1251: 8, 1252: 8, 1254: 8, 1264: 8, 1284: 8, 1536: 8, 1537: 8, 1543: 8, 1545: 8, 1562: 8, 1568: 8, 1570: 8, 1572: 8, 1593: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1867: 8, 1875: 8, 1882: 8, 1890: 8, 1891: 8, 1892: 8, 1894: 8, 1896: 8, 1904: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 + 55: 8, 168: 8, 179: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 341: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 530: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 640: 1, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 840: 8, 844: 5, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 874: 2, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 960: 4, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 8, 1225: 8, 1227: 8, 1235: 8, 1242: 8, 1250: 8, 1251: 8, 1252: 8, 1254: 8, 1264: 8, 1284: 8, 1536: 8, 1537: 8, 1538: 8, 1543: 8, 1545: 8, 1562: 8, 1568: 8, 1570: 8, 1572: 8, 1593: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1867: 8, 1875: 8, 1882: 8, 1890: 8, 1891: 8, 1892: 8, 1894: 8, 1896: 8, 1904: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 }], } From cb2a53ae80ab3917986266290f37ef0228a6ca21 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 1 Mar 2023 19:01:08 -0800 Subject: [PATCH 32/45] laikad: fix qcom without internet (#27468) move week Co-authored-by: Kurt Nistelberger --- selfdrive/locationd/laikad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 10c5e1b7e5..2b18dcf152 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -193,10 +193,10 @@ class Laikad: elif self.is_good_report(gnss_msg): week, tow, new_meas = self.read_report(gnss_msg) + self.gps_week = week if len(new_meas) == 0: return None - self.gps_week = week t = gnss_mono_time * 1e-9 if week > 0: self.got_first_gnss_msg = True From afc24f08d66c34ccebf3143e5062390e8529f26f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 2 Mar 2023 13:54:07 +0800 Subject: [PATCH 33/45] cabana: fix wrong tooltip (#27480) --- tools/cabana/chartswidget.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 2c27fbd8b9..bd4bf4aba9 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -708,14 +708,16 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { if (!s.series->isVisible()) continue; // use reverse iterator to find last item <= sec. + double value = 0; auto it = std::lower_bound(s.vals.rbegin(), s.vals.rend(), sec, [](auto &p, double x) { return p.x() > x; }); if (it != s.vals.rend() && it->x() >= axis_x->min()) { + value = it->y(); s.track_pt = chart()->mapToPosition(*it); x = std::max(x, s.track_pt.x()); } text_list.push_back(QString("%2: %3") .arg(s.series->color().name(), s.sig->name, - s.track_pt.isNull() ? "--" : QString::number(s.track_pt.y()))); + s.track_pt.isNull() ? "--" : QString::number(value))); } if (x < 0) { x = ev->pos().x(); @@ -779,7 +781,7 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { painter->setPen(Qt::NoPen); qreal track_line_x = -1; for (auto &s : sigs) { - if (!s.track_pt.isNull() && s.series->isVisible()) { + if (!s.track_pt.isNull() && s.series->isVisible()) { painter->setBrush(s.series->color().darker(125)); painter->drawEllipse(s.track_pt, 5.5, 5.5); track_line_x = std::max(track_line_x, s.track_pt.x()); From 9245335e8c0cf4c5371a1afa5a9ff5d4469f8d30 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 2 Mar 2023 16:44:58 -0800 Subject: [PATCH 34/45] Car docs: add Toyota Camry 2023 (#27483) * We support 2023 Camry * update docs --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 3bc918f784..20155f306b 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -181,7 +181,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Camry 2021-23|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 0639d46ec0..35e2db8b1e 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -115,7 +115,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.AVALONH_TSS2: ToyotaCarInfo("Toyota Avalon Hybrid 2022"), CAR.CAMRY: ToyotaCarInfo("Toyota Camry 2018-20", video_link="https://www.youtube.com/watch?v=fkcjviZY9CM", footnotes=[Footnote.CAMRY]), CAR.CAMRYH: ToyotaCarInfo("Toyota Camry Hybrid 2018-20", video_link="https://www.youtube.com/watch?v=Q2DYY0AWKgk"), - CAR.CAMRY_TSS2: ToyotaCarInfo("Toyota Camry 2021-22", footnotes=[Footnote.CAMRY]), + CAR.CAMRY_TSS2: ToyotaCarInfo("Toyota Camry 2021-23", footnotes=[Footnote.CAMRY]), CAR.CAMRYH_TSS2: ToyotaCarInfo("Toyota Camry Hybrid 2021-23"), CAR.CHR: ToyotaCarInfo("Toyota C-HR 2017-20"), CAR.CHR_TSS2: ToyotaCarInfo("Toyota C-HR 2021"), From 3ab8645d3af948a35ac410ad7f841ab670091e32 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 2 Mar 2023 20:11:24 -0800 Subject: [PATCH 35/45] uiPlan: add planned acceleration field (#27484) * add accel * bump cereal * Update ref_commit --------- Co-authored-by: Bruce Wayne --- cereal | 2 +- selfdrive/controls/lib/longitudinal_planner.py | 3 ++- selfdrive/controls/plannerd.py | 1 + selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cereal b/cereal index b88523f05a..42f84fd85d 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit b88523f05ac958f87a8f6d57c3f4bb20da55f216 +Subproject commit 42f84fd85d06c0fc85371daa2b4820fca49d763e diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 2ef9051122..e959b14ee3 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -122,8 +122,9 @@ class LongitudinalPlanner: self.mpc.update(sm['radarState'], v_cruise, x, v, a, j) self.v_desired_trajectory_full = np.interp(T_IDXS, T_IDXS_MPC, self.mpc.v_solution) + self.a_desired_trajectory_full = np.interp(T_IDXS, T_IDXS_MPC, self.mpc.a_solution) self.v_desired_trajectory = self.v_desired_trajectory_full[:CONTROL_N] - self.a_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC, self.mpc.a_solution) + self.a_desired_trajectory = self.a_desired_trajectory_full[:CONTROL_N] self.j_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC[:-1], self.mpc.j_solution) # TODO counter is only needed because radar is glitchy, remove once radar is gone diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index 543274d841..d8cf9386d1 100755 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -22,6 +22,7 @@ def publish_ui_plan(sm, pm, lateral_planner, longitudinal_planner): uiPlan.position.x = np.interp(plan_odo, model_odo, lateral_planner.lat_mpc.x_sol[:,0]).tolist() uiPlan.position.y = np.interp(plan_odo, model_odo, lateral_planner.lat_mpc.x_sol[:,1]).tolist() uiPlan.position.z = np.interp(plan_odo, model_odo, lateral_planner.path_xyz[:,2]).tolist() + uiPlan.accel = longitudinal_planner.a_desired_trajectory_full.tolist() pm.send('uiPlan', ui_send) def plannerd_thread(sm=None, pm=None): diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index b44c9c2f46..79769e14b6 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -dfa8e947c4ef76a9d89974a434e94a078e1ccc6a \ No newline at end of file +f9c7e05b836c4bff364978752e82d64b90f9d6e6 From 6c4320559a05d6af1ee7b0f4bbebda171b94e20a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 3 Mar 2023 14:30:12 +0800 Subject: [PATCH 36/45] replay: fixed the status is always "loading" if there is no carState in events (#27481) --- tools/replay/consoleui.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/replay/consoleui.cc b/tools/replay/consoleui.cc index 5ad702590c..077861ff96 100644 --- a/tools/replay/consoleui.cc +++ b/tools/replay/consoleui.cc @@ -165,7 +165,10 @@ void ConsoleUI::updateStatus() { sm.update(0); if (status != Status::Paused) { - status = (sm.updated("carState") || sm.updated("liveParameters")) ? Status::Playing : Status::Waiting; + auto events = replay->events(); + uint64_t current_mono_time = replay->routeStartTime() + replay->currentSeconds() * 1e9; + bool playing = !events->empty() && events->back()->mono_time > current_mono_time; + status = playing ? Status::Playing : Status::Waiting; } auto [status_str, status_color] = status_text[status]; write_item(0, 0, "STATUS: ", status_str, " ", false, status_color); From a7d9085bca46e83c6b2ea6a64c4bc9d214a0e733 Mon Sep 17 00:00:00 2001 From: Saber422 <81108166+Saber422@users.noreply.github.com> Date: Sat, 4 Mar 2023 08:19:36 +0800 Subject: [PATCH 37/45] VW MQB: Add FW for 2019 Skoda Superb (#27490) * VW MQB: Add FW for 2019 Skoda Superb 'carVin': 'TMBJD9NP0K7067520', * sort alphabetically --------- Co-authored-by: Cameron Clough --- selfdrive/car/volkswagen/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index b53820a32e..4eef1307be 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1147,6 +1147,7 @@ FW_VERSIONS = { b'\xf1\x8704L906026FP\xf1\x891196', b'\xf1\x8704L906026KB\xf1\x894071', b'\xf1\x8704L906026KD\xf1\x894798', + b'\xf1\x873G0906259 \xf1\x890004', b'\xf1\x873G0906259B \xf1\x890002', b'\xf1\x873G0906264A \xf1\x890002', ], @@ -1156,12 +1157,14 @@ FW_VERSIONS = { b'\xf1\x870D9300012 \xf1\x894940', b'\xf1\x870D9300041H \xf1\x894905', b'\xf1\x870GC300043 \xf1\x892301', + b'\xf1\x870D9300043F \xf1\x895202', ], (Ecu.srs, 0x715, None): [ b'\xf1\x875Q0959655AE\xf1\x890130\xf1\x82\x12111200111121001121110012211292221111', b'\xf1\x875Q0959655AE\xf1\x890130\xf1\x82\022111200111121001121118112231292221111', b'\xf1\x875Q0959655AK\xf1\x890130\xf1\x82\022111200111121001121110012211292221111', b'\xf1\x875Q0959655BH\xf1\x890336\xf1\x82\02331310031313100313131013141319331413100', + b'\xf1\x875Q0959655CA\xf1\x890403\xf1\x82\x1331310031313100313151013141319331423100', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909143K \xf1\x892033\xf1\x820514UZ070203', From f17ac166a325ae1f73778ac45af57fc1b23a1298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Fri, 3 Mar 2023 17:48:51 -0800 Subject: [PATCH 38/45] Enable dmoji crosshairs in gray when not enabled (#27491) * try * add fade back --------- Co-authored-by: ZwX1616 --- selfdrive/ui/qt/onroad.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 98c636b0a4..dc2f1368ac 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -573,7 +573,10 @@ void AnnotatedCameraWidget::drawDriverState(QPainter &painter, const UIState *s) const int arc_l = 133; const float arc_t_default = 6.7; const float arc_t_extend = 12.0; - QColor arc_color = QColor::fromRgbF(0.09, 0.945, 0.26, 0.4*(1.0-dm_fade_state)*(s->engaged())); + QColor arc_color = QColor::fromRgbF(0.545 - 0.445 * s->engaged(), + 0.545 + 0.4 * s->engaged(), + 0.545 - 0.285 * s->engaged(), + 0.4 * (1.0 - dm_fade_state)); float delta_x = -scene.driver_pose_sins[1] * arc_l / 2; float delta_y = -scene.driver_pose_sins[0] * arc_l / 2; painter.setPen(QPen(arc_color, arc_t_default+arc_t_extend*fmin(1.0, scene.driver_pose_diff[1] * 5.0), Qt::SolidLine, Qt::RoundCap)); From 703f5e34ba783dba5369bf44caa95ed66a07855a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 4 Mar 2023 02:18:03 -0800 Subject: [PATCH 39/45] bump panda (#27497) --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 1923b14189..e0e754de2c 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 1923b1418933e464ff7460a3e0a05d63aad0d53b +Subproject commit e0e754de2c7fdbf943dd02db203b7bb40bf3e9b5 From 2de085d39d0b9f149526828cd02cc4ccb9122d05 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 6 Mar 2023 07:55:22 +0800 Subject: [PATCH 40/45] cabana: faster copy events (#27499) --- tools/cabana/streams/livestream.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index b2fc7ea4a6..8f63d3baec 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -89,10 +89,11 @@ void LiveStream::removeExpiredEvents() { } const std::vector *LiveStream::events() const { - events_vector.clear(); std::lock_guard lk(lock); - events_vector.reserve(can_events.size()); - std::copy(can_events.begin(), can_events.end(), std::back_inserter(events_vector)); + if (events_vector.capacity() <= can_events.size()) { + events_vector.reserve(can_events.size() * 2); + } + events_vector.assign(can_events.begin(), can_events.end()); return &events_vector; } From c2018d6bf291e68102859eb31bb1dd68790172b1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 6 Mar 2023 08:03:44 +0800 Subject: [PATCH 41/45] cabana: use a segment tree to solve range queries in O(log n) time complexity (#27498) --- tools/cabana/chartswidget.cc | 17 +++++++++++++---- tools/cabana/chartswidget.h | 1 + tools/cabana/util.cc | 34 ++++++++++++++++++++++++++++++++++ tools/cabana/util.h | 13 +++++++++++++ 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index bd4bf4aba9..54966be578 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -562,6 +562,9 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even if (events->size()) { s.last_value_mono_time = events->back()->mono_time; } + if (!can->liveStreaming()) { + s.segment_tree.build(s.vals); + } s.series->replace(series_type == SeriesType::StepLine ? s.step_vals : s.vals); } } @@ -586,9 +589,15 @@ void ChartView::updateAxisY() { auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); - for (auto it = first; it != last; ++it) { - if (it->y() < min) min = it->y(); - if (it->y() > max) max = it->y(); + if (can->liveStreaming()) { + for (auto it = first; it != last; ++it) { + if (it->y() < min) min = it->y(); + if (it->y() > max) max = it->y(); + } + } else { + auto [min_y, max_y] = s.segment_tree.minmax(std::distance(s.vals.begin(), first), std::distance(s.vals.begin(), last)); + min = std::min(min, min_y); + max = std::max(max, max_y); } } if (min == std::numeric_limits::max()) min = 0; @@ -781,7 +790,7 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { painter->setPen(Qt::NoPen); qreal track_line_x = -1; for (auto &s : sigs) { - if (!s.track_pt.isNull() && s.series->isVisible()) { + if (!s.track_pt.isNull() && s.series->isVisible()) { painter->setBrush(s.series->color().darker(125)); painter->drawEllipse(s.track_pt, 5.5, 5.5); track_line_x = std::max(track_line_x, s.track_pt.x()); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 76943c1fe9..c86c19a04e 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -46,6 +46,7 @@ public: QVector step_vals; uint64_t last_value_mono_time = 0; QPointF track_pt{}; + SegmentTree segment_tree; }; signals: diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 5e4f505d29..1a0b9d93ef 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -67,6 +67,40 @@ void ChangeTracker::clear() { colors.clear(); } + +// SegmentTree + +void SegmentTree::build(const QVector &arr) { + size = arr.size(); + tree.resize(4 * size); // size of the tree is 4 times the size of the array + if (size > 0) { + build_tree(arr, 1, 0, size - 1); + } +} + +void SegmentTree::build_tree(const QVector &arr, int n, int left, int right) { + if (left == right) { + const double y = arr[left].y(); + tree[n] = {y, y}; + } else { + const int mid = (left + right) >> 1; + build_tree(arr, 2 * n, left, mid); + build_tree(arr, 2 * n + 1, mid + 1, right); + tree[n] = {std::min(tree[2 * n].first, tree[2 * n + 1].first), std::max(tree[2 * n].second, tree[2 * n + 1].second)}; + } +} + +std::pair SegmentTree::get_minmax(int n, int left, int right, int range_left, int range_right) const { + if (range_left > right || range_right < left) + return {std::numeric_limits::max(), std::numeric_limits::lowest()}; + if (range_left <= left && range_right >= right) + return tree[n]; + int mid = (left + right) >> 1; + auto l = get_minmax(2 * n, left, mid, range_left, range_right); + auto r = get_minmax(2 * n + 1, mid + 1, right, range_left, range_right); + return {std::min(l.first, r.first), std::max(l.second, r.second)}; +} + // MessageBytesDelegate MessageBytesDelegate::MessageBytesDelegate(QObject *parent) : QStyledItemDelegate(parent) { diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 5eb5c3c5aa..cf1b5d4b20 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -35,6 +35,19 @@ enum { BytesRole = Qt::UserRole + 2 }; +class SegmentTree { +public: + SegmentTree() = default; + void build(const QVector &arr); + inline std::pair minmax(int left, int right) const { return get_minmax(1, 0, size - 1, left, right); } + +private: + std::pair get_minmax(int n, int left, int right, int range_left, int range_right) const; + void build_tree(const QVector &arr, int n, int left, int right); + std::vector> tree; + int size = 0; +}; + class MessageBytesDelegate : public QStyledItemDelegate { Q_OBJECT public: From fd2e03decf0a89e1c04e0a8d6aee0bf033d2ec0b Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 6 Mar 2023 02:44:56 +0000 Subject: [PATCH 42/45] Ford: add missing Explorer FW (#27502) `1493c38de09a381a|2023-03-05--21-10-07--0` VIN: `1FMSK8FH6LGB17698` --- selfdrive/car/ford/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 3bc56eb9dd..50c7d93987 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -165,6 +165,7 @@ FW_VERSIONS = { b'M1MC-14D003-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x760, None): [ + b'L1MC-2D053-BA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MC-2D053-BB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MC-2D053-BF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MC-2D053-KB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', @@ -178,6 +179,7 @@ FW_VERSIONS = { b'LC5T-14F397-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x7E0, None): [ + b'LB5A-14C204-BUJ\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LB5A-14C204-EAC\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'MB5A-14C204-MD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'MB5A-14C204-RC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', From e729f5b763a98f4156c1761f1511135cc32121d3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 6 Mar 2023 15:36:39 -0800 Subject: [PATCH 43/45] Remove dashcam override param (#27509) * remove dashcam override * sort * remove ford from segments --- common/params.cc | 1 - selfdrive/controls/controlsd.py | 3 --- selfdrive/test/process_replay/process_replay.py | 3 --- selfdrive/test/process_replay/test_processes.py | 3 +-- 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/common/params.cc b/common/params.cc index 2ba4f7e8ab..e74c63bf6a 100644 --- a/common/params.cc +++ b/common/params.cc @@ -99,7 +99,6 @@ std::unordered_map keys = { {"CompletedTrainingVersion", PERSISTENT}, {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, - {"DashcamOverride", PERSISTENT}, {"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"DisablePowerDown", PERSISTENT}, {"ExperimentalMode", PERSISTENT}, diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index f49b58212a..1391d6570c 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -112,9 +112,6 @@ class Controls: if not self.disengage_on_accelerator: self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS - if self.CP.dashcamOnly and self.params.get_bool("DashcamOverride"): - self.CP.dashcamOnly = False - # read params self.is_metric = self.params.get_bool("IsMetric") self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled") diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 7dc0b139a3..971ddb3fe2 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -449,9 +449,6 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None): if CP.openpilotLongitudinalControl: params.put_bool("ExperimentalLongitudinalEnabled", True) - # controlsd process configuration assume all routes are out of dashcam - params.put_bool("DashcamOverride", True) - def python_replay_process(cfg, lr, fingerprint=None): sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub] diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 569090f606..07117c2e7f 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -29,12 +29,12 @@ source_segments = [ ("SUBARU", "341dccd5359e3c97|2022-09-12--10-35-33--3"), # SUBARU.OUTBACK ("GM", "0c58b6a25109da2b|2021-02-23--16-35-50--11"), # GM.VOLT ("GM2", "376bf99325883932|2022-10-27--13-41-22--1"), # GM.BOLT_EUV - ("FORD", "54827bf84c38b14f|2023-01-26--21-59-07--4"), # FORD.BRONCO_SPORT_MK1 ("NISSAN", "35336926920f3571|2021-02-12--18-38-48--46"), # NISSAN.XTRAIL ("VOLKSWAGEN", "de9592456ad7d144|2021-06-29--11-00-15--6"), # VOLKSWAGEN.GOLF ("MAZDA", "bd6a637565e91581|2021-10-30--15-14-53--4"), # MAZDA.CX9_2021 # Enable when port is tested and dashcamOnly is no longer set + #("FORD", "54827bf84c38b14f|2023-01-26--21-59-07--4"), # FORD.BRONCO_SPORT_MK1 #("TESLA", "bb50caf5f0945ab1|2021-06-19--17-20-18--3"), # TESLA.AP2_MODELS #("VOLKSWAGEN2", "3cfdec54aa035f3f|2022-07-19--23-45-10--2"), # VOLKSWAGEN.PASSAT_NMS ] @@ -53,7 +53,6 @@ segments = [ ("SUBARU", "regen1E72BBDCED5|2022-09-27--15-55-31--0"), ("GM", "regen45B05A80EF6|2022-09-27--15-57-22--0"), ("GM2", "376bf99325883932|2022-10-27--13-41-22--1"), - ("FORD", "54827bf84c38b14f|2023-01-26--21-59-07--4"), ("NISSAN", "regenC19D899B46D|2022-09-27--15-59-13--0"), ("VOLKSWAGEN", "regenD8F7AC4BD0D|2022-09-27--16-41-45--0"), ("MAZDA", "regenFC3F9ECBB64|2022-09-27--16-03-09--0"), From 3892c6098085ad05878f78aef0afefac55e38306 Mon Sep 17 00:00:00 2001 From: George Hotz <72895+geohot@users.noreply.github.com> Date: Mon, 6 Mar 2023 15:50:28 -0800 Subject: [PATCH 44/45] tinygrad: bump to 0.5 (#27505) * bump tinygrad to 0.5 * update release files * ref commit + bump tinygrad * save 220 mW --------- Co-authored-by: Comma Device --- release/files_common | 9 +++++---- selfdrive/modeld/SConscript | 2 +- selfdrive/test/process_replay/model_replay_ref_commit | 2 +- system/hardware/tici/test_power_draw.py | 2 +- tinygrad_repo | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/release/files_common b/release/files_common index 5b310d5c80..e0f989e9be 100644 --- a/release/files_common +++ b/release/files_common @@ -577,13 +577,14 @@ opendbc/tesla_can.dbc opendbc/tesla_radar.dbc opendbc/tesla_powertrain.dbc -tinygrad_repo/accel/opencl/* -tinygrad_repo/tinygrad/llops/ops_opencl.py tinygrad_repo/openpilot/compile.py tinygrad_repo/extra/onnx.py +tinygrad_repo/extra/onnx_ops.py tinygrad_repo/extra/thneed.py tinygrad_repo/extra/utils.py -tinygrad_repo/tinygrad/llops/ops_gpu.py -tinygrad_repo/tinygrad/shape/* +tinygrad_repo/tinygrad/codegen/ast.py +tinygrad_repo/tinygrad/codegen/gpu.py tinygrad_repo/tinygrad/nn/* +tinygrad_repo/tinygrad/runtime/ops_gpu.py +tinygrad_repo/tinygrad/shape/* tinygrad_repo/tinygrad/*.py diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index 7bbc1b3477..c7e0dc5d86 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -70,7 +70,7 @@ lenv.Program('_dmonitoringmodeld', [ if use_thneed and arch == "larch64" or GetOption('pc_thneed'): fn = File("models/supercombo").abspath - tinygrad_opts = ["NATIVE_EXPLOG=1", "VALIDHACKS=1", "OPTWG=1", "IMAGE=2", "GPU=1", "CLCACHE=0"] + tinygrad_opts = ["NATIVE_EXPLOG=1", "VALIDHACKS=1", "OPTLOCAL=1", "IMAGE=2", "GPU=1", "ENABLE_METHOD_CACHE=1"] if not GetOption('pc_thneed'): # use FLOAT16 on device for speed + don't cache the CL kernels for space tinygrad_opts += ["FLOAT16=1", "PYOPENCL_NO_CACHE=1"] diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index c64f522352..ad09668a46 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -ba947edbb131a2a36ced7c490dfcf3280ad5b167 +ab64afd1abd1059c14f50c67b51e5ef89029f216 diff --git a/system/hardware/tici/test_power_draw.py b/system/hardware/tici/test_power_draw.py index 2460152998..6c3f5747e3 100755 --- a/system/hardware/tici/test_power_draw.py +++ b/system/hardware/tici/test_power_draw.py @@ -20,7 +20,7 @@ class Proc: PROCS = [ Proc('camerad', 2.15), - Proc('modeld', 1.15, atol=0.2), + Proc('modeld', 0.93, atol=0.2), Proc('dmonitoringmodeld', 0.4), Proc('encoderd', 0.23), ] diff --git a/tinygrad_repo b/tinygrad_repo index 2e1d47b166..d8dda2af3a 160000 --- a/tinygrad_repo +++ b/tinygrad_repo @@ -1 +1 @@ -Subproject commit 2e1d47b16625ff343516287cdd9e4bcb26f5c4ef +Subproject commit d8dda2af3afcef0bb772fff580cfa8b3eabf7f69 From ebd25b8a7de29542be7c6a213c578bc363999857 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 6 Mar 2023 16:13:29 -0800 Subject: [PATCH 45/45] test_power_draw: add header to output table (#27511) * test_power_draw: add header to output table * units --- poetry.lock | 30 +++++++++++-------------- pyproject.toml | 1 + system/hardware/tici/test_power_draw.py | 10 +++++---- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/poetry.lock b/poetry.lock index 91e1b5c826..ec4022c81f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4355,6 +4355,14 @@ python-versions = "*" [package.dependencies] types-urllib3 = "<1.27" +[[package]] +name = "types-tabulate" +version = "0.9.0.1" +description = "Typing stubs for tabulate" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "types-urllib3" version = "1.26.25.1" @@ -4567,7 +4575,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "9e9495c896e6fd0855803aeaf46513c6c22424b86be820759a8baf27d44e73ee" +content-hash = "669485055bf8d77336509cb7a3878e06aa32431c520825948914d76b57347fde" [metadata.files] adal = [ @@ -6616,7 +6624,6 @@ onnx = [ ] onnx2torch = [ {file = "onnx2torch-1.5.4-py3-none-any.whl", hash = "sha256:fd1a0fe05072bfb9f3d86d9330299b130b41f11bd4ae634db17078974e711725"}, - {file = "onnx2torch-1.5.4.tar.gz", hash = "sha256:df837b557a63540223d85fde4a1d679fde0ca8d8bb89d5379c030b01eddc9c24"}, ] onnxoptimizer = [ {file = "onnxoptimizer-0.3.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e73a5e2e3ca4db9bff54f7131768749c861677b97ee811a136fcf1a52783cf6e"}, @@ -7002,7 +7009,6 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c9ed8aa31c146bef65d89a1b655f5f4eab5e1120f55fc297713c89c9e56ff0b"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:5099c9ca345b2f252f0c28e96904643153bae9258647585e5e6f649bb7a1844a"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:2ec709b0a58b539a4f9d33fb8508264c3678d7edb33a68b8906ba914f71e8c13"}, - {file = "pycryptodome-3.15.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:2ae53125de5b0d2c95194d957db9bb2681da8c24d0fb0fe3b056de2bcaf5d837"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win32.whl", hash = "sha256:fd2184aae6ee2a944aaa49113e6f5787cdc5e4db1eb8edb1aea914bd75f33a0c"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:7e3a8f6ee405b3bd1c4da371b93c31f7027944b2bcce0697022801db93120d83"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:b9c5b1a1977491533dfd31e01550ee36ae0249d78aae7f632590db833a5012b8"}, @@ -7010,14 +7016,12 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2aa55aae81f935a08d5a3c2042eb81741a43e044bd8a81ea7239448ad751f763"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c3640deff4197fa064295aaac10ab49a0d55ef3d6a54ae1499c40d646655c89f"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:045d75527241d17e6ef13636d845a12e54660aa82e823b3b3341bcf5af03fa79"}, - {file = "pycryptodome-3.15.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:eb6fce570869e70cc8ebe68eaa1c26bed56d40ad0f93431ee61d400525433c54"}, {file = "pycryptodome-3.15.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e"}, - {file = "pycryptodome-3.15.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:50ca7e587b8e541eb6c192acf92449d95377d1f88908c0a32ac5ac2703ebe28b"}, {file = "pycryptodome-3.15.0-cp35-abi3-win32.whl", hash = "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1"}, {file = "pycryptodome-3.15.0-cp35-abi3-win_amd64.whl", hash = "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9"}, {file = "pycryptodome-3.15.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f"}, @@ -7659,18 +7663,6 @@ setproctitle = [ {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1"}, {file = "setproctitle-1.3.2-cp310-cp310-win32.whl", hash = "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099"}, {file = "setproctitle-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d"}, - {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a97d51c17d438cf5be284775a322d57b7ca9505bb7e118c28b1824ecaf8aeaa"}, - {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:587c7d6780109fbd8a627758063d08ab0421377c0853780e5c356873cdf0f077"}, - {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d17c8bd073cbf8d141993db45145a70b307385b69171d6b54bcf23e5d644de"}, - {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e932089c35a396dc31a5a1fc49889dd559548d14cb2237adae260382a090382e"}, - {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e4f8f12258a8739c565292a551c3db62cca4ed4f6b6126664e2381acb4931bf"}, - {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:570d255fd99c7f14d8f91363c3ea96bd54f8742275796bca67e1414aeca7d8c3"}, - {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a8e0881568c5e6beff91ef73c0ec8ac2a9d3ecc9edd6bd83c31ca34f770910c4"}, - {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4bba3be4c1fabf170595b71f3af46c6d482fbe7d9e0563999b49999a31876f77"}, - {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:37ece938110cab2bb3957e3910af8152ca15f2b6efdf4f2612e3f6b7e5459b80"}, - {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db684d6bbb735a80bcbc3737856385b55d53f8a44ce9b46e9a5682c5133a9bf7"}, - {file = "setproctitle-1.3.2-cp311-cp311-win32.whl", hash = "sha256:ca58cd260ea02759238d994cfae844fc8b1e206c684beb8f38877dcab8451dfc"}, - {file = "setproctitle-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:88486e6cce2a18a033013d17b30a594f1c5cb42520c49c19e6ade40b864bb7ff"}, {file = "setproctitle-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927"}, {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02"}, {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83"}, @@ -8066,6 +8058,10 @@ types-requests = [ {file = "types-requests-2.28.11.2.tar.gz", hash = "sha256:fdcd7bd148139fb8eef72cf4a41ac7273872cad9e6ada14b11ff5dfdeee60ed3"}, {file = "types_requests-2.28.11.2-py3-none-any.whl", hash = "sha256:14941f8023a80b16441b3b46caffcbfce5265fd14555844d6029697824b5a2ef"}, ] +types-tabulate = [ + {file = "types-tabulate-0.9.0.1.tar.gz", hash = "sha256:e486292c279f19247865bdabe802419740a0e74b53444e7f7a8009e08129da5d"}, + {file = "types_tabulate-0.9.0.1-py3-none-any.whl", hash = "sha256:be2ea0de05f615ccfcbadf6206aa720e265955eb1de23e343aec9d8bf3fa9aaa"}, +] types-urllib3 = [ {file = "types-urllib3-1.26.25.1.tar.gz", hash = "sha256:a948584944b2412c9a74b9cf64f6c48caf8652cb88b38361316f6d15d8a184cd"}, {file = "types_urllib3-1.26.25.1-py3-none-any.whl", hash = "sha256:f6422596cc9ee5fdf68f9d547f541096a20c2dcfd587e37c804c9ea720bf5cb2"}, diff --git a/pyproject.toml b/pyproject.toml index 6b4b0bb5fa..b1ad273cd7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,6 +59,7 @@ urllib3 = "^1.26.10" utm = "^0.7.0" websocket_client = "^1.3.3" polyline = "^1.4.0" +types-tabulate = "^0.9.0.1" [tool.poetry.group.dev.dependencies] diff --git a/system/hardware/tici/test_power_draw.py b/system/hardware/tici/test_power_draw.py index 6c3f5747e3..f563933285 100755 --- a/system/hardware/tici/test_power_draw.py +++ b/system/hardware/tici/test_power_draw.py @@ -3,6 +3,7 @@ import unittest import time import math from dataclasses import dataclass +from tabulate import tabulate from system.hardware import HARDWARE, TICI from system.hardware.tici.power_monitor import get_power @@ -58,15 +59,16 @@ class TestPowerDraw(unittest.TestCase): manager_cleanup() - print("-"*35) - print(f"Baseline {baseline:.2f}W\n") + tab = [] + tab.append(['process', 'expected (W)', 'current (W)']) for proc in PROCS: cur = used[proc.name] expected = proc.power - print(f"{proc.name.ljust(20)} {expected:.2f}W {cur:.2f}W") + tab.append([proc.name, round(expected, 2), round(cur, 2)]) with self.subTest(proc=proc.name): self.assertTrue(math.isclose(cur, expected, rel_tol=proc.rtol, abs_tol=proc.atol)) - print("-"*35) + print(tabulate(tab)) + print(f"Baseline {baseline:.2f}W\n") if __name__ == "__main__":