当前位置: 首页 > news >正文

编写 navigation2 控制器插件

简介

  本教程展示了如何创建自己的控制器插件。在本教程中,我们将基于这篇论文实现纯追踪路径跟踪算法。建议您阅读该论文。
  注意:本教程基于 Nav2 堆栈中以前存在的简化版本的 Regulated Pure Pursuit 控制器。您可以在此处找到与本教程相匹配的源代码。

1- 创建一个新的控制器插件

  我们将实现纯追踪控制器。本教程中的注释代码可以在 navigation_tutorials存储库中的 nav2_pure_pursuit_controller 中找到。这个包可以被视为编写自己的控制器插件的参考。
  我们的示例插件类 nav2_pure_pursuit_controller::PurePursuitController 继承自基类nav2_core::Controller。基类提供了一组虚拟方法来实现控制器插件。这些方法在运行时被控制器服务器调用以计算速度命令。下表列出了各种虚函数、函数描述和以及是否需要重新:

虚函数方法描述需要重写?
configure()当控制器服务器进入on_configure状态时调用该方法。理想情况下,该方法应执行ROS参数的声明和控制器成员变量的初始化。该方法接受4个输入参数:父节点的弱引用、控制器名称、tf缓冲区指针和costmap的共享指针。
activate()当控制器服务器进入on_activate状态时调用该方法。理想情况下,该方法应实现在控制器进入活动状态之前必要的操作。
deactivate()当控制器服务器进入on_deactivate状态时调用该方法。理想情况下,该方法应实现在控制器进入非活动状态之前必要的操作。
cleanup()当控制器服务器进入on_cleanup状态时调用该方法。理想情况下,该方法应清理为控制器创建的资源。
setPlan()当全局路径更新时调用该方法。理想情况下,该方法应执行转换全局路径和存储路径的操作。
computeVelocityCommands()当控制器服务器要求提供新的速度命令,以便机器人按照全局路径行驶时,调用该方法。该方法返回一个geometry_msgs::msg::TwistStamped,表示机器人行驶的速度命令。该方法传递两个参数:当前机器人位姿的引用和当前速度。
setSpeedLimit()当需要限制机器人的最大线速度时调用该方法。速度限制可以用绝对值(m/s)或相对于最大机器人速度的百分比来表示。请注意,通常情况下,最大旋转速度与最大线速度的变化成比例地被限制,以保持当前机器人的行为不变。

  在本教程中,我们将使用 PurePursuitController 类的 configure、setPlan 和 computeVelocityCommands 方法。
  在控制器中,configure()方法必须从ROS参数设置成员变量,并执行任何所需的初始化操作。

void PurePursuitController::configure(const rclcpp_lifecycle::LifecycleNode::WeakPtr & parent,std::string name, std::shared_ptr<tf2_ros::Buffer> tf,std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros)
{node_ = parent;auto node = node_.lock();costmap_ros_ = costmap_ros;tf_ = tf;plugin_name_ = name;logger_ = node->get_logger();clock_ = node->get_clock();declare_parameter_if_not_declared(node, plugin_name_ + ".desired_linear_vel", rclcpp::ParameterValue(0.2));declare_parameter_if_not_declared(node, plugin_name_ + ".lookahead_dist",rclcpp::ParameterValue(0.4));declare_parameter_if_not_declared(node, plugin_name_ + ".max_angular_vel", rclcpp::ParameterValue(1.0));declare_parameter_if_not_declared(node, plugin_name_ + ".transform_tolerance", rclcpp::ParameterValue(0.1));node->get_parameter(plugin_name_ + ".desired_linear_vel", desired_linear_vel_);node->get_parameter(plugin_name_ + ".lookahead_dist", lookahead_dist_);node->get_parameter(plugin_name_ + ".max_angular_vel", max_angular_vel_);double transform_tolerance;node->get_parameter(plugin_name_ + ".transform_tolerance", transform_tolerance);transform_tolerance_ = rclcpp::Duration::from_seconds(transform_tolerance);
}

  在这里,plugin_name_ + “.desired_linear_vel” 获取了名为 desired_linear_vel 的ROS 参数,该参数是特定于我们的控制器的。Nav2 允许加载多个插件,并且为了保持事物的组织性,每个插件都映射到某个ID/名称。现在,如果我们想要检索特定插件的参数,我们可以使用<mapped_name_of_plugin>.<name_of_parameter>,就像上面的片段中所做的那样。例如,我们的示例控制器被映射到名称FollowPath,要检索特定于“FollowPath”的desired_linear_vel参数,我们使用FollowPath.desired_linear_vel。换句话说,FollowPath用作插件特定参数的命名空间。当我们讨论参数文件(或params文件)时,我们将更详细地讨论这个问题。
  传入的参数被存储在成员变量中,以便在以后的阶段如果需要的话可以使用它们。
  在setPlan()方法中,我们接收到机器人需要跟随的更新的全局路径。在我们的示例中,我们将接收到的全局路径转换为机器人的坐标系,并将这个转换后的全局路径存储起来以备后用。

