从0开始跑通小乌龟三个功能

发布时间:2026/8/27 8:51:23

从0开始跑通小乌龟三个功能
提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档文章目录前言一、pandas是什么二、使用步骤1.引入库2.读入数据总结前言学习完ROS的节点和话题通信我们接下来通过三个最基础的例子去更加深刻的学习话题通信和节点间的信号传输。第一个是通过键盘控制小乌龟的方向运动第二个是通过订阅话题去监控小乌龟的位置第三个是智能巡航给定一个目标自动导航到目标位置。一、按键控制小乌龟运动ROS2 的 Topic 可以理解成一个聊天频道群聊。Topic 的名字决定消息发送到哪个频道消息类型决定频道里大家使用什么格式交流。只有 Topic 名字相同且消息类型一致Publisher 和 Subscriber 才能成功通信。其中名字就相当于群聊的名字类型相当于要发送的内容举个例子你和一个外国人在一个群里面但是你们之间语言不通用所以你们无法通信。一个节点可以同时加入很多不同的频道也可以自己创建新的频道。这个小乌龟里面已经定义了发布者和订阅者的名字类型所以你想要进行控制或监听就必须按这样的格式去写。第一个工程Turtle_keyboard就是发布一个话题给小乌龟的订阅者去接收。小乌龟其实就相当于一个节点等开启时它的这些发布者和订阅者就开始不断发送消息。对于这个简单的控制我们将问题拆解首先要获取键盘数据、再将键盘数据转换成小乌龟可以识别的数据、最后再将转换好的数据进行发送。#include rclcpp/rclcpp.hpp #include geometry_msgs/msg/twist.hpp #include iostream /* std本质上命名空间里面存放来用于标准库的函数和类比如cout、cin、endl等 的作用就是去某个命名空间去找某个函数或类比如std::cout 也可以在类里使用当你定义了一个class后在类外实现某个函数时需要在类名前加:: 比如TurtleKeyboard::readKeyboard using namespace std;这个就是告诉编译器默认都去std空间下找 */ class TurtleKeyboard:public rclcpp::Node { public: TurtleKeyboard():Node(turtlekeyboard) { publisher_this-create_publishergeometry_msgs::msg::Twist(/turtle1/cmd_vel,10); RCLCPP_INFO(this-get_logger(),Turtle Keyboard Node Started); } void run();//声明一个函数把函数定义和函数实现分开因为以后类会非常大如果都写成函数内容会有几千行 private: //private 只限制谁可以调用不限制在哪里实现 char readKeyboard();//读取键盘指令 geometry_msgs::msg::Twist processKey(char key);//用于将键盘数据转换为Twist void publishVelocity(const geometry_msgs::msg::Twist msg);//用于发布Twist private: rclcpp::Publishergeometry_msgs::msg::Twist::SharedPtr publisher_; }; char TurtleKeyboard::readKeyboard()//键盘获取函数 { char key; std::cout请输入控制指令std::endl; std::cout W:前进 std::endl; std::cout A:左转 std::endl; std::cout D:右转 std::endl; std::cout S:停止 std::endl; std::cout Q:退出程序 std::endl; std::cout 输入; std::cinkey; return std::tolower(key);//兼容大小写 } geometry_msgs::msg::Twist TurtleKeyboard::processKey(char key) { geometry_msgs::msg::Twist msg{}; //不加{}就感觉在创建一个函数它的作用是初始化一个Twist对象用于存储速度控制 switch (key) { case w: msg.linear.y2.0; /* code */ break; case a: msg.linear.x-2.0; /* code */ break; case d: msg.linear.x2.0; /* code */ break; case s: msg.linear.y-2.0; break; default: break; } return msg;//因为要传的数据是geometry_msgs::msg::Twist } void TurtleKeyboard::run() { while (rclcpp::ok()) { char keyreadKeyboard();//这个会阻塞等待 if(keyq) { break; } auto msgprocessKey(key); publishVelocity(msg);//只发布来一次指令 } } /* 为什么发布来速度指令但是小乌龟却运动了一段距离呢 每次按键你只发布一次速度消息。在ROS中速度指令不是开关式的而是持续指令。 当小乌龟收到一次速度指令后它会按照这个速度移动但如果没有持续收到相同的速度指令它就会逐渐减速并停止。 */ void TurtleKeyboard::publishVelocity(const geometry_msgs::msg::Twist msg) { publisher_-publish(msg); } int main(int argc,char *argv[]) { rclcpp::init(argc,argv); auto nodestd::make_sharedTurtleKeyboard(); node-run();//外部调用这个函数运动 rclcpp::shutdown(); return 0; }完后运行这个工程的同时还需要运行小乌龟节点小乌龟节点运行方式如下然后就可以操作小乌龟进行运动。ros2 run turtlesim turtlesim_node二、订阅小乌龟运动状态这个项目就是实时监听小乌龟的坐标信息可以配合第一个项目进行联动当启动项目一时同时开启小乌龟监听节点即可获得小乌龟实时动态信息。/* 学会Subscribe订阅监控乌龟的位置 turtlesim │ ▼ /turtle1/pose │ ▼ Subscriber │ ▼ 打印当前位置 x 5.23 y 3.84 theta 1.52 linear_velocity 2.0 angular_velocity 0 */ #include rclcpp/rclcpp.hpp #include turtlesim/msg/pose.hpp ///turtle1/pose 这个话题发布的数据类型就是 turtlesim::msg::Pose //Subscriber 必须知道接收到的数据长什么样所以需要包含 turtlesim/msg/pose.hpp。 //geometry_msgs::msg::Twist 是 /turtle1/cmd_vel 使用的数据类型用来表示速度控制不适用于订阅位置话题。 #include iostream class TurtlePoseSubscriber:public rclcpp::Node { private: void pose_callback(const turtlesim::msg::Pose::SharedPtr msg)//msg是指针用于指向Pose对象的智能指针 { //对象用.指针用- RCLCPP_INFO(this-get_logger(), x%.2f y%.2f theta%.2f, msg-x, msg-y, msg-theta); } private: //定义一个订阅者用于订阅/turtle1/pose话题 rclcpp::Subscriptionturtlesim::msg::Pose::SharedPtr subscription_; public: //主要将构造函数初始化成员变量初始化在构造函数中 TurtlePoseSubscriber():Node(turtlePoseSubscriber) { //如果不赋值对象很快就会因为引用计数归零而销毁 subscription_this-create_subscriptionturtlesim::msg::Pose(/turtle1/pose,10, std::bind(TurtlePoseSubscriber::pose_callback,this,std::placeholders::_1)); //第三个参数需要的是一个可以被调用的函数 //std::placeholders::_1这个意思就是第一个参数以后再给回调函数。 } }; int main(int argc,char *argv[]) { rclcpp::init(argc,argv); auto nodestd::make_sharedTurtlePoseSubscriber();//创建一个节点用于订阅/turtle1/pose话题 rclcpp::spin(node); rclcpp::shutdown(); return 0; }这里要注意的知识点是订阅者和回调函数。订阅者的机制是当 ROS2 executor 发现 subscription 收到消息 → 就调用回调函数。流程如下publisher → DDS/中间层 → subscription队列 → executor → callback。回调函数的作用是打印输出位置信息。std::bind(TurtlePoseSubscriber::pose_callback, this, std::placeholders::_1)三、智能导航自动巡航到目标位置这个项目是对前面两个项目的综合运用将给小乌龟发送位置和订阅位置信息相融合通过反馈的位置信息不断修正自己的位置从而完成到达指定位置点的功能。/* 智能导航给定一个目标自动导航到目标位置。 */ #include rclcpp/rclcpp.hpp #include geometry_msgs/msg/twist.hpp//速度消息线速度和角速度 #include turtlesim/msg/pose.hpp//位姿消息 #include cmath class Turtle_navigation:public rclcpp::Node { private: void targetnode(const turtlesim::msg::Pose::SharedPtr pose) { geometry_msgs::msg::Twist message;//用于速度的接受后面给发布者去发布 //记录当前位置 double current_xpose-x; double current_ypose-y; double K{0.5};//控制系数 RCLCPP_INFO(this-get_logger(),current_x:%f,current_y:%f,current_x,current_y); //计算目标位置与当前位置的差值 double distancestd::sqrt((target_x-current_x)*(target_x-current_x)(target_y-current_y)*(target_y-current_y)); double anglestd::atan2(target_y-current_y,target_x-current_x)-pose-theta; //前面的先计算形成的三角形夹角后面的是当前和x轴的夹角 RCLCPP_INFO(this-get_logger(),distance:%f,angle:%f,distance,angle); //控制策略 if(distance0.5) { if(std::fabs(angle)0.5) { //向目标位置旋转再加速运动 message.angular.zK*angle; }else { //向目标位置加速运动 message.linear.xK*distance; } } publisher_-publish(message); } private: rclcpp::Publishergeometry_msgs::msg::Twist::SharedPtr publisher_; rclcpp::Subscriptionturtlesim::msg::Pose::SharedPtr subscription_; double target_x{3.0}; double target_y{3.0}; public:Turtle_navigation():Node(turtle_navigation) { publisher_this-create_publishergeometry_msgs::msg::Twist(/turtle1/cmd_vel,10); subscription_this-create_subscriptionturtlesim::msg::Pose(/turtle1/pose,10, std::bind(Turtle_navigation::targetnode,this,std::placeholders::_1)); } }; int main(int argc, char * argv[]) { rclcpp::init(argc, argv); auto nodestd::make_sharedTurtle_navigation(); rclcpp::spin(node); rclcpp::shutdown(); return 0; }主要难点在于如何写好回调函数通过不断对比距离的差距采用的是先旋转方向再发送速度使其运动当足够靠近点的时候减小速度逐渐趋近于标定点。总结这三个工程主要是对Topic话题发布的订阅的应用。对于熟练掌握这部分知识点为后续的学习打下坚实的基础。

