ROS学习笔记12——tf坐标变换

embedded/2024/9/23 17:09:06/

以ros自带的小乌龟作为案例的载体,完成通信方式、坐标变换等的练习,实现程序启动之初 产生两只乌龟,中间的乌龟(turtle1) 和 左下乌龟(turtle2), turtle2 会自动运行至turtle1的位置,并且键盘控制时,只是控制 turtle1 的运动,但是 turtle2 可以跟随 turtle1 运行。

1、创建功能包

创建项目功能包依赖于roscpp、rospy、std_msgs、 tf2、tf2_ros、tf2_geometry_msgs、geometry_msgs、turtlesim

2、服务客户端(生成新的小乌龟turtle2)

#include "ros/ros.h"
#include "turtlesim/Spawn.h"
/*需求:向服务端发送请求,生成一只新乌龟话题:/spawn -> 通过rosservice list看到消息类型:turtlesim/Spawn -> 通过rosservice info /spawn看到消息的具体内容:。。。 -> 通过rossrv info turtlesim/Spawn看到
*/int main(int argc, char *argv[])
{/* code */setlocale(LC_ALL, "");ros::init(argc, argv,"create_new_turtle");ros::NodeHandle nh;//创建服务对象ros::ServiceClient client = nh.serviceClient<turtlesim::Spawn>("/spawn");//组织数据turtlesim::Spawn spawn;spawn.request.name = "turtle2";spawn.request.x = 1.0;spawn.request.y = 2.0;spawn.request.theta = 1.57;client.waitForExistence();//判断服务器状态//发送请求bool flag = client.call(spawn);//flag用来接收响应状态的,响应结果也会被设置进spawn对象if(flag){ROS_INFO("新乌龟 %s 成功生成", spawn.response.name.c_str());}else{ROS_INFO("新乌龟生成失败");}ros::spin();return 0;
}

3、发布方(发布两只小乌龟的坐标信息)

可以订阅乌龟的位姿信息,然后转换成坐标系关系,两只乌龟的实现逻辑是相同的,修改订阅话题和消息类型之后,新建一个cpp重复实现一遍逻辑当然是可以的,但是加大了代码量,并且降低了代码的复用率。这些细微的差异可以通过args设置参数来传入:

  • 该节点需要启动两次
  • 每次启动时都需要传入乌龟节点名称(第一次是 turtle1 第二次是 turtle2)
#include "ros/ros.h"
#include "turtlesim/Pose.h"
#include "tf2_ros/transform_broadcaster.h"
#include "geometry_msgs/TransformStamped.h"
#include "tf2/LinearMath/Quaternion.h"
/*
发布方实现需求:订阅乌龟的位姿信息,转换成相对于窗体的坐标关系,并发布准备:话题:/turtle1/pose、/turtle2/pose消息:turtlesim/Pose流程:1、包含头文件2、设置编码、初始化、NodeHandle等3、创建订阅对象、订阅话题:/turtle1/pose、/turtle2/pose4、**回调函数,处理订阅的消息:把订阅的位姿信息转换成坐标系相对关系,并发布5、spin()
*///声明接收传递参数的变量
std::string turtle_name;void doPose(const turtlesim::Pose::ConstPtr &pose)
{//获取位姿信息,转换成坐标系相对关系,并发布//5.1 创建发布对象static tf2_ros::TransformBroadcaster pub;   //设为static静态变量,每次回调使用同一个pub对象//5.2 组织被发布的数据  geometry_msgs::TransformStamped ts;ts.header.frame_id = "world";ts.header.stamp = ros::Time::now();//**子级坐标系名称动态传入ts.child_frame_id = turtle_name;//坐标系偏移量ts.transform.translation.x = pose->x;ts.transform.translation.y = pose->y;ts.transform.translation.z = 0;tf2::Quaternion qnt;qnt.setRPY(0,0,pose->theta);ts.transform.rotation.w = qnt.getW();ts.transform.rotation.x = qnt.getX();ts.transform.rotation.y = qnt.getY();ts.transform.rotation.z = qnt.getZ();//5.3 发布pub.sendTransform(ts);
}int main(int argc, char *argv[])
{/* code *//*解析 launch 文件通过 args 传入的参数*/if(argc != 4){ROS_INFO("请传入一个参数");return 1;}else{turtle_name = argv[1];}setlocale(LC_ALL,"");// 2、设置编码、初始化、NodeHandle等ros::init(argc,argv,"dynamic_pub_turtle");ros::NodeHandle nh;// **3、创建订阅对象、订阅话题:/turtle1 或者 turtle2 是动态传入的ros::Subscriber sub = nh.subscribe<turtlesim::Pose>(turtle_name + "/pose",100,doPose);// 4、**回调函数,处理订阅的消息:把订阅的位姿信息转换成坐标相对关系,并发布// 5、spin()    ros::spin();return 0;
}

