00001
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
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
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 ) {
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
00216 sensor_msgs::TimeReferencePtr time_unix = boost::make_shared<sensor_msgs::TimeReference>();
00217 ros::Time time_ref(
00218 mtime.time_unix_usec / 1000000,
00219 (mtime.time_unix_usec % 1000000) * 1000);
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
00232 std_msgs::DurationPtr offset = boost::make_shared<std_msgs::Duration>();
00233 ros::Duration time_ref(
00234 time_offset_us / 1000000,
00235 (time_offset_us % 1000000) * 1000);
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;
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 };
00257
00258 PLUGINLIB_EXPORT_CLASS(mavplugin::SystemTimePlugin, mavplugin::MavRosPlugin)