SLAM从入门到精通(tf的使用)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        在ros的机器人学习过程中,有一件事情是肯定少不了的。那就是坐标系的转换。其实这也很容易理解。假设有一个机器人,它有一个3d camera、有一个机械手臂。这个时候有一个需求,需要通过3d camera告知物体的位置,然后通知另外一个机械手臂取走。

        看上去这个任务很简单,但是这中间就涉及到了坐标系的转换。比如说,摄像头识别到物体,这个时候物体是摄像头坐标系下的一个pose,需要通过robot1坐标系、全局坐标系的转换关系,进一步变成世界坐标系下的位置。这样,camera看到的物体pose,就有一个全局pose信息,虽然还是同一个物品。

        那么这个物体的位姿信息怎么通知到机械手臂呢?那么又需要进行反向的坐标系转换。即将物体的全局pose,转成robot2坐标系下的pose,然后进一步转换成机械手臂下的局部pose。这样机械手臂,就可以根据这个局部的pose信息,实现物体的抓取了。

1、tf的作用

        tf的主要作用,其实就是实现坐标系的转换。它的作用,有可能是局部坐标系到世界坐标系,也有可能是世界坐标系到局部坐标系。

2、tf的主要构成

        坐标系的主要沟通有两部分,一部分是xyz,一部分是围绕xyz坐标轴的旋转。其中xyz就是直接用浮点数表示,旋转一般用xyzw的四元数来表示。如果要转成rpy的角度转换,需要用tf提供的公式转换一下。

3、tf的计算方法

        目前计算的方法很多,不过主要还是利用矩阵计算,如果是计算一个点在另外一个坐标系下的坐标,过程中仅仅涉及到旋转的话,一般是

p1 = r * p0

        中间如果涉及到位移的话,一般还会添加一个offset,

p1=r*p0+offset

        这样的公式虽然比较简单,但是转成矩阵不太方便,我们可以通过补齐1来处理,

\begin{bmatrix} p1\\ 1 \end{bmatrix} = \begin{bmatrix} r & offset\\ 0& 1 \end{bmatrix} * \begin{bmatrix} p0\\ 1 \end{bmatrix}

        这样看上去公式完美一些了,可以进一步简化一下,

P1=R*P0

        公式上面似乎回到了原点,但是每一个变量的含义其实都发生了改变。当然,这里的R仅仅表示P0到P1的转变。很多人也许会问了,如果是P1到P0的转变,这个时候应该怎么处理呢。这个时候矩阵的优势就发挥出来了,

R^{-1} * P 1=P0

        所以,如果是需要P1坐标系下面的一个点,此时需要秀姐P0坐标系下的坐标,它所需要的就是求解旋转矩阵R的逆即可。有了单一的坐标转换,那么连续的坐标转换就变得容易了,

P\_final = Rn * ... * R1 * P\_start

        反之也是一样,

R1^{-1} *R2^{-1} * ... * Rn^{-1} * P\_final = P\_start

4、tf中的静态消息和动态消息

        坐标系转换中,有的是静态转换,有的是动态转换。所谓的静态转换,就是那种确定了之后,就一直不变化的。比如传感器和robot之间的固定位置。还有一种就是动态变换,它所指向的就是那种一直在变化的坐标映射关系,比如robot和map之间的位置转换关系。

5、amcl举例说明

        关于amcl算法,大家可以参考这个链接http://wiki.ros.org/amcl。在这中间就包含了大家想学习的tf信息。

        根据输入,它所以依赖的消息有scan雷达、tf坐标系转换、初始位置、map地图四个数据。第1、3、4都比较好理解。而第2个数据就和今天学习的知识相关,包含了lidar到robot、robot到odom的转换等。一开始的时候,我们还在寻找算法里面怎么没有里程计odom的数据,其实答案就在tf里面。

        经过算法求解,这个时候会输出三种数据,分别是amcl位姿、粒子云和tf。第1、2都比较好理解,还有一个tf数据。根据英文解释,它发布的就是map坐标系下odom的里程数据。

6、tf的编程范例

        了解一些tf的编程接口,也对我们理解和认识tf很有帮助。如果是tf的发布,一般会涉及到这样的接口,

tf::TransformBroadcaster
tf::Transform
tf::Quaternion

        相反,如果是一些接收的接口,也会有一些tf的数据结构,

tf::TransformListener
geometry_msgs::PointStamped

        为了说明如何使用这些代码,我们可以通过编写两个程序来说明一下。一个是book_tfpub.cpp,一个是book_tflis.cpp,前者的代码如下所示,

