ROS TF坐标变换 - 动态坐标变换

目录

  • 一、动态坐标变换(C++实现)
  • 二、动态坐标变换(Python实现)

一、动态坐标变换(C++实现)

所谓动态坐标变换,是指两个坐标系之间的相对位置是变化的。比如机械臂末端执行器与 base_link 之间,移动机器人base_link与world之间。可以理解动态坐标关系是随时间变化的静态坐标关系(即静态是动态对时间的微分)。

我们使用ROS的 turtlesim 模拟一个移动机器人,通过TF发布它相对世界坐标系的坐标。

在创建的 tf2_learning 包路径下的 src 目录中创建 dynamic_frame_broadcast.cppdynamic_frame_listen.cpp ,修改 CMakeLists.txt ,添加如下内容:

add_executable(${PROJECT_NAME}_dynamic_broadcast src/dynamic_frame_broadcast.cpp)
add_executable(${PROJECT_NAME}_dynamic_listen src/dynamic_frame_listen.cpp)target_link_libraries(${PROJECT_NAME}_dynamic_broadcast${catkin_LIBRARIES}
)target_link_libraries(${PROJECT_NAME}_dynamic_listen${catkin_LIBRARIES}
)

dynamic_frame_broadcast.cpp 实现广播子坐标系相对于父坐标系的动态坐标关系,内容如下:

/*** @file: dynamic_frame_broadcast.cpp* @brief: 动态的坐标系相对姿态发布* @author: 万俟淋曦(1055311345@qq.com)* @date: 2023-12-30 22:47:33* @modifier:* @date: 2023-12-30 22:47:33*/#include "ros/ros.h"
#include "turtlesim/Pose.h"
#include "tf2_ros/transform_broadcaster.h"
#include "geometry_msgs/TransformStamped.h"
#include "tf2/LinearMath/Quaternion.h"void turtle1PoseCallback(const turtlesim::Pose::ConstPtr &pose)
{// 创建 TF 广播器static tf2_ros::TransformBroadcaster broadcaster;// 创建 广播的数据geometry_msgs::TransformStamped tfs;// --头设置tfs.header.frame_id = "world";tfs.header.stamp = ros::Time::now();// --坐标系idtfs.child_frame_id = "turtle1";// --坐标系相对信息设置tfs.transform.translation.x = pose->x;tfs.transform.translation.y = pose->y;tfs.transform.translation.z = 0.0; // 二维, z为0//  --欧拉角转四元数tf2::Quaternion qtn;qtn.setRPY(0, 0, pose->theta); // 二维, 只有偏航角tfs.transform.rotation.x = qtn.getX();tfs.transform.rotation.y = qtn.getY();tfs.transform.rotation.z = qtn.getZ();tfs.transform.rotation.w = qtn.getW();// 广播器发布数据broadcaster.sendTransform(tfs);
}int main(int argc, char **argv)
{// 初始化 ROS 节点ros::init(argc, argv, "dynamic_frame_broadcast");// 创建 ROS 句柄ros::NodeHandle nh;// 创建订阅对象,订阅乌龟的世界位姿ros::Subscriber sub = nh.subscribe<turtlesim::Pose>("/turtle1/pose", 1000, turtle1PoseCallback);ros::spin();return 0;
}

dynamic_frame_listen.cpp 订阅动态坐标转换关系,并利用该关系将小乌龟坐标系下的坐标转换到 world 坐标系,编辑内容如下:

