-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[TransformManager] moved TfMappingOrigin to separate class
- Loading branch information
Showing
3 changed files
with
358 additions
and
270 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,346 @@ | ||
#pragma once | ||
#ifndef TF_MAPPING_ORIGIN_H | ||
#define TF_MAPPING_ORIGIN_H | ||
|
||
#include <ros/ros.h> | ||
|
||
#include <mrs_lib/param_loader.h> | ||
#include <mrs_lib/subscribe_handler.h> | ||
#include <mrs_lib/transform_broadcaster.h> | ||
#include <mrs_lib/attitude_converter.h> | ||
|
||
#include <nav_msgs/Odometry.h> | ||
#include <geometry_msgs/QuaternionStamped.h> | ||
#include <geometry_msgs/TransformStamped.h> | ||
|
||
#include <mrs_uav_managers/estimation_manager/support.h> | ||
#include <mrs_uav_managers/estimation_manager/common_handlers.h> | ||
|
||
namespace mrs_uav_managers | ||
{ | ||
|
||
/*//{ class TfMappingOrigin */ | ||
class TfMappingOrigin { | ||
|
||
using Support = estimation_manager::Support; | ||
|
||
public: | ||
/*//{ constructor */ | ||
TfMappingOrigin(ros::NodeHandle nh, const std::shared_ptr<mrs_lib::TransformBroadcaster>& broadcaster, | ||
const std::shared_ptr<estimation_manager::CommonHandlers_t> ch) | ||
: nh_(nh), broadcaster_(broadcaster), ch_(ch) { | ||
|
||
ROS_INFO("[%s]: initializing", getPrintName().c_str()); | ||
|
||
|
||
mrs_lib::ParamLoader param_loader(nh_, getPrintName()); | ||
|
||
const std::string yaml_prefix = "mrs_uav_managers/transform_manager/mapping_origin_tf/"; | ||
|
||
/*//{ load mapping origin parameters */ | ||
param_loader.loadParam(yaml_prefix + "lateral_topic", mapping_origin_tf_lateral_topic_); | ||
param_loader.loadParam(yaml_prefix + "altitude_topic", mapping_origin_tf_altitude_topic_); | ||
param_loader.loadParam(yaml_prefix + "orientation_topic", mapping_origin_tf_orientation_topic_); | ||
param_loader.loadParam(yaml_prefix + "inverted", mapping_origin_tf_inverted_); | ||
param_loader.loadParam(yaml_prefix + "custom_frame_id/enabled", mapping_origin_tf_custom_frame_id_enabled_); | ||
if (mapping_origin_tf_custom_frame_id_enabled_) { | ||
param_loader.loadParam(yaml_prefix + "custom_frame_id/frame_id", mapping_origin_tf_custom_frame_id_); | ||
} | ||
|
||
if (!param_loader.loadedSuccessfully()) { | ||
ROS_ERROR("[%s]: Could not load all non-optional parameters. Shutting down.", getPrintName().c_str()); | ||
ros::shutdown(); | ||
} | ||
|
||
/*//}*/ | ||
|
||
/*//{ initialize subscribers */ | ||
mrs_lib::SubscribeHandlerOptions shopts; | ||
shopts.nh = nh_; | ||
shopts.node_name = getPrintName(); | ||
shopts.no_message_timeout = mrs_lib::no_timeout; | ||
shopts.threadsafe = true; | ||
shopts.autostart = true; | ||
shopts.queue_size = 10; | ||
shopts.transport_hints = ros::TransportHints().tcpNoDelay(); | ||
|
||
sh_mapping_odom_lat_ = mrs_lib::SubscribeHandler<nav_msgs::Odometry>(shopts, "/" + ch_->uav_name + "/" + mapping_origin_tf_lateral_topic_, | ||
&TfMappingOrigin::callbackMappingOdomLat, this); | ||
|
||
if (mapping_origin_tf_orientation_topic_ != mapping_origin_tf_lateral_topic_) { | ||
sh_mapping_odom_rot_ = mrs_lib::SubscribeHandler<geometry_msgs::QuaternionStamped>( | ||
shopts, "/" + ch_->uav_name + "/" + mapping_origin_tf_orientation_topic_.c_str(), &TfMappingOrigin::callbackMappingOdomRot, this); | ||
} | ||
|
||
if (mapping_origin_tf_altitude_topic_ != mapping_origin_tf_lateral_topic_) { | ||
sh_mapping_odom_alt_ = mrs_lib::SubscribeHandler<nav_msgs::Odometry>(shopts, "/" + ch_->uav_name + "/" + mapping_origin_tf_altitude_topic_.c_str(), | ||
&TfMappingOrigin::callbackMappingOdomAlt, this); | ||
} | ||
/*//}*/ | ||
|
||
is_initialized_ = true; | ||
ROS_INFO("[%s]: initialized", getPrintName().c_str()); | ||
} | ||
/*//}*/ | ||
|
||
/*//{ getName() */ | ||
std::string getName() { | ||
return name_; | ||
} | ||
/*//}*/ | ||
|
||
/*//{ getPrintName() */ | ||
std::string getPrintName() { | ||
return ch_->nodelet_name + "/" + name_; | ||
} | ||
/*//}*/ | ||
|
||
private: | ||
const std::string name_ = "TfMappingOrigin"; | ||
|
||
ros::NodeHandle nh_; | ||
|
||
std::shared_ptr<mrs_lib::TransformBroadcaster> broadcaster_; | ||
|
||
std::shared_ptr<estimation_manager::CommonHandlers_t> ch_; | ||
|
||
std::atomic_bool is_initialized_ = false; | ||
|
||
bool mapping_origin_tf_inverted_; | ||
bool mapping_origin_tf_custom_frame_id_enabled_; | ||
std::string mapping_origin_tf_custom_frame_id_; | ||
double mapping_origin_tf_cache_duration_; | ||
|
||
std::string mapping_origin_tf_lateral_topic_; | ||
mrs_lib::SubscribeHandler<nav_msgs::Odometry> sh_mapping_odom_lat_; | ||
std::vector<nav_msgs::Odometry> vec_mapping_odom_lat_; | ||
|
||
/*//{ callbackMappingOdomLat() */ | ||
|
||
void callbackMappingOdomLat(const nav_msgs::Odometry::ConstPtr msg) { | ||
|
||
if (!is_initialized_) { | ||
return; | ||
} | ||
|
||
if (!got_mapping_odom_rot_ && mapping_origin_tf_orientation_topic_ == mapping_origin_tf_lateral_topic_) { | ||
got_mapping_odom_rot_ = true; | ||
} | ||
|
||
if (!got_mapping_odom_alt_ && mapping_origin_tf_altitude_topic_ == mapping_origin_tf_lateral_topic_) { | ||
got_mapping_odom_alt_ = true; | ||
} | ||
|
||
mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("TfMappingOrigin::callbackMappingOdomLat", ch_->scope_timer.logger, ch_->scope_timer.enabled); | ||
|
||
const double hdg_mapping_old = mrs_lib::AttitudeConverter(msg->pose.pose.orientation).getHeading(); | ||
|
||
/* publish aloam mapping origin tf //{ */ | ||
|
||
bool clear_needed = false; | ||
|
||
if (got_mapping_odom_rot_ && got_mapping_odom_alt_) { | ||
std::scoped_lock lock(mtx_mapping_odom_rot_); | ||
|
||
// Copy mapping odometry | ||
nav_msgs::Odometry mapping_odom; | ||
mapping_odom = *msg; | ||
|
||
// Find corresponding orientation | ||
tf2::Quaternion tf2_rot; | ||
geometry_msgs::QuaternionStamped rot_tmp = *sh_mapping_odom_rot_.getMsg(); // start with newest msg | ||
|
||
for (size_t i = 0; i < vec_mapping_odom_rot_.size(); i++) { | ||
if (mapping_odom.header.stamp < vec_mapping_odom_rot_.at(i).header.stamp) { | ||
|
||
// Choose an orientation with closest timestamp | ||
double time_diff = std::fabs(vec_mapping_odom_rot_.at(i).header.stamp.toSec() - mapping_odom.header.stamp.toSec()); | ||
double time_diff_prev = std::numeric_limits<double>::max(); | ||
if (i > 0) { | ||
time_diff_prev = std::fabs(vec_mapping_odom_rot_.at(i - 1).header.stamp.toSec() - mapping_odom.header.stamp.toSec()); | ||
} | ||
if (time_diff_prev < time_diff && i > 0) { | ||
i = i - 1; | ||
} | ||
|
||
// Cache is too small if it is full and its oldest element is used | ||
if (clear_needed && i == 0) { | ||
ROS_WARN_THROTTLE(1.0, "[%s] Mapping orientation cache is too small.", getPrintName().c_str()); | ||
} | ||
rot_tmp = vec_mapping_odom_rot_.at(i); | ||
break; | ||
} | ||
} | ||
|
||
tf2_rot = mrs_lib::AttitudeConverter(rot_tmp.quaternion); | ||
|
||
// Obtain heading from orientation | ||
double hdg = 0; | ||
try { | ||
hdg = mrs_lib::AttitudeConverter(rot_tmp.quaternion).getHeading(); | ||
} | ||
catch (...) { | ||
ROS_WARN("[%s]: failed to getHeading() from rot_tmp", getPrintName().c_str()); | ||
} | ||
|
||
// Build rotation matrix from difference between new heading and old heading | ||
tf2::Matrix3x3 rot_mat = mrs_lib::AttitudeConverter(Eigen::AngleAxisd(hdg_mapping_old - hdg, Eigen::Vector3d::UnitZ())); | ||
|
||
// Transform the mavros orientation by the rotation matrix | ||
geometry_msgs::Quaternion new_orientation = mrs_lib::AttitudeConverter(tf2::Transform(rot_mat) * tf2_rot); | ||
|
||
// Set new orientation | ||
mapping_odom.pose.pose.orientation = new_orientation; | ||
|
||
|
||
// Find corresponding local odom | ||
double odom_alt = msg->pose.pose.position.z; | ||
for (size_t i = 0; i < vec_mapping_odom_alt_.size(); i++) { | ||
if (mapping_odom.header.stamp < vec_mapping_odom_alt_.at(i).header.stamp) { | ||
|
||
// Choose orientation with closest timestamp | ||
double time_diff = std::fabs(vec_mapping_odom_alt_.at(i).header.stamp.toSec() - mapping_odom.header.stamp.toSec()); | ||
double time_diff_prev = std::numeric_limits<double>::max(); | ||
if (i > 0) { | ||
time_diff_prev = std::fabs(vec_mapping_odom_alt_.at(i - 1).header.stamp.toSec() - mapping_odom.header.stamp.toSec()); | ||
} | ||
if (time_diff_prev < time_diff && i > 0) { | ||
i = i - 1; | ||
} | ||
// Cache is too small if it is full and its oldest element is used | ||
if (clear_needed && i == 0) { | ||
ROS_WARN_THROTTLE(1.0, "[%s] mapping orientation cache (for slam mapping tf) is too small.", getPrintName().c_str()); | ||
} | ||
odom_alt = vec_mapping_odom_alt_.at(i).pose.pose.position.z; | ||
break; | ||
} | ||
} | ||
|
||
// Set altitude | ||
mapping_odom.pose.pose.position.z = odom_alt; | ||
|
||
// Get inverse transform | ||
tf2::Transform tf_mapping_inv = Support::tf2FromPose(mapping_odom.pose.pose).inverse(); | ||
geometry_msgs::Pose pose_mapping_inv = Support::poseFromTf2(tf_mapping_inv); | ||
|
||
geometry_msgs::TransformStamped tf_mapping; | ||
tf_mapping.header.stamp = mapping_odom.header.stamp; | ||
tf_mapping.header.frame_id = ch_->frames.ns_fcu; | ||
if (mapping_origin_tf_custom_frame_id_enabled_) { | ||
tf_mapping.child_frame_id = ch_->uav_name + "/" + mapping_origin_tf_custom_frame_id_; | ||
} else { | ||
tf_mapping.child_frame_id = mapping_odom.header.frame_id; | ||
} | ||
tf_mapping.transform.translation = Support::pointToVector3(pose_mapping_inv.position); | ||
tf_mapping.transform.rotation = pose_mapping_inv.orientation; | ||
|
||
if (Support::noNans(tf_mapping)) { | ||
try { | ||
broadcaster_->sendTransform(tf_mapping); | ||
} | ||
catch (...) { | ||
ROS_ERROR("[%s]: Exception caught during publishing TF: %s - %s.", getPrintName().c_str(), tf_mapping.child_frame_id.c_str(), | ||
tf_mapping.header.frame_id.c_str()); | ||
} | ||
} else { | ||
ROS_WARN_THROTTLE(1.0, "[%s]: NaN detected in transform from %s to %s. Not publishing tf.", getPrintName().c_str(), tf_mapping.header.frame_id.c_str(), | ||
tf_mapping.child_frame_id.c_str()); | ||
} | ||
} | ||
|
||
//} | ||
} | ||
/*//}*/ | ||
|
||
std::string mapping_origin_tf_orientation_topic_; | ||
mrs_lib::SubscribeHandler<geometry_msgs::QuaternionStamped> sh_mapping_odom_rot_; | ||
std::vector<geometry_msgs::QuaternionStamped> vec_mapping_odom_rot_; | ||
std::mutex mtx_mapping_odom_rot_; | ||
bool got_mapping_odom_rot_ = false; | ||
|
||
/*//{ callbackMappingOdomRot() */ | ||
void callbackMappingOdomRot(const geometry_msgs::QuaternionStamped::ConstPtr msg) { | ||
|
||
if (!is_initialized_) { | ||
return; | ||
} | ||
std::scoped_lock lock(mtx_mapping_odom_rot_); | ||
|
||
const ros::Time time_now = ros::Time::now(); | ||
|
||
// Add new data | ||
vec_mapping_odom_rot_.push_back(*msg); | ||
|
||
// Delete old data | ||
size_t index_delete = 0; | ||
bool clear_needed = false; | ||
for (size_t i = 0; i < vec_mapping_odom_rot_.size(); i++) { | ||
if (time_now - vec_mapping_odom_rot_.at(i).header.stamp > ros::Duration(mapping_origin_tf_cache_duration_)) { | ||
index_delete = i; | ||
clear_needed = true; | ||
} else { | ||
break; | ||
} | ||
} | ||
if (clear_needed) { | ||
for (int i = (int)index_delete; i >= 0; i--) { | ||
vec_mapping_odom_rot_.erase(vec_mapping_odom_rot_.begin() + i); | ||
} | ||
clear_needed = false; | ||
} | ||
|
||
if (!got_mapping_odom_rot_) { | ||
got_mapping_odom_rot_ = true; | ||
} | ||
} | ||
/*//}*/ | ||
|
||
std::string mapping_origin_tf_altitude_topic_; | ||
mrs_lib::SubscribeHandler<nav_msgs::Odometry> sh_mapping_odom_alt_; | ||
std::vector<nav_msgs::Odometry> vec_mapping_odom_alt_; | ||
std::mutex mtx_mapping_odom_alt_; | ||
bool got_mapping_odom_alt_ = false; | ||
|
||
/*//{ callbackMappingOdomAlt() */ | ||
void callbackMappingOdomAlt(const nav_msgs::Odometry::ConstPtr msg) { | ||
|
||
if (!is_initialized_) { | ||
return; | ||
} | ||
|
||
std::scoped_lock lock(mtx_mapping_odom_alt_); | ||
|
||
const ros::Time time_now = ros::Time::now(); | ||
|
||
// Add new data | ||
vec_mapping_odom_alt_.push_back(*msg); | ||
|
||
// Delete old data | ||
size_t index_delete = 0; | ||
bool clear_needed = false; | ||
for (size_t i = 0; i < vec_mapping_odom_alt_.size(); i++) { | ||
if (time_now - vec_mapping_odom_alt_.at(i).header.stamp > ros::Duration(mapping_origin_tf_cache_duration_)) { | ||
index_delete = i; | ||
clear_needed = true; | ||
} else { | ||
break; | ||
} | ||
} | ||
if (clear_needed) { | ||
for (int i = (int)index_delete; i >= 0; i--) { | ||
vec_mapping_odom_alt_.erase(vec_mapping_odom_alt_.begin() + i); | ||
} | ||
clear_needed = false; | ||
} | ||
|
||
if (!got_mapping_odom_alt_) { | ||
got_mapping_odom_alt_ = true; | ||
} | ||
} | ||
/*//}*/ | ||
}; | ||
/*//}*/ | ||
|
||
} // namespace mrs_uav_managers | ||
|
||
#endif |
Oops, something went wrong.