当前位置: 首页 > news >正文

ROS2之TF

TF

TF(Transform Frame) 是 ROS2 中用于维护多个坐标系之间空间关系的坐标变换系统。它可以实时跟踪机器人各个部分(如底盘、传感器、地图等)在三维空间中的位置与姿态,通过建立一棵动态的 坐标变换树(TF Tree),实现不同坐标系间的转换,使得各模块在统一的空间基准下进行感知、定位与导航。

ROS2 中的几大核心坐标系

坐标系名称 英文名 作用 常见来源
map Map Frame 表示世界或全局地图坐标系,固定不动 SLAM、AMCL、定位系统
odom Odometry Frame 由轮式里程计或视觉里程计建立,短期连续但可能漂移 里程计节点(odom publisher)
base_link Base Link Frame 机器人本体中心坐标系,所有传感器相对于此定义 机器人底盘(底盘驱动节点)
laser / camera_link Sensor Frame 各类传感器的坐标系(相机、激光雷达、IMU等) 驱动或URDF定义
map→odom→base_link 坐标链(Transform Tree) 描述世界到机器人到传感器的连续变换 tf2 广播与

其对应的层次结构

map
 └── odom
      └── base_link
           ├── laser_link
           └── camera_link

ROS2中TF对应的消息接口

消息类型 所属包 作用说明
geometry_msgs/msg/TransformStamped geometry_msgs 表示一个时间戳的坐标变换(最核心的单位)
tf2_msgs/msg/TFMessage tf2_msgs 表示一组变换(TransformStamped 数组),用于 TF 话题传输
geometry_msgs/msg/Transform geometry_msgs 表示平移 + 旋转的基本坐标变换
geometry_msgs/msg/Vector3 geometry_msgs 表示 3D 向量(用于平移部分)
geometry_msgs/msg/Quaternion geometry_msgs 表示四元数(用于旋转部分)

其中第一个消息接口是TF 系统的核心单元,下面是此消息接口的详细介绍

std_msgs/Header header             # 消息头部(包含时间戳和父坐标系信息)
  uint32 seq                        # 序列号(自动递增,用于标识消息顺序,可忽略)
  builtin_interfaces/Time stamp     # 时间戳(当前变换的时间点)
    int32 sec                       # 时间(秒)
    uint32 nanosec                  # 时间(纳秒),与 sec 组合成完整时间
  string frame_id                   # 父坐标系名称(Parent Frame),即该变换相对于谁

string child_frame_id               # 子坐标系名称(Child Frame),即被描述的目标坐标系

geometry_msgs/Transform transform   # 坐标变换(包括平移 + 旋转)
  geometry_msgs/Vector3 translation # 平移分量(位置)
    float64 x                       # 在父坐标系 X 方向的平移量(单位:米)
    float64 y                       # 在父坐标系 Y 方向的平移量(单位:米)
    float64 z                       # 在父坐标系 Z 方向的平移量(单位:米)

  geometry_msgs/Quaternion rotation # 旋转分量(姿态),使用四元数表示,得到一个旋转轴向量轴和w为旋转的角度
    float64 x                       # 四元数的 X 分量
    float64 y                       # 四元数的 Y 分量
    float64 z                       # 四元数的 Z 分量
    float64 w                       # 四元数的 W 分量(标量部分)

坐标变换包括静态和动态的

静态 TF 表示两个坐标系之间固定不动的空间关系,比如摄像头相对于机器人底盘的位置永远固定而动态 TF 用于描述随时间变化的坐标变换关系,比如机器人在地图中不断移动

image 

发布一个base_linkcamera_link的静态坐标转换话题

通过ros2 pkg create demo_python_tf --build-type ament_python --dependencies rclpy geometry_msgs tf_ros tf_transformations --license Apache-2.0创建功能包在工作区tf_ws下

