当前位置: 首页 > 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…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...