机器人系统ros2-开发实践07-将机器人的状态广播到 tf2(Python)

上个教程将静态坐标系广播到 tf2,基于这个基础原理这个教程将演示机器人的点位状态发布到tf2

1. 写入广播节点

我们首先创建源文件。转到learning_tf2_py我们在上一教程中创建的包。在src/learning_tf2_py/learning_tf2_py目录中输入以下命令来下载示例广播示例代码:

wget https://raw.githubusercontent.com/ros/geometry_tutorials/ros2/turtle_tf2_py/turtle_tf2_py/turtle_tf2_broadcaster.py

用vc code 打开源码文件

# Copyright 2021 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.import mathfrom geometry_msgs.msg import TransformStampedimport numpy as npimport rclpy
from rclpy.node import Nodefrom tf2_ros import TransformBroadcasterfrom turtlesim.msg import Pose# This function is a stripped down version of the code in
# https://github.com/matthew-brett/transforms3d/blob/f185e866ecccb66c545559bc9f2e19cb5025e0ab/transforms3d/euler.py
# Besides simplifying it, this version also inverts the order to return x,y,z,w, which is
# the way that ROS prefers it.
def quaternion_from_euler(ai, aj, ak):ai /= 2.0aj /= 2.0ak /= 2.0ci = math.cos(ai)si = math.sin(ai)cj = math.cos(aj)sj = math.sin(aj)ck = math.cos(ak)sk = math.sin(ak)cc = ci*ckcs = ci*sksc = si*ckss = si*skq = np.empty((4, ))q[0] = cj*sc - sj*csq[1] = cj*ss + sj*ccq[2] = cj*cs - sj*scq[3] = cj*cc + sj*ssreturn qclass FramePublisher(Node):def __init__(self):super().__init__('turtle_tf2_frame_publisher')# Declare and acquire `turtlename` parameterself.turtlename = self.declare_parameter('turtlename', 'turtle').get_parameter_value().string_value# Initialize the transform broadcasterself.tf_broadcaster = TransformBroadcaster(self)# Subscribe to a turtle{1}{2}/pose topic and call handle_turtle_pose# callback function on each messageself.subscription = self.create_subscription(Pose,f'/{self.turtlename}/pose',self.handle_turtle_pose,1)self.subscription  # prevent unused variable warningdef handle_turtle_pose(self, msg):t = TransformStamped()# Read message content and assign it to# corresponding tf variablest.header.stamp = self.get_clock().now().to_msg()t.header.frame_id = 'world't.child_frame_id = self.turtlename# Turtle only exists in 2D, thus we get x and y translation# coordinates from the message and set the z coordinate to 0t.transform.translation.x = msg.xt.transform.translation.y = msg.yt.transform.translation.z = 0.0# For the same reason, turtle can only rotate around one axis# and this why we set rotation in x and y to 0 and obtain# rotation in z axis from the messageq = quaternion_from_euler(0, 0, msg.theta)t.transform.rotation.x = q[0]t.transform.rotation.y = q[1]t.transform.rotation.z = q[2]t.transform.rotation.w = q[3]# Send the transformationself.tf_broadcaster.sendTransform(t)def main():rclpy.init()node = FramePublisher()try:rclpy.spin(node)except KeyboardInterrupt:passrclpy.shutdown()

代码解释:

def quaternion_from_euler(ai, aj, ak):ai /= 2.0aj /= 2.0ak /= 2.0ci = math.cos(ai)si = math.sin(ai)cj = math.cos(aj)sj = math.sin(aj)ck = math.cos(ak)sk = math.sin(ak)cc = ci*ckcs = ci*sksc = si*ckss = si*skq = np.empty((4, ))q[0] = cj*sc - sj*csq[1] = cj*ss + sj*ccq[2] = cj*cs - sj*scq[3] = cj*cc + sj*ssreturn q

这段 Python 代码的目的是将欧拉角转换为四元数表示。
欧拉角通常以滚转(roll)、俯仰(pitch)、偏航(yaw)的形式给出,也就是代码中的 (ai, aj, ak)。这个函数首先将这些角度除以2(假设输入的角度原本是以弧度为单位),然后使用三角函数计算四元数的组成部分。

这里逐步解释代码的每个部分:

  • 角度转换为弧度:
    假设输入的角度是以弧度为单位,首先将这些角度除以2。这一步是必要的,因为四元数的计算公式需要使用半角。
  • 计算半角的三角函数值:
    ci, si, cj, sj, ck, sk 分别是半角 ai, aj, ak 的余弦和正弦值。
  • 结合三角函数结果计算四元数分量:
    根据将欧拉角转换为四元数的特定公式进行组合,该公式考虑了旋转轴的顺序。结果是一个四元数 [q0, q1, q2, q3],其中 q0 是标量部分,[q1, q2, q3] 是向量部分。
  • 返回四元数:
    返回的四元数以 numpy 数组的形式,适用于 Python 中的数值计算。