import rclpy
from rclpy.node import Node
from tf2_ros import StaticTransformBroadcaster #静态坐标发布器
from geometry_msgs.msg import TransformStamped #消息接口
from tf_transformations import quaternion_from_euler#欧拉角转四元数函数
import math #角度转弧度函数class StaticTFBroadcaster(Node):def __init__(self):super().__init__('static_tf_broadcaster')self.static_broadcaster_= StaticTransformBroadcaster(self)self.publish_static_tf()def publish_static_tf(self):'''发布静态TF从base_link到camera_link之间的坐标关系'''transform= TransformStamped()transform.header.frame_id = 'base_link'transform.child_frame_id = 'camera_link'transform.header.stamp = self.get_clock().now().to_msg()transform.transform.translation.x = 0.5transform.transform.translation.y = 0.3transform.transform.translation.z = 0.6#欧拉角转四元数q=x,y,z,Wq = quaternion_from_euler(math.radians(180),0,0)#旋转部分进行赋值transform.transform.rotation.x = q[0]transform.transform.rotation.y = q[1]transform.transform.rotation.z = q[2]transform.transform.rotation.w = q[3]#静态坐标关系发布出去self.static_broadcaster_.sendTransform(transform)self.get_logger().info(f'发布静态TF:{transform}')
def main():rclpy.init()node = StaticTFBroadcaster()rclpy.spin(node)rclpy.shutdown()

 image

 发布一个bottle_linkcamera_link的动态坐标转换话题

import rclpy
from rclpy.node import Node
from tf2_ros import StaticTransformBroadcaster #静态坐标发布器
from geometry_msgs.msg import TransformStamped #消息接口
from tf_transformations import quaternion_from_euler#欧拉角转四元数函数
import math #角度转弧度函数class DynamicTFBroadcaster(Node):def __init__(self):super().__init__('dynamic_tf_broadcaster')self.static_broadcaster_= StaticTransformBroadcaster(self)# 没0.01秒触发发布一个瓶子相对于相机的坐标变换self.timer = self.create_timer(0.01,self.publish_dynamic_tf)def publish_dynamic_tf(self):'''发布动态TF从camera_link到bottle_link之间的坐标关系'''transform= TransformStamped()transform.header.frame_id = 'camera_link'transform.child_frame_id = 'bottle_link'transform.header.stamp = self.get_clock().now().to_msg()transform.transform.translation.x = 0.5transform.transform.translation.y = 0.3transform.transform.translation.z = 0.6#欧拉角转四元数q=x,y,z,Wq = quaternion_from_euler(math.radians(180),0,0)#旋转部分进行赋值transform.transform.rotation.x = q[0]transform.transform.rotation.y = q[1]transform.transform.rotation.z = q[2]transform.transform.rotation.w = q[3]#静态坐标关系发布出去self.static_broadcaster_.sendTransform(transform)self.get_logger().info(f'发布动态TF:{transform}')
def main():rclpy.init()node = DynamicTFBroadcaster()rclpy.spin(node)rclpy.shutdown()

image

创建订阅监听并获取得到base_linkbottle_link的转换关系,实时监听两个坐标系(base_linkbottle_link)之间的空间变换关系(平移 + 旋转),并将结果打印出来

import rclpy
from rclpy.node import Node
from rclpy.time import Time,Duration
from tf2_ros import TransformListener,Buffer 
from geometry_msgs.msg import TransformStamped #消息接口
from tf_transformations import euler_from_quaternion #四元数函数转欧拉角
import math #角度转弧度函数class TFListener(Node):def __init__(self):super().__init__('tf_listener')self.buffer =Buffer()self.listener =TransformListener(self.buffer,self)self.timer = self.create_timer(1.0,self.get_transform)def get_transform(self):'''实时查询坐标关系buffer'''try:# Time(seconds=0.0)为最新时间,Duration(seconds=1.0)为最大等待时间result = self.buffer.lookup_transform('base_link','bottle_link',Time(seconds=0.0),Duration(seconds=1.0))transform= result.transformself.get_logger().info(f'平移:{transform.translation}')self.get_logger().info(f'旋转:{transform.rotation}')rotation_euler = euler_from_quaternion([transform.rotation.x,transform.rotation.y,transform.rotation.z,transform.rotation.w])self.get_logger().info(f'旋转RPY:{rotation_euler}')except Exception as e:self.get_logger().warn(f'获取坐标变换失败:原因{str(e)}')
def main():rclpy.init()node = TFListener()rclpy.spin(node)rclpy.shutdown()