4、订阅方(解析坐标信息并且生成速度信息)

#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"
#include "geometry_msgs/TransformStamped.h"
#include "geometry_msgs/Twist.h"
/*需求1:换算出 turtle1 相对于 turtle2 的关系需求2:计算角速度和线速度并发布
*/
int main(int argc, char *argv[])
{/* code */setlocale(LC_ALL, "");// 2、编码、初始化、NodeHandleros::init(argc, argv,"tfs_sub");ros::NodeHandle nh;// 3、创建订阅对象tf2_ros::Buffer buffer;tf2_ros::TransformListener sub(buffer);//A、创建发布对象ros::Publisher pub = nh.advertise<geometry_msgs::Twist>("/turtle2/cmd_vel",100);// 4、编写解析逻辑(循环,坐标关系和坐标点的转换)//ros::Duration(2).sleep();ros::Rate rate(10);while(ros::ok()){try{// 1、计算 turtle1 和 turtle2 之间的相对关系/* lookupTransform(参数1:B,参数2:A,参数3)## A 相对于 B 的坐标系关系参数1:"目标坐标系 B"参数2:"源坐标系 A"参数3:ros::Time(0) 取间隔最短的两个坐标系帧计算相对关系返回值:geometry_msgs::TransformStamped*/geometry_msgs::TransformStamped tfs = buffer.lookupTransform("turtle2","turtle1",ros::Time(0));ROS_INFO("turtle1 相对于 turtle2 的信息:父级名称:%s,子级名称:%s,偏移量:(%.2f,%.2f,%.2f)",tfs.header.frame_id.c_str(), //turtle2tfs.child_frame_id.c_str(),   //turtle1tfs.transform.translation.x,tfs.transform.translation.y,tfs.transform.translation.z); //B、根据相对位置计算并组织速度消息geometry_msgs::Twist twist;/*linear.x = 系数 * 开放(y^2 + x^2)angular.z = 反正切(对边,临边)*/twist.linear.x = 0.5 * sqrt(pow(tfs.transform.translation.x,2) + pow(tfs.transform.translation.y,2));twist.angular.z = 4 * atan2(tfs.transform.translation.y,tfs.transform.translation.x);//C、发布pub.publish(twist);}catch(const std::exception& e){//std::cerr << e.what() << '\n';ROS_INFO("异常消息:%s", e.what());}rate.sleep();// 5、spinOnce()ros::spinOnce();}return 0;
}

5、运行

使用 launch 文件组织需要运行的节点

<launch><!-- 启动小乌龟GUI --><node pkg="turtlesim" type="turtlesim_node" name="turtle1" output="screen" /><!-- 键盘控制节点 --><node pkg="turtlesim" type="turtle_teleop_key" name="key" output="screen" /><!-- 创建新的小乌龟 --><node pkg="tfs_test" type="create_new_turtle" name="turtle2" output="screen" /><!-- 需要启动两个乌龟相对于世界坐标系的坐标关系的发布节点 --><!-- 实现思路:1、只编写一个节点2、这个节点需要启动两次3、节点启动时,动态传参:第一次:turtle1第二次:turtle2--><node pkg="tfs_test" type="pub_turtle" name="pub_turtle1" args="turtle1" output="screen" /><node pkg="tfs_test" type="pub_turtle" name="pub_turtle2" args="turtle2" output="screen" /><!-- 订阅turtle1与 turtle2 相对于世界坐标系的坐标关系并生成 turtle1 相对于 turtle2 的坐标关系再生成速度消息 --><node pkg="tfs_test" type="control_turtle2" name="control" output="screen" />
</launch>