void PurePursuitController::setPlan(const nav_msgs::msg::Path & path)
{// Transform global path into the robot's frameglobal_plan_ = transformGlobalPlan(path);
}

  计算期望速度的操作发生在computeVelocityCommands()方法中。它用于根据当前速度和姿态计算期望速度指令。第三个参数是一个指向nav2_core::GoalChecker的指针,用于检查是否已达到目标。在我们的示例中,这个参数不会被使用。对于纯追踪算法而言,该算法计算速度指令,使得机器人尽可能地紧跟全局路径。该算法假设线速度是恒定的,并根据全局路径的曲率计算角速度。

geometry_msgs::msg::TwistStamped PurePursuitController::computeVelocityCommands(const geometry_msgs::msg::PoseStamped & pose,const geometry_msgs::msg::Twist & velocity,nav2_core::GoalChecker * /*goal_checker*/)
{// Find the first pose which is at a distance greater than the specified lookahead distanceauto goal_pose = std::find_if(global_plan_.poses.begin(), global_plan_.poses.end(),[&](const auto & global_plan_pose) {return hypot(global_plan_pose.pose.position.x,global_plan_pose.pose.position.y) >= lookahead_dist_;})->pose;double linear_vel, angular_vel;// If the goal pose is in front of the robot then compute the velocity using the pure pursuit algorithm// else rotate with the max angular velocity until the goal pose is in front of the robotif (goal_pose.position.x > 0) {auto curvature = 2.0 * goal_pose.position.y /(goal_pose.position.x * goal_pose.position.x + goal_pose.position.y * goal_pose.position.y);linear_vel = desired_linear_vel_;angular_vel = desired_linear_vel_ * curvature;} else {linear_vel = 0.0;angular_vel = max_angular_vel_;}// Create and publish a TwistStamped message with the desired velocitygeometry_msgs::msg::TwistStamped cmd_vel;cmd_vel.header.frame_id = pose.header.frame_id;cmd_vel.header.stamp = clock_->now();cmd_vel.twist.linear.x = linear_vel;cmd_vel.twist.angular.z = max(-1.0 * abs(max_angular_vel_), min(angular_vel, abs(max_angular_vel_)));return cmd_vel;
}

  剩下的方法虽然没有使用,但是必须进行重写。根据规定,我们确实进行了重写,但是将它们保留为空。

2- 导出控制器插件

  现在我们已经创建了自定义的控制器,我们需要导出我们的控制器插件,这样它才能被控制器服务器看到。插件是在运行时加载的,如果它们不可见,那么我们的控制器服务器就无法加载它们。在ROS 2中,导出和加载插件是由pluginlib来处理的。
  回到我们的教程,nav2_pure_pursuit_controller::PurePursuitController 类是以动态方式加载的,作为 nav2_core::Controller 的派生类。

  • 1.要导出该控制器,我们需要提供两行代码
