TF坐标变换(一)

本文详细介绍了ROS中的geometry_msgs/TransformStamped和geometry_msgs/PointStamped消息格式,展示了如何在坐标转换中使用这些消息来表示坐标系关系和点坐标。同时讲解了静态坐标变换的概念及其在机器人模型中的应用,包括发布方和订阅方的实现步骤,以及rviz工具的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.msg信息

订阅发布模型中数据载体 msg 是一个重要实现,首先需要了解一下,在坐标转换实现中常用的 msg:geometry_msgs/TransformStampedgeometry_msgs/PointStamped

前者用于传输坐标系相关位置信息,后者用于传输某个坐标系内坐标点的信息。在坐标变换中,频繁的需要使用到坐标系的相对关系以及坐标点信息。

1.geometry_msgs/TransformStamped

命令行键入:rosmsg info geometry_msgs/TransformStamped

std_msgs/Header header                     #头信息
  uint32 seq                                #|-- 序列号
  time stamp                                #|-- 时间戳
  string frame_id                            #|-- 坐标 ID
string child_frame_id                    #子坐标系的 id
geometry_msgs/Transform transform        #坐标信息
  geometry_msgs/Vector3 translation        #偏移量
    float64 x                                #|-- X 方向的偏移量
    float64 y                                #|-- Y 方向的偏移量
    float64 z                                #|-- Z 方向上的偏移量
  geometry_msgs/Quaternion rotation        #四元数
    float64 x                                
    float64 y                                
    float64 z                                
    float64 w

四元数用于表示坐标的相对姿态

2.geometry_msgs/PointStamped

命令行键入:rosmsg info geometry_msgs/PointStamped

std_msgs/Header header                    #头
  uint32 seq                                #|-- 序号
  time stamp                                #|-- 时间戳
  string frame_id                            #|-- 所属坐标系的 id
geometry_msgs/Point point                #点坐标
  float64 x                                    #|-- x y z 坐标
  float64 y
  float64 z

序列号
在ROS中,序列号是用于标识消息的唯一数字。每当发布者发布一个消息时,它会递增序列号,确保每个消息都有一个唯一的标识符。序列号通常是一个32位的无符号整数(uint32)。

序列号的主要目的是在通信中跟踪消息的顺序和唯一性。这对于消费者来说是很重要的,特别是在处理实时数据时。通过序列号,消费者可以检测是否有消息丢失或重复,并确保按照正确的顺序处理它们。

在ROS消息头(std_msgs/Header)中,有一个名为seq的字段,它表示消息的序列号。这个字段的值会在每个新消息中递增,为每个消息提供一个唯一的标识符

时间戳
时间戳在ROS消息头(std_msgs/Header)中的作用是提供消息创建的时间信息。在header中的stamp字段包含了消息的时间戳,表示消息被创建的具体时刻


2. 静态坐标变换

所谓静态坐标变换,是指两个坐标系之间的相对位置是固定的。

需求描述:

现有一机器人模型,核心构成包含主体与雷达,各对应一坐标系,坐标系的原点分别位于主体与雷达的物理中心,已知雷达原点相对于主体原点位移关系如下: x 0.2 y0.0 z0.5。当前雷达检测到一障碍物,在雷达坐标系中障碍物的坐标为 (2.0 3.0 5.0),请问,该障碍物相对于主体的坐标是多少?

结果演示:
实现分析:
  1. 坐标系相对关系,可以通过发布方发布
  2. 订阅方,订阅到发布的坐标系相对关系,再传入坐标点信息(可以写死),然后借助于 tf 实现坐标变换,并将结果输出
实现流程:
  1. 新建功能包,添加依赖
  2. 编写发布方实现
  3. 编写订阅方实现
  4. 执行并查看结果

1.创建功能包

创建项目功能包依赖于 tf2、tf2_ros、tf2_geometry_msgs、roscpp rospy std_msgs geometry_msgs
(总共七个功能包,创建项目依赖时别遗漏)