相关新闻

DS28EC20与dsPIC33FJ256GP710A在嵌入式存储中的实践

DS28EC20与dsPIC33FJ256GP710A在嵌入式存储中的实践

2026/8/26 16:04:29

1. 为什么选择DS28EC20和dsPIC33FJ256GP710A组合在嵌入式系统中保存用户设置和偏好是个看似简单但暗藏玄机的需求。我最近在一个工业控制项目中选择DS28EC20 EEPROM搭配dsPIC33FJ256GP710A微控制器的方案,这套组合有几个关键优势:首先,DS28EC…

6DoF运动感知与IMU在嵌入式系统的应用实践

6DoF运动感知与IMU在嵌入式系统的应用实践

2026/8/26 18:12:06

1. 从3D到6DoF的运动感知升级在嵌入式系统和物联网设备中,运动感知能力正经历着从基础3D到高级6DoF的技术跃迁。3D运动感知通常指三维空间中的线性运动检测(通过加速度计实现),而6DoF(Six Degrees of Freedom&#xff…

如何免费解锁Wand专业版:开源增强工具使用指南

如何免费解锁Wand专业版:开源增强工具使用指南

2026/8/26 18:42:43

如何免费解锁Wand专业版:开源增强工具使用指南 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/gh_mirrors/we/Wand-Enhancer 还在为Wand(原WeMod)的…

数学建模实战:基于Matlab的垃圾收运路径优化算法与应用

数学建模实战:基于Matlab的垃圾收运路径优化算法与应用

2026/8/27 8:47:39

1. 从垃圾围城到数学方程:一个建模者的实战视角 如果你问我,数学建模离我们有多远?我会说,它可能就在你家楼下的垃圾桶里。这不是一句玩笑话。作为一名在数学建模竞赛里摸爬滚打多年,也参与过一些实际市政咨询项目的“…

Java IDEA - 各种快捷键设置汇总(提高工具使用效率)

Java IDEA - 各种快捷键设置汇总(提高工具使用效率)

2026/8/27 8:47:39

目录 (速查快捷键,点击标题则跳转到对应快捷键的设置)(不断更新中,需要的可以收藏) 一、序列化Serializable设置 (光标放在类上 -> alt enter即可) 二、回退/前进 到上一个查看的类 /…

数学建模聚类算法实战:从K-Means到DBSCAN的思维转换与应用

数学建模聚类算法实战:从K-Means到DBSCAN的思维转换与应用

2026/8/27 8:47:39

1. 从“分类”到“聚类”:数学建模中一个根本性的思维转换 如果你参加过数学建模比赛,或者正在准备,大概率听过“聚类算法”这个词。很多新手拿到一个涉及数据分组的题目,第一反应是去找“标准答案”——比如,题目里给…

Codex实战指南:从环境配置到开发工作流落地

Codex实战指南:从环境配置到开发工作流落地

2026/8/27 8:47:39

我第一次打开 Codex 时,心里想的还是“聊天窗口里写代码”那套老经验。后来发现,Codex 的工作方式完全是另一个路径:它不只是给出代码建议,而是会自己读文件、跑命令、看报错、然后继续改。这个区别,决定了你接下来的所…

ContextMenuMgr Plus:Windows右键菜单清理与防护实战

ContextMenuMgr Plus:Windows右键菜单清理与防护实战

2026/8/27 8:47:39

这次我们来看一个 GitHub 上关注度比较高的开源 Windows 工具:ContextMenuMgr Plus。它的定位很直接:管理 Windows 右键菜单。很多人电脑用久了之后,右键菜单会变得特别长,打开文件资源管理器都变卡,还时不时冒出来一些…

Hugging Face 是什么?-Day29

Hugging Face 是什么?-Day29

2026/8/27 8:37:39

关键词:Hugging Face, AI Hub, Transformers, 开源模型, 机器学习平台一、Hugging Face 是什么? Hugging Face(https://huggingface.co) 是全球最大的开源人工智能社区与模型托管平台,被誉为 “AI 领域的 GitHub”。它…

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

2026/8/26 1:50:39

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

2026/8/27 7:25:23

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

2026/8/26 17:50:58

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

Go语言构建企业级AI服务网关:统一管理英伟达等AI接口调用

Go语言构建企业级AI服务网关:统一管理英伟达等AI接口调用

2026/8/27 0:07:12

1. 项目概述:从零构建一个企业级的AI服务网关 最近在帮一个做内容审核的团队做技术架构升级,他们原来的业务里,每天有几十万张图片和短视频需要过审,最初是接了几个开源的AI模型自己部署,但效果和性能一直不太稳定。后…

LeetCode Hot100(51-60)算法精解与面试技巧

LeetCode Hot100(51-60)算法精解与面试技巧

2026/8/27 0:07:12

1. 题目背景与核心价值"hot100(51-60)"这个标题看起来像是某个编程题库或算法练习集中的一组题目编号。在技术社区中,类似命名通常指向LeetCode、牛客网等平台的热门题目集合。作为刷过300题的算法老手,我理解这类题目的核心价值在于&#xff…

CRC校验实战:从模2除法到HJ212协议排错

CRC校验实战:从模2除法到HJ212协议排错

2026/8/27 0:07:12

1. 为什么一个“校验码”能扛住工业现场90%的数据 corruption? 你有没有遇到过这样的场景:嵌入式设备通过RS-485上传温湿度数据,上位机偶尔收到一帧乱码——温度显示成-273℃,湿度跳到999%,但串口波形看起来完全正常&a…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/22 2:02:26

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/26 18:07:30

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/26 17:57:52

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…