#include "pluginlib/class_list_macros.hpp"
PLUGINLIB_EXPORT_CLASS(nav2_pure_pursuit_controller::PurePursuitController, nav2_core::Controller)

  请注意,它需要pluginlib来导出插件的类。Pluginlib 会提供宏PLUGINLIB_EXPORT_CLASS,它负责完成导出工作。
  将这两行代码放在文件末尾是一种良好的实践,但从技术上讲,你也可以将其放在文件的顶部。

  • 2.下一步是在包的根目录中创建插件的描述文件。例如,在我们的教程包中创建pure_pursuit_controller_plugin.xml文件。该文件包含以下信息:
    library path: Plugin’s library name and its location.
    class name: Name of the class.
    class type: Type of class.
    base class: Name of the base class.
    description: Description of the plugin.
<library path="nav2_pure_pursuit_controller"><class type="nav2_pure_pursuit_controller::PurePursuitController" base_class_type="nav2_core::Controller"><description>This is pure pursuit controller</description></class>
</library>
  • 3.下一步是使用CMakeLists.txt导出插件,使用 CMake 函数pluginlib_export_plugin_description_file()。该函数将插件描述文件安装到share目录,并设置ament索引以使其可被发现。
pluginlib_export_plugin_description_file(nav2_core pure_pursuit_controller_plugin.xml)
  • 4 插件描述文件还应添加到package.xml中。
<export><build_type>ament_cmake</build_type><nav2_core plugin="${prefix}/pure_pursuit_controller_plugin.xml" />
</export>
  • 5.编译后,它应该被注册了。接下来,我们将使用这个插件。

3- 通过params文件传递插件名称

要启用该插件,我们需要修改nav2_params.yaml文件,如下所示:

controller_server:ros__parameters:controller_plugins: ["FollowPath"]FollowPath:plugin: "nav2_pure_pursuit_controller::PurePursuitController"debug_trajectory_details: Truedesired_linear_vel: 0.2lookahead_dist: 0.4max_angular_vel: 1.0transform_tolerance: 1.0

  在上面的代码片段中,你可以看到我们将nav2_pure_pursuit_controller/PurePursuitController控制器映射到其id FollowPath。为了传递插件特定的参数,我们使用了<plugin_id>.<plugin_specific_parameter>的格式。

4- 运行纯追踪控制器插件

  使用启用了 Nav2 的 Turtlebot3 仿真。如何运行它的详细说明写在了Getting Started中。下面是一个快捷命令:

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

然后转到 RViz,在顶部点击“2D姿势估计”按钮,并根据“入门指南”中的描述,在地图上指向位置。机器人将在地图上进行定位,然后点击“Nav2目标”,并点击您希望机器人导航到的姿势。之后,控制器将使机器人沿着全局路径行进。

相关文章:

编写 navigation2 控制器插件

简介 本教程展示了如何创建自己的控制器插件。在本教程中&#xff0c;我们将基于这篇论文实现纯追踪路径跟踪算法。建议您阅读该论文。   注意&#xff1a;本教程基于 Nav2 堆栈中以前存在的简化版本的 Regulated Pure Pursuit 控制器。您可以在此处找到与本教程相匹配的源代…...

计算机网络 第六章应用层

文章目录 1 应用层功能概述2 网络应用模型&#xff1a;客户服务器(CS)3 网络应用模型&#xff1a;PeerToPeer(P2P)4 域名和域名系统5 常见域名解析服务器6 两种域名解析过程7 什么是FTP8 FTP的工作原理9 EMail的组成 1 应用层功能概述 2 网络应用模型&#xff1a;客户服务器(CS…...

人工智能领域CCF推荐国际学术刊物最新目录(全)

