Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nav: use laikad position if locationd is not yet available #25033

Merged
merged 5 commits into from
Jul 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions selfdrive/navd/navd.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import threading

import requests
import numpy as np

import cereal.messaging as messaging
from cereal import log
from common.api import Api
from common.params import Params
from common.realtime import Ratekeeper
from common.transformations.coordinates import ecef2geodetic
from selfdrive.navd.helpers import (Coordinate, coordinate_from_param,
distance_along_geometry, maxspeed_to_ms,
minimum_distance,
Expand All @@ -18,6 +20,7 @@

REROUTE_DISTANCE = 25
MANEUVER_TRANSITION_THRESHOLD = 10
VALID_POS_STD = 50.0


class RouteEngine:
Expand Down Expand Up @@ -72,13 +75,21 @@ def update(self):

def update_location(self):
location = self.sm['liveLocationKalman']
self.gps_ok = location.gpsOK
laikad = self.sm['gnssMeasurements']

self.localizer_valid = (location.status == log.LiveLocationKalman.Status.valid) and location.positionGeodetic.valid
locationd_valid = (location.status == log.LiveLocationKalman.Status.valid) and location.positionGeodetic.valid
laikad_valid = laikad.positionECEF.valid and np.linalg.norm(laikad.positionECEF.std) < VALID_POS_STD

if self.localizer_valid:
self.localizer_valid = locationd_valid or laikad_valid
self.gps_ok = location.gpsOK or laikad_valid

if locationd_valid:
self.last_bearing = math.degrees(location.calibratedOrientationNED.value[2])
self.last_position = Coordinate(location.positionGeodetic.value[0], location.positionGeodetic.value[1])
elif laikad_valid:
geodetic = ecef2geodetic(laikad.positionECEF.value)
self.last_position = Coordinate(geodetic[0], geodetic[1])
self.last_bearing = None

def recompute_route(self):
if self.last_position is None:
Expand Down Expand Up @@ -276,7 +287,7 @@ def should_recompute(self):

def main(sm=None, pm=None):
if sm is None:
sm = messaging.SubMaster(['liveLocationKalman', 'managerState'])
sm = messaging.SubMaster(['liveLocationKalman', 'gnssMeasurements', 'managerState'])
if pm is None:
pm = messaging.PubMaster(['navInstruction', 'navRoute'])

Expand Down
71 changes: 55 additions & 16 deletions selfdrive/ui/qt/maps/map.cc
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#include "selfdrive/ui/qt/maps/map.h"

#include <eigen3/Eigen/Dense>
#include <cmath>

#include <QDebug>
#include <QFileInfo>
#include <QPainterPath>

#include "common/swaglog.h"
#include "common/transformations/coordinates.hpp"
#include "selfdrive/ui/qt/maps/map_helpers.h"
#include "selfdrive/ui/qt/request_repeater.h"
#include "selfdrive/ui/qt/util.h"
Expand All @@ -22,6 +24,8 @@ const float MAX_PITCH = 50;
const float MIN_PITCH = 0;
const float MAP_SCALE = 2;

const float VALID_POS_STD = 50.0; // m

const QString ICON_SUFFIX = ".png";

MapWindow::MapWindow(const QMapboxGLSettings &settings) : m_settings(settings), velocity_filter(0, 10, 0.05) {
Expand Down Expand Up @@ -105,18 +109,53 @@ void MapWindow::updateState(const UIState &s) {
update();

if (sm.updated("liveLocationKalman")) {
auto location = sm["liveLocationKalman"].getLiveLocationKalman();
auto pos = location.getPositionGeodetic();
auto orientation = location.getCalibratedOrientationNED();
auto velocity = location.getVelocityCalibrated();

localizer_valid = (location.getStatus() == cereal::LiveLocationKalman::Status::VALID) &&
pos.getValid() && orientation.getValid() && velocity.getValid();

if (localizer_valid) {
last_position = QMapbox::Coordinate(pos.getValue()[0], pos.getValue()[1]);
last_bearing = RAD2DEG(orientation.getValue()[2]);
velocity_filter.update(velocity.getValue()[0]);
auto locationd_location = sm["liveLocationKalman"].getLiveLocationKalman();
auto locationd_pos = locationd_location.getPositionGeodetic();
auto locationd_orientation = locationd_location.getCalibratedOrientationNED();
auto locationd_velocity = locationd_location.getVelocityCalibrated();

locationd_valid = (locationd_location.getStatus() == cereal::LiveLocationKalman::Status::VALID) &&
locationd_pos.getValid() && locationd_orientation.getValid() && locationd_velocity.getValid();

if (locationd_valid) {
last_position = QMapbox::Coordinate(locationd_pos.getValue()[0], locationd_pos.getValue()[1]);
last_bearing = RAD2DEG(locationd_orientation.getValue()[2]);
velocity_filter.update(locationd_velocity.getValue()[0]);
}
}

if (sm.updated("gnssMeasurements")) {
auto laikad_location = sm["gnssMeasurements"].getGnssMeasurements();
auto laikad_pos = laikad_location.getPositionECEF();
auto laikad_pos_ecef = laikad_pos.getValue();
auto laikad_pos_std = laikad_pos.getStd();
auto laikad_velocity_ecef = laikad_location.getVelocityECEF().getValue();

laikad_valid = laikad_pos.getValid() && Eigen::Vector3d(laikad_pos_std[0], laikad_pos_std[1], laikad_pos_std[2]).norm() < VALID_POS_STD;

if (laikad_valid && !locationd_valid) {
ECEF ecef = {.x = laikad_pos_ecef[0], .y = laikad_pos_ecef[1], .z = laikad_pos_ecef[2]};
Geodetic laikad_pos_geodetic = ecef2geodetic(ecef);
last_position = QMapbox::Coordinate(laikad_pos_geodetic.lat, laikad_pos_geodetic.lon);

// Compute NED velocity
LocalCoord converter(ecef);
ECEF next_ecef = {.x = ecef.x + laikad_velocity_ecef[0], .y = ecef.y + laikad_velocity_ecef[1], .z = ecef.z + laikad_velocity_ecef[2]};
Eigen::VectorXd ned_vel = converter.ecef2ned(next_ecef).to_vector() - converter.ecef2ned(ecef).to_vector();

float velocity = ned_vel.norm();
velocity_filter.update(velocity);

// Convert NED velocity to angle
if (velocity > 1.0) {
float new_bearing = fmod(RAD2DEG(atan2(ned_vel[1], ned_vel[0])) + 360.0, 360.0);
if (last_bearing) {
float delta = 0.1 * angle_difference(*last_bearing, new_bearing); // Smooth heading
last_bearing = fmod(*last_bearing + delta + 360.0, 360.0);
} else {
last_bearing = new_bearing;
}
}
}
}

Expand All @@ -142,9 +181,7 @@ void MapWindow::updateState(const UIState &s) {

initLayers();

if (!localizer_valid) {
map_instructions->showError("Waiting for GPS");
} else {
if (locationd_valid || laikad_valid) {
map_instructions->noError();

// Update current location marker
Expand All @@ -154,6 +191,8 @@ void MapWindow::updateState(const UIState &s) {
carPosSource["type"] = "geojson";
carPosSource["data"] = QVariant::fromValue<QMapbox::Feature>(feature1);
m_map->updateSource("carPosSource", carPosSource);
} else {
map_instructions->showError("Waiting for GPS");
}

if (pan_counter == 0) {
Expand All @@ -174,7 +213,7 @@ void MapWindow::updateState(const UIState &s) {
auto i = sm["navInstruction"].getNavInstruction();
emit ETAChanged(i.getTimeRemaining(), i.getTimeRemainingTypical(), i.getDistanceRemaining());

if (localizer_valid) {
if (locationd_valid || laikad_valid) {
m_map->setPitch(MAX_PITCH); // TODO: smooth pitching based on maneuver distance
emit distanceChanged(i.getManeuverDistance()); // TODO: combine with instructionsChanged
emit instructionsChanged(i);
Expand Down
3 changes: 2 additions & 1 deletion selfdrive/ui/qt/maps/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ class MapWindow : public QOpenGLWidget {
std::optional<QMapbox::Coordinate> last_position;
std::optional<float> last_bearing;
FirstOrderFilter velocity_filter;
bool localizer_valid = false;
bool laikad_valid = false;
bool locationd_valid = false;

MapInstructions* map_instructions;
MapETA* map_eta;
Expand Down
5 changes: 5 additions & 0 deletions selfdrive/ui/qt/maps/map_helpers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,8 @@ std::optional<QMapbox::Coordinate> coordinate_from_param(std::string param) {
return {};
}
}

double angle_difference(double angle1, double angle2) {
double diff = fmod(angle2 - angle1 + 180.0, 360.0) - 180.0;
return diff < -180.0 ? diff + 360.0 : diff;
}
1 change: 1 addition & 0 deletions selfdrive/ui/qt/maps/map_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ QMapbox::CoordinatesCollections capnp_coordinate_list_to_collection(const capnp:
QMapbox::CoordinatesCollections coordinate_list_to_collection(QList<QGeoCoordinate> coordinate_list);

std::optional<QMapbox::Coordinate> coordinate_from_param(std::string param);
double angle_difference(double angle1, double angle2);
2 changes: 1 addition & 1 deletion selfdrive/ui/ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ UIState::UIState(QObject *parent) : QObject(parent) {
sm = std::make_unique<SubMaster, const std::initializer_list<const char *>>({
"modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "roadCameraState",
"pandaStates", "carParams", "driverMonitoringState", "sensorEvents", "carState", "liveLocationKalman",
"wideRoadCameraState", "managerState", "navInstruction", "navRoute",
"wideRoadCameraState", "managerState", "navInstruction", "navRoute", "gnssMeasurements",
});

Params params;
Expand Down