2.发布方
#! /usr/bin/env python
"""  
    静态坐标变换发布方:
        发布关于 laser 坐标系的位置信息 
    实现流程:
        1.导包
        2.初始化 ROS 节点
        3.创建 静态坐标广播器
        4.创建并组织被广播的消息
        5.广播器发送消息
        6.spin
"""
# 1.导包
import rospy
import tf2_ros
import tf
from geometry_msgs.msg import TransformStamped

if __name__ == "__main__":
    # 2.初始化 ROS 节点
    rospy.init_node("static_tf_pub_p")
    # 3.创建 静态坐标广播器
    broadcaster = tf2_ros.StaticTransformBroadcaster()
    # 4.创建并组织被广播的消息
    tfs = TransformStamped()
    # --- 头信息
    tfs.header.frame_id = "base_link"
    tfs.header.stamp = rospy.Time.now()
    tfs.header.seq = 101
    # --- 子坐标系
    tfs.child_frame_id = "laser"
    # --- 坐标系相对信息
    # ------ 偏移量
    tfs.transform.translation.x = 0.2
    tfs.transform.translation.y = 0.0
    tfs.transform.translation.z = 0.5
    # ------ 四元数
    # 先从欧拉角转换为四元数
    qtn = tf.transformations.quaternion_from_euler(0,0,0)
    #再设置四元数
    tfs.transform.rotation.x = qtn[0]
    tfs.transform.rotation.y = qtn[1]
    tfs.transform.rotation.z = qtn[2]
    tfs.transform.rotation.w = qtn[3]


    # 5.广播器发送消息
    broadcaster.sendTransform(tfs)
    # 6.spin
    rospy.spin()

notice: 四元数通常不会直接设置,而是先设置欧拉角,然后再用已经封装好的函数将欧拉角转换为四元数

权限设置以及配置文件此处略。

3.订阅方
#! /usr/bin/env python
"""  
    订阅坐标系信息,生成一个相对于 子级坐标系的坐标点数据,
    转换成父级坐标系中的坐标点

    实现流程:
        1.导包
        2.初始化 ROS 节点
        3.创建 TF 订阅对象
        4.创建一个 laser 坐标系中的坐标点
        5.调研订阅对象的 API 将 4 中的点坐标转换成相对于 base_link 的坐标
        6.spin

"""
# 1.导包
import rospy
import tf2_ros
# 不要使用 geometry_msgs,需要使用 tf2 内置的消息类型
from tf2_geometry_msgs import PointStamped
# from geometry_msgs.msg import PointStamped

if __name__ == "__main__":
    # 2.初始化 ROS 节点
    rospy.init_node("static_sub_tf_p")
    # 3.创建 TF 订阅对象
    # 3-1 创建缓存对象
    buffer = tf2_ros.Buffer()
    # 3-2 创建订阅对象(将缓存传入)
    listener = tf2_ros.TransformListener(buffer)

    rate = rospy.Rate(1)
    while not rospy.is_shutdown():    
    # 4.创建一个 laser 坐标系中的坐标点
        point_source = PointStamped()
        point_source.header.frame_id = "laser"
        point_source.header.stamp = rospy.Time.now()
        point_source.point.x = 10
        point_source.point.y = 2
        point_source.point.z = 3

        try:
    #     5.调研订阅对象的 API 将 4 中的点坐标转换成相对于 base_link 的坐标
            point_target = buffer.transform(point_source,"base_link")
            rospy.loginfo("转换结果:x = %.2f, y = %.2f, z = %.2f",
                            point_target.point.x,
                            point_target.point.y,
                            point_target.point.z)
        except Exception as e:
            rospy.logerr("异常:%s",e)

    #     6.spin
        rate.sleep()

权限设置以及配置文件此处略。

PS: 在 tf2 的 python 实现中,tf2 已经封装了一些消息类型,不可以使用 geometry_msgs.msg 中的类型

notice first

