ROS TF坐标变换 - 静态坐标变换
目录
- 一、静态坐标变换(C++实现)
- 二、静态坐标变换(Python实现)
如前文所属,ROS通过广播的形式告知各模块的位姿关系,接下来详述这一机制的代码实现。
模块间的位置关系有两种类型,一种是相对固定的,称为静态坐标变换,一种是相对不固定,变化的,称为动态坐标变换。
一、静态坐标变换(C++实现)
所谓静态坐标变换,是指两个坐标系之间的相对位置是固定的。比如机器人底盘上安装了一个激光雷达,他和底盘组成一个刚体,它们的相对位姿不会随机器人的运动而变化,他们之间的坐标变换即属于静态坐标变换。
假设激光雷达相对与底盘的欧拉位姿为(0.5, 0.0, 0.3; 0.0, 0.0, 0.0)
雷达检测到的障碍物位置为(2.0, 2.5, 0.3)
若要计算障碍物和底盘的相对位置,就可以通过雷达到底盘的坐标变换来计算,步骤如下:
- 雷达(laser)发布自己和底盘(base_link)的相对静态坐标
- 避障模块监听雷达(laser)和底盘(base_link)的相对坐标关系,并通过
tf
计算障碍物位置。
首先创建 tf2_learning
包,命令如下:(这一步不是必须,这里只是为了方便清晰的说明,也可以使用已有的包,在包里新增节点等方法)
catkin_creat_pkg tf2_learning roscpp rospy geometry_msgs std_msgs tf2 tf2_geometry_msgs tf2_ros
创建后,文件结构如下:
在创建的 tf2_learning
包路径下有一个 src
目录,在这里存储C++源码,我们创建 static_frame_broadcast.cpp
和 static_frame_listen.cpp
,修改 CMakeLists.txt
,添加如下内容:
add_executable(${PROJECT_NAME}_broadcast src/static_frame_broadcast.cpp)
add_executable(${PROJECT_NAME}_listen src/static_frame_listen.cpp)target_link_libraries(${PROJECT_NAME}_broadcast${catkin_LIBRARIES}
)target_link_libraries(${PROJECT_NAME}_listen${catkin_LIBRARIES}
)
static_frame_broadcast.cpp
实现广播子坐标系相对于父坐标系的静态坐标,内容如下:
#include "ros/ros.h"
#include "tf2_ros/static_transform_broadcaster.h"
#include "geometry_msgs/TransformStamped.h"
#include "tf2/LinearMath/Quaternion.h"int main(int argc, char **argv)
{// 初始化 ROS 节点ros::init(argc, argv, "static_frame_broadcast");// 创建静态坐标转换广播器tf2_ros::StaticTransformBroadcaster broadcaster;// 创建坐标系信息geometry_msgs::TransformStamped ts;// --设置头信息ts.header.seq = 100;ts.header.stamp = ros::Time::now();ts.header.frame_id = "base_link";// --设置子级坐标系ts.child_frame_id = "laser";// --设置子坐标系相对于父坐标系的平移偏移量ts.transform.translation.x = 0.5;ts.transform.translation.y = 0.0;ts.transform.translation.z = 0.3;// --设置子坐标系相对于父坐标系的旋转偏移量// --将欧拉角转换成四元数tf2::Quaternion qtn; // tf2的四元数类qtn.setRPY(0, 0, 0); // 设置欧拉角// 获取旋转的四元数值ts.transform.rotation.x = qtn.getX();ts.transform.rotation.y = qtn.getY();ts.transform.rotation.z = qtn.getZ();ts.transform.rotation.w = qtn.getW();// 广播器发布坐标系信息broadcaster.sendTransform(ts);ros::spin();return 0;
}
static_frame_listen.cpp
实现订阅静态坐标转换关系,并利用该关系将雷达坐标系的点转换到 base_link 坐标系,内容如下:
#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"int main(int argc, char *argv[])
{// 初始化 ROS 节点ros::init(argc, argv, "static_frame_listen");ros::NodeHandle nh;// 创建 TF 订阅节点tf2_ros::Buffer buffer;tf2_ros::TransformListener listener(buffer);ros::Rate rate(1);while (ros::ok()){// 生成一个坐标点, 模拟雷达检测到的障碍物坐标点(雷达坐标系下的坐标)geometry_msgs::PointStamped point_laser;point_laser.header.frame_id = "laser";point_laser.header.stamp = ros::Time::now();point_laser.point.x = 2.0;point_laser.point.y = 2.5;point_laser.point.z = 0.3;// 转换坐标点, 计算障碍物坐标点在 base_link 下的坐标try{geometry_msgs::PointStamped point_base;point_base = buffer.transform(point_laser, "base_link");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());}rate.sleep();ros::spinOnce();}return 0;
}
编译后,执行 rosrun tf2_learning tf2_learning_broadcast
开始广播坐标,此时打开rviz
订阅TF
看到TF树模型,操作与结果如下:
- 输入命令:rviz
- 在启动的 rviz 中设置
Fixed Frame
为base_link
- 点击左下的
Add
按钮,在弹出的窗口中选择TF
组件,即可显示坐标关系。
继续执行命令rosrun tf2_learning tf2_learning_listen
可以看到转换后的坐标,以及所属父坐标系,如下:
其中,ERROR
是由于节点刚起来时,TF数据还未来得及写入缓存,导致base_link
不存在,可以发现第二次调用就没有报错了,实际使用中,可以等待要操作的frame
存在再做转换,如下:
tf2_ros::Buffer buffer;
tf2_ros::TransformListener listener(buffer);
// _frameExists()返回指定frame是否存在于tf树中
if (!buffer._frameExists("base_link"))
{ROS_WARN("base_link frame does not exist.");
}
二、静态坐标变换(Python实现)
在创建的 tf2_learning
包路径下 src
目录的同级,创建一个 scripts
目录,在这里存储脚本(如python脚本),我们创建 tf2_learning_broadcast.py
以实现坐标广播,编辑内容如下:
#! /usr/bin/env pythonimport rospy
import tf
import tf2_ros
from geometry_msgs.msg import TransformStampedif __name__ == "__main__":# 初始化 ROS 节点rospy.init_node("static_frame_broadcast_py")# 创建静态坐标广播器broadcaster = tf2_ros.StaticTransformBroadcaster()# 创建并组织被广播的消息tfs = TransformStamped()# -- 头信息tfs.header.frame_id = "base_link" # 父坐标系tfs.header.stamp = rospy.Time.now()tfs.header.seq = 101# -- 子坐标系tfs.child_frame_id = "laser"# -- 坐标系相对信息# ---- 相对于父坐标系的平移偏移量tfs.transform.translation.x = 0.5tfs.transform.translation.y = 0.0tfs.transform.translation.z = 0.3# ---- 相对于父坐标系的旋转偏移量# ---- 设置欧拉角,并将欧拉角转换成四元数qtn = tf.transformations.quaternion_from_euler(0, 0, 0)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)# spinrospy.spin()
创建 tf2_learning_listen.py
以订阅静态坐标转换关系,并利用该关系将雷达坐标系的点转换到 base_link 坐标系,编辑内容如下:
#! /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("static_frame_listen")# 创建 TF 订阅对象buffer = tf2_ros.Buffer()listener = tf2_ros.TransformListener(buffer)rate = rospy.Rate(1)while not rospy.is_shutdown():# 生成一个坐标点, 模拟雷达检测到的障碍物坐标点(雷达坐标系下的坐标)point_laser = PointStamped()point_laser.header.frame_id = "laser"point_laser.header.stamp = rospy.Time.now()point_laser.point.x = 2.0point_laser.point.y = 2.5point_laser.point.z = 0.3try:# 转换坐标点, 计算障碍物坐标点在 base_link 下的坐标point_base = buffer.transform(point_laser, "base_link")rospy.loginfo("point_base: (%.2f, %.2f, %.2f), frame: %s",point_base.point.x,point_base.point.y,point_base.point.z,point_base.header.frame_id)except Exception as e:rospy.logerr("%s", e)# spinrate.sleep()
相关文章:

