48.在ROS中实现local planner(1)- 实现一个可以用的模板
有了之前45.在ROS中实现global planner(1)- 实现一个可以用模板的global planner的经验, 现在再去创建一个local planner的包就容易多了
1. 创建包
- 创建
cd ~/pibot_ros/ros_ws/src # 这里可以使用自己的ros workspace
catkin_create_pkg sample_local_planner
-
添加类
我们需要实现一个从nav_core::BaseLocalPlanner继承的类,nav_core::BaseLocalPlanner接口类定义在这里base_local_planner.h#L50)可以看到 -
修改编译
修改CMakeLists.txt,添加相关编译参数和选项 -
添加
bgp_plugin.xml文件
指定导出的类名称
<library path="lib/libsample_local_planner"><class name="sample_local_planner/LocalPlanner" type="sample_local_planner::LocalPlanner" base_class_type="nav_core::BaseLocalPlanner"><description>A sample implementation of a grid local planner </description></class>
</library>
目录结构这样
❯ tree sample_local_planner
sample_local_planner
├── bgp_plugin.xml
├── CMakeLists.txt
├── include
│ └── sample_local_planner
│ └── planner_node.h
├── package.xml
└── src└── planner_node.cpp
- 导出类
参考navigation里面, 添加宏导出该类
PLUGINLIB_EXPORT_CLASS(sample_local_planner::LocalPlanner, nav_core::BaseLocalPlanner)
2. 接口实现
2.1 接口
base_local_planner.h#L50)可以看到接口类
namespace nav_core {class BaseLocalPlanner{public:virtual bool computeVelocityCommands(geometry_msgs::Twist& cmd_vel) = 0;virtual bool isGoalReached() = 0;virtual bool setPlan(const std::vector<geometry_msgs::PoseStamped>& plan) = 0;virtual void initialize(std::string name, tf2_ros::Buffer* tf, costmap_2d::Costmap2DROS* costmap_ros) = 0;};
}; // namespace nav_core
通过命名大概就知道其定义,
initialize
初始化接口,给我们传相关功能接口的,如tf,costmapsetPlan
规划控制接口,给我们提供一个plan,这个应该是global planner的输出,通过move_base转了一手给到我们,后面可以看下move_base源码computeVelocityCommands
计算速度,传入的参数是一个引用,应该是输出函数,我们把计算好的速度填进去就可以isGoalReached
获取是否以及到达目标点
2.2 不同ros版本接口差异
BaseLocalPlanner在ros kinetic 中的initialize接口稍有差异 见base_local_planner.h#L78
// kinetic
virtual void initialize(std::string name, tf::TransformListener* tf, costmap_2d::Costmap2DROS* costmap_ros) = 0;// melodic&noetic
virtual void initialize(std::string name, tf2_ros::Buffer* tf, costmap_2d::Costmap2DROS* costmap_ros) = 0;
后面我们以melodic&noetic实现
2.3 实现
主要代码如下,stopwatch_为计时器,我们在setPlan调用后,设置变量,computeVelocityCommands接口中设置固定的速度,在时间到达后,输出0,同时isGoalReached接口返回true
void LocalPlanner::initialize(std::string name, tf::TransformListener *tf,costmap_2d::Costmap2DROS *costmap_ros){ROS_INFO("LocalPlanner initialize");}bool LocalPlanner::computeVelocityCommands(geometry_msgs::Twist &cmd_vel){ROS_INFO("LocalPlanner computeVelocityCommands");if (start_flag_) {cmd_vel.linear.x = 0.2;cmd_vel.linear.y = 0;cmd_vel.angular.z = 0.8;} else {cmd_vel.linear.x = 0;cmd_vel.linear.y = 0;cmd_vel.angular.z = 0;}return true;}bool LocalPlanner::setPlan(const std::vector<geometry_msgs::PoseStamped> &orig_global_plan){ROS_INFO("LocalPlanner setPlan");if (!start_flag_) {start_flag_ = true;stopwatch_.reset();}return true;}bool LocalPlanner::isGoalReached(){if (stopwatch_.elapsed(std::chrono::seconds(2))){ROS_INFO("LocalPlanner GoalReached");return true;}return false;}
通过查看move_base源码,上面几个接口是在同一个线程被调用,所有后续不需要考虑资源竞争,即变量无需加锁
3. 测试
3.1 编译
cd ~/pibot_ros/ros_ws
catkin_make
3.2 测试
修改~/pibot_ros/src/pibot_simulator/move_base_params.yaml
# base_local_planner: "dwa_local_planner/DWAPlannerROS"
base_local_planner: sample_local_planner/LocalPlanner
dwa_local_planner/DWAPlannerROS ----> sample_local_planner/LocalPlanner
- 启动模拟器
pibot_simulator
- 查看当前的
local_planner
❯ rosparam get /move_base/base_local_planner
sample_local_planner/LocalPlanner # 输出sample_local_planner/LocalPlanner表示插件已经被正确加载
- 启动rviz发送点位,选点导航测试
pibot_view
3.3 测试结果
[ INFO] [1676647988.863610652]: make plan start:[0.000000 0.000000], goal:[-2.986773 4.282055]
[ INFO] [1676647989.063781836]: LocalPlanner setPlan
[ INFO] [1676647989.064015702]: LocalPlanner computeVelocityCommands
[ INFO] [1676647989.263707871]: LocalPlanner computeVelocityCommands
[ INFO] [1676647989.463771479]: LocalPlanner computeVelocityCommands
[ INFO] [1676647989.663754028]: LocalPlanner computeVelocityCommands
[ INFO] [1676647989.863583610]: LocalPlanner computeVelocityCommands
[ INFO] [1676647989.864067517]: make plan start:[0.000000 0.000000], goal:[-2.986773 4.282055]
[ INFO] [1676647990.063701815]: LocalPlanner setPlan
[ INFO] [1676647990.063874092]: LocalPlanner computeVelocityCommands
[ INFO] [1676647990.263710418]: LocalPlanner computeVelocityCommands
[ INFO] [1676647990.463773749]: LocalPlanner computeVelocityCommands
[ INFO] [1676647990.663630163]: LocalPlanner computeVelocityCommands
[ INFO] [1676647990.863635728]: LocalPlanner computeVelocityCommands
[ INFO] [1676647990.864087581]: make plan start:[0.000000 0.000000], goal:[-2.986773 4.282055]
[ INFO] [1676647991.063713670]: LocalPlanner setPlan
[ INFO] [1676647991.063894899]: LocalPlanner computeVelocityCommands
[ INFO] [1676647991.263639509]: LocalPlanner GoalReached
通过日志可以看出
- 在全局规划(
make plan start是我们前面文章新增的astar planner输出)后LocalPlanner的接口setPlan被调用 computeVelocityCommands函数没0.2s被调用一次, 期间机器人也在做圆周运动- 全局规划再次被调用(
move_bsae里配置了规划频率1hz,这里可以看到间隔1s全局规划一次),重复前面的 - 直到超时
GoalReached返回true完成
4. 总结
本文简单实现了一个local planner的插件,显然实际没啥用,不过可以作为一个模板,基于该模板实现自己的算法。后面我们将基于该模板实现可用的局部规划控制。
本文代码见sample_local_planner
相关文章:
48.在ROS中实现local planner(1)- 实现一个可以用的模板
有了之前45.在ROS中实现global planner(1)- 实现一个可以用模板的global planner的经验, 现在再去创建一个local planner的包就容易多了 1. 创建包 创建 cd ~/pibot_ros/ros_ws/src # 这里可以使用自己的ros workspace catkin_create_pkg sample_loc…...
jenkins基础部署
一、jenkins是什么1.Jenkins的前身是Hudson,采用JAVA编写的持续集成开源工具。Hudson由Sun公司在2004年启动,第一个版本于2005年在java.net发布。2007年开始Hudson逐渐取代CruiseControl和其他的开源构建工具的江湖地位。在2008年的JavaOne大会上在开发者…...
Unity3D -知识点(1)
1.场景视图鼠标滚轮:场景放大缩小鼠标右键:场景左右平移场景编辑器中,能看到什么?网格,每一格大小为1unit,建模不同,规定不同,(对应屏幕上100个像素)世界坐标系y轴向上为正x轴向右为…...
【学习笔记】NOIP暴零赛3
博弈(game) 观察到博弈过程中胜负态不会发生改变,那么求出从每个棋子出发能走的最长链,然后背包即可。 复杂度O(nm)O(nm)O(nm)。 #include<bits/stdc.h> #define ll long long #define pb push_back using namespace std; const int mod9982443…...
Java JSR规范列表
Java JSR规范列表目录概述需求:设计思路实现思路分析1.JSR2.JSR方法3.web service4.Webservice:5.数据处理器拓展实现参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy,skip hardness,m…...
Java必备小知识点1
Java程序类型: Applications和AppletApplications:是指在计算机操作系统中运行的程序。是完整的程序,能独立运行。被编译后,用普通的Java解释器就可以使其边解释边执行。必定含有一个main方法,程序执行时,首先寻找main方法&#x…...
JavaScript作用域、闭包
文章目录作用域、作用域链作用域作用域链循环中的作用域自由变量、闭包自由变量闭包的定义、表现、应用如何确定在闭包中获取正确的变量总结作用域、作用域链 作用域 编程语言中存储、访问、修改变量当中的值是一项基本能力、存储变量、访问变量必须按照一定的规则࿰…...
JavaScript Date(日期) 对象
JavaScript Date 对象是 JavaScript 中用于处理日期和时间的内置对象。它可以用于获取当前时间、设置日期和时间、计算日期和时间之间的差异、以及将日期和时间格式化为各种字符串格式。在本文中,我们将详细介绍 JavaScript Date 对象的作用和在实际工作中的用途。 …...
rust过程宏 proc-macro-workshop解题-4-sorted
名字版本号rust1.69.0OSubuntu 22.04这一大关卡介绍的是属性式过程宏。 第一关:01-parse-enum 还是简单的看我们是否已经实现了一个属性式过程宏的空架子,如果有这个空架子,就直接通过了。 use proc_macro::TokenStream; use proc_macro2; use syn;#[proc_macro_attribut…...
数据结构与算法—队列
队列 队列介绍 有序列表,可以用数组或者链表实现。遵循先进先出原则。 数组实现队列 public class ArrayQueue {public static void main(String[] args) {ArrayQueue queue new ArrayQueue(3);// 接收用户输入char key ;Scanner sc new Scanner(System.in);…...
AcWing3416.时间显示——学习笔记
目录 题目 代码 AC结果 思路 关键步骤 题目 3416. 时间显示 - AcWing题库https://www.acwing.com/problem/content/description/3419/ 代码 import java.util.Scanner;public class Main {public static void main(String[] args){Scanner input new Scanner(System.in…...
贴吧手机端防删图GIF动态图制作解析
贴吧存活 思路技术运气 1:防删图不是存活的绝对因素,除了防删图,还有账号,ip,内容,吧的问题 2:一个图不是每个吧都可以发 3:一个贴不被删不仅仅看图片 4:有时候运气也很…...
iOS接入Google登录
1.在Google Cloud后台配置客户端ID 首先要在 Google Cloud 中创建一个项目。新创建的Project需要先配置同意屏幕。一共有4步骤需要配置。 1.OAuth 同意屏幕 User Type选择"外部"进行创建。填写必必要的信息,应用名称、用户支持电子邮件地址、开发者电子邮…...
【C语言】大小端字节序问题
一、大小端字节序问题 大小端是由CPU决定的,大小端可以理解为字节顺序,所以大小端全称叫大端字节序、小端字节序。其实大端、小端这两个词是从《格列佛游记》里出来的。《格列佛游记》有一段讲的是吃鸡蛋是从大的那头敲开还是小的那头敲开的问题…...
Linux | 网络通信 | 序列化和反序列化的讲解与实现
文章目录为什么要序列化?协议的实现服务端与客户端代码实现为什么要序列化? 由于默认对齐数的不同,不同的平台对相同数据进行内存对齐后,可能得到不同的数据。如果直接将这些数据进行网络传输,对方很可能无法正确的获…...
C#的委托原理刨析and事件原理刨析和两者的比较
什么是委托委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。 在实例化委托时,你可以将其实例与任何具有兼容参数和返回类型的方法进行绑定。 你可以通过委托实例调用方法。简单的理解,委托是方法的抽象类,它定…...
Redis学习【8】之Redis RDB持久化
文章目录Redis 持久化1 持久化基本原理2 RDB(Redis DataBase) 持久化2.1 持久化的执行2.2 手动 save 命令2.3 手动 bgsave 命令2.4 自动条件触发2.5 查看持久化时间3 RDB 优化配置3.1 save3.2 stop-write-on-bgsave-error3.3 rdbcompression3.4 rdbchecksum3.5 sanitize-dump-p…...
SpringSecurity认证
文章目录登陆校验流程依赖yaml实现建表、工具类、实体类加密器、AuthenticationManager登录逻辑登录过滤器、配置过滤器登出登陆校验流程 认证 登录: ①自定义登录接口 调用ProviderManager的方法进行认证 如果认证通过生成token,根据userId把用…...
Socket套接字
概念 Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程。 分类 Socket套接字主要针对传输层协议划分为如下三类: 流套接字:使用传输层TCP…...
mysql详解之innoDB
索引 Mysql由索引组织,所以索引是mysql多重要概念之一。 聚簇索引 InnoDB和MyISAm一样都是采用B树结构,但不同点在于InnoDB是聚簇索引(或聚集索引),将数据行直接放在叶子节点后面。 这里可能存在一个误区࿱…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
