navigation2 编写规划器(planner)插件

2023-10-28 13:04

本文主要是介绍navigation2 编写规划器(planner)插件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • navigation2 编写规划器(planner)插件
    • 1- 创建一个新的规划器插件
    • 2- 导出规划器插件
      • 1. 要导出规划器,我们需要提供两行代码:
      • 2. 接下来的步骤是在包的根目录中创建插件的描述文件。例如,在我们的教程包中创建`global_planner_plugin.xml`文件。该文件包含以下信息:
      • 3. 接下来的步骤是使用 CMakeLists.txt 导出插件,通过使用 cmake 函数`pluginlib_export_plugin_description_file()`。这个函数将插件描述文件安装到 share目录,并设置ament索引以使其可被发现。
      • 4. 插件描述文件也应该添加到package.xml文件中。
      • 5. 编译后,插件应该已注册。接下来,我们将使用这个插件
    • 3- 通过参数文件传递插件名称。
    • 4- 运行 StraightLine 插件

navigation2 编写规划器(planner)插件

教程步骤如下

1- 创建一个新的规划器插件

  我们将创建一个简单的直线规划器。本教程中带注释代码可以在 navigation_tutorials 仓库中的 nav2_straightline_planner 找到。这个软件包可以作为编写规划器插件的参考。
  我们的示例插件继承自基类 nav2_core::GlobalPlanner。基类提供了5个纯虚方法来实现规划器插件。该插件将被规划器服务器用于计算路径。让我们更深入地了解编写规划器插件所需的方法。

虚方法方法描述是否需要重写?
configure()当规划器服务器进入 on_configure 状态时调用该方法。理想情况下,此方法应执行 ROS 参数的声明和规划器成员变量的初始化。此方法接受4个输入参数:指向父节点的共享指针、规划器名称、tf 缓冲区指针和代价地图的共享指针。
activate()当规划器服务器进入on_activate状态时调用该方法。理想情况下,此方法应实现在规划器进入活动状态之前必要的操作。
deactivate()当规划器服务器进入on_deactivate状态时调用该方法。理想情况下,此方法应实现在规划器进入非活动状态之前必要的操作。
cleanup()当规划器服务器进入on_cleanup状态时调用该方法。理想情况下,此方法应清理为规划器创建的资源。
createPlan()当规划器服务器要求为指定的起点和目标姿态提供全局计划时,调用该方法。该方法返回携带全局计划的 nav_msgs::msg::Path。此方法接受2个输入参数:起始姿态和目标姿态。

  在本教程中,我们将使用 StraightLine::configure()StraightLine::createPlan() 方法来创建直线规划器。
  在规划器中,configure() 方法必须从ROS参数中设置成员变量,并进行任何所需的初始化。

node_ = parent;
tf_ = tf;
name_ = name;
costmap_ = costmap_ros->getCostmap();
global_frame_ = costmap_ros->getGlobalFrameID();// Parameter initialization
nav2_util::declare_parameter_if_not_declared(node_, name_ + ".interpolation_resolution", rclcpp::ParameterValue(0.1));
node_->get_parameter(name_ + ".interpolation_resolution", interpolation_resolution_);

  这里,name_ + ".interpolation_resolution" 是获取特定于我们规划器的 ROS 参数interpolation_resolution。Nav2 允许加载多个插件,并为了保持组织结构的整洁性,每个插件都映射到某个 ID/ 名称。现在,如果我们想要检索特定插件的参数,我们使用<mapped_name_of_plugin>.<name_of_parameter>,就像上面的代码片段中所做的那样。例如,我们的示例规划器映射到名称“GridBased”,要检索特定于 “GridBased” 的 interpolation_resolution 参数,我们使用 GridBased.interpolation_resolution 。换句话说,GridBased 被用作插件特定参数的命名空间。在讨论参数文件(或参数文件)时,我们将更详细地介绍这一点。
  在 createPlan() 方法中,我们需要根据给定的起始和目标姿态创建路径。使用起始姿态和目标姿态调用StraightLine::createPlan()来解决全局路径规划问题。如果成功,它将将路径转换为nav_msgs::msg::Path并返回给规划器服务器。下面的注释显示了该方法的实现。

