ROS python实现乌龟跟随

        产生两只乌龟,中间的乌龟(A) 和 左下乌龟(B), B 会自动运行至A的位置,并且键盘控制时,只是控制 A 的运动,但是 B 可以跟随 A 运行

        乌龟跟随实现的核心,是乌龟A和B都要发布相对世界坐标系的坐标信息,然后,订阅到该信息需要转换获取A相对于B坐标系的信息,最后,再生成速度信息,并控制B运动。

Python实现

1.创建功能包

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

2.服务客户端(生成乌龟)
#! /usr/bin/env python
import rospy
from turtlesim.srv import Spawn,SpawnRequest,SpawnResponse
"""需求:向服务器发送请求生成一只乌龟话题:/spawn消息:turtlesim/Spawn1、导包2、初始化ROS节点3、创建服务的客户端对象4、组织数据并发送请求5、处理响应结果
"""if __name__=="__main__":#2、初始化ROS节点rospy.init_node("service_call_p")#3、创建服务的客户端对象client=rospy.ServiceProxy("/spawn",Spawn)#4、组织数据并发送请求request = SpawnRequest()request.x=4.5request.y=2.0request.theta=-3request.name="turtle2"#4-2 判断服务器状态并发送client.wait_for_service()#客户端等待服务,若服务端没有启动则挂起try:response=client.call(request)#5、处理响应结果rospy.loginfo("生成乌龟的名字叫:%s",response.name)except Exception as e:rospy.logerr("请求处理异常")

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

#! /usr/bin/env python
import rospy
import tf.transformations
from turtlesim.msg import Pose
import tf2_ros
from geometry_msgs.msg import TransformStamped
import tf
import sys
"""发布方:订阅乌龟的位姿信息,转换处呢个坐标系的相对关系,再发布准备:话题:/turtle1/pose类型:/turtlesim/Pose流程:1、导包2、初始化ROS节点3、创建订阅对象4、回调函数处理订阅到的消息(核心)5、spin()
"""#接受乌龟名称的变量
turtle_name = ""def doPose(pose): #参数为订阅到的消息 pose#创建发布坐标系相对关系的对象pub=tf2_ros.TransformBroadcaster()#将pose转换成坐标系相对关系消息ts=TransformStamped()ts.header.frame_id="world"  #被参考的坐标系ts.header.stamp=rospy.Time.now()#修改2--------------------------------------------------------------ts.child_frame_id=turtle_name#子级坐标系相对于父级坐标系的偏移量ts.transform.translation.x=pose.xts.transform.translation.y=pose.yts.transform.translation.z=0#四元数#从欧拉角转换四元数"""乌龟是2D的,不存在X上的翻滚Y上偏航,只有Z上的偏航0 0 pose.thera"""qtn=tf.transformations.quaternion_from_euler(0,0,pose.theta)ts.transform.rotation.x=qtn[0]ts.transform.rotation.y=qtn[1]ts.transform.rotation.z=qtn[2]ts.transform.rotation.w=qtn[3]#发布pub.sendTransform(ts)if __name__=="__main__":# 2、初始化ROS节点rospy.init_node("dynamic_pub_p")# 3、创建订阅对象#解析传入的参数(现在传入几个参数?文件全路径+传入的参数+自己定义的节点名称+日志文件路径)if len(sys.argv)!=4:rospy.loginfo("参数个数不对")sys.exit(1)else:turtle_name=sys.argv[1]#修改1sub=rospy.Subscriber(turtle_name+"/pose",Pose,doPose,queue_size=100)# 4、回调函数处理订阅到的消息(核心)# 5、spin()rospy.spin()

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

#! /usr/bin/env python
import rospy
import tf2_ros
import tf2_geometry_msgs
# 不要使用 geometry_msgs,需要使用 tf2 内置的消息类型
from tf2_geometry_msgs import PointStamped
# from geometry_msgs.msg import PointStamped
from geometry_msgs.msg import TransformStamped,Twist   
import math                   if __name__=="__main__":# 2、初始化rospy.init_node("static_sub_p")# 3、创建订阅对象#3-1 创建缓存对象buffer=tf2_ros.Buffer()#3-2 创建订阅对象(将缓存传入)sub=tf2_ros.TransformListener(buffer)# 创建速度消息发布对象pub=rospy.Publisher("/turtle2/cmd_vel",Twist,queue_size=100)# 5、转换逻辑实现,调用tf封装的算法rate=rospy.Rate(10)while not rospy.is_shutdown():try:#--------------------计算相son1相对于son2的坐标关系"""参数1:目标坐标系参数2:源坐标系参数3:rospy.Time(0)----------取时间间隔最近的两个坐标系帧(son1相对world与son2相对world)来计算结果返回值:son1与son2的坐标关系"""ts=buffer.lookup_transform("turtle2","turtle1",rospy.Time(0))rospy.loginfo("父级坐标系:%s,子级坐标系:%s,偏移量(%.2f,%.2f,%.2f)",ts.header.frame_id,ts.child_frame_id,ts.transform.translation.x,ts.transform.translation.y,ts.transform.translation.z)#组织Twist消息twist=Twist()#线速度=系数*坐标系原点的间距=系数*(x^2 +y^2 )再开方#角速度=系数*夹角          =系数*atan2(y,x)twist.linear.x=0.5*math.sqrt(math.pow(ts.transform.translation.x,2) + math.pow(ts.transform.translation.y,2))twist.angular.z=4*math.atan2(ts.transform.translation.y,ts.transform.translation.x)#发布消息pub.publish(twist)except Exception as e:rospy.logwarn("错误提示:%s",e)# 7、spain()  |spinOnce()rate.sleep()

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

