21#include "modules/common_msgs/sensor_msgs/gnss_best_pose.pb.h"
28namespace localization {
31using ::Eigen::Vector3d;
34 : map_offset_{0.0, 0.0, 0.0},
36 apollo::common::monitor::MonitorMessageItem::LOCALIZATION) {}
47 const std::shared_ptr<localization::Gps> &gps_msg) {
48 double time_delay = last_received_timestamp_sec_
50 : last_received_timestamp_sec_;
51 if (time_delay > gps_time_delay_tolerance_) {
53 ss <<
"GPS message time interval: " << time_delay;
54 monitor_logger_.WARN(ss.str());
58 std::unique_lock<std::mutex> lock(imu_list_mutex_);
60 if (imu_list_.empty()) {
61 AERROR <<
"IMU message buffer is empty.";
62 if (service_started_) {
63 monitor_logger_.ERROR(
"IMU message buffer is empty.");
70 std::unique_lock<std::mutex> lock(gps_status_list_mutex_);
72 if (gps_status_list_.empty()) {
73 AERROR <<
"Gps status message buffer is empty.";
74 if (service_started_) {
75 monitor_logger_.ERROR(
"Gps status message buffer is empty.");
82 PrepareLocalizationMsg(*gps_msg, &last_localization_result_,
83 &last_localization_status_result_);
84 service_started_ =
true;
85 if (service_started_time == 0.0) {
90 RunWatchDog(gps_msg->header().timestamp_sec());
96 const std::shared_ptr<drivers::gnss::InsStat> &status_msg) {
97 std::unique_lock<std::mutex> lock(gps_status_list_mutex_);
98 if (gps_status_list_.size() < gps_status_list_max_size_) {
99 gps_status_list_.push_back(*status_msg);
101 gps_status_list_.pop_front();
102 gps_status_list_.push_back(*status_msg);
107 const std::shared_ptr<localization::CorrectedImu> &imu_msg) {
108 std::unique_lock<std::mutex> lock(imu_list_mutex_);
109 if (imu_list_.size() < imu_list_max_size_) {
110 imu_list_.push_back(*imu_msg);
112 imu_list_.pop_front();
113 imu_list_.push_back(*imu_msg);
120 *localization = last_localization_result_;
125 *localization_status = last_localization_status_result_;
128void RTKLocalization::RunWatchDog(
double gps_timestamp) {
129 if (!enable_watch_dog_) {
136 int64_t gps_delay_cycle_cnt =
137 static_cast<int64_t
>(gps_delay_sec * localization_publish_freq_);
139 bool msg_delay =
false;
140 if (gps_delay_cycle_cnt > report_threshold_err_num_ &&
141 static_cast<int>(gps_service_delay) > service_delay_threshold) {
143 std::stringstream ss;
144 ss <<
"Raw GPS Message Delay. GPS message is " << gps_delay_cycle_cnt
145 <<
" cycle " << gps_delay_sec <<
" sec behind current time.";
146 monitor_logger_.ERROR(ss.str());
150 std::unique_lock<std::mutex> lock(imu_list_mutex_);
151 auto imu_msg = imu_list_.back();
153 double imu_delay_sec =
155 int64_t imu_delay_cycle_cnt =
156 static_cast<int64_t
>(imu_delay_sec * localization_publish_freq_);
157 if (imu_delay_cycle_cnt > report_threshold_err_num_ &&
158 static_cast<int>(gps_service_delay) > service_delay_threshold) {
160 std::stringstream ss;
161 ss <<
"Raw IMU Message Delay. IMU message is " << imu_delay_cycle_cnt
162 <<
" cycle " << imu_delay_sec <<
" sec behind current time.";
163 monitor_logger_.ERROR(ss.str());
168 (last_reported_timestamp_sec_ < 1. ||
170 AERROR <<
"gps/imu frame Delay!";
175void RTKLocalization::PrepareLocalizationMsg(
176 const localization::Gps &gps_msg, LocalizationEstimate *localization,
177 LocalizationStatus *localization_status) {
179 double gps_time_stamp = gps_msg.header().timestamp_sec();
180 CorrectedImu imu_msg;
181 FindMatchingIMU(gps_time_stamp, &imu_msg);
182 ComposeLocalizationMsg(gps_msg, imu_msg, localization);
184 drivers::gnss::InsStat gps_status;
185 FindNearestGpsStatus(gps_time_stamp, &gps_status);
186 FillLocalizationStatusMsg(gps_status, localization_status);
189void RTKLocalization::FillLocalizationMsgHeader(
190 LocalizationEstimate *localization) {
191 auto *header = localization->mutable_header();
193 header->set_module_name(module_name_);
194 header->set_timestamp_sec(timestamp);
195 header->set_sequence_num(
static_cast<unsigned int>(++localization_seq_num_));
198void RTKLocalization::FillLocalizationStatusMsg(
199 const drivers::gnss::InsStat &status,
200 LocalizationStatus *localization_status) {
203 header->set_timestamp_sec(timestamp);
204 localization_status->set_measurement_time(status.header().timestamp_sec());
206 if (!status.has_pos_type()) {
208 localization_status->set_state_message(
209 "Error: Current Localization Status Is Missing.");
218 localization_status->set_state_message(
"");
223 localization_status->set_state_message(
224 "Warning: Current Localization Is Unstable.");
228 localization_status->set_state_message(
229 "Error: Current Localization Is Very Unstable.");
234void RTKLocalization::ComposeLocalizationMsg(
235 const localization::Gps &gps_msg,
const localization::CorrectedImu &imu_msg,
236 LocalizationEstimate *localization) {
237 localization->Clear();
239 FillLocalizationMsgHeader(localization);
241 localization->set_measurement_time(gps_msg.header().timestamp_sec());
244 auto mutable_pose = localization->mutable_pose();
245 if (gps_msg.has_localization()) {
246 const auto &pose = gps_msg.localization();
248 if (pose.has_position()) {
251 mutable_pose->mutable_position()->set_x(pose.position().x() -
253 mutable_pose->mutable_position()->set_y(pose.position().y() -
255 mutable_pose->mutable_position()->set_z(pose.position().z() -
260 if (pose.has_orientation()) {
261 mutable_pose->mutable_orientation()->CopyFrom(pose.orientation());
263 pose.orientation().qw(), pose.orientation().qx(),
264 pose.orientation().qy(), pose.orientation().qz());
265 mutable_pose->set_heading(heading);
268 if (pose.has_linear_velocity()) {
269 mutable_pose->mutable_linear_velocity()->CopyFrom(pose.linear_velocity());
273 if (imu_msg.has_imu()) {
274 const auto &imu = imu_msg.imu();
276 if (imu.has_linear_acceleration()) {
277 if (localization->pose().has_orientation()) {
280 Vector3d orig(imu.linear_acceleration().x(),
281 imu.linear_acceleration().y(),
282 imu.linear_acceleration().z());
284 localization->pose().orientation(), orig);
285 mutable_pose->mutable_linear_acceleration()->set_x(vec[0]);
286 mutable_pose->mutable_linear_acceleration()->set_y(vec[1]);
287 mutable_pose->mutable_linear_acceleration()->set_z(vec[2]);
290 mutable_pose->mutable_linear_acceleration_vrf()->CopyFrom(
291 imu.linear_acceleration());
293 AERROR <<
"[PrepareLocalizationMsg]: "
294 <<
"fail to convert linear_acceleration";
299 if (imu.has_angular_velocity()) {
300 if (localization->pose().has_orientation()) {
303 Vector3d orig(imu.angular_velocity().x(), imu.angular_velocity().y(),
304 imu.angular_velocity().z());
306 localization->pose().orientation(), orig);
307 mutable_pose->mutable_angular_velocity()->set_x(vec[0]);
308 mutable_pose->mutable_angular_velocity()->set_y(vec[1]);
309 mutable_pose->mutable_angular_velocity()->set_z(vec[2]);
312 mutable_pose->mutable_angular_velocity_vrf()->CopyFrom(
313 imu.angular_velocity());
315 AERROR <<
"[PrepareLocalizationMsg]: fail to convert angular_velocity";
320 if (imu.has_euler_angles()) {
321 mutable_pose->mutable_euler_angles()->CopyFrom(imu.euler_angles());
326bool RTKLocalization::FindMatchingIMU(
const double gps_timestamp_sec,
327 CorrectedImu *imu_msg) {
328 if (imu_msg ==
nullptr) {
329 AERROR <<
"imu_msg should NOT be nullptr.";
333 std::unique_lock<std::mutex> lock(imu_list_mutex_);
334 auto imu_list = imu_list_;
337 if (imu_list.empty()) {
338 AERROR <<
"Cannot find Matching IMU. "
339 <<
"IMU message Queue is empty! GPS timestamp[" << gps_timestamp_sec
346 auto imu_it = imu_list.begin();
347 for (; imu_it != imu_list.end(); ++imu_it) {
348 if ((*imu_it).header().timestamp_sec() - gps_timestamp_sec >
349 std::numeric_limits<double>::min()) {
354 if (imu_it != imu_list.end()) {
355 if (imu_it == imu_list.begin()) {
356 AERROR <<
"IMU queue too short or request too old. "
357 <<
"Oldest timestamp[" << imu_list.front().header().timestamp_sec()
358 <<
"], Newest timestamp["
359 << imu_list.back().header().timestamp_sec() <<
"], GPS timestamp["
360 << gps_timestamp_sec <<
"]";
361 *imu_msg = imu_list.front();
364 auto imu_it_1 = imu_it;
366 if (!(*imu_it).has_header() || !(*imu_it_1).has_header()) {
367 AERROR <<
"imu1 and imu_it_1 must both have header.";
370 if (!InterpolateIMU(*imu_it_1, *imu_it, gps_timestamp_sec, imu_msg)) {
371 AERROR <<
"failed to interpolate IMU";
377 *imu_msg = imu_list.back();
378 if (imu_msg ==
nullptr) {
379 AERROR <<
"Fail to get latest observed imu_msg.";
383 if (!imu_msg->has_header()) {
384 AERROR <<
"imu_msg must have header.";
388 if (std::fabs(imu_msg->header().timestamp_sec() - gps_timestamp_sec) >
389 gps_imu_time_diff_threshold_) {
391 AERROR <<
"Cannot find Matching IMU. IMU messages too old. "
392 <<
"Newest timestamp[" << imu_list.back().header().timestamp_sec()
393 <<
"], GPS timestamp[" << gps_timestamp_sec <<
"]";
400bool RTKLocalization::InterpolateIMU(
const CorrectedImu &imu1,
401 const CorrectedImu &imu2,
402 const double timestamp_sec,
403 CorrectedImu *imu_msg) {
404 if (!(imu1.header().has_timestamp_sec() &&
405 imu2.header().has_timestamp_sec())) {
406 AERROR <<
"imu1 and imu2 has no header or no timestamp_sec in header";
409 if (timestamp_sec < imu1.header().timestamp_sec()) {
410 AERROR <<
"[InterpolateIMU1]: the given time stamp["
412 <<
"] is older than the 1st message["
415 }
else if (timestamp_sec > imu2.header().timestamp_sec()) {
416 AERROR <<
"[InterpolateIMU2]: the given time stamp[" << timestamp_sec
417 <<
"] is newer than the 2nd message["
418 << imu2.header().timestamp_sec() <<
"]";
422 imu_msg->mutable_header()->set_timestamp_sec(timestamp_sec);
425 imu2.header().timestamp_sec() - imu1.header().timestamp_sec();
426 if (fabs(time_diff) >= 0.001) {
428 (timestamp_sec - imu1.header().timestamp_sec()) / time_diff;
430 if (imu1.imu().has_angular_velocity() &&
431 imu2.imu().has_angular_velocity()) {
432 auto val = InterpolateXYZ(imu1.imu().angular_velocity(),
433 imu2.imu().angular_velocity(), frac1);
434 imu_msg->mutable_imu()->mutable_angular_velocity()->CopyFrom(val);
437 if (imu1.imu().has_linear_acceleration() &&
438 imu2.imu().has_linear_acceleration()) {
439 auto val = InterpolateXYZ(imu1.imu().linear_acceleration(),
440 imu2.imu().linear_acceleration(), frac1);
441 imu_msg->mutable_imu()->mutable_linear_acceleration()->CopyFrom(val);
444 if (imu1.imu().has_euler_angles() && imu2.imu().has_euler_angles()) {
445 auto val = InterpolateXYZ(imu1.imu().euler_angles(),
446 imu2.imu().euler_angles(), frac1);
447 imu_msg->mutable_imu()->mutable_euler_angles()->CopyFrom(val);
455T RTKLocalization::InterpolateXYZ(
const T &p1,
const T &p2,
456 const double frac1) {
458 double frac2 = 1.0 - frac1;
459 if (p1.has_x() && !std::isnan(p1.x()) && p2.has_x() && !std::isnan(p2.x())) {
460 p.set_x(p1.x() * frac2 + p2.x() * frac1);
462 if (p1.has_y() && !std::isnan(p1.y()) && p2.has_y() && !std::isnan(p2.y())) {
463 p.set_y(p1.y() * frac2 + p2.y() * frac1);
465 if (p1.has_z() && !std::isnan(p1.z()) && p2.has_z() && !std::isnan(p2.z())) {
466 p.set_z(p1.z() * frac2 + p2.z() * frac1);
471bool RTKLocalization::FindNearestGpsStatus(
const double gps_timestamp_sec,
472 drivers::gnss::InsStat *status) {
473 CHECK_NOTNULL(status);
475 std::unique_lock<std::mutex> lock(gps_status_list_mutex_);
476 auto gps_status_list = gps_status_list_;
479 double timestamp_diff_sec = 1e8;
480 auto nearest_itr = gps_status_list.end();
481 for (
auto itr = gps_status_list.begin(); itr != gps_status_list.end();
483 double diff = std::abs(itr->header().timestamp_sec() - gps_timestamp_sec);
484 if (diff < timestamp_diff_sec) {
485 timestamp_diff_sec = diff;
490 if (nearest_itr == gps_status_list.end()) {
494 if (timestamp_diff_sec > gps_status_time_diff_threshold_) {
498 *status = *nearest_itr;
a singleton clock that can be used to get the current timestamp.
static double NowInSeconds()
gets the current time in second.
void GpsStatusCallback(const std::shared_ptr< drivers::gnss::InsStat > &status_msg)
void ImuCallback(const std::shared_ptr< localization::CorrectedImu > &imu_msg)
void InitConfig(const rtk_config::Config &config)
void GetLocalization(LocalizationEstimate *localization)
void GpsCallback(const std::shared_ptr< localization::Gps > &gps_msg)
void GetLocalizationStatus(LocalizationStatus *localization_status)
Eigen::Vector3d QuaternionRotate(const Quaternion &orientation, const Eigen::Vector3d &original)
double QuaternionToHeading(const double qw, const double qx, const double qy, const double qz)
Contains a number of helper functions related to quaternions.
Some string util functions.
#define FORMAT_TIMESTAMP(timestamp)
optional double map_offset_x
optional double map_offset_z
optional double map_offset_y
optional int32 imu_list_max_size
optional double gps_imu_time_diff_threshold