image

 C++实现查询静动态坐标系并查询

image

有地图坐标系,机器人坐标系和目标点,其中机器人是会移动的而其余两个则是静止的

#include <iostream>
#include <rclcpp/rclcpp.hpp>
#include <geometry_msgs/msg/transform_stamped.hpp> //提供消息接口
#include <tf2/LinearMath/Quaternion.h> //提供tf2::Quaternion类
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp> //消息类型转换函数
#include <tf2_ros/static_transform_broadcaster.h> //静态坐标广播器类
using namespace std;
using namespace rclcpp;class StaticTFBroadcaster: public Node
{private:shared_ptr<tf2_ros::StaticTransformBroadcaster> broadcaster;public:StaticTFBroadcaster(): Node("static_tf_broadcaster"){this->broadcaster = std::make_shared<tf2_ros::StaticTransformBroadcaster>(this);this->publish_tf();}void publish_tf(){geometry_msgs::msg::TransformStamped transform;transform.header.stamp = this->get_clock()->now();transform.header.frame_id="map";transform.child_frame_id="target_point";transform.transform.translation.x = 5.0;transform.transform.translation.y= 3.0;transform.transform.translation.z=0.0;tf2::Quaternion q;q.setRPY(0.0,0.0,60*M_PI/180.0);transform.transform.rotation =tf2::toMsg(q);this->broadcaster->sendTransform(transform);}};int main(int argc,char* argv[]){init(argc,argv);auto node = make_shared<StaticTFBroadcaster>();spin(node);shutdown();}
#include <iostream>
#include <rclcpp/rclcpp.hpp>
#include <geometry_msgs/msg/transform_stamped.hpp> //提供消息接口
#include <tf2/LinearMath/Quaternion.h> //提供tf2::Quaternion类
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp> //消息类型转换函数
#include <tf2_ros/static_transform_broadcaster.h> //静态坐标广播器类
using namespace std;
using namespace rclcpp;class DynamicTFBroadcaster: public Node
{private:shared_ptr<tf2_ros::StaticTransformBroadcaster> broadcaster;shared_ptr<TimerBase> timer;public:DynamicTFBroadcaster(): Node("dynamic_tf_broadcaster"){this->broadcaster = std::make_shared<tf2_ros::StaticTransformBroadcaster>(this);timer = this->create_wall_timer(100ms,bind(&DynamicTFBroadcaster::publish_tf,this));}void publish_tf(){geometry_msgs::msg::TransformStamped transform;transform.header.stamp = this->get_clock()->now();transform.header.frame_id="map";transform.child_frame_id="base_link";transform.transform.translation.x = 2.0;transform.transform.translation.y= 3.0;transform.transform.translation.z=0.0;tf2::Quaternion q;q.setRPY(0.0,0.0,60*M_PI/180.0);transform.transform.rotation =tf2::toMsg(q);this->broadcaster->sendTransform(transform);}};int main(int argc,char* argv[]){init(argc,argv);auto node = make_shared<DynamicTFBroadcaster>();spin(node);shutdown();}
#include <iostream>
#include <rclcpp/rclcpp.hpp>
#include <geometry_msgs/msg/transform_stamped.hpp> //提供消息接口
#include <tf2/LinearMath/Quaternion.h> //提供tf2::Quaternion类
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp> //消息类型转换函数
#include <tf2_ros/transform_listener.h> //监听器类
#include <tf2_ros/buffer.h>
#include <tf2/utils.h>
using namespace std;
using namespace rclcpp;class TFListener: public Node
{private:shared_ptr<tf2_ros::TransformListener> listener;shared_ptr<tf2_ros::Buffer> buffer;shared_ptr<TimerBase> timer;public:TFListener(): Node("tf_listener"){this->buffer = std::make_shared<tf2_ros::Buffer>(this->get_clock());this->listener = std::make_shared<tf2_ros::TransformListener>(*buffer,this);timer = this->create_wall_timer(100ms,bind(&TFListener::getTransfrom,this));}void getTransfrom(){try{//查询坐标关系const auto tranform = buffer->lookupTransform("base_link","target_point",this->get_clock()->now(),rclcpp::Duration::from_seconds(1.0f));//获取查询结果auto translation =tranform.transform.translation;auto rotation= tranform.transform.rotation;double y,p,r;tf2::getEulerYPR(rotation,y,p,r);RCLCPP_INFO(get_logger(),"平移:%f,%f,%f",translation.x,translation.y,translation.z);RCLCPP_INFO(get_logger(),"旋转:%f,%f,%f",y,p,r);}catch(const std::exception&e){RCLCPP_WARN(get_logger(),"%s",e.what());}}};int main(int argc,char* argv[]){init(argc,argv);auto node = make_shared<TFListener>();spin(node);shutdown();}

image

可视化工具

Rqt:rqt 是一个基于 Qt 框架的可视化工具框架,用于创建和集成各种 ROS 相关的图形化界面工具,rqt关联许多插件通过下面命令进行安装sudo apt install ros-$ROS_DISTRO-rqt* # 安装所有rqt插件(以ROS2 Humble为例)

例如sudo apt install ros-$ROS_DISTRO-rqt-tf-tree -y

安装之后需要更新配置环境

sudo rm -rf ~/.config/ros.org/rqt_gui.ini

image

然后启动rqt之后会自动生成一个带有新插件rqt_gui.ini

Rviz2:rviz2是 ROS2中最核心的 3D 可视化工具,用于实时显示机器人的传感器数据、状态信息、环境地图等,是机器人开发、调试和演示的必备工具。

通过add按钮可增加插件,FixedFrame为固定坐标系,其余坐标系的坐标都是以这个为参考,一般为世界坐标系

image

image

启动话题之后显示出三个坐标系

image

数据记录工具Ros2 bag

Ros2Bagros2 bag 是 ROS 2 中用于记录和回放话题数据的核心工具,类似于 ROS 1 中的 rosbag。它能将 ROS 2 系统中流转的话题数据(如传感器数据、机器人状态等)存储到 .bag 文件中,便于离线分析、场景复现或数据共享。

bag 文件:存储 ROS 2 话题数据的二进制文件,包含话题名称、消息类型、时间戳及具体数据,后缀为 .bag(ROS 2 中默认使用 SQLite 格式,与 ROS 1 的格式不同)。

核心功能:记录(record)、回放(play)、查看信息(info)、验证(check)等。

http://www.hskmm.com/?act=detail&tid=29641

相关文章:

  • 深入解析:2025年真实手机牧场CC攻击破防游戏盾?四维防御体系全面升级!
  • 代码源2025长训
  • 代码源国庆模拟赛
  • CSP-S模拟30 2025.10.12
  • 记录fiddler抓包mumu模拟器
  • 神经网络读书报告
  • 机器学习初识
  • MinIO 介绍(2)--MinIO 客户端 mc 基本功能
  • 深度学习初识
  • 关于UE5基础关卡创建的注意点
  • 2025年10月恒温恒湿系统厂家最新推荐榜单,精加工车间/厂房/美术馆/仓库/计算机房/档案室/工业/工厂车间恒温恒湿空调系统公司推荐
  • 征集歌单
  • Hello world
  • ABC427 游记
  • 乐理 -02调式
  • Python 基于python实现的图片压缩助手
  • ElasticSearch
  • 20232302 2025-2026-1《网络与系统攻防技术》实验一实验报告
  • 2023 ICPC ECfinal J
  • 嵌入式十六进制的地址转换成十进制MB单位
  • 20232318 2025-2026-1 《网络与系统攻防技术》 实验一实验报告
  • 实时Galgame - 动漫角色 语言生成+图片生成
  • 系统响应慢分析案例
  • Linux文件系统与磁盘工作原理
  • 平安好车主小程序 充电站、加油站列表vmp+wasm逆向
  • Linux文件系统的实验
  • 软中断softirq的CPU使用率升高
  • CPU多进程切换导致过载-CPU上下文切换
  • Vue3 之pinia状态管理
  • 乐理 -01识谱