Apollo 10.0
自动驾驶开放平台
rtk_localization.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2017 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
18
19#include <limits>
20
21#include "modules/common_msgs/sensor_msgs/gnss_best_pose.pb.h"
22
23#include "cyber/time/clock.h"
26
27namespace apollo {
28namespace localization {
29
31using ::Eigen::Vector3d;
32
34 : map_offset_{0.0, 0.0, 0.0},
35 monitor_logger_(
36 apollo::common::monitor::MonitorMessageItem::LOCALIZATION) {}
37
39 imu_list_max_size_ = config.imu_list_max_size();
40 gps_imu_time_diff_threshold_ = config.gps_imu_time_diff_threshold();
41 map_offset_[0] = config.map_offset_x();
42 map_offset_[1] = config.map_offset_y();
43 map_offset_[2] = config.map_offset_z();
44}
45
47 const std::shared_ptr<localization::Gps> &gps_msg) {
48 double time_delay = last_received_timestamp_sec_
49 ? Clock::NowInSeconds() - last_received_timestamp_sec_
50 : last_received_timestamp_sec_;
51 if (time_delay > gps_time_delay_tolerance_) {
52 std::stringstream ss;
53 ss << "GPS message time interval: " << time_delay;
54 monitor_logger_.WARN(ss.str());
55 }
56
57 {
58 std::unique_lock<std::mutex> lock(imu_list_mutex_);
59
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.");
64 }
65 return;
66 }
67 }
68
69 {
70 std::unique_lock<std::mutex> lock(gps_status_list_mutex_);
71
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.");
76 }
77 return;
78 }
79 }
80
81 // publish localization messages
82 PrepareLocalizationMsg(*gps_msg, &last_localization_result_,
83 &last_localization_status_result_);
84 service_started_ = true;
85 if (service_started_time == 0.0) {
86 service_started_time = Clock::NowInSeconds();
87 }
88
89 // watch dog
90 RunWatchDog(gps_msg->header().timestamp_sec());
91
92 last_received_timestamp_sec_ = Clock::NowInSeconds();
93}
94
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);
100 } else {
101 gps_status_list_.pop_front();
102 gps_status_list_.push_back(*status_msg);
103 }
104}
105
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);
111 } else {
112 imu_list_.pop_front();
113 imu_list_.push_back(*imu_msg);
114 }
115}
116
117bool RTKLocalization::IsServiceStarted() { return service_started_; }
118
120 *localization = last_localization_result_;
121}
122
124 LocalizationStatus *localization_status) {
125 *localization_status = last_localization_status_result_;
126}
127
128void RTKLocalization::RunWatchDog(double gps_timestamp) {
129 if (!enable_watch_dog_) {
130 return;
131 }
132
133 // check GPS time stamp against system time
134 double gps_delay_sec = Clock::NowInSeconds() - gps_timestamp;
135 double gps_service_delay = Clock::NowInSeconds() - service_started_time;
136 int64_t gps_delay_cycle_cnt =
137 static_cast<int64_t>(gps_delay_sec * localization_publish_freq_);
138
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) {
142 msg_delay = true;
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());
147 }
148
149 // check IMU time stamp against system time
150 std::unique_lock<std::mutex> lock(imu_list_mutex_);
151 auto imu_msg = imu_list_.back();
152 lock.unlock();
153 double imu_delay_sec =
154 Clock::NowInSeconds() - imu_msg.header().timestamp_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) {
159 msg_delay = true;
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());
164 }
165
166 // to prevent it from beeping continuously
167 if (msg_delay &&
168 (last_reported_timestamp_sec_ < 1. ||
169 Clock::NowInSeconds() > last_reported_timestamp_sec_ + 1.)) {
170 AERROR << "gps/imu frame Delay!";
171 last_reported_timestamp_sec_ = Clock::NowInSeconds();
172 }
173}
174
175void RTKLocalization::PrepareLocalizationMsg(
176 const localization::Gps &gps_msg, LocalizationEstimate *localization,
177 LocalizationStatus *localization_status) {
178 // find the matching gps and imu message
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);
183
184 drivers::gnss::InsStat gps_status;
185 FindNearestGpsStatus(gps_time_stamp, &gps_status);
186 FillLocalizationStatusMsg(gps_status, localization_status);
187}
188
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_));
196}
197
198void RTKLocalization::FillLocalizationStatusMsg(
199 const drivers::gnss::InsStat &status,
200 LocalizationStatus *localization_status) {
201 apollo::common::Header *header = localization_status->mutable_header();
203 header->set_timestamp_sec(timestamp);
204 localization_status->set_measurement_time(status.header().timestamp_sec());
205
206 if (!status.has_pos_type()) {
207 localization_status->set_fusion_status(MeasureState::ERROR);
208 localization_status->set_state_message(
209 "Error: Current Localization Status Is Missing.");
210 return;
211 }
212
213 auto pos_type = static_cast<drivers::gnss::SolutionType>(status.pos_type());
214 switch (pos_type) {
217 localization_status->set_fusion_status(MeasureState::OK);
218 localization_status->set_state_message("");
219 break;
222 localization_status->set_fusion_status(MeasureState::WARNNING);
223 localization_status->set_state_message(
224 "Warning: Current Localization Is Unstable.");
225 break;
226 default:
227 localization_status->set_fusion_status(MeasureState::ERROR);
228 localization_status->set_state_message(
229 "Error: Current Localization Is Very Unstable.");
230 break;
231 }
232}
233
234void RTKLocalization::ComposeLocalizationMsg(
235 const localization::Gps &gps_msg, const localization::CorrectedImu &imu_msg,
236 LocalizationEstimate *localization) {
237 localization->Clear();
238
239 FillLocalizationMsgHeader(localization);
240
241 localization->set_measurement_time(gps_msg.header().timestamp_sec());
242
243 // combine gps and imu
244 auto mutable_pose = localization->mutable_pose();
245 if (gps_msg.has_localization()) {
246 const auto &pose = gps_msg.localization();
247
248 if (pose.has_position()) {
249 // position
250 // world frame -> map frame
251 mutable_pose->mutable_position()->set_x(pose.position().x() -
252 map_offset_[0]);
253 mutable_pose->mutable_position()->set_y(pose.position().y() -
254 map_offset_[1]);
255 mutable_pose->mutable_position()->set_z(pose.position().z() -
256 map_offset_[2]);
257 }
258
259 // orientation
260 if (pose.has_orientation()) {
261 mutable_pose->mutable_orientation()->CopyFrom(pose.orientation());
262 double heading = common::math::QuaternionToHeading(
263 pose.orientation().qw(), pose.orientation().qx(),
264 pose.orientation().qy(), pose.orientation().qz());
265 mutable_pose->set_heading(heading);
266 }
267 // linear velocity
268 if (pose.has_linear_velocity()) {
269 mutable_pose->mutable_linear_velocity()->CopyFrom(pose.linear_velocity());
270 }
271 }
272
273 if (imu_msg.has_imu()) {
274 const auto &imu = imu_msg.imu();
275 // linear acceleration
276 if (imu.has_linear_acceleration()) {
277 if (localization->pose().has_orientation()) {
278 // linear_acceleration:
279 // convert from vehicle reference to map reference
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]);
288
289 // linear_acceleration_vfr
290 mutable_pose->mutable_linear_acceleration_vrf()->CopyFrom(
291 imu.linear_acceleration());
292 } else {
293 AERROR << "[PrepareLocalizationMsg]: "
294 << "fail to convert linear_acceleration";
295 }
296 }
297
298 // angular velocity
299 if (imu.has_angular_velocity()) {
300 if (localization->pose().has_orientation()) {
301 // angular_velocity:
302 // convert from vehicle reference to map reference
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]);
310
311 // angular_velocity_vf
312 mutable_pose->mutable_angular_velocity_vrf()->CopyFrom(
313 imu.angular_velocity());
314 } else {
315 AERROR << "[PrepareLocalizationMsg]: fail to convert angular_velocity";
316 }
317 }
318
319 // euler angle
320 if (imu.has_euler_angles()) {
321 mutable_pose->mutable_euler_angles()->CopyFrom(imu.euler_angles());
322 }
323 }
324}
325
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.";
330 return false;
331 }
332
333 std::unique_lock<std::mutex> lock(imu_list_mutex_);
334 auto imu_list = imu_list_;
335 lock.unlock();
336
337 if (imu_list.empty()) {
338 AERROR << "Cannot find Matching IMU. "
339 << "IMU message Queue is empty! GPS timestamp[" << gps_timestamp_sec
340 << "]";
341 return false;
342 }
343
344 // scan imu buffer, find first imu message that is newer than the given
345 // timestamp
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()) {
350 break;
351 }
352 }
353
354 if (imu_it != imu_list.end()) { // found one
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(); // the oldest imu
362 } else {
363 // here is the normal case
364 auto imu_it_1 = imu_it;
365 imu_it_1--;
366 if (!(*imu_it).has_header() || !(*imu_it_1).has_header()) {
367 AERROR << "imu1 and imu_it_1 must both have header.";
368 return false;
369 }
370 if (!InterpolateIMU(*imu_it_1, *imu_it, gps_timestamp_sec, imu_msg)) {
371 AERROR << "failed to interpolate IMU";
372 return false;
373 }
374 }
375 } else {
376 // give the newest imu, without extrapolation
377 *imu_msg = imu_list.back();
378 if (imu_msg == nullptr) {
379 AERROR << "Fail to get latest observed imu_msg.";
380 return false;
381 }
382
383 if (!imu_msg->has_header()) {
384 AERROR << "imu_msg must have header.";
385 return false;
386 }
387
388 if (std::fabs(imu_msg->header().timestamp_sec() - gps_timestamp_sec) >
389 gps_imu_time_diff_threshold_) {
390 // 20ms threshold to report error
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 << "]";
394 }
395 }
396
397 return true;
398}
399
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";
407 return false;
408 }
409 if (timestamp_sec < imu1.header().timestamp_sec()) {
410 AERROR << "[InterpolateIMU1]: the given time stamp["
411 << FORMAT_TIMESTAMP(timestamp_sec)
412 << "] is older than the 1st message["
413 << FORMAT_TIMESTAMP(imu1.header().timestamp_sec()) << "]";
414 *imu_msg = imu1;
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() << "]";
419 *imu_msg = imu2;
420 } else {
421 *imu_msg = imu1;
422 imu_msg->mutable_header()->set_timestamp_sec(timestamp_sec);
423
424 double time_diff =
425 imu2.header().timestamp_sec() - imu1.header().timestamp_sec();
426 if (fabs(time_diff) >= 0.001) {
427 double frac1 =
428 (timestamp_sec - imu1.header().timestamp_sec()) / time_diff;
429
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);
435 }
436
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);
442 }
443
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);
448 }
449 }
450 }
451 return true;
452}
453
454template <class T>
455T RTKLocalization::InterpolateXYZ(const T &p1, const T &p2,
456 const double frac1) {
457 T p;
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);
461 }
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);
464 }
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);
467 }
468 return p;
469}
470
471bool RTKLocalization::FindNearestGpsStatus(const double gps_timestamp_sec,
472 drivers::gnss::InsStat *status) {
473 CHECK_NOTNULL(status);
474
475 std::unique_lock<std::mutex> lock(gps_status_list_mutex_);
476 auto gps_status_list = gps_status_list_;
477 lock.unlock();
478
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();
482 ++itr) {
483 double diff = std::abs(itr->header().timestamp_sec() - gps_timestamp_sec);
484 if (diff < timestamp_diff_sec) {
485 timestamp_diff_sec = diff;
486 nearest_itr = itr;
487 }
488 }
489
490 if (nearest_itr == gps_status_list.end()) {
491 return false;
492 }
493
494 if (timestamp_diff_sec > gps_status_time_diff_threshold_) {
495 return false;
496 }
497
498 *status = *nearest_itr;
499 return true;
500}
501
502} // namespace localization
503} // namespace apollo
a singleton clock that can be used to get the current timestamp.
Definition clock.h:39
static double NowInSeconds()
gets the current time in second.
Definition clock.cc:56
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)
#define AERROR
Definition log.h:44
Eigen::Vector3d QuaternionRotate(const Quaternion &orientation, const Eigen::Vector3d &original)
Definition quaternion.h:103
double QuaternionToHeading(const double qw, const double qx, const double qy, const double qz)
Definition quaternion.h:56
class register implement
Definition arena_queue.h:37
Contains a number of helper functions related to quaternions.
Some string util functions.
#define FORMAT_TIMESTAMP(timestamp)
Definition string_util.h:29