tf2_ros.TransformListener 是一个用于订阅和监听ROS中坐标变换消息的类。它是TF2库的一部分,TF2库用于在ROS中处理坐标变换。
具体来说,tf2_ros.TransformListener 的作用包括:

  1. 订阅坐标变换消息: 它订阅了ROS中发布的坐标变换消息,这些消息描述了不同坐标系之间的变换关系。

  2. 监听坐标变换: 一旦订阅了坐标变换消息,TransformListener 可以监听并提供在两个坐标系之间进行变换的功能。

  3. 缓存坐标变换: 它使用一个缓存(通常是 tf2_ros.Buffer 类型的对象)来存储已接收到的坐标变换信息。这样,在需要进行坐标变换时,可以直接从缓存中获取,而无需重新计算。

  4. 提供坐标变换的查询接口: 通过调用 buffer.transform() 等方法,可以查询缓存中已存储的坐标变换信息。

notice second
  1. 在执行 buffer = tf2_ros.Buffer() 这一行时,buffer 对象被创建,但此时并没有内容。tf2_ros.Buffer 对象是一个用于存储和查询坐标变换信息的缓存,它在后续的使用中通过监听和存储变换信息来填充缓存。

  2. 在这段代码中,listener = tf2_ros.TransformListener(buffer) 创建了一个 TransformListener 对象,并将之前创建的 buffer 对象传递给它。这个 TransformListener 对象会在循环中监听坐标变换,并将获取到的变换信息存储到 buffer 中。因此,当执行 buffer.transform(point_source, "base_link") 时,buffer 中才会包含坐标变换的信息。

notice third

在ROS中,tf2_ros 提供了与坐标变换(tf2)相关的ROS功能包。以下是主要功能和类:

  1. Buffer (tf2_ros.Buffer): 用于存储和查询坐标变换信息的缓存。Buffertf2的ROS封装,它可以在监听到坐标变换信息后存储这些信息,并在需要时提供坐标变换查询。

  2. TransformListener (tf2_ros.TransformListener): 用于监听坐标变换信息并将其存储到 Buffer 中。TransformListener 对象负责接收tf2广播的变换信息,并将其存储在关联的 Buffer 中,以便进行后续的查询。

  3. StaticTransformBroadcaster (tf2_ros.StaticTransformBroadcaster): 用于发布静态坐标变换信息的类。静态坐标变换是在运行时不会改变的坐标变换,通过 StaticTransformBroadcaster 可以将这些信息发布到tf2。

  4. MessageFilter (tf2_ros.MessageFilter): 用于在ROS话题消息上应用坐标变换的类。它可以通过提供一个回调函数,在消息传递过程中应用坐标变换。

这些类在ROS中被广泛用于处理坐标变换,让不同坐标系之间的变换变得更加简单和方便。

4.执行

可以使用命令行或launch文件的方式分别启动发布节点与订阅节点,如果程序无异常,控制台将输出,坐标转换后的结果。


补充1:

当坐标系之间的相对位置固定时,那么所需参数也是固定的: 父系坐标名称、子级坐标系名称、x偏移量、y偏移量、z偏移量、x 翻滚角度、y俯仰角度、z偏航角度,实现逻辑相同,参数不同,那么 ROS 系统就已经封装好了专门的节点,使用方式如下:

rosrun tf2_ros static_transform_publisher x偏移量 y偏移量 z偏移量 z偏航角度 y俯仰角度 x翻滚角度 父级坐标系 子级坐标系

示例:rosrun tf2_ros static_transform_publisher 0.2 0 0.5 0 0 0 /baselink /laser

也建议使用该种方式直接实现静态坐标系相对信息发布。

补充2:

可以借助于rviz显示坐标系关系,具体操作:

  • 新建窗口输入命令:rviz;
  • 在启动的 rviz 中设置Fixed Frame 为 base_link;
  • 点击左下的 add 按钮,在弹出的窗口中选择 TF 组件,即可显示坐标关系。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值