ROS 2边学边练(33)-- 写一个静态广播(C++)

前言

        通过这一篇我们将了解并学习到如何广播静态坐标变换到tf2(由tf2来转换这些坐标系)。

        发布静态变换对于定义机器人底座与其传感器或非移动部件之间的关系非常有用。例如,在以激光扫描仪中心的坐标系中推理激光扫描测量数据是最简单的。

        这是一个独立的教程,涵盖了静态变换的基础知识,包含两个部分。在第一部分,我们将编写代码以将静态变换发布到tf2。在第二部分,我们将说明如何在tf2_ros中使用命令行工具static_transform_publisher

        后面的接着两篇博文中(下一篇可能会穿插一篇有关ROS世界坐标系的博文),我们将重新学习下上一篇博文(《初识tf2》)的一些知识,在后面的其他博文将会涉及到tf2的更多高级功能。

动动手

创建功能包

        我们在之前创建的某个工作空间(比如ros2_ws)或新建一个工作空间内创建一个learning_tf2_cpp包(工作空间的src路径下):

$ros2 pkg create --build-type ament_cmake --license Apache-2.0 --dependencies geometry_msgs rclcpp tf2 tf2_ros turtlesim -- learning_tf2_cpp

写个静态广播节点

        在learning_tf2_cpp/src下,执行如下命令下载官方为我们准备好的源文件:

$wget https://raw.githubusercontent.com/ros/geometry_tutorials/ros2/turtle_tf2_cpp/src/static_turtle_tf2_broadcaster.cpp

        下载下来的static_turtle_tf2_broadcaster.cpp内容如下:

