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

【ROS】航点导航功能

【ROS】航点导航功能

  • 前言
  • 航点导航中的 Action 编程接口
    • 什么是 Action 通信?
  • 航点导航的 Action 节点的实现
  • 导航目标点发布节点
    • 编写节点文件
    • 测试节点
  • 航点导航插件:`waterplus_map_tools`
    • 安装方法
    • 航点设置、保存与测试
      • 1. 设置航点
      • 2. 保存航点
      • 3. 航点自动导航测试
  • 集成航点导航插件到导航 launch 文件中
    • 修改 launch 文件,集成航点导航插件
    • 测试流程
  • 自定义 `wp_navi_server` 的航点发布接口节点
    • 创建节点文件
    • 测试节点

前言

在实际的 ROS 导航应用中,我们不可能始终依赖 RViz 手动设置导航目标点。RViz 设置目标点仅适用于测试或调试阶段。在复杂任务或自动化流程中,导航目标点的发布应由专门的程序节点负责。

因此,本节将实现一个自定义的 Action 接口,用于发布导航目标点,并介绍一个实用的插件工具,帮助我们更高效地开发航点导航功能。

我的环境:
本教程使用的环境是:实体 ROS 小车,Ubuntu 18.04,ROS1 Melodic

参考资料:

  • ROS导航系统 | Action 编程接口
  • ROS 坐标导航的 Python 编程实现
  • 一款开源的 ROS 航点导航插件
  • ROS 航点导航插件的集成和启动
  • ROS 航点导航功能的 Python 实现

航点导航中的 Action 编程接口

推荐阅读以下视频以更深入了解:

  • ROS导航系统 | Action 编程接口

在智能车导航的测试阶段,我们常用 RViz 手动发送导航点 来进行路径测试。但在实际应用中,不可能每次都手动发点来控制机器人。为了实现自主导航,就需要使用 ROS 官方推荐的 Action 编程接口 来通过代码控制导航过程。


什么是 Action 通信?

Action 是 ROS 中的一种通信机制,和话题(Topic)不同:

  • 话题通信:是单向通信,一个节点发布,另一个节点订阅,不能实现实时反馈。
  • Action 通信:是双向通信,包含**客户端(Client)服务端(Server)**两部分。

在 ROS 导航系统中的应用

以 ROS 导航系统为例:

  • move_base 是 Action 的服务端(Server),负责实际的导航控制;
  • 我们自己写的程序是客户端(Client),向 move_base 发送导航目标点(包括位置和朝向);

Action 通信的优势在于:

  • 支持反馈:客户端可以实时接收到服务端的反馈,比如“导航进度 10%、50%、到达目标”等;
  • 支持取消任务:如果中途想停止导航,可以发送取消请求;
  • 支持超时和失败返回:如果导航失败,客户端也能及时收到失败的消息。

Action 通信与 Service 通信的区别

虽然 Action 和 Service 都属于“请求-响应”机制,都包含客户端和服务端,但两者的适用场景和功能不同:

特性Service(服务)Action(动作)
适用场景短时间、快速完成的任务长时间执行、需要过程反馈的任务
是否支持反馈
是否支持取消任务
通信模式一次请求、一次响应,完成后即断开请求后可持续反馈,直到完成或被取消

类比理解

  • Service 就像你去便利店买东西,提出请求后立即完成,一次性交互,不能中途更改。
  • Action 更像是点外卖,下单后骑手配送过程中你可以查看实时进度,也可以取消订单,并在
    最后收到完成或失败的结果。

航点导航的 Action 节点的实现

该部分内容建议参考以下视频:

  • ROS 坐标导航的 Python 编程实现
    action借点的实现分为三部,
    1.编写借点文件
    2.给借点文件添加可执行权限
    3.运行借点文件

导航目标点发布节点

该部分内容建议参考以下视频:

  • ROS 坐标导航的 Python 编程实现

编写节点文件

我们先在功能包的 scripts 文件夹下新建一个用于发送航点导航目标的客户端节点,文件名为 nav_client.py,内容如下:

