ROS TF2

本文涉及的产品
资源编排,不限时长
简介: turtlesim的多机器人示例中,展示了tf2的一些功能。 也介绍了使用tf2_echo,view_frames和rviz。使对tf2可以做的事情有个很好的了解。

介绍tf2

turtlesim的多机器人示例中,展示了tf2的一些功能。 也介绍了使用tf2_echo,view_frames和rviz。
使对tf2可以做的事情有个很好的了解。

1、安装演示示例

首先,获取所有依赖项并编译演示包。

$ sudo apt-get install ros-$ROS_DISTRO-turtle-tf2 ros-$ROS_DISTRO-tf2-tools ros-$ROS_DISTRO-tf

在这里插入图片描述
完毕后如上图

2、运行演示示例

现在,已经编译了turtle_tf2教程包,运行演示。

$ roslaunch turtle_tf2 turtle_tf2_demo.launch

有两只小乌龟,一只爬向了另一只
在这里插入图片描述
运行键盘控制乌龟移动的节点

rosrun turtlesim turtle_teleop_key

通过箭头来移动一只乌龟,可以看到另一只乌龟一直追着。

在这里插入图片描述

3、如何实现的

使用tf2库创建三个坐标系:世界坐标系、turtle1坐标系和turtle2坐标系。 使用tf2广播器发布turtle标系,并使用tf2侦听器计算turtle标系中的差异并移动一只乌龟跟随另一只乌龟。

4、tf2 工具

4.1 view_frames

view_frames 创建 tf2 通过ROS广播的所有坐标系的示意图,他们的相互关系。

$ rosrun tf2_tools view_frames.py

在这里插入图片描述tf2侦听器正在侦听通过ROS广播的坐标系,并绘制坐标系连接方式的树。 要查看树:
可以通过指令

$ evince frames.pdf

在这里插入图片描述
这个指令会运行然后自动结束的。直接给你保存到home路径下,也不问一下。。。

在这个图上,可以看到tf2广播的三个坐标系:世界坐标系,turtle1坐标系和turtle2坐标系,并且世界坐标系是turtle1和turtle2坐标系的父级。 view_frames还报告一些诊断信息,这些信息有关何时接收到最旧和最新的坐标系转换,以及将tf2帧发布到tf2进行调试的速度。

4.2 tf_echo

tf_echo报告 通过ROS广播的任何两个坐标系之间的转换关系

指令格式

$ rosrun tf tf_echo [reference_frame] [target_frame]

看一下turtle2坐标系相对于turtle1坐标系的变换

$ rosrun tf tf_echo turtle1 turtle2

未运动时
在这里插入图片描述移动时
在这里插入图片描述
当移动乌龟时,会看到随着两只乌龟相对移动,坐标变换发生了变化。

4.3 rviz

rviz是一种可视化工具,可用于检查tf2坐标系。 看看通过rviz的turtle坐标系。 让我们使用turtle_tf2配置文件,使用rviz的-d选项启动rviz:

$ rosrun rviz rviz -d `rospack find turtle_tf2`/rviz/turtle_rviz.rviz

在这里插入图片描述控制乌龟移动,会看到 网格中的两个坐标系也动了,并且一个跟随一个。

编写tf2静态广播器(C ++)

下面 记录 如何将静态坐标系广播到tf2
之后编写 代码 实现 上面的演示 示例

1、创建 learning_tf2 功能包

首先,将创建一个catkin功能包,该功能包将用于学习tf2。 这个名为learning_tf2的软件包依赖tf2,tf2_ros,roscpp,rospy和turtlesim。

指令:

$ catkin_create_pkg learning_tf2 tf2 tf2_ros roscpp rospy turtlesim

2、How to broadcast transforms

2.1 代码

创建一个 cpp src/static_turtle_tf2_broadcaster.cpp

#include <ros/ros.h>
#include <tf2_ros/static_transform_broadcaster.h>
#include <geometry_msgs/TransformStamped.h>
#include <cstdio>
#include <tf2/LinearMath/Quaternion.h>


std::string static_turtle_name;

