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

目标

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

疑惑点(已解决)

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.xdnf.cn/news/1474865.html

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

相关文章

【感谢告知】本账号内容调整,聚焦于Google账号和产品的使用经验和问题案例分析

亲爱的各位朋友&#xff1a; 感谢您对本账号的关注和支持&#xff01; 基于对朋友们需求的分析和个人兴趣的转变&#xff0c;该账号从今天将对内容做一些调整&#xff0c;有原来的内容改为Google&#xff08;谷歌&#xff09;账号和产品的使用经验&#xff0c;以及相关问题的…

判断是否为完全二叉树

目录 分析 分析 1.完全二叉树的概念&#xff1a;对于深度为K的&#xff0c;有n个结点的二叉树&#xff0c;当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。 2.思路&#xff1a;可以采…

Redis源码整体结构

一 前言 Redis源码研究为什么先介绍整体结构呢?其实也很简单,作为程序员的,要想对一个项目有快速的认知,对项目整体目录结构有一个清晰认识,有助于我们更好的了解这个系统。 二 目录结构 Redis源码download到本地之后,对应结构如下: 从上面的截图可以看出,Redis源码一…

pdf怎么转换成图片格式文件,pdf文档怎么转换成图片格式

在数字化时代&#xff0c;pdf文件转换成图片格式是一种常见的操作&#xff0c;无论是在工作还是日常生活中&#xff0c;我们总会遇到需要将pdf文件转换为图片的需求。这可能是因为图片格式更易于分享、展示或编辑。那么&#xff0c;如何高效地将pdf转换成图片呢&#xff1f;本文…

C++初学者指南-4.诊断---未定义行为检测器

C初学者指南-4.诊断—未定义行为检测器 未定义行为检测器(UBSAN) 适用编译器&#xff1a;clang,g在运行时检测许多类型的未定义行为 解引用空指针从未对齐的指针读取整数溢出被0除 … 在代码中加入额外的指令:在调试构建中增加运行时约25% 示例&#xff1a;有符号整形溢出 …

RabbitMq - Java客户端基础【简单案例 +Work模型】

目录 1、前置知识 1.1、AMQP怎么理解 1.2、Spring AMQP是什么 1.3、为什么要了解Spring-AMQP&#xff1f; 2、使用Spring-AMQP实现一个发消息案例 3、Work模型 问题&#xff1a; 优化&#xff1a; 小结&#xff1a;Work模型的使用&#xff1a; 1、前置知识 1.1、AMQP怎…

【论文阅读】-- Visual Traffic Jam Analysis Based on Trajectory Data

基于轨迹数据的可视化交通拥堵分析 摘要1 引言2 相关工作2.1 交通事件检测2.2 交通可视化2.3 传播图可视化 3 概述3.1 设计要求3.2 输入数据说明3.3 交通拥堵数据模型3.4 工作流程 4 预处理4.1 路网处理4.2 GPS数据清理4.3 地图匹配4.4 道路速度计算4.5 交通拥堵检测4.6 传播图…

2024世界人工智能大会,神仙打架

B站&#xff1a;啥都会一点的研究生公众号&#xff1a;啥都会一点的研究生 AI圈最近又发生了啥新鲜事&#xff1f; 该栏目以周更频率总结国内外前沿AI动态&#xff0c;感兴趣的可以点击订阅合集以及时收到最新推送 B站首秀世界人工智能大会&#xff0c;展示自研AI技术与AIGC…

生成式人工智能如何改变软件开发:助手还是取代者?

生成式人工智能如何改变软件开发&#xff1a;助手还是取代者&#xff1f; 生成式人工智能&#xff08;AIGC&#xff09;正在引领软件开发领域的技术变革。从代码生成、错误检测到自动化测试&#xff0c;AI工具在提高开发效率的同时&#xff0c;也引发了对开发者职业前景的讨论…

【shell编程小项目】

目录 一、项目拓扑二、要求三、shell编程 一、项目拓扑 二、要求 环境准备&#xff1a; 准备两个虚拟机&#xff0c;按照环境配置好对应的 IP 地址和对应的主机名和 SSH 密钥登录在 workstation.exam.com 节点实现如下需求&#xff1a; 1、编写 Shell 脚本&#xff0c;要求代码…

【web APIs】快速上手Day04(Dom节点)

