> 文章列表 > ROS学习第十九节——TF静态坐标变换

ROS学习第十九节——TF静态坐标变换

ROS学习第十九节——TF静态坐标变换

1.坐标msg消息

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

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

1.1geometry_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

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

1.2geometry_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 yfloat64 z

另请参考:

  • geometry_msgs/TransformStamped Documentation

  • geometry_msgs/PointStamped Documentation

2 静态坐标变换

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

需求描述:

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

结果演示:

2.1创建功能包

创建项目功能包依赖于 tf2、tf2_ros、tf2_geometry_msgs、roscpp rospy std_msgs geometry_msgs

2.2发布方

/* 静态坐标变换发布方:发布关于 laser 坐标系的位置信息 实现流程:1.包含头文件2.初始化 ROS 节点3.创建静态坐标转换广播器4.创建坐标系信息5.广播器发布坐标系信息6.spin()
*/// 1.包含头文件
#include "ros/ros.h"
#include "tf2_ros/static_transform_broadcaster.h"
#include "geometry_msgs/TransformStamped.h"
#include "tf2/LinearMath/Quaternion.h"int main(int argc, char *argv[])
{setlocale(LC_ALL,"");// 2.初始化 ROS 节点ros::init(argc,argv,"static_brocast");// 3.创建静态坐标转换广播器tf2_ros::StaticTransformBroadcaster broadcaster;// 4.创建坐标系信息geometry_msgs::TransformStamped ts;//----设置头信息ts.header.seq = 100;ts.header.stamp = ros::Time::now();//相对坐标中被参考的那一个ts.header.frame_id = "base_link";//----设置子级坐标系ts.child_frame_id = "laser";//----设置子级相对于父级的偏移量ts.transform.translation.x = 0.2;ts.transform.translation.y = 0.0;ts.transform.translation.z = 0.5;//----设置四元数:将 欧拉角数据转换成四元数tf2::Quaternion qtn;//创建四元数对象//向该对象设置欧拉角,这个对象可以将欧拉角转化成四元数qtn.setRPY(0,0,0);//欧拉角的单位是弧度ts.transform.rotation.x = qtn.getX();ts.transform.rotation.y = qtn.getY();ts.transform.rotation.z = qtn.getZ();ts.transform.rotation.w = qtn.getW();// 5.广播器发布坐标系信息broadcaster.sendTransform(ts);ros::spin();return 0;
}

配置文件

运行效果

 2.3订阅方

/*  订阅坐标系信息,生成一个相对于 子级坐标系的坐标点数据,转换成父级坐标系中的坐标点实现流程:1.包含头文件2.初始化 ROS 节点3.创建 TF 订阅节点4.生成一个坐标点(相对于子级坐标系)5.转换坐标点(相对于父级坐标系)6.spin()
*/
//1.包含头文件
#include "ros/ros.h"
#include "tf2_ros/transform_listener.h"
#include "tf2_ros/buffer.h"
#include "geometry_msgs/PointStamped.h"
#include "tf2_geometry_msgs/tf2_geometry_msgs.h" //注意: 调用 transform 必须包含该头文件int main(int argc, char *argv[])
{setlocale(LC_ALL,"");// 2.初始化 ROS 节点ros::init(argc,argv,"tf_sub");ros::NodeHandle nh;// 3.创建 TF 订阅节点//创建一个buffer缓存tf2_ros::Buffer buffer;//再创建监听对象(监听对象可以将订阅的数据存入buffer)tf2_ros::TransformListener listener(buffer);// 4.生成一个坐标点(相对于子级坐标系)geometry_msgs::PointStamped point_laser;point_laser.header.frame_id = "laser";point_laser.header.stamp = ros::Time::now();point_laser.point.x = 1;point_laser.point.y = 2;point_laser.point.z = 7.3;ros::Duration(2).sleep();ros::Rate r(1);while (ros::ok()){// 5.转换坐标点(相对于父级坐标系)//新建一个坐标点,用于接收转换结果  //--------------使用 try 语句或休眠,否则可能由于缓存接收延迟而导致坐标转换失败------------------------try{geometry_msgs::PointStamped point_base;/*调用buffer的转换函数transform参数1:被转换的坐标点参数2:目标坐标系参数3:输出的坐标点调用时候必须包含头文件,tf2_geometry_msgs/tf2_geometry_msgs.h运行时存在的问题,说base_link不存在,原因:订阅数据是一个耗时操作,转换函数是坐标系的相对关系还没有订阅到,因此出现异常解决:方案一:订阅之前休眠两秒方案二:进行异常处理*/point_base = buffer.transform(point_laser,"base_link");ROS_INFO("转换后的数据:(%.2f,%.2f,%.2f),参考的坐标系是:%s",point_base.point.x,point_base.point.y,point_base.point.z,point_base.header.frame_id.c_str());}catch(const std::exception& e){// std::cerr << e.what() << '\\n';ROS_INFO("程序异常.....");}r.sleep();  ros::spinOnce();}return 0;
}

2.3可以借助于rviz显示坐标系

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

 2.4

当坐标系之间的相对位置固定时,那么所需参数也是固定的: 父系坐标名称、子级坐标系名称、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

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