【古月居《ros入门21讲》学习笔记】16_tf坐标系广播与监听的编程实现

目录

说明:

1. 实现过程(C++)

创建功能包(C++)

创建tf广播器代码(C++)

创建tf监听器代码(C++)

配置tf监听器与广播器代码编译规则

编译并运行

编译

运行

2. 实现过程(Python)

创建tf广播器代码(Python)

创建tf监听器代码(Python)

运行效果


说明:

1. 本系列学习笔记基于B站:古月居《ROS入门21讲》课程,且使用的Ubuntu与ROS系统版本与课程完全一致;

虚拟机版本Linux系统版本ROS系统版本
VMware WorkStation Pro 16Ubuntu18.04Melodic

2. 课程中的所有示例代码均已跑通,且对Pyhon版本的代码也都做了运行验证,并附带验证过程(错误均已修正);

3. 本节是整个笔记的第16节,对应视频课程的第18节,请自行对应学习;

4. 整个系列笔记基本已经完结,但部分章节仍需润色修改 ,后面会陆续发布,请大家持续关注,      创作不易,感谢支持!


1. 实现过程(C++)

创建功能包(C++)

cd ~/catkin_ws/src
catkin_create_pkg learning_tf roscpp rospy tfturtlesim

image-20230606160521970

创建tf广播器代码(C++)

cd ~/catkin_ws/src/learning_tf/src
touch turtle_tf_broadcaster.cpp

  • 定义tf广播器(TransformBroadcaster);

  • 创建坐标变换值;

  • 发布坐标变换(sendTransform)

/*** 该例程产生tf数据,并计算、发布turtle2的速度指令*/
​
#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <turtlesim/Pose.h>
​
std::string turtle_name;
​
void poseCallback(const turtlesim::PoseConstPtr& msg)
{// 创建tf的广播器static tf::TransformBroadcaster br;
​// 初始化tf数据tf::Transform transform;transform.setOrigin( tf::Vector3(msg->x, msg->y, 0.0) );tf::Quaternion q;q.setRPY(0, 0, msg->theta);transform.setRotation(q);
​// 广播world与海龟坐标系之间的tf数据br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name));
}
​
int main(int argc, char** argv)
{// 初始化ROS节点ros::init(argc, argv, "my_tf_broadcaster");
​// 输入参数作为海龟的名字if (argc != 2){ROS_ERROR("need turtle name as argument"); return -1;}
​turtle_name = argv[1];
​// 订阅海龟的位姿话题ros::NodeHandle node;ros::Subscriber sub = node.subscribe(turtle_name+"/pose", 10, &poseCallback);
​// 循环等待回调函数ros::spin();
​return 0;
};
​

image-20230606161054441

创建tf监听器代码(C++)

cd ~/catkin_ws/src/learning_tf/src
touch turtle_tf_listener.cpp

  • 定义tf监听器(TransformListener);

  • 查找坐标变换(waitForTransform、lookupTransform)

/*** 该例程监听tf数据,并计算、发布turtle2的速度指令*/
​
#include <ros/ros.h>
#include <tf/transform_listener.h>
#include <geometry_msgs/Twist.h>
#include <turtlesim/Spawn.h>
​
int main(int argc, char** argv)
{// 初始化ROS节点ros::init(argc, argv, "my_tf_listener");
​// 创建节点句柄ros::NodeHandle node;
​// 请求产生turtle2ros::service::waitForService("/spawn");ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");turtlesim::Spawn srv;add_turtle.call(srv);
​// 创建发布turtle2速度控制指令的发布者ros::Publisher turtle_vel = node.advertise<geometry_msgs::Twist>("/turtle2/cmd_vel", 10);
​// 创建tf的监听器tf::TransformListener listener;
​ros::Rate rate(10.0);while (node.ok()){// 获取turtle1与turtle2坐标系之间的tf数据tf::StampedTransform transform;try{listener.waitForTransform("/turtle2", "/turtle1", ros::Time(0), ros::Duration(3.0));listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform);}catch (tf::TransformException &ex) {ROS_ERROR("%s",ex.what());ros::Duration(1.0).sleep();continue;}
​// 根据turtle1与turtle2坐标系之间的位置关系,发布turtle2的速度控制指令geometry_msgs::Twist vel_msg;vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(),transform.getOrigin().x());vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) +pow(transform.getOrigin().y(), 2));turtle_vel.publish(vel_msg);
​rate.sleep();}return 0;
};

image-20230606162405983

配置tf监听器与广播器代码编译规则