nav_msgs::msg::Path global_path;// Checking if the goal and start state is in the global frame
if (start.header.frame_id != global_frame_) {RCLCPP_ERROR(node_->get_logger(), "Planner will only except start position from %s frame",global_frame_.c_str());return global_path;
}if (goal.header.frame_id != global_frame_) {RCLCPP_INFO(node_->get_logger(), "Planner will only except goal position from %s frame",global_frame_.c_str());return global_path;
}global_path.poses.clear();
global_path.header.stamp = node_->now();
global_path.header.frame_id = global_frame_;
// calculating the number of loops for current value of interpolation_resolution_
int total_number_of_loop = std::hypot(goal.pose.position.x - start.pose.position.x,goal.pose.position.y - start.pose.position.y) /interpolation_resolution_;
double x_increment = (goal.pose.position.x - start.pose.position.x) / total_number_of_loop;
double y_increment = (goal.pose.position.y - start.pose.position.y) / total_number_of_loop;for (int i = 0; i < total_number_of_loop; ++i) {geometry_msgs::msg::PoseStamped pose;pose.pose.position.x = start.pose.position.x + x_increment * i;pose.pose.position.y = start.pose.position.y + y_increment * i;pose.pose.position.z = 0.0;pose.pose.orientation.x = 0.0;pose.pose.orientation.y = 0.0;pose.pose.orientation.z = 0.0;pose.pose.orientation.w = 1.0;pose.header.stamp = node_->now();pose.header.frame_id = global_frame_;global_path.poses.push_back(pose);
}global_path.poses.push_back(goal);return global_path;

剩余的方法虽然没有被使用,但是必须重写。根据规则,我们确实重写了所有这些方法,但是将它们留空。

2- 导出规划器插件

  现在我们已经创建了自定义规划器,我们需要导出我们的规划器插件,以便它对规划器服务器可见。插件在运行时加载,如果它们不可见,那么我们的规划器服务器将无法加载它。在ROS 2中,导出和加载插件是由pluginlib处理的。
  回到我们的教程,nav2_straightline_planner::StraightLine类以动态方式加载为我们的基类nav2_core::GlobalPlanner

1. 要导出规划器,我们需要提供两行代码:

#include "pluginlib/class_list_macros.hpp"
PLUGINLIB_EXPORT_CLASS(nav2_straightline_planner::StraightLine, nav2_core::GlobalPlanner)

将这两行代码放在文件末尾是一个良好的实践,但从技术上讲,你也可以将其放在文件的顶部。

2. 接下来的步骤是在包的根目录中创建插件的描述文件。例如,在我们的教程包中创建global_planner_plugin.xml文件。该文件包含以下信息:

  • library path: 插件库的名称和位置。
  • class name: 类的名称。
  • class type: 类的类型。
  • base class: 基类的名称。
  • description: 插件的描述。
<library path="nav2_straightline_planner_plugin"><class name="nav2_straightline_planner/StraightLine" type="nav2_straightline_planner::StraightLine" base_class_type="nav2_core::GlobalPlanner"><description>This is an example plugin which produces straight path.</description></class>
</library>

3. 接下来的步骤是使用 CMakeLists.txt 导出插件,通过使用 cmake 函数pluginlib_export_plugin_description_file()。这个函数将插件描述文件安装到 share目录,并设置ament索引以使其可被发现。

pluginlib_export_plugin_description_file(nav2_core global_planner_plugin.xml)

4. 插件描述文件也应该添加到package.xml文件中。

<export><build_type>ament_cmake</build_type><nav2_core plugin="${prefix}/global_planner_plugin.xml" />
</export>

5. 编译后,插件应该已注册。接下来,我们将使用这个插件

3- 通过参数文件传递插件名称。

