00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00120 #include <exception>
00121 #include <string>
00122
00123 #include <boost/accumulators/accumulators.hpp>
00124 #include <boost/accumulators/statistics/max.hpp>
00125 #include <boost/accumulators/statistics/mean.hpp>
00126 #include <boost/accumulators/statistics/min.hpp>
00127 #include <boost/accumulators/statistics/rolling_mean.hpp>
00128 #include <boost/accumulators/statistics/stats.hpp>
00129 #include <boost/accumulators/statistics/tail.hpp>
00130 #include <boost/accumulators/statistics/variance.hpp>
00131 #include <boost/circular_buffer.hpp>
00132
00133 #include <diagnostic_msgs/DiagnosticStatus.h>
00134 #include <diagnostic_updater/diagnostic_updater.h>
00135 #include <diagnostic_updater/publisher.h>
00136 #include <gps_common/GPSFix.h>
00137 #include <nodelet/nodelet.h>
00138 #include <novatel_gps_msgs/NovatelCorrectedImuData.h>
00139 #include <novatel_gps_msgs/NovatelFRESET.h>
00140 #include <novatel_gps_msgs/NovatelMessageHeader.h>
00141 #include <novatel_gps_msgs/NovatelPosition.h>
00142 #include <novatel_gps_msgs/NovatelVelocity.h>
00143 #include <novatel_gps_msgs/Gpgga.h>
00144 #include <novatel_gps_msgs/Gprmc.h>
00145 #include <novatel_gps_msgs/Range.h>
00146 #include <novatel_gps_msgs/Time.h>
00147 #include <novatel_gps_driver/novatel_gps.h>
00148 #include <ros/ros.h>
00149 #include <sensor_msgs/Imu.h>
00150 #include <sensor_msgs/NavSatFix.h>
00151 #include <std_msgs/Time.h>
00152 #include <swri_math_util/math_util.h>
00153 #include <swri_roscpp/parameters.h>
00154 #include <swri_roscpp/publisher.h>
00155 #include <swri_roscpp/subscriber.h>
00156
00157 namespace stats = boost::accumulators;
00158
00159 namespace novatel_gps_driver
00160 {
00161 class NovatelGpsNodelet : public nodelet::Nodelet
00162 {
00163 public:
00164 NovatelGpsNodelet() :
00165 device_(""),
00166 connection_type_("serial"),
00167 polling_period_(0.05),
00168 publish_gpgsa_(false),
00169 publish_gpgsv_(false),
00170 imu_rate_(100.0),
00171 imu_sample_rate_(200.0),
00172 publish_imu_messages_(false),
00173 publish_novatel_positions_(false),
00174 publish_novatel_velocity_(false),
00175 publish_nmea_messages_(false),
00176 publish_range_messages_(false),
00177 publish_time_messages_(false),
00178 publish_trackstat_(false),
00179 publish_diagnostics_(true),
00180 publish_sync_diagnostic_(true),
00181 reconnect_delay_s_(0.5),
00182 use_binary_messages_(false),
00183 connection_(NovatelGps::SERIAL),
00184 last_sync_(ros::TIME_MIN),
00185 rolling_offset_(stats::tag::rolling_window::window_size = 10),
00186 expected_rate_(20),
00187 device_timeouts_(0),
00188 device_interrupts_(0),
00189 device_errors_(0),
00190 gps_parse_failures_(0),
00191 gps_insufficient_data_warnings_(0),
00192 publish_rate_warnings_(0),
00193 measurement_count_(0),
00194 last_published_(ros::TIME_MIN),
00195 imu_frame_id_(""),
00196 frame_id_("")
00197 {
00198 }
00199
00200 ~NovatelGpsNodelet()
00201 {
00202 gps_.Disconnect();
00203 }
00204
00209 void onInit()
00210 {
00211 ros::NodeHandle &node = getNodeHandle();
00212 ros::NodeHandle &priv = getPrivateNodeHandle();
00213
00214 swri::param(priv, "device", device_, device_);
00215 swri::param(priv, "imu_rate", imu_rate_, imu_rate_);
00216 swri::param(priv, "imu_sample_rate", imu_sample_rate_, imu_sample_rate_);
00217 swri::param(priv, "publish_gpgsa", publish_gpgsa_, publish_gpgsa_);
00218 swri::param(priv, "publish_gpgsv", publish_gpgsv_, publish_gpgsv_);
00219 swri::param(priv, "publish_imu_messages", publish_imu_messages_, publish_imu_messages_);
00220 swri::param(priv, "publish_novatel_positions", publish_novatel_positions_, publish_novatel_positions_);
00221 swri::param(priv, "publish_novatel_velocity", publish_novatel_velocity_, publish_novatel_velocity_);
00222 swri::param(priv, "publish_nmea_messages", publish_nmea_messages_, publish_nmea_messages_);
00223 swri::param(priv, "publish_range_messages", publish_range_messages_, publish_range_messages_);
00224 swri::param(priv, "publish_time_messages", publish_time_messages_, publish_time_messages_);
00225 swri::param(priv, "publish_trackstat", publish_trackstat_, publish_trackstat_);
00226 swri::param(priv, "publish_diagnostics", publish_diagnostics_, publish_diagnostics_);
00227 swri::param(priv, "publish_sync_diagnostic", publish_sync_diagnostic_, publish_sync_diagnostic_);
00228 swri::param(priv, "polling_period", polling_period_, polling_period_);
00229 swri::param(priv, "reconnect_delay_s", reconnect_delay_s_, reconnect_delay_s_);
00230 swri::param(priv, "use_binary_messages", use_binary_messages_, use_binary_messages_);
00231
00232 swri::param(priv, "connection_type", connection_type_, connection_type_);
00233 connection_ = NovatelGps::ParseConnection(connection_type_);
00234
00235 swri::param(priv, "imu_frame_id", imu_frame_id_, std::string(""));
00236 swri::param(priv, "frame_id", frame_id_, std::string(""));
00237
00238
00239 swri::param(priv, "gpgga_gprmc_sync_tol", gps_.gpgga_gprmc_sync_tol_, 0.01);
00240 swri::param(priv, "gpgga_position_sync_tol", gps_.gpgga_position_sync_tol_, 0.01);
00241 swri::param(priv, "wait_for_position", gps_.wait_for_position_, false);
00242
00243
00244 reset_service_ = priv.advertiseService("freset", &NovatelGpsNodelet::resetService, this);
00245
00246 sync_sub_ = swri::Subscriber(node, "gps_sync", 100, &NovatelGpsNodelet::SyncCallback, this);
00247
00248 std::string gps_topic = node.resolveName("gps");
00249 gps_pub_ = swri::advertise<gps_common::GPSFix>(node, gps_topic, 100);
00250 fix_pub_ = swri::advertise<sensor_msgs::NavSatFix>(node, "fix", 100);
00251
00252 if (publish_nmea_messages_)
00253 {
00254 gpgga_pub_ = swri::advertise<novatel_gps_msgs::Gpgga>(node,"gpgga", 100);
00255 gprmc_pub_ = swri::advertise<novatel_gps_msgs::Gprmc>(node,"gprmc", 100);
00256 }
00257
00258 if (publish_gpgsa_)
00259 {
00260 gpgsa_pub_ = swri::advertise<novatel_gps_msgs::Gpgsa>(node, "gpgsa", 100);
00261 }
00262
00263 if (publish_imu_messages_)
00264 {
00265 imu_pub_ = swri::advertise<sensor_msgs::Imu>(node, "imu", 100);
00266 novatel_imu_pub_= swri::advertise<novatel_gps_msgs::NovatelCorrectedImuData>(node, "corrimudata", 100);
00267 insstdev_pub_ = swri::advertise<novatel_gps_msgs::Insstdev>(node, "insstdev", 100);
00268 inspva_pub_ = swri::advertise<novatel_gps_msgs::Inspva>(node, "inspva", 100);
00269 inscov_pub_ = swri::advertise<novatel_gps_msgs::Inscov>(node, "inscov", 100);
00270 }
00271
00272 if (publish_gpgsv_)
00273 {
00274 gpgsv_pub_ = swri::advertise<novatel_gps_msgs::Gpgsv>(node, "gpgsv", 100);
00275 }
00276
00277 if (publish_novatel_positions_)
00278 {
00279 novatel_position_pub_ = swri::advertise<novatel_gps_msgs::NovatelPosition>(node, "bestpos", 100);
00280 }
00281
00282 if (publish_novatel_velocity_)
00283 {
00284 novatel_velocity_pub_ = swri::advertise<novatel_gps_msgs::NovatelVelocity>(node, "bestvel", 100);
00285 }
00286
00287 if (publish_range_messages_)
00288 {
00289 range_pub_ = swri::advertise<novatel_gps_msgs::Range>(node, "range", 100);
00290 }
00291
00292 if (publish_time_messages_)
00293 {
00294 time_pub_ = swri::advertise<novatel_gps_msgs::Time>(node, "time", 100);
00295 }
00296
00297 if (publish_trackstat_)
00298 {
00299 trackstat_pub_ = swri::advertise<novatel_gps_msgs::Trackstat>(node, "trackstat", 100);
00300 }
00301
00302 hw_id_ = "Novatel GPS (" + device_ +")";
00303 if (publish_diagnostics_)
00304 {
00305 diagnostic_updater_.setHardwareID(hw_id_);
00306 diagnostic_updater_.add("Connection",
00307 this,
00308 &NovatelGpsNodelet::DeviceDiagnostic);
00309 diagnostic_updater_.add("Hardware",
00310 this,
00311 &NovatelGpsNodelet::GpsDiagnostic);
00312 diagnostic_updater_.add("Data",
00313 this,
00314 &NovatelGpsNodelet::DataDiagnostic);
00315 diagnostic_updater_.add("Rate",
00316 this,
00317 &NovatelGpsNodelet::RateDiagnostic);
00318 diagnostic_updater_.add("GPS Fix",
00319 this,
00320 &NovatelGpsNodelet::FixDiagnostic);
00321 if (publish_sync_diagnostic_)
00322 {
00323 diagnostic_updater_.add("Sync",
00324 this,
00325 &NovatelGpsNodelet::SyncDiagnostic);
00326 }
00327 }
00328 thread_ = boost::thread(&NovatelGpsNodelet::Spin, this);
00329 NODELET_INFO("%s initialized", hw_id_.c_str());
00330 }
00331
00332 void SyncCallback(const std_msgs::TimeConstPtr& sync)
00333 {
00334 boost::unique_lock<boost::mutex> lock(mutex_);
00335 sync_times_.push_back(sync->data);
00336 }
00337
00342 void Spin()
00343 {
00344 std::string format_suffix;
00345 if (use_binary_messages_)
00346 {
00347
00348
00349 format_suffix = "b";
00350 }
00351 else
00352 {
00353 format_suffix = "a";
00354 }
00355
00356 NovatelMessageOpts opts;
00357 opts["gpgga"] = polling_period_;
00358 opts["gprmc"] = polling_period_;
00359 opts["bestpos" + format_suffix] = polling_period_;
00360 opts["time" + format_suffix] = 1.0;
00361
00362 if (publish_gpgsa_)
00363 {
00364 opts["gpgsa"] = polling_period_;
00365 }
00366 if (publish_gpgsv_)
00367 {
00368 opts["gpgsv"] = 1.0;
00369 }
00370 if (publish_imu_messages_)
00371 {
00372 double period = 1.0 / imu_rate_;
00373 opts["corrimudata" + format_suffix] = period;
00374 opts["inscov" + format_suffix] = 1.0;
00375 opts["inspva" + format_suffix] = period;
00376 opts["insstdev" + format_suffix] = 1.0;
00377 if (!use_binary_messages_)
00378 {
00379 NODELET_WARN("Using the ASCII message format with CORRIMUDATA logs is not recommended. "
00380 "A serial link will not be able to keep up with the data rate.");
00381 }
00382 gps_.SetImuRate(imu_sample_rate_);
00383 }
00384 if (publish_novatel_velocity_)
00385 {
00386 opts["bestvel" + format_suffix] = polling_period_;
00387 }
00388 if (publish_range_messages_)
00389 {
00390 opts["range" + format_suffix] = 1.0;
00391 }
00392 if (publish_trackstat_)
00393 {
00394 opts["trackstat" + format_suffix] = 1.0;
00395 }
00396 while (ros::ok())
00397 {
00398 if (gps_.Connect(device_, connection_, opts))
00399 {
00400
00401 NODELET_INFO("%s connected to device", hw_id_.c_str());
00402 while (gps_.IsConnected() && ros::ok())
00403 {
00404
00405 CheckDeviceForData();
00406
00407
00408
00409
00410 if (publish_diagnostics_)
00411 {
00412 diagnostic_updater_.update();
00413 }
00414
00415
00416 ros::spinOnce();
00417
00418 boost::this_thread::sleep(boost::posix_time::microseconds(1));
00419 }
00420 }
00421 else
00422 {
00423 NODELET_ERROR_THROTTLE(1, "Error connecting to device <%s:%s>: %s",
00424 connection_type_.c_str(),
00425 device_.c_str(),
00426 gps_.ErrorMsg().c_str());
00427 device_errors_++;
00428 error_msg_ = gps_.ErrorMsg();
00429 }
00430
00431 if (ros::ok())
00432 {
00433
00434
00435 ros::Duration(reconnect_delay_s_).sleep();
00436 }
00437
00438
00439
00440
00441 if (publish_diagnostics_)
00442 {
00443 diagnostic_updater_.update();
00444 }
00445
00446
00447 ros::spinOnce();
00448
00449 boost::this_thread::sleep(boost::posix_time::microseconds(1));
00450
00451 if (connection_ == NovatelGps::PCAP)
00452 {
00453
00454 ros::shutdown();
00455 }
00456 }
00457
00458 gps_.Disconnect();
00459 NODELET_INFO("%s disconnected and shut down", hw_id_.c_str());
00460 }
00461
00462 private:
00463
00465 std::string device_;
00467 std::string connection_type_;
00468 double polling_period_;
00469 bool publish_gpgsa_;
00470 bool publish_gpgsv_;
00472 double imu_rate_;
00474 double imu_sample_rate_;
00475 bool publish_imu_messages_;
00476 bool publish_novatel_positions_;
00477 bool publish_novatel_velocity_;
00478 bool publish_nmea_messages_;
00479 bool publish_range_messages_;
00480 bool publish_time_messages_;
00481 bool publish_trackstat_;
00482 bool publish_diagnostics_;
00483 bool publish_sync_diagnostic_;
00484 double reconnect_delay_s_;
00485 bool use_binary_messages_;
00486
00487 ros::Publisher fix_pub_;
00488 ros::Publisher gps_pub_;
00489 ros::Publisher imu_pub_;
00490 ros::Publisher inscov_pub_;
00491 ros::Publisher inspva_pub_;
00492 ros::Publisher insstdev_pub_;
00493 ros::Publisher novatel_imu_pub_;
00494 ros::Publisher novatel_position_pub_;
00495 ros::Publisher novatel_velocity_pub_;
00496 ros::Publisher gpgga_pub_;
00497 ros::Publisher gpgsv_pub_;
00498 ros::Publisher gpgsa_pub_;
00499 ros::Publisher gprmc_pub_;
00500 ros::Publisher range_pub_;
00501 ros::Publisher time_pub_;
00502 ros::Publisher trackstat_pub_;
00503
00504 ros::ServiceServer reset_service_;
00505
00506 NovatelGps::ConnectionType connection_;
00507 NovatelGps gps_;
00508
00509 boost::thread thread_;
00510 boost::mutex mutex_;
00511
00513 swri::Subscriber sync_sub_;
00514 ros::Time last_sync_;
00516 boost::circular_buffer<ros::Time> sync_times_;
00518 boost::circular_buffer<ros::Time> msg_times_;
00520 stats::accumulator_set<float, stats::stats<
00521 stats::tag::max,
00522 stats::tag::min,
00523 stats::tag::mean,
00524 stats::tag::variance> > offset_stats_;
00526 stats::accumulator_set<float, stats::stats<stats::tag::rolling_mean> > rolling_offset_;
00527
00528
00529 std::string error_msg_;
00530 diagnostic_updater::Updater diagnostic_updater_;
00531 std::string hw_id_;
00532 double expected_rate_;
00533 int32_t device_timeouts_;
00534 int32_t device_interrupts_;
00535 int32_t device_errors_;
00536 int32_t gps_parse_failures_;
00537 int32_t gps_insufficient_data_warnings_;
00538 int32_t publish_rate_warnings_;
00539 int32_t measurement_count_;
00540 ros::Time last_published_;
00541 novatel_gps_msgs::NovatelPositionPtr last_novatel_position_;
00542
00543 std::string imu_frame_id_;
00544 std::string frame_id_;
00545
00549 bool resetService(novatel_gps_msgs::NovatelFRESET::Request& req,
00550 novatel_gps_msgs::NovatelFRESET::Response& res)
00551 {
00552 if (gps_.IsConnected() == false)
00553 {
00554 res.success = false;
00555 }
00556
00557
00558 std::string command = "FRESET ";
00559 command += req.target.length() ? "STANDARD" : req.target;
00560 command += '\n';
00561 gps_.Write(command);
00562
00563 if (req.target.length() == 0)
00564 {
00565 ROS_WARN("No FRESET target specified. Doing FRESET STANDARD. This may be undesired behavior.");
00566 }
00567
00568 res.success = true;
00569 return true;
00570 }
00571
00578 void CheckDeviceForData()
00579 {
00580 std::vector<novatel_gps_msgs::NovatelPositionPtr> position_msgs;
00581 std::vector<gps_common::GPSFixPtr> fix_msgs;
00582 std::vector<novatel_gps_msgs::GpggaPtr> gpgga_msgs;
00583 std::vector<novatel_gps_msgs::GprmcPtr> gprmc_msgs;
00584
00585
00586 NovatelGps::ReadResult result = gps_.ProcessData();
00587 if (result == NovatelGps::READ_ERROR)
00588 {
00589 NODELET_ERROR_THROTTLE(1, "Error reading from device <%s:%s>: %s",
00590 connection_type_.c_str(),
00591 device_.c_str(),
00592 gps_.ErrorMsg().c_str());
00593 device_errors_++;
00594 }
00595 else if (result == NovatelGps::READ_TIMEOUT)
00596 {
00597 device_timeouts_++;
00598 }
00599 else if (result == NovatelGps::READ_INTERRUPTED)
00600 {
00601
00602
00603 device_interrupts_++;
00604 }
00605 else if (result == NovatelGps::READ_PARSE_FAILED)
00606 {
00607 NODELET_ERROR("Error reading from device <%s:%s>: %s",
00608 connection_type_.c_str(),
00609 device_.c_str(),
00610 gps_.ErrorMsg().c_str());
00611 gps_parse_failures_++;
00612 }
00613 else if (result == NovatelGps::READ_INSUFFICIENT_DATA)
00614 {
00615 gps_insufficient_data_warnings_++;
00616 }
00617
00618
00619 gps_.GetGpggaMessages(gpgga_msgs);
00620 gps_.GetGprmcMessages(gprmc_msgs);
00621 gps_.GetNovatelPositions(position_msgs);
00622 gps_.GetFixMessages(fix_msgs);
00623
00624
00625
00626 measurement_count_ += gpgga_msgs.size();
00627
00628
00629 if (!position_msgs.empty())
00630 {
00631 last_novatel_position_ = position_msgs.back();
00632 }
00633
00634
00635
00636
00637 for (const auto& msg : gpgga_msgs)
00638 {
00639 if (msg->utc_seconds != 0)
00640 {
00641 int64_t second = static_cast<int64_t>(swri_math_util::Round(msg->utc_seconds));
00642 double difference = std::fabs(msg->utc_seconds - second);
00643
00644 if (difference < 0.02)
00645 {
00646 msg_times_.push_back(msg->header.stamp);
00647 }
00648 }
00649 }
00650
00651
00652
00653
00654 CalculateTimeSync();
00655
00656
00657
00658
00659 ros::Duration sync_offset(0);
00660 if (last_sync_ != ros::TIME_MIN)
00661 {
00662 sync_offset = ros::Duration(stats::rolling_mean(rolling_offset_));
00663 }
00664 NODELET_DEBUG_STREAM("GPS TimeSync offset is " << sync_offset);
00665
00666 if (publish_nmea_messages_)
00667 {
00668 for (const auto& msg : gpgga_msgs)
00669 {
00670 msg->header.stamp += sync_offset;
00671 msg->header.frame_id = frame_id_;
00672 gpgga_pub_.publish(msg);
00673 }
00674
00675 for (const auto& msg : gprmc_msgs)
00676 {
00677 msg->header.stamp += sync_offset;
00678 msg->header.frame_id = frame_id_;
00679 gprmc_pub_.publish(msg);
00680 }
00681 }
00682
00683 if (publish_gpgsa_)
00684 {
00685 std::vector<novatel_gps_msgs::GpgsaPtr> gpgsa_msgs;
00686 gps_.GetGpgsaMessages(gpgsa_msgs);
00687 for (const auto& msg : gpgsa_msgs)
00688 {
00689 msg->header.stamp = ros::Time::now();
00690 msg->header.frame_id = frame_id_;
00691 gpgsa_pub_.publish(msg);
00692 }
00693 }
00694
00695 if (publish_gpgsv_)
00696 {
00697 std::vector<novatel_gps_msgs::GpgsvPtr> gpgsv_msgs;
00698 gps_.GetGpgsvMessages(gpgsv_msgs);
00699 for (const auto& msg : gpgsv_msgs)
00700 {
00701 msg->header.stamp = ros::Time::now();
00702 msg->header.frame_id = frame_id_;
00703 gpgsv_pub_.publish(msg);
00704 }
00705 }
00706
00707 if (publish_novatel_positions_)
00708 {
00709 for (const auto& msg : position_msgs)
00710 {
00711 msg->header.stamp += sync_offset;
00712 msg->header.frame_id = frame_id_;
00713 novatel_position_pub_.publish(msg);
00714 }
00715 }
00716
00717 if (publish_novatel_velocity_)
00718 {
00719 std::vector<novatel_gps_msgs::NovatelVelocityPtr> velocity_msgs;
00720 gps_.GetNovatelVelocities(velocity_msgs);
00721 for (const auto& msg : velocity_msgs)
00722 {
00723 msg->header.stamp += sync_offset;
00724 msg->header.frame_id = frame_id_;
00725 novatel_velocity_pub_.publish(msg);
00726 }
00727 }
00728 if (publish_time_messages_)
00729 {
00730 std::vector<novatel_gps_msgs::TimePtr> time_msgs;
00731 gps_.GetTimeMessages(time_msgs);
00732 for (const auto& msg : time_msgs)
00733 {
00734 msg->header.stamp += sync_offset;
00735 msg->header.frame_id = frame_id_;
00736 time_pub_.publish(msg);
00737 }
00738 }
00739 if (publish_range_messages_)
00740 {
00741 std::vector<novatel_gps_msgs::RangePtr> range_msgs;
00742 gps_.GetRangeMessages(range_msgs);
00743 for (const auto& msg : range_msgs)
00744 {
00745 msg->header.stamp += sync_offset;
00746 msg->header.frame_id = frame_id_;
00747 range_pub_.publish(msg);
00748 }
00749 }
00750 if (publish_trackstat_)
00751 {
00752 std::vector<novatel_gps_msgs::TrackstatPtr> trackstat_msgs;
00753 gps_.GetTrackstatMessages(trackstat_msgs);
00754 for (const auto& msg : trackstat_msgs)
00755 {
00756 msg->header.stamp += sync_offset;
00757 msg->header.frame_id = frame_id_;
00758 trackstat_pub_.publish(msg);
00759 }
00760 }
00761 if (publish_imu_messages_)
00762 {
00763 std::vector<novatel_gps_msgs::NovatelCorrectedImuDataPtr> novatel_imu_msgs;
00764 gps_.GetNovatelCorrectedImuData(novatel_imu_msgs);
00765 for (const auto& msg : novatel_imu_msgs)
00766 {
00767 msg->header.stamp += sync_offset;
00768 msg->header.frame_id = imu_frame_id_;
00769 novatel_imu_pub_.publish(msg);
00770 }
00771
00772 std::vector<sensor_msgs::ImuPtr> imu_msgs;
00773 gps_.GetImuMessages(imu_msgs);
00774 for (const auto& msg : imu_msgs)
00775 {
00776 msg->header.stamp += sync_offset;
00777 msg->header.frame_id = imu_frame_id_;
00778 imu_pub_.publish(msg);
00779 }
00780
00781 std::vector<novatel_gps_msgs::InscovPtr> inscov_msgs;
00782 gps_.GetInscovMessages(inscov_msgs);
00783 for (const auto& msg : inscov_msgs)
00784 {
00785 msg->header.stamp += sync_offset;
00786 msg->header.frame_id = imu_frame_id_;
00787 inscov_pub_.publish(msg);
00788 }
00789
00790 std::vector<novatel_gps_msgs::InspvaPtr> inspva_msgs;
00791 gps_.GetInspvaMessages(inspva_msgs);
00792 for (const auto& msg : inspva_msgs)
00793 {
00794 msg->header.stamp += sync_offset;
00795 msg->header.frame_id = imu_frame_id_;
00796 inspva_pub_.publish(msg);
00797 }
00798
00799 std::vector<novatel_gps_msgs::InsstdevPtr> insstdev_msgs;
00800 gps_.GetInsstdevMessages(insstdev_msgs);
00801 for (const auto& msg : insstdev_msgs)
00802 {
00803 msg->header.stamp += sync_offset;
00804 msg->header.frame_id = imu_frame_id_;
00805 insstdev_pub_.publish(msg);
00806 }
00807 }
00808
00809 for (const auto& msg : fix_msgs)
00810 {
00811 msg->header.stamp += sync_offset;
00812 msg->header.frame_id = frame_id_;
00813 gps_pub_.publish(msg);
00814
00815 if (fix_pub_.getNumSubscribers() > 0)
00816 {
00817 sensor_msgs::NavSatFixPtr fix_msg = ConvertGpsFixToNavSatFix(msg);
00818
00819 fix_pub_.publish(fix_msg);
00820 }
00821
00822
00823
00824
00825 if (last_published_ != ros::TIME_MIN &&
00826 (msg->header.stamp - last_published_).toSec() > 1.5 * (1.0 / expected_rate_))
00827 {
00828 publish_rate_warnings_++;
00829 }
00830
00831 last_published_ = msg->header.stamp;
00832 }
00833 }
00834
00835 sensor_msgs::NavSatFixPtr ConvertGpsFixToNavSatFix(const gps_common::GPSFixPtr& msg)
00836 {
00837 sensor_msgs::NavSatFixPtr fix_msg = boost::make_shared<sensor_msgs::NavSatFix>();
00838 fix_msg->header = msg->header;
00839 fix_msg->latitude = msg->latitude;
00840 fix_msg->longitude = msg->longitude;
00841 fix_msg->altitude = msg->altitude;
00842 fix_msg->position_covariance = msg->position_covariance;
00843 switch (msg->status.status)
00844 {
00845 case gps_common::GPSStatus::STATUS_NO_FIX:
00846 fix_msg->status.status = sensor_msgs::NavSatStatus::STATUS_NO_FIX;
00847 break;
00848 case gps_common::GPSStatus::STATUS_FIX:
00849 fix_msg->status.status = sensor_msgs::NavSatStatus::STATUS_FIX;
00850 break;
00851 case gps_common::GPSStatus::STATUS_SBAS_FIX:
00852 fix_msg->status.status = sensor_msgs::NavSatStatus::STATUS_SBAS_FIX;
00853 break;
00854 case gps_common::GPSStatus::STATUS_GBAS_FIX:
00855 fix_msg->status.status = sensor_msgs::NavSatStatus::STATUS_GBAS_FIX;
00856 break;
00857 case gps_common::GPSStatus::STATUS_DGPS_FIX:
00858 case gps_common::GPSStatus::STATUS_WAAS_FIX:
00859 default:
00860 ROS_WARN_ONCE("Unsupported fix status: %d", msg->status.status);
00861 fix_msg->status.status = sensor_msgs::NavSatStatus::STATUS_FIX;
00862 break;
00863 }
00864 switch (msg->position_covariance_type)
00865 {
00866 case gps_common::GPSFix::COVARIANCE_TYPE_KNOWN:
00867 fix_msg->position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_KNOWN;
00868 break;
00869 case gps_common::GPSFix::COVARIANCE_TYPE_APPROXIMATED:
00870 fix_msg->position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_APPROXIMATED;
00871 break;
00872 case gps_common::GPSFix::COVARIANCE_TYPE_DIAGONAL_KNOWN:
00873 fix_msg->position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
00874 break;
00875 case gps_common::GPSFix::COVARIANCE_TYPE_UNKNOWN:
00876 fix_msg->position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
00877 break;
00878 default:
00879 ROS_WARN_ONCE("Unsupported covariance type: %d", msg->position_covariance_type);
00880 fix_msg->position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
00881 break;
00882 }
00883
00884 fix_msg->status.service = 0;
00885
00886 return fix_msg;
00887 }
00888
00893 void CalculateTimeSync()
00894 {
00895 boost::unique_lock<boost::mutex> lock(mutex_);
00896 int32_t synced_i = -1;
00897 int32_t synced_j = -1;
00898
00899 for (int32_t i = 0; i < sync_times_.size(); i++)
00900 {
00901
00902 for (int32_t j = synced_j + 1; j < msg_times_.size(); j++)
00903 {
00904
00905 double offset = (sync_times_[i] - msg_times_[j]).toSec();
00906 if (std::fabs(offset) < 0.49)
00907 {
00908
00909 synced_i = static_cast<int32_t>(i);
00910 synced_j = static_cast<int32_t>(j);
00911
00912 offset_stats_(offset);
00913 rolling_offset_(offset);
00914
00915 last_sync_ = sync_times_[i];
00916
00917 break;
00918 }
00919 }
00920 }
00921
00922
00923 for (int i = 0; i <= synced_i && !sync_times_.empty(); i++)
00924 {
00925 sync_times_.pop_front();
00926 }
00927
00928
00929 for (int j = 0; j <= synced_j && !msg_times_.empty(); j++)
00930 {
00931 msg_times_.pop_front();
00932 }
00933 }
00934
00935 void FixDiagnostic(diagnostic_updater::DiagnosticStatusWrapper &status)
00936 {
00937 status.clear();
00938 status.summary(diagnostic_msgs::DiagnosticStatus::OK, "Nominal");
00939
00940 if (!last_novatel_position_)
00941 {
00942 status.summary(diagnostic_msgs::DiagnosticStatus::WARN, "No Status");
00943 NODELET_WARN("No GPS status data.");
00944 return;
00945 }
00946
00947 status.add("Solution Status", last_novatel_position_->solution_status);
00948 status.add("Position Type", last_novatel_position_->position_type);
00949 status.add("Solution Age", last_novatel_position_->solution_age);
00950 status.add("Satellites Tracked", static_cast<int>(last_novatel_position_->num_satellites_tracked));
00951 status.add("Satellites Used", static_cast<int>(last_novatel_position_->num_satellites_used_in_solution));
00952 status.add("Software Version", last_novatel_position_->novatel_msg_header.receiver_software_version);
00953
00954 const novatel_gps_msgs::NovatelReceiverStatus& rcvr_status = last_novatel_position_->novatel_msg_header.receiver_status;
00955 status.add("Status Code", rcvr_status.original_status_code);
00956
00957 if (last_novatel_position_->novatel_msg_header.receiver_status.original_status_code != 0)
00958 {
00959 uint8_t level = diagnostic_msgs::DiagnosticStatus::WARN;
00960 std::string msg = "Status Warning";
00961
00962 if (rcvr_status.antenna_is_open ||
00963 rcvr_status.antenna_is_shorted ||
00964 !rcvr_status.antenna_powered)
00965 {
00966 msg += " Antenna Problem";
00967 level = diagnostic_msgs::DiagnosticStatus::ERROR;
00968 }
00969 status.add("Error Flag", rcvr_status.error_flag?"true":"false");
00970 status.add("Temperature Flag", rcvr_status.temperature_flag?"true":"false");
00971 status.add("Voltage Flag", rcvr_status.voltage_supply_flag?"true":"false");
00972 status.add("Antenna Not Powered", rcvr_status.antenna_powered?"false":"true");
00973 status.add("Antenna Open", rcvr_status.antenna_is_open?"true":"false");
00974 status.add("Antenna Shorted", rcvr_status.antenna_is_shorted?"true":"false");
00975 status.add("CPU Overloaded", rcvr_status.cpu_overload_flag?"true":"false");
00976 status.add("COM1 Buffer Overrun", rcvr_status.com1_buffer_overrun?"true":"false");
00977 status.add("COM2 Buffer Overrun", rcvr_status.com2_buffer_overrun?"true":"false");
00978 status.add("COM3 Buffer Overrun", rcvr_status.com3_buffer_overrun?"true":"false");
00979 status.add("USB Buffer Overrun", rcvr_status.usb_buffer_overrun?"true":"false");
00980 status.add("RF1 AGC Flag", rcvr_status.rf1_agc_flag?"true":"false");
00981 status.add("RF2 AGC Flag", rcvr_status.rf2_agc_flag?"true":"false");
00982 status.add("Almanac Flag", rcvr_status.almanac_flag?"true":"false");
00983 status.add("Position Solution Flag", rcvr_status.position_solution_flag?"true":"false");
00984 status.add("Position Fixed Flag", rcvr_status.position_fixed_flag?"true":"false");
00985 status.add("Clock Steering Status", rcvr_status.clock_steering_status_enabled?"true":"false");
00986 status.add("Clock Model Flag", rcvr_status.clock_model_flag?"true":"false");
00987 status.add("OEMV External Oscillator Flag", rcvr_status.oemv_external_oscillator_flag?"true":"false");
00988 status.add("Software Resource Flag", rcvr_status.software_resource_flag?"true":"false");
00989 status.add("Auxiliary1 Flag", rcvr_status.aux1_status_event_flag?"true":"false");
00990 status.add("Auxiliary2 Flag", rcvr_status.aux2_status_event_flag?"true":"false");
00991 status.add("Auxiliary3 Flag", rcvr_status.aux3_status_event_flag?"true":"false");
00992 NODELET_WARN("Novatel status code: %d", rcvr_status.original_status_code);
00993 status.summary(level, msg);
00994 }
00995 }
00996
00997 void SyncDiagnostic(diagnostic_updater::DiagnosticStatusWrapper &status)
00998 {
00999 status.summary(diagnostic_msgs::DiagnosticStatus::OK, "Nominal");
01000
01001 if (last_sync_ == ros::TIME_MIN)
01002 {
01003 status.summary(diagnostic_msgs::DiagnosticStatus::WARN, "No Sync");
01004 return;
01005 }
01006 else if (last_sync_ < ros::Time::now() - ros::Duration(10))
01007 {
01008 status.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Sync Stale");
01009 NODELET_ERROR("GPS time synchronization is stale.");
01010 }
01011
01012 status.add("Last Sync", last_sync_);
01013 status.add("Mean Offset", stats::mean(offset_stats_));
01014 status.add("Mean Offset (rolling)", stats::rolling_mean(rolling_offset_));
01015 status.add("Offset Variance", stats::variance(offset_stats_));
01016 status.add("Min Offset", stats::min(offset_stats_));
01017 status.add("Max Offset", stats::max(offset_stats_));
01018 }
01019
01020 void DeviceDiagnostic(diagnostic_updater::DiagnosticStatusWrapper &status)
01021 {
01022 status.summary(diagnostic_msgs::DiagnosticStatus::OK, "Nominal");
01023
01024 if (device_errors_ > 0)
01025 {
01026 status.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Device Errors");
01027 }
01028 else if (device_interrupts_ > 0)
01029 {
01030 status.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Device Interrupts");
01031 NODELET_WARN("device interrupts detected <%s:%s>: %d",
01032 connection_type_.c_str(), device_.c_str(), device_interrupts_);
01033 }
01034 else if (device_timeouts_)
01035 {
01036 status.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Device Timeouts");
01037 NODELET_WARN("device timeouts detected <%s:%s>: %d",
01038 connection_type_.c_str(), device_.c_str(), device_timeouts_);
01039 }
01040
01041 status.add("Errors", device_errors_);
01042 status.add("Interrupts", device_interrupts_);
01043 status.add("Timeouts", device_timeouts_);
01044
01045 device_timeouts_ = 0;
01046 device_interrupts_ = 0;
01047 device_errors_ = 0;
01048 }
01049
01050 void GpsDiagnostic(diagnostic_updater::DiagnosticStatusWrapper &status)
01051 {
01052 status.summary(diagnostic_msgs::DiagnosticStatus::OK, "Nominal");
01053
01054 if (gps_parse_failures_ > 0)
01055 {
01056 status.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Parse Failures");
01057 NODELET_WARN("gps parse failures detected <%s>: %d",
01058 hw_id_.c_str(), gps_parse_failures_);
01059 }
01060
01061 status.add("Parse Failures", gps_parse_failures_);
01062 status.add("Insufficient Data Warnings", gps_insufficient_data_warnings_);
01063
01064 gps_parse_failures_ = 0;
01065 gps_insufficient_data_warnings_ = 0;
01066 }
01067
01068 void DataDiagnostic(diagnostic_updater::DiagnosticStatusWrapper &status)
01069 {
01070 status.summary(diagnostic_msgs::DiagnosticStatus::OK, "Nominal");
01071
01072 double period = diagnostic_updater_.getPeriod();
01073 double measured_rate = measurement_count_ / period;
01074
01075 if (measured_rate < 0.5 * expected_rate_)
01076 {
01077 status.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Insufficient Data Rate");
01078 NODELET_ERROR("insufficient data rate <%s>: %lf < %lf",
01079 hw_id_.c_str(), measured_rate, expected_rate_);
01080 }
01081 else if (measured_rate < 0.95 * expected_rate_)
01082 {
01083 status.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Insufficient Data Rate");
01084 NODELET_WARN("insufficient data rate <%s>: %lf < %lf",
01085 hw_id_.c_str(), measured_rate, expected_rate_);
01086 }
01087
01088 status.add("Measurement Rate (Hz)", measured_rate);
01089
01090 measurement_count_ = 0;
01091 }
01092
01093 void RateDiagnostic(diagnostic_updater::DiagnosticStatusWrapper &status)
01094 {
01095 status.summary(diagnostic_msgs::DiagnosticStatus::OK, "Nominal Publish Rate");
01096
01097 double elapsed = (ros::Time::now() - last_published_).toSec();
01098 bool gap_detected = false;
01099 if (elapsed > 2.0 / expected_rate_)
01100 {
01101 publish_rate_warnings_++;
01102 gap_detected = true;
01103 }
01104
01105 if (publish_rate_warnings_ > 1 || gap_detected)
01106 {
01107 status.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Insufficient Publish Rate");
01108 NODELET_WARN("publish rate failures detected <%s>: %d",
01109 hw_id_.c_str(), publish_rate_warnings_);
01110 }
01111
01112 status.add("Warnings", publish_rate_warnings_);
01113
01114 publish_rate_warnings_ = 0;
01115 }
01116 };
01117 }
01118
01119
01120 #include <swri_nodelet/class_list_macros.h>
01121 SWRI_NODELET_EXPORT_CLASS(novatel_gps_driver, NovatelGpsNodelet)