6、记得配置CMakeLists


http://www.ppmy.cn/embedded/24618.html

相关文章

mac资源库的东西可以删除吗?提升Mac运行速度秘籍 Mac实用软件

很多小伙伴在使用mac电脑处理工作的时候&#xff0c;就会很疑惑&#xff0c;电脑的运行速度怎么越来越慢&#xff0c;就想着通过删除mac资源库的东西&#xff0c;那么mac资源库的东西可以删除吗&#xff1f;删除了会不会造成电脑故障呢&#xff1f; 首先&#xff0c;mac资源库…

WebGL/Cesium 大空间相机抖动 RTE(Relative to Eye)实现原理简析

在浏览器中渲染大尺寸 3D 模型&#xff1a;Speckle 处理空间抖动的方法 WebGL/Cesium 大空间相机抖动 RTE(Relative to Eye)实现原理简析 注: 相机空间和视图空间 概念等效混用 1、实现的关键代码 const material new THREE.RawShaderMaterial({uniforms: {cameraPostion: {…

windows驱动开发-I/O请求(二)

前面我们已经介绍了I/O请求的数据结构&#xff0c;接下来就是I/O请求的处理了。 IRP的处理 驱动例程收到IRP请求的时候&#xff0c;一般会使用一个巨大的switch语句&#xff0c;来处理每一个IOCTL&#xff0c;虽然前面我们简单的讲述了三种不同的I/O缓冲区方式&#xff0c;但…

MySQL 高级 - 第四章 | 配置文件与系统变量

目录 一、配置文件的使用1.1 配置文件格式1.2 启动命令和选项组1.3 特定 MySQL 版本的专用选项1.4 同一个配置文件中多个组的优先级1.5 命令行和配置文件中启动选项的区别 二、系统变量2.1 系统变量简介2.2 查看系统变量2.3 设置系统变量2.3.1 通过启动选项配置2.3.2 服务器程序…

与 Apollo 共创生态:Apollo 七周年大会给带来的震撼

文章目录 一、七年蛰伏&#xff0c;Apollo 迎来“智变”时刻二、Apollo 企业生态计划与开放平台2.1 Apollo X 企业自动驾驶解决方案2.2 Apollo 开放平台携手伙伴共创生态 三、个人感悟 一、七年蛰伏&#xff0c;Apollo 迎来“智变”时刻 让我们把时间倒回到 2013 年&#xff0…

RustGUI学习(iced)之小部件(五):如何使用按钮开关toggler部件?

前言 本专栏是学习Rust的GUI库iced的合集,将介绍iced涉及的各个小部件分别介绍,最后会汇总为一个总的程序。 iced是RustGUI中比较强大的一个,目前处于发展中(即版本可能会改变),本专栏基于版本0.12.1. 概述 这是本专栏的第五篇,主要讲述开关按钮toggler部件的使用,会结…

小长假来临,企业借助巡检系统做好安全巡查工作

节前节后是安全隐患事故多发期&#xff0c;小长假来了&#xff0c;企业面临着员工离岗、生产活动减少等特殊情况&#xff0c;这可能导致一些安全隐患被忽视。因此&#xff0c;借助巡检系统做好全面安全巡查工作显得尤为重要。巡检系统可以帮助企业实现巡检工作的规范化、标准化…

Flink checkpoint 源码分析- Flink Checkpoint 触发流程分析

序言 最近因为工作需要在阅读flink checkpoint处理机制&#xff0c;学习的过程中记录下来&#xff0c;并分享给大家。也算是学习并记录。 目前公司使用的flink版本为1.11。因此以下的分析都是基于1.11版本来的。 在分享前可以简单对flink checkpoint机制做一个大致的了解。 …