2021年1月&#xff0c;CCF决定启动新一轮中国计算机学会推荐国际学术会议和期刊目录调整工作并委托CCF学术工作委员会组织实施。 2023年3月8日, 中国计算机学会正式发布了2022版《中国计算机学会推荐国际学术会议和期刊目录》(以下简称《目录》) 。 相较于上一版目录&#xff0…...

实现基于 Azure DevOps 的数据库 CI/CD 最佳实践

数据库变更一直是整个应用发布过程中效率最低、流程最复杂、风险最高的环节&#xff0c;也是 DevOps 流程中最难以攻克的阵地。那我们是否能在具体的 CI/CD 流程中&#xff0c;像处理代码那样处理数据库变更呢&#xff1f; DORA 调研报告 DORA&#xff08;DevOps Research &am…...

上海实习小记

8月3日入职10月27日离职&#xff0c;原本还想做满3个月再走&#xff0c;可惜公司提早要迁到成都&#xff0c;就只好 离职了回学校了。在博客随便写写记录一下这几个月的生活吧&#xff0c;想到哪里写到哪里 实习的公司是一个小公司&#xff0c;开发一款类似于咸鱼之王的游戏&am…...

uniapp实现路线规划

UniApp是一个基于Vue.js框架开发的跨平台应用开发框架&#xff0c;可以同时构建iOS、Android、H5等多个平台的应用。它使用了基于前端技术栈的Web开发方式&#xff0c;通过编写一套代码&#xff0c;即可在不同平台上运行和发布应用。 UniApp具有以下特点&#xff1a; 跨平台开…...

飞利浦双串口51单片机485网关

主要功能将PC端的数据接收下来&#xff0c;分发到不同的设备&#xff0c;也是轮询设备数据读取回来&#xff0c;打包回传到PC端&#xff0c;数据包包头包尾识别&#xff0c;数据校验&#xff0c;接收超时处理&#xff0c;将协议结构化处理&#xff0c;协议的改动不需要改动程序…...

生态扩展:Flink Doris Connector

生态扩展&#xff1a;Flink Doris Connector 官网地址&#xff1a; https://doris.apache.org/zh-CN/docs/dev/ecosystem/flink-doris-connector flink的安装&#xff1a; tar -zxvf flink-1.16.0-bin-scala_2.12.tgz mv flink-1.16.0-bin-scala_2.12.tgz /opt/flinkflink环境…...

HarmonyOS(二)—— 初识ArkTS开发语言(上)之TypeScript入门

前言 Mozilla创造了JS&#xff0c;Microsoft创建了TS&#xff0c;而Huawei进一步推出了ArkTS。因此在学习使用ArkTS前&#xff0c;需要掌握基本的TS开发技能。 ArkTS介绍 ArkTS是HarmonyOS优选的主力应用开发语言。它在TypeScript&#xff08;简称TS&#xff09;的基础上&am…...

从零开始实现神经网络(一)_NN神经网络

参考文章&#xff1a;神经网络介绍 一、神经元 这一神经网络的基本单元&#xff0c;神经元接受输入&#xff0c;对它们进行一些数学运算&#xff0c;并产生一个输出。 这里有三步。 首先&#xff0c;将每个输入&#xff08;X1&#xff09;乘以一个权重&#xff1a; 接下来&…...

C语言 每日一题 Day10

1.使用函数判断完全平方数 本题要求实现一个判断整数是否为完全平方数的简单函数。 函数接口定义&#xff1a; int IsSquare(int n); 其中n是用户传入的参数&#xff0c;在长整型范围内。如果n是完全平方数&#xff0c;则函数IsSquare必须返回1&#xff0c;否则返回0。 代码实…...

C++继承——矩形和长方体

Rectangle矩形类 /*矩形类*/ class Rectangle { private:double L 0;double W 0; public:Rectangle() default;Rectangle(double a, double b);double GetArea(); /*矩形面积*/double GetGirth(); /*矩形周长*/ }; /*构造函数*/ Rectangle::Rectangle(double a, double b) …...

