navd: render map into VisionIPC (#22800)

* navd: render simple map

* render route

* offscreen rendering

* cleanup

* more cleanup

* render into visionIPC

* rename class

* split position update from route update

* stop broadcast if not active

* gate vipc server behind flag

* add python library

* faster

* no vipc from python

* put behind extras

* only send when loaded

* add glFlush just to be sure

* cleanup settings into helper function

* function ordering

* broadcast thumbnails

* put behind param

* adjust zoom level

* add route to python bindings

* revert that freq change

* add logging if map rendering is enabled

* use rlogs if available

* bump cereal
pull/23053/head
Willem Melching 2021-11-26 14:38:02 +01:00 committed by GitHub
parent 21ff97b8c9
commit 5069852573
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 476 additions and 45 deletions

2
cereal

@ -1 +1 @@
Subproject commit 238e0c5793daed7dce6e1e072c4ae510f06ea515
Subproject commit 9b245b60238b54867057c591b9ac2948b81a1794

View File

@ -20,9 +20,13 @@ if __name__ == "__main__":
mkdirs_exists_ok(out_path)
r = Route(args.route)
lr = list(LogReader(r.qlog_paths()[args.segment]))
path = r.log_paths()[args.segment] or r.qlog_paths()[args.segment]
lr = list(LogReader(path))
for msg in tqdm(lr):
if msg.which() == 'thumbnail':
with open(os.path.join(out_path, f"{msg.thumbnail.frameId}.jpg"), 'wb') as f:
f.write(msg.thumbnail.thumbnail)
elif msg.which() == 'navThumbnail':
with open(os.path.join(out_path, f"nav_{msg.navThumbnail.frameId}.jpg"), 'wb') as f:
f.write(msg.navThumbnail.thumbnail)

View File

@ -135,6 +135,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"LiveParameters", PERSISTENT},
{"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
{"NavSettingTime24h", PERSISTENT},
{"NavdRender", PERSISTENT},
{"OpenpilotEnabledToggle", PERSISTENT},
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
{"Passive", PERSISTENT},

View File

@ -126,5 +126,8 @@ if arch in ['x86_64', 'Darwin'] or GetOption('extras'):
# navd
if maps:
navd_src = ["navd/main.cc", "navd/route_engine.cc"]
navd_src = ["navd/main.cc", "navd/route_engine.cc", "navd/map_renderer.cc"]
qt_env.Program("navd/_navd", navd_src, LIBS=qt_libs + ['common', 'json11'])
if GetOption('extras'):
qt_env.SharedLibrary("navd/map_renderer", ["navd/map_renderer.cc"], LIBS=qt_libs + ['common', 'messaging'])

View File

@ -5,9 +5,11 @@
#include <csignal>
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/maps/map_helpers.h"
#include "selfdrive/ui/navd/route_engine.h"
RouteEngine* route_engine = nullptr;
#include "selfdrive/ui/navd/map_renderer.h"
#include "selfdrive/hardware/hw.h"
#include "selfdrive/common/params.h"
void sigHandler(int s) {
qInfo() << "Shutting down";
@ -30,7 +32,14 @@ int main(int argc, char *argv[]) {
parser.process(app);
const QStringList args = parser.positionalArguments();
route_engine = new RouteEngine();
RouteEngine* route_engine = new RouteEngine();
if (Params().getBool("NavdRender")) {
MapRenderer * m = new MapRenderer(get_mapbox_settings());
QObject::connect(route_engine, &RouteEngine::positionUpdated, m, &MapRenderer::updatePosition);
QObject::connect(route_engine, &RouteEngine::routeUpdated, m, &MapRenderer::updateRoute);
}
return app.exec();
}

View File

@ -0,0 +1,200 @@
#include "selfdrive/ui/navd/map_renderer.h"
#include <QApplication>
#include <QBuffer>
#include <QDebug>
#include "selfdrive/ui/qt/maps/map_helpers.h"
#include "selfdrive/common/timing.h"
const float ZOOM = 13.5; // Don't go below 13 or features will start to disappear
const int WIDTH = 256;
const int HEIGHT = WIDTH;
const int NUM_VIPC_BUFFERS = 4;
MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool enable_vipc) : m_settings(settings) {
QSurfaceFormat fmt;
fmt.setRenderableType(QSurfaceFormat::OpenGLES);
ctx = std::make_unique<QOpenGLContext>();
ctx->setFormat(fmt);
ctx->create();
assert(ctx->isValid());
surface = std::make_unique<QOffscreenSurface>();
surface->setFormat(ctx->format());
surface->create();
ctx->makeCurrent(surface.get());
assert(QOpenGLContext::currentContext() == ctx.get());
gl_functions.reset(ctx->functions());
gl_functions->initializeOpenGLFunctions();
QOpenGLFramebufferObjectFormat fbo_format;
fbo.reset(new QOpenGLFramebufferObject(WIDTH, HEIGHT, fbo_format));
m_map.reset(new QMapboxGL(nullptr, m_settings, fbo->size(), 1));
m_map->setCoordinateZoom(QMapbox::Coordinate(0, 0), ZOOM);
m_map->setStyleUrl("mapbox://styles/commaai/ckvmksrpd4n0a14pfdo5heqzr");
m_map->createRenderer();
m_map->resize(fbo->size());
m_map->setFramebufferObject(fbo->handle(), fbo->size());
gl_functions->glViewport(0, 0, WIDTH, HEIGHT);
if (enable_vipc) {
qWarning() << "Enabling navd map rendering";
vipc_server.reset(new VisionIpcServer("navd"));
vipc_server->create_buffers(VisionStreamType::VISION_STREAM_RGB_MAP, NUM_VIPC_BUFFERS, true, WIDTH, HEIGHT);
vipc_server->start_listener();
pm.reset(new PubMaster({"navThumbnail"}));
}
}
void MapRenderer::updatePosition(QMapbox::Coordinate position, float bearing) {
if (m_map.isNull()) {
return;
}
m_map->setCoordinate(position);
m_map->setBearing(bearing);
update();
}
bool MapRenderer::loaded() {
return m_map->isFullyLoaded();
}
void MapRenderer::update() {
gl_functions->glClear(GL_COLOR_BUFFER_BIT);
m_map->render();
gl_functions->glFlush();
sendVipc();
}
void MapRenderer::sendVipc() {
if (!vipc_server || !loaded()) {
return;
}
QImage cap = fbo->toImage().convertToFormat(QImage::Format_RGB888, Qt::AutoColor);
uint64_t ts = nanos_since_boot();
VisionBuf* buf = vipc_server->get_buffer(VisionStreamType::VISION_STREAM_RGB_MAP);
VisionIpcBufExtra extra = {
.frame_id = frame_id,
.timestamp_sof = ts,
.timestamp_eof = ts,
};
assert(cap.sizeInBytes() == buf->len);
memcpy(buf->addr, cap.bits(), buf->len);
vipc_server->send(buf, &extra);
if (frame_id % 100 == 0) {
// Write jpeg into buffer
QByteArray buffer_bytes;
QBuffer buffer(&buffer_bytes);
buffer.open(QIODevice::WriteOnly);
cap.save(&buffer, "JPG", 50);
kj::Array<capnp::byte> buffer_kj = kj::heapArray<capnp::byte>((const capnp::byte*)buffer_bytes.constData(), buffer_bytes.size());
// Send thumbnail
MessageBuilder msg;
auto thumbnaild = msg.initEvent().initNavThumbnail();
thumbnaild.setFrameId(frame_id);
thumbnaild.setTimestampEof(ts);
thumbnaild.setThumbnail(buffer_kj);
pm->send("navThumbnail", msg);
}
frame_id++;
}
uint8_t* MapRenderer::getImage() {
QImage cap = fbo->toImage().convertToFormat(QImage::Format_RGB888, Qt::AutoColor);
uint8_t* buf = new uint8_t[cap.sizeInBytes()];
memcpy(buf, cap.bits(), cap.sizeInBytes());
return buf;
}
void MapRenderer::updateRoute(QList<QGeoCoordinate> coordinates) {
if (m_map.isNull()) return;
initLayers();
auto route_points = coordinate_list_to_collection(coordinates);
QMapbox::Feature feature(QMapbox::Feature::LineStringType, route_points, {}, {});
QVariantMap navSource;
navSource["type"] = "geojson";
navSource["data"] = QVariant::fromValue<QMapbox::Feature>(feature);
m_map->updateSource("navSource", navSource);
m_map->setLayoutProperty("navLayer", "visibility", "visible");
}
void MapRenderer::initLayers() {
if (!m_map->layerExists("navLayer")) {
QVariantMap nav;
nav["id"] = "navLayer";
nav["type"] = "line";
nav["source"] = "navSource";
m_map->addLayer(nav, "road-intersection");
m_map->setPaintProperty("navLayer", "line-color", QColor("blue"));
m_map->setPaintProperty("navLayer", "line-width", 3);
m_map->setLayoutProperty("navLayer", "line-cap", "round");
}
}
MapRenderer::~MapRenderer() {
}
extern "C" {
MapRenderer* map_renderer_init() {
char *argv[] = {
(char*)"navd",
nullptr
};
int argc = 0;
QApplication *app = new QApplication(argc, argv);
assert(app);
QMapboxGLSettings settings;
settings.setApiBaseUrl(MAPS_HOST);
settings.setAccessToken(get_mapbox_token());
return new MapRenderer(settings, false);
}
void map_renderer_update_position(MapRenderer *inst, float lat, float lon, float bearing) {
inst->updatePosition({lat, lon}, bearing);
QApplication::processEvents();
}
void map_renderer_update_route(MapRenderer *inst, char* polyline) {
inst->updateRoute(polyline_to_coordinate_list(QString::fromUtf8(polyline)));
}
void map_renderer_update(MapRenderer *inst) {
inst->update();
}
void map_renderer_process(MapRenderer *inst) {
QApplication::processEvents();
}
bool map_renderer_loaded(MapRenderer *inst) {
return inst->loaded();
}
uint8_t * map_renderer_get_image(MapRenderer *inst) {
return inst->getImage();
}
void map_renderer_free_image(MapRenderer *inst, uint8_t * buf) {
delete[] buf;
}
}

View File

@ -0,0 +1,49 @@
#pragma once
#include <memory>
#include <QOpenGLContext>
#include <QMapboxGL>
#include <QTimer>
#include <QGeoCoordinate>
#include <QOpenGLBuffer>
#include <QOffscreenSurface>
#include <QOpenGLFunctions>
#include <QOpenGLFramebufferObject>
#include "cereal/visionipc/visionipc_server.h"
#include "cereal/messaging/messaging.h"
class MapRenderer : public QObject {
Q_OBJECT
public:
MapRenderer(const QMapboxGLSettings &, bool enable_vipc=true);
uint8_t* getImage();
void update();
bool loaded();
~MapRenderer();
private:
std::unique_ptr<QOpenGLContext> ctx;
std::unique_ptr<QOffscreenSurface> surface;
std::unique_ptr<QOpenGLFunctions> gl_functions;
std::unique_ptr<QOpenGLFramebufferObject> fbo;
std::unique_ptr<VisionIpcServer> vipc_server;
std::unique_ptr<PubMaster> pm;
void sendVipc();
QMapboxGLSettings m_settings;
QScopedPointer<QMapboxGL> m_map;
void initLayers();
uint32_t frame_id = 0;
public slots:
void updatePosition(QMapbox::Coordinate position, float bearing);
void updateRoute(QList<QGeoCoordinate> coordinates);
};

View File

@ -0,0 +1,78 @@
#!/usr/bin/env python3
# You might need to uninstall the PyQt5 pip package to avoid conflicts
import os
import time
from cffi import FFI
from common.ffi_wrapper import suffix
from common.basedir import BASEDIR
HEIGHT = WIDTH = 256
def get_ffi():
lib = os.path.join(BASEDIR, "selfdrive", "ui", "navd", "libmap_renderer" + suffix())
ffi = FFI()
ffi.cdef("""
void* map_renderer_init();
void map_renderer_update_position(void *inst, float lat, float lon, float bearing);
void map_renderer_update_route(void *inst, char *polyline);
void map_renderer_update(void *inst);
void map_renderer_process(void *inst);
bool map_renderer_loaded(void *inst);
uint8_t* map_renderer_get_image(void *inst);
void map_renderer_free_image(void *inst, uint8_t *buf);
""")
return ffi, ffi.dlopen(lib)
def wait_ready(lib, renderer):
while not lib.map_renderer_loaded(renderer):
lib.map_renderer_update(renderer)
# The main qt app is not execed, so we need to periodically process events for e.g. network requests
lib.map_renderer_process(renderer)
time.sleep(0.01)
def get_image(lib, renderer):
buf = lib.map_renderer_get_image(renderer)
r = list(buf[0:3 * WIDTH * HEIGHT])
lib.map_renderer_free_image(renderer, buf)
# Convert to numpy
r = np.asarray(r)
return r.reshape((WIDTH, HEIGHT, 3))
if __name__ == "__main__":
import matplotlib.pyplot as plt
import numpy as np
ffi, lib = get_ffi()
renderer = lib.map_renderer_init()
wait_ready(lib, renderer)
geometry = r"{yxk}@|obn~Eg@@eCFqc@J{RFw@?kA@gA?q|@Riu@NuJBgi@ZqVNcRBaPBkG@iSD{I@_H@cH?gG@mG@gG?aD@{LDgDDkVVyQLiGDgX@q_@@qI@qKhS{R~[}NtYaDbGoIvLwNfP_b@|f@oFnF_JxHel@bf@{JlIuxAlpAkNnLmZrWqFhFoh@jd@kX|TkJxH_RnPy^|[uKtHoZ~Um`DlkCorC``CuShQogCtwB_ThQcr@fk@sVrWgRhVmSb\\oj@jxA{Qvg@u]tbAyHzSos@xjBeKbWszAbgEc~@~jCuTrl@cYfo@mRn\\_m@v}@ij@jp@om@lk@y|A`pAiXbVmWzUod@xj@wNlTw}@|uAwSn\\kRfYqOdS_IdJuK`KmKvJoOhLuLbHaMzGwO~GoOzFiSrEsOhD}PhCqw@vJmnAxSczA`Vyb@bHk[fFgl@pJeoDdl@}}@zIyr@hG}X`BmUdBcM^aRR}Oe@iZc@mR_@{FScHxAn_@vz@zCzH~GjPxAhDlB~DhEdJlIbMhFfG|F~GlHrGjNjItLnGvQ~EhLnBfOn@p`@AzAAvn@CfC?fc@`@lUrArStCfSxEtSzGxM|ElFlBrOzJlEbDnC~BfDtCnHjHlLvMdTnZzHpObOf^pKla@~G|a@dErg@rCbj@zArYlj@ttJ~AfZh@r]LzYg@`TkDbj@gIdv@oE|i@kKzhA{CdNsEfOiGlPsEvMiDpLgBpHyB`MkB|MmArPg@|N?|P^rUvFz~AWpOCdAkB|PuB`KeFfHkCfGy@tAqC~AsBPkDs@uAiAcJwMe@s@eKkPMoXQux@EuuCoH?eI?Kas@}Dy@wAUkMOgDL"
lib.map_renderer_update_route(renderer, geometry.encode())
POSITIONS = [
(32.71569271952601, -117.16384270868463, 0), (32.71569271952601, -117.16384270868463, 45), # San Diego
(52.378641991483136, 4.902623379456488, 0), (52.378641991483136, 4.902623379456488, 45), # Amsterdam
]
plt.figure()
for i, pos in enumerate(POSITIONS):
t = time.time()
lib.map_renderer_update_position(renderer, *pos)
wait_ready(lib, renderer)
print(f"{pos} took {time.time() - t:.2f} s")
plt.subplot(2, 2, i + 1)
plt.imshow(get_image(lib, renderer))
plt.show()

View File

@ -91,7 +91,6 @@ static void parse_banner(cereal::NavInstruction::Builder &instruction, const QMa
}
}
}
}
RouteEngine::RouteEngine() {
@ -99,14 +98,17 @@ RouteEngine::RouteEngine() {
pm = new PubMaster({"navInstruction", "navRoute"});
// Timers
timer = new QTimer(this);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate()));
timer->start(1000);
route_timer = new QTimer(this);
QObject::connect(route_timer, SIGNAL(timeout()), this, SLOT(routeUpdate()));
route_timer->start(1000);
msg_timer = new QTimer(this);
QObject::connect(msg_timer, SIGNAL(timeout()), this, SLOT(msgUpdate()));
msg_timer->start(50);
// Build routing engine
QVariantMap parameters;
QString token = MAPBOX_TOKEN.isEmpty() ? CommaApi::create_jwt({}, 4 * 7 * 24 * 3600) : MAPBOX_TOKEN;
parameters["mapbox.access_token"] = token;
parameters["mapbox.access_token"] = get_mapbox_token();
parameters["mapbox.directions_api_url"] = MAPS_HOST + "/directions/v5/mapbox/";
geoservice_provider = new QGeoServiceProvider("mapbox", parameters);
@ -124,12 +126,14 @@ RouteEngine::RouteEngine() {
}
}
void RouteEngine::timerUpdate() {
sm->update(0);
void RouteEngine::msgUpdate() {
sm->update(1000);
if (!sm->updated("liveLocationKalman")) {
active = false;
return;
}
if (sm->updated("managerState")) {
for (auto const &p : (*sm)["managerState"].getManagerState().getProcesses()) {
if (p.getName() == "ui" && p.getRunning()) {
@ -153,6 +157,15 @@ void RouteEngine::timerUpdate() {
if (localizer_valid) {
last_bearing = RAD2DEG(orientation.getValue()[2]);
last_position = QMapbox::Coordinate(pos.getValue()[0], pos.getValue()[1]);
emit positionUpdated(*last_position, *last_bearing);
}
active = true;
}
void RouteEngine::routeUpdate() {
if (!active) {
return;
}
recomputeRoute();
@ -261,6 +274,10 @@ bool RouteEngine::shouldRecompute() {
}
void RouteEngine::recomputeRoute() {
if (!last_position) {
return;
}
auto new_destination = coordinate_from_param("NavDestination");
if (!new_destination) {
clearRoute();
@ -308,6 +325,9 @@ void RouteEngine::routeCalculated(QGeoRouteReply *reply) {
route = reply->routes().at(0);
segment = route.firstRouteSegment();
auto path = route.path();
emit routeUpdated(path);
} else {
qWarning() << "Got empty route response";
}

View File

@ -23,7 +23,8 @@ public:
SubMaster *sm;
PubMaster *pm;
QTimer* timer;
QTimer* msg_timer;
QTimer* route_timer;
std::optional<int> ui_pid;
@ -41,6 +42,7 @@ public:
bool localizer_valid = false;
// Route recompute
bool active = false;
int recompute_backoff = 0;
int recompute_countdown = 0;
void calculateRoute(QMapbox::Coordinate destination);
@ -48,8 +50,13 @@ public:
bool shouldRecompute();
private slots:
void timerUpdate();
void routeUpdate();
void msgUpdate();
void routeCalculated(QGeoRouteReply *reply);
void recomputeRoute();
void sendRoute();
signals:
void positionUpdated(QMapbox::Coordinate position, float bearing);
void routeUpdated(QList<QGeoCoordinate> coordinates);
};

View File

@ -22,9 +22,6 @@
#include "selfdrive/common/util.h"
#include "cereal/messaging/messaging.h"
const QString MAPBOX_TOKEN = util::getenv("MAPBOX_TOKEN").c_str();
const QString MAPS_HOST = util::getenv("MAPS_HOST", MAPBOX_TOKEN.isEmpty() ? "https://maps.comma.ai" : "https://api.mapbox.com").c_str();
class MapInstructions : public QWidget {
Q_OBJECT

View File

@ -4,7 +4,25 @@
#include <QJsonObject>
#include "selfdrive/common/params.h"
#include "selfdrive/hardware/hw.h"
#include "selfdrive/ui/qt/api.h"
QString get_mapbox_token() {
// Valid for 4 weeks since we can't swap tokens on the fly
return MAPBOX_TOKEN.isEmpty() ? CommaApi::create_jwt({}, 4 * 7 * 24 * 3600) : MAPBOX_TOKEN;
}
QMapboxGLSettings get_mapbox_settings() {
QMapboxGLSettings settings;
if (!Hardware::PC()) {
settings.setCacheDatabasePath(MAPS_CACHE_PATH);
}
settings.setApiBaseUrl(MAPS_HOST);
settings.setAccessToken(get_mapbox_token());
return settings;
}
QGeoCoordinate to_QGeoCoordinate(const QMapbox::Coordinate &in) {
return QGeoCoordinate(in.first, in.second);
@ -83,6 +101,48 @@ QMapbox::CoordinatesCollections coordinate_list_to_collection(QList<QGeoCoordina
return collections;
}
QList<QGeoCoordinate> polyline_to_coordinate_list(const QString &polylineString) {
QList<QGeoCoordinate> path;
if (polylineString.isEmpty())
return path;
QByteArray data = polylineString.toLatin1();
bool parsingLatitude = true;
int shift = 0;
int value = 0;
QGeoCoordinate coord(0, 0);
for (int i = 0; i < data.length(); ++i) {
unsigned char c = data.at(i) - 63;
value |= (c & 0x1f) << shift;
shift += 5;
// another chunk
if (c & 0x20)
continue;
int diff = (value & 1) ? ~(value >> 1) : (value >> 1);
if (parsingLatitude) {
coord.setLatitude(coord.latitude() + (double)diff/1e6);
} else {
coord.setLongitude(coord.longitude() + (double)diff/1e6);
path.append(coord);
}
parsingLatitude = !parsingLatitude;
value = 0;
shift = 0;
}
return path;
}
static QGeoCoordinate sub(QGeoCoordinate v, QGeoCoordinate w) {
return QGeoCoordinate(v.latitude() - w.latitude(), v.longitude() - w.longitude());
}

View File

@ -5,12 +5,17 @@
#include <QMapboxGL>
#include <QGeoCoordinate>
#include "selfdrive/common/util.h"
#include "common/transformations/coordinates.hpp"
#include "common/transformations/orientation.hpp"
#include "cereal/messaging/messaging.h"
#define RAD2DEG(x) ((x) * 180.0 / M_PI)
const QString MAPBOX_TOKEN = util::getenv("MAPBOX_TOKEN").c_str();
const QString MAPS_HOST = util::getenv("MAPS_HOST", MAPBOX_TOKEN.isEmpty() ? "https://maps.comma.ai" : "https://api.mapbox.com").c_str();
const QString MAPS_CACHE_PATH = "/data/mbgl-cache-navd.db";
QString get_mapbox_token();
QMapboxGLSettings get_mapbox_settings();
QGeoCoordinate to_QGeoCoordinate(const QMapbox::Coordinate &in);
QMapbox::CoordinatesCollections model_to_collection(
const cereal::LiveLocationKalman::Measurement::Reader &calibratedOrientationECEF,
@ -19,6 +24,7 @@ QMapbox::CoordinatesCollections model_to_collection(
QMapbox::CoordinatesCollections coordinate_to_collection(QMapbox::Coordinate c);
QMapbox::CoordinatesCollections capnp_coordinate_list_to_collection(const capnp::List<cereal::NavRoute::Coordinate>::Reader &coordinate_list);
QMapbox::CoordinatesCollections coordinate_list_to_collection(QList<QGeoCoordinate> coordinate_list);
QList<QGeoCoordinate> polyline_to_coordinate_list(const QString &polylineString);
float minimum_distance(QGeoCoordinate a, QGeoCoordinate b, QGeoCoordinate p);
std::optional<QMapbox::Coordinate> coordinate_from_param(std::string param);

View File

@ -12,7 +12,7 @@ DriverViewWindow::DriverViewWindow(QWidget* parent) : QWidget(parent) {
layout = new QStackedLayout(this);
layout->setStackingMode(QStackedLayout::StackAll);
cameraView = new CameraViewWidget(VISION_STREAM_RGB_FRONT, true, this);
cameraView = new CameraViewWidget("camerad", VISION_STREAM_RGB_FRONT, true, this);
layout->addWidget(cameraView);
scene = new DriverViewScene(this);

View File

@ -5,9 +5,9 @@
#include "selfdrive/common/timing.h"
#include "selfdrive/ui/paint.h"
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/api.h"
#ifdef ENABLE_MAPS
#include "selfdrive/ui/qt/maps/map.h"
#include "selfdrive/ui/qt/maps/map_helpers.h"
#endif
OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
@ -68,19 +68,7 @@ void OnroadWindow::offroadTransition(bool offroad) {
#ifdef ENABLE_MAPS
if (!offroad) {
if (map == nullptr && (QUIState::ui_state.has_prime || !MAPBOX_TOKEN.isEmpty())) {
QMapboxGLSettings settings;
// Valid for 4 weeks since we can't swap tokens on the fly
QString token = MAPBOX_TOKEN.isEmpty() ? CommaApi::create_jwt({}, 4 * 7 * 24 * 3600) : MAPBOX_TOKEN;
if (!Hardware::PC()) {
settings.setCacheDatabasePath("/data/mbgl-cache.db");
}
settings.setApiBaseUrl(MAPS_HOST);
settings.setCacheDatabaseMaximumSize(20 * 1024 * 1024);
settings.setAccessToken(token.trimmed());
MapWindow * m = new MapWindow(settings);
MapWindow * m = new MapWindow(get_mapbox_settings());
m->setFixedWidth(topWidget(this)->width() / 2);
QObject::connect(this, &OnroadWindow::offroadTransitionSignal, m, &MapWindow::offroadTransition);
split->addWidget(m, 0, Qt::AlignRight);

View File

@ -29,7 +29,7 @@ class NvgWindow : public CameraViewWidget {
Q_OBJECT
public:
explicit NvgWindow(VisionStreamType type, QWidget* parent = 0) : CameraViewWidget(type, true, parent) {}
explicit NvgWindow(VisionStreamType type, QWidget* parent = 0) : CameraViewWidget("camerad", type, true, parent) {}
protected:
void paintGL() override;

View File

@ -94,8 +94,8 @@ mat4 get_fit_view_transform(float widget_aspect_ratio, float frame_aspect_ratio)
} // namespace
CameraViewWidget::CameraViewWidget(VisionStreamType type, bool zoom, QWidget* parent) :
stream_type(type), zoomed_view(zoom), QOpenGLWidget(parent) {
CameraViewWidget::CameraViewWidget(std::string stream_name, VisionStreamType type, bool zoom, QWidget* parent) :
stream_name(stream_name), stream_type(type), zoomed_view(zoom), QOpenGLWidget(parent) {
setAttribute(Qt::WA_OpaquePaintEvent);
connect(this, &CameraViewWidget::vipcThreadConnected, this, &CameraViewWidget::vipcConnected, Qt::BlockingQueuedConnection);
connect(this, &CameraViewWidget::vipcThreadFrameReceived, this, &CameraViewWidget::vipcFrameReceived);
@ -276,7 +276,7 @@ void CameraViewWidget::vipcThread() {
while (!QThread::currentThread()->isInterruptionRequested()) {
if (!vipc_client || cur_stream_type != stream_type) {
cur_stream_type = stream_type;
vipc_client.reset(new VisionIpcClient("camerad", cur_stream_type, true));
vipc_client.reset(new VisionIpcClient(stream_name, cur_stream_type, true));
}
if (!vipc_client->connected) {

View File

@ -15,7 +15,7 @@ class CameraViewWidget : public QOpenGLWidget, protected QOpenGLFunctions {
public:
using QOpenGLWidget::QOpenGLWidget;
explicit CameraViewWidget(VisionStreamType stream_type, bool zoom, QWidget* parent = nullptr);
explicit CameraViewWidget(std::string stream_name, VisionStreamType stream_type, bool zoom, QWidget* parent = nullptr);
~CameraViewWidget();
void setStreamType(VisionStreamType type) { stream_type = type; }
void setBackgroundColor(const QColor &color) { bg = color; }
@ -43,6 +43,7 @@ protected:
QOpenGLShaderProgram *program;
QColor bg = QColor("#000000");
std::string stream_name;
int stream_width = 0;
int stream_height = 0;
std::atomic<VisionStreamType> stream_type;

View File

@ -17,12 +17,20 @@ int main(int argc, char *argv[]) {
QVBoxLayout *layout = new QVBoxLayout(&w);
layout->setMargin(0);
layout->setSpacing(0);
layout->addWidget(new CameraViewWidget(VISION_STREAM_RGB_BACK, false));
QHBoxLayout *hlayout = new QHBoxLayout();
layout->addLayout(hlayout);
hlayout->addWidget(new CameraViewWidget(VISION_STREAM_RGB_FRONT, false));
hlayout->addWidget(new CameraViewWidget(VISION_STREAM_RGB_WIDE, false));
{
QHBoxLayout *hlayout = new QHBoxLayout();
layout->addLayout(hlayout);
hlayout->addWidget(new CameraViewWidget("navd", VISION_STREAM_RGB_MAP, false));
hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_RGB_BACK, false));
}
{
QHBoxLayout *hlayout = new QHBoxLayout();
layout->addLayout(hlayout);
hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_RGB_FRONT, false));
hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_RGB_WIDE, false));
}
return a.exec();
}