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.hqwc.cn/news/314963.html

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

相关文章

革新MIMO无线电测试,精准测量10 MHz-8 GHz复杂射频信号!

背景介绍 在当今发展的趋势下&#xff0c;无线通信协议变得越来越复杂。具有多个输入和输出&#xff08;MIMO&#xff09;、高达320 MHz的带宽以及高4096 QAM的调制方案。而EN 300 328和EN 301 893标准描述了无线电以及2.4 GHz和5 GHz宽带信号的频谱参数。 EN 300328是欧盟RE…

Java面试题大全

发现网上很多Java面试题都没有答案&#xff0c;所以花了很长时间搜集整理出来了这套Java面试题大全&#xff0c;希望对大家有帮助哈~博主已将这些面试题整理到一个网站上&#xff0c;每天更新 Java 面试题&#xff0c;目前有 1万多道 Java 高频面试题。 本套Java面试题大全&am…

SDG大数据平台简介

联合国可持续发展目标&#xff08;Sustainable Development Goals&#xff09;缩写SDGs&#xff0c;是联合国制定的17个全球发展目标&#xff0c;在2000-2015年千年发展目标&#xff08;MDGs&#xff09;到期之后继续指导2015-2030年的全球发展工作。&#xff08;摘自百度&…

【PWN学习之House of 系列】House Of Einherjar

写在前面 有路线的学习一下 glibc 堆利用的 house of 系列利用手法。 主要参考以下文章以及文章中涉及的连接。 https://roderickchan.github.io/zh-cn/2023-02-27-house-of-all-about-glibc-heap-exploitation 简介 漏洞成因 溢出写、off by one、off by null 适用范围 …

树莓派4B-Python使用PyCharm的SSH协议在电脑上远程编辑程序

目录 前言一、pycharm的选择二、添加SSH的解释器使用总结 前言 树莓派的性能始终有限&#xff0c;不好安装与使用高级一点的程序编辑器&#xff0c;如果只用thonny的话&#xff0c;本人用得不习惯&#xff0c;还不如PyCharm&#xff0c;所以想着能不能用电脑中的pycharm来编写…

一、Linux内核介绍

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

目标检测-One Stage-SSD

文章目录 前言一、SSD的网络结构和流程二、SSD的创新点总结 前言 根据前文目标检测-One Stage-YOLOv1可以看出YOLOv1的主要缺点是&#xff1a; 每个格子针对目标框的回归是不加限制的&#xff0c;导致目标的定位并不是很精准和Faster RCNN等先进Two Stage算法相比&#xff0c…

Unity之地形的构建

PS&#xff1a;公司没活干&#xff0c;好无聊偷偷摸鱼学Unity&#xff0c;害怕自己学完之后忘记&#xff0c;写下这一篇博客 先来看一下效果图&#xff1a;有山有水有树有草地 创建一个新的Unity3D项目 这里要用到Unity官方的免费资源包&#xff08;现在好像已经下架了百度网盘…

如何在iPhone设备中查看崩溃日志

​ 目录 如何在iPhone设备中查看崩溃日志 摘要 引言 导致iPhone设备崩溃的主要原因是什么&#xff1f; 使用克魔助手查看iPhone设备中的崩溃日志 奔溃日志分析 总结 摘要 本文介绍了如何在iPhone设备中查看崩溃日志&#xff0c;以便调查崩溃的原因。我们将展示三种不同的…

【华为机试】2023年真题B卷(python)-计算疫情扩散时间

一、题目 题目描述&#xff1a; 请根据给定的地图计算&#xff0c;多少天以后&#xff0c;全部区域都会被感染。 如果初始地图上所有区域全部都被感染&#xff0c;或者没有被感染区域&#xff0c;返回-1 二、输入输出 输入描述: 一行N*N个数字&#xff08;只包含0,1&#xff0c…

分布式【Zookeeper】

1.1 ZooKeeper 是什么 ZooKeeper 是 Apache 的顶级项目。ZooKeeper 为分布式应用提供了高效且可靠的分布式协调服务&#xff0c;提供了诸如统一命名服务、配置管理和分布式锁等分布式的基础服务。在解决分布式数据一致性方面&#xff0c;ZooKeeper 并没有直接采用 Paxos 算法&…

SQL常见面试题

今天刷了一遍牛客里的必知必会题&#xff0c;一共50道题&#xff0c;大部分都比较基础&#xff0c;下面汇总一下易错题。 SQL81 顾客登录名 本题几个关键点&#xff1a; 登录名是其名称和所在城市的组合&#xff0c;因此需要使用substring()和concat()截取和拼接字段。得到登…