为了启用插件,我们需要修改nav2_params.yaml文件,如下所示,替换以下参数:

  • 备注:
    从Galactic版本开始,plugin_namesplugin_types已被替换为一个plugins字符串向量用于插件名称。类型现在在plugin_name命名空间中的plugin字段中定义(例如,plugin: MyPlugin::Plugin)。代码块中的内联注释将帮助指导你进行操作。
planner_server:ros__parameters:plugins: ["GridBased"]use_sim_time: TrueGridBased:plugin: "nav2_navfn_planner/NavfnPlanner" # For Foxy and latertolerance: 2.0use_astar: falseallow_unknown: true

with

planner_server:ros__parameters:plugins: ["GridBased"]use_sim_time: TrueGridBased:plugin: "nav2_straightline_planner/StraightLine"interpolation_resolution: 0.1

在上面的代码片段中,你可以观察到我们将nav2_straightline_planner/StraightLine规划器映射到其id GridBased。为了传递插件特定的参数,我们使用了<plugin_id>.<plugin_specific_parameter>的格式。

4- 运行 StraightLine 插件

  使用启用了Navigation2的Turtlebot3仿真。如何制作的详细说明已在“入门指南”中编写。以下是一个快捷命令:

ros2 launch nav2_bringup tb3_simulation_launch.py params_file:=/path/to/your_params_file.yaml

  然后进入RViz,点击顶部的“2D姿态估计”按钮,并在地图上指向位置,就像在“入门指南”中描述的那样。机器人将在地图上进行定位,然后点击“Navigation2目标”,并单击您希望规划器考虑的目标姿态。之后,规划器将规划路径,机器人将开始朝着目标移动。

这篇关于navigation2 编写规划器(planner)插件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/293404

相关文章

利用Python编写一个简单的聊天机器人

《利用Python编写一个简单的聊天机器人》这篇文章主要为大家详细介绍了如何利用Python编写一个简单的聊天机器人,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 使用 python 编写一个简单的聊天机器人可以从最基础的逻辑开始,然后逐步加入更复杂的功能。这里我们将先实现一个简单的

使用PyQt5编写一个简单的取色器

《使用PyQt5编写一个简单的取色器》:本文主要介绍PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16进制颜色编码,一款跟随鼠标刷新图像的RGB和16... 目录取色器1取色器2PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16

IDEA常用插件之代码扫描SonarLint详解

《IDEA常用插件之代码扫描SonarLint详解》SonarLint是一款用于代码扫描的插件,可以帮助查找隐藏的bug,下载并安装插件后,右键点击项目并选择“Analyze”、“Analyzewit... 目录SonajavascriptrLint 查找隐藏的bug下载安装插件扫描代码查看结果总结Sona

使用Java编写一个文件批量重命名工具

《使用Java编写一个文件批量重命名工具》这篇文章主要为大家详细介绍了如何使用Java编写一个文件批量重命名工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录背景处理1. 文件夹检查与遍历2. 批量重命名3. 输出配置代码片段完整代码背景在开发移动应用时,UI设计通常会提供不

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

如何编写Linux PCIe设备驱动器 之二

如何编写Linux PCIe设备驱动器 之二 功能(capability)集功能(capability)APIs通过pci_bus_read_config完成功能存取功能APIs参数pos常量值PCI功能结构 PCI功能IDMSI功能电源功率管理功能 功能(capability)集 功能(capability)APIs int pcie_capability_read_wo

数学建模笔记—— 非线性规划

数学建模笔记—— 非线性规划 非线性规划1. 模型原理1.1 非线性规划的标准型1.2 非线性规划求解的Matlab函数 2. 典型例题3. matlab代码求解3.1 例1 一个简单示例3.2 例2 选址问题1. 第一问 线性规划2. 第二问 非线性规划 非线性规划 非线性规划是一种求解目标函数或约束条件中有一个或几个非线性函数的最优化问题的方法。运筹学的一个重要分支。2