|
|
|
@ -1,5 +1,6 @@ |
|
|
|
|
#include "selfdrive/ui/qt/maps/map.h" |
|
|
|
|
|
|
|
|
|
#include <eigen3/Eigen/Dense> |
|
|
|
|
#include <cmath> |
|
|
|
|
|
|
|
|
|
#include <QDebug> |
|
|
|
@ -7,6 +8,7 @@ |
|
|
|
|
#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" |
|
|
|
@ -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) { |
|
|
|
@ -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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -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
|
|
|
|
@ -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) { |
|
|
|
@ -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); |
|
|
|
|