self.turtlename = self.declare_parameter('turtlename', 'turtle').get_parameter_value().string_value

定义并获取一个参数turtlename,它指定一个海龟名称,例如turtle1或turtle2。就是定义一个机器人对象


之后,节点订阅主题并对每条传入消息turtleX/pose运行函数。handle_turtle_pose

self .subscription = self.create_subscription(Pose,f'/{self.turtlename}/pose',self.handle_turtle_pose,1)

现在,我们创建一个TransformStamped对象并为其提供适当的元数据。

  1. 我们需要为正在发布的转换提供一个时间戳,并且我们只需通过调用 来用当前时间来标记它self.get_clock().now()。这将返回 所使用的当前时间Node。

  2. 然后我们需要设置我们正在创建的链接的父框架的名称,在本例中为world。

  3. 最后,我们需要设置我们正在创建的链接的子节点的名称,在本例中这是海龟本身的名称。

海龟姿势消息的处理程序函数广播该海龟的平移和旋转,并将其作为帧world到帧的变换发布turtleX。

t = TransformStamped()# Read message content and assign it to
# corresponding tf variables
t.header.stamp = self.get_clock().now().to_msg()
t.header.frame_id = 'world'
t.child_frame_id = self.turtlename

这段代码是在处理与图形界面中的“乌龟”,它使用了欧拉角到四元数的转换来处理乌龟的旋转,同时也设置了乌龟在2D空间中的位置。以下是详细解释:

设置位置坐标:
t.transform.translation.x = msg.x 和 t.transform.translation.y = msg.y:这两行代码从消息中获取乌龟在x和y轴上的位置坐标,并将其赋给变换的位置属性。
t.transform.translation.z = 0.0:由于乌龟仅存在于2D平面中,z轴的坐标设置为0。
设置旋转:
因为乌龟只能在2D空间中绕z轴旋转(即仅围绕一个轴旋转),因此旋转在x轴和y轴的分量需要设置为0。
q = quaternion_from_euler(0, 0, msg.theta):这行代码调用之前提到的函数,将欧拉角转换为四元数。由于乌龟只在一个平面上旋转,所以x和y的旋转角度为0,而z轴的旋转角度从消息中获取。
t.transform.rotation.x = q[0]、t.transform.rotation.y = q[1]、t.transform.rotation.z = q[2] 和 t.transform.rotation.w = q[3]:这些行将计算出的四元数分量赋值给旋转的相应属性。

# Turtle only exists in 2D, thus we get x and y translation
# coordinates from the message and set the z coordinate to 0
t.transform.translation.x = msg.x
t.transform.translation.y = msg.y
t.transform.translation.z = 0.0# For the same reason, turtle can only rotate around one axis
# and this why we set rotation in x and y to 0 and obtain
# rotation in z axis from the message
q = quaternion_from_euler(0, 0, msg.theta)
t.transform.rotation.x = q[0]
t.transform.rotation.y = q[1]
t.transform.rotation.z = q[2]
t.transform.rotation.w = q[3]

最后,我们将构建的转换传递给负责广播sendTransform

# Send the transformation
self.tf_broadcaster.sendTransform(t)

1.2 添加入口点

要允许命令运行您的节点,您必须将入口点添加到(位于目录中)。
更改
/home/yhg/ros2_study/src/learning_tf2_py/setup.py

在括号之间添加以下行’console_scripts’::

'turtle_tf2_broadcaster = learning_tf2_py.turtle_tf2_broadcaster:main',

在这里插入图片描述


2. 编写启动文件

现在为此演示创建一个启动文件。在 learning_tf2_py下新增launch 文件夹,在launch 文件夹创建 turtle_tf2_demo.launch.py 文件

代码如下:

from launch import LaunchDescription
from launch_ros.actions import Nodedef generate_launch_description():return LaunchDescription([Node(package='turtlesim',executable='turtlesim_node',name='sim'),Node(package='learning_tf2_py',executable='turtle_tf2_broadcaster',name='broadcaster1',parameters=[{'turtlename': 'turtle1'}]),])

首先我们从和包中导入所需的模块launch_ros。应该注意的是,这launch是一个通用的启动框架(不是 ROS 2 特定的),并且launch_ros具有 ROS 2 特定的东西,比如我们在这里导入的节点。


现在我们运行节点来启动turtlesim 模拟并使用我们的节点将turtle1状态广播到tf2 。turtle_tf2_broadcaster

定义启动节点对象

Node(package='turtlesim',executable='turtlesim_node',name='sim'
),
Node(package='learning_tf2_py',executable='turtle_tf2_broadcaster',name='broadcaster1',parameters=[{'turtlename': 'turtle1'}]
),