ROS TF坐标变换 - 静态坐标变换
目录 一、静态坐标变换(C实现)二、静态坐标变换(Python实现) 如前文所属,ROS通过广播的形式告知各模块的位姿关系,接下来详述这一机制的代码实现。 模块间的位置关系有两种类型,一种是相对固定…...

香橙派5plus从ssd启动Ubuntu
官方接口图 我实际会用到的就几个接口,背面的话就一个M.2固态的位置: 其中WIFI模块的接口应该也可以插2230的固态,不过是pcie2.0的速度,背面的接口则是pcie3.0*4的速度,差距还是挺大的。 开始安装系统 准备工作 一张…...
JWT+Redis 实现接口 Token 校验
1、业务逻辑 有一些接口,需要用户登录以后才能访问,用户没有登录则无法访问。 因此,对于一些限制用户访问的接口,可以在请求头中增加一个校验参数,用于判断接口对应的用户是否登录。 而对于一些不需要登录即可访问的接…...

C语言 linux文件操作(二)
文章目录 一、获取文件长度二、追加写入三、覆盖写入四、文件创建函数creat 一、获取文件长度 通过lseek函数,除了操作定位文件指针,还可以获取到文件大小,注意这里是文件大小,单位是字节。例如在file1文件中事先写入"你好世…...

机器学习分类
1. 监督学习 监督学习指的是人们给机器一大堆标记好的数据,比如: 一大堆照片,标记出哪些是猫的照片,哪些是狗的照片 让机器自己学习归纳出算法或模型 使用该算法或模型判断出其他没有标记的照片是否是猫或狗 上述流程如下图所…...

