【总结学习】ROS——TF tree

本文主要介绍了ROS中的TF框架,讲解了如何进行坐标系转化,特别是TransformStamped消息中的父节点和子节点关系。重点在于理解TransformStamped用于将子坐标系下的点转换到父坐标系,并提供了转换函数transformPose的使用方法。同时,文章还提到了四元数与欧拉角的转化,并给出了相关参考资料。


近期进行了机器人相关的项目,其中涉及了TF tree的概念,查阅浏览了相关材料,准备把相关知识总结一下,到时候也方便自己查看,若有侵权,实在抱歉,请联系我进行删除,感谢~

最重要的关键点

坐标系转化

通常来说 geometry_msgs/TransformStamped.msg 定义了两个坐标系的转换关系,在 TransformStamped 下Header 中的 frame_id 表示的是父节点, 与 Header 同一级别的 child_frame_id 表示的子节点。父节点与子节点在 TF tree 关系图中表示为,父节点——箭头指向——子节点 ,这也有助于根据 rqt_graph 中出现的节点图来判断节点之间的关系。

那么在 TransformStamped 中另外一个重要的部分是 transform ,官方对其描述为 # This represents the transform between two coordinate frames in free space,也就是说在这一部分中定义了两个坐标系的转换关系,具体地 transform 由 translation 以及 rotation 组成,分别代表了平移和旋转,因为任意两个坐标系都可以通过有限的平移和转旋所重合。

重点!!那么上面所说的 TransformStamped 描述的是 父节点中的坐标系向子节点坐标系转换呢,还是子节点内坐标系向父节点所代表的坐标系转化呢。答案是,其作用是将在 子坐标系下的A点的坐标,转换到A点在父坐标系下的新坐标。所以在使用该msgs时一定要区分清楚,想要将某一点的坐标转换到哪一个坐标系下,这个想要转换到的坐标系就是你的父节点所代表的坐标系。同时, transform 部分如何赋值呢,具体地为,针对 子结点所代表的坐标系的原点,得到这个原点在父坐标系下的位置,以及旋转角度,然后将其坐标和转旋直接填入到 transform 内对应的 translation.x/y/z 以及 rotation.x/y/z/w 即可。

坐标转化 TransformPose

void transformPose(const std::string &target_frame, const geometry_msgs::PoseStamped &stamped_in, geometry_msgs::PoseStamped &stamped_out) const

target_frame 为目标坐标系。假如原始 pose 的 frame_id 为 “odom”,想要转化到 "map"上,则 target_frame 为“map” 。stamped_in 为源pose,而stamped_out就是输出目标数据了,即转换完成的数据。

需要注意的是,在参数输入中,是不需要指定 源frame_id的,这是因为 在原 pose 当中是会包含 自己的frame_id 的,换句话说,就是TransformPose 函数一个隐含的使用条件是,stamped_in 必须带有自己的 frame_id。

cppgeometry_msgs::PoseStamped pose_odom;
pose_odom.header = odom->header;
pose_odom.pose = odom->pose.pose;
 
geometry_msgs::PoseStamped pose_map;

将其放入到整个代码当中

#include <tf/transform_listener.h>
#include <nav_msgs/Odometry.h>
#include <ros/ros.h>void odomReceived(const nav_msgs::Odometry::ConstPtr& odom)
{
    // transform from "odom" to "map"    tf::TransformListener listener;
    geometry_msgs::PoseStamped pose_odom;
    pose_odom.header = odom->header;
    pose_odom.pose = odom->pose.pose;
 
    geometry_msgs::PoseStamped pose_map;
 
    try{
        listener.transformPose("map", pose_odom, pose_map);
    }
    catch( tf::TransformException ex)
    {
        ROS_WARN("transfrom exception : %s",ex.what());
        return;
    }
 
    ROS_INFO_STREAM(pose_map);
}

描述规范:

  1. source、target frame是在进行坐标变换时的概念,source是坐标变换的源坐标系,target是目标坐标系。这个时候,这个变换代表的是坐标变换。
  2. parent、child frame是在描述坐标系变换时的概念,parent是原坐标系,child是变换后的坐标系,这个时候这个变换描述的是坐标系变换,也是child坐标系在parent坐标系下的描述。
  3. a frame到b frame的坐标系变换(frame transform),也表示了b frame在a frame的描述,也代表了把一个点在b frame里坐标变换成在a frame里坐标的坐标变换。
  4. 从parent到child的坐标系变换(frame transform)等同于把一个点从child坐标系向parent坐标系的坐标变换,等于child坐标系在parent frame坐标系的姿态描述。