2.2 添加依赖

导航回到learning_tf2_py目录 ,新增

package.xml使用文本编辑器打开。添加与启动文件的导入语句相对应的以下依赖项

<exec_depend>launch</exec_depend>
<exec_depend>launch_ros</exec_depend>

在这里插入图片描述

这在执行其代码时声明了额外的必需launch和launch_ros依赖项

2.3 更新setup.py

  1. 在文件顶部添加依赖
import os
from glob import glob
  1. 在data_files 中加入
 (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*launch.[pxy][yma]*'))),

在这里插入图片描述

3.构建

在工作区的根目录中运行rosdep以检查是否缺少依赖项。

rosdep install -i --from-path src --rosdistro humble -y

运行结果如下:在这里插入图片描述

仍然在工作区的根目录中构建您的包:

colcon build --packages-select learning_tf2_py

打开一个新终端,导航到工作区的根目录,然后获取安装文件:

. install/setup.bash

4 运行

现在运行启动文件,将启动turtlesim模拟节点和turtle_tf2_broadcaster节点:

ros2 launch learning_tf2_py turtle_tf2_demo.launch.py

在第二个终端窗口中键入以下命令:

ros2 run turtlesim turtle_teleop_key

在这里插入图片描述

现在,使用该tf2_echo工具检查海龟姿势是否确实广播到 tf2:

在这里插入图片描述
控制小乌龟移动可观察到上面数字的变动

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

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

相关文章

双ISP住宅IP有何优势?

双ISP住宅IP在当前的互联网环境中具有显著的优势&#xff0c;这些优势主要体现在网络连接的稳定性、安全性、速度以及业务适用范围等方面。以下是对双ISP住宅IP优势的详细分析&#xff1a; 第一点网络连接的稳定性&#xff0c;双ISP住宅IP使用两个不同的互联网服务提供商&…

区块链 | NFT 相关论文:Preventing Content Cloning in NFT Collections(三)

&#x1f436;原文&#xff1a; Preventing Content Cloning in NFT Collections &#x1f436;写在前面&#xff1a; 这是一篇 2023 年的 CCF-C 类&#xff0c;本博客只记录其中提出的方法。 F C o l l N F T \mathbf{F_{CollNFT}} FCollNFT​ and Blockchains with Native S…

SpringBoot2 仿B站高性能前端+后端项目(wanjie)

SpringBoot2 仿B站高性能前端后端项目(完结) Spring Boot 2 仿B站高性能前端后端项目&#xff1a;打造高效、稳定、可扩展的应用 在当今的互联网时期&#xff0c;网站的性能、稳定性和可扩展性成为了权衡一个项目胜利与否的关键要素。本文将引见如何运用 Spring Boot 2 构建一…

智启算力平台基本操作

智启算力平台 智启算力平台路径搭载数据集搭载镜像配置 智启算力平台 开发文档 帮助文档 - OpenI - 启智AI开源社区 路径搭载 OpenIOSSG/promote: 启智AI协作平台首页推荐组织及推荐项目申请。 - notice/Other_notes/SDKGetPath.md at master - promote - OpenI - 启智AI开…

数据结构-线性表-应用题-2.2-11

1)算法的基本设计思想&#xff1a; 分别求两个升序序列的中位数a,b 若ab&#xff0c;则a或b即为所求中位数 若a<b&#xff0c;则舍弃A中较小的一半&#xff08;中位数偏小&#xff0c;往后面找&#xff09;&#xff0c;同时舍弃序列B中较大的一半&#xff0c;两次舍弃长度…

【Leetcode每日一题】 穷举vs暴搜vs深搜vs回溯vs剪枝_全排列 - 子集(解法2)(难度⭐⭐)(72)

1. 题目解析 题目链接&#xff1a;78. 子集 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 为了生成一个给定数组 nums 的所有子集&#xff0c;我们可以利用一种称为回溯&#xff08;backtracking&#xff09;的算法…

pytest(二):关于pytest自动化脚本编写中,初始化方式setup_class与fixture的对比

一、自动化脚本实例对比 下面是一条用例,使用pytest框架,放在一个类中,两种实现方式: 1.1 setup_class初始化方式 1. 优点: 代码结构清晰,setup_class 和 teardown_class 看起来像传统的类级别的 setup 和 teardown 方法。2. 缺点: 使用 autouse=True 的 fixture 作为…

Mac 链接 HP 136w 打印机步骤

打开 WI-FI 【1】打开打印机左下角Wi-Fi网络设计【或者点击…按钮进入WI-FI菜单】&#xff0c;找到NetWork选项OK进入&#xff1b; 【2】设置WI-FI选项&#xff1a;在菜单内找到Wi-Fi选项OK进入&#xff1b; 【3】在菜单内找到Wi-Fi Direct选项OK进入&#xff1b; 【4】在菜单…