#!/usr/bin/env python3
# coding=utf-8import rospy
import actionlib
# 导入 move_base action 需要的消息类型
from move_base_msgs.msg import MoveBaseAction, MoveBaseGoalif __name__ == "__main__":# 初始化 ROS 节点,节点名为 "nav_client"rospy.init_node("nav_client")# 创建一个 SimpleActionClient,用于与名为 'move_base' 的 action 服务器通信# Action 类型是 MoveBaseActionac = actionlib.SimpleActionClient('move_base', MoveBaseAction)# 等待 action 服务器启动并准备好rospy.loginfo("等待 move_base action 服务器...")ac.wait_for_server()rospy.loginfo("move_base action 服务器已连接!")# 创建一个 MoveBaseGoal 消息,用于设置导航目标goal = MoveBaseGoal()# 设置目标姿态 (pose) 的 header 信息# 设置 frame_id 为 "map",表示目标坐标是基于 map 坐标系的goal.target_pose.header.frame_id = "map"# 设置 timestamp 为当前 ROS 时间,这是一个好的实践,确保消息的新鲜度goal.target_pose.header.stamp = rospy.Time.now() # 设置目标位置 (position)goal.target_pose.pose.position.x = -3.0goal.target_pose.pose.position.y = 2.0goal.target_pose.pose.position.z = 0.0 # 通常在2D导航中 z 设为 0# 设置目标方向 (orientation),使用四元数表示goal.target_pose.pose.orientation.x = 0.0goal.target_pose.pose.orientation.y = 0.0goal.target_pose.pose.orientation.z = 0.0# 设置 w 为 1.0,当 x, y, z 都为 0 时,(0,0,0,1) 代表没有旋转,即朝向 map 坐标系的 +X 方向goal.target_pose.pose.orientation.w = 1.0 rospy.loginfo("开始导航,发送目标到 (-3.0, 2.0) ...") # 将目标发送给 action 服务器ac.send_goal(goal)# 等待 action 服务器执行完目标,直到返回结果rospy.loginfo("等待导航结果...")ac.wait_for_result()# 获取最终的导航状态# GoalStatus.SUCCEEDED 表示导航成功到达目标if ac.get_state() == actionlib.GoalStatus.SUCCEEDED:rospy.loginfo("导航成功!机器人已到达目标点。")else:# 如果状态不是 SUCCEEDED,则认为导航失败# 可能的原因包括:目标不可达、机器人被困、操作被取消/抢占等rospy.loginfo("导航失败。机器人未能到达目标点。") 

测试节点

1. 添加可执行权限

进入脚本所在目录,使用如下命令赋予执行权限:

chmod +x nav_client.py

执行 ls 时如果看到 nav_client.py 显示为绿色,则说明权限设置成功。

2. 测试节点功能

步骤一:启动导航功能

roslaunch nav_pkg nav.launch

步骤二:运行自定义发布节点

rosrun nav_pkg nav_client.py

观察终端输出及 RViz 中的导航过程,即可验证功能是否正常。


航点导航插件:waterplus_map_tools

该部分建议参考以下视频讲解:

  • 一款开源的 ROS 航点导航插件

在上一节中,我们已经实现了基础的单点导航功能。
但存在一个问题:导航目标点需要手动通过坐标设置,无法直接在地图上选点,操作繁琐且不直观。

为了解决这个问题,我们可以使用一款开源工具插件:waterplus_map_tools
该工具可以直接在 RViz 中可视化选点,并实现航点的保存与自动巡航等功能,非常适合用于测试或比赛中的航点导航。

GitHub 项目地址:

  • Github - waterplus_map_tools
    详细使用说明见其项目下的 README 文档。

安装方法

  1. 在工作空间的 src 目录下克隆项目:

    git clone https://github.com/6-robot/waterplus_map_tools.git
    
  2. 根据你的 ROS 版本安装对应的依赖:

    ~/lby_ws/src/waterplus_map_tools/scripts/install_for_melodic.sh
    
  3. 回到工作空间根目录进行编译:

    cd ~/lby_ws
    catkin_make
    

