18 #include <tf2_ros/transform_listener.h>
19 #include <tf2_ros/buffer.h>
20 #include <tf2_eigen/tf2_eigen.h>
21 #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
22 #include <tf/transform_datatypes.h>
23 #include <tf_conversions/tf_eigen.h>
25 #include <mrs_msgs/ReferenceStamped.h>
27 #include <geometry_msgs/PoseStamped.h>
28 #include <geometry_msgs/Vector3Stamped.h>
29 #include <std_msgs/Header.h>
33 #include <pcl_ros/point_cloud.h>
34 #include <pcl_ros/transforms.h>
35 #include <pcl_conversions/pcl_conversions.h>
38 #include <experimental/type_traits>
45 template <
typename pt_t>
46 void doTransform(
const pcl::PointCloud<pt_t>& cloud_in, pcl::PointCloud<pt_t>& cloud_out,
const geometry_msgs::TransformStamped& transform)
48 pcl_ros::transformPointCloud(cloud_in, cloud_out, transform.transform);
49 pcl_conversions::toPCL(transform.header.stamp, cloud_out.header.stamp);
50 cloud_out.header.frame_id = transform.header.frame_id;
58 static const std::string UTM_ORIGIN =
"utm_origin";
59 static const std::string LATLON_ORIGIN =
"latlon_origin";
92 Transformer(
const std::string& node_name,
const ros::Duration& cache_time = ros::Duration(tf2_ros::Buffer::DEFAULT_CACHE_TIME));
103 Transformer(
const ros::NodeHandle& nh,
const std::string& node_name = std::string(),
const ros::Duration& cache_time = ros::Duration(tf2_ros::Buffer::DEFAULT_CACHE_TIME));
132 std::scoped_lock lck(mutex_);
133 default_frame_id_ = frame_id;
155 std::scoped_lock lck(mutex_);
159 prefix_ = prefix +
"/";
176 void setLatLon(
const double lat,
const double lon);
193 std::scoped_lock lck(mutex_);
194 lookup_timeout_ = timeout;
213 std::scoped_lock lck(mutex_);
214 retry_lookup_newest_ = retry;
230 std::scoped_lock lck(mutex_);
250 std::scoped_lock lck(mutex_);
251 return resolveFrameImpl(frame_id);
266 [[nodiscard]] std::optional<T>
transformSingle(
const T& what,
const std::string& to_frame);
279 [[nodiscard]] std::optional<boost::shared_ptr<T>>
transformSingle(
const boost::shared_ptr<T>& what,
const std::string& to_frame)
295 [[nodiscard]] std::optional<boost::shared_ptr<T>>
transformSingle(
const boost::shared_ptr<const T>& what,
const std::string& to_frame)
298 if (ret == std::nullopt)
301 return boost::make_shared<T>(std::move(ret.value()));
317 [[nodiscard]] std::optional<T>
transformSingle(
const std::string& from_frame,
const T& what,
const std::string& to_frame,
const ros::Time& time_stamp = ros::Time(0));
332 [[nodiscard]] std::optional<boost::shared_ptr<T>>
transformSingle(
const std::string& from_frame,
const boost::shared_ptr<T>& what,
const std::string& to_frame,
const ros::Time& time_stamp = ros::Time(0))
334 return transformSingle(from_frame, boost::shared_ptr<const T>(what), to_frame, time_stamp);
350 [[nodiscard]] std::optional<boost::shared_ptr<T>>
transformSingle(
const std::string& from_frame,
const boost::shared_ptr<const T>& what,
const std::string& to_frame,
const ros::Time& time_stamp = ros::Time(0))
353 if (ret == std::nullopt)
356 return boost::make_shared<T>(std::move(ret.value()));
372 [[nodiscard]] std::optional<T>
transform(
const T& what,
const geometry_msgs::TransformStamped& tf);
385 [[nodiscard]] std::optional<boost::shared_ptr<T>>
transform(
const boost::shared_ptr<const T>& what,
const geometry_msgs::TransformStamped& tf)
388 if (ret == std::nullopt)
391 return boost::make_shared<T>(std::move(ret.value()));
405 [[nodiscard]] std::optional<boost::shared_ptr<T>>
transform(
const boost::shared_ptr<T>& what,
const geometry_msgs::TransformStamped& tf)
407 return transform(boost::shared_ptr<const T>(what), tf);
423 [[nodiscard]] std::optional<Eigen::Vector3d>
transformAsVector(
const Eigen::Vector3d& what,
const geometry_msgs::TransformStamped& tf);
437 [[nodiscard]] std::optional<Eigen::Vector3d>
transformAsVector(
const std::string& from_frame,
const Eigen::Vector3d& what,
const std::string& to_frame,
const ros::Time& time_stamp = ros::Time(0));
451 [[nodiscard]] std::optional<Eigen::Vector3d>
transformAsPoint(
const Eigen::Vector3d& what,
const geometry_msgs::TransformStamped& tf);
465 [[nodiscard]] std::optional<Eigen::Vector3d>
transformAsPoint(
const std::string& from_frame,
const Eigen::Vector3d& what,
const std::string& to_frame,
const ros::Time& time_stamp = ros::Time(0));
479 [[nodiscard]] std::optional<geometry_msgs::TransformStamped>
getTransform(
const std::string& from_frame,
const std::string& to_frame,
const ros::Time& time_stamp = ros::Time(0));
496 [[nodiscard]] std::optional<geometry_msgs::TransformStamped>
getTransform(
const std::string& from_frame,
const ros::Time& from_stamp,
const std::string& to_frame,
const ros::Time& to_stamp,
const std::string& fixed_frame);
506 bool initialized_ =
false;
507 std::string node_name_;
509 std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
510 std::unique_ptr<tf2_ros::TransformListener> tf_listener_ptr_;
513 std::string default_frame_id_ =
"";
514 std::string prefix_ =
"";
516 ros::Duration lookup_timeout_ = ros::Duration(0);
517 bool retry_lookup_newest_ =
false;
519 bool got_utm_zone_ =
false;
520 std::array<char, 10> utm_zone_ = {};
523 std::string getFramePrefix(
const std::string& frame_id);
526 std::optional<T> transformImpl(
const geometry_msgs::TransformStamped& tf,
const T& what);
527 std::optional<mrs_msgs::ReferenceStamped> transformImpl(
const geometry_msgs::TransformStamped& tf,
const mrs_msgs::ReferenceStamped& what);
528 std::optional<Eigen::Vector3d> transformImpl(
const geometry_msgs::TransformStamped& tf,
const Eigen::Vector3d& what);
530 [[nodiscard]] std::optional<geometry_msgs::TransformStamped> getTransformImpl(
const std::string& from_frame,
const std::string& to_frame,
const ros::Time& time_stamp,
const std::string& latlon_frame);
531 [[nodiscard]] std::optional<geometry_msgs::TransformStamped> getTransformImpl(
const std::string& from_frame,
const ros::Time& from_stamp,
const std::string& to_frame,
const ros::Time& to_stamp,
const std::string& fixed_frame,
const std::string& latlon_frame);
533 std::string resolveFrameImpl(
const std::string& frame_id);
536 std::optional<T> doTransform(
const T& what,
const geometry_msgs::TransformStamped& tf);
550 static constexpr
const std::string&
frame_from(
const geometry_msgs::TransformStamped& msg)
552 return msg.child_frame_id;
563 static constexpr std::string&
frame_from(geometry_msgs::TransformStamped& msg)
565 return msg.child_frame_id;
574 static constexpr
const std::string&
frame_to(
const geometry_msgs::TransformStamped& msg)
576 return msg.header.frame_id;
587 static constexpr std::string&
frame_to(geometry_msgs::TransformStamped& msg)
589 return msg.header.frame_id;
598 static geometry_msgs::TransformStamped
inverse(
const geometry_msgs::TransformStamped& msg)
601 tf2::fromMsg(msg.transform, tf2);
603 return create_transform(
frame_to(msg),
frame_from(msg), msg.header.stamp, tf2::toMsg(tf2));
609 static geometry_msgs::TransformStamped create_transform(
const std::string& from_frame,
const std::string& to_frame,
const ros::Time& time_stamp)
611 geometry_msgs::TransformStamped ret;
614 ret.header.stamp = time_stamp;
618 static geometry_msgs::TransformStamped create_transform(
const std::string& from_frame,
const std::string& to_frame,
const ros::Time& time_stamp,
const geometry_msgs::Transform& tf)
620 geometry_msgs::TransformStamped ret;
623 ret.header.stamp = time_stamp;
633 using has_header_member_chk = decltype( std::declval<T&>().header );
635 static constexpr
bool has_header_member_v = std::experimental::is_detected<has_header_member_chk, T>::value;
637 template <
typename msg_t>
638 std_msgs::Header getHeader(
const msg_t& msg);
639 template <
typename pt_t>
640 std_msgs::Header getHeader(
const pcl::PointCloud<pt_t>& cloud);
642 template <
typename msg_t>
643 void setHeader(msg_t& msg,
const std_msgs::Header& header);
644 template <
typename pt_t>
645 void setHeader(pcl::PointCloud<pt_t>& cloud,
const std_msgs::Header& header);
647 template <
typename T>
648 T copyChangeFrame(
const T& what,
const std::string& frame_id);
653 geometry_msgs::Point LLtoUTM(
const geometry_msgs::Point& what,
const std::string& prefix);
654 geometry_msgs::PointStamped LLtoUTM(
const geometry_msgs::PointStamped& what,
const std::string& prefix);
655 geometry_msgs::Pose LLtoUTM(
const geometry_msgs::Pose& what,
const std::string& prefix);
656 geometry_msgs::PoseStamped LLtoUTM(
const geometry_msgs::PoseStamped& what,
const std::string& prefix);
658 std::optional<geometry_msgs::Point> UTMtoLL(
const geometry_msgs::Point& what,
const std::string& prefix);
659 std::optional<geometry_msgs::PointStamped> UTMtoLL(
const geometry_msgs::PointStamped& what,
const std::string& prefix);
660 std::optional<geometry_msgs::Pose> UTMtoLL(
const geometry_msgs::Pose& what,
const std::string& prefix);
661 std::optional<geometry_msgs::PoseStamped> UTMtoLL(
const geometry_msgs::PoseStamped& what,
const std::string& prefix);
664 template<
class Class,
typename Message>
665 using UTMLL_method_chk = decltype(std::declval<Class>().UTMtoLL(std::declval<const Message&>(),
""));
666 template<
class Class,
typename Message>
667 using LLUTM_method_chk = decltype(std::declval<Class>().LLtoUTM(std::declval<const Message&>(),
""));
668 template<
class Class,
typename Message>
669 static constexpr
bool UTMLL_exists_v = std::experimental::is_detected<UTMLL_method_chk, Class, Message>::value && std::experimental::is_detected<LLUTM_method_chk, Class, Message>::value;
678 #include <mrs_lib/impl/transformer.hpp>
680 #endif // TRANSFORMER_H