CSS之元素转换
我想大家在写代码时有一个疑问,块级元素可以转换成其他元素吗? 让我为大家介绍一下元素转换 1.display:block(转换成块元素) display:block可以把我们的行内元素或者行内块元素转换成块元素 接下来让我为大家演示一下: <!DO…...

自激振荡电路笔记 电弧打火机
三极管相关 三极管的形象描述 二极管 简单求解(理想) 优先导通(理想) 恒压降 稳压管(二极管plus) 基础工作模块 理想稳压管的工作特性 晶体管之三极管(“两个二极管的组合” ) 电弧打火机电路 1.闭合开…...
Linux su 命令
Linux su(英文全拼:switch user)命令用于变更为其他使用者的身份,除 root 外,需要键入该使用者的密码。 使用权限:所有使用者。 语法 su [-fmp] [-c command] [-s shell] [--help] [--version] [-] [USE…...

论文阅读: AAAI 2022行人重识别方向论文-PFD_Net
本篇博客用于记录一篇行人重识别方向的论文所提出的优化方法《Pose-Guided Feature Disentangling for Occluded Person Re-identification Based on Transformer》,论文中提出的PDF_Net模型的backbone是采用《TransReID: Transformer-based Object Re-Identificati…...

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

Codeforces Round 900 (Div. 3)(A-F)
比赛链接 : Dashboard - Codeforces Round 900 (Div. 3) - Codeforces A. How Much Does Daytona Cost? 题面 : 思路 : 在序列中只要找到k,就返回true ; 代码 : #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)…...
vue大屏-列表自动滚动vue-seamless-scroll
vue大屏-列表自动滚动vue-seamless-scroll vue-seamless-scroll的官方文档地址:https://chenxuan0000.github.io/vue-seamless-scroll/zh/guide/ 具体效果可到官方文档那里查看。 1、下载依赖 npm install vue-seamless-scroll --save2、使用例子 <template…...

easyx的窗口函数
文章目录 前言一、EasyX的颜色二、EasyX的坐标和设备1,EasyX的坐标2,EasyX的设备 三、窗口函数1,初始化窗口函数2,关闭绘图窗口3,设置窗口背景板颜色4,清空绘图设备 前言 easyx是针对c的图形库,…...
【记录】开始学习网络安全
本文持续更新学习进度 背景 在私企干了5年虚拟化、云原生相关的运维,学到了很多,但不成体系。老板是清华毕业法国留学在德勤干过,最后回国创业的野路子。我工作是为了更好的生活,我挺担心老板因为家庭变故或者炒个原油宝&#x…...

【Java EE初阶三 】线程的状态与安全(下)
3. 线程安全 线程安全:某个代码,不管它是单个线程执行,还是多个线程执行,都不会产生bug,这个情况就成为“线程安全”。 线程不安全:某个代码,它单个线程执行,不会产生bug,…...

MD5算法
一、引言 MD5(Message-Digest Algorithm 5)是一种广泛应用的密码散列算法,由Ronald L. Rivest于1991年提出。MD5算法主要用于对任意长度的消息进行加密,将消息压缩成固定长度的摘要(通常为128位)。在密码学…...

Postman使用
Postman使用 Pre-request Script 参考: Scripting in Postman 可以请求、集合或文件夹中添加Pre-request Script,在请求运行之前执行JavaScript 如设置变量值、参数、Header和正文数据,也可以使用Pre-request Script来调试代码࿰…...

【python 的各种模块】(8) 在python使用matplotlib和wordcloud库来画wordcloud词云图
目录 目标:用python画出,网上流行的wordcloud词云图 1 准备工作 1.1环境准备 1.1.1安装步骤 1.2 资源准备 1.2.1 文本文件内容如下 1.2.2 图片资源 2 代码测试 2.1 第一版代码和效果 2.1.1 代码和效果 2.1.2 一般plt里解决中文乱码问题 2.1…...

MFC随对话框大小改变同时改变控件大小
先看一下效果; 初始; 窗口变大,控件也变大; 二个也可以; 窗口变大,控件变大; 默认生成的对话框没有WM_SIZE消息的处理程序;打开类向导,选中WM_SIZE消息,对CxxxDlg类添加该消息的处理程序;默认生成的函数名是OnSize; 添加了以后代码中会有三处变化; 在对话框类的…...

MK米客方德品牌 SD NAND在对讲机领域的引领作用
SD NAND在对讲机上的应用 SD NAND在对讲机上广泛应用,为其提供了高效可靠的存储解决方案。 这种存储技术不仅能容纳大量语音和数据文件,而且具有高速读取的特点,保障了实时通信的质量。SD NAND还注重安全性,通过数据加密和访问控…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...

网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...