add_executable(turtle_tf_broadcaster src/turtle_tf_broadcaster.cpp)
target_link_libraries(turtle_tf_broadcaster ${catkin_LIBRARIES})
​
add_executable(turtle_tf_listener src/turtle_tf_listener.cpp)
target_link_libraries(turtle_tf_listener ${catkin_LIBRARIES})

image-20230606165523395

编译并运行

编译
cd ~/catkin_ws
catkin_make
source devel/setup.bash(如已配置 **.bashrc**文件,则此步不需要,配置方法在publisher的章节里)

image-20230606173417459

运行
roscore
rosrun turtlesim turtlesim_node

下面我们传入参数 第1个参数:因为在turtle_tf_broadcaster.cpp定义节点时使用了"my_tf_broadcaster"的名字,所以后面使用__name:=传入新的名字代 替"my_tf_broadcaster",以此来避免名字重复(ROS中的节点名字不能重复),如此就能重复跑这个程序了。

第2个参数:turtle名称 turtle1 和 turtle2。

rosrun learning_tf turtle_tf_broadcaster __name:=turtle1_tf_broadcaster /turtle1
rosrun learning_tf turtle_tf_broadcaster __name:=turtle2_tf_broadcaster /turtle2
rosrun learning_tf turtle_tf_listener

上面完成后,会有一只海龟在中心点,另一只海龟在左下方,并且左下方的海龟会跑向中间的那只海龟

image-20230607105934024

打开键盘控制节点,通过键盘控制中心点那只海龟,另只海龟也会自动的跟随前面的那只海龟同步去运动

rosrun turtlesim turtle_teleop_key

image-20230607110507433

2. 实现过程(Python)

创建tf广播器代码(Python)

cd ~/catkin_ws/src/learning_tf
mkdir scripts
cd scripts
touch turtle_tf_broadcaster.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将请求/show_person服务,服务数据类型learning_service::Person
​
import roslib
roslib.load_manifest('learning_tf')
import rospy
​
import tf
import turtlesim.msg
​
def handle_turtle_pose(msg, turtlename):br = tf.TransformBroadcaster()br.sendTransform((msg.x, msg.y, 0),tf.transformations.quaternion_from_euler(0, 0, msg.theta),rospy.Time.now(),turtlename,"world")
​
if __name__ == '__main__':rospy.init_node('turtle_tf_broadcaster')turtlename = rospy.get_param('~turtle')rospy.Subscriber('/%s/pose' % turtlename,turtlesim.msg.Pose,handle_turtle_pose,turtlename)rospy.spin()
​
​

image-20230607111815061

创建tf监听器代码(Python)

cd ~/catkin_ws/src/learning_tf/scripts
touch turtle_tf_listener.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将请求/show_person服务,服务数据类型learning_service::Person
​
import roslib
roslib.load_manifest('learning_tf')
import rospy
import math
import tf
import geometry_msgs.msg
import turtlesim.srv
​
if __name__ == '__main__':rospy.init_node('turtle_tf_listener')
​listener = tf.TransformListener()
​rospy.wait_for_service('spawn')spawner = rospy.ServiceProxy('spawn', turtlesim.srv.Spawn)spawner(4, 2, 0, 'turtle2')
​turtle_vel = rospy.Publisher('turtle2/cmd_vel', geometry_msgs.msg.Twist,queue_size=1)
​rate = rospy.Rate(10.0)while not rospy.is_shutdown():try:(trans,rot) = listener.lookupTransform('/turtle2', '/turtle1', rospy.Time(0))except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):continue
​angular = 4 * math.atan2(trans[1], trans[0])linear = 0.5 * math.sqrt(trans[0] ** 2 + trans[1] ** 2)cmd = geometry_msgs.msg.Twist()cmd.linear.x = linearcmd.angular.z = angularturtle_vel.publish(cmd)
​rate.sleep()
​
​

image-20230607112048252

注意:给turtle_tf_broadcaster.py 和 turtle_tf_listener.py文件赋予作为程序文件执行的权限,

点击turtle_tf_broadcaster.py文件,右键,属性,权限,勾选(允许作为程序文件执行),

turtle_tf_listener.py文件操作同上,在ROS-Melodic版本中,python文件不需要编译,直接运行即可。

image-20230607112635115

运行效果

roscore
rosrun turtlesim turtlesim_node
​
rosrun learning_tf turtle_tf_broadcaster.py __name:=turtle1_tf_broadcaster _turtle:=turtle1
rosrun learning_tf turtle_tf_broadcaster.py __name:=turtle2_tf_broadcaster _turtle:=turtle2
rosrun learning_tf turtle_tf_listener.py
​
rosrun turtlesim turtle_teleop_key

image-20230607113817681

image-20230607113919029


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

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

相关文章

API网关

