Program Listing for File tf_utils.cpp
↰ Return to documentation for file (/tmp/ws/src/aerostack2/as2_core/src/utils/tf_utils.cpp
)
// Copyright 2023 Universidad Politécnica de Madrid
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of the Universidad Politécnica de Madrid nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
/*!*******************************************************************************************
* \file tf_utils.cpp
* \brief Tranform utilities library implementation file.
* \authors David Perez Saura
********************************************************************************/
#include "as2_core/utils/tf_utils.hpp"
namespace as2
{
namespace tf
{
using namespace std::chrono_literals; // NOLINT
std::string generateTfName(rclcpp::Node * node, std::string _frame_name)
{
return generateTfName(node->get_namespace(), _frame_name);
}
std::string generateTfName(const std::string & _namespace, const std::string & _frame_name)
{
if (!_frame_name.size()) {
throw std::runtime_error("Empty frame name");
}
if (_frame_name[0] == '/') {
return _frame_name.substr(1);
}
if (!_namespace.size()) {
RCLCPP_WARN(
rclcpp::get_logger("tf_utils"),
"The frame name [%s] is not absolute and the node namespace is empty. This could "
"lead to conflicts.",
_frame_name.c_str());
return _frame_name;
}
std::string ns = _namespace;
if (ns[0] == '/') {
ns = ns.substr(1);
}
// If _frame_name until first '/' is equal to _namespace, then _frame_name is absolute
auto pos = _frame_name.find('/');
if (pos != std::string::npos) {
if (_frame_name.substr(0, pos) == ns) {
return _frame_name;
}
}
return ns + "/" + _frame_name;
}
geometry_msgs::msg::TransformStamped getTransformation(
const std::string & _frame_id, const std::string & _child_frame_id, double _translation_x,
double _translation_y, double _translation_z, double _roll, double _pitch, double _yaw)
{
geometry_msgs::msg::TransformStamped transformation;
transformation.header.frame_id = _frame_id;
transformation.child_frame_id = _child_frame_id;
transformation.transform.translation.x = _translation_x;
transformation.transform.translation.y = _translation_y;
transformation.transform.translation.z = _translation_z;
tf2::Quaternion q;
q.setRPY(_roll, _pitch, _yaw);
transformation.transform.rotation.x = q.x();
transformation.transform.rotation.y = q.y();
transformation.transform.rotation.z = q.z();
transformation.transform.rotation.w = q.w();
return transformation;
}
geometry_msgs::msg::PointStamped TfHandler::convert(
const geometry_msgs::msg::PointStamped & _point, const std::string & target_frame,
const std::chrono::nanoseconds timeout)
{
geometry_msgs::msg::PointStamped point_out;
if (timeout != std::chrono::nanoseconds::zero()) {
tf2::doTransform(
_point, point_out,
tf_buffer_->lookupTransform(
target_frame, node_->get_clock()->now(), _point.header.frame_id, _point.header.stamp,
"earth", timeout));
} else {
tf2::doTransform(
_point, point_out,
tf_buffer_->lookupTransform(
target_frame, tf2::TimePointZero, _point.header.frame_id, tf2::TimePointZero, "earth",
timeout));
}
point_out.header.stamp = _point.header.stamp;
point_out.header.frame_id = target_frame;
return point_out;
}
geometry_msgs::msg::PoseStamped TfHandler::convert(
const geometry_msgs::msg::PoseStamped & _pose, const std::string & target_frame,
const std::chrono::nanoseconds timeout)
{
geometry_msgs::msg::PoseStamped pose_out;
if (timeout != std::chrono::nanoseconds::zero()) {
tf2::doTransform(
_pose, pose_out,
tf_buffer_->lookupTransform(
target_frame, node_->get_clock()->now(), _pose.header.frame_id, _pose.header.stamp, "earth",
timeout));
} else {
tf2::doTransform(
_pose, pose_out,
tf_buffer_->lookupTransform(
target_frame, tf2::TimePointZero, _pose.header.frame_id, tf2::TimePointZero, "earth",
timeout));
}
pose_out.header.frame_id = target_frame;
pose_out.header.stamp = _pose.header.stamp;
return pose_out;
}
geometry_msgs::msg::TwistStamped TfHandler::convert(
const geometry_msgs::msg::TwistStamped & _twist, const std::string & target_frame,
const std::chrono::nanoseconds timeout)
{
geometry_msgs::msg::TwistStamped twist_out;
geometry_msgs::msg::Vector3Stamped vector_out;
vector_out.header = _twist.header;
vector_out.vector = _twist.twist.linear;
// transform linear speed
vector_out = convert(vector_out, target_frame, timeout);
twist_out.header = vector_out.header;
twist_out.twist.linear = vector_out.vector;
twist_out.twist.angular = _twist.twist.angular;
return twist_out;
}
geometry_msgs::msg::Vector3Stamped TfHandler::convert(
const geometry_msgs::msg::Vector3Stamped & _vector, const std::string & target_frame,
const std::chrono::nanoseconds timeout)
{
geometry_msgs::msg::Vector3Stamped vector_out;
if (timeout != std::chrono::nanoseconds::zero()) {
tf2::doTransform(
_vector, vector_out,
tf_buffer_->lookupTransform(
target_frame, node_->get_clock()->now(), _vector.header.frame_id, _vector.header.stamp,
"earth", timeout));
} else {
tf2::doTransform(
_vector, vector_out,
tf_buffer_->lookupTransform(
target_frame, tf2::TimePointZero, _vector.header.frame_id, tf2::TimePointZero, "earth",
timeout));
}
vector_out.header.frame_id = target_frame;
vector_out.header.stamp = _vector.header.stamp;
return vector_out;
}
nav_msgs::msg::Path TfHandler::convert(
const nav_msgs::msg::Path & _path, const std::string & target_frame,
const std::chrono::nanoseconds timeout)
{
nav_msgs::msg::Path path_out;
for (auto & pose : _path.poses) {
geometry_msgs::msg::PoseStamped pose_out;
if (timeout != std::chrono::nanoseconds::zero()) {
tf2::doTransform(
pose, pose_out,
tf_buffer_->lookupTransform(
target_frame, node_->get_clock()->now(), pose.header.frame_id, pose.header.stamp, "earth",
timeout));
} else {
tf2::doTransform(
pose, pose_out,
tf_buffer_->lookupTransform(
target_frame, tf2::TimePointZero, pose.header.frame_id, tf2::TimePointZero, "earth",
timeout));
}
path_out.poses.push_back(pose_out);
}
path_out.header.frame_id = target_frame;
path_out.header.stamp = _path.header.stamp;
return path_out;
}
geometry_msgs::msg::QuaternionStamped TfHandler::convert(
const geometry_msgs::msg::QuaternionStamped & _quaternion, const std::string & target_frame,
const std::chrono::nanoseconds timeout)
{
geometry_msgs::msg::QuaternionStamped quaternion_out;
if (timeout != std::chrono::nanoseconds::zero()) {
tf2::doTransform(
_quaternion, quaternion_out,
tf_buffer_->lookupTransform(
target_frame, node_->get_clock()->now(), _quaternion.header.frame_id,
_quaternion.header.stamp, "earth", timeout));
} else {
tf2::doTransform(
_quaternion, quaternion_out,
tf_buffer_->lookupTransform(
target_frame, tf2::TimePointZero, _quaternion.header.frame_id, tf2::TimePointZero, "earth",
timeout));
}
quaternion_out.header.frame_id = target_frame;
quaternion_out.header.stamp = _quaternion.header.stamp;
return quaternion_out;
}
geometry_msgs::msg::PoseStamped TfHandler::getPoseStamped(
const std::string & target_frame, const std::string & source_frame, const rclcpp::Time & time,
const std::chrono::nanoseconds timeout)
{
return getPoseStamped(target_frame, source_frame, tf2_ros::fromMsg(time), timeout);
}
geometry_msgs::msg::PoseStamped TfHandler::getPoseStamped(
const std::string & target_frame, const std::string & source_frame, const tf2::TimePoint & time,
const std::chrono::nanoseconds timeout)
{
// if-else needed for galactic
geometry_msgs::msg::TransformStamped transform;
if (timeout != std::chrono::nanoseconds::zero()) {
transform = tf_buffer_->lookupTransform(
target_frame, tf2_ros::fromMsg(node_->get_clock()->now()), source_frame, time, "earth",
timeout);
} else {
transform = tf_buffer_->lookupTransform(
target_frame, tf2::TimePointZero, source_frame, tf2::TimePointZero, "earth",
timeout);
}
geometry_msgs::msg::PoseStamped pose;
pose.header.frame_id = target_frame;
pose.header.stamp = transform.header.stamp;
pose.pose.position.x = transform.transform.translation.x;
pose.pose.position.y = transform.transform.translation.y;
pose.pose.position.z = transform.transform.translation.z;
pose.pose.orientation.x = transform.transform.rotation.x;
pose.pose.orientation.y = transform.transform.rotation.y;
pose.pose.orientation.z = transform.transform.rotation.z;
pose.pose.orientation.w = transform.transform.rotation.w;
return pose;
}
geometry_msgs::msg::QuaternionStamped TfHandler::getQuaternionStamped(
const std::string & target_frame, const std::string & source_frame, const rclcpp::Time & time,
const std::chrono::nanoseconds timeout)
{
return getQuaternionStamped(target_frame, source_frame, tf2_ros::fromMsg(time), timeout);
}
geometry_msgs::msg::QuaternionStamped TfHandler::getQuaternionStamped(
const std::string & target_frame, const std::string & source_frame, const tf2::TimePoint & time,
const std::chrono::nanoseconds timeout)
{
geometry_msgs::msg::TransformStamped transform;
if (timeout != std::chrono::nanoseconds::zero()) {
transform = tf_buffer_->lookupTransform(
target_frame, tf2_ros::fromMsg(node_->get_clock()->now()), source_frame, time, "earth",
timeout);
} else {
transform = tf_buffer_->lookupTransform(
target_frame, tf2::TimePointZero, source_frame, tf2::TimePointZero, "earth",
timeout);
}
geometry_msgs::msg::QuaternionStamped quaternion;
quaternion.header.frame_id = target_frame;
quaternion.header.stamp = transform.header.stamp;
quaternion.quaternion.x = transform.transform.rotation.x;
quaternion.quaternion.y = transform.transform.rotation.y;
quaternion.quaternion.z = transform.transform.rotation.z;
quaternion.quaternion.w = transform.transform.rotation.w;
return quaternion;
}
geometry_msgs::msg::TransformStamped TfHandler::getTransform(
const std::string & target_frame, const std::string & source_frame, const tf2::TimePoint & time)
{
return tf_buffer_->lookupTransform(target_frame, source_frame, time);
}
bool TfHandler::tryConvert(
geometry_msgs::msg::PointStamped & _point, const std::string & _target_frame,
const std::chrono::nanoseconds timeout)
{
try {
_point = convert(_point, _target_frame, timeout);
return true;
} catch (tf2::TransformException & ex) {
RCLCPP_WARN(node_->get_logger(), "Could not get transform: %s", ex.what());
return false;
}
return false;
}
bool TfHandler::tryConvert(
geometry_msgs::msg::PoseStamped & _pose, const std::string & _target_frame,
const std::chrono::nanoseconds timeout)
{
try {
_pose = convert(_pose, _target_frame, timeout);
return true;
} catch (tf2::TransformException & ex) {
RCLCPP_WARN(node_->get_logger(), "Could not get transform: %s", ex.what());
return false;
}
return false;
}
bool TfHandler::tryConvert(
geometry_msgs::msg::TwistStamped & _twist, const std::string & _target_frame,
const std::chrono::nanoseconds timeout)
{
try {
_twist = convert(_twist, _target_frame, timeout);
return true;
} catch (tf2::TransformException & ex) {
RCLCPP_ERROR(node_->get_logger(), "Could not get transform: %s", ex.what());
}
return false;
}
bool TfHandler::tryConvert(
geometry_msgs::msg::QuaternionStamped & _quaternion, const std::string & _target_frame,
const std::chrono::nanoseconds timeout)
{
try {
_quaternion = convert(_quaternion, _target_frame, timeout);
return true;
} catch (tf2::TransformException & ex) {
RCLCPP_ERROR(node_->get_logger(), "Could not get transform: %s", ex.what());
}
return false;
}
std::pair<geometry_msgs::msg::PoseStamped, geometry_msgs::msg::TwistStamped> TfHandler::getState(
const geometry_msgs::msg::TwistStamped & _twist, const std::string & _twist_target_frame,
const std::string & _pose_target_frame, const std::string & _pose_source_frame,
const std::chrono::nanoseconds _timeout)
{
geometry_msgs::msg::TwistStamped twist = convert(_twist, _twist_target_frame, _timeout);
geometry_msgs::msg::PoseStamped pose = getPoseStamped(
_pose_target_frame, _pose_source_frame, tf2_ros::fromMsg(twist.header.stamp), _timeout);
return std::make_pair(pose, twist);
}
} // namespace tf
} // namespace as2