/*** @file: dynamic_frame_listen.cpp* @brief: 订阅动态坐标系并转换相应坐标* @author: 万俟淋曦(1055311345@qq.com)* @date: 2023-12-31 11:55:40* @modifier:* @date: 2023-12-31 11:55:40*/
#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" // 包含TF坐标转换方法int main(int argc, char **argv)
{// 初始化 ROS 节点ros::init(argc, argv, "dynamic_frame_listen");ros::NodeHandle nh;// 创建 TF 订阅节点tf2_ros::Buffer buffer;tf2_ros::TransformListener listener(buffer);ros::Rate r(1);while (ros::ok()){// 生成一个坐标点, 模拟末端执行器坐标系下的点坐标(小乌龟坐标系下的坐标)geometry_msgs::PointStamped point_turtle1;point_turtle1.header.frame_id = "turtle1";point_turtle1.header.stamp = ros::Time();point_turtle1.point.x = 1;point_turtle1.point.y = 1;point_turtle1.point.z = 0;// 转换坐标点, 计算小乌龟坐标系下的坐标点在 world 下的坐标try{geometry_msgs::PointStamped point_base;point_base = buffer.transform(point_turtle1, "world");ROS_INFO("point_base: (%.2f, %.2f, %.2f), frame: %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){ROS_ERROR("%s", e.what());}r.sleep();ros::spinOnce();}return 0;
}

编译后,

  • 首先开启小乌龟 rosrun turtlesim turtlesim_node

  • 执行 rosrun tf2_learning tf2_learning_dynamic_broadcast 开始广播坐标,此时打开rviz订阅TF看到TF树模型

  • 输入命令:rviz

  • 在启动的 rviz 中设置 Fixed Frameworld

  • 点击左下的 Add 按钮,在弹出的窗口中选择 TF 组件,即可显示坐标关系,如下:

在这里插入图片描述

继续执行命令rosrun tf2_learning tf2_learning_listen可以看到转换后的坐标,以及所属父坐标系

在这里插入图片描述

执行命令 rosrun turtlesim turtle_teleop_key 使用键盘控制小乌龟移动,可以看到 rviz以及转换后的坐标都在同步动态变化。

在这里插入图片描述

二、动态坐标变换(Python实现)

在创建的 tf2_learning 包路径下 src 目录的同级,创建一个 scripts 目录,在这里存储脚本(如python脚本),我们创建 dynamic_frame_broadcast.py 以实现坐标广播,编辑内容如下:

#! /usr/bin/env pythonimport rospy
import tf2_ros
import tf
from turtlesim.msg import Pose
from geometry_msgs.msg import TransformStamped# 回调函数处理
def turtle1PoseCallback(pose):# 创建 TF 广播器broadcaster = tf2_ros.TransformBroadcaster()# 创建 广播的数据(通过 pose 设置)tfs = TransformStamped()tfs.header.frame_id = "world"tfs.header.stamp = rospy.Time.now()tfs.child_frame_id = "turtle1"tfs.transform.translation.x = pose.xtfs.transform.translation.y = pose.ytfs.transform.translation.z = 0.0qtn = tf.transformations.quaternion_from_euler(0,0,pose.theta)tfs.transform.rotation.x = qtn[0]tfs.transform.rotation.y = qtn[1]tfs.transform.rotation.z = qtn[2]tfs.transform.rotation.w = qtn[3]# 广播器发布数据broadcaster.sendTransform(tfs)if __name__ == "__main__":# 初始化 ROS 节点rospy.init_node("dynamic_frame_broadcast_py")# 订阅 /turtle1/pose 话题消息sub = rospy.Subscriber("/turtle1/pose", Pose, turtle1PoseCallback)rospy.spin()

创建 dynamic_frame_listen.py 以订阅静态坐标转换关系,并利用该关系将雷达坐标系的点转换到 world 坐标系,编辑内容如下:

#! /usr/bin/env pythonimport rospy
import tf2_ros
# 不要使用 geometry_msgs,需要使用 tf2 内置的消息类型
from tf2_geometry_msgs import PointStamped
# from geometry_msgs.msg import PointStampedif __name__ == "__main__":# 初始化 ROS 节点rospy.init_node("dynamic_frame_listen_py")# 创建 TF 订阅对象buffer = tf2_ros.Buffer()listener = tf2_ros.TransformListener(buffer)rate = rospy.Rate(1)while not rospy.is_shutdown():    # 创建一个 radar 坐标系中的坐标点point_source = PointStamped()point_source.header.frame_id = "turtle1"point_source.header.stamp = rospy.Time.now()point_source.point.x = 10point_source.point.y = 2point_source.point.z = 3try:# 转换坐标点, 计算小乌龟坐标系下的坐标点在 world 下的坐标point_target = buffer.transform(point_source,"world",rospy.Duration(1))rospy.loginfo("point_target: (%.2f, %.2f, %.2f), frame: %s",point_target.point.x,point_target.point.y,point_target.point.z,point_target.header.frame_id)except Exception as e:rospy.logerr("%s", e)rate.sleep()

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

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

相关文章

渗透线上下料控制(SCL源代码)

有关渗透线的其它详细介绍请参考下面链接文章&#xff1a; https://rxxw-control.blog.csdn.net/article/details/133611151https://rxxw-control.blog.csdn.net/article/details/133611151这里的渗透线上下料属于整个渗透线流程里的最前端和最后端&#xff0c;分别负责待处理…

《Linux系统与网络管理》复习题库---简答题

1、简述这些分区的名字以及各自的作用。 答&#xff1a; /boot 存放内核镜像的地方&#xff0c;这个文件夹独立分区的意义在于降低不能开机的风险。 /根目录&#xff0c;一般采用 ext3 文件系统&#xff0c;分区的容量一定要大于安装软件包的容量。 /usr 多数软件的默认安装的地…

Anaconda3 2021.11安装

1. 镜像下载&#xff1a;Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 2. 安装在D盘&#xff1a; 3. 配置环境变量&#xff1a; 在这里&#xff0c;第一个教程A在系统变量里配置了五个&#xff0c;但我没有 所以又搜了教程B&#xf…

扎根底层技术,推动机器人换代式升级

热赛道和冷市场的矛盾之下&#xff0c;机器人需要一次换代式升级。 冷中有热的资本市场 在宏观经济下行的影响下&#xff0c;我国服务机器人产量从2022年开始出现明显放缓&#xff0c;2021年12月至2022年12月&#xff0c;我国服务机器人产量都处于同比下滑的状态&#xff0c;…

LeetCode每日一题.05(N皇后)

按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案。 每一种…

以元旦为题的诗词(三)

愿新的一年给我们带来无尽的好运和幸福愿我们的梦想在新的起点绽放! 让我们在未来的日子里书写新的篇章! 接着分享几首以元旦为题的几首诗&#xff0c;喜欢的朋友可以自取&#xff0c;想要更多免费的诗词&#xff0c;请自行百度或小程序搜索&#xff1a;美诗计 元旦 元旦佳节…

剑指“CPU飙高”问题

一、什么是cpu飙高&#xff1f; 一般指程序运行时cpu占用率过高   linux系统中&#xff0c;我们使用top命令&#xff0c;会看到正在运行进程的cpu使用率等&#xff0c;同时在最上面也会看到总的cpu使用率&#xff0c;当总的cpu使用率过高&#xff0c;如果有运维监控平台&…

【Linux】理解文件系统

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 1. 了解磁盘1.1 磁盘的物理结构1.2 磁盘的逻辑结构1.3 磁盘的存储结构 2. 文件系统2.…

2023年12月编程语言排行榜

TIOBE Index for December 2023 December Headline: C# on its way to become programming language of the year 2023 2023年12月的TIOBE指数&#xff1a;12月头条:c#将成为2023年最佳编程语言 Yes, I know, we have been here before. At the end of 2022, it looked like …

全局异常和自定义异常处理

全局异常GlobalException.java&#xff0c;basePackages&#xff1a;controller层所在的包全路径 import com.guet.score_management_system.common.domian.AjaxResult; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bi…

电脑怎么设置代理IP上网?如何隐藏自己电脑的真实IP?