航点设置、保存与测试

1. 设置航点

首先启动航点设置工具:

roslaunch waterplus_map_tools add_waypoint.launch

注意:maps 文件夹下需要提前放置你已经建好的地图文件。

启动后,在 RViz 中点击上方工具栏中的 Add Waypoint(添加航点) 按钮:

添加航点图标

然后在地图上点击你想要添加航点的位置,按照顺序添加多个航点。

2. 保存航点

设置好航点后,使用以下命令将航点信息保存到本地:

rosrun waterplus_map_tools wp_saver

这样就完成了航点保存。如果你仅仅想通过该工具来“取点”,而不使用它自带的自动导航功能,到此为止即可。

3. 航点自动导航测试

使用以下命令测试机器人自动遍历所有航点:

rosrun waterplus_map_tools wp_nav_test

机器人将按照你设置的顺序依次前往各个航点,实现自动巡航。


集成航点导航插件到导航 launch 文件中

该部分建议参考以下视频讲解:

  • ROS 航点导航插件的集成和启动

在这里插入图片描述

waterplus_map_tools 功能包中提供了两个主要节点:wp_navi_serverwp_manager

  • wp_manager 节点:用于读取 waypoints.xml 文件中保存的航点信息(包括每个航点的坐标及朝向,即姿态信息);
  • wp_navi_server 节点:订阅一个“目标航点”的话题,并将目标姿态信息发送给 move_base 进行导航,同时发布导航结果话题。

我们可以自己编写一个节点,将目标航点编号发布到“目标航点”话题,wp_navi_server 订阅该话题,并根据其编号从 wp_manager 中读取相应的航点姿态,然后给 move_base发送导航目标点。

此外,该功能包中还包含一个测试节点 demo_map_tool,可用于快速测试航点导航功能。

修改 launch 文件,集成航点导航插件

我们在原有导航的 launch 文件中,添加以下两行启动节点:

<!-- 启动 wp_navi_server 节点 -->
<node pkg="waterplus_map_tools" type="wp_navi_server" name="wp_navi_server" output="screen" /><!-- 启动 wp_manager 节点 -->
<node pkg="waterplus_map_tools" type="wp_manager" name="wp_manager" output="screen" />

同时,将 rviz 的配置文件路径修改为 map_tools.rviz,这样便于在 RViz 中使用航点标记功能。

完整示例:

<launch><node pkg="move_base" type="move_base" name="move_base"><rosparam file="$(find wpb_home_tutorials)/nav_lider/costmap_common_params.yaml" command="load" ns="global_costmap"/><rosparam file="$(find wpb_home_tutorials)/nav_lider/costmap_common_params.yaml" command="load" ns="local_costmap"/><rosparam file="$(find wpb_home_tutorials)/nav_lider/global_costmap_params.yaml" command="load"/><rosparam file="$(find wpb_home_tutorials)/nav_lider/local_costmap_params.yaml" command="load"/><param name="base_global_planner" value="global_planner/GlobalPlanner" /><param name="base_local_planner" value="wpbh_local_planner/WpbhLocalPlanner" /><param name="controller_frequency" value="10" type="double"/></node><node pkg="map_server" type="map_server" name="map_server" args="$(find wpr_simulation)/maps/m" /><node pkg="amcl" type="amcl" name="amcl"/><!-- 启动 RViz,加载专用于 waterplus_map_tools 的配置 --><node pkg="rviz" type="rviz" name="rviz" args="-d $(find nav_pkg)/rviz/map_tools.rviz"/><!-- 集成 waterplus_map_tools 的两个核心节点 --><node pkg="waterplus_map_tools" type="wp_navi_server" name="wp_navi_server" output="screen" /><node pkg="waterplus_map_tools" type="wp_manager" name="wp_manager" output="screen" /></launch>

测试流程

  1. 启动导航 launch 文件:
roslaunch nav_pkg nav.launch
  1. 启动测试节点发送航点:
rosrun wpr_simulation demo_map_tool

