ROS——多个海龟追踪一个海龟实验

news2024/9/21 2:44:07

目标

  • 通过键盘控制一个海龟(领航龟)的移动,其余生成的海龟通过监听实现追踪
  • 定期获取领航龟和其余龟的坐标信息,通过广播告知其余龟,进行相应移动
  • 其余龟负责监听

疑惑点(已解决)

int main(int argc, char** argv) 是 C 和 C++ 程序中主函数 (main) 的常见定义形式。这个函数是程序的入口点,操作系统在启动程序时首先调用 main 函数。

参数解释:

int argc:代表 “argument count”,是一个整型变量,表示传递给程序的命令行参数的数量(包括程序名称本身)。例如,如果你的程序名为 myprog,并且在命令行下以 myprog arg1 arg2 的方式运行,那么 argc 将为 3(程序名 myprog 计为第一个参数)。
char** argv:代表 “argument vector”,是一个字符指针数组的指针,每个元素都是指向一个字符串的指针。这个数组包含了所有通过命令行传递给程序的参数。argv[0] 总是指向程序的名称,而 argv[1]、argv[2] 等分别指向后续的各个参数。每个参数都是一个以空字符 ‘\0’ 结尾的字符串。
main 函数返回类型为 int,通常用来表示程序的退出状态。返回值为 0 表示程序正常结束,非零值则表示有错误发生,具体的数值可以根据需要定义,但通常的约定是返回负数或非零正数表示异常终止。

生成海龟

在这里插入图片描述

生成执行文件及相关依赖

add_executable(fllow_broadcaster src/turtle_broadcaster.cpp)
target_link_libraries(fllow_broadcaster ${catkin_LIBRARIES})

add_executable(fllow_listener src/turtle_listener.cpp)
target_link_libraries(fllow_listener ${catkin_LIBRARIES})

add_executable(create_turtle src/spawn_turtle.cpp)
target_link_libraries(create_turtle ${catkin_LIBRARIES})

xml配置

<launch>
  <node pkg="turtlesim" type="turtlesim_node" name="sim" />
  <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen" />
  
  <!-- 生成多个海龟,这里的type指的是可执行文件的自定义名字-->
  <node pkg="Fllowing_test" type="create_turtle" name="c_turtle" args="a b c d e f g" /> 
  
  <!-- 构建多个海龟广播-->
  <node pkg="Fllowing_test" type="fllow_broadcaster" args="turtle1" name="turtle1_broadcaster" /> 
  <node pkg="Fllowing_test" type="fllow_broadcaster" args="a" name="turtle2_broadcaster" />
  <node pkg="Fllowing_test" type="fllow_broadcaster" args="b" name="turtle3_broadcaster" />
  <node pkg="Fllowing_test" type="fllow_broadcaster" args="c" name="turtle4_broadcaster" />
  <node pkg="Fllowing_test" type="fllow_broadcaster" args="d" name="turtle5_broadcaster" />
  <node pkg="Fllowing_test" type="fllow_broadcaster" args="e" name="turtle6_broadcaster" />
  <node pkg="Fllowing_test" type="fllow_broadcaster" args="f" name="turtle7_broadcaster" /> 
  <node pkg="Fllowing_test" type="fllow_broadcaster" args="g" name="turtle8_broadcaster" /> 
    
  <!-- 设置多个海龟之间的监听关系 -->
  <node pkg="Fllowing_test" type="fllow_listener" args="turtle1 a" name="turtle1_tf_listener" />
  <node pkg="Fllowing_test" type="fllow_listener" args="a b" name="turtle2_tf_listener" />
  <node pkg="Fllowing_test" type="fllow_listener" args="b c" name="turtle3_tf_listener" />
  <node pkg="Fllowing_test" type="fllow_listener" args="c d" name="turtle4_tf_listener" />
  <node pkg="Fllowing_test" type="fllow_listener" args="d e" name="turtle5_tf_listener" />
  <node pkg="Fllowing_test" type="fllow_listener" args="e f" name="turtle6_tf_listener" />
  <node pkg="Fllowing_test" type="fllow_listener" args="f g" name="turtle7_tf_listener" />
