机器人系统ros2-开发实践08-了解如何使用 tf2 来访问坐标帧转换(Python)

news2024/11/18 7:33:38

tf2 库允许你在 ROS 节点中查询两个帧之间的转换。这个查询可以是阻塞的,也可以是非阻塞的,取决于你的需求。下面是一个基本的 Python 示例,展示如何在 ROS 节点中使用 tf2 查询帧转换。

本教程假设您已完成tf2 静态广播器教程 (Python)和tf2 广播器教程 (Python)。在上一个教程中,我们创建了一个learning_tf2_py包。机器人系统ros2-开发实践06-将静态坐标系广播到 tf2(Python)-定义机器人底座与其传感器或非移动部件之间的关系

步骤1:

1 编写监听节点

我们首先创建源文件。转到learning_tf2_py我们在上一教程中创建的包。在src/learning_tf2_py/learning_tf2_py目录中新建turtle_tf2_listener.py,用vscode 打开文件,将下面的代码贴入文件中。

代码如下:

import math

from geometry_msgs.msg import Twist

import rclpy
from rclpy.node import Node

from tf2_ros import TransformException
from tf2_ros.buffer import Buffer
from tf2_ros.transform_listener import TransformListener

from turtlesim.srv import Spawn


class FrameListener(Node):

    def __init__(self):
        super().__init__('turtle_tf2_frame_listener')

        # Declare and acquire `target_frame` parameter
        self.target_frame = self.declare_parameter(
          'target_frame', 'turtle1').get_parameter_value().string_value

        self.tf_buffer = Buffer()
        self.tf_listener = TransformListener(self.tf_buffer, self)

        # Create a client to spawn a turtle
        self.spawner = self.create_client(Spawn, 'spawn')
        # Boolean values to store the information
        # if the service for spawning turtle is available
        self.turtle_spawning_service_ready = False
        # if the turtle was successfully spawned
        self.turtle_spawned = False

        # Create turtle2 velocity publisher
        self.publisher = self.create_publisher(Twist, 'turtle2/cmd_vel', 1)

        # Call on_timer function every second
        self.timer = self.create_timer(1.0, self.on_timer)

    def on_timer(self):
        # Store frame names in variables that will be used to
        # compute transformations
        from_frame_rel = self.target_frame
        to_frame_rel = 'turtle2'

        if self.turtle_spawning_service_ready:
            if self.turtle_spawned:
                # Look up for the transformation between target_frame and turtle2 frames
                # and send velocity commands for turtle2 to reach target_frame
                try:
                    t = self.tf_buffer.lookup_transform(
                        to_frame_rel,
                        from_frame_rel,
                        rclpy.time.Time())
                except TransformException as ex:
                    self.get_logger().info(
                        f'Could not transform {to_frame_rel} to {from_frame_rel}: {ex}')
                    return

                msg = Twist()
                scale_rotation_rate = 1.0
                msg.angular.z = scale_rotation_rate * math.atan2(
                    t.transform.translation.y,
                    t.transform.translation.x)

                scale_forward_speed = 0.5
                msg.linear.x = scale_forward_speed * math.sqrt(
                    t.transform.translation.x ** 2 +
                    t.transform.translation.y ** 2)

                self.publisher.publish(msg)
            else:
                if self.result.done():
                    self.get_logger().info(
                        f'Successfully spawned {self.result.result().name}')
                    self.turtle_spawned = True
                else:
                    self.get_logger().info('Spawn is not finished')
        else:
            if self.spawner.service_is_ready():
                # Initialize request with turtle name and coordinates
                # Note that x, y and theta are defined as floats in turtlesim/srv/Spawn
                request = Spawn.Request()
                request.name = 'turtle2'
                request.x = float(4)
                request.y = float(2)
                request.theta = float(0)
                # Call request
                self.result = self.spawner.call_async(request)
                self.turtle_spawning_service_ready = True
            else:
                # Check if the service is ready
                self.get_logger().info('Service is not ready')


def main():
    rclpy.init()
    node = FrameListener()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass

    rclpy.shutdown()

2 代码说明:

TransformListener以帮助简化接收转换的任务。

from tf2_ros.transform_listener import TransformListener

在这里,我们创建一个TransformListener对象。创建侦听器后,它开始通过线路接收 tf2 转换,并将它们缓冲最多 10 秒。

self.tf_listener = TransformListener(self.tf_buffer, self)

最后,我们向侦听器查询特定的转换。我们lookup_transform使用以下参数调用方法:
提供rclpy.time.Time()只会为我们提供最新的可用转换。所有这些都包含在 try- except 块中以处理可能的异常

t = self.tf_buffer.lookup_transform(
    to_frame_rel,
    from_frame_rel,
    rclpy.time.Time())

