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
00030
00031
00032
00033
00034 #include <algorithm>
00035 #include <ros/ros.h>
00036 #include <nodelet/nodelet.h>
00037 #include <pluginlib/class_list_macros.h>
00038 #include <diagnostic_updater/diagnostic_updater.h>
00039 #include <diagnostic_updater/update_functions.h>
00040 #include <string>
00041 #include <angles/angles.h>
00042 #include <tf/tf.h>
00043 #include <tf/transform_listener.h>
00044 #include <tf/transform_datatypes.h>
00045 #include <nav_msgs/Odometry.h>
00046 #include <Eigen/Eigen>
00047
00048 using namespace std;
00049
00050 namespace flyer_est
00051 {
00052
00053
00054 const double VEL_FILT_A = 0.9;
00055 const double VEL_FILT_B = 0.1;
00056
00057 class Estimator : public nodelet::Nodelet
00058 {
00059 private:
00060 ros::NodeHandle nh;
00061 ros::NodeHandle nh_priv;
00062
00063 diagnostic_updater::Updater diag_updater;
00064 double min_freq;
00065 double max_freq;
00066 diagnostic_updater::FrequencyStatus freq_status;
00067
00068 string transform_topic;
00069 double freq;
00070 double xy_vel_filt_a;
00071 double xy_vel_filt_b;
00072 double z_vel_filt_a;
00073 double z_vel_filt_b;
00074 double ang_vel_filt_a;
00075 double ang_vel_filt_b;
00076 bool use_udp_for_transform_subscriber;
00077
00078 ros::Publisher output_pub;
00079
00080 ros::Subscriber transform_sub;
00081
00082 tf::TransformListener tf_listener;
00083
00084 ros::Timer main_timer;
00085 ros::Timer get_transforms_timer;
00086
00087 string flyer_imu_tf_node;
00088 string flyer_vicon_tf_node;
00089 bool got_first_transform;
00090 double last_transform_age;
00091 tf::StampedTransform last_transform;
00092 tf::StampedTransform T_flyer_vicon__flyer_imu;
00093 tf::StampedTransform T_enu__ned;
00094 nav_msgs::Odometry state_msg;
00095 tf::Quaternion prev_quat;
00096 Eigen::Vector4d prev_quat_deriv;
00097 boost::mutex state_mutex;
00098 bool main_cb_first_time;
00099 double max_dt;
00100 bool got_new_measurement;
00101 int published_without_new_measurement_count;
00102 int max_published_without_new_measurement;
00103
00104 public:
00105 EIGEN_MAKE_ALIGNED_OPERATOR_NEW Estimator() :
00106 diag_updater(), min_freq(40), max_freq(60), freq_status(
00107 diagnostic_updater::FrequencyStatusParam(&min_freq, &max_freq)),
00108 transform_topic("vicon_recv_direct/output"), freq(50),
00109 xy_vel_filt_a(0.9), xy_vel_filt_b(0.1),
00110 z_vel_filt_a(0.9), z_vel_filt_b(0.1),
00111 ang_vel_filt_a(0.9), ang_vel_filt_b(0.1),
00112 use_udp_for_transform_subscriber(false),
00113 got_first_transform(false), prev_quat_deriv(0, 0, 0, 0), main_cb_first_time(true), max_dt(0),
00114 got_new_measurement(false), published_without_new_measurement_count(0), max_published_without_new_measurement(0)
00115 {
00116 }
00117
00118 void onInit()
00119 {
00120 nh = getMTNodeHandle();
00121 nh_priv = getMTPrivateNodeHandle();
00122
00123
00124 diag_updater.add("Estimator Status", this, &Estimator::diagnostics);
00125 diag_updater.add(freq_status);
00126 diag_updater.setHardwareID("none");
00127 diag_updater.force_update();
00128
00129 nh_priv.param("transform_topic", transform_topic, transform_topic);
00130 nh_priv.param("freq", freq, freq);
00131 nh_priv.param("xy_vel_filt_a", xy_vel_filt_a, xy_vel_filt_a);
00132 nh_priv.param("xy_vel_filt_b", xy_vel_filt_b, xy_vel_filt_b);
00133 nh_priv.param("z_vel_filt_a", z_vel_filt_a, z_vel_filt_a);
00134 nh_priv.param("z_vel_filt_b", z_vel_filt_b, z_vel_filt_b);
00135 nh_priv.param("ang_vel_filt_a", ang_vel_filt_a, ang_vel_filt_a);
00136 nh_priv.param("ang_vel_filt_b", ang_vel_filt_a, ang_vel_filt_a);
00137 nh_priv.param("use_udp_for_transform_subscriber", use_udp_for_transform_subscriber,
00138 use_udp_for_transform_subscriber);
00139 min_freq = freq * 0.9;
00140 max_freq = freq * 1.1;
00141
00142 output_pub = nh_priv.advertise<nav_msgs::Odometry>("output", 10);
00143
00144 flyer_imu_tf_node = ros::this_node::getNamespace() + "/flyer_imu";
00145 flyer_vicon_tf_node = ros::this_node::getNamespace() + "/flyer_vicon";
00146
00147
00148 if (flyer_imu_tf_node.substr(0, 2) == "//")
00149 flyer_imu_tf_node = flyer_imu_tf_node.substr(1, flyer_imu_tf_node.size() - 1);
00150 if (flyer_vicon_tf_node.substr(0, 2) == "//")
00151 flyer_vicon_tf_node = flyer_vicon_tf_node.substr(1, flyer_vicon_tf_node.size() - 1);
00152 get_transforms_timer = nh.createTimer(ros::Duration(0.01), boost::bind(&Estimator::getTransforms, this, _1), true);
00153 }
00154
00155 void getTransforms(const ros::TimerEvent& event)
00156 {
00157 ROS_INFO("Looking up flyer_vicon --> flyer_imu transform");
00158 ROS_INFO_STREAM(
00159 "flyer_imu_tf_node = '" << flyer_imu_tf_node <<"', flyer_vicon_tf_node = '" << flyer_vicon_tf_node << "'");
00160
00161 bool gotit = false;
00162 ros::Duration waiter(0.5);
00163 while (!gotit)
00164 {
00165 try
00166 {
00167 tf_listener.lookupTransform(flyer_vicon_tf_node, flyer_imu_tf_node, ros::Time(0), T_flyer_vicon__flyer_imu);
00168 tf_listener.lookupTransform("/enu", "/ned", ros::Time(0), T_enu__ned);
00169 gotit = true;
00170 }
00171 catch (tf::TransformException& ex)
00172 {
00173 ROS_ERROR("Exception looking up transform: %s", ex.what());
00174 }
00175 waiter.sleep();
00176 }
00177 ROS_INFO_STREAM(
00178 "Got flyer_vicon --> flyer_imu transform: " << T_flyer_vicon__flyer_imu.getOrigin().getX() << " " << T_flyer_vicon__flyer_imu.getOrigin().getY() << " " << T_flyer_vicon__flyer_imu.getOrigin().getZ());
00179 ROS_INFO_STREAM(
00180 "Got /enu --> /ned transform: " << T_enu__ned.getOrigin().getX() << " " << T_enu__ned.getOrigin().getY() << " " << T_enu__ned.getOrigin().getZ());
00181
00182 if (use_udp_for_transform_subscriber)
00183 {
00184 transform_sub = nh.subscribe(transform_topic, 1, &Estimator::transformCallback, this,
00185 ros::TransportHints().unreliable().tcpNoDelay());
00186 }
00187 else
00188 {
00189 transform_sub = nh.subscribe(transform_topic, 1, &Estimator::transformCallback, this,
00190 ros::TransportHints().tcpNoDelay());
00191 }
00192
00193 main_timer = nh.createTimer(ros::Duration(1 / freq), &Estimator::mainCallback, this);
00194 }
00195
00196 private:
00197 void transformCallback(const geometry_msgs::TransformStampedConstPtr& msg)
00198 {
00199 boost::mutex::scoped_lock(state_mutex);
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216 static ros::Time prev_stamp = ros::Time::now();
00217 tf::StampedTransform T_enu__flyer_vicon;
00218 tf::transformStampedMsgToTF(*msg, T_enu__flyer_vicon);
00219 tf::StampedTransform T_ned_imu;
00220 T_ned_imu.setData(T_enu__ned.inverse() * T_enu__flyer_vicon * T_flyer_vicon__flyer_imu);
00221 T_ned_imu.stamp_ = (*msg).header.stamp;
00222
00223
00224
00225
00226
00227 last_transform_age = (T_ned_imu.stamp_ - ros::Time::now()).toSec() * 1000;
00228 double dt = (T_ned_imu.stamp_ - prev_stamp).toSec();
00229 got_new_measurement = true;
00230 max_dt = max(dt*1000, max_dt);
00231 if (dt > 0.001)
00232 {
00233 tf::Vector3 trans = T_ned_imu.getOrigin();
00234 state_msg.pose.pose.position.x = trans[0];
00235 state_msg.pose.pose.position.y = trans[1];
00236 state_msg.pose.pose.position.z = trans[2];
00237 tf::Quaternion quat = T_ned_imu.getRotation();
00238 state_msg.pose.pose.orientation.w = quat.getW();
00239 state_msg.pose.pose.orientation.x = quat.getX();
00240 state_msg.pose.pose.orientation.y = quat.getY();
00241 state_msg.pose.pose.orientation.z = quat.getZ();
00242 freq_status.tick();
00243 calcVelocity(state_msg.pose.pose.position.x, state_msg.pose.pose.position.y, state_msg.pose.pose.position.z, dt,
00244 state_msg.twist.twist.linear.x, state_msg.twist.twist.linear.y, state_msg.twist.twist.linear.z);
00245 Eigen::Vector4d new_quat_deriv(0, 0, 0, 0);
00246 Eigen::Vector3d new_ang_vel(0, 0, 0);
00247 if (!got_first_transform)
00248 prev_quat = quat;
00249 calcAngularVelocity(quat, prev_quat, prev_quat_deriv, dt, new_quat_deriv, new_ang_vel);
00250 prev_quat = quat;
00251 prev_quat_deriv = new_quat_deriv;
00252 state_msg.twist.twist.angular.x = new_ang_vel[0];
00253 state_msg.twist.twist.angular.y = new_ang_vel[1];
00254 state_msg.twist.twist.angular.z = new_ang_vel[2];
00255 state_msg.header.stamp = T_ned_imu.stamp_;
00256 }
00257 else
00258 {
00259 ROS_WARN_STREAM("dt too small: " << dt);
00260 }
00261
00262 prev_stamp = T_ned_imu.stamp_;
00263 if (!got_first_transform)
00264 got_first_transform = true;
00265 }
00266
00267 void diagnostics(diagnostic_updater::DiagnosticStatusWrapper& stat)
00268 {
00269 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "OK");
00270 stat.add("Got TF data", got_first_transform);
00271 stat.add("Last transform age [ms]", last_transform_age);
00272 stat.add("Maximum dt [ms]", max_dt);
00273 stat.add("Max # state msg published w/o new measurement", max_published_without_new_measurement);
00274 }
00275
00276
00277 void calcAngularVelocity(const tf::Quaternion& cur_quat, const tf::Quaternion& prev_quat,
00278 const Eigen::Vector4d& prev_quat_deriv, const double dt,
00279 Eigen::Vector4d& new_quat_deriv, Eigen::Vector3d& new_ang_vel)
00280 {
00281
00282 if (dt > 0.0001)
00283 {
00284 double mult = 1.0;
00285 if (cur_quat.w() * prev_quat.w() < 0)
00286 {
00287 NODELET_INFO("quat w's (cur, prev) = %f %f", cur_quat.w(), prev_quat.w());
00288 mult = -1.0;
00289 }
00290 tf::Quaternion temp = (cur_quat * mult - prev_quat) * ang_vel_filt_a / dt + prev_quat * ang_vel_filt_b;
00291 new_quat_deriv << temp.w(), temp.x(), temp.y(), temp.z();
00292 }
00293 else
00294 {
00295 ROS_WARN_STREAM("dt too small: " << dt);
00296 new_quat_deriv = prev_quat_deriv;
00297 }
00298
00299
00300
00301 Eigen::Matrix<double, 3, 4> W;
00302 W << -cur_quat.x(), cur_quat.w(), -cur_quat.z(), cur_quat.y(),
00303 -cur_quat.y(), cur_quat.z(), cur_quat.w(), -cur_quat.x(),
00304 -cur_quat.z(), -cur_quat.y(), cur_quat.x(), cur_quat.w();
00305 new_ang_vel = 2 * W * new_quat_deriv;
00306 }
00307
00308 void calcVelocity(const double& current_x, const double& current_y, const double& current_z, const double dt,
00309 double& new_vx, double& new_vy, double& new_vz)
00310 {
00311 static double prev_x, prev_y, prev_z;
00312 static double prev_vx = 0, prev_vy = 0, prev_vz = 0;
00313 static bool first = true;
00314 if (first)
00315 {
00316 new_vx = new_vy = new_vz = 0;
00317 first = false;
00318 }
00319 else
00320 {
00321 if (dt > 0.0001)
00322 {
00323 new_vx = xy_vel_filt_a * (current_x - prev_x) / dt + xy_vel_filt_b * prev_vx;
00324 new_vy = xy_vel_filt_a * (current_y - prev_y) / dt + xy_vel_filt_b * prev_vy;
00325 new_vz = z_vel_filt_a * (current_z - prev_z) / dt + z_vel_filt_b * prev_vz;
00326 }
00327 else
00328 {
00329 ROS_WARN_STREAM("dt too small: " << dt);
00330 new_vx = prev_vx;
00331 new_vy = prev_vy;
00332 new_vz = prev_vz;
00333 }
00334 }
00335 prev_x = current_x;
00336 prev_y = current_y;
00337 prev_z = current_z;
00338 prev_vx = new_vx;
00339 prev_vy = new_vy;
00340 prev_vz = new_vz;
00341
00342 }
00343
00344 void mainCallback(const ros::TimerEvent& e)
00345 {
00346
00347 if (!got_first_transform)
00348 {
00349 if (main_cb_first_time)
00350 {
00351 ROS_INFO_STREAM(
00352 "Waiting for transforms from /ned to " << flyer_vicon_tf_node << " on topic " << transform_topic);
00353 main_cb_first_time = false;
00354 }
00355 }
00356 else
00357 {
00358 nav_msgs::OdometryPtr state_msg_ptr(new nav_msgs::Odometry);
00359 {
00360 boost::mutex::scoped_lock(state_mutex);
00361 *state_msg_ptr = state_msg;
00362 if (got_new_measurement)
00363 {
00364 got_new_measurement = false;
00365 published_without_new_measurement_count = 0;
00366 }
00367 else
00368 {
00369 published_without_new_measurement_count++;
00370 max_published_without_new_measurement = max(published_without_new_measurement_count,
00371 max_published_without_new_measurement);
00372 }
00373 }
00374 output_pub.publish(state_msg_ptr);
00375 }
00376
00377 diag_updater.update();
00378
00379 }
00380 };
00381 PLUGINLIB_DECLARE_CLASS(flyer_est, Estimator, flyer_est::Estimator, nodelet::Nodelet);
00382
00383 }
00384
00385
00386
00387
00388
00389
00390
00391
00392