<launch>
<!--流程详解:1.准备工作:启动乌龟的GUI节点和键盘控制节点2、需要调用服务器生成一只新的乌龟3、发布两只乌龟的坐标信息4、订阅坐标信息,并转换成乌龟A相对于乌龟B 的坐标信息,最后再生成控制乌龟的速度信息
--><!--1.准备工作:启动乌龟的GUI节点和键盘控制节点--><!--乌龟GUI--><node pkg="turtlesim" type="turtlesim_node" name="turtle1" output="screen" /><!--键盘控制--><node pkg="turtlesim" type="turtle_teleop_key" name="key" output="screen" />   <!--2、需要调用服务器生成一只新的乌龟--><node pkg="tf04_test" type="test01_new_turtle_p.py" name="turtle2" output="screen" /><!--3、发布两只乌龟的坐标信息A、复用之前的乌龟坐标发布功能B、调用节点时,以参数的方式传递乌龟名称,解析参数置换:订阅的话题消息和子级坐标系的名称--><node pkg="tf04_test" type="test02_pub_turtle_p.py" name="pub1" args="turtle1" output="screen" /><node pkg="tf04_test" type="test02_pub_turtle_p.py" name="pub2" args="turtle2" output="screen" /><!--4、订阅坐标信息,并转换成乌龟A相对于乌龟B 的坐标信息,最后再生成控制乌龟的速度信息--><node pkg="tf04_test" type="test03_control_turtle2_p.py" name="control" output="screen" /></launch>

 先修改py文件的权限并在CMakeList中加相应的配置

运行launch文件

参考链接:

[1]207坐标变换实操Python01_生成乌龟-ROS常用组件_哔哩哔哩_bilibili

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

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

相关文章

vue3组件 描点定位以及监听滚动切换对应activeTab

描点定位以及监听滚动切换对应activeTab 基本逻辑 init 初始化 获取滚动区域内所有非文本子节点offsetTopArr 存储所有子节点的高度scroll 监听滚动的距离&#xff0c;找到还在可视区的元素高度 <template><div class"tab-list"><div v-for"i…

力扣HOT100 - 994. 腐烂的橘子

解题思路&#xff1a; 因为要记录轮数&#xff08;分钟数&#xff09;&#xff0c;所以不能一口气遍历到底&#xff0c;所以不能用深搜&#xff08;bfs&#xff09;&#xff0c;而要用广搜&#xff08;bfs&#xff0c;层序遍历&#xff09;。 先记录下新鲜橘子数&#xff0c;…

理解控制反转

好久之前写的学习笔记&#xff0c;一直落在草稿箱里今天才发现&#xff0c;既然写了就补发出来吧~ 当需要实现不同操作时&#xff0c;用户和程序员都无需修改&#xff0c;只需要修改xml配置即可。 代码体现&#xff1a; 不同接口的实现类&#xff1a; xml具体配置 通过set注入…

GO语言写Prometheus自定义node-exporter的Docker容器测试

1. 安装docker-compose 执行以下命令&#xff0c;安装docker-compose到CentOS7.9环境中&#xff1a; # 下载二进制文件 sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.7/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/d…

后端面试---分布式微服务

分布式&微服务 分布式1、什么时候用到分布式开发三级目录 微服务 分布式 1、什么时候用到分布式开发 三级目录 微服务 1、谈谈你对微服务的理解&#xff0c;什么时候用微服务 2、若A服务请求B服务B1接口&#xff0c;B1接口又请求A服务的A2接口&#xff0c;会不会有问题…

Qt : 在QTreeWidget中添加自定义右键菜单

一、引言 如图&#xff0c;我们需要在一个QTreeWidget 控件中添加了自定义右键菜单。 二、思路 如何做到的呢&#xff0c;很简单。浅浅记录和分享一下。 继承QTreeWidget&#xff0c;定义一个子类CustomTreeWidget &#xff0c;在重写contextMenuEvent 事件即可。 三、代…

单链表(详解)

目录 一.链表的介绍二.链表的各种方法单链表的结构初始化链表为链表开辟新节点打印链表尾插头插尾删头删查找指定位置之前插入指定位置之后插入删除(pos)节点删除节点&#xff08;pos&#xff09;之后的节点链表的销毁&#xff08;节点被一个一个地销毁&#xff09; 一.链表的介…

linux调试-访问物理地址