java:File类概述和构造方法

一、File类概述和构造方法 1.File类的概述 File&#xff1a;它是文件和目录路径名的抽象表示 文件和目录是可以通过File封装成对象的对File而言&#xff0c;其封装并不是一个真正存在的文件&#xff0c;仅仅是一个路径名而已。它可以是存在的&#xff0c;也可以是不存在的。…

瑞友天翼应用虚拟化系统SQL注入致远程代码执行漏洞复现

0x01 产品简介 瑞友天翼应用虚拟化系统是西安瑞友信息技术资讯有限公司研发的具有自主知识产权,基于服务器计算架构的应用虚拟化平台。它将用户各种应用软件集中部署在瑞友天翼服务器(群)上,客户端通过WEB即可快速安全的访问经服务器上授权的应用软件,实现集中应用、远程接…

人工智能-2024期中考试

前言 人工智能期中考试&#xff0c;认真准备了但是没考好&#xff0c;结果中游偏下水平。 第4题没拿分 &#xff08;遗传算法&#xff1a;知识点在课堂上一笔带过没有细讲&#xff0c;轮盘赌算法在书本上没有提到&#xff0c;考试的时候也没讲清楚&#xff0c;只能靠猜&…

Python网络协议socket

01 协议基础 01 网络协议 协议&#xff1a;一种规则 网络协议&#xff1a;网络规则&#xff0c;一种在网络通信中的数据包的数据规则 02 TCP/IP协议 osi模型 tcp/ip协议 03 tcp协议 TCP协议提供了一种端到端的、基于连接的、可靠的通信服务。 三次握手 创建连接 四次挥手…

华为:三层交换机与路由器连通上网实验

三层交换机是一种网络交换机&#xff0c;可以实现基于IP地址的高效数据转发和路由功能&#xff0c;通常用于大型企业、数据中心和校园网络等场景。此外&#xff0c;三层交换机还支持多种路由协议&#xff08;如OSPF、BGP等&#xff09;&#xff0c;以实现更为复杂的网络拓扑结构…

深度学习之基于Matlab卷积神经网络验证码识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 随着互联网的发展&#xff0c;验证码作为一种常用的安全验证手段&#xff0c;被广泛应用于各种网站和…

W801学习笔记二十一:英语背单词学习应用——上

英语背单词是比较常见的学习APP&#xff0c;参考唐诗宋词应用&#xff0c;本章做一个类似的应用。 一、单词数据清洗及格式转换 诗词数据的获取渠道很多&#xff0c;一般可以按照年级来分文件。如一到九年级&#xff0c;四六级&#xff0c;雅思等等。 1、先从网上某某地方下载…

python+flask+ldap3搭建简易版IDaaS系统(前端站点)

Python工具开源专栏 Py0006 pythonflaskldap3搭建简易版IDaaS系统&#xff08;前端站点&#xff09; Python工具开源专栏前言目录结构前端网站的部分演示首页查询数据数据同步数据关联查询系统日志 完整代码已在GitHub上开源 前言 pythonflaskldap3搭建简易版IDaaS系统的前端站…

redis分片java实践、redis哨兵机制实现、redis集群搭建

redis分片java实践 linux安装redishttps://mp.csdn.net/mp_blog/creation/editor/134864302复制redis.conf配置文件成redis1.conf、redis2.conf、redis3.conf 修改redis的端口信息和存pid文件的路径。存pid文件的路径只要不同就行了&#xff0c;没什么特别要求。 指定配置文件…

《Fundamentals of Power Electronics》——示例:Buck-Boost转换器模型变为正则形式

为了说明正则电路模型推导的步骤&#xff0c;让我们将buck-boost转换器的等效电路操作成规范形式。buck-boost转换器的一个小信号交流等效电路如下图所示。 为了将上图所示网络转换成正则形式&#xff0c;需要将所有独立源d(t)转换到左侧&#xff0c;而将所有电感转换到右侧与变…

【Qt QML】ComboBox组件

ComboBox 是一个组合的按钮和弹出列表。它提供了一种以最小的屏幕空间呈现选项列表给用户的方式。ComboBox 使用数据模型填充。数据模型通常是一个 JavaScript 数组、一个 ListModel 或一个整数&#xff0c;但也支持其他类型的数据模型。 下面是一个简单的使用方式。 import …

汽车 - 什么是车轮抱死

车轮抱死分为两种情况&#xff0c;一种是车辆故障层面&#xff0c;另一种是驾驶过程中的物理现象。我们先来说最通俗的刹车车轮抱死吧。 刹车制动车轮抱死 车轮停止轴向转动就是抱死&#xff0c;有速度的情况下抱死车轮&#xff0c;如果车辆的惯性动能大于轮胎抓地力&#xff0…