#include <memory>#include "geometry_msgs/msg/transform_stamped.hpp"
#include "rclcpp/rclcpp.hpp"
#include "tf2/LinearMath/Quaternion.h"
#include "tf2_ros/static_transform_broadcaster.h"class StaticFramePublisher : public rclcpp::Node
{
public:explicit StaticFramePublisher(char * transformation[]): Node("static_turtle_tf2_broadcaster"){tf_static_broadcaster_ = std::make_shared<tf2_ros::StaticTransformBroadcaster>(this);// Publish static transforms once at startupthis->make_transforms(transformation);}private:void make_transforms(char * transformation[]){geometry_msgs::msg::TransformStamped t;t.header.stamp = this->get_clock()->now();t.header.frame_id = "world";t.child_frame_id = transformation[1];//命令行传入的第二个参数,第一个参数为可执行文件的名称t.transform.translation.x = atof(transformation[2]);t.transform.translation.y = atof(transformation[3]);t.transform.translation.z = atof(transformation[4]);tf2::Quaternion q;q.setRPY(atof(transformation[5]),atof(transformation[6]),atof(transformation[7]));t.transform.rotation.x = q.x();t.transform.rotation.y = q.y();t.transform.rotation.z = q.z();t.transform.rotation.w = q.w();tf_static_broadcaster_->sendTransform(t);}std::shared_ptr<tf2_ros::StaticTransformBroadcaster> tf_static_broadcaster_;
};int main(int argc, char * argv[])
{auto logger = rclcpp::get_logger("logger");// Obtain parameters from command line argumentsif (argc != 8) {RCLCPP_INFO(logger, "Invalid number of parameters\nusage: ""$ ros2 run learning_tf2_cpp static_turtle_tf2_broadcaster ""child_frame_name x y z roll pitch yaw");return 1;}// As the parent frame of the transform is `world`, it is// necessary to check that the frame name passed is differentif (strcmp(argv[1], "world") == 0) {RCLCPP_INFO(logger, "Your static turtle name cannot be 'world'");return 1;}// Pass parameters and initialize noderclcpp::init(argc, argv);rclcpp::spin(std::make_shared<StaticFramePublisher>(argv));rclcpp::shutdown();return 0;
}
代码分析
#include "geometry_msgs/msg/transform_stamped.hpp"

        包含transform_stamped.hpp头文件是为了能访问TransformStamped消息类型,并将其发布到转换树当中去。

#include "rclcpp/rclcpp.hpp"

        包含rclcpp.hpp头文件,是为了使用rcl::Node类。

#include "tf2/LinearMath/Quaternion.h"
#include "tf2_ros/static_transform_broadcaster.h"

        包含Quaternion.h是为了利用四元数类中提供的方便转换欧拉角为四元数(或四元数转换为欧拉角)的功能,包含static_transform_broadcaster.h是为了使用TransformBroadcaster从而使得发布静态转换变得简单。

tf_static_broadcaster_ = std::make_shared<tf2_ros::StaticTransformBroadcaster>(this);this->make_transforms(transformation);

        StaticFramePublisher类的构造函数中初始化名称为static_turtle_tf2_broadcaster的节点。然后,创建StaticTransformBroadcaster,它将在启动时发送一个静态转换。 

geometry_msgs::msg::TransformStamped t;t.header.stamp = this->get_clock()->now();
t.header.frame_id = "world";
t.child_frame_id = transformation[1];

        在这里,我们创建一个TransformStamped对象,它将是我们在填充后发送的消息载体。在传递实际的转换值之前,我们需要为其提供适当的元数据初始化一下。 

  1.         t.header.stamp,这个好理解,将当前时间作为时间戳填充上;
  2.         t.hear.frame_id,我们创建连接(link)的父坐标系名称,我们取名“world”;
  3.         t.child_frame_id, 我们创建连接(link)的子坐标系名称;
t.transform.translation.x = atof(transformation[2]);
t.transform.translation.y = atof(transformation[3]);
t.transform.translation.z = atof(transformation[4]);
tf2::Quaternion q;
q.setRPY(atof(transformation[5]),atof(transformation[6]),atof(transformation[7]));
t.transform.rotation.x = q.x();
t.transform.rotation.y = q.y();
t.transform.rotation.z = q.z();
t.transform.rotation.w = q.w();

        这里是填充关于小海龟的6D(六个自由度)位姿数据(偏移及旋转)。

tf_static_broadcaster_->sendTransform(t);

         数据都准备好了之后,我们调用sendTransform函数将消息t(静态转换)发布广播出去。

更新package.xml和CMakeLists.txt

package.xml

<description>Learning tf2 with rclcpp</description>
<maintainer email="mike@qq.com">mike</maintainer>
<license>Apache License 2.0</license>

        根据实际情况手动修改。

CMakeLists.txt

add_executable(static_turtle_tf2_broadcaster src/static_turtle_tf2_broadcaster.cpp)
ament_target_dependencies(static_turtle_tf2_broadcastergeometry_msgsrclcpptf2tf2_ros
)

        添加可执行程序,名字为static_turtle_tf2_broadcaster,我们在使用ros2 run命令时会使用到此生成的可执行程序。

install(TARGETSstatic_turtle_tf2_broadcasterDESTINATION lib/${PROJECT_NAME})

        指定构建安装的路径(可执行程序生成的路径),方便调用程序按图索骥。

构建

        都搞定之后,我们就可以构建这个包了,但,养成好习惯,先检查依赖再构建。

$rosdep install -i --from-path src --rosdistro iron -y
$colcon build --packages-select learning_tf2_cpp

运行

        我们新开一个终端,先进入工作空间根路径然后source下环境:

$source install/setup.bash

        现在我们终于可以运行了,但我们需要在调用可执行文件时还需将位姿数据传进去,方便该节点填充消息(x,y,z,r,p,y->0,0,1,0,0,0):

$ros2 run learning_tf2_cpp static_turtle_tf2_broadcaster mystaticturtle 0 0 1 0 0 0

上面的参数z为1,代表给mystaticturtle坐标系广播了一个离地1米高度的海龟位姿信息(让mystaticturtle坐标系朝着这个小目标前进)。

补充一点机器人学背景专业知识。

在ROS(Robot Operating System)中,6自由度(6DOF,即6 Degrees of Freedom)通常指的是一个刚体在空间中的完全定位所需的参数。这些参数描述了刚体在三维空间中的位置和姿态。具体来说,6自由度包括:三个位置参数(Position):X轴位移(X-axis translation)Y轴位移(Y-axis translation)Z轴位移(Z-axis translation)这三个参数描述了刚体在三维空间中的位置。三个姿态参数(Attitude)或方向参数(Orientation):横滚角(Roll)俯仰角(Pitch)偏航角(Yaw)这三个参数描述了刚体在三维空间中的方向或姿态。这些角度通常使用欧拉角、四元数或其他方式来表示。在ROS中,这些参数经常用于描述传感器数据(如IMU、激光雷达等)、机器人末端执行器的位置、机器人的自身姿态等。例如,tf2库就用于处理这些变换,允许用户在不同坐标系之间转换点、向量和姿态。当处理机器人学中的运动时,了解这些参数和它们如何影响机器人在空间中的位置和姿态是非常重要的。

位置参数(Position)X轴位移(X-axis translation):这个参数描述了刚体在X轴方向上的位置。正值通常表示向右移动,负值表示向左移动。它决定了刚体在三维空间中的水平位置。Y轴位移(Y-axis translation):这个参数描述了刚体在Y轴方向上的位置。正值通常表示向前移动,负值表示向后移动。它决定了刚体在三维空间中的前后位置。Z轴位移(Z-axis translation):这个参数描述了刚体在Z轴方向上的位置。正值通常表示向上移动,负值表示向下移动。它决定了刚体在三维空间中的垂直位置。姿态参数(Attitude)或方向参数(Orientation)姿态参数通常用来描述刚体在三维空间中的方向或朝向。有多种方式可以表示姿态,但最常见的包括欧拉角和四元数。这里,我们简单解释欧拉角:横滚角(Roll):这个参数描述了刚体绕其X轴的旋转。正值通常表示顺时针旋转,负值表示逆时针旋转。它描述了刚体在水平面上的旋转。俯仰角(Pitch):这个参数描述了刚体绕其Y轴的旋转。正值通常表示向上抬头,负值表示向下低头。它描述了刚体在垂直平面内的旋转。偏航角(Yaw):这个参数描述了刚体绕其Z轴的旋转。正值通常表示向右转动,负值表示向左转动。它描述了刚体在水平面上的方向改变。需要注意的是,欧拉角存在万向锁问题,即在某些特定姿态下,横滚角和俯仰角会变得不确定,影响姿态描述的准确性。因此,在实际应用中,有时会更倾向于使用四元数或其他方法来表示姿态。

         我们再来检查一下主题/tf_static发布的静态转换消息(不知道是哪个主题可以ros2 topic list确认一下)。

$ros2 topic echo /tf_static

 如果一切顺利,我们将会看到下面的内容。

发布静态转换的正确方式

        除了我们上面编写构建的StaticTransformBroadcaster可以发布静态转换外,我们还可以利用tf2_ros工具(名字为static_transform_publisher)来实现同样的目的(实际情况就是直接使用现成的工具而不是自己去实现,上面的代码实现是为了让我们了解到其内部的实现,知己知彼嘛),我们可以直接在命令行调用此工具或者在launch文件里添加使用。

        使用以米为单位的x/y/z偏移和以弧度为单位的滚转/俯仰/偏航,将静态坐标变换发布到tf2。我们来看看怎么调用:

$ros2 run tf2_ros static_transform_publisher --x x --y y --z z --yaw yaw --pitch pitch --roll roll --frame-id frame_id --child-frame-id child_frame_id

        可以看出,除了6D参数外还有我们在自己编写的代码里面的父子坐标系名称。我们执行一下,效果与上面的是一样的。

 

 

        使用以米和四元数为单位的x/y/z偏移将静态坐标变换发布到tf2。

$ros2 run tf2_ros static_transform_publisher --x x --y y --z z --qx qx --qy qy --qz qz --qw qw --frame-id frame_id --child-frame-id child_frame_id

补充四元数知识点:

四元素(Quaternion)是一种用于表示旋转的数学工具,在机器人学和计算机图形学等领域有广泛应用。它由一个实部和三个虚部组成,可以表示为(w, x, y, z)或(w, V),其中V是虚部,表示为向量(x, y, z)。四元素满足特定的数学规则,包括虚部的乘法规则,如i^2 = j^2 = k^2 = ijk = −1等。在ROS(Robot Operating System)中,四元素常用于表示机器人的姿态。姿态描述了机器人在三维空间中的位置和朝向,而四元素是描述这种姿态的一种常用方式。ROS提供了处理四元素的库和工具,使得机器人软件能够方便地处理与姿态相关的任务。在使用四元素时,需要注意其标准化问题。标准化四元素意味着将其长度(模长)调整为1,以确保其正确表示旋转。未标准化的四元素可能会导致错误的结果。此外,ROS中的tf2系统也涉及到四元素的使用。tf2用于进行坐标旋转以及tf、msg两种四元素数据结构的变换,它使得在不同坐标系之间转换姿态变得简单高效。综上所述,四元素是机器人学和计算机图形学中的重要工具,尤其在ROS中,它扮演着描述机器人姿态的关键角色。

  static_transform_publisher既可以直接在命令行使用又可以在launch文件里面使用,我们来看看它在launch文件里面是怎么用的。

from launch import LaunchDescription
from launch_ros.actions import Nodedef generate_launch_description():return LaunchDescription([Node(package='tf2_ros',executable='static_transform_publisher',arguments = ['--x', '0', '--y', '0', '--z', '1', '--yaw', '0', '--pitch', '0', '--roll', '0', '--frame-id', 'world', '--child-frame-id', 'mystaticturtle']),])

        看起来是不是比较容易接受,但需要注意的是,除了参数--frame-id 和参数 --child-frame-id外的其他参数都是可选的,如果未指定某个特定选项,则会假定使用恒等变换(默认值)。

本篇完。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/2348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器 BMC(基板管理控制器,Baseboard Management Controller)认知

写在前面 工作中遇到&#xff0c;简单整理博文内容涉及 BMC 基本认知理解不足小伙伴帮忙指正 不必太纠结于当下&#xff0c;也不必太忧虑未来&#xff0c;当你经历过一些事情的时候&#xff0c;眼前的风景已经和从前不一样了。——村上春树 基板管理控制器&#xff08;BMC&…

数字孪生创新工作流,助力百年大桥翻修

利用 Bentley 的 iTwin Capture 和 iTwin Experience 创建数字孪生模型&#xff0c;将现场施工时间缩短了 20% 重要交通枢纽焕然一新 罗伯特街大桥位于明尼苏达州圣保罗市&#xff0c;外观呈彩虹样拱形&#xff0c;近 100 年来一直是圣保罗市的标志性建筑。这座八跨钢筋混凝土…

Linux复习提纲2

Linux复习提纲 Linux概述 shell&#xff1a;交互式命令解释程序&#xff1b;用户和内核间交互的桥梁Shell不仅是交互式命令解释程序&#xff0c;还是一种程序设计语言shell是一种命令解释程序&#xff0c;批处理shell是linux的外壳&#xff0c;默认是bash2.1 Linux基础概念 log…

线上剧本杀小程序开发,未来行业的发展趋势?

当下&#xff0c;剧本杀成为了大众最喜欢的娱乐方式之一&#xff0c;作为以沉浸式为主的剧本杀正成为新时代下的发展潮流。 数据显示&#xff0c;剧本杀行业已达到了百亿元。面对发展迅猛的剧本杀市场&#xff0c;越来越多的资本进入到了市场中&#xff0c;剧本杀的产业链也逐…

【C语言】手撕二叉树

标题&#xff1a;【C语言】手撕二叉树 水墨不写bug 正文开始&#xff1a; 二叉树是一种基本的树形数据结构&#xff0c;对于初学者学习树形结构而言较容易接受。二叉树作为一种数据结构&#xff0c;在单纯存储数据方面没有 顺序表&#xff0c;链表&#xff0c;队列等线性结构…

菜鸟Java面向对象 2. Java 重写(Override)与重载(Overload)

Java 重写(Override)与重载(Overload) Java 重写与重载 Java 重写(Override)与重载(Overload)1. 重写(Override)1. 概念解释&#xff1a;2. 好处说明3. 异常规则处理 2. 方法的重写规则3. Super 关键字的使用4. 重载(Overload)**重载规则:**实例 5. 重写与重载之间的区别总结 1…

什么是手机运营商三要素验证API接口

手机运营商三要素验证API接口又叫手机运营商三要素核验API接口&#xff0c;指的是输入姓名、身份证号码及手机号&#xff0c;通过运营商数据库实时校验此三项是否匹配。手机运营商三要素核验API接口广泛用于实名注册、风控审核等场景&#xff0c;如电商、直播、游戏、金融等。接…

Leetcode刷题之链表小结(1)|92反转链表|206反转链表

TOC 小结 1. 如何反转某一个节点的指向? 206反转链表(简单)的递归解法——该方法的理念是: 若节点k1到节点m已经被反转&#xff0c;而我们当前处于k位置&#xff0c;那么我们希望k1指向k, 体现在以下代码的head->next->next head;这一句,可以记做一种常用的反转单个…

AI+招聘,激活企业的「新质生产力」

两会以来&#xff0c;「新质生产力」成为热词。而所谓的新质生产力&#xff0c;是创新起主导作用&#xff0c;摆脱传统经济增长方式、生产力发展路径&#xff0c;具有高科技、高效能、高质量特征&#xff0c;符合新发展理念的先进生产力质态。新质之「新」&#xff0c;很重要的…

wandb注册 wandb: ERROR api_key

wandb: ERROR api_key not configured (no-tty). call wandb.login(key[your_api_key]) Traceback (most recent call last): 背景 使用yolov8训练时 在pycharm中出现wandb账号未注册错误 Transferred 355/355 items from pretrained weights TensorBoard: Start with tensor…

平衡二叉树(AVLTree)

AVLTree 1、树的分类2、平衡二叉树2.1、构建一个平衡二叉树2.2、删除节点2.3、搜索方式2.3.1、广度优先搜索&#xff08;BFS&#xff09;2.3.2、深度优先搜索&#xff08;DFS&#xff09; 1、树的分类 树形结构是编程当中特别常见的一种数据结构。比如电脑中的文件管理系统就大…

(超级详细)JAVA之Stream流分析-------持续更新喔!!!

学习目标&#xff1a; 掌握 Java Stream流的相关api 掌握 Java Stream流的基本实现 掌握 java Stream流的使用场景 代码已经整理上传到了gitee中&#xff0c;有需要的小伙伴可以取查看一下源码点个小心心喔 大家也可以帮我提交一点案例喔&#xff01;&#xff01;&#xff01;&…

【QT进阶】Qt Web混合编程之使用ECharts显示各类折线图等

往期回顾 【QT进阶】Qt Web混合编程之QWebEngineView基本用法-CSDN博客 【QT进阶】Qt Web混合编程之CMake VS2019编译并使用QCefView&#xff08;图文并茂超详细版本&#xff09;-CSDN博客【QT进阶】Qt Web混合编程之html、 js的简单交互-CSDN博客 【QT进阶】Qt Web混合编程之使…

【MATLAB源码-第196期】基于matlab的A*融合DWA算法栅格路径规划仿真,画出路径图、姿态角度以及线角速度。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 A算法与DWA算法的融合是一个高效的路径规划策略&#xff0c;这种策略将A算法的全局路径规划能力与DWA算法的局部避障能力结合起来&#xff0c;以期达到更快、更安全的导航效果。以下是对这种融合策略的详细描述。 一、基本概…

Linux thermal框架介绍

RK3568温控 cat /sys/class/thermal/thermal_zone0/temp cat /sys/class/thermal/thermal_zone1/temp cat /sys/class/thermal/cooling_device0/cur_state cat /sys/class/thermal/cooling_device1/cur_state cat /sys/class/thermal/cooling_device2/cur_state thermal_zone…

信息打点--公众号服务

微信公众号 获取微信公众号的途径https://weixin.sogou.com/ 微信公众号没有第三方服务 Github监控 人员&域名&邮箱 eg&#xff1a;xxx.cn password in:file https://gitee.com/ https://github.com/ https://www.huzhan.com/ 资源搜索 in:name test 仓库标题搜索含有…

ASP.NET教务管理平台-权限及公共模块设计与开发

摘 要 随着教育改革的不断深化&#xff0c;高等院校的建设与发展对国民整体素质的提高起着越来越重要的作用&#xff0c;建立一套能够适应这些改变的行政管理方案也就显得尤为重要。对于教务处来说&#xff0c;将信息技术用于校务管理中便是迫切的要求。 教务系统中的用户…

产品规划|如何从0到1规划设计一款产品?

我们要如何从0到1规划设计一款产品?在前期工作我们需要做什么呢?下面这篇文章就是关于此的相关内容,大家一起往下看多多了解了解吧! 一、什么是产品规划? 产品规划是一种策略,它设定了产品的价值和目标,并确定实施方案以实现这些目标。它考虑了产品的整个生命周期,基于…

22长安杯电子取证复现(检材一,二)

检材一 先用VC容器挂载&#xff0c;拿到完整的检材 从检材一入手&#xff0c;火眼创建案件&#xff0c;打开检材一 1.检材1的SHA256值为 计算SHA256值&#xff0c;直接用火眼计算哈希计算 9E48BB2CAE5C1D93BAF572E3646D2ECD26080B70413DC7DC4131F88289F49E34 2.分析检材1&am…

dremio支持设置

Dremio 支持提供可用于诊断目的的设置。这些设置通过 Dremio UI&#xff1a;设置>支持启用&#xff08;或禁用&#xff09; 使用 Client Tools 可以配置当用户查看数据集中的数据时&#xff0c;Dremio 项目的工具栏上显示哪些客户端应用程序按钮。用户可以通过单击相应的工具…