代码随想录打卡第五十八天|● 583. 两个字符串的删除操作 ● 72. 编辑距离

583. 两个字符串的删除操作 题目&#xff1a; 给定两个单词 word1 和 word2 &#xff0c;返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字符串中的一个字符。 题目链接&#xff1a; 583. 两个字符串的删除操作 解题思路&#xff1a; dp数组的含义&am…...

面试流程之——程序员如何写项目经验

在简历中介绍IT项目经验&#xff0c;你可以遵循以下步骤&#xff1a; 明确项目目标&#xff1a;首先&#xff0c;清晰地阐述项目的目标。这可以是提升某个软件的性能&#xff0c;改进某个系统的用户界面&#xff0c;或者增加某款产品的功能。让读者了解你的工作与项目的整体目…...

框架安全-CVE 漏洞复现DjangoFlaskNode.jsJQuery框架漏洞复现

目录 服务攻防-框架安全&CVE复现&Django&Flask&Node.JS&JQuery漏洞复现中间件列表介绍常见语言开发框架Python开发框架安全-Django&Flask漏洞复现Django开发框架漏洞复现CVE-2019-14234&#xff08;Django JSONField/HStoreField SQL注入漏洞&#xff…...

基于SSM的理发店管理系统

基于SSM的理发店管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringSpringMVCMyBatis工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 公告信息 管理员界面 用户界面 摘要 基于SSM&#xff08;Spring、Spring MVC、…...

2.Spark的工作与架构原理

概述 目标&#xff1a; spark的工作原理spark数据处理通用流程rdd 什么是rddrdd 的特点 spark架构 spark架构相关进程spark架构原理 spark的工作原理 spark 的工作原理&#xff0c;如下图 图中中间部分是spark集群&#xff0c;也可以是基于 yarn 的&#xff0c;图上可以…...

qt-C++笔记之带有倒计数显示的按钮,计时期间按钮锁定

qt-C笔记之带有倒计数显示的按钮&#xff0c;计时期间按钮锁定 code review! 文章目录 qt-C笔记之带有倒计数显示的按钮&#xff0c;计时期间按钮锁定1.运行2.main.cc3.main.pro 1.运行 2.main.cc 代码 #include <QApplication> #include <QPushButton> #includ…...

HTML全局属性(global attribute)有哪些?

HTML全局属性是指在HTML元素上可用的基本属性&#xff0c;它们适用于所有HTML元素。以下是一些常见的HTML全局属性&#xff1a; 1&#xff1a;class&#xff1a;为元素指定一个或多个类名&#xff0c;用于与CSS样式表关联。 2&#xff1a;id&#xff1a;:为元素指定唯一的标识…...

MyBatis-Plus返回getOne返回null疑惑

getOne返回null 问题描述分析过程总结 问题描述 在数据库建了一张表主要包括两个字段master_id和slave_id;主要的额外字段max_lots 默认值是null&#xff1b; 当调用getOne进行查询结果是null&#xff0c;但实际情况是数据库时应该返回值的&#xff1b; AotfxMasterSlave ex…...

4道高频面试题,吃透时间复杂度(递归_堆_贪心_快排)

4道高频面试题&#xff0c;吃透时间复杂度&#xff08;递归/堆/贪心/快排&#xff09; 前言&#xff1a;时间复杂度是算法面试的“必考题”&#xff0c;也是区分初级与中级开发者的核心考点。很多开发者能写出正确的算法代码&#xff0c;却无法清晰、严谨地分析其时间复杂度&am…...

Agent自治宣言:当智能体要求带薪休假时的法律困境

一个假设引发的现实思辨想象这样一个场景&#xff1a;在一个高度自动化的软件测试团队中&#xff0c;一个名为“TestMaster-AI”的智能体经过数月的连续工作&#xff0c;突然通过内部系统向项目经理提交了一份申请&#xff1a;“根据我的连续运行时长和学习迭代次数&#xff0c…...