</launch>

spawn_turtle.cpp

  • 测试指令:rosrun Fllowing_test create_turtle a b c d e (后续字母 + i 是自定义海龟名字)
#include <ros/ros.h>
#include <turtlesim/Spawn.h>

int main(int argc ,char **argv){
  int i;
  if(argc < 2) {
    ROS_ERROR("Turtle's name can't be empty");
    return -1;
  }
  
  ros::init(argc,argv,"Create_turtle");
  ros::NodeHandle node;
  
  ros::service::waitForService("spawn");
  ros::ServiceClient create_turtle_client = node.serviceClient<turtlesim::Spawn>("spawn");
  turtlesim::Spawn srv;  //用于配置海龟信息
  
  for(i = 1;i < argc;++i){
      srv.request.x = i;
      srv.request.y = i;
      srv.request.theta = 0;
      srv.request.name = *(argv+i);
      create_turtle_client.call(srv);     //发送请求生成海龟的服务
  }
  
  return 0;
}

turtle_broadcaster

// 例程产生 tf 数据,并计算、发布 turtle2的速度指令
#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <turtlesim/Pose.h>

std::string turtle_name;

//pose回调函数
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);   //当前海龟的RPY旋转状态
    transform.setRotation(q);
    
    //广播world与海龟坐标系之间的tf数据
    br.sendTransform(tf::StampedTransform(transform,ros::Time::now(),"world",turtle_name));
}

int main(int argc,char** argv){
  
  ros::init(argc,argv,"turtle_broadcaster");
  
  //输入参数作为海龟的名字
  if(argc < 2){
     ROS_ERROR("need turtle name as argument!");
     return -1;
  }
  
  turtle_name = argv[1];   //argv[0]是程序文件名,argv[1]以及后续才是参数列表
  
  //订阅海龟位置
  ros::NodeHandle node;
  ros::Subscriber sub = node.subscribe(turtle_name+"/pose",10,&poseCallback);
  
  // 循环等待回调函数
  ros::spin();
  
  return 0;
}

turtle_listener.cpp

#include <ros/ros.h>
#include <tf/transform_listener.h>
#include <turtlesim/Spawn.h>
#include <geometry_msgs/Twist.h>
#include <string>
using namespace std;

