21 #include <boost/algorithm/string.hpp> 23 #include <nav_msgs/Odometry.h> 24 #include <geometry_msgs/TransformStamped.h> 27 namespace extra_plugins {
28 using mavlink::common::MAV_FRAME;
29 using Matrix6d = Eigen::Matrix<double, 6, 6, Eigen::RowMajor>;
39 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
64 boost::algorithm::to_lower(local_frame_out);
65 boost::algorithm::to_lower(body_frame_orientation_out_desired);
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 }
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 }
89 if (local_frame_in ==
"local_origin_ned")
92 ROS_FATAL_NAMED(
"odom",
"ODOM: invalid input local frame \"%s\"", local_frame_in.c_str());
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") {
107 ROS_FATAL_NAMED(
"odom",
"ODOM: invalid ouput local frame \"%s\"", local_frame_out.c_str());
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")
115 body_frame_orientation_in_desired =
"fcu";
118 ROS_FATAL_NAMED(
"odom",
"ODOM: invalid input body frame orientation \"%s\"", body_frame_orientation_in_desired.c_str());
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")
127 body_frame_orientation_in_desired =
"fcu";
130 ROS_FATAL_NAMED(
"odom",
"ODOM: invalid output body frame orientation \"%s\"", body_frame_orientation_out_desired.c_str());
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)
178 frame_id, local_frame_orientation,
181 child_frame_id, local_frame_orientation,
186 frame_id, body_frame_orientation,
189 child_frame_id, body_frame_orientation,
204 void handle_odom(
const mavlink::mavlink_message_t *msg, mavlink::common::msg::ODOMETRY &odom_msg)
207 geometry_msgs::TransformStamped
transform;
209 transform.header.frame_id =
"local_origin_ned";
210 transform.child_frame_id =
"fcu_frd";
212 tf::vectorEigenToMsg(Eigen::Vector3d(odom_msg.x, odom_msg.y, odom_msg.z), transform.transform.translation);
221 Eigen::Affine3d tf_parent2local;
222 Eigen::Affine3d tf_child2local;
223 Eigen::Affine3d tf_parent2body;
224 Eigen::Affine3d tf_child2body;
228 local_frame_orientation_in, body_frame_orientation_in_desired,
229 tf_parent2local, tf_child2local, tf_parent2body, tf_child2body);
232 Matrix6d cov_pose = Matrix6d::Zero();
236 Matrix6d cov_vel = Matrix6d::Zero();
239 Eigen::Vector3d position {};
240 Eigen::Quaterniond orientation {};
241 Eigen::Vector3d lin_vel {};
242 Eigen::Vector3d ang_vel {};
246 auto odom = boost::make_shared<nav_msgs::Odometry>();
254 position = Eigen::Vector3d(tf_parent2local.linear() * Eigen::Vector3d(odom_msg.x, odom_msg.y, odom_msg.z));
261 Eigen::Affine3d tf_local2body = tf_parent2local * q_parent2child * tf_child2body.inverse();
262 orientation = Eigen::Quaterniond(tf_local2body.linear());
265 r_pose.block<3, 3>(0, 0) = r_pose.block<3, 3>(3, 3) = tf_parent2local.linear();
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();
277 if (odom_msg.child_frame_id == odom_msg.frame_id) {
279 set_tf(tf_child2local);
283 set_tf(tf_child2body);
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;
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;
315 Eigen::Affine3d tf_parent2local;
316 Eigen::Affine3d tf_child2local;
317 Eigen::Affine3d tf_parent2body;
318 Eigen::Affine3d tf_child2body;
322 local_frame_orientation_out, body_frame_orientation_out_desired,
323 tf_parent2local, tf_child2local, tf_parent2body, tf_child2body);
336 Eigen::Vector3d position {};
337 Eigen::Quaterniond orientation {};
338 Eigen::Vector3d lin_vel {};
339 Eigen::Vector3d ang_vel {};
343 mavlink::common::msg::ODOMETRY
msg {};
351 position = Eigen::Vector3d(tf_parent2local.linear() *
ftf::to_eigen(odom->pose.pose.position));
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());
358 r_pose.block<3, 3>(0, 0) = r_pose.block<3, 3>(3, 3) = tf_parent2local.linear();
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();
374 if (odom->child_frame_id ==
"world" || odom->child_frame_id ==
"odom") {
376 set_tf(tf_child2local, lf_id);
380 set_tf(tf_child2body, bf_id);
384 cov_pose_map = r_pose * cov_pose_map * r_pose.transpose();
385 cov_vel_map = r_vel * cov_vel_map * r_vel.transpose();
391 msg.time_usec = odom->header.stamp.toNSec() / 1e3;
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();
std::string body_frame_orientation_in_desired
orientation of the body frame (input data)
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
#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
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)
EIGEN_MAKE_ALIGNED_OPERATOR_NEW OdometryPlugin()
void mavlink_urt_to_covariance_matrix(const std::array< float, ARR_SIZE > &covmsg, T &covmat)
MAV_FRAME lf_id
local frame (pose) ID
tf2_ros::TransformBroadcaster tf2_broadcaster
std::string local_frame_in
orientation and source of the input local frame
#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 ¶m_name, T ¶m_val, const T &default_val) const
std::string local_frame_orientation_in
orientation of the local frame (input data)
ros::NodeHandle odom_nh
node handler
std::string local_frame_out
orientation and source of the output local frame
#define UAS_FCU(uasobjptr)
void handle_odom(const mavlink::mavlink_message_t *msg, mavlink::common::msg::ODOMETRY &odom_msg)
Handle ODOMETRY MAVlink message.
ros::Time synchronise_stamp(uint32_t time_boot_ms)
Subscriptions get_subscriptions()
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
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void initialize(UAS &uas_)
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.
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.
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)
ros::Publisher odom_pub
nav_msgs/Odometry publisher
std::string frame_id
parent frame identifier
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
MAV_FRAME bf_id
body frame (pose) ID
Eigen::Isometry3d transformToEigen(const geometry_msgs::Transform &t)
constexpr std::underlying_type< _T >::type enum_value(_T e)