int main(int argc, char **argv)
{
  ros::init(argc,argv, "my_static_tf2_broadcaster"); //初始化ros节点
  
// 判断参数 对不对   参数应该有8个 
  if(argc != 8)
  {
    ROS_ERROR("Invalid number of parameters\nusage: static_turtle_tf2_broadcaster child_frame_name x y z roll pitch yaw");
    return -1;
  }
  if(strcmp(argv[1],"world")==0)  // 子坐标系 不能 是 world
  {
    ROS_ERROR("Your static turtle name cannot be 'world'");
    return -1;
  }



  static_turtle_name = argv[1];  // 取得静态 乌龟坐标系的名字
  
  static tf2_ros::StaticTransformBroadcaster static_broadcaster;//创建了一个 StaticTransformBroadcaster 对象  之后通过 这个来 发布  转换信息
  
  geometry_msgs::TransformStamped static_transformStamped; // 声明转换信息

  // 赋值 转换信息
  static_transformStamped.header.stamp = ros::Time::now();
  static_transformStamped.header.frame_id = "world";
  static_transformStamped.child_frame_id = static_turtle_name;
  static_transformStamped.transform.translation.x = atof(argv[2]);
  static_transformStamped.transform.translation.y = atof(argv[3]);
  static_transformStamped.transform.translation.z = atof(argv[4]);
  tf2::Quaternion quat;
  quat.setRPY(atof(argv[5]), atof(argv[6]), atof(argv[7]));
  static_transformStamped.transform.rotation.x = quat.x();
  static_transformStamped.transform.rotation.y = quat.y();
  static_transformStamped.transform.rotation.z = quat.z();
  static_transformStamped.transform.rotation.w = quat.w();

  
  // 通过  StaticTransformBroadcaster  把 转换信息发送出去
  static_broadcaster.sendTransform(static_transformStamped);
  
  // 终端 显示
  ROS_INFO("Spinning until killed publishing %s to world", static_turtle_name.c_str());
  ros::spin();
  return 0;
};

2.2 代码解释

包含 发布静态 坐标 转换 需要的文件

#include <ros/ros.h>
#include <tf2_ros/static_transform_broadcaster.h>  // 这个是 核心
#include <geometry_msgs/TransformStamped.h>
#include <cstdio>
#include <tf2/LinearMath/Quaternion.h>

判断参数 对不对 参数应该有8个

// 判断参数 对不对   参数应该有8个 
  if(argc != 8)
  {
    ROS_ERROR("Invalid number of parameters\nusage: static_turtle_tf2_broadcaster child_frame_name x y z roll pitch yaw");
    return -1;
  }
  if(strcmp(argv[1],"world")==0)  // 子坐标系 不能 是 world
  {
    ROS_ERROR("Your static turtle name cannot be 'world'");
    return -1;
  }

声明一些 内容

static_turtle_name = argv[1];  // 取得静态 乌龟坐标系的名字
  
  static tf2_ros::StaticTransformBroadcaster static_broadcaster;//创建了一个 StaticTransformBroadcaster 对象  之后通过 这个来 发布  转换信息
  
  geometry_msgs::TransformStamped static_transformStamped; // 声明转换信息

赋值 转换信息


  // 赋值 转换信息
  static_transformStamped.header.stamp = ros::Time::now();
  static_transformStamped.header.frame_id = "world";
  static_transformStamped.child_frame_id = static_turtle_name;
  static_transformStamped.transform.translation.x = atof(argv[2]);
  static_transformStamped.transform.translation.y = atof(argv[3]);
  static_transformStamped.transform.translation.z = atof(argv[4]);
  tf2::Quaternion quat;
  quat.setRPY(atof(argv[5]), atof(argv[6]), atof(argv[7]));
  static_transformStamped.transform.rotation.x = quat.x();
  static_transformStamped.transform.rotation.y = quat.y();
  static_transformStamped.transform.rotation.z = quat.z();
  static_transformStamped.transform.rotation.w = quat.w();

通过 StaticTransformBroadcaster 把 转换信息发送出去

  // 通过  StaticTransformBroadcaster  把 转换信息发送出去
  static_broadcaster.sendTransform(static_transformStamped);

可以看到 main函数里没有 while 循环 ,所以只执行一次。
相当于 设定的 一个 静态(不变)的坐标系 和 世界坐标系的 转换(TF)

3、编译 运行

在 CMakeLists.txt 添加

add_executable(static_turtle_tf2_broadcaster src/static_turtle_tf2_broadcaster.cpp)
target_link_libraries(static_turtle_tf2_broadcaster  ${catkin_LIBRARIES} )

编译

$ catkin_make

运行

$ roscore
rosrun learning_tf2 static_turtle_tf2_broadcaster mystaticturtle 0 0 1 0 0 0

4、检查结果

 $ rostopic echo /tf_static

结果
在这里插入图片描述/tf_static 这个topic 可能会 存放 所有 通过 StaticTransformBroadcaster 静态坐标转换

5、发布静态转换更合适的方法

上面的代码 旨在说明如何使用StaticTransformBroadcaster发布静态转换。 在实际的开发过程中,不必自己编写此代码,而应优先使用专用的tf2_ros工具来编写代码。 tf2_ros提供了一个名为static_transform_publisher的可执行文件,可以用作命令行工具或可以添加到启动文件的节点。