API网关的作用 下图显示了详细信息。 步骤 1 - 客户端向 API 网关发送 HTTP 请求。 步骤 2 - API 网关解析并验证 HTTP 请求中的属性。 步骤 3 - API 网关执行允许列表/拒绝列表检查。 步骤 4 - API 网关与身份提供商对话以进行身份​​验证和授权。 步骤 5 - 将速率限制规…

ChatGPT到底是如何运作?

自从2022年11月30日发布以来&#xff0c;ChatGPT一直占据着科技届的头条位置&#xff0c;随着苹果的创新能力下降&#xff0c;ChatGPT不断给大家带来震撼&#xff0c;2023年11月7日&#xff0c;首届OpenAI开发者大会在洛杉矶举行&#xff0c;业界普遍认为&#xff0c;OpenAI的开…

Java程序连接 nacos集群

我们在bootstrap.yml文件里可以直接连一个nacos集群的. 架构如下 没错,我们程序直连的是通过Nginx的,利用nginx的反向代理来做到连接nacos集群. 我们先把nginx的配置贴上来 upstream cluster{server 127.0.0.1:8848;server 127.0.0.1:8849;server 127.0.0.1:8850; }server{l…

ACM程序设计课内实验(1)数学问题

1.The Hardest Problem Ever Description Julius Caesar生活在一个危险而又充斥着阴谋的时代。Caesar面对的最难的情况关系着他的存亡。为了让自己生存&#xff0c;他决心去创造第一种加密方法之一。这个加密方法听起来是这样的令人难以置信&#xff0c;没有一个人可以指出它&a…

基于微信小程序的爱心捐赠平台的设计与实现-计算机毕业设计源码64923

摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c; 小程序的爱心捐赠平台被用户普遍使用&#xff0c;为方便…

WebUI自动化学习(Selenium+Python+Pytest框架)003

1.元素操作 在成功定位到元素之后&#xff0c;我们需要对元素进行一些操作动作。常用的元素操作动作有&#xff1a; &#xff08;1&#xff09;send_keys() 键盘动作&#xff1a;向浏览器发送一个内容&#xff0c;通常用于输入框输入内容或向浏览器发送快捷键 &#xff08;2…

[DASCTF 2023 0X401七月暑期挑战赛] web刷题记录

文章目录 EzFlask方法一 python原型链污染方法二 flask框架静态文件方法三 pin码计算 MyPicDisk方法一 字符串拼接执行命令方法二 phar反序列化 ez_cms EzFlask 考点&#xff1a;python原型链污染、flask框架理解、pin码计算 源码如下 import uuidfrom flask import Flask, re…

【EasyExcel实践】导出多个sheet到多个excel文件,并压缩到一个zip文件

文章目录 前言正文一、项目依赖二、封装表格实体和Sheet实体2.1 表格实体2.2 Sheet实体 三、核心实现3.1 核心实现之导出为输出流3.2 web导出3.3 导出为字节数组 四、调试4.1 构建调试用的实体类4.2 控制器调用4.3 测试结果 五、注册大数转换器&#xff0c;长度大于15时&#x…

游戏开发原画的设计方法

游戏原画设计是游戏开发中至关重要的一环&#xff0c;因为它直接影响到游戏的视觉吸引力和用户体验。以下是一些常见的游戏原画设计方法&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 理解游戏概念&…

学生护眼灯怎么选?2023备考护眼台灯推荐

近期&#xff0c;许多“护眼台灯是否是智商税”的帖子频繁出现&#xff0c;引起了许多群众的关注&#xff0c;作为一名护眼台灯资深使用者&#xff0c;在这里声明一下&#xff0c;护眼台灯绝对不是智商税。护眼台灯是通过调节光线亮度和色温&#xff0c;降低蓝光辐射&#xff0…

【黑马甄选离线数仓day07_常见优化手段及核销主题域开发】

1.常见优化手段 1.1 分桶表基本介绍 分桶表: 分文件的, 在创建表的时候, 指定分桶字段, 并设置分多少个桶, 在添加数据的时候, hive会根据设置分桶字段, 将数据划分到N个桶(文件)中, 默认情况采用HASH分桶方案 , 分多少个桶, 取决于建表的时候, 设置分桶数量, 分了多少个桶最终…

一维数组,逆序存放并输出【样例输入】20 30 10 50 40 90 80 70【样例输出】70 80 90 40 50 10 30 20

一维数组&#xff0c;逆序存放并输出 【样例输入】 20 30 10 50 40 90 80 70 【样例输出】 70 80 90 40 50 10 30 20 以下是使用C语言编写的将一维数组逆序存放并输出的示例代码&#xff1a; #include <stdio.h>void reverseArray(int arr[], int size) {int start…