sys_time.cpp
Go to the documentation of this file.
00001 
00009 /*
00010  * Copyright 2013 Vladimir Ermakov.
00011  *
00012  * This program is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 3 of the License, or
00015  * (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful, but
00018  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00019  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00020  * for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License along
00023  * with this program; if not, write to the Free Software Foundation, Inc.,
00024  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00025  */
00026 
00027 #include <mavros/mavros_plugin.h>
00028 #include <pluginlib/class_list_macros.h>
00029 
00030 #include <sensor_msgs/TimeReference.h>
00031 #include <std_msgs/Duration.h>
00032 
00033 namespace mavplugin {
00034 
00040 class TimeSyncStatus : public diagnostic_updater::DiagnosticTask
00041 {
00042 public:
00043         TimeSyncStatus(const std::string name, size_t win_size) :
00044                 diagnostic_updater::DiagnosticTask(name),
00045                 window_size_(win_size),
00046                 min_freq_(0.01),
00047                 max_freq_(10),
00048                 tolerance_(0.1),
00049                 times_(win_size),
00050                 seq_nums_(win_size),
00051                 last_dt(0),
00052                 dt_sum(0)
00053         {
00054                 clear();
00055         }
00056 
00057         void clear() {
00058                 lock_guard lock(mutex);
00059                 ros::Time curtime = ros::Time::now();
00060                 count_ = 0;
00061                 dt_sum = 0;
00062 
00063                 for (int i = 0; i < window_size_; i++)
00064                 {
00065                         times_[i] = curtime;
00066                         seq_nums_[i] = count_;
00067                 }
00068 
00069                 hist_indx_ = 0;
00070         }
00071 
00072         void tick(int64_t dt, uint64_t timestamp_us) {
00073                 lock_guard lock(mutex);
00074                 count_++;
00075                 last_dt = dt;
00076                 dt_sum += dt;
00077                 last_ts = timestamp_us;
00078         }
00079 
00080         void set_timestamp(uint64_t timestamp_us) {
00081                 lock_guard lock(mutex);
00082                 last_ts = timestamp_us;
00083         }
00084 
00085         void run(diagnostic_updater::DiagnosticStatusWrapper &stat) {
00086                 lock_guard lock(mutex);
00087                 ros::Time curtime = ros::Time::now();
00088                 int curseq = count_;
00089                 int events = curseq - seq_nums_[hist_indx_];
00090                 double window = (curtime - times_[hist_indx_]).toSec();
00091                 double freq = events / window;
00092                 seq_nums_[hist_indx_] = curseq;
00093                 times_[hist_indx_] = curtime;
00094                 hist_indx_ = (hist_indx_ + 1) % window_size_;
00095 
00096                 if (events == 0) {
00097                         stat.summary(2, "No events recorded.");
00098                 }
00099                 else if (freq < min_freq_ * (1 - tolerance_)) {
00100                         stat.summary(1, "Frequency too low.");
00101                 }
00102                 else if (freq > max_freq_ * (1 + tolerance_)) {
00103                         stat.summary(1, "Frequency too high.");
00104                 }
00105                 else {
00106                         stat.summary(0, "Normal");
00107                 }
00108 
00109                 stat.addf("Events in window", "%d", events);
00110                 stat.addf("Events since startup", "%d", count_);
00111                 stat.addf("Duration of window (s)", "%f", window);
00112                 stat.addf("Actual frequency (Hz)", "%f", freq);
00113                 stat.addf("Last dt (ms)", "%0.3f", last_dt / 1000.0);
00114                 stat.addf("Mean dt (ms)", "%0.3f", (count_)? dt_sum / count_ / 1000.0 : 0.0);
00115                 stat.addf("Last system time (s)", "%0.6f", last_ts / 1e6);
00116         }
00117 
00118 private:
00119         int count_;
00120         std::vector<ros::Time> times_;
00121         std::vector<int> seq_nums_;
00122         int hist_indx_;
00123         std::recursive_mutex mutex;
00124         const size_t window_size_;
00125         const double min_freq_;
00126         const double max_freq_;
00127         const double tolerance_;
00128         int64_t last_dt;
00129         int64_t dt_sum;
00130         uint64_t last_ts;
00131 };
00132 
00133 
00134 
00135 class SystemTimePlugin : public MavRosPlugin {
00136 public:
00137         SystemTimePlugin():
00138                 uas(nullptr),
00139                 dt_diag("Time Sync", 10),
00140                 time_offset_us(0)
00141         {};
00142 
00143         void initialize(UAS &uas_,
00144                         ros::NodeHandle &nh,
00145                         diagnostic_updater::Updater &diag_updater)
00146         {
00147                 double conn_system_time_d;
00148 
00149                 uas = &uas_;
00150 
00151                 nh.param("conn_system_time", conn_system_time_d, 0.0);
00152                 nh.param<std::string>("frame_id", frame_id, "fcu");
00153                 nh.param<std::string>("time_ref_source", time_ref_source, frame_id);
00154 
00155                 diag_updater.add(dt_diag);
00156 
00157                 time_ref_pub = nh.advertise<sensor_msgs::TimeReference>("time_reference", 10);
00158                 time_offset_pub = nh.advertise<std_msgs::Duration>("time_offset", 10);
00159 
00160                 // timer for sending time sync messages
00161                 if (conn_system_time_d > 0.0) {
00162                         sys_time_timer = nh.createTimer(ros::Duration(conn_system_time_d),
00163                                         &SystemTimePlugin::sys_time_cb, this);
00164                         sys_time_timer.start();
00165                 }
00166         }
00167 
00168 
00169         std::string const get_name() const {
00170                 return "SystemTime";
00171         }
00172 
00173         const message_map get_rx_handlers() {
00174                 return {
00175                         MESSAGE_HANDLER(MAVLINK_MSG_ID_SYSTEM_TIME, &SystemTimePlugin::handle_system_time),
00176                 };
00177         }
00178 
00179 private:
00180         UAS *uas;
00181         ros::Publisher time_ref_pub;
00182         ros::Publisher time_offset_pub;
00183         ros::Timer sys_time_timer;
00184         TimeSyncStatus dt_diag;
00185 
00186         std::string frame_id;
00187         std::string time_ref_source;
00188         uint64_t time_offset_us;
00189 
00190         void handle_system_time(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
00191                 mavlink_system_time_t mtime;
00192                 mavlink_msg_system_time_decode(msg, &mtime);
00193 
00194                 uint64_t now_ms = ros::Time::now().toNSec() / 1000000;
00195 
00196                 // date -d @1234567890: Sat Feb 14 02:31:30 MSK 2009
00197                 const bool fcu_time_valid = mtime.time_unix_usec > 1234567890ULL * 1000000;
00198                 const bool ros_time_valid = now_ms > 1234567890ULL * 1000;
00199 
00200                 int64_t offset_us = (now_ms - mtime.time_boot_ms) * 1000;
00201                 int64_t dt = offset_us - time_offset_us;
00202                 if (std::abs(dt) > 2000000 /* microseconds */) {
00203                         ROS_WARN_THROTTLE_NAMED(10, "time", "TM: Large clock skew detected (%0.6f s). "
00204                                         "Resyncing clocks.", dt / 1e6);
00205                         time_offset_us = offset_us;
00206                         dt_diag.clear();
00207                         dt_diag.set_timestamp(mtime.time_unix_usec);
00208                 }
00209                 else {
00210                         time_offset_us = (time_offset_us + offset_us) / 2;
00211                         dt_diag.tick(dt, mtime.time_unix_usec);
00212                 }
00213 
00214                 if (fcu_time_valid) {
00215                         // continious publish for ntpd
00216                         sensor_msgs::TimeReferencePtr time_unix = boost::make_shared<sensor_msgs::TimeReference>();
00217                         ros::Time time_ref(
00218                                         mtime.time_unix_usec / 1000000,                 // t_sec
00219                                         (mtime.time_unix_usec % 1000000) * 1000);       // t_nsec
00220 
00221                         time_unix->source = time_ref_source;
00222                         time_unix->time_ref = time_ref;
00223                         time_unix->header.stamp = ros::Time::now();
00224 
00225                         time_ref_pub.publish(time_unix);
00226                 }
00227                 else {
00228                         ROS_WARN_THROTTLE_NAMED(60, "time", "TM: Wrong GPS time.");
00229                 }
00230 
00231                 // offset publisher
00232                 std_msgs::DurationPtr offset = boost::make_shared<std_msgs::Duration>();
00233                 ros::Duration time_ref(
00234                                 time_offset_us / 1000000,               // t_sec
00235                                 (time_offset_us % 1000000) * 1000);     // t_nsec
00236 
00237                 offset->data = time_ref;
00238 
00239                 uas->set_time_offset(time_offset_us);
00240                 time_offset_pub.publish(offset);
00241         }
00242 
00243         void sys_time_cb(const ros::TimerEvent &event) {
00244                 mavlink_message_t msg;
00245 
00246                 uint64_t time_unix_usec = ros::Time::now().toNSec() / 1000;  // nano -> micro
00247 
00248                 mavlink_msg_system_time_pack_chan(UAS_PACK_CHAN(uas), &msg,
00249                                 time_unix_usec,
00250                                 0
00251                                 );
00252                 UAS_FCU(uas)->send_message(&msg);
00253         }
00254 };
00255 
00256 }; // namespace mavplugin
00257 
00258 PLUGINLIB_EXPORT_CLASS(mavplugin::SystemTimePlugin, mavplugin::MavRosPlugin)


mavros
Author(s): Vladimir Ermakov
autogenerated on Wed Aug 26 2015 12:29:13