一、理论理解
1.TF:维护机器人各个坐标系之间位姿变换关系
举例:base_link 机器人底盘,laser_link 激光雷达,雷达装在底盘上方,需要告诉 ROS 雷达相对于底盘在哪。
2.TF广播器TransformBroadcaster:向外发布「子坐标系相对父坐标系」的位姿(平移 + 旋转)。传感器、底盘都要广播自己的坐标系。
3.TF 监听器 TransformListener:查询两个坐标系之间的变换,把数据从一个坐标系转换到另一个坐标系。导航算法、点云处理都靠监听。
4.父坐标系 / 子坐标系:描述:子坐标系相对于父坐标系的位置姿态
5.旋转不用手写矩阵,使用tf::Quaternion生成四元数。
6.ros::Time(0):获取缓存中最新的 TF 数据,新手固定写这个。
7.监听必须加try‑catch异常捕获,TF 找不到变换直接会让程序崩溃。
二、代码实现

// ROS核心头文件,提供节点初始化、句柄、时间、Rate、spinOnce等全部基础功能
#include <ros/ros.h>
// tf旧版广播器头文件,tf::TransformBroadcaster、tf::Transform、tf::Quaternion都在这里
#include <tf/transform_broadcaster.h>

// 程序入口 main函数
// argc:命令行参数个数;argv:命令行参数数组,ros::init会从这里提取ROS相关参数
int main(int argc, char** argv)
{
    // ①ROS节点初始化
    // 参数:命令行参数,节点名字:tf_broadcaster_node
    ros::init(argc, argv, "tf_broadcaster_node");

    // ②创建节点句柄nh
    // 句柄相当于你程序和ROS系统沟通的手柄,发布、订阅、参数、tf都依赖它
    ros::NodeHandle nh;

    // ③设置循环频率对象 rate,10Hz,代表每秒循环执行10次,单次周期0.1s
    ros::Rate rate(10); 

    // ④创建TF广播器对象 br
    // TransformBroadcaster专门用来向外发布坐标变换消息,底层会自动订阅/tf话题
    tf::TransformBroadcaster br;

    // ⑤ROS主循环
    // ros::ok() 判断节点是否正常运行;按下Ctrl+C,ros::ok()返回false,退出循环
    while(ros::ok())
    {
        // transform:存储一组坐标变换,包含两部分:平移(origin) + 旋转(rotation)
        tf::Transform transform;

        // setOrigin() 设置平移部分
        // tf::Vector3(x,y,z) 三维向量,单位米
        // 含义:子坐标系laser_link,在父坐标系base_link下坐标(0, 0, 0.2),底盘正上方0.2米
        transform.setOrigin(tf::Vector3(0.0, 0.0, 0.2));

        // tf::Quaternion 四元数,ROS用来存储旋转姿态,避免欧拉角万向锁缺陷
        tf::Quaternion q;

        // setRPY(roll, pitch, yaw) 单位:弧度!不是角度
        // roll:绕X轴旋转;pitch:绕Y轴旋转;yaw:绕Z轴旋转(机器人转向)
        // 全部填0:代表没有任何旋转,laser_link和base_link朝向完全一致
        q.setRPY(0,0,0);

        // 将四元数旋转赋值给transform变换对象
        transform.setRotation(q);

        // ==========核心:广播TF变换 sendTransform==========
        // StampedTransform:带时间戳的变换,TF的每条变换必须绑定时间
        br.sendTransform(tf::StampedTransform(
            transform,          // 平移+旋转的数据
            ros::Time::now(),   // 时间戳:当前系统时间,标记这个变换生效的时刻
            "base_link",        // 父坐标系(参考基准)
            "laser_link"));     // 子坐标系:子相对于父的位置姿态
            // 顺序千万不能写反:sendTransform(变换,时间,父,子)

        // ros::spinOnce():处理ROS消息回调
        // 当前程序只发TF,没有订阅回调,逻辑上可以不写;属于ROS代码规范,建议保留
        ros::spinOnce();

        // rate.sleep():休眠,保证整体循环维持10Hz。
        // 会扣除掉上面代码执行消耗的时间,保证周期稳定0.1s
        rate.sleep();
    }
    // main函数返回,程序结束
    return 0;
}
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