3 新增启动入口点

要允许命令运行您的节点,您必须将入口点添加到src/learning_tf2_py 的setup.py ,在setup.py 文件里找到console_scripts,在括号之间添加以下行

'turtle_tf2_listener = learning_tf2_py.turtle_tf2_listener:main',

在这里插入图片描述

3.1 更新启动文件

使用文本编辑器打开目录中调用的启动文件src/learning_tf2_py/launch,向启动描述turtle_tf2_demo.launch.py添加两个新节点,添加启动参数,然后添加导入。生成的新的文件应如下所示:

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration

from launch_ros.actions import Node


def 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'}
            ]
        ),
        DeclareLaunchArgument(
            'target_frame', default_value='turtle1',
            description='Target frame name.'
        ),
        Node(
            package='learning_tf2_py',
            executable='turtle_tf2_broadcaster',
            name='broadcaster2',
            parameters=[
                {'turtlename': 'turtle2'}
            ]
        ),
        Node(
            package='learning_tf2_py',
            executable='turtle_tf2_listener',
            name='listener',
            parameters=[
                {'target_frame': LaunchConfiguration('target_frame')}
            ]
        ),
    ])

这将声明一个target_frame启动参数,为我们将生成的第二只海龟启动一个广播器,以及将订阅这些转换的坐标侦监听器。

3 构建

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

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

在这里插入图片描述

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

colcon build --packages-select learning_tf2_py

在这里插入图片描述

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

. install/setup.bash

4 运行

现在您已准备好开始完整的海龟演示:
在工作区的根目录执行

ros2 launch learning_tf2_py turtle_tf2_demo.launch.py

看到有两个海龟,另外一个会向其中一个自动靠齐

在这里插入图片描述

您应该会看到海龟模拟卡上有两只海龟。在第二个终端窗口中键入以下命令:

ros2 run turtlesim turtle_teleop_key

在这里插入图片描述

要查看是否有效,只需使用箭头键围绕第一只乌龟行驶(确保您的终端窗口处于活动状态,而不是模拟器窗口),您将看到第二只乌龟紧随第一只乌龟!

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

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

相关文章

车辆运动模型中LQR代码实现

一、前言 最近看到关于架构和算法两者关系的一个描述,我觉得非常认同,分享给大家。 1、好架构起到两个作用:合理的分解功能、合理的适配算法; 2、好的架构是好的功能的必要条件,不是充分条件,一味追求架构…

海外云手机解决海外社交媒体运营难题

随着全球数字化浪潮的推进,海外社交媒体已成为外贸企业拓展市场、提升品牌影响力的重要阵地。Tiktok、Facebook、领英、twitter等平台以其庞大的用户基础和高度互动性,为企业提供了前所未有的营销机会。本文将介绍如何通过海外云手机,高效、快…

[优选算法]------滑动窗⼝——209. 长度最小的子数组

目录 1.题目 1.解法⼀(暴⼒求解)(会超时): 2.解法⼆(滑动窗⼝): 1.算法思路: 2.手撕图解 3.代码实现 1.C 2.C语言 1.题目 209. 长度最小的子数组 给定一个含有 n…

pod介绍

一、前言 Pod 是 Kubernetes 中最小的部署单元,它可以包含一个或多个容器,以及共享的存储卷和网络命名空间,Pod 提供了一种抽象,用于组织和管理容器化的应用程序,并提供了一种灵活、轻量级的方式来部署和管理应用程序 …

基于JSP动漫论坛的设计与实现(四)

目录 功能模块测试 6.1 测试概述及所用方案 6.1.1软件测试概述 6.1.3 测试的步骤 6.1.4 测试的主要内容 6.1.5 测试方案 6.1.6测试设计 6.2 前端功能测试 6.2.1 登录功能测试 6.2.2 注册功能测试 6.2.3 发帖功能测试 6.2.4 回复帖子测试 6.3 后台功能测试 6…

ETL工具中JSON格式的转换方式

JSON的用处 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,其设计初衷是为了提升网络应用中数据的传输效率及简化数据结构的解析过程。自其诞生以来,JSON 已成为Web开发乃至众多软件开发领域中不可或缺的一部分&a…

C++:类与对象—继承