测试过程中,demo_map_tool 会向目标话题发布航点编号,wp_navi_server 会调用 move_base 导航到目标点。


自定义 wp_navi_server 的航点发布接口节点

该部分建议参考以下视频讲解:

  • ROS 航点导航功能的 Python 实现

本节目标是实现一个自定义节点,向 wp_navi_server 所监听的航点话题发布目标航点编号,同时订阅导航结果,从而实现完整的航点导航控制。你可以将其看作是 demo_map_tool 的简化版或替代版本,后续也可以在此基础上扩展功能。

如下图所示,我们即将实现红框标注的节点: 它既要发布目标航点编号,又要订阅导航结果
在这里插入图片描述


创建节点文件

在你的导航功能包的 scripts 文件夹下,创建一个新文件:
wp_node.py,并写入以下代码:

#!/usr/bin/env python3
# coding=utf-8import rospy
from std_msgs.msg import String# 定义导航结果的回调函数
def NavResultCallback(msg):rospy.logwarn("导航结果 = %s", msg.data)if __name__ == "__main__":# 初始化 ROS 节点rospy.init_node("wp_node")# 创建发布者,发布航点编号到指定话题navi_pub = rospy.Publisher("/waterplus/navi_waypoint", String, queue_size=10)# 创建订阅者,接收导航结果res_sub = rospy.Subscriber("/waterplus/navi_result", String, NavResultCallback, queue_size=10)# 等待连接建立rospy.sleep(1)# 创建并发布航点编号 '1'navi_msg = String()navi_msg.data = '1'rospy.loginfo("发布导航目标:航点 %s", navi_msg.data)navi_pub.publish(navi_msg)# 进入回调监听循环rospy.spin()

测试节点

1. 添加可执行权限

进入脚本所在目录,使用如下命令赋予执行权限:

chmod +x wp_node.py

执行 ls 时如果看到 wp_node.py 显示为绿色,则说明权限设置成功。

2. 测试节点功能

步骤一:启动导航功能(包括 wp_navi_serverwp_manager

roslaunch nav_pkg nav.launch

步骤二:运行自定义发布节点

rosrun nav_pkg wp_node.py

观察终端输出及 RViz 中的导航过程,即可验证功能是否正常。

相关文章:

  • 解决vscode找不到Python自定义模块,报错No module named ‘xxx‘
  • 【Redis】Redis中的常见数据类型(一)
  • 通过爬虫方式实现头条号发布视频(2025年4月)
  • 常见的页面报错
  • Spring MVC 如何体现 Model-View-Controller 各自的职责?它们之间是如何协作的?
  • VS Code 远程连接服务器:Anaconda 环境与 Python/Jupyter 运行全指南。研0大模型学习(第六、第七天)
  • LicheeRV Nano 与Ubuntu官方risc-v 镜像混合
  • xss学习3之服务端session
  • 大数据开发知识1:数据仓库
  • Java表达式1.0
  • 相对路径和绝对路径解析
  • 遇到QT进程启动失败。被调用的程序丢失,或者您可能没有足够的权限来调用该程序。
  • 聊一聊接口测试后垃圾数据如何清理?
  • C语言状态字与库函数详解:概念辨析与应用实践
  • 【leetcode刷题日记】lc.152-乘积最大子数组
  • 念去去千里烟波,雾霭沉沉楚天阔
  • 大语言模型推理能力的强化学习现状理解GRPO与近期推理模型研究的新见解
  • 网络基础与 HTTP 协议
  • LeetCode第159题_至多包含两个不同字符的最长子串
  • Ubuntu下安装和卸载MySQL
  • 用了半年的洗衣机竟比马桶还脏,别再这样洗衣服了
  • 重点并不在于设计更聪明的机器,而在于开发宇宙技术的多样性
  • “30小时不够”,泽连斯基建议延长停火至30天
  • 菲律宾群岛地区发生5.6级地震,震源深度20千米
  • 2025年青年普法志愿者法治文化基层行活动启动
  • 吉林省文联党组书记、主席赵明接受纪律审查和监察调查