有两种方式 一种 角度 的一种四元数的 用有几个参数来区分

static_transform_publisher x y z yaw pitch roll frame_id child_frame_id
Publish a static coordinate transform to tf2 using an x/y/z offset in meters and quaternion. 

通过 这中 launch 文件的 方式 ,直接在launch 中发布静态 坐标变化

<launch>
<node pkg="tf2_ros" type="static_transform_publisher" name="link1_broadcaster" args="1 0 0 0 0 0 1 link1_parent link1" />
</launch>

编写 tf2 坐标变换 (上面为静态,此为动态)

上面为 静态:两坐标变换关系 不变
此为 动态 :两坐标变换关系 改变

下面记录 如何将坐标系广播到tf2。 在这种情况下,广播海龟移动时不断变化的坐标系。

1、创建 learning_tf2 功能包

首先,将创建一个catkin功能包,该功能包将用于学习tf2。 这个名为learning_tf2的软件包依赖tf2,tf2_ros,roscpp,rospy和turtlesim。

指令:

$ catkin_create_pkg learning_tf2 tf2 tf2_ros roscpp rospy turtlesim

2、代码

#include <ros/ros.h>
#include <tf2/LinearMath/Quaternion.h>
#include <tf2_ros/transform_broadcaster.h>
#include <geometry_msgs/TransformStamped.h>
#include <turtlesim/Pose.h>

std::string turtle_name;

void poseCallback(const turtlesim::PoseConstPtr& msg){
  static tf2_ros::TransformBroadcaster br;
  geometry_msgs::TransformStamped transformStamped;
  
  transformStamped.header.stamp = ros::Time::now();
  transformStamped.header.frame_id = "world";
  transformStamped.child_frame_id = turtle_name;
  transformStamped.transform.translation.x = msg->x;
  transformStamped.transform.translation.y = msg->y;
  transformStamped.transform.translation.z = 0.0;
  tf2::Quaternion q;
  q.setRPY(0, 0, msg->theta);
  transformStamped.transform.rotation.x = q.x();
  transformStamped.transform.rotation.y = q.y();
  transformStamped.transform.rotation.z = q.z();
  transformStamped.transform.rotation.w = q.w();

  br.sendTransform(transformStamped);
}

int main(int argc, char** argv){
  ros::init(argc, argv, "my_tf2_broadcaster");

  ros::NodeHandle private_node("~");
  if (! private_node.hasParam("turtle"))
  {
    if (argc != 2){ROS_ERROR("need turtle name as argument"); return -1;};
    turtle_name = argv[1];
  }
  else
  {
    private_node.getParam("turtle", turtle_name);
  }
    
  ros::NodeHandle node;
  ros::Subscriber sub = node.subscribe(turtle_name+"/pose", 10, &poseCallback);

  ros::spin();
  return 0;
};

3、代码解释

1)

#include <ros/ros.h>
#include <tf2/LinearMath/Quaternion.h>
#include <tf2_ros/transform_broadcaster.h>
#include <geometry_msgs/TransformStamped.h>
#include <turtlesim/Pose.h>

tf2 软件包提供了 TransformBroadcaster 的实现,以帮助简化发布转换的任务。 要使用TransformBroadcaster,需要包含tf2_ros / transform_broadcaster.h头文件。

2)

  static tf2_ros::TransformBroadcaster br;

创建一个TransformBroadcaster对象,稍后将使用它发送tf。

3)

  geometry_msgs::TransformStamped transformStamped;
  
  transformStamped.header.stamp = ros::Time::now();
  transformStamped.header.frame_id = "world";
  transformStamped.child_frame_id = turtle_name;

创建一个Transform对象,并为其提供适当的数据。

给要发布的tf加一个时间戳,用当前时间ros :: Time :: now()标记它。

设置要创建的link的父框架的名称,在本例中为“ world”

设置要创建的link的子节点的名称,这就是乌龟本身的名称。

4)

  transformStamped.transform.translation.x = msg->x;
  transformStamped.transform.translation.y = msg->y;
  transformStamped.transform.translation.z = 0.0;
  tf2::Quaternion q;
  q.setRPY(0, 0, msg->theta);
  transformStamped.transform.rotation.x = q.x();
  transformStamped.transform.rotation.y = q.y();
  transformStamped.transform.rotation.z = q.z();
  transformStamped.transform.rotation.w = q.w();

将3D乌龟位姿信息复制到3D变换(TF)中

5)

  br.sendTransform(transformStamped);

完成实际工作的地方。 使用TransformBroadcaster发送转换仅需要传递转换本身。