#include <iostream>
#include "ros/ros.h"
#include "tf/transform_broadcaster.h"
#include "geometry_msgs/Point.h"
#include "tf/tf.h"int main(int argc, char* argv[])
{ros::init(argc, argv, "tf_transformpub");ros::NodeHandle nh;static tf::TransformBroadcaster transfpub;tf::Transform base2laser;base2laser.setOrigin(tf::Vector3(1,0,0));tf::Quaternion q;q.setRPY(0,0,0);base2laser.setRotation(q);ros::Rate rate(10);while(nh.ok()){transfpub.sendTransform(tf::StampedTransform(base2laser, ros::Time::now(), "base_link", "laser_link"));rate.sleep();}return 0;
}

        后者的代码如下所示,


#include <iostream>
#include "ros/ros.h"
#include "tf/transform_listener.h"
#include "geometry_msgs/PointStamped.h"using namespace  std;int main(int argc, char* argv[])
{ros::init(argc, argv, "tf_transformlis");ros::NodeHandle nh;tf::TransformListener tflis;geometry_msgs::PointStamped plaser;plaser.header.frame_id = "laser_link";plaser.point.x = 1;plaser.point.y = 0;plaser.point.z = 0;geometry_msgs::PointStamped pbase;ros::Rate rate(10);while(nh.ok()){cout << "start listening" << endl;tflis.waitForTransform("base_link", "laser_link", ros::Time(0), ros::Duration(3));tflis.transformPoint("base_link", plaser, pbase);cout << "pbase is: (" << pbase.point.x << "," << pbase.point.y << "," << pbase.point.z << ")" << endl;rate.sleep();}return 0;
}

        为了让两个代码都能顺利编译通过。有两个地方需要修改下。一个是package.xml,

  <build_depend>tf</build_depend>

        另外一个就是CMakeLists.txt,

## Find catkin and any catkin packages
find_package(catkin REQUIRED COMPONENTS message_generation roscpp rospy std_msgs genmsg tf)add_executable(book_tfpub src/book_tfpub.cpp)
target_link_libraries(book_tfpub ${catkin_LIBRARIES})
add_dependencies(book_tfpub beginner_tutorials_generate_messages_cpp)add_executable(book_tflis src/book_tflis.cpp)
target_link_libraries(book_tflis ${catkin_LIBRARIES})
add_dependencies(book_tflis beginner_tutorials_generate_messages_cpp)

        经过catkin_make编译和rosrun启动,就可以看到这样的打印信息了,

start listening
pbase is: (2,0,0)
start listening
pbase is: (2,0,0)
start listening
pbase is: (2,0,0)
start listening
pbase is: (2,0,0)
start listening
pbase is: (2,0,0)
start listening
pbase is: (2,0,0)

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

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

相关文章

推荐算法——Apriori算法原理

0、前言&#xff1a; 首先名字别读错&#xff1a;an pu ruo ao rui 【拼音发音】Apriori是一种推荐算法推荐系统&#xff1a;从海量数据中&#xff0c;帮助用户进行信息的过滤和选择。主要推荐方法有&#xff1a;基于内容的推荐、协同过滤推荐、基于关联规则的推荐、基于知识的…

Spring整合RabbitMQ——生产者

1.生产者整合步骤 添加依赖坐标&#xff0c;在producer和consumer模块的pom文件中各复制一份。 配置producer的配置文件 配置producer的xml配置文件 编写测试类发送消息

《HelloGitHub》第 90 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 https://github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 …

javascript: Sorting Algorithms

// Sorting Algorithms int JavaScript https://www.geeksforgeeks.org/sorting-algorithms/ /** * file Sort.js * 1. Bubble Sort冒泡排序法 * param arry * param nszie */ function BubbleSort(arry, nszie) {var i, j, temp;var swapped;for (i 0; i < nszie - 1; i)…

设计模式——5. 原型模式

1. 说明 原型模式(Prototype Pattern)是一种创建型设计模式,其核心思想是通过复制(克隆)一个现有对象来创建新的对象,而不是通过实例化类来创建。这意味着在原型模式中,新对象的创建不需要知道具体的类,而是通过复制现有对象的属性和状态来创建。原型模式通常包括一个…

动态规划算法(1)--矩阵连乘和凸多边形剖分

目录 一、动态数组 1、创建动态数组 2、添加元素 3、删除修改元素 4、访问元素 5、返回数组长度 6、for each遍历数组 二、输入多个数字 1、正则表达式 2、has.next()方法 三、矩阵连乘 1、什么是矩阵连乘&#xff1f; 2、动态规划思路 3、手推m和s矩阵 4、完…

2024智慧养老展,北京老博会,北京远程医疗展,适老科技展

CBIAIE智慧养老展-专注于智慧养老发展&#xff0c;以科技提升老年人的晚年幸福&#xff1b; 2024第11届中国&#xff08;北京&#xff09;国际智慧养老产业展览会 The 2024 China (Beijing) international pension Industry Exhibition 时间&#xff1a;2024年04月10日—12日…

