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
,costmap
setPlan
规划控制接口,给我们提供一个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是聚簇索引(或聚集索引),将数据行直接放在叶子节点后面。 这里可能存在一个误区࿱…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...

代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...