类与对象—继承 一、继承是什么?二、继承定义三、基类和派生类对象赋值转换四、继承中的作用域五、派生类的默认成员函数六、继承与友元七、继承与静态成员八、复杂的菱形继承及菱形虚拟继承九、继承的总结和反思十、考察重点 一、继承是什么? 继承(inh…

基于 LlaMA 3 + LangGraph 在windows本地部署大模型 (三)

基于 LlaMA 3 LangGraph 在windows本地部署大模型 (三) 大家继续看 https://lilianweng.github.io/posts/2023-06-23-agent/的文档内容 第二部分:内存 记忆的类型 记忆可以定义为用于获取、存储、保留以及随后检索信息的过程。人脑中有多…

【qt】设计器实现界面

设计器实现界面 一.总体思路二.具体操作1.创建项目2.粗略拖放3.水平布局4.垂直布局5.修改名字6.转到槽7.实现槽函数 一.总体思路 二.具体操作 1.创建项目 这次咱们一定要勾选Generate form哦。 因为我们要使用设计器进行拖放。 2.粗略拖放 这里用到了复选框:C…

dos命令改3389端口,通过dos命令更改3389端口的操作

要使用DOS命令更改3389端口,通常涉及修改Windows注册表中的相关键值。请注意,直接操作注册表具有一定的风险,因此在进行任何更改之前,请确保您了解正在进行的操作,并已经采取了适当的备份措施。 以下是一个基本的操作步…

Apache Sqoop:高效数据传输工具搭建与使用教程

目录 引言一、环境准备二、安装sqoop下载sqoop包解压文件 三、配置Sqoop下载mysql驱动拷贝hive的归档文件配置环境变量修改sqoop-env.sh配置文件替换版本的commons-lang的jar包 验证Sqoop安装查看Sqoop版本测试Sqoop连接MySQL数据库是否成功查看数据库查看数据表去除警告信息 四…

matlab的imclose()详解

J imclose(I,SE) J imclose(I,nhood) 说明 J imclose(I,SE) 使用结构元素 SE 对灰度或二值图像 I 执行形态学闭运算。形态学闭运算是先膨胀后腐蚀,这两种运算使用相同的结构元素。 J imclose(I,nhood) 对图像 I 执行闭运算,其中 nhood 是由指定结…

开启异步线程的方法

1,开启异步线程,在启动类上加注解: 2,自定义线程池: Configuration public class PromotionConfig {Beanpublic Executor generateExchangeCodeExecutor() {ThreadPoolTaskExecutor executor new ThreadPoolTaskExec…

大模型面试常考知识点1

文章目录 1. 写出Multi-Head Attention2. Pre-Norm vs Post-Norm3. Layer NormRMS NormBatch Norm 4. SwiGLU从ReLU到SwishSwiGLU 5. AdamW6. 位置编码Transformer位置编码RoPEALibi 7. LoRA初始化 参考文献 1. 写出Multi-Head Attention import torch import torch.nn as nn …

【.NET Core】你认识Attribute之CallerMemberName、CallerFilePath、CallerLineNumber三兄弟

你认识Attribute之CallerMemberName、CallerFilePath、CallerLineNumber三兄弟 文章目录 你认识Attribute之CallerMemberName、CallerFilePath、CallerLineNumber三兄弟一、概述二、CallerMemberNameAttribute类三、CallerFilePathAttribute 类四、CallerLineNumberAttribute 类…

Java面试题:ReentrantLock

ReentrantLock 可重入锁 可中断 可以设置超时时间 可以让线程在超时后放弃获取锁 可以设置公平锁 可以实现公平锁或非公平锁 支持多个条件变量 让线程在某些条件下进入等待 和synchronized一样都支持重入 //创建锁对象 ReentrantLock Lock new ReentrantLock(); try…

oracle 9i 行头带有scn的表

oracle 9i 行头带有scn的表 conn scott/tiger drop table t1; drop table t2; create table t1(c varchar2(5)); create table t2(c varchar2(6)) ROWDEPENDENCIES; --t2表每行都有scn,会增加六个字节的开销 alter table t1 pctfree 0; alter table t2 pctfree 0; insert in…

Transformer模型详解03-Self-Attention(自注意力机制)

文章目录 简介基础知识什么是AttentionSelf Attention原理通俗易懂理解矩阵计算Q,K,V计算Self-Attention 的输出 优势 Multi-head self-attention原理通俗易懂理解矩阵计算代码实现 简介 下图是论文中 Transformer 的内部结构图,左侧为 Enco…

十、Redis内存回收策略和机制

1、Redis的内存回收 在Redis中可以设置key的过期时间,以期可以让Redis回收内存,循环使用。在Redis中有4个命令可以设置Key的过期时间。分别为 expire、pexpire、expireat、pexpireat。 1.1、expire expire key ttl:将key的过期时间设置为tt…

SpringBoot自定义初始化sql文件 支持多类型数据库

我在resources目录下有init.sql初始化sql语句 指定sql文件的地址 sql内容如下: /*角色表*/ INSERT INTO #{schema}ccc_base_role (id, create_time, create_user_id, is_delete, role_name, status, update_time, update_user_id) VALUES(b89e30d81acb88448d412…