在现代互联网中&#xff0c;代理IP已成为许多用户保护隐私和上网安全的重要手段。通过设置代理IP&#xff0c;用户可以隐藏自己的真实IP地址&#xff0c;提高上网的安全性&#xff0c;同时保护个人信息不被泄露。本文将详细介绍如何设置代理IP上网以及如何隐藏电脑的真实IP地址…

Vue Tinymce富文本组件添加自定义字体项

实现效果如下&#xff1a; Tinymce 组件进行字体设置 设置完后&#xff0c;就可以使用自定义的字体了。

Spring Boot整合 EasyExcel 实现复杂 Excel 表格的导入与导出功能

文章目录 1. 简介2. 引入依赖3. 导入功能实现3.1 创建实体类3.2 编写导入 Controller3.3 编写导入页面 4. 导出功能实现4.1 编写导出 Controller4.2 编写导出页面 5. 启动应用 &#x1f388;个人主页&#xff1a;程序员 小侯 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &…

你好2024!

大家好&#xff0c;我是小悟 2024年1月1日&#xff0c;新年的第一天&#xff0c;阳光明媚&#xff0c;空气中弥漫着希望和新的开始的气息。在这个特别的日子里&#xff0c;大家纷纷走出家门&#xff0c;迎接新年的到来。 街道上&#xff0c;熙熙攘攘的人群中&#xff0c;有孩…

【动态管理日志】Spring Boot 实现 热插拔 AOP,非常实用!

现在有这么一个需求&#xff1a;就是我们日志的开与关是交给使用人员来控制的&#xff0c;而不是由我们开发人员固定写死的。大家都知道可以用aop来实现日志管理&#xff0c;但是如何动态的来实现日志管理呢&#xff1f;aop源码中的实现逻辑中有这么一个步骤&#xff0c;就是会…

将学习自动化测试时的医药管理信息系统项目用idea运行

将学习自动化测试时的医药管理信息系统项目用idea运行 背景 学习自动化测试的时候老师的运行方式是把医药管理信息系统项目打包成war包后再放到tomcat的webapp中去运行&#xff0c;于是我想着用idea运行会方便点&#xff0c;现在记录下步骤方便以后查找最开始没有查阅资料&am…

蓝牙物联网灯控设计方案

蓝牙技术是当前应用最广泛的无线通信技术之一&#xff0c;工作在全球通用的 2.4GHZ 的ISM 频段。蓝牙的工作距离约为 100 米&#xff0c;具有一定的穿透性&#xff0c;没有方向限制。具有低成本、抗干扰能力强、传输质量高、低功耗等特点。蓝牙技术组网比较简单&#xff0c;无需…

【 YOLOv5】目标检测 YOLOv5 开源代码项目调试与讲解实战(3)-训练yolov5模型(本地)

训练yolov5模型&#xff08;本地&#xff09; 训练文件 train.py训练如下图 一些参数的设置weights:对于weight参数&#xff0c;可以往Default参数中填入的参数有 cfg&#xff1a;&#xff08;缩写&#xff09;cfg参数可以选择的网络模型 data对于data hyp 超参数epochs 训练多…

托管在亚马逊云科技的向量数据库MyScale如何借助AWS基础设施构建稳定高效的云数据库

MyScale是一款完全托管于亚马逊云科技&#xff0c;支持SQL的高效向量数据库。MyScale的优势在于&#xff0c;它在提供与专用向量数据库相匹敌甚至优于的性能的同时&#xff0c;还支持完整的SQL语法。以下内容&#xff0c;将阐述MyScale是如何借助亚马逊云科技的基础设施&#x…

张量操作与线性回归

一、张量的操作&#xff1a;拼接、切分、索引和变换 &#xff08;1&#xff09;张量拼接与切分 1.1 torch.cat() 功能&#xff1a;将张量按维度dim进行拼接 • tensors: 张量序列 • dim : 要拼接的维度 torch.cat(tensors, dim0, outNone)函数用于沿着指定维度dim将多个张量…