|
|
@ -41,14 +41,25 @@ const int GPS_ORIENTATION_ERROR_RESET_CNT = 3; |
|
|
|
|
|
|
|
|
|
|
|
const bool DEBUG = getenv("DEBUG") != nullptr && std::string(getenv("DEBUG")) != "0"; |
|
|
|
const bool DEBUG = getenv("DEBUG") != nullptr && std::string(getenv("DEBUG")) != "0"; |
|
|
|
|
|
|
|
|
|
|
|
static VectorXd floatlist2vector(const capnp::List<float, capnp::Kind::PRIMITIVE>::Reader& floatlist) { |
|
|
|
template <typename ListType, typename Vector> |
|
|
|
VectorXd res(floatlist.size()); |
|
|
|
static Vector floatlist2vector(const ListType& floatlist) { |
|
|
|
|
|
|
|
Vector res(floatlist.size()); |
|
|
|
for (int i = 0; i < floatlist.size(); i++) { |
|
|
|
for (int i = 0; i < floatlist.size(); i++) { |
|
|
|
res[i] = floatlist[i]; |
|
|
|
res[i] = floatlist[i]; |
|
|
|
} |
|
|
|
} |
|
|
|
return res; |
|
|
|
return res; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename ListType> |
|
|
|
|
|
|
|
static VectorXd float64list2vector(const ListType& floatlist) { |
|
|
|
|
|
|
|
return floatlist2vector<ListType, VectorXd>(floatlist); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename ListType> |
|
|
|
|
|
|
|
static VectorXf float32list2vector(const ListType& floatlist) { |
|
|
|
|
|
|
|
return floatlist2vector<ListType, VectorXf>(floatlist); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static Vector4d quat2vector(const Quaterniond& quat) { |
|
|
|
static Vector4d quat2vector(const Quaterniond& quat) { |
|
|
|
return Vector4d(quat.w(), quat.x(), quat.y(), quat.z()); |
|
|
|
return Vector4d(quat.w(), quat.x(), quat.y(), quat.z()); |
|
|
|
} |
|
|
|
} |
|
|
@ -63,6 +74,11 @@ static void init_measurement(cereal::LiveLocationKalman::Measurement::Builder me |
|
|
|
meas.setValid(valid); |
|
|
|
meas.setValid(valid); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void init_xyz_measurement(cereal::LivePose::XYZMeasurement::Builder meas, const VectorXf& val, const VectorXf& std, bool valid) { |
|
|
|
|
|
|
|
meas.setX(val[0]); meas.setY(val[1]); meas.setZ(val[2]); |
|
|
|
|
|
|
|
meas.setXStd(std[0]); meas.setYStd(std[1]); meas.setZStd(std[2]); |
|
|
|
|
|
|
|
meas.setValid(valid); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static MatrixXdr rotate_cov(const MatrixXdr& rot_matrix, const MatrixXdr& cov_in) { |
|
|
|
static MatrixXdr rotate_cov(const MatrixXdr& rot_matrix, const MatrixXdr& cov_in) { |
|
|
|
// To rotate a covariance matrix, the cov matrix needs to multiplied left and right by the transform matrix
|
|
|
|
// To rotate a covariance matrix, the cov matrix needs to multiplied left and right by the transform matrix
|
|
|
@ -91,6 +107,30 @@ Localizer::Localizer(LocalizerGnssSource gnss_source) { |
|
|
|
this->configure_gnss_source(gnss_source); |
|
|
|
this->configure_gnss_source(gnss_source); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Localizer::build_live_pose(cereal::LivePose::Builder& livePose, cereal::LiveLocationKalman::Reader& liveLocation) { |
|
|
|
|
|
|
|
// Just copy the values from liveLocation to livePose for now
|
|
|
|
|
|
|
|
VectorXf orientation_ned = float32list2vector(liveLocation.getOrientationNED().getValue()), orientation_ned_std = float32list2vector(liveLocation.getOrientationNED().getStd()); |
|
|
|
|
|
|
|
init_xyz_measurement(livePose.initOrientationNED(), orientation_ned, orientation_ned_std, this->gps_mode); |
|
|
|
|
|
|
|
VectorXf velocity_device = float32list2vector(liveLocation.getVelocityDevice().getValue()), velocity_device_std = float32list2vector(liveLocation.getVelocityDevice().getStd()); |
|
|
|
|
|
|
|
init_xyz_measurement(livePose.initVelocityDevice(), velocity_device, velocity_device_std, true); |
|
|
|
|
|
|
|
VectorXf acceleration_device = float32list2vector(liveLocation.getAccelerationDevice().getValue()), acceleration_device_std = float32list2vector(liveLocation.getAccelerationDevice().getStd()); |
|
|
|
|
|
|
|
init_xyz_measurement(livePose.initAccelerationDevice(), acceleration_device, acceleration_device_std, true); |
|
|
|
|
|
|
|
VectorXf ang_velocity_device = float32list2vector(liveLocation.getAngularVelocityDevice().getValue()), ang_velocity_device_std = float32list2vector(liveLocation.getAngularVelocityDevice().getStd()); |
|
|
|
|
|
|
|
init_xyz_measurement(livePose.initAngularVelocityDevice(), ang_velocity_device, ang_velocity_device_std, true); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (DEBUG) { |
|
|
|
|
|
|
|
VectorXd filter_state = float64list2vector(liveLocation.getFilterState().getValue()), filter_state_std = float64list2vector(liveLocation.getFilterState().getStd()); |
|
|
|
|
|
|
|
cereal::LivePose::FilterState::Builder filter_state_builder = livePose.initFilterState(); |
|
|
|
|
|
|
|
filter_state_builder.setValue(kj::arrayPtr(filter_state.data(), filter_state.size())); |
|
|
|
|
|
|
|
filter_state_builder.setStd(kj::arrayPtr(filter_state_std.data(), filter_state_std.size())); |
|
|
|
|
|
|
|
filter_state_builder.setValid(true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
livePose.setInputsOK(liveLocation.getInputsOK()); |
|
|
|
|
|
|
|
livePose.setPosenetOK(liveLocation.getPosenetOK()); |
|
|
|
|
|
|
|
livePose.setSensorsOK(liveLocation.getSensorsOK()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Localizer::build_live_location(cereal::LiveLocationKalman::Builder& fix) { |
|
|
|
void Localizer::build_live_location(cereal::LiveLocationKalman::Builder& fix) { |
|
|
|
VectorXd predicted_state = this->kf->get_x(); |
|
|
|
VectorXd predicted_state = this->kf->get_x(); |
|
|
|
MatrixXdr predicted_cov = this->kf->get_P(); |
|
|
|
MatrixXdr predicted_cov = this->kf->get_P(); |
|
|
@ -279,7 +319,7 @@ void Localizer::handle_sensor(double current_time, const cereal::SensorEventData |
|
|
|
// TODO: reduce false positives and re-enable this check
|
|
|
|
// TODO: reduce false positives and re-enable this check
|
|
|
|
// check if device fell, estimate 10 for g
|
|
|
|
// check if device fell, estimate 10 for g
|
|
|
|
// 40m/s**2 is a good filter for falling detection, no false positives in 20k minutes of driving
|
|
|
|
// 40m/s**2 is a good filter for falling detection, no false positives in 20k minutes of driving
|
|
|
|
// this->device_fell |= (floatlist2vector(v) - Vector3d(10.0, 0.0, 0.0)).norm() > 40.0;
|
|
|
|
// this->device_fell |= (float64list2vector(v) - Vector3d(10.0, 0.0, 0.0)).norm() > 40.0;
|
|
|
|
|
|
|
|
|
|
|
|
auto meas = Vector3d(-v[2], -v[1], -v[0]); |
|
|
|
auto meas = Vector3d(-v[2], -v[1], -v[0]); |
|
|
|
if (meas.norm() < ACCEL_SANITY_CHECK) { |
|
|
|
if (meas.norm() < ACCEL_SANITY_CHECK) { |
|
|
@ -311,7 +351,7 @@ void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::R |
|
|
|
bool gps_unreasonable = (Vector2d(log.getHorizontalAccuracy(), log.getVerticalAccuracy()).norm() >= SANE_GPS_UNCERTAINTY); |
|
|
|
bool gps_unreasonable = (Vector2d(log.getHorizontalAccuracy(), log.getVerticalAccuracy()).norm() >= SANE_GPS_UNCERTAINTY); |
|
|
|
bool gps_accuracy_insane = ((log.getVerticalAccuracy() <= 0) || (log.getSpeedAccuracy() <= 0) || (log.getBearingAccuracyDeg() <= 0)); |
|
|
|
bool gps_accuracy_insane = ((log.getVerticalAccuracy() <= 0) || (log.getSpeedAccuracy() <= 0) || (log.getBearingAccuracyDeg() <= 0)); |
|
|
|
bool gps_lat_lng_alt_insane = ((std::abs(log.getLatitude()) > 90) || (std::abs(log.getLongitude()) > 180) || (std::abs(log.getAltitude()) > ALTITUDE_SANITY_CHECK)); |
|
|
|
bool gps_lat_lng_alt_insane = ((std::abs(log.getLatitude()) > 90) || (std::abs(log.getLongitude()) > 180) || (std::abs(log.getAltitude()) > ALTITUDE_SANITY_CHECK)); |
|
|
|
bool gps_vel_insane = (floatlist2vector(log.getVNED()).norm() > TRANS_SANITY_CHECK); |
|
|
|
bool gps_vel_insane = (float64list2vector(log.getVNED()).norm() > TRANS_SANITY_CHECK); |
|
|
|
|
|
|
|
|
|
|
|
if (!log.getHasFix() || gps_unreasonable || gps_accuracy_insane || gps_lat_lng_alt_insane || gps_vel_insane) { |
|
|
|
if (!log.getHasFix() || gps_unreasonable || gps_accuracy_insane || gps_lat_lng_alt_insane || gps_vel_insane) { |
|
|
|
//this->gps_valid = false;
|
|
|
|
//this->gps_valid = false;
|
|
|
@ -450,8 +490,8 @@ void Localizer::handle_car_state(double current_time, const cereal::CarState::Re |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Localizer::handle_cam_odo(double current_time, const cereal::CameraOdometry::Reader& log) { |
|
|
|
void Localizer::handle_cam_odo(double current_time, const cereal::CameraOdometry::Reader& log) { |
|
|
|
VectorXd rot_device = this->device_from_calib * floatlist2vector(log.getRot()); |
|
|
|
VectorXd rot_device = this->device_from_calib * float64list2vector(log.getRot()); |
|
|
|
VectorXd trans_device = this->device_from_calib * floatlist2vector(log.getTrans()); |
|
|
|
VectorXd trans_device = this->device_from_calib * float64list2vector(log.getTrans()); |
|
|
|
|
|
|
|
|
|
|
|
if (!this->is_timestamp_valid(current_time)) { |
|
|
|
if (!this->is_timestamp_valid(current_time)) { |
|
|
|
this->observation_timings_invalid = true; |
|
|
|
this->observation_timings_invalid = true; |
|
|
@ -463,8 +503,8 @@ void Localizer::handle_cam_odo(double current_time, const cereal::CameraOdometry |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
VectorXd rot_calib_std = floatlist2vector(log.getRotStd()); |
|
|
|
VectorXd rot_calib_std = float64list2vector(log.getRotStd()); |
|
|
|
VectorXd trans_calib_std = floatlist2vector(log.getTransStd()); |
|
|
|
VectorXd trans_calib_std = float64list2vector(log.getTransStd()); |
|
|
|
|
|
|
|
|
|
|
|
if ((rot_calib_std.minCoeff() <= MIN_STD_SANITY_CHECK) || (trans_calib_std.minCoeff() <= MIN_STD_SANITY_CHECK)) { |
|
|
|
if ((rot_calib_std.minCoeff() <= MIN_STD_SANITY_CHECK) || (trans_calib_std.minCoeff() <= MIN_STD_SANITY_CHECK)) { |
|
|
|
this->observation_values_invalid["cameraOdometry"] += 1.0; |
|
|
|
this->observation_values_invalid["cameraOdometry"] += 1.0; |
|
|
@ -499,7 +539,7 @@ void Localizer::handle_live_calib(double current_time, const cereal::LiveCalibra |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (log.getRpyCalib().size() > 0) { |
|
|
|
if (log.getRpyCalib().size() > 0) { |
|
|
|
auto live_calib = floatlist2vector(log.getRpyCalib()); |
|
|
|
auto live_calib = float64list2vector(log.getRpyCalib()); |
|
|
|
if ((live_calib.minCoeff() < -CALIB_RPY_SANITY_CHECK) || (live_calib.maxCoeff() > CALIB_RPY_SANITY_CHECK)) { |
|
|
|
if ((live_calib.minCoeff() < -CALIB_RPY_SANITY_CHECK) || (live_calib.maxCoeff() > CALIB_RPY_SANITY_CHECK)) { |
|
|
|
this->observation_values_invalid["liveCalibration"] += 1.0; |
|
|
|
this->observation_values_invalid["liveCalibration"] += 1.0; |
|
|
|
return; |
|
|
|
return; |
|
|
@ -611,8 +651,8 @@ void Localizer::handle_msg(const cereal::Event::Reader& log) { |
|
|
|
this->update_reset_tracker(); |
|
|
|
this->update_reset_tracker(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
kj::ArrayPtr<capnp::byte> Localizer::get_message_bytes(MessageBuilder& msg_builder, bool inputsOK, |
|
|
|
void Localizer::build_location_message( |
|
|
|
bool sensorsOK, bool gpsOK, bool msgValid) { |
|
|
|
MessageBuilder& msg_builder, bool inputsOK, bool sensorsOK, bool gpsOK, bool msgValid) { |
|
|
|
cereal::Event::Builder evt = msg_builder.initEvent(); |
|
|
|
cereal::Event::Builder evt = msg_builder.initEvent(); |
|
|
|
evt.setValid(msgValid); |
|
|
|
evt.setValid(msgValid); |
|
|
|
cereal::LiveLocationKalman::Builder liveLoc = evt.initLiveLocationKalman(); |
|
|
|
cereal::LiveLocationKalman::Builder liveLoc = evt.initLiveLocationKalman(); |
|
|
@ -620,7 +660,19 @@ kj::ArrayPtr<capnp::byte> Localizer::get_message_bytes(MessageBuilder& msg_build |
|
|
|
liveLoc.setSensorsOK(sensorsOK); |
|
|
|
liveLoc.setSensorsOK(sensorsOK); |
|
|
|
liveLoc.setGpsOK(gpsOK); |
|
|
|
liveLoc.setGpsOK(gpsOK); |
|
|
|
liveLoc.setInputsOK(inputsOK); |
|
|
|
liveLoc.setInputsOK(inputsOK); |
|
|
|
return msg_builder.toBytes(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Localizer::build_pose_message( |
|
|
|
|
|
|
|
MessageBuilder& msg_builder, MessageBuilder& location_msg_builder, bool inputsOK, bool sensorsOK, bool msgValid) { |
|
|
|
|
|
|
|
cereal::Event::Builder evt = msg_builder.initEvent(); |
|
|
|
|
|
|
|
evt.setValid(msgValid); |
|
|
|
|
|
|
|
cereal::LivePose::Builder livePose = evt.initLivePose(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cereal::LiveLocationKalman::Reader location_msg = location_msg_builder.getRoot<cereal::Event>().getLiveLocationKalman().asReader(); |
|
|
|
|
|
|
|
this->build_live_pose(livePose, location_msg); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
livePose.setSensorsOK(sensorsOK); |
|
|
|
|
|
|
|
livePose.setInputsOK(inputsOK); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool Localizer::is_gps_ok() { |
|
|
|
bool Localizer::is_gps_ok() { |
|
|
@ -692,7 +744,7 @@ int Localizer::locationd_thread() { |
|
|
|
"carState", "accelerometer", "gyroscope"}; |
|
|
|
"carState", "accelerometer", "gyroscope"}; |
|
|
|
|
|
|
|
|
|
|
|
SubMaster sm(service_list, {}, nullptr, {gps_location_socket}); |
|
|
|
SubMaster sm(service_list, {}, nullptr, {gps_location_socket}); |
|
|
|
PubMaster pm({"liveLocationKalman"}); |
|
|
|
PubMaster pm({"liveLocationKalman", "livePose"}); |
|
|
|
|
|
|
|
|
|
|
|
uint64_t cnt = 0; |
|
|
|
uint64_t cnt = 0; |
|
|
|
bool filterInitialized = false; |
|
|
|
bool filterInitialized = false; |
|
|
@ -726,9 +778,15 @@ int Localizer::locationd_thread() { |
|
|
|
this->ttff = std::max(1e-3, (sm[trigger_msg].getLogMonoTime() * 1e-9) - this->first_valid_log_time); |
|
|
|
this->ttff = std::max(1e-3, (sm[trigger_msg].getLogMonoTime() * 1e-9) - this->first_valid_log_time); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
MessageBuilder msg_builder; |
|
|
|
MessageBuilder location_msg_builder, pose_msg_builder; |
|
|
|
kj::ArrayPtr<capnp::byte> bytes = this->get_message_bytes(msg_builder, inputsOK, sensorsOK, gpsOK, filterInitialized); |
|
|
|
this->build_location_message(location_msg_builder, inputsOK, sensorsOK, gpsOK, filterInitialized); |
|
|
|
pm.send("liveLocationKalman", bytes.begin(), bytes.size()); |
|
|
|
this->build_pose_message(pose_msg_builder, location_msg_builder, inputsOK, sensorsOK, filterInitialized); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
kj::ArrayPtr<capnp::byte> location_bytes = location_msg_builder.toBytes(); |
|
|
|
|
|
|
|
pm.send("liveLocationKalman", location_bytes.begin(), location_bytes.size()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
kj::ArrayPtr<capnp::byte> pose_bytes = pose_msg_builder.toBytes(); |
|
|
|
|
|
|
|
pm.send("livePose", pose_bytes.begin(), pose_bytes.size()); |
|
|
|
|
|
|
|
|
|
|
|
if (cnt % 1200 == 0 && gpsOK) { // once a minute
|
|
|
|
if (cnt % 1200 == 0 && gpsOK) { // once a minute
|
|
|
|
VectorXd posGeo = this->get_position_geodetic(); |
|
|
|
VectorXd posGeo = this->get_position_geodetic(); |
|
|
|