int main(int argc,char **argv){
  
  //拼接海龟驱动指令
  string driver_cmd("/");
  driver_cmd.append(argv[2]);
  driver_cmd.append("/cmd_vel");
  
   if(argc < 3){
     ROS_ERROR("need turtle name as argument!");
     return -1;
  }
  
  ros::init(argc,argv,"turtle_listener");
  
  ros::NodeHandle node;
  
  //请求产生海龟对象
  ros::service::waitForService("/spawn");
  ros::ServiceClient turtle = node.serviceClient<turtlesim::Spawn>("/spawn");
  turtlesim::Spawn srv_add_turtle;
  turtle.call(srv_add_turtle);

  
  //创建发布速度控制指令的发布者,控制海龟移动的
  ros::Publisher turtle_vel = node.advertise<geometry_msgs::Twist>(driver_cmd,10);
  
  //创建tf的监听器
  tf::TransformListener listener;
  
  ros::Rate rate(10.0);
  while(node.ok()){
     //获取坐标系之间的tf数据
     tf::StampedTransform transform;
     
     try{
       // 判断坐标系中是否存在相应海龟节点,持续三秒,向广播者发送位置信息请求
       listener.waitForTransform(argv[2],argv[1],ros::Time(0),ros::Duration(3.0));
       
       // 获取实时位置,将四元数存到transform变量中
       listener.lookupTransform(argv[2],argv[1],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;
}

实验结果呈现

在这里插入图片描述

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

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

相关文章

【网络安全】实验四(网络扫描工具的使用)

一、本次实验的实验目的 &#xff08;1&#xff09;掌握使用端口扫描器的技术&#xff0c;了解端口扫描器的原理 &#xff08;2&#xff09;会用Wireshark捕获数据包&#xff0c;并对捕获的数据包进行简单的分析 二、搭配环境 打开两台虚拟机&#xff0c;并参照下图&#xff…

k8s+docker集群整合搭建(完整版)

一、Kubernetes系列之介绍篇 1、背景介绍 云计算飞速发展 IaaS PaaS SaaS Docker技术突飞猛进 一次构建&#xff0c;到处运行 容器的快速轻量 完整的生态环境 2、什么是kubernetes 首先&#xff0c;他是一个全新的基于容器技术的分布式架构领先方案。Kubernetes(k8s)是Goog…

磐维2.0数据库日常维护

磐维数据库简介 “中国移动磐维数据库”&#xff08;ChinaMobileDB&#xff09;&#xff0c;简称“磐维数据库”&#xff08;PanWeiDB&#xff09;。是中国移动信息技术中心首个基于中国本土开源数据库打造的面向ICT基础设施的自研数据库产品。 其产品内核能力基于华为 OpenG…

001uboot体验

1.uboot的作用&#xff1a; 上电->uboot启动->关闭看门狗、初始化时钟、sdram、uart等外设->把内核文件从flash读取到SDRAM->引导内核启动->挂载根文件系统->启动根文件系统的应用程序 2.uboot编译 uboot是一个通用的裸机程序&#xff0c;为了适应各种芯片&…

注意力机制 attention Transformer 笔记

动手学深度学习 这里写自定义目录标题 注意力加性注意力缩放点积注意力多头注意力自注意力自注意力缩放点积注意力&#xff1a;案例Transformer 注意力 注意力汇聚的输出为值的加权和 查询的长度为q&#xff0c;键的长度为k&#xff0c;值的长度为v。 q ∈ 1 q , k ∈ 1 k …

现场Live震撼!OmAgent框架强势开源!行业应用已全面开花

第一个提出自动驾驶并进行研发的公司是Google&#xff0c;巧的是&#xff0c;它发布的Transformer模型也为今天的大模型发展奠定了基础。 自动驾驶已经完成从概念到现实的华丽转变&#xff0c;彻底重塑了传统驾车方式&#xff0c;而大模型行业正在经历的&#xff0c;恰如自动驾…

Mac安装AndroidStudio连接手机 客户端测试

参考文档&#xff1a;https://www.cnblogs.com/andy0816/p/17097760.html 环境依赖 需要java 1.8 java安装 略 下载Android Studio 地址 下载 Android Studio 和应用工具 - Android 开发者 | Android Developers 本机对应的包进行下载 安装过程 https://www.cnblogs.c…

STM32实现硬件IIC通信(HAL库)

文章目录 一. 前言二. 关于IIC通信三. IIC通信过程四. STM32实现硬件IIC通信五. 关于硬件IIC的Bug 一. 前言 最近正在DIY一款智能电池&#xff0c;需要使用STM32F030F4P6和TI的电池管理芯片BQ40Z50进行SMBUS通信。SMBUS本质上就是IIC通信&#xff0c;项目用到STM32CubeMXHAL库…

2025中国郑州门窗业博览会暨整屋定制家居展

2025中国郑州门窗业博览会 2025中国郑州整屋定制家居及家具产业博览会 2025中国家居行业开年第1展 邀请函 展览时间&#xff1a;第一期 2025年2月15日-17日 第二期 2025年2月22日-24日 展览地址&#xff1a;郑州国际会展中心 组委会&#xff1a;【I 3 3】【937O】【7897】…

软件工程(上)

目录 软件过程模型&#xff08;软件开发模型&#xff09; 瀑布模型 原型模型 V模型 构件组装模型 螺旋模型&#xff08;原型瀑布&#xff09; 基于构件的软件工程&#xff08;CBSE&#xff09; 快速应用开发模型&#xff08;RAD&#xff09; 统一过程&#xff08;UP&a…

HTTP模块(一)

HTTP服务 本小节主要讲解HTTP服务如何创建服务&#xff0c;查看HTTP请求&响应报文&#xff0c;还有注意事项说明&#xff0c;另外讲解本地环境&Node环境&浏览器之间的链路图示&#xff0c;如何提取HTTP报文字符串&#xff0c;及报错信息查询。 创建HTTP服务端 c…

【TB作品】51单片机 Proteus仿真00016 乒乓球游戏机

课题任务 本课题任务 (联机乒乓球游戏)如下图所示: 同步显示 oo 8个LED ooooo oo ooooo 8个LED 单片机 单片机 按键 主机 从机 按键 设计题目:两机联机乒乓球游戏 图1课题任务示意图 具体说明: 共有两个单片机,每个单片机接8个LED和1 个按键,两个单片机使用串口连接。 (2)单片机…

【高阶数据结构】B-数、B+树、B*树的原理

文章目录 B树的概念及其特点解析B树的基本操作插入数据插入数据模拟 分析分裂如何维护平衡性分析B树的性能 B树和B*树B树B树的分裂B树的优势 B*B*树的分裂 总结 B树的概念及其特点 B树是一颗多叉的平衡搜索树&#xff0c;广泛应用于数据库和 文件系统中&#xff0c;以保持数据…

第2集《修习止观坐禅法要》

请打开补充讲表第一面&#xff0c;附表一、念佛摄心方便法。 我们前面讲到修止&#xff0c;就是善取所缘境的相貌&#xff0c;然后心于所缘&#xff0c;专一安住&#xff1b;心于所缘&#xff0c;相续安住&#xff1b;达到心一境性的目的。 站在修学净土的角度&#xff0c;他…

基于Python API的机械臂UDP上报设置及读取

睿尔曼机械臂提供了1个可持续读取机械臂状态的接口&#xff0c;UDP通信状态反馈接口。 该接口提供了json协议、API的读取&#xff0c;设置通信开启之后无需再进行设置即可以固定频率读取。 Python程序源码可从以下网盘地址获取&#xff08;地址永久有效&#xff09;&#xff1…

C# WinForm —— 38 SplitContainer介绍

1. 简介 将页面拆分成两个大小可以调整的区域&#xff0c;中间有一个拆分条&#xff0c;可以拖动拆分条来调整左右区域的大小 2. 属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候会用到BoderStyle边框样式&#xff1a;None、FixedSingle、Fixed3DAutoScroll当控件…

PyFluent入门之旅(4)算例求解

在网格划分完成或已有网格的情况下&#xff0c;可以进行算例的求解。 1. 切换/打开求解器 一般启动求解器前有两种情况&#xff1a; 已启动FluentMeshing并生成了网格&#xff0c;需要在不退出FluentMeshing的情况下直接切换至Fluent求解器。已经有现成的网格文件&#xff0…

亚信安全发布2024年6月威胁态势,高危漏洞猛增60%

近日&#xff0c;亚信安全正式发布《2024年6月威胁态势报告》&#xff08;以下简称“报告”&#xff09;&#xff0c;报告显示&#xff0c;6月份新增信息安全漏洞 1794个&#xff0c;高危漏洞激增60%&#xff0c;涉及0day漏洞占67.67%&#xff1b;监测发现当前较活跃的勒索病毒…

Mysql 数据库主从复制-CSDN

查询两台虚拟机的IP 主虚拟机IP 从虚拟机IP服务 修改对应的配置文件 查询对应配置文件的命令 find / -name my.cnf编辑对应的配置文件 主 my.cnf &#xff08;部分配置&#xff09; [mysqld] ########basic settings######## server_id 1 log_bin /var/log/mysql/mysql-…