1. devmem 方式 rootraspberrypi:/home/niyu# busybox devmem 0x7e215000 8 0xa rootraspberrypi:/home/niyu# busybox devmem 0x7e215000 8 0x0A rootraspberrypi:/home/niyu# busybox devmem 0x7e215000 8 0xb rootraspberrypi:/home/niyu# busybox devmem 0x7e21500…

如何制作个性又美观的二维码?自定义Logo、样式,还能一键复用

草料二维码提供基础的二维码美化设置&#xff0c;包含Logo、颜色、码点码眼、容错、添加文字等设置。 还提供150标签样式&#xff0c;标签样式中所有内容&#xff0c;包括LOGO、背景、字段数量等&#xff0c;均可修改。 同时&#xff0c;支持将样式保存到账号下&#xff0c;方…

磨损对输送带安全的影响

磨损对输送带安全的影响 在工业生产中&#xff0c;输送带作为重要的物流传输设备&#xff0c;广泛应用于煤炭、化工、冶金、电力、建材等多个行业。然而&#xff0c;输送带在使用过程中不可避免地会出现磨损现象&#xff0c;这不仅会影响其使用寿命&#xff0c;还可能对生产安…

vue-router学习3:路由传参方式

路由传参的方式主要有两种&#xff1a;query传参和params传参。 1. Query 传参 首先&#xff0c;在路由配置文件中&#xff08;通常是 router/index.ts&#xff09;&#xff0c;定义你的路由&#xff1a; import { createRouter, createWebHistory } from vue-router; imp…

从递归角度串联二叉树-图论-动态规划

一、深度理解二叉树的前中后序遍历 二叉树遍历框架如下&#xff1a; void traverse(TreeNode* root) {if (root nullptr) {return;}// 前序位置traverse(root->left);// 中序位置traverse(root->right);// 后序位置 }先不管所谓前中后序&#xff0c;单看 traverse 函数…

常见的工业路由器访问问题

A&#xff1a;工业路由器已经设置了pptp怎么访问路由下面的电脑 1. 确认PPTP VPN设置&#xff1a;首先&#xff0c;确保PPTP VPN服务器在工业路由器上已正确设置&#xff0c;并且处于活动状态。这包括确保VPN服务器的IP地址、端口、用户名和密码等设置正确无误。 2. 连接到VP…

硬件24、嘉立创EDA丝印的优化和调整

1、调整全部丝印的属性 先选中一个丝印&#xff0c;然后右键点击它&#xff0c;选择查找&#xff0c;然后选择查找全部 选择查找全部这个时候可以设置所有丝印在元件的位置了&#xff0c;布局-》属性位置&#xff0c;位号&#xff0c;属性位置设置为上边&#xff0c;这时丝印就…

Linux红帽(RHCE)认证学习笔记 - (2)用户组和用户的管理

二、用户组和用户密码和用户组密码管理 ⽤户的添加(useradd) ⽤户的删除(userdel) ⽤户的修改(usermod) ⽤户的查看(查看/etc/passwd) id用户信息都是存放在 /etc/passwd 用户密码都是存放在 /etc/shadow 用户组信息都是存放在 /etc/group 用户组密码都是存放在 /etc/…

五、yolov8 tensorRT c++部署及接口封装(保姆级教程附源码)

采用 CTensorRT来部署深度学习模型有以下几个优点&#xff1a; 高性能推理&#xff1a;TensorRT是一个高性能的深度学习推理&#xff08;Inference&#xff09;优化器&#xff0c;专门为NVIDIA GPU硬件平台设计&#xff0c;能够提供低延迟、高吞吐量的模型推理性能。这意味着在…

深度学习pytorch实战4---猴逗病识别·

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营](https://mp.weixin.qq.com/s/0dvHCaOoFnW8SCp3JpzKxg) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊](https://mtyjkh.blog.csdn.net/)** 引言 1.复习上周并反思 K同学针对大家近…

STM32 float浮点数转换成四个字节

float浮点数转换成四个字节 在C或C中&#xff0c;联合体&#xff08;union&#xff09;是一种特殊的数据结构&#xff0c;它允许在相同的内存位置存储不同的数据类型。联合体中的所有成员共享同一块内存区域&#xff0c;这意味着同一时间内&#xff0c;联合体只能保存其中一个…

python爬虫 - 爬取html中的script数据(36kr.com新闻信息)

文章目录 1. 分析页面内容数据格式2. 使用re.findall方法&#xff0c;爬取新闻3. 使用re.search 方法&#xff0c;爬取新闻 1. 分析页面内容数据格式 打开 https://36kr.com/ 按F12&#xff08;或 在网页上右键 --> 检查&#xff08;Inspect&#xff09;&#xff09; 找…

c++初阶——类和对象(中)

大家好&#xff0c;我是小锋&#xff0c;我们今天继续来学习类和对象。 类的6个默认成员函数 我们想一想如果一个类什么都没有那它就是一个空类&#xff0c;但是空类真的什么都没有吗&#xff1f; 其实并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以…