MySQL——四、SQL语句(下篇)

MySQL 一、常见的SQL函数1、数学函数2、日期函数3、分组函数(聚合函数)4、流程控制函数 二、where条件查询和order by排序三、分组统计四、多表关联查询1、交叉连接CROSS2、内连接inner3、外连接&#xff1a;outer4、子查询 五、分页查询 一、常见的SQL函数 1、length(str):获…

【生物信息学】计算图网络中节点的中心性指标:聚集系数、介数中心性、度中心性

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 3. IDE 三、实验内容 0. 导入必要的工具 1. 生成邻接矩阵simulate_G: 2. 计算节点的聚集系数 CC(G): 3.计算节点的介数中心性 BC(G) 4. 计算节点的度中心性 DC(G) 5. 综合centrality(G) 6. 代…

第3章-指标体系与数据可视化-3.1.2-Seaborn绘图库

目录 3.1.2 Seaborn绘图库 1. 带核密度估计的直方图 2. 二元分布图 一维正态分布 联合分布

xilinx的原语的使用

xilinx的原语的使用 在学习FPGA实现千兆网时需要GMII转RGMII&#xff0c;这就涉及了原语的使用&#xff0c;特此记录&#xff01; 一、原语 与RGMII接口相关的原语&#xff1a; BUFG:全局时钟网络 BUFIO&#xff1a;只能采集IO的数据&#xff0c;采集IO数据的时候延时是最低的…

【【萌新的Risc-V学习之再看读不懂的流水线设计-10】】

萌新的Risc-V学习之再看读不懂的流水线设计-10 我们将流水线和之前案例中洗衣服的例子进行对照 我们把整个流水线分为5个阶段 也就是做成五级流水线 IF: 取指令ID: 指令译码和读寄存器堆EX: 执行或计算地址MEM: 数据存储器访问WB: 写回 我先在这里表述一下基本的几个指令的用…

四、cadence ic 617 ——添加工艺库文件

1.打开软件 linux界面与window不同,打开软件是由代码实现的。 打开软件时要在设定的工作区域打开,因为软件使用时会返回很多文件,在设定的工作区打开软件,这些文件就会返回到工作区域内。 输入ls回车,可以查询当前所在目录下的文件 输入cd+空格+文件名可以进入该文件 输…

【Java基础】抽象类和接口的使用

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【JavaSE_primary】 本专栏旨在分享学习JavaSE的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录 一、抽象类抽象类概念…

无设计经验也能制作专业国庆微传单

如果你正在计划一个国庆活动&#xff0c;或者想要创建一个微传单来宣传你的品牌或产品&#xff0c;那么你可以尝试使用乔拓云微传单平台。通过这个平台&#xff0c;你可以轻松地创建和发布一个精美的微传单&#xff0c;而且完全免费。 以下是制作国庆微传单H5的步骤&#xff1a…

react的组件

组件 组件是用来实现局部功能的代码和资源的集合&#xff08;html/css/js&#xff09;&#xff0c;用来复用代码。 react中分为函数式组件和类式组件。函数式组件就是一个函数&#xff0c;函数的返回值就是组件的视图内容。类式组件就是通过class关键字创建的类&#xff0c;类…

力扣每日一题(+日常水几题)

121. 买卖股票的最佳时机 - 力扣&#xff08;LeetCode&#xff09;(很水) class Solution { public:int maxProfit(vector<int>& prices) {int ans 0;int pre prices[0];for(auto & x : prices){pre min(pre,x);ans max(ans, x - pre);}return ans;} }; 64…

stl格式-3D三角形

文章目录 什么是stl文件?格式首选stl的语法1.这是一个stl格式的文件:(ASCII码)2.下面先举个例子(难度略微提示)补充:关于\<\<我试了一下:这个法线你随便写好像也没问题\>> 3.来个立方体4.最后再写一个由三个直角形组成的立方体(直棱锥)5.amend 修正(右手定则,法线…

Java 多态

Java 多态 目录 Java 多态 实例 虚方法 多态是同一个行为具有多个不同表现形式或形态的能力。 多态性是对象多种表现形式的体现。 比如我们说"宠物"这个对象&#xff0c;它就有很多不同的表达或实现&#xff0c;比如有小猫、小狗、蜥蜴等等。那么我到宠物店说&q…

决策树剪枝:解决模型过拟合【决策树、机器学习】

如何通过剪枝解决决策树的过拟合问题 决策树是一种强大的机器学习算法&#xff0c;用于解决分类和回归问题。决策树模型通过树状结构的决策规则来进行预测&#xff0c;但在构建决策树时&#xff0c;常常会出现过拟合的问题&#xff0c;即模型在训练数据上表现出色&#xff0c;…