目录 Web APIs - 第4天日期对象实例化方法案例-页面显示时间时间的另外一个写法 时间戳三种方式获取时间戳案例-毕业倒计时效果 节点操作DOM节点查找节点父节点查找案例-关闭广告子节点查找兄弟关系查找 增加节点创建节点追加节点案例-学成在线案例渲染克隆节点 删除节点 M端事…

ESP32 步进电机精准控制:打造高精度 DIY 写字机器人,实现流畅书写体验

摘要: 想让你的 ESP32 不再仅仅是控制灯光的工具吗&#xff1f; 本文将带你使用 ESP32 开发板、步进电机和简单的机械结构打造一个能够自动写字的机器人。我们将深入浅出地讲解硬件连接、软件代码以及控制逻辑&#xff0c;并提供完整的项目代码和电路图&#xff0c;即使是 Ardu…

在mac下 Vue2和Vue3并存 全局Vue2环境创建Vue3新项目(Vue cli2和Vue cli4)

全局安装vue2 npm install vue-cli -g自行在任意位置创建一个文件夹vue3&#xff0c;局部安装vue3,注意不要带-g npm install vue/cli安装完成后&#xff0c;进入目录&#xff0c;修改vue为vue3 找到vue3/node-moudles/.bin/vue&#xff0c;把vue改成vue3。 对环境变量进行配置…

码垛机:物流自动化的关键设备

在数字化浪潮席卷全球的今天&#xff0c;物流行业正迎来前所未有的变革。其中&#xff0c;码垛机作为物流自动化的关键设备&#xff0c;正在逐步改变着传统仓库的运营模式&#xff0c;引领着物流自动化的新篇章。 一、码垛机&#xff1a;物流自动化的得力助手 码垛机是一种能够…

【手写数据库内核组件】0201 哈希表hashtable的实战演练,多种非加密算法,hash桶的冲突处理,查找插入删除操作的代码实现

hash表原理与实战 ​专栏内容&#xff1a; postgresql使用入门基础手写数据库toadb并发编程 个人主页&#xff1a;我的主页 管理社区&#xff1a;开源数据库 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 文章目录 hash表…

从资金管理的角度 谈谈伦敦金投资技巧

刚进入伦敦金市场的时候&#xff0c;笔者认为技术分析是很重要的&#xff0c;所以将学习伦敦金投资技巧的精力全部投入到技术分析的学习中。经过一系列交易的亏损&#xff0c;笔者才发现&#xff0c;其实交易管理才是最重要的。如果管理得好&#xff0c;30%的胜率&#xff0c;投…

Python28-7.5 降维算法之t-分布邻域嵌入t-SNE

t-分布邻域嵌入&#xff08;t-distributed Stochastic Neighbor Embedding&#xff0c;t-SNE&#xff09;是一种用于数据降维和可视化的机器学习算法&#xff0c;尤其适用于高维数据的降维。t-SNE通过将高维数据嵌入到低维空间&#xff08;通常是二维或三维&#xff09;中&…

CC工具箱使用指南:【相交占比分析】

一、简介 需求场景如下&#xff0c;有【待分析地块】和【面积占比参考】2个图层。2个图层之间存在空间上的重叠。工具的目的是为了分析出【待分析地块】的每1个图斑中&#xff0c;和【面积占比参考】相交的面积&#xff0c;以及和总面积的占比。 举一个应用场景为例&#xff0…

STM32点灯闪烁

stm32c8t6引脚图 开发板引脚图 GPIO端口的每个位可以由软件分别配置成 多种模式。 ─ 输入浮空 ─ 输入上拉 ─ 输入下拉 ─ 模拟输入 ─ 开漏输出 ─ 推挽式输出 ─ 推挽式复用功能 ─ 开漏复用功能 配置GPIO端口步骤&#xff1a;开启时钟->使用结构体设置输出模式…

WAIC热点聚焦|新质生产力与低空经济

WAIC热点聚焦|新质生产力与低空经济 概览 # WAIC热点聚焦 | 新质生产力与低空经济## 1. 新质生产力定义与特点 - 新质生产力是在新的经济社会发展阶段中形成的&#xff0c;具有变革性和高增长潜力的生产能力。## 2. 低空经济概念与构成 ### 2.1 低空经济定义 - 低空经济是依托…