四元数的相关转化

参考这篇文章,很详细
https://blog.youkuaiyun.com/sunqin_csdn/article/details/108045463

四元数转化欧拉角——可视化

https://quaternions.online/

参考文献

[1] https://www.guyuehome.com/355
[2] https://chanchanchan97.github.io/2020/03/26/TF%E5%9D%90%E6%A0%87%E7%B3%BB%E5%8F%98%E6%8D%A2%E7%9A%84%E7%BC%96%E7%A8%8B%E5%AE%9E%E7%8E%B0/
[3] https://blog.youkuaiyun.com/u012706484/article/details/108070293
[4] https://zhuanlan.zhihu.com/p/442775614
[5] https://www.cnblogs.com/sxy370921/p/11726691.html
[6] https://sychaichangkun.gitbooks.io/ros-tutorial-icourse163/content/chapter8/8.2.html
[7] https://blog.youkuaiyun.com/kalenee/article/details/107593033
[8] https://blog.youkuaiyun.com/liuzubing/article/details/81014240
[9] https://blog.youkuaiyun.com/weixin_45590473/article/details/122908060?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-1-122908060-blog-106680103.pc_relevant_default&spm=1001.2101.3001.4242.2&utm_relevant_index=4

03-08
### ROS TF2 使用指南和常见问题解决 #### 安装与配置 为了使用 `tf2`,通常不需要单独安装该库,因为大多数ROS 2发行版已经包含了它。然而,在某些情况下可能需要额外组件的支持。例如,对于特定功能如监听器或广播器,可以利用Python接口来操作变换树[^2]。 #### 基本概念介绍 - **Transform Tree (TF tree)** 是一个有向无环图(DAG),节点代表坐标系之间的相对位置关系。 - **Static Transform Publisher**: 发布静态转换信息;适用于固定不变的关系。 - **Broadcasters 和 Listeners** : 广播当前时刻的空间变换数据以及订阅这些消息并查询历史记录。 #### Python API 示例 下面是一个简单的例子展示如何创建一个发布者和接收者的配对: ```python import rclpy from geometry_msgs.msg import TransformStamped from tf2_ros import StaticTransformBroadcaster, Buffer, TransformListener def handle_turtle_pose(msg, turtlename): stfbrd = StaticTransformBroadcaster(node) # 构建新的变换帧 transform = TransformStamped() transform.header.stamp = node.get_clock().now().to_msg() transform.header.frame_id = 'world' transform.child_frame_id = f'{turtlename}/base_link' # 设置平移分量 transform.transform.translation.x = msg.x transform.transform.translation.y = msg.y # 添加旋转四元数表示法... quaternion = euler_to_quaternion(0, 0, theta) # Assuming you have a function to convert Euler angles to Quaternion. transform.transform.rotation.w = quaternion[0] transform.transform.rotation.x = quaternion[1] transform.transform.rotation.y = quaternion[2] transform.transform.rotation.z = quaternion[3] stfbrd.sendTransform(transform) if __name__ == '__main__': rclpy.init() node = rclpy.create_node('my_tf_broadcaster') sub = node.create_subscription( Pose, '/turtle1/pose', lambda msg: handle_turtle_pose(msg, 'turtle1'), 10) try: while rclpy.ok(): rclpy.spin_once(node) except KeyboardInterrupt: pass node.destroy_node() rclpy.shutdown() ``` 这段代码展示了怎样通过监听海龟机器人的姿态变化并将之作为世界坐标系下的位姿更新发送出去。 #### 解决方案建议 如果遇到无法获取预期的变换结果的问题时,请确认以下几点: - 所有的广播源都正常工作并且频率合理; - 时间戳同步良好——即所有参与计算的时间标记应该尽可能接近实际发生时间; - 正确设置了父级(`frame_id`)和子级(`child_frame_id`)名称; - 如果涉及到多个不同步的消息流,则考虑引入缓存机制以确保一致性。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值