tf学习
1 tf简介
1.1 什么是tf
tf是一个让用户随时间跟踪多个参考系的功能包,它使用一种树型数据结构,根据时间缓冲并维护多个参考系之间的坐标变换关系,可以帮助用户在任意时间,将点、向量等数据的坐标,在两个参考系中完成坐标变换。
tf的相关设计思想,可以参见:tf设计
1.2 tf可以做什么
一个机器人系统通常有很多三维的参考系,而且会随着时间的推移发生变化,例如全局参考系(world frame),机器人中心参考系(base frame),机械夹参考系(gripper frame),机器人头参考系(head frame)等等。tf可以以时间为轴,跟踪这些参考系(默认是10秒之内的),并且允许用户提出如下的申请:
- 五秒钟之前,机器人头参考系相对于全局参考系的关系是什么样的?
- 机器人夹取的物体相对于机器人中心参考系的位置在哪里?
- 机器人中心参考系相对于全局参考系的位置在哪里?
1.3 tf的使用流程
想要使用tf功能包,总体来讲可以分为以下两个步骤:
(1) 监听tf变换
接收并缓存系统中发布的所有参考系变换,并从中查询所需要的参考系变换。
(2) 广播tf变换
向系统中广播参考系之间的坐标变换关系。系统中更可能会存在多个不同部分的tf变换广播,每个广播都可以直接将参考系变换关系直接插入tf树中,不需要再进行同步。template <typename T> class Stamped:public T { public: ros::Time stamp_; std::string frame_id_; Stamped() :frame_id_("NO_ID_STAMPED_DEFAULT_CONSTRUCTION"){};// 默认构造器仅仅是用于预分配 Stamped(const T& input, const ros::Time& timestamp, const std::string & frame_id); void setData(const T& input); }
1.3 tf::StampedTransform
tf::StampedTransform 是一个tf::Transforms的特殊例子,它包含了坐标系frame_id,时间戳stamp以及子坐标系child_frame_id.
/*由tf使用的时间戳的transform类型*/ class StampedTransform : public tf::Transform { public: ros::Time stamp_;//与变换transform相关的时间戳 std::string frame_id_;//坐标系的frame_id,transform被定义在该坐标系里面 StampedTransform(const tf::Transform& input, const ros::Time& timestamp, const std::string & frame_id, const std::string & child_frame_id): tf::Transform ( input ), stamp_ ( timestamp ), frame_id_ (frame_id), child_frame_id_(child_frame_id) { }; //默认的构造器只用于预分配 StampedTransform() {} //设置继承的Transform数据 void setData(const tf::Transform& input){*static_cast<tf::Transform*>(this) = input;} };
1.4)帮助函数
tf::Quaternion createIdentityQuaternion()
Return an identity quaternion.
tf::Quaternion createQuaternionFromRPY(double roll , double pitch, double yaw)
Return a tf::Quaternion constructed from Fixed-Axis Roll, Pitch and Yaw
geometry_msgs::Quaternion createQuaternionMsgFromRollPitchYaw(double roll, double pitch, double yaw)
Return a geometry_msgs::Quaternion constructed from Fixed-Axis Roll,Pitch and Yaw.
1.5)数据类型转换Data type conversions
http://docs.ros.org/api/tf/html/c++/transform__datatypes_8h.html
2)变换与参考系
坐标系,变换,以及TF
1.参考
2.坐标系和点
一个frame是一个坐标系统。在ROS中的坐标系统总是以3D的形式,右手坐标系,X向前,Y左,Z向上。
在坐标系中的点用tf::Point来表示,它等同于bullet type btVector3。在坐标系W中的点p的坐标被写为Wp.
3.坐标系的位姿
在两个坐标系之间的关系用一个6DOF的相对位姿来表示,一个平移加上一个旋转。如果W和A是两个坐标系,在W坐标系中A的位姿用从W的原点到A的原点的平移和A坐标轴在W中的旋转来表示。
在W坐标系当中,平移是一个向量,WtA.它由tf::Vector3来表示,它等同于btVector3。
A的旋转由一个旋转矩阵来表示,表示为WAR,读的方式:“坐标系A在W坐标系中的旋转。”R的列是在W中由A的三个轴的单位向量组成:WXA, WYA, and WZA.
没有tf类型用于旋转矩阵;而是,tf表示旋转通过tf::Quaternion来表示,等同于btQuaternion。bullet quaternion类型有函数用于创建四元素从旋转矩阵当中,反之,也有。
在齐次坐标系当中,表达平移和旋转是很方便的,用一个4*4的矩阵WAT。可以读作:“A坐标系相对于W坐标系的位姿”,相对位姿由以下来构造:
WAR |
WtA |
0 |
1 |
在tf中,相对位姿由tf::Pose表示,它等同于bullet type btTransform。成员函数是getRotation()或者getBasis()用于旋转,另外getOffset()用于位姿的平移。See the bullet btTransform class reference.
4.坐标系位姿作为点映射Frame poses as Point Mappings
在位姿和映射点之间存在二元性,当从一个坐标系到另一个坐标系的时候。位姿WAT可以被读作,“把A坐标系中的点转换到W坐标系当中”
void sendTransform(const StampedTransform & transform); void sendTransform(const geometry_msgs::TransformStamped & transform);
1.TransformListener
对于使用tf的大部分情况,通过tf::TransformListener就可以完成。它从tf::Transform中继承了一些方法,以下是一些主要的方法:
1.1构造器
TransformListener(const ros::NodeHandle &nh, ros::Duration max_cache_time = ros::Duration(DEFAULT_CACHE_TIME), bool spin_thread = true); TransformListener(ros::Duration max_cache_time=ros::Duration(DEFAULT_CACHE_TIME), bool spin_thread=true);
1.2帮助函数
std::string tf::TransformListener::resolve (const std::string &frame_id)
遵循tf_prefix规则来解析frame_id。See geometry/CoordinateFrameConventions.
1.3 canTransform()
该方法返回一个bool,是否该变换可以被评估。它不会throw。如果你传递了一个非NULL的字符串指针,它将会填充字符串error_msgs以免错误。
NOTE: this takes notably more resources to generate the error message.
1.3.1 基本的API
bool tf::TransformListener::canTransform (const std::string &target_frame, const std::string & source_frame, const ros::Time &time, std::string *error_msg=NULL) const
测试是否源frame可以被转换到目标frame在规定的时间内
1.3.2 高级 API
bool tf::TransformListener::canTransform (const std::string &target_frame,const ros::Time &target_time,const std::string & source_frame, const ros::Time &source_time, const std::string &fixed_frame,std::string *error_msg=NULL) const
Test if source_frame can be transformed to fixed_frame at time source_time, and from there can be tranformed into target_frame at target_time.
1.4 waitForTransform
1.4.1 基本API
bool tf::TransformListener::waitForTransform (const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration &timeout, const ros::Duration &polling_sleep_duration=ros::Duration(0.01), std::string *error_msg=NULL) const
Test if source_frame can be transformed to target_frame at time time.
The waitForTransform() methods return a bool whether the transform can be evaluated. It will sleep and retry every polling_duration until the duration of timeout has been passed. It will not throw. If you pass a non NULL string pointer it will fill the string error_msg in the case of an error.
1.4.2 高级API
bool tf::TransformListener::waitForTransform (const std::string &target_frame, const ros::Time &target_time, const std::string &source_frame, const ros::Time &source_time, const std::string &fixed_frame, const ros::Duration &timeout, const ros::Duration &polling_sleep_duration=ros::Duration(0.01), std::string *error_msg=NULL) const
Test if source_frame can be transformed to fixed_frame at time source_time, and from there can be transformed into target_frame at target_time.
1.5 lookupTransform
lookupTransform()是一个更底层的方法,它将返回两个坐标系之间的transform。该方法是tf库的核心功能,然而,常见的transform * 方法将被终端用户使用。该方法被设计于在transform*()中使用。
返回的变换的方向是从目标坐标系到源坐标系。如果将之应用到数据,将会转换源坐标系中的数据到目标坐标系当中。See geometry/CoordinateFrameConventions#Transform_Direction。This may throw any tf exception。
1.5.1 基本的API
void tf::TransformListener::lookupTransform (const std::string &target_frame, const std::string &source_frame, const ros::Time &time, StampedTransform &transform) const
Fill transform with the transform from source_frame to target_frame at time.
1.5.2 高级API
void tf::TransformListener::lookupTransform (const std::string &target_frame, const ros::Time &target_time, const std::string &source_frame, const ros::Time &source_time, const std::string &fixed_frame, StampedTransform &transform) const
Fill transform with the transform from source_frame to fixed_frame at source_time, chained with the transform from fixed_frame to target_frame at target_time
1.6 transformDATA Methods
tf::TransformListener的主要目的是在两个坐标系之间变换数据,以下是两个主要的原型
1.6.1 支持的数据类型
C++ Method Name |
Python Method Name |
Full Datatype |
transformQuaternion() |
none |
tf::Stamped<tf::Quaternion> |
transformVector() |
none |
tf::Stamped<tf::Vector3> |
transformPoint() |
none |
tf::Stamped<tf::Point> |
transformPose() |
none |
tf::Stamped<tf::Pose> |
transformQuaternion() |
transformQuaternion() |
|
transformVector() |
transformVector3() |
|
transformPoint() |
transformPoint() |
|
transformPose() |
transformPose() |
|
transformPointCloud() |
transformPointCloud() |
1.6.2 基本的API
c++
void tf::TransformListener::transformDATATYPE (const std::string &target_frame, const geometry_msgs::DATATYPEStamped &stamped_in, geometry_msgs::DATATYPEStamped &stamped_out) const
Transform the data stamped_in into the target_frame, using the frame_id and stamp inside the stamped datatype as the source.
1.6.3 高级API
void tf::TransformListener::transformDATATYPE (const std::string &target_frame, const ros::Time &target_time, const geometry_msgs::DATATYPEStamped &pin, const std::string &fixed_frame, geometry_msgs::DATATYPEStamped &pout) const
Transform the data stamped_in into the fixed_frame. Using the frame_id and stamp inside the stamped datatype as the source. Then transform from the fixed_frame into the target_frame at the target_time.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】