From f811dcc0cb4881fc6b1139d27a0fc15141c28f69 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 26 Mar 2021 01:03:42 -0700 Subject: [PATCH 01/18] always qt --- selfdrive/ui/sidebar.cc | 4 ---- selfdrive/ui/ui.hpp | 4 ---- 2 files changed, 8 deletions(-) diff --git a/selfdrive/ui/sidebar.cc b/selfdrive/ui/sidebar.cc index 150841008e..805e1520cd 100644 --- a/selfdrive/ui/sidebar.cc +++ b/selfdrive/ui/sidebar.cc @@ -7,11 +7,7 @@ #include "sidebar.hpp" static void draw_background(UIState *s) { -#ifndef QT_GUI_LIB - const NVGcolor color = COLOR_BLACK_ALPHA(85); -#else const NVGcolor color = nvgRGBA(0x39, 0x39, 0x39, 0xff); -#endif ui_fill_rect(s->vg, {0, 0, sbr_w, s->fb_h}, color); } diff --git a/selfdrive/ui/ui.hpp b/selfdrive/ui/ui.hpp index b32116e006..e5e8790b1a 100644 --- a/selfdrive/ui/ui.hpp +++ b/selfdrive/ui/ui.hpp @@ -74,11 +74,7 @@ typedef enum UIStatus { } UIStatus; static std::map bg_colors = { -#ifndef QT_GUI_LIB - {STATUS_OFFROAD, nvgRGBA(0x07, 0x23, 0x39, 0xf1)}, -#else {STATUS_OFFROAD, nvgRGBA(0x0, 0x0, 0x0, 0xff)}, -#endif {STATUS_DISENGAGED, nvgRGBA(0x17, 0x33, 0x49, 0xc8)}, {STATUS_ENGAGED, nvgRGBA(0x17, 0x86, 0x44, 0xf1)}, {STATUS_WARNING, nvgRGBA(0xDA, 0x6F, 0x25, 0xf1)}, From 524c9aaa0f7733d2598dc7ab58ace907dd82994f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 26 Mar 2021 01:05:32 -0700 Subject: [PATCH 02/18] add rest of vw to release notes --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index fd1058e187..a0e9e490df 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -10,7 +10,9 @@ Version 0.8.3 (2021-XX-XX) * Default SSH key only used for setup * Kia Ceed 2019 support thanks to ZanZaD13! * Kia Seltos 2021 support thanks to speedking456! + * Skoda Kodiaq 2018 support thanks to jyoung8607! * Volkswagen Tiguan 2020 support thanks to jyoung8607! + * Volkswagen Jetta 2018-2021 support thanks to jyoung8607! Version 0.8.2 (2021-02-26) ======================== From 6340b43359e9f53174b31cd3940c6068f82e74f7 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 26 Mar 2021 02:01:41 -0700 Subject: [PATCH 03/18] NEOS 16.2 (#20485) * NEOS 16.2 * new img * emoji --- installer/updater/update.json | 8 ++++---- launch_chffrplus.sh | 3 --- launch_env.sh | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/installer/updater/update.json b/installer/updater/update.json index 18d2139572..faff0c52d7 100644 --- a/installer/updater/update.json +++ b/installer/updater/update.json @@ -1,7 +1,7 @@ { - "ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-c082c7c3365829b9df9cbbc5b20a9aed3cc5c98ebb17351e7e00e6285072c403.zip", - "ota_hash": "c082c7c3365829b9df9cbbc5b20a9aed3cc5c98ebb17351e7e00e6285072c403", - "recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-a7c7d5d54b9f3afa6ae3d22ceab44f018b819c02443e4a09578089fbdb2ec4ee.img", + "ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-969e22c42e5c6314e54bc3ccaa5c6a684f3130a53a7a70e0cea9f1453ceb0b06.zip", + "ota_hash": "969e22c42e5c6314e54bc3ccaa5c6a684f3130a53a7a70e0cea9f1453ceb0b06", + "recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-9c784a24826c25df315d0ace864224478e9c0e86b904f5d1f8e18ea1037e842b.img", "recovery_len": 15209772, - "recovery_hash": "a7c7d5d54b9f3afa6ae3d22ceab44f018b819c02443e4a09578089fbdb2ec4ee" + "recovery_hash": "9c784a24826c25df315d0ace864224478e9c0e86b904f5d1f8e18ea1037e842b" } diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index cc6e8f4973..c9605cbab3 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -10,9 +10,6 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" function two_init { - export QT_QPA_EGLFS_PHYSICAL_WIDTH=151 - export QT_QPA_EGLFS_PHYSICAL_HEIGHT=74 - # Wifi scan wpa_cli IFNAME=wlan0 SCAN diff --git a/launch_env.sh b/launch_env.sh index 6bc84c7068..da81aa4126 100755 --- a/launch_env.sh +++ b/launch_env.sh @@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1 export VECLIB_MAXIMUM_THREADS=1 if [ -z "$REQUIRED_NEOS_VERSION" ]; then - export REQUIRED_NEOS_VERSION="16.1" + export REQUIRED_NEOS_VERSION="16.2" fi if [ -z "$AGNOS_VERSION" ]; then From 763b43780dae7aca1544e8a3cc525ce72f4abfc8 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 26 Mar 2021 11:57:59 +0100 Subject: [PATCH 04/18] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index ad9ecefe65..4906dc7b22 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit ad9ecefe65ce4ea7bcaf3bfe692ee2a3fc6b0b63 +Subproject commit 4906dc7b220c672fc61119354f4bbc89fccf07df From 80ae6a7e1b1d1ec231c4719b677fd08b22818ce1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 26 Mar 2021 20:29:30 +0800 Subject: [PATCH 05/18] Qt: cache home screen state (#20395) * cache drive stats * don't parse response if it's the same as previous * remove blank line * cleanup * update stats in place * validate json * add DriveStats to params.pyx * cleanup * cleanup * remove //#include * simplify * add cache to RequestRepeater * rename CachedDriveStats to ApiCacheDriveStats * rename ApiCacheDriveStats to ApiCache_DriveStats Co-authored-by: Willem Melching --- common/params_pyx.pyx | 1 + selfdrive/ui/qt/api.cc | 14 +++- selfdrive/ui/qt/api.hpp | 3 +- selfdrive/ui/qt/widgets/drive_stats.cc | 94 ++++++++----------------- selfdrive/ui/qt/widgets/drive_stats.hpp | 8 +-- 5 files changed, 49 insertions(+), 71 deletions(-) diff --git a/common/params_pyx.pyx b/common/params_pyx.pyx index 2add3a0772..81368a401a 100755 --- a/common/params_pyx.pyx +++ b/common/params_pyx.pyx @@ -15,6 +15,7 @@ cdef enum TxType: keys = { b"AccessToken": [TxType.CLEAR_ON_MANAGER_START], + b"ApiCache_DriveStats": [TxType.PERSISTENT], b"AthenadPid": [TxType.PERSISTENT], b"CalibrationParams": [TxType.PERSISTENT], b"CarBatteryCapacity": [TxType.PERSISTENT], diff --git a/selfdrive/ui/qt/api.cc b/selfdrive/ui/qt/api.cc index 48726b989b..c20a68872a 100644 --- a/selfdrive/ui/qt/api.cc +++ b/selfdrive/ui/qt/api.cc @@ -76,8 +76,8 @@ QString CommaApi::create_jwt() { return create_jwt(*(new QVector>())); } -RequestRepeater::RequestRepeater(QWidget* parent, QString requestURL, int period_seconds, QVector> payloads, bool disableWithScreen) - : disableWithScreen(disableWithScreen), QObject(parent) { +RequestRepeater::RequestRepeater(QWidget* parent, QString requestURL, int period_seconds, const QString &cache_key, QVector> payloads, bool disableWithScreen) + : disableWithScreen(disableWithScreen), cache_key(cache_key), QObject(parent) { networkAccessManager = new QNetworkAccessManager(this); reply = NULL; @@ -90,6 +90,12 @@ RequestRepeater::RequestRepeater(QWidget* parent, QString requestURL, int period networkTimer->setSingleShot(true); networkTimer->setInterval(20000); connect(networkTimer, SIGNAL(timeout()), this, SLOT(requestTimeout())); + + if (!cache_key.isEmpty()) { + if (std::string cached_resp = Params().get(cache_key.toStdString()); !cached_resp.empty()) { + QTimer::singleShot(0, [=]() { emit receivedResponse(QString::fromStdString(cached_resp)); }); + } + } } void RequestRepeater::sendRequest(QString requestURL, QVector> payloads){ @@ -126,6 +132,10 @@ void RequestRepeater::requestFinished(){ networkTimer->stop(); QString response = reply->readAll(); if (reply->error() == QNetworkReply::NoError) { + // save to cache + if (!cache_key.isEmpty()) { + Params().write_db_value(cache_key.toStdString(), response.toStdString()); + } emit receivedResponse(response); } else { qDebug() << reply->errorString(); diff --git a/selfdrive/ui/qt/api.hpp b/selfdrive/ui/qt/api.hpp index 43bf7b13ba..408adcac99 100644 --- a/selfdrive/ui/qt/api.hpp +++ b/selfdrive/ui/qt/api.hpp @@ -33,7 +33,7 @@ class RequestRepeater : public QObject { Q_OBJECT public: - explicit RequestRepeater(QWidget* parent, QString requestURL, int period = 10, QVector> payloads = *(new QVector>()), bool disableWithScreen = true); + explicit RequestRepeater(QWidget* parent, QString requestURL, int period = 10, const QString &cache_key = "", QVector> payloads = *(new QVector>()), bool disableWithScreen = true); bool active = true; private: @@ -41,6 +41,7 @@ private: QNetworkReply* reply; QNetworkAccessManager* networkAccessManager; QTimer* networkTimer; + QString cache_key; void sendRequest(QString requestURL, QVector> payloads); private slots: diff --git a/selfdrive/ui/qt/widgets/drive_stats.cc b/selfdrive/ui/qt/widgets/drive_stats.cc index 1c2af95a9a..b745291d93 100644 --- a/selfdrive/ui/qt/widgets/drive_stats.cc +++ b/selfdrive/ui/qt/widgets/drive_stats.cc @@ -1,8 +1,6 @@ #include #include #include -#include -#include #include #include "api.hpp" @@ -11,94 +9,62 @@ const double MILE_TO_KM = 1.60934; -void clearLayouts(QLayout* layout) { - while (QLayoutItem* item = layout->takeAt(0)) { - if (QWidget* widget = item->widget()) { - widget->deleteLater(); - } - if (QLayout* childLayout = item->layout()) { - clearLayouts(childLayout); - } - delete item; - } -} - -QLayout* build_stat(QString name, int stat) { +static QLayout* build_stat_layout(QLabel** metric, const QString& name) { QVBoxLayout* layout = new QVBoxLayout; layout->setMargin(0); - - QLabel* metric = new QLabel(QString("%1").arg(stat)); - metric->setStyleSheet(R"( - font-size: 80px; - font-weight: 600; - )"); - layout->addWidget(metric, 0, Qt::AlignLeft); + *metric = new QLabel("0"); + (*metric)->setStyleSheet("font-size: 80px; font-weight: 600;"); + layout->addWidget(*metric, 0, Qt::AlignLeft); QLabel* label = new QLabel(name); - label->setStyleSheet(R"( - font-size: 45px; - font-weight: 500; - )"); + label->setStyleSheet("font-size: 45px; font-weight: 500;"); layout->addWidget(label, 0, Qt::AlignLeft); - return layout; } -void DriveStats::parseError(QString response) { - clearLayouts(vlayout); - vlayout->addWidget(new QLabel("No Internet connection"), 0, Qt::AlignCenter); -} - void DriveStats::parseResponse(QString response) { - response.chop(1); - clearLayouts(vlayout); + response = response.trimmed(); QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); if (doc.isNull()) { qDebug() << "JSON Parse failed on getting past drives statistics"; return; } - bool metric = Params().read_db_bool("IsMetric"); + auto update = [](const QJsonObject &obj, StatsLabels& labels, bool metric) { + labels.routes->setText(QString::number((int)obj["routes"].toDouble())); + labels.distance->setText(QString::number(obj["distance"].toDouble() * (metric ? MILE_TO_KM : 1))); + labels.hours->setText(QString::number((int)(obj["minutes"].toDouble() / 60))); + }; + bool metric = Params().read_db_bool("IsMetric"); QJsonObject json = doc.object(); - auto all = json["all"].toObject(); - auto week = json["week"].toObject(); + update(json["all"].toObject(), all_, metric); + update(json["week"].toObject(), week_, metric); +} + +DriveStats::DriveStats(QWidget* parent) : QWidget(parent) { + setStyleSheet("QLabel {font-size: 48px; font-weight: 500;}"); + auto add_stats_layouts = [&](QGridLayout* gl, StatsLabels& labels, int row, const char* distance_unit) { + gl->addLayout(build_stat_layout(&labels.routes, "DRIVES"), row, 0, 3, 1); + gl->addLayout(build_stat_layout(&labels.distance, distance_unit), row, 1, 3, 1); + gl->addLayout(build_stat_layout(&labels.hours, "HOURS"), row, 2, 3, 1); + }; + + const char* distance_unit = Params().read_db_bool("IsMetric") ? "KM" : "MILES"; QGridLayout* gl = new QGridLayout(); gl->setMargin(0); - - int all_distance = all["distance"].toDouble() * (metric ? MILE_TO_KM : 1); gl->addWidget(new QLabel("ALL TIME"), 0, 0, 1, 3); - gl->addLayout(build_stat("DRIVES", all["routes"].toDouble()), 1, 0, 3, 1); - gl->addLayout(build_stat(metric ? "KM" : "MILES", all_distance), 1, 1, 3, 1); - gl->addLayout(build_stat("HOURS", all["minutes"].toDouble() / 60), 1, 2, 3, 1); - - int week_distance = week["distance"].toDouble() * (metric ? MILE_TO_KM : 1); + add_stats_layouts(gl, all_, 1, distance_unit); gl->addWidget(new QLabel("PAST WEEK"), 6, 0, 1, 3); - gl->addLayout(build_stat("DRIVES", week["routes"].toDouble()), 7, 0, 3, 1); - gl->addLayout(build_stat(metric ? "KM" : "MILES", week_distance), 7, 1, 3, 1); - gl->addLayout(build_stat("HOURS", week["minutes"].toDouble() / 60), 7, 2, 3, 1); - - QWidget* q = new QWidget; - q->setLayout(gl); - vlayout->addWidget(q); -} + add_stats_layouts(gl, week_, 7, distance_unit); -DriveStats::DriveStats(QWidget* parent) : QWidget(parent) { - vlayout = new QVBoxLayout(this); - vlayout->setMargin(0); - setLayout(vlayout); - setStyleSheet(R"( - QLabel { - font-size: 48px; - font-weight: 500; - } - )"); + QVBoxLayout* vlayout = new QVBoxLayout(this); + vlayout->addLayout(gl); // TODO: do we really need to update this frequently? QString dongleId = QString::fromStdString(Params().get("DongleId")); QString url = "https://api.commadotai.com/v1.1/devices/" + dongleId + "/stats"; - RequestRepeater* repeater = new RequestRepeater(this, url, 13); + RequestRepeater* repeater = new RequestRepeater(this, url, 13, "ApiCache_DriveStats"); QObject::connect(repeater, SIGNAL(receivedResponse(QString)), this, SLOT(parseResponse(QString))); - QObject::connect(repeater, SIGNAL(failedResponse(QString)), this, SLOT(parseError(QString))); } diff --git a/selfdrive/ui/qt/widgets/drive_stats.hpp b/selfdrive/ui/qt/widgets/drive_stats.hpp index 40cefbb4d9..64b93cfe73 100644 --- a/selfdrive/ui/qt/widgets/drive_stats.hpp +++ b/selfdrive/ui/qt/widgets/drive_stats.hpp @@ -1,7 +1,6 @@ #pragma once -#include -#include +#include class DriveStats : public QWidget { Q_OBJECT @@ -10,9 +9,10 @@ public: explicit DriveStats(QWidget* parent = 0); private: - QVBoxLayout* vlayout; + struct StatsLabels { + QLabel *routes, *distance, *hours; + } all_, week_; private slots: - void parseError(QString response); void parseResponse(QString response); }; From 0ce3792a15ceca429b867493664705d430921d8c Mon Sep 17 00:00:00 2001 From: grekiki Date: Fri, 26 Mar 2021 14:08:01 +0100 Subject: [PATCH 06/18] =?UTF-8?q?RELEASES.md:=20Skoda=20->=20=C5=A0koda=20?= =?UTF-8?q?(#20496)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index a0e9e490df..4bdc9d0755 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -10,7 +10,7 @@ Version 0.8.3 (2021-XX-XX) * Default SSH key only used for setup * Kia Ceed 2019 support thanks to ZanZaD13! * Kia Seltos 2021 support thanks to speedking456! - * Skoda Kodiaq 2018 support thanks to jyoung8607! + * Škoda Kodiaq 2018 support thanks to jyoung8607! * Volkswagen Tiguan 2020 support thanks to jyoung8607! * Volkswagen Jetta 2018-2021 support thanks to jyoung8607! From 32330bbf8930bf20ef9ef2c54682faa5c30eff6c Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 26 Mar 2021 14:52:47 +0100 Subject: [PATCH 07/18] drive_stats.cc: fix distance rounding --- selfdrive/ui/qt/widgets/drive_stats.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/widgets/drive_stats.cc b/selfdrive/ui/qt/widgets/drive_stats.cc index b745291d93..7cbcc0aabd 100644 --- a/selfdrive/ui/qt/widgets/drive_stats.cc +++ b/selfdrive/ui/qt/widgets/drive_stats.cc @@ -32,7 +32,7 @@ void DriveStats::parseResponse(QString response) { auto update = [](const QJsonObject &obj, StatsLabels& labels, bool metric) { labels.routes->setText(QString::number((int)obj["routes"].toDouble())); - labels.distance->setText(QString::number(obj["distance"].toDouble() * (metric ? MILE_TO_KM : 1))); + labels.distance->setText(QString::number(int(obj["distance"].toDouble() * (metric ? MILE_TO_KM : 1)))); labels.hours->setText(QString::number((int)(obj["minutes"].toDouble() / 60))); }; From d43d62561063c4d3f8b10b08d7bde9ed8bd0f395 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 26 Mar 2021 14:53:12 +0100 Subject: [PATCH 08/18] Cache prime/points widget (#20497) * cache prime status on homescreen * use stacked widget * add caching and clear on 404 --- common/params_pyx.pyx | 2 ++ selfdrive/ui/qt/api.cc | 10 ++++++---- selfdrive/ui/qt/api.hpp | 1 + selfdrive/ui/qt/widgets/setup.cc | 23 ++++++++++++++++++----- selfdrive/ui/qt/widgets/setup.hpp | 5 +++-- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/common/params_pyx.pyx b/common/params_pyx.pyx index 81368a401a..499e6ea6e7 100755 --- a/common/params_pyx.pyx +++ b/common/params_pyx.pyx @@ -16,6 +16,8 @@ cdef enum TxType: keys = { b"AccessToken": [TxType.CLEAR_ON_MANAGER_START], b"ApiCache_DriveStats": [TxType.PERSISTENT], + b"ApiCache_Device": [TxType.PERSISTENT], + b"ApiCache_Owner": [TxType.PERSISTENT], b"AthenadPid": [TxType.PERSISTENT], b"CalibrationParams": [TxType.PERSISTENT], b"CarBatteryCapacity": [TxType.PERSISTENT], diff --git a/selfdrive/ui/qt/api.cc b/selfdrive/ui/qt/api.cc index c20a68872a..5522705c4f 100644 --- a/selfdrive/ui/qt/api.cc +++ b/selfdrive/ui/qt/api.cc @@ -133,16 +133,18 @@ void RequestRepeater::requestFinished(){ QString response = reply->readAll(); if (reply->error() == QNetworkReply::NoError) { // save to cache - if (!cache_key.isEmpty()) { - Params().write_db_value(cache_key.toStdString(), response.toStdString()); + if (!cache_key.isEmpty()) { + Params().write_db_value(cache_key.toStdString(), response.toStdString()); } emit receivedResponse(response); } else { - qDebug() << reply->errorString(); + if (!cache_key.isEmpty()) { + Params().delete_db_value(cache_key.toStdString()); + } emit failedResponse(reply->errorString()); } } else { - emit failedResponse("network timeout"); + emit timeoutResponse("timeout"); } reply->deleteLater(); reply = NULL; diff --git a/selfdrive/ui/qt/api.hpp b/selfdrive/ui/qt/api.hpp index 408adcac99..3772727be9 100644 --- a/selfdrive/ui/qt/api.hpp +++ b/selfdrive/ui/qt/api.hpp @@ -51,4 +51,5 @@ private slots: signals: void receivedResponse(QString response); void failedResponse(QString errorString); + void timeoutResponse(QString errorString); }; diff --git a/selfdrive/ui/qt/widgets/setup.cc b/selfdrive/ui/qt/widgets/setup.cc index 64a2f68265..32e14f20dd 100644 --- a/selfdrive/ui/qt/widgets/setup.cc +++ b/selfdrive/ui/qt/widgets/setup.cc @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include @@ -107,7 +107,7 @@ PrimeUserWidget::PrimeUserWidget(QWidget* parent) : QWidget(parent) { // TODO: only send the request when widget is shown QString url = "https://api.commadotai.com/v1/devices/" + dongleId + "/owner"; - RequestRepeater* repeater = new RequestRepeater(this, url, 6); + RequestRepeater* repeater = new RequestRepeater(this, url, 6, "ApiCache_Owner"); QObject::connect(repeater, SIGNAL(receivedResponse(QString)), this, SLOT(replyFinished(QString))); } @@ -156,7 +156,7 @@ PrimeAdWidget::PrimeAdWidget(QWidget* parent) : QWidget(parent) { SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { - mainLayout = new QStackedLayout; + mainLayout = new QStackedWidget; // Unpaired, registration prompt layout @@ -214,7 +214,12 @@ SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { primeUser = new PrimeUserWidget; mainLayout->addWidget(primeUser); - setLayout(mainLayout); + mainLayout->setCurrentWidget(primeAd); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(mainLayout); + setLayout(layout); + setStyleSheet(R"( SetupWidget { background-color: #292929; @@ -226,16 +231,23 @@ SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { } )"); + // Retain size while hidden + QSizePolicy sp_retain = sizePolicy(); + sp_retain.setRetainSizeWhenHidden(true); + setSizePolicy(sp_retain); + // set up API requests QString dongleId = QString::fromStdString(Params().get("DongleId")); QString url = "https://api.commadotai.com/v1.1/devices/" + dongleId + "/"; - RequestRepeater* repeater = new RequestRepeater(this, url, 5); + RequestRepeater* repeater = new RequestRepeater(this, url, 5, "ApiCache_Device"); QObject::connect(repeater, SIGNAL(receivedResponse(QString)), this, SLOT(replyFinished(QString))); QObject::connect(repeater, SIGNAL(failedResponse(QString)), this, SLOT(parseError(QString))); + hide(); // Only show when first request comes back } void SetupWidget::parseError(QString response) { + show(); showQr = false; mainLayout->setCurrentIndex(0); } @@ -246,6 +258,7 @@ void SetupWidget::showQrCode(){ } void SetupWidget::replyFinished(QString response) { + show(); QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); if (doc.isNull()) { qDebug() << "JSON Parse failed on getting pairing and prime status"; diff --git a/selfdrive/ui/qt/widgets/setup.hpp b/selfdrive/ui/qt/widgets/setup.hpp index 6cd18b1bc7..0479db8f95 100644 --- a/selfdrive/ui/qt/widgets/setup.hpp +++ b/selfdrive/ui/qt/widgets/setup.hpp @@ -1,7 +1,8 @@ #pragma once #include -#include +#include +#include #include #include "api.hpp" @@ -48,7 +49,7 @@ public: explicit SetupWidget(QWidget* parent = 0); private: - QStackedLayout* mainLayout; + QStackedWidget* mainLayout; CommaApi* api; PrimeAdWidget *primeAd; PrimeUserWidget *primeUser; From 52035170578ccdf0b70da7a481731e3e794fe36e Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 26 Mar 2021 14:54:55 +0100 Subject: [PATCH 09/18] qt ui add gitignore to release --- release/files_common | 1 + 1 file changed, 1 insertion(+) diff --git a/release/files_common b/release/files_common index 4a4c185233..8536da8758 100644 --- a/release/files_common +++ b/release/files_common @@ -336,6 +336,7 @@ selfdrive/test/helpers.py selfdrive/test/setup_device_ci.sh selfdrive/test/test_fingerprints.py +selfdrive/ui/.gitignore selfdrive/ui/SConscript selfdrive/ui/*.cc selfdrive/ui/*.hpp From 32b59ba114f0e086fa842f0e2dc53a053ad07f7e Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Fri, 26 Mar 2021 10:01:31 -0400 Subject: [PATCH 10/18] VW MQB: SEAT Ateca Mk1 (#20492) * Add SEAT Ateca * Add test route for Ateca * Add Ateca to README * Pull unnecessary comments --- README.md | 1 + selfdrive/car/volkswagen/interface.py | 5 +++++ selfdrive/car/volkswagen/values.py | 24 +++++++++++++++++++++++- selfdrive/test/test_car_models.py | 4 ++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bb67fb347c..5edf3e833e 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,7 @@ Community Maintained Cars and Features | Nissan | Leaf 2018-20 | ProPILOT | Stock | 0mph | 0mph | | Nissan | Rogue 2018-19 | ProPILOT | Stock | 0mph | 0mph | | Nissan | X-Trail 2017 | ProPILOT | Stock | 0mph | 0mph | +| SEAT | Ateca 2018 | Driver Assistance | Stock | 0mph | 0mph | | Škoda | Kodiaq 2018 | Driver Assistance | Stock | 0mph | 0mph | | Subaru | Ascent 2019 | EyeSight | Stock | 0mph | 0mph | | Subaru | Crosstrek 2018-19 | EyeSight | Stock | 0mph | 0mph | diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 7bdfda9d36..0bf04dd298 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -72,6 +72,11 @@ class CarInterface(CarInterfaceBase): ret.mass = 1715 + STD_CARGO_KG ret.wheelbase = 2.74 + elif candidate == CAR.SEAT_ATECA_MK1: + # Averages of all 5F Ateca variants + ret.mass = 1900 + STD_CARGO_KG + ret.wheelbase = 2.64 + elif candidate == CAR.SKODA_KODIAQ_MK1: # Averages of all 5N Kodiaq variants ret.mass = 1569 + STD_CARGO_KG diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 482c01f1a5..ab7825ff76 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -58,6 +58,7 @@ class CAR: GOLF = "VOLKSWAGEN GOLF" # Chassis 5G/AU/BA/BE, Mk7 VW Golf and variants JETTA_MK7 = "VOLKSWAGEN JETTA 7TH GEN" # Chassis BU, Mk7 Jetta TIGUAN_MK2 = "VOLKSWAGEN TIGUAN 2ND GEN" # Chassis AD/BW, Mk2 VW Tiguan and variants + SEAT_ATECA_MK1 = "SEAT ATECA 1ST GEN" # Chassis 5F, Mk1 SEAT Ateca and CUPRA Ateca SKODA_KODIAQ_MK1 = "SKODA KODIAQ 1ST GEN" # Chassis NS, Mk1 Skoda Kodiaq AUDI_A3 = "AUDI A3" # Chassis 8V/FF, Mk3 Audi A3 and variants @@ -74,12 +75,15 @@ FINGERPRINTS = { CAR.AUDI_A3: [{ 64: 8, 134: 8, 159: 8, 173: 8, 178: 8, 253: 8, 257: 8, 260: 8, 262: 8, 278: 8, 279: 8, 283: 8, 285: 8, 286: 8, 288: 8, 289: 8, 290: 8, 294: 8, 295: 8, 299: 8, 302: 8, 346: 8, 418: 8, 427: 8, 506: 8, 679: 8, 681: 8, 695: 8, 779: 8, 780: 8, 783: 8, 787: 8, 788: 8, 789: 8, 792: 8, 802: 8, 804: 8, 806: 8, 807: 8, 808: 8, 809: 8, 846: 8, 847: 8, 870: 8, 896: 8, 897: 8, 898: 8, 901: 8, 917: 8, 919: 8, 949: 8, 958: 8, 960: 4, 981: 8, 987: 8, 988: 8, 991: 8, 997: 8, 1000: 8, 1019: 8, 1122: 8, 1123: 8, 1124: 8, 1153: 8, 1162: 8, 1175: 8, 1312: 8, 1385: 8, 1413: 8, 1440: 5, 1514: 8, 1515: 8, 1520: 8, 1600: 8, 1601: 8, 1603: 8, 1624: 8, 1629: 8, 1631: 8, 1646: 8, 1648: 8, 1712: 6, 1714: 8, 1716: 8, 1717: 8, 1719: 8, 1720: 8, 1721: 8, 1792: 8, 1872: 8, 1976: 8, 1977: 8, 1982: 8, 1985: 8 }], + CAR.SEAT_ATECA_MK1: [{ + 64: 8, 134: 8, 159: 8, 173: 8, 178: 8, 253: 8, 257: 8, 260: 8, 262: 8, 278: 8, 279: 8, 283: 8, 286: 8, 288: 8, 289: 8, 290: 8, 294: 8, 299: 8, 302: 8, 346: 8, 385: 8, 418: 8, 427: 8, 668: 8, 679: 8, 681: 8, 684: 8, 779: 8, 780: 8, 792: 8, 795: 8, 804: 8, 806: 8, 807: 8, 808: 8, 809: 8, 870: 8, 901: 8, 917: 8, 919: 8, 927: 8, 949: 8, 958: 8, 960: 4, 981: 8, 987: 8, 988: 8, 991: 8, 997: 8, 1000: 8, 1019: 8, 1120: 8, 1122: 8, 1123: 8, 1124: 8, 1153: 8, 1162: 8, 1175: 8, 1312: 8, 1385: 8, 1413: 8, 1440: 5, 1514: 8, 1515: 8, 1520: 8, 1600: 8, 1601: 8, 1603: 8, 1605: 8, 1624: 8, 1626: 8, 1629: 8, 1631: 8, 1646: 8, 1648: 8, 1712: 6, 1714: 8, 1716: 8, 1717: 8, 1719: 8, 1720: 8, 1721: 8 + }], CAR.SKODA_KODIAQ_MK1: [{ 64: 8, 134: 8, 159: 8, 173: 8, 178: 8, 253: 8, 257: 8, 260: 8, 262: 8, 278: 8, 279: 8, 283: 8, 286: 8, 288: 8, 289: 8, 290: 8, 294: 8, 299: 8, 302: 8, 346: 8, 385: 8, 418: 8, 427: 8, 573: 8, 668: 8, 679: 8, 681: 8, 684: 8, 695: 8, 779: 8, 780: 8, 783: 8, 787: 8, 788: 8, 789: 8, 792: 8, 795: 8, 802: 8, 804: 8, 806: 8, 807: 8, 808: 8, 809: 8, 828: 8, 870: 8, 896: 8, 897: 8, 898: 8, 901: 8, 917: 8, 919: 8, 949: 8, 958: 8, 960: 4, 981: 8, 987: 8, 988: 8, 991: 8, 997: 8, 1000: 8, 1019: 8, 1120: 8, 1153: 8, 1162: 8, 1175: 8, 1312: 8, 1385: 8, 1413: 8, 1440: 5, 1514: 8, 1515: 8, 1520: 8, 1529: 8, 1600: 8, 1601: 8, 1603: 8, 1605: 8, 1624: 8, 1626: 8, 1629: 8, 1631: 8, 1646: 8, 1648: 8, 1712: 6, 1714: 8, 1716: 8, 1717: 8, 1719: 8, 1720: 8, 1721: 8, 1792: 8, 1871: 8, 1872: 8, 1879: 8, 1909: 8, 1976: 8, 1977: 8, 1985: 8 }], } -IGNORED_FINGERPRINTS = [CAR.JETTA_MK7, CAR.TIGUAN_MK2, CAR.SKODA_KODIAQ_MK1] +IGNORED_FINGERPRINTS = [CAR.JETTA_MK7, CAR.TIGUAN_MK2, CAR.SEAT_ATECA_MK1, CAR.SKODA_KODIAQ_MK1] FW_VERSIONS = { CAR.AUDI_A3: { @@ -161,6 +165,23 @@ FW_VERSIONS = { b'\xf1\x872Q0907572R \xf1\x890372', ], }, + CAR.SEAT_ATECA_MK1: { + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x8704E906027KA\xf1\x893749', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x870D9300014S \xf1\x895202', + ], + (Ecu.srs, 0x715, None): [ + b'\xf1\x873Q0959655BH\xf1\x890703\xf1\x82\0161212001211001305121211052900', + ], + (Ecu.eps, 0x712, None): [ + b'\xf1\x873Q0909144L \xf1\x895081\xf1\x82\00571N60511A1', + ], + (Ecu.fwdRadar, 0x757, None): [ + b'\xf1\x872Q0907572M \xf1\x890233', + ], + }, CAR.SKODA_KODIAQ_MK1: { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8704E906027DD\xf1\x893123', @@ -188,5 +209,6 @@ DBC = { CAR.JETTA_MK7: dbc_dict('vw_mqb_2010', None), CAR.TIGUAN_MK2: dbc_dict('vw_mqb_2010', None), CAR.AUDI_A3: dbc_dict('vw_mqb_2010', None), + CAR.SEAT_ATECA_MK1: dbc_dict('vw_mqb_2010', None), CAR.SKODA_KODIAQ_MK1: dbc_dict('vw_mqb_2010', None), } diff --git a/selfdrive/test/test_car_models.py b/selfdrive/test/test_car_models.py index 5188371407..41aba7c668 100755 --- a/selfdrive/test/test_car_models.py +++ b/selfdrive/test/test_car_models.py @@ -453,6 +453,10 @@ routes = { 'carFingerprint': VOLKSWAGEN.AUDI_A3, 'enableCamera': True, }, + "8f205bdd11bcbb65|2021-03-26--01-00-17": { + 'carFingerprint': VOLKSWAGEN.SEAT_ATECA_MK1, + 'enableCamera': True, + }, "90434ff5d7c8d603|2021-03-15--12-07-31": { 'carFingerprint': VOLKSWAGEN.SKODA_KODIAQ_MK1, 'enableCamera': True, From 9ef0eee6b1a8f48f0fc4ccd8dea50a23ceab8046 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Fri, 26 Mar 2021 10:02:29 -0400 Subject: [PATCH 11/18] Add 2020 Skoda Scala (#20494) Co-authored-by: Willem Melching --- README.md | 1 + selfdrive/car/volkswagen/interface.py | 5 +++++ selfdrive/car/volkswagen/values.py | 24 +++++++++++++++++++++++- selfdrive/test/test_car_models.py | 4 ++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5edf3e833e..e846bf74c7 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,7 @@ Community Maintained Cars and Features | Nissan | X-Trail 2017 | ProPILOT | Stock | 0mph | 0mph | | SEAT | Ateca 2018 | Driver Assistance | Stock | 0mph | 0mph | | Škoda | Kodiaq 2018 | Driver Assistance | Stock | 0mph | 0mph | +| Škoda | Scala 2020 | Driver Assistance | Stock | 0mph | 0mph | | Subaru | Ascent 2019 | EyeSight | Stock | 0mph | 0mph | | Subaru | Crosstrek 2018-19 | EyeSight | Stock | 0mph | 0mph | | Subaru | Forester 2019-20 | EyeSight | Stock | 0mph | 0mph | diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 0bf04dd298..cae48fc614 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -82,6 +82,11 @@ class CarInterface(CarInterfaceBase): ret.mass = 1569 + STD_CARGO_KG ret.wheelbase = 2.79 + elif candidate == CAR.SKODA_SCALA_MK1: + # Averages of all NW Scala variants + ret.mass = 1192 + STD_CARGO_KG + ret.wheelbase = 2.65 + ret.centerToFront = ret.wheelbase * 0.45 ret.enableCamera = True # Stock camera detection doesn't apply to VW diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index ab7825ff76..8b6820d26d 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -60,6 +60,7 @@ class CAR: TIGUAN_MK2 = "VOLKSWAGEN TIGUAN 2ND GEN" # Chassis AD/BW, Mk2 VW Tiguan and variants SEAT_ATECA_MK1 = "SEAT ATECA 1ST GEN" # Chassis 5F, Mk1 SEAT Ateca and CUPRA Ateca SKODA_KODIAQ_MK1 = "SKODA KODIAQ 1ST GEN" # Chassis NS, Mk1 Skoda Kodiaq + SKODA_SCALA_MK1 = "SKODA SCALA 1ST GEN" # Chassis NW, Mk1 Skoda Scala and Skoda Kamiq AUDI_A3 = "AUDI A3" # Chassis 8V/FF, Mk3 Audi A3 and variants FINGERPRINTS = { @@ -81,9 +82,12 @@ FINGERPRINTS = { CAR.SKODA_KODIAQ_MK1: [{ 64: 8, 134: 8, 159: 8, 173: 8, 178: 8, 253: 8, 257: 8, 260: 8, 262: 8, 278: 8, 279: 8, 283: 8, 286: 8, 288: 8, 289: 8, 290: 8, 294: 8, 299: 8, 302: 8, 346: 8, 385: 8, 418: 8, 427: 8, 573: 8, 668: 8, 679: 8, 681: 8, 684: 8, 695: 8, 779: 8, 780: 8, 783: 8, 787: 8, 788: 8, 789: 8, 792: 8, 795: 8, 802: 8, 804: 8, 806: 8, 807: 8, 808: 8, 809: 8, 828: 8, 870: 8, 896: 8, 897: 8, 898: 8, 901: 8, 917: 8, 919: 8, 949: 8, 958: 8, 960: 4, 981: 8, 987: 8, 988: 8, 991: 8, 997: 8, 1000: 8, 1019: 8, 1120: 8, 1153: 8, 1162: 8, 1175: 8, 1312: 8, 1385: 8, 1413: 8, 1440: 5, 1514: 8, 1515: 8, 1520: 8, 1529: 8, 1600: 8, 1601: 8, 1603: 8, 1605: 8, 1624: 8, 1626: 8, 1629: 8, 1631: 8, 1646: 8, 1648: 8, 1712: 6, 1714: 8, 1716: 8, 1717: 8, 1719: 8, 1720: 8, 1721: 8, 1792: 8, 1871: 8, 1872: 8, 1879: 8, 1909: 8, 1976: 8, 1977: 8, 1985: 8 }], + CAR.SKODA_SCALA_MK1: [{ + 64: 8, 134: 8, 159: 8, 173: 8, 178: 8, 253: 8, 257: 8, 262: 8, 278: 8, 279: 8, 283: 8, 286: 8, 288: 8, 289: 8, 290: 8, 294: 8, 299: 8, 302: 8, 346: 8, 418: 8, 427: 8, 506: 8, 568: 8, 569: 8, 572: 8, 573: 8, 679: 8, 681: 8, 684: 8, 695: 8, 779: 8, 780: 8, 783: 8, 787: 8, 788: 8, 789: 8, 792: 8, 795: 8, 804: 8, 806: 8, 807: 8, 808: 8, 809: 8, 826: 8, 827: 8, 828: 8, 870: 8, 879: 8, 884: 8, 888: 8, 891: 8, 901: 8, 913: 8, 917: 8, 919: 8, 949: 8, 958: 8, 960: 4, 981: 8, 987: 8, 988: 8, 991: 8, 997: 8, 1000: 8, 1019: 8, 1122: 8, 1123: 8, 1124: 8, 1153: 8, 1156: 8, 1157: 8, 1158: 8, 1162: 8, 1175: 8, 1312: 8, 1343: 8, 1385: 8, 1413: 8, 1440: 5, 1514: 8, 1515: 8, 1520: 8, 1600: 8, 1601: 8, 1603: 8, 1605: 8, 1624: 8, 1626: 8, 1629: 8, 1631: 8, 1635: 8, 1646: 8, 1648: 8, 1712: 6, 1714: 8, 1716: 8, 1717: 8, 1719: 8, 1720: 8, 1721: 8, 1792: 8, 1872: 8, 1879: 8, 1976: 8, 1977: 8, 1982: 8, 1985: 8 + }], } -IGNORED_FINGERPRINTS = [CAR.JETTA_MK7, CAR.TIGUAN_MK2, CAR.SEAT_ATECA_MK1, CAR.SKODA_KODIAQ_MK1] +IGNORED_FINGERPRINTS = [CAR.JETTA_MK7, CAR.TIGUAN_MK2, CAR.SEAT_ATECA_MK1, CAR.SKODA_KODIAQ_MK1, CAR.SKODA_SCALA_MK1] FW_VERSIONS = { CAR.AUDI_A3: { @@ -202,6 +206,23 @@ FW_VERSIONS = { b'\xf1\x872Q0907572R \xf1\x890372', ], }, + CAR.SKODA_SCALA_MK1: { + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x8704C906025AK\xf1\x897053', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x870CW300050 \xf1\x891709', + ], + (Ecu.srs, 0x715, None): [ + b'\xf1\x872Q0959655AM\xf1\x890351\xf1\x82\022111104111104112104040404111111112H14', + ], + (Ecu.eps, 0x712, None): [ + b'\xf1\x872Q1909144M \xf1\x896041', + ], + (Ecu.fwdRadar, 0x757, None): [ + b'\xf1\x872Q0907572R \xf1\x890372', + ], + }, } DBC = { @@ -211,4 +232,5 @@ DBC = { CAR.AUDI_A3: dbc_dict('vw_mqb_2010', None), CAR.SEAT_ATECA_MK1: dbc_dict('vw_mqb_2010', None), CAR.SKODA_KODIAQ_MK1: dbc_dict('vw_mqb_2010', None), + CAR.SKODA_SCALA_MK1: dbc_dict('vw_mqb_2010', None), } diff --git a/selfdrive/test/test_car_models.py b/selfdrive/test/test_car_models.py index 41aba7c668..a6e7f1b3ac 100755 --- a/selfdrive/test/test_car_models.py +++ b/selfdrive/test/test_car_models.py @@ -461,6 +461,10 @@ routes = { 'carFingerprint': VOLKSWAGEN.SKODA_KODIAQ_MK1, 'enableCamera': True, }, + "026b6d18fba6417f|2021-03-26--09-17-04": { + 'carFingerprint': VOLKSWAGEN.SKODA_SCALA_MK1, + 'enableCamera': True, + }, "3c8f0c502e119c1c|2020-06-30--12-58-02": { 'carFingerprint': SUBARU.ASCENT, 'enableCamera': True, From 5da6fced2b87c0737570ffc8408418753fea00c6 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Fri, 26 Mar 2021 10:03:41 -0400 Subject: [PATCH 12/18] VW MQB: Volkswagen Passat Mk8 (#20493) * Add VW Passat * Add Passat legacy FP Co-authored-by: Willem Melching --- README.md | 2 ++ selfdrive/car/volkswagen/interface.py | 5 +++++ selfdrive/car/volkswagen/values.py | 29 ++++++++++++++++++++++++++- selfdrive/test/test_car_models.py | 4 ++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e846bf74c7..cd55603070 100644 --- a/README.md +++ b/README.md @@ -177,10 +177,12 @@ Community Maintained Cars and Features | Subaru | Forester 2019-20 | EyeSight | Stock | 0mph | 0mph | | Subaru | Impreza 2017-19 | EyeSight | Stock | 0mph | 0mph | | Volkswagen| Jetta 2018-21 | Driver Assistance | Stock | 0mph | 0mph | +| Volkswagen| Passat 2016-172 | Driver Assistance | Stock | 0mph | 0mph | | Volkswagen| Golf 2015-19 | Driver Assistance | Stock | 0mph | 0mph | | Volkswagen| Tiguan 2020 | Driver Assistance | Stock | 0mph | 0mph | 1Requires an [OBD-II car harness](https://comma.ai/shop/products/comma-car-harness) and [community built ASCM harness](https://github.com/commaai/openpilot/wiki/GM#hardware). ***NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).***
+2Only includes the MQB Passat sold outside of North America. The NMS Passat made in Chattanooga TN is not yet supported. Although it's not upstream, there's a community of people getting openpilot to run on Tesla's [here](https://tinkla.us/) diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index cae48fc614..e37780fa79 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -67,6 +67,11 @@ class CarInterface(CarInterfaceBase): ret.mass = 1328 + STD_CARGO_KG ret.wheelbase = 2.71 + elif candidate == CAR.PASSAT_MK8: + # Averages of all 3C Passat variants + ret.mass = 1551 + STD_CARGO_KG + ret.wheelbase = 2.79 + elif candidate == CAR.TIGUAN_MK2: # Average of SWB and LWB variants ret.mass = 1715 + STD_CARGO_KG diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 8b6820d26d..7605c28223 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -57,6 +57,7 @@ MQB_LDW_MESSAGES = { class CAR: GOLF = "VOLKSWAGEN GOLF" # Chassis 5G/AU/BA/BE, Mk7 VW Golf and variants JETTA_MK7 = "VOLKSWAGEN JETTA 7TH GEN" # Chassis BU, Mk7 Jetta + PASSAT_MK8 = "VOLKSWAGEN PASSAT 8TH GEN" # Chassis 3G, Mk8 Passat and variants TIGUAN_MK2 = "VOLKSWAGEN TIGUAN 2ND GEN" # Chassis AD/BW, Mk2 VW Tiguan and variants SEAT_ATECA_MK1 = "SEAT ATECA 1ST GEN" # Chassis 5F, Mk1 SEAT Ateca and CUPRA Ateca SKODA_KODIAQ_MK1 = "SKODA KODIAQ 1ST GEN" # Chassis NS, Mk1 Skoda Kodiaq @@ -70,6 +71,9 @@ FINGERPRINTS = { CAR.JETTA_MK7: [{ 64: 8, 134: 8, 159: 8, 173: 8, 178: 8, 253: 8, 257: 8, 260: 8, 262: 8, 264: 8, 278: 8, 279: 8, 283: 8, 286: 8, 288: 8, 289: 8, 290: 8, 294: 8, 299: 8, 302: 8, 346: 8, 376: 8, 418: 8, 427: 8, 679: 8, 681: 8, 695: 8, 779: 8, 780: 8, 783: 8, 792: 8, 795: 8, 804: 8, 806: 8, 807: 8, 808: 8, 809: 8, 828: 8, 870: 8, 879: 8, 884: 8, 888: 8, 891: 8, 901: 8, 913: 8, 919: 8, 949: 8, 958: 8, 960: 4, 981: 8, 987: 8, 988: 8, 991: 8, 997: 8, 1000: 8, 1019: 8, 1122: 8, 1123: 8, 1124: 8, 1153: 8, 1156: 8, 1157: 8, 1158: 8, 1162: 8, 1312: 8, 1343: 8, 1385: 8, 1413: 8, 1440: 5, 1471: 4, 1514: 8, 1515: 8, 1520: 8, 1600: 8, 1601: 8, 1603: 8, 1605: 8, 1624: 8, 1626: 8, 1629: 8, 1631: 8, 1635: 8, 1646: 8, 1648: 8, 1712: 6, 1714: 8, 1716: 8, 1717: 8, 1719: 8, 1720: 8 }], + CAR.PASSAT_MK8: [{ + 64: 8, 134: 8, 159: 8, 173: 8, 178: 8, 253: 8, 257: 8, 260: 8, 262: 8, 264: 8, 278: 8, 279: 8, 283: 8, 286: 8, 288: 8, 289: 8, 290: 8, 294: 8, 295: 8, 299: 8, 302: 8, 346: 8, 385: 8, 391: 8, 427: 8, 668: 8, 679: 8, 681: 8, 695: 8, 779: 8, 780: 8, 783: 8, 787: 8, 788: 8, 789: 8, 791: 8, 792: 8, 799: 8, 802: 8, 804: 8, 806: 8, 807: 8, 808: 8, 809: 8, 828: 8, 838: 8, 839: 8, 840: 8, 841: 8, 842: 8, 843: 8, 844: 8, 845: 8, 870: 8, 896: 8, 897: 8, 898: 8, 901: 8, 917: 8, 919: 8, 927: 8, 949: 8, 958: 8, 960: 4, 981: 8, 987: 8, 988: 8, 991: 8, 997: 8, 1000: 8, 1019: 8, 1120: 8, 1122: 8, 1123: 8, 1124: 8, 1153: 8, 1162: 8, 1175: 8, 1312: 8, 1385: 8, 1413: 8, 1438: 8, 1440: 5, 1461: 8, 1514: 8, 1515: 8, 1520: 8, 1529: 8, 1600: 8, 1601: 8, 1603: 8, 1624: 8, 1629: 8, 1631: 8, 1646: 8, 1648: 8, 1712: 6, 1714: 8, 1716: 8, 1717: 8, 1719: 8, 1720: 8, 1721: 8 + }], CAR.TIGUAN_MK2: [{ 64: 8, 134: 8, 159: 8, 173: 8, 178: 8, 253: 8, 257: 8, 260: 8, 262: 8, 278: 8, 279: 8, 283: 8, 286: 8, 288: 8, 289: 8, 290: 8, 294: 8, 299: 8, 302: 8, 346: 8, 376: 8, 418: 8, 427: 8, 573: 8, 679: 8, 681: 8, 684: 8, 695: 8, 779: 8, 780: 8, 783: 8, 787: 8, 788: 8, 789: 8, 792: 8, 795: 8, 804: 8, 806: 8, 807: 8, 808: 8, 809: 8, 828: 8, 870: 8, 879: 8, 884: 8, 888: 8, 891: 8, 896: 8, 897: 8, 898: 8, 901: 8, 913: 8, 917: 8, 919: 8, 949: 8, 958: 8, 960: 4, 981: 8, 987: 8, 988: 8, 991: 8, 997: 8, 1000: 8, 1019: 8, 1122: 8, 1123: 8, 1124: 8, 1153: 8, 1156: 8, 1157: 8, 1158: 8, 1162: 8, 1175: 8, 1312: 8, 1343: 8, 1385: 8, 1413: 8, 1440: 5, 1471: 4, 1514: 8, 1515: 8, 1520: 8, 1600: 8, 1601: 8, 1603: 8, 1605: 8, 1624: 8, 1626: 8, 1629: 8, 1631: 8, 1635: 8, 1646: 8, 1648: 8, 1712: 6, 1714: 8, 1716: 8, 1717: 8, 1719: 8, 1720: 8, 1721: 8 }], @@ -87,7 +91,7 @@ FINGERPRINTS = { }], } -IGNORED_FINGERPRINTS = [CAR.JETTA_MK7, CAR.TIGUAN_MK2, CAR.SEAT_ATECA_MK1, CAR.SKODA_KODIAQ_MK1, CAR.SKODA_SCALA_MK1] +IGNORED_FINGERPRINTS = [CAR.JETTA_MK7, CAR.PASSAT_MK8, CAR.TIGUAN_MK2, CAR.SEAT_ATECA_MK1, CAR.SKODA_KODIAQ_MK1, CAR.SKODA_SCALA_MK1] FW_VERSIONS = { CAR.AUDI_A3: { @@ -152,6 +156,28 @@ FW_VERSIONS = { b'\xf1\x875Q0907572R \xf1\x890771', ], }, + CAR.PASSAT_MK8: { + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x8704E906023AH\xf1\x893379', + b'\xf1\x8704L906026GA\xf1\x892013', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x870DD300045T \xf1\x891601', + b'\xf1\x870D9300014L \xf1\x895002', + ], + (Ecu.srs, 0x715, None): [ + b'\xf1\x875Q0959655S \xf1\x890870\xf1\x82\02315120011111200631145171716121691132111', + b'\xf1\x873Q0959655AN\xf1\x890306\xf1\x82\r58160058140013036914110311', + ], + (Ecu.eps, 0x712, None): [ + b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522B0080803', + b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\00521B00703A1', + ], + (Ecu.fwdRadar, 0x757, None): [ + b'\xf1\x875Q0907572R \xf1\x890771', + b'\xf1\x873Q0907572C \xf1\x890195', + ], + }, CAR.TIGUAN_MK2: { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8783A907115B \xf1\x890005', @@ -228,6 +254,7 @@ FW_VERSIONS = { DBC = { CAR.GOLF: dbc_dict('vw_mqb_2010', None), CAR.JETTA_MK7: dbc_dict('vw_mqb_2010', None), + CAR.PASSAT_MK8: dbc_dict('vw_mqb_2010', None), CAR.TIGUAN_MK2: dbc_dict('vw_mqb_2010', None), CAR.AUDI_A3: dbc_dict('vw_mqb_2010', None), CAR.SEAT_ATECA_MK1: dbc_dict('vw_mqb_2010', None), diff --git a/selfdrive/test/test_car_models.py b/selfdrive/test/test_car_models.py index a6e7f1b3ac..1692c301a9 100755 --- a/selfdrive/test/test_car_models.py +++ b/selfdrive/test/test_car_models.py @@ -445,6 +445,10 @@ routes = { 'carFingerprint': VOLKSWAGEN.JETTA_MK7, 'enableCamera': True, }, + "4d134e099430fba2|2021-03-26--00-26-06": { + 'carFingerprint': VOLKSWAGEN.PASSAT_MK8, + 'enableCamera': True, + }, "2cef8a0b898f331a|2021-03-25--20-13-57": { 'carFingerprint': VOLKSWAGEN.TIGUAN_MK2, 'enableCamera': True, From c0e3e2ba1b7c606395f0e892762ee4953f188c26 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 26 Mar 2021 17:04:30 +0100 Subject: [PATCH 13/18] add debug script to run paramsd on route --- .../debug/internal/run_paramsd_on_route.py | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100755 selfdrive/debug/internal/run_paramsd_on_route.py diff --git a/selfdrive/debug/internal/run_paramsd_on_route.py b/selfdrive/debug/internal/run_paramsd_on_route.py new file mode 100755 index 0000000000..1e633bdce1 --- /dev/null +++ b/selfdrive/debug/internal/run_paramsd_on_route.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +# pylint: skip-file +# flake8: noqa +# type: ignore + +import math +import multiprocessing + +import numpy as np +from tqdm import tqdm + +from selfdrive.locationd.paramsd import ParamsLearner, States +from tools.lib.logreader import LogReader +from tools.lib.route import Route + +ROUTE = "b2f1615665781088|2021-03-14--17-27-47" +PLOT = True + + +def load_segment(segment_name): + print(f"Loading {segment_name}") + if segment_name is None: + return [] + + try: + return list(LogReader(segment_name)) + except ValueError as e: + print(f"Error parsing {segment_name}: {e}") + return [] + + +if __name__ == "__main__": + route = Route(ROUTE) + + msgs = [] + with multiprocessing.Pool(24) as pool: + for d in pool.map(load_segment, route.log_paths()): + msgs += d + + for m in msgs: + if m.which() == 'carParams': + CP = m.carParams + break + + params = { + 'carFingerprint': CP.carFingerprint, + 'steerRatio': CP.steerRatio, + 'stiffnessFactor': 1.0, + 'angleOffsetAverageDeg': 0.0, + } + + for m in msgs: + if m.which() == 'liveParameters': + params['steerRatio'] = m.liveParameters.steerRatio + params['angleOffsetAverageDeg'] = m.liveParameters.angleOffsetAverageDeg + break + + for m in msgs: + if m.which() == 'carState': + last_carstate = m + break + + print(params) + learner = ParamsLearner(CP, params['steerRatio'], params['stiffnessFactor'], math.radians(params['angleOffsetAverageDeg'])) + msgs = [m for m in tqdm(msgs) if m.which() in ('liveLocationKalman', 'carState', 'liveParameters')] + + ts = [] + ts_log = [] + results = [] + results_log = [] + for m in tqdm(msgs): + if m.which() == 'carState': + last_carstate = m + + elif m.which() == 'liveLocationKalman': + t = last_carstate.logMonoTime / 1e9 + learner.handle_log(t, 'carState', last_carstate.carState) + + t = m.logMonoTime / 1e9 + learner.handle_log(t, 'liveLocationKalman', m.liveLocationKalman) + + x = learner.kf.x + sr = float(x[States.STEER_RATIO]) + st = float(x[States.STIFFNESS]) + ao_avg = math.degrees(x[States.ANGLE_OFFSET]) + ao = ao_avg + math.degrees(x[States.ANGLE_OFFSET_FAST]) + r = [sr, st, ao_avg, ao] + if any(math.isnan(v) for v in r): + print("NaN", t) + + ts.append(t) + results.append(r) + + elif m.which() == 'liveParameters': + t = m.logMonoTime / 1e9 + mm = m.liveParameters + + r = [mm.steerRatio, mm.stiffnessFactor, mm.angleOffsetAverageDeg, mm.angleOffsetDeg] + if any(math.isnan(v) for v in r): + print("NaN in log", t) + ts_log.append(t) + results_log.append(r) + + results = np.asarray(results) + results_log = np.asarray(results_log) + + if PLOT: + import matplotlib.pyplot as plt + plt.figure() + + plt.subplot(3, 2, 1) + plt.plot(ts, results[:, 0], label='Steer Ratio') + plt.grid() + plt.ylim([0, 20]) + plt.legend() + + plt.subplot(3, 2, 3) + plt.plot(ts, results[:, 1], label='Stiffness') + plt.ylim([0, 2]) + plt.grid() + plt.legend() + + plt.subplot(3, 2, 5) + plt.plot(ts, results[:, 2], label='Angle offset (average)') + plt.plot(ts, results[:, 3], label='Angle offset (instant)') + plt.ylim([-5, 5]) + plt.grid() + plt.legend() + + plt.subplot(3, 2, 2) + plt.plot(ts_log, results_log[:, 0], label='Steer Ratio') + plt.grid() + plt.ylim([0, 20]) + plt.legend() + + plt.subplot(3, 2, 4) + plt.plot(ts_log, results_log[:, 1], label='Stiffness') + plt.ylim([0, 2]) + plt.grid() + plt.legend() + + plt.subplot(3, 2, 6) + plt.plot(ts_log, results_log[:, 2], label='Angle offset (average)') + plt.plot(ts_log, results_log[:, 3], label='Angle offset (instant)') + plt.ylim([-5, 5]) + plt.grid() + plt.legend() + plt.show() + From 2b2d868c862bf18a0977ada70961ca636822021f Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 26 Mar 2021 17:07:33 +0100 Subject: [PATCH 14/18] temporarily increase ui cpu allowance --- selfdrive/test/test_onroad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index adb44c35ef..94fcab538d 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -18,7 +18,7 @@ PROCS = [ ("./loggerd", 45.0), ("selfdrive.locationd.locationd", 35.0), ("selfdrive.controls.plannerd", 20.0), - ("./_ui", 15.0), + ("./_ui", 30.0), # TODO put back to 15% after fixing cpu usage playing sounds ("selfdrive.locationd.paramsd", 12.0), ("./camerad", 7.07), ("./_sensord", 6.17), From da5f0c5332af939c8bb5ac7e947babdcd9e7863e Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 26 Mar 2021 17:15:55 +0100 Subject: [PATCH 15/18] run paramsd: sort messages --- selfdrive/debug/internal/run_paramsd_on_route.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/debug/internal/run_paramsd_on_route.py b/selfdrive/debug/internal/run_paramsd_on_route.py index 1e633bdce1..54519e3777 100755 --- a/selfdrive/debug/internal/run_paramsd_on_route.py +++ b/selfdrive/debug/internal/run_paramsd_on_route.py @@ -63,6 +63,7 @@ if __name__ == "__main__": print(params) learner = ParamsLearner(CP, params['steerRatio'], params['stiffnessFactor'], math.radians(params['angleOffsetAverageDeg'])) msgs = [m for m in tqdm(msgs) if m.which() in ('liveLocationKalman', 'carState', 'liveParameters')] + msgs = sorted(msgs, key=lambda m: m.logMonoTime) ts = [] ts_log = [] From d2dc38839ef18e6cd66f5e32d1517fe2adac68d9 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 26 Mar 2021 17:21:10 +0100 Subject: [PATCH 16/18] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 4906dc7b22..f146aa367b 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 4906dc7b220c672fc61119354f4bbc89fccf07df +Subproject commit f146aa367b82f041b4eadcaab0bb2fc79e388b94 From 6e57fb3767ca8a0f5eca5685d83d4e15fbca6efe Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 26 Mar 2021 17:29:53 +0100 Subject: [PATCH 17/18] Revert "temporarily increase ui cpu allowance" This reverts commit 2b2d868c862bf18a0977ada70961ca636822021f. --- selfdrive/test/test_onroad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 94fcab538d..adb44c35ef 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -18,7 +18,7 @@ PROCS = [ ("./loggerd", 45.0), ("selfdrive.locationd.locationd", 35.0), ("selfdrive.controls.plannerd", 20.0), - ("./_ui", 30.0), # TODO put back to 15% after fixing cpu usage playing sounds + ("./_ui", 15.0), ("selfdrive.locationd.paramsd", 12.0), ("./camerad", 7.07), ("./_sensord", 6.17), From 97133a8facf848d5fc709a0ab98ab2c26690ee19 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Fri, 26 Mar 2021 13:23:18 -0700 Subject: [PATCH 18/18] camerad jenkins box test (#20413) * separate test * send * update test * snapshot is rgb * this does not belong here * clean up * tici * no if * no black frames * flaky leds * rename and cleanup * should be stable and avoid lucky pass * print * logical and * run in jenkins * source profile on tici Co-authored-by: Comma Device Co-authored-by: Adeeb Shihadeh --- Jenkinsfile | 25 ++++++++- selfdrive/camerad/test/test_camerad.py | 66 ------------------------ selfdrive/camerad/test/test_exposure.py | 68 +++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 68 deletions(-) create mode 100755 selfdrive/camerad/test/test_exposure.py diff --git a/Jenkinsfile b/Jenkinsfile index 3ededf4506..78a3a0fa63 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -11,6 +11,9 @@ export GIT_BRANCH=${env.GIT_BRANCH} export GIT_COMMIT=${env.GIT_COMMIT} source ~/.bash_profile +if [ -f /TICI ]; then + source /etc/profile +fi ln -snf ${env.TEST_DIR} /data/pythonpath @@ -151,7 +154,6 @@ pipeline { ["test boardd loopback", "nosetests -s selfdrive/boardd/tests/test_boardd_loopback.py"], ["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"], ["test encoder", "python selfdrive/loggerd/tests/test_encoder.py"], - ["test camerad", "python selfdrive/camerad/test/test_camerad.py"], ["test logcatd", "python selfdrive/logcatd/tests/test_logcatd_android.py"], //["test updater", "python installer/updater/test_updater.py"], ]) @@ -167,12 +169,31 @@ pipeline { ["build", "SCONS_CACHE=1 scons -j16"], ["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"], - ["test camerad", "python selfdrive/camerad/test/test_camerad.py"], //["build release3-staging", "cd release && PUSH=${env.R3_PUSH} ./build_release3.sh"], ]) } } + stage('camerad') { + steps { + phone_steps("eon-party", [ + ["build", "SCONS_CACHE=1 scons -j16"], + ["test camerad", "python selfdrive/camerad/test/test_camerad.py"], + ["test exposure", "python selfdrive/camerad/test/test_exposure.py"], + ]) + } + } + + stage('Tici camerad') { + steps { + phone_steps("tici-party", [ + ["build", "SCONS_CACHE=1 scons -j16"], + ["test camerad", "python selfdrive/camerad/test/test_camerad.py"], + ["test exposure", "python selfdrive/camerad/test/test_exposure.py"], + ]) + } + } + } } } diff --git a/selfdrive/camerad/test/test_camerad.py b/selfdrive/camerad/test/test_camerad.py index e2333b3839..11e070f328 100755 --- a/selfdrive/camerad/test/test_camerad.py +++ b/selfdrive/camerad/test/test_camerad.py @@ -2,11 +2,9 @@ import time import unittest -import numpy as np import cereal.messaging as messaging from selfdrive.test.helpers import with_processes -from selfdrive.camerad.snapshot.snapshot import get_snapshots # only tests for EON and TICI from selfdrive.hardware import EON, TICI @@ -31,70 +29,6 @@ class TestCamerad(unittest.TestCase): if not (EON or TICI): raise unittest.SkipTest - # assert "SEND_REAR" in os.environ - # assert "SEND_FRONT" in os.environ - - def _numpy_bgr2gray(self, im): - ret = np.clip(im[:,:,0] * 0.114 + im[:,:,1] * 0.587 + im[:,:,2] * 0.299, 0, 255).astype(np.uint8) - return ret - - def _numpy_lap(self, im): - ret = np.zeros(im.shape) - ret += -4 * im - ret += np.concatenate([np.zeros((im.shape[0],1)),im[:,:-1]], axis=1) - ret += np.concatenate([im[:,1:],np.zeros((im.shape[0],1))], axis=1) - ret += np.concatenate([np.zeros((1,im.shape[1])),im[:-1,:]], axis=0) - ret += np.concatenate([im[1:,:],np.zeros((1,im.shape[1]))], axis=0) - ret = np.clip(ret, 0, 255).astype(np.uint8) - return ret - - def _is_really_sharp(self, i, threshold=800, roi_max=np.array([8,6]), roi_xxyy=np.array([1,6,2,3])): - i = self._numpy_bgr2gray(i) - x_pitch = i.shape[1] // roi_max[0] - y_pitch = i.shape[0] // roi_max[1] - lap = self._numpy_lap(i) - lap_map = np.zeros((roi_max[1], roi_max[0])) - for r in range(lap_map.shape[0]): - for c in range(lap_map.shape[1]): - selected_lap = lap[r*y_pitch:(r+1)*y_pitch, c*x_pitch:(c+1)*x_pitch] - lap_map[r][c] = 5*selected_lap.var() + selected_lap.max() - print(lap_map[roi_xxyy[2]:roi_xxyy[3]+1,roi_xxyy[0]:roi_xxyy[1]+1]) - if (lap_map[roi_xxyy[2]:roi_xxyy[3]+1,roi_xxyy[0]:roi_xxyy[1]+1] > threshold).sum() > \ - (roi_xxyy[1]+1-roi_xxyy[0]) * (roi_xxyy[3]+1-roi_xxyy[2]) * 0.9: - return True - else: - return False - - def _is_exposure_okay(self, i, med_ex=np.array([0.2,0.4]), mean_ex=np.array([0.2,0.6])): - i = self._numpy_bgr2gray(i) - i_median = np.median(i) / 256 - i_mean = np.mean(i) / 256 - print([i_median, i_mean]) - return med_ex[0] < i_median < med_ex[1] and mean_ex[0] < i_mean < mean_ex[1] - - @unittest.skip # skip for now - @with_processes(['camerad']) - def test_camera_operation(self): - print("checking image outputs") - if EON: - # run checks similar to prov - time.sleep(15) # wait for startup and AF - pic, fpic = get_snapshots() - self.assertTrue(self._is_really_sharp(pic)) - self.assertTrue(self._is_exposure_okay(pic)) - self.assertTrue(self._is_exposure_okay(fpic)) - - time.sleep(30) - # check again for consistency - pic, fpic = get_snapshots() - self.assertTrue(self._is_really_sharp(pic)) - self.assertTrue(self._is_exposure_okay(pic)) - self.assertTrue(self._is_exposure_okay(fpic)) - elif TICI: - raise unittest.SkipTest # TBD - else: - raise unittest.SkipTest - @with_processes(['camerad']) def test_frame_packets(self): print("checking frame pkts continuity") diff --git a/selfdrive/camerad/test/test_exposure.py b/selfdrive/camerad/test/test_exposure.py new file mode 100755 index 0000000000..0b5b5ace88 --- /dev/null +++ b/selfdrive/camerad/test/test_exposure.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +import time +import unittest +import os +import numpy as np + +from selfdrive.test.helpers import with_processes +from selfdrive.camerad.snapshot.snapshot import get_snapshots + +from selfdrive.hardware import EON, TICI + +TEST_TIME = 45 +REPEAT = 5 + +os.environ["SEND_ROAD"] = "1" +os.environ["SEND_DRIVER"] = "1" +if TICI: + os.environ["SEND_WIDE_ROAD"] = "1" + +class TestCamerad(unittest.TestCase): + @classmethod + def setUpClass(cls): + if not (EON or TICI): + raise unittest.SkipTest + + def _numpy_rgb2gray(self, im): + ret = np.clip(im[:,:,2] * 0.114 + im[:,:,1] * 0.587 + im[:,:,0] * 0.299, 0, 255).astype(np.uint8) + return ret + + def _is_exposure_okay(self, i, med_mean=np.array([[0.2,0.4],[0.2,0.6]])): + h, w = i.shape[:2] + i = i[h//10:9*h//10,w//10:9*w//10] + med_ex, mean_ex = med_mean + i = self._numpy_rgb2gray(i) + i_median = np.median(i) / 255. + i_mean = np.mean(i) / 255. + print([i_median, i_mean]) + return med_ex[0] < i_median < med_ex[1] and mean_ex[0] < i_mean < mean_ex[1] + + + @with_processes(['camerad']) + def test_camera_operation(self): + print("checking image outputs") + + start = time.time() + passed = 0 + while(time.time() - start < TEST_TIME and passed < REPEAT): + rpic, dpic = get_snapshots(frame="roadCameraState", front_frame="driverCameraState") + + res = self._is_exposure_okay(rpic) + res = res and self._is_exposure_okay(dpic) + + if TICI: + wpic, _ = get_snapshots(frame="wideRoadCameraState") + res = res and self._is_exposure_okay(wpic) + + if passed > 0 and not res: + passed = -passed # fails test if any failure after first sus + break + + passed += int(res) + time.sleep(2) + print(passed) + self.assertTrue(passed >= REPEAT) + +if __name__ == "__main__": + unittest.main()