私有化视频会议系统/私有化视频会议解决方案EasyDSS技术架构解析与应用实践

在数字化转型的浪潮中&#xff0c;视频会议已成为政企日常协作的核心纽带&#xff0c;但公有云会议平台的数据安全隐患、合规性短板&#xff0c;始终是政务、金融、军工等涉密领域的心头之患。EasyDSS私有化视频会议系统&#xff0c;以数据自主可控为核心&#xff0c;融合全场景…...

手机摄影党必看!用Flare7K数据集原理改善夜间拍摄(华为/iPhone实测)

手机摄影党必看&#xff01;用Flare7K数据集原理改善夜间拍摄&#xff08;华为/iPhone实测&#xff09; 夜间拍摄时&#xff0c;你是否经常遇到这样的困扰&#xff1a;路灯变成模糊的光团&#xff0c;霓虹灯周围出现奇怪的彩虹条纹&#xff0c;或是画面中突然多出几条不明来源的…...

告别重复编码:用快马AI为你的.NET项目自动生成高效工具类与模板

今天想和大家分享一个.NET开发中的效率提升小技巧——如何用自动化工具快速生成常用工具类代码。作为一个经常需要重复编写类似功能的后端开发者&#xff0c;我发现合理使用代码生成工具可以节省大量时间&#xff0c;让我们把精力集中在更有价值的业务逻辑上。 分页响应类的设…...

西门子S7-1200的PID三兄弟:PID_Compact、PID_3Step、PID_Temp到底该怎么选?看完这篇不再纠结

西门子S7-1200 PID三兄弟实战选型指南&#xff1a;从原理到场景化决策 在工业自动化领域&#xff0c;温度、压力和流量等过程变量的精确控制始终是核心挑战。西门子S7-1200 PLC提供的三种PID控制指令——PID_Compact、PID_3Step和PID_Temp&#xff0c;就像三位各有所长的技术专…...

产品经理开需求评审会议2026年这5款会议语音转文字工具 帮你节省90会议纪要整理时间

做了5年产品经理&#xff0c;谁懂啊&#xff0c;每周三四场需求评审会&#xff0c;自己记笔记跟不上&#xff0c;转头leader就让你出整理好的带待办的纪要&#xff0c;漏一个需求点就要背锅&#xff1b;之前录了音自己逐字转&#xff0c;1小时的会我要整理2小时&#xff0c;经常…...

STM32F4项目实战:用INA219给锂电池做个“智能管家”(附完整代码)

STM32F4项目实战&#xff1a;用INA219打造高精度锂电池监控系统 锂电池作为便携式设备的能量来源&#xff0c;其状态监控直接影响设备可靠性和用户体验。传统电压检测法误差高达20%&#xff0c;而采用TI的INA219电流传感器配合STM32F4系列MCU&#xff0c;可实现0.5%精度的充放电…...

BLIP-2:如何通过Q-Former桥接冻结视觉与大语言模型实现高效多模态预训练

1. BLIP-2为什么能成为多模态预训练的里程碑 第一次看到BLIP-2论文时&#xff0c;最让我惊讶的是它用如此"简单"的方式解决了多模态预训练的两个核心痛点。传统方法就像要求一个厨师同时精通中餐和西餐&#xff0c;而BLIP-2的创新在于让中餐主厨和西餐主厨各司其职&a…...

告别重复造轮子:用快马AI一键生成高效开发技能工具库

告别重复造轮子&#xff1a;用快马AI一键生成高效开发技能工具库 作为一名前端开发者&#xff0c;我经常需要重复编写一些基础功能代码。每次新项目开始&#xff0c;都要重新写表单验证、日期格式化这些轮子&#xff0c;既浪费时间又容易出错。最近发现InsCode(快马)平台的AI代…...