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

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...