odom.cpp
Go to the documentation of this file.
1 
10 /*
11  * Copyright 2017 James Goppert
12  * Copyright 2017,2018 Nuno Marques
13  *
14  * This file is part of the mavros package and subject to the license terms
15  * in the top-level LICENSE file of the mavros repository.
16  * https://github.com/mavlink/mavros/tree/master/LICENSE.md
17  */
18 
19 #include <mavros/mavros_plugin.h>
20 #include <tf2_eigen/tf2_eigen.h>
21 #include <boost/algorithm/string.hpp>
22 
23 #include <nav_msgs/Odometry.h>
24 #include <geometry_msgs/TransformStamped.h>
25 
26 namespace mavros {
27 namespace extra_plugins {
28 using mavlink::common::MAV_FRAME;
29 using Matrix6d = Eigen::Matrix<double, 6, 6, Eigen::RowMajor>;
30 
38 public:
39  EIGEN_MAKE_ALIGNED_OPERATOR_NEW // XXX(vooon): added to try to fix #1223. Not sure that it is needed because class do not have Eigen:: fields.
40 
42  odom_nh("~odometry"),
45  child_frame_id("base_link"),
46  frame_id("odom"),
47  local_frame_in("local_origin_ned"),
48  local_frame_out("vision_ned")
49  { }
50 
51  void initialize(UAS &uas_)
52  {
54 
55  odom_nh.param<std::string>("frame_id", frame_id, "odom");
56  odom_nh.param<std::string>("child_frame_id", child_frame_id, "base_link");
57 
58  // frame tf params:
59  odom_nh.param<std::string>("in/frame_tf/local_frame", local_frame_in, "local_origin_ned");
60  odom_nh.param<std::string>("out/frame_tf/local_frame", local_frame_out, "vision_ned");
61  odom_nh.param<std::string>("in/frame_tf/body_frame_orientation", body_frame_orientation_in_desired, "flu");
62  odom_nh.param<std::string>("out/frame_tf/body_frame_orientation", body_frame_orientation_out_desired, "frd");
63 
64  boost::algorithm::to_lower(local_frame_out);
65  boost::algorithm::to_lower(body_frame_orientation_out_desired);
66 
67  // publishers
68  odom_pub = odom_nh.advertise<nav_msgs::Odometry>("in", 10);
69 
70  // subscribers
72 
74  const std::unordered_map<std::string, MAV_FRAME> lf_map {
75  { "vision_enu", MAV_FRAME::VISION_ENU },
76  { "vision_ned", MAV_FRAME::VISION_NED },
77  { "mocap_enu", MAV_FRAME::MOCAP_ENU },
78  { "mocap_ned", MAV_FRAME::MOCAP_NED }
79  };
80 
82  const std::unordered_map<std::string, MAV_FRAME> bf_map {
83  { "ned", MAV_FRAME::BODY_NED },
84  { "frd", MAV_FRAME::BODY_FRD },
85  { "flu", MAV_FRAME::BODY_FLU }
86  };
87 
88  // Determine input frame_id naming
89  if (local_frame_in == "local_origin_ned")
91  else
92  ROS_FATAL_NAMED("odom", "ODOM: invalid input local frame \"%s\"", local_frame_in.c_str());
93 
94  // Determine output frame_id naming - considering the ROS msg frame_id
95  // as "odom" by default
96  auto lf_it = lf_map.find(local_frame_out);
97  if (lf_it != lf_map.end()) {
98  lf_id = lf_it->second;
99  auto orient = local_frame_out.substr(local_frame_out.length() - 3);
100  if (orient != "enu") {
101  local_frame_orientation_out = "local_origin_" + orient;
102  } else {
103  local_frame_orientation_out = "local_origin";
104  }
105  }
106  else
107  ROS_FATAL_NAMED("odom", "ODOM: invalid ouput local frame \"%s\"", local_frame_out.c_str());
108 
109  // Determine input child_frame_id naming
110  auto bf_it_in = bf_map.find(body_frame_orientation_in_desired);
111  if (bf_it_in != bf_map.end()) {
112  if (body_frame_orientation_in_desired != "flu")
113  body_frame_orientation_in_desired = "fcu_" + body_frame_orientation_in_desired;
114  else
115  body_frame_orientation_in_desired = "fcu";
116  }
117  else
118  ROS_FATAL_NAMED("odom", "ODOM: invalid input body frame orientation \"%s\"", body_frame_orientation_in_desired.c_str());
119 
120  // Determine output child_frame_id naming
121  auto bf_it = bf_map.find(body_frame_orientation_out_desired);
122  if (bf_it != bf_map.end()) {
123  bf_id = bf_it->second;
124  if (body_frame_orientation_out_desired != "flu")
125  body_frame_orientation_out_desired = "fcu_" + body_frame_orientation_out_desired;
126  else
127  body_frame_orientation_in_desired = "fcu";
128  }
129  else
130  ROS_FATAL_NAMED("odom", "ODOM: invalid output body frame orientation \"%s\"", body_frame_orientation_out_desired.c_str());
131  }
132 
134  {
135  return {
137  };
138  }
139 
140 private:
144 
145  std::string local_frame_in;
146  std::string local_frame_out;
151  std::string frame_id;
152  std::string child_frame_id;
153 
156 
170  void transform_lookup(const std::string &frame_id, const std::string &child_frame_id,
171  const std::string &local_frame_orientation, const std::string &body_frame_orientation,
172  Eigen::Affine3d &tf_parent2local, Eigen::Affine3d &tf_child2local,
173  Eigen::Affine3d &tf_parent2body, Eigen::Affine3d &tf_child2body)
174  {
175  try {
176  // transform lookup WRT local frame
178  frame_id, local_frame_orientation,
179  ros::Time(0)));
181  child_frame_id, local_frame_orientation,
182  ros::Time(0)));
183 
184  // transform lookup WRT body frame
186  frame_id, body_frame_orientation,
187  ros::Time(0)));
189  child_frame_id, body_frame_orientation,
190  ros::Time(0)));
191  } catch (tf2::TransformException &ex) {
192  ROS_ERROR_THROTTLE_NAMED(1, "odom", "ODOM: Ex: %s", ex.what());
193  return;
194  }
195  }
196 
204  void handle_odom(const mavlink::mavlink_message_t *msg, mavlink::common::msg::ODOMETRY &odom_msg)
205  {
206  /*** Send fcu_frd <-> local_origin_ned transform ***/
207  geometry_msgs::TransformStamped transform;
208  transform.header.stamp = m_uas->synchronise_stamp(odom_msg.time_usec);
209  transform.header.frame_id = "local_origin_ned";
210  transform.child_frame_id = "fcu_frd";
211 
212  tf::vectorEigenToMsg(Eigen::Vector3d(odom_msg.x, odom_msg.y, odom_msg.z), transform.transform.translation);
213  tf::quaternionEigenToMsg(ftf::mavlink_to_quaternion(odom_msg.q), transform.transform.rotation);
214 
215  m_uas->tf2_broadcaster.sendTransform(transform);
216  /***************************************************/
217 
221  Eigen::Affine3d tf_parent2local;
222  Eigen::Affine3d tf_child2local;
223  Eigen::Affine3d tf_parent2body;
224  Eigen::Affine3d tf_child2body;
225 
227  transform_lookup("local_origin_ned", "fcu_frd",
228  local_frame_orientation_in, body_frame_orientation_in_desired,
229  tf_parent2local, tf_child2local, tf_parent2body, tf_child2body);
230 
232  Matrix6d cov_pose = Matrix6d::Zero();
233  ftf::mavlink_urt_to_covariance_matrix(odom_msg.pose_covariance, cov_pose);
234 
236  Matrix6d cov_vel = Matrix6d::Zero();
237  ftf::mavlink_urt_to_covariance_matrix(odom_msg.velocity_covariance, cov_vel);
238 
239  Eigen::Vector3d position {};
240  Eigen::Quaterniond orientation {};
241  Eigen::Vector3d lin_vel {};
242  Eigen::Vector3d ang_vel {};
243  Matrix6d r_pose = Matrix6d::Zero();
244  Matrix6d r_vel = Matrix6d::Zero();
245 
246  auto odom = boost::make_shared<nav_msgs::Odometry>();
247 
248  odom->header = m_uas->synchronized_header(frame_id, odom_msg.time_usec);
249  odom->child_frame_id = child_frame_id;
250 
254  position = Eigen::Vector3d(tf_parent2local.linear() * Eigen::Vector3d(odom_msg.x, odom_msg.y, odom_msg.z));
255  tf::pointEigenToMsg(position, odom->pose.pose.position);
256 
260  Eigen::Quaterniond q_parent2child(ftf::mavlink_to_quaternion(odom_msg.q));
261  Eigen::Affine3d tf_local2body = tf_parent2local * q_parent2child * tf_child2body.inverse();
262  orientation = Eigen::Quaterniond(tf_local2body.linear());
263  tf::quaternionEigenToMsg(orientation, odom->pose.pose.orientation);
264 
265  r_pose.block<3, 3>(0, 0) = r_pose.block<3, 3>(3, 3) = tf_parent2local.linear();
266 
271  auto set_tf = [&](Eigen::Affine3d affineTf) {
272  lin_vel = Eigen::Vector3d(affineTf.linear() * Eigen::Vector3d(odom_msg.vx, odom_msg.vy, odom_msg.vz));
273  ang_vel = Eigen::Vector3d(affineTf.linear() * Eigen::Vector3d(odom_msg.rollspeed, odom_msg.pitchspeed, odom_msg.yawspeed));
274  r_vel.block<3, 3>(0, 0) = r_vel.block<3, 3>(3, 3) = affineTf.linear();
275  };
276 
277  if (odom_msg.child_frame_id == odom_msg.frame_id) {
278  // the child_frame_id would be the same reference frame as frame_id
279  set_tf(tf_child2local);
280  }
281  else {
282  // the child_frame_id would be the WRT a body frame reference
283  set_tf(tf_child2body);
284  }
285 
286  tf::vectorEigenToMsg(lin_vel, odom->twist.twist.linear);
287  tf::vectorEigenToMsg(ang_vel, odom->twist.twist.angular);
288 
292  cov_pose = r_pose * cov_pose * r_pose.transpose();
294  Eigen::Map<Matrix6d>(odom->pose.covariance.data(), cov_pose.rows(), cov_pose.cols()) = cov_pose;
295 
297  cov_vel = r_vel * cov_vel * r_vel.transpose();
298  Eigen::Map<Matrix6d>(odom->twist.covariance.data(), cov_vel.rows(), cov_vel.cols()) = cov_vel;
299 
301  odom_pub.publish(odom);
302  }
303 
311  {
315  Eigen::Affine3d tf_parent2local;
316  Eigen::Affine3d tf_child2local;
317  Eigen::Affine3d tf_parent2body;
318  Eigen::Affine3d tf_child2body;
319 
321  transform_lookup(odom->header.frame_id, odom->child_frame_id,
322  local_frame_orientation_out, body_frame_orientation_out_desired,
323  tf_parent2local, tf_child2local, tf_parent2body, tf_child2body);
324 
326  ftf::Covariance6d cov_pose = odom->pose.covariance;
327  ftf::EigenMapCovariance6d cov_pose_map(cov_pose.data());
328 
330  ftf::Covariance6d cov_vel = odom->twist.covariance;
331  ftf::EigenMapCovariance6d cov_vel_map(cov_vel.data());
332 
336  Eigen::Vector3d position {};
337  Eigen::Quaterniond orientation {};
338  Eigen::Vector3d lin_vel {};
339  Eigen::Vector3d ang_vel {};
340  Matrix6d r_pose = Matrix6d::Zero();
341  Matrix6d r_vel = Matrix6d::Zero();
342 
343  mavlink::common::msg::ODOMETRY msg {};
344 
351  position = Eigen::Vector3d(tf_parent2local.linear() * ftf::to_eigen(odom->pose.pose.position));
352 
353  // Orientation represented by a quaternion rotation from the local frame to XYZ body frame
354  Eigen::Quaterniond q_parent2child(ftf::to_eigen(odom->pose.pose.orientation));
355  Eigen::Affine3d tf_local2body = tf_parent2local * q_parent2child * tf_child2body.inverse();
356  orientation = Eigen::Quaterniond(tf_local2body.linear());
357 
358  r_pose.block<3, 3>(0, 0) = r_pose.block<3, 3>(3, 3) = tf_parent2local.linear();
359 
360  msg.frame_id = utils::enum_value(lf_id);
361 
366  auto set_tf = [&](Eigen::Affine3d affineTf, MAV_FRAME frame_id) {
367  lin_vel = Eigen::Vector3d(affineTf.linear() * ftf::to_eigen(odom->twist.twist.linear));
368  ang_vel = Eigen::Vector3d(affineTf.linear() * ftf::to_eigen(odom->twist.twist.angular));
369  r_vel.block<3, 3>(0, 0) = r_vel.block<3, 3>(3, 3) = affineTf.linear();
370 
371  msg.child_frame_id = utils::enum_value(frame_id);
372  };
373 
374  if (odom->child_frame_id == "world" || odom->child_frame_id == "odom") {
375  // the child_frame_id would be the same reference frame as frame_id
376  set_tf(tf_child2local, lf_id);
377  }
378  else {
379  // the child_frame_id would be the WRT a body frame reference
380  set_tf(tf_child2body, bf_id);
381  }
382 
384  cov_pose_map = r_pose * cov_pose_map * r_pose.transpose();
385  cov_vel_map = r_vel * cov_vel_map * r_vel.transpose();
386 
387  ROS_DEBUG_STREAM_NAMED("odom", "ODOM: output: pose covariance matrix:" << std::endl << cov_pose_map);
388  ROS_DEBUG_STREAM_NAMED("odom", "ODOM: output: velocity covariance matrix:" << std::endl << cov_vel_map);
389 
390  /* -*- ODOMETRY msg parser -*- */
391  msg.time_usec = odom->header.stamp.toNSec() / 1e3;
392 
393  // [[[cog:
394  // for a, b in (('', 'position'), ('v', 'lin_vel')):
395  // for f in 'xyz':
396  // cog.outl("msg.{a}{f} = {b}.{f}();".format(**locals()))
397  // for a, b in zip("xyz", ('rollspeed', 'pitchspeed', 'yawspeed')):
398  // cog.outl("msg.{b} = ang_vel.{a}();".format(**locals()))
399  // ]]]
400  msg.x = position.x();
401  msg.y = position.y();
402  msg.z = position.z();
403  msg.vx = lin_vel.x();
404  msg.vy = lin_vel.y();
405  msg.vz = lin_vel.z();
406  msg.rollspeed = ang_vel.x();
407  msg.pitchspeed = ang_vel.y();
408  msg.yawspeed = ang_vel.z();
409  // [[[end]]] (checksum: ead24a1a6a14496c9de6c1951ccfbbd7)
410 
411  ftf::quaternion_to_mavlink(orientation, msg.q);
412  ftf::covariance_urt_to_mavlink(cov_pose_map, msg.pose_covariance);
413  ftf::covariance_urt_to_mavlink(cov_vel_map, msg.velocity_covariance);
414 
415  // send ODOMETRY msg
416  UAS_FCU(m_uas)->send_message_ignore_drop(msg);
417  }
418 };
419 } // namespace extra_plugins
420 } // namespace mavros
421 
msg
std::string body_frame_orientation_in_desired
orientation of the body frame (input data)
Definition: odom.cpp:149
std::shared_ptr< MAVConnInterface const > ConstPtr
std_msgs::Header synchronized_header(const std::string &frame_id, const T time_stamp)
ros::Subscriber odom_sub
nav_msgs/Odometry subscriber
Definition: odom.cpp:143
#define ROS_DEBUG_STREAM_NAMED(name, args)
void publish(const boost::shared_ptr< M > &message) const
void quaternionEigenToMsg(const Eigen::Quaterniond &e, geometry_msgs::Quaternion &m)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
Eigen::Matrix< double, 6, 6, Eigen::RowMajor > Matrix6d
Definition: odom.cpp:29
HandlerInfo make_handler(const mavlink::msgid_t id, void(_C::*fn)(const mavlink::mavlink_message_t *msg, const mavconn::Framing framing))
Eigen::Quaterniond mavlink_to_quaternion(const std::array< float, 4 > &q)
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
Eigen::Map< Eigen::Matrix< double, 6, 6, Eigen::RowMajor > > EigenMapCovariance6d
std::string body_frame_orientation_out_desired
orientation of the body frame (output data)
Definition: odom.cpp:150
EIGEN_MAKE_ALIGNED_OPERATOR_NEW OdometryPlugin()
Definition: odom.cpp:41
void mavlink_urt_to_covariance_matrix(const std::array< float, ARR_SIZE > &covmsg, T &covmat)
MAV_FRAME lf_id
local frame (pose) ID
Definition: odom.cpp:154
tf2_ros::TransformBroadcaster tf2_broadcaster
std::string local_frame_in
orientation and source of the input local frame
Definition: odom.cpp:145
#define ROS_ERROR_THROTTLE_NAMED(period, name,...)
tf2_ros::Buffer tf2_buffer
void vectorEigenToMsg(const Eigen::Vector3d &e, geometry_msgs::Vector3 &m)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
std::string local_frame_orientation_in
orientation of the local frame (input data)
Definition: odom.cpp:147
ros::NodeHandle odom_nh
node handler
Definition: odom.cpp:141
std::string local_frame_out
orientation and source of the output local frame
Definition: odom.cpp:146
#define UAS_FCU(uasobjptr)
void handle_odom(const mavlink::mavlink_message_t *msg, mavlink::common::msg::ODOMETRY &odom_msg)
Handle ODOMETRY MAVlink message.
Definition: odom.cpp:204
ros::Time synchronise_stamp(uint32_t time_boot_ms)
Eigen::Vector3d to_eigen(const geometry_msgs::Point r)
void covariance_urt_to_mavlink(const T &covmap, std::array< float, ARR_SIZE > &covmsg)
geometry_msgs::PoseWithCovariance::_covariance_type Covariance6d
std::string child_frame_id
child frame identifier
Definition: odom.cpp:152
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void sendTransform(const geometry_msgs::TransformStamped &transform)
void pointEigenToMsg(const Eigen::Vector3d &e, geometry_msgs::Point &m)
void odom_cb(const nav_msgs::Odometry::ConstPtr &odom)
Sends odometry data msgs to the FCU.
Definition: odom.cpp:310
void transform_lookup(const std::string &frame_id, const std::string &child_frame_id, const std::string &local_frame_orientation, const std::string &body_frame_orientation, Eigen::Affine3d &tf_parent2local, Eigen::Affine3d &tf_child2local, Eigen::Affine3d &tf_parent2body, Eigen::Affine3d &tf_child2body)
Lookup transforms.
Definition: odom.cpp:170
std::vector< HandlerInfo > Subscriptions
void initialize(UAS &uas_)
#define ROS_FATAL_NAMED(name,...)
void quaternion_to_mavlink(const Eigen::Quaterniond &q, std::array< float, 4 > &qmsg)
std::string local_frame_orientation_out
orientation of the local frame (output data)
Definition: odom.cpp:148
ros::Publisher odom_pub
nav_msgs/Odometry publisher
Definition: odom.cpp:142
std::string frame_id
parent frame identifier
Definition: odom.cpp:151
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
MAV_FRAME bf_id
body frame (pose) ID
Definition: odom.cpp:155
Eigen::Isometry3d transformToEigen(const geometry_msgs::Transform &t)
constexpr std::underlying_type< _T >::type enum_value(_T e)


mavros_extras
Author(s): Vladimir Ermakov
autogenerated on Mon Jul 8 2019 03:20:18