4、运行例程

1)编译

CMakeLists.txt 文件中加入

add_executable(turtle_tf2_broadcaster src/turtle_tf2_broadcaster.cpp)
target_link_libraries(turtle_tf2_broadcaster
 ${catkin_LIBRARIES}
)

编译

 $ catkin_make

bin文件夹中应该有一个名为turtle_tf2_broadcaster的二进制文件。
在这里插入图片描述

2)为此bin文件 创建启动文件(launch)。 命名为start_demo.launch

新建文件夹 launch 和文件 start_demo.launch
在这里插入图片描述
写如下代码

  <launch>
     <!-- Turtlesim Node-->
    <node pkg="turtlesim" type="turtlesim_node" name="sim"/>

    <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>
    <!-- Axes -->
    <param name="scale_linear" value="2" type="double"/>
    <param name="scale_angular" value="2" type="double"/>

    <node pkg="learning_tf2" type="turtle_tf2_broadcaster"
          args="/turtle1" name="turtle1_tf2_broadcaster" />
    <node pkg="learning_tf2" type="turtle_tf2_broadcaster"
          args="/turtle2" name="turtle2_tf2_broadcaster" />

  </launch>

3)运行

 $ roslaunch learning_tf2 start_demo.launch

在这里插入图片描述

4)查看结果

 $ rosrun tf tf_echo /world /turtle1

在这里插入图片描述

相关实践学习
使用ROS创建VPC和VSwitch
本场景主要介绍如何利用阿里云资源编排服务,定义资源编排模板,实现自动化创建阿里云专有网络和交换机。
阿里云资源编排ROS使用教程
资源编排(Resource Orchestration)是一种简单易用的云计算资源管理和自动化运维服务。用户通过模板描述多个云计算资源的依赖关系、配置等,并自动完成所有资源的创建和配置,以达到自动化部署、运维等目的。编排模板同时也是一种标准化的资源和应用交付方式,并且可以随时编辑修改,使基础设施即代码(Infrastructure as Code)成为可能。 产品详情:https://www.aliyun.com/product/ros/
相关文章
|
算法 机器人 API
【ROS】TF2坐标转换及实战示例
ROS中提供了坐标转换的软件包 Transform Frame TF的作用是ROS中实现不同坐标点/向量的转换。
708 0
ROS TF2当前坐标系如何计算其它历史坐标系的坐标变换
ROS TF2当前坐标系如何计算其它历史坐标系的坐标变换
ROS TF2当前坐标系如何计算其它历史坐标系的坐标变换
|
传感器 C++
ROS TF2 添加一个 坐标系 附实例
ROS TF2 添加一个 坐标系 附实例
ROS TF2 添加一个 坐标系 附实例
|
传感器 缓存
ROS TF2 :通过tf2_ros::MessageFilter 将世界坐标系下的点转为期望坐标系下的点
ROS TF2 :通过tf2_ros::MessageFilter 将世界坐标系下的点转为期望坐标系下的点
|
2月前
|
Ubuntu 机器人 Linux
|
15天前
|
自动驾驶 安全 机器人
ROS2:从初识到深入,探索机器人操作系统的进化之路
前言 最近开始接触到基于DDS的这个系统,是在稚晖君的机器人项目中了解和认识到。于是便开始自己买书学习起来,感觉挺有意思的,但是只是单纯的看书籍,总会显得枯燥无味,于是自己又开始在网上找了一些视频教程结合书籍一起来看,便让我对ROS系统有了更深的认识和理解。 ROS的发展历程 ROS诞生于2007年的斯坦福大学,这是早期PR2机器人的原型,这个项目很快被一家商业公司Willow Garage看中,类似现在的风险投资一样,他们投了一大笔钱给这群年轻人,PR2机器人在资本的助推下成功诞生。 2010年,随着PR2机器人的发布,其中的软件正式确定了名称,就叫做机器人操作系统,Robot Op
58 14
|
27天前
|
XML 算法 自动驾驶
ROS进阶:使用URDF和Xacro构建差速轮式机器人模型
【11月更文挑战第7天】本篇文章介绍的是ROS高效进阶内容,使用URDF 语言(xml格式)做一个差速轮式机器人模型,并使用URDF的增强版xacro,对机器人模型文件进行二次优化。
|
1月前
|
自动驾驶 安全 机器人
ROS2:从初识到深入,探索机器人操作系统的进化之路
【11月更文挑战第4天】ROS2的学习过程和应用,介绍DDS系统的框架和知识。
|
7月前
|
传感器 人工智能 算法
ROS机器人操作系统
ROS机器人操作系统
181 1

推荐镜像

更多