一,安装
Navigation工具包包含在 navigation
元功能包中。你可以通过以下命令安装:
sudo apt-get install ros-noetic-navigation
如果你使用的是其他ROS版本(如Melodic),将 noetic 替换为对应的版本名称(如 melodic)。
如果你只需要Navigation工具包中的部分功能包,可以单独安装。例如
sudo apt-get install ros-noetic-amcl ros-noetic-move-base ros-noetic-map-server
安装完成后,可以通过以下命令验证是否安装成功:
rospack find navigation
如果安装成功,会输出Navigation工具包的安装路径:
/opt/ros/noetic/share/navigation
注意:使用 sudo apt-get install ros-noetic-navigation
安装的Navigation工具包是二进制版本(即编译好的可执行文件),不包含源码。也就是说这种方式无法直接调整参数。
为了在使用Navigation时能够方便的调整参数,有两种解决方式:
1,创建新功能包
第一种方式是在sudo apt-get install ros-noetic-navigation后,在你创建的ROS工作空间中再创建一个导航工具包专门存放参数,这种方法允许你覆盖默认参数,而无需修改系统安装的Navigation工具包。具体方式如下:
一,创建功能包
cd ~/catkin_ws/src
catkin_create_pkg my_navigation_params
二,创建必要文件
在 my_navigation_params
功能包中,创建相关目录和文件。文件结构可以在篇尾下载百度网盘我的文件查看。
三,编辑功能包文件
package.xml
以下是我的xml文件内容:
<?xml version="1.0"?>
<package format="2">
<name>my_navigation_params</name>
<version>0.0.0</version>
<description>The ucar_nav package</description>
<!-- One maintainer tag required, multiple allowed, one person per tag -->
<!-- Example: -->
<!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
<maintainer email="jwliang@iflytek.com">iflytek</maintainer>
<!-- One license tag required, multiple allowed, one license per tag -->
<!-- Commonly used license strings: -->
<!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
<license>BSD</license>
<!-- Url tags are optional, but multiple are allowed, one per tag -->
<!-- Optional attribute type can be: website, bugtracker, or repository -->
<!-- Example: -->
<!-- <url type="website">http://wiki.ros.org/ucar_nav</url> -->
<!-- Author tags are optional, multiple are allowed, one per tag -->
<!-- Authors do not have to be maintainers, but could be -->
<!-- Example: -->
<!-- <author email="jane.doe@example.com">Jane Doe</author> -->
<!-- The *depend tags are used to specify dependencies -->
<!-- Dependencies can be catkin packages or system dependencies -->
<!-- Examples: -->
<!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
<!-- <depend>roscpp</depend> -->
<!-- Note that this is equivalent to the following: -->
<!-- <build_depend>roscpp</build_depend> -->
<!-- <exec_depend>roscpp</exec_depend> -->
<!-- Use build_depend for packages you need at compile time: -->
<!-- <build_depend>message_generation</build_depend> -->
<!-- Use build_export_depend for packages you need in order to build against this package: -->
<!-- <build_export_depend>message_generation</build_export_depend> -->
<!-- Use buildtool_depend for build tool packages: -->
<!-- <buildtool_depend>catkin</buildtool_depend> -->
<!-- Use exec_depend for packages you need at runtime: -->
<!-- <exec_depend>message_runtime</exec_depend> -->
<!-- Use test_depend for packages you need only for testing: -->
<!-- <test_depend>gtest</test_depend> -->
<!-- Use doc_depend for packages you need only for building documentation: -->
<!-- <doc_depend>doxygen</doc_depend> -->
<buildtool_depend>catkin</buildtool_depend>
<build_depend>nav_msgs</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
<build_export_depend>nav_msgs</build_export_depend>
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<exec_depend>nav_msgs</exec_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<!-- The export tag contains other, unspecified, tags -->
<export>
<!-- Other tools can request additional information be placed here -->
</export>
</package>
高亮显示代表有用的部分(未被注释的部分) ,以下给出解释:
- 第一行 <?xml version="1.0"?> 这是XML文件的声明,表示文件遵循XML 1.0标准。
- 第二行 <package format="2"> 定义这是一个ROS功能包,
format="2"
表示使用ROS的package.xml
格式版本2(这是ROS中最常用的格式)。 - 功能包基本信息:
<name>ucar_nav</name>
<version>0.0.0</version>
<description>The ucar_nav package</description>
<!-----
<name>:功能包的名称。必须是唯一的,通常与功能包的文件夹名称一致。
<version>:功能包的版本号。通常遵循语义化版本规范(如 1.0.0)。
<description>:功能包的简短描述,说明功能包的作用。
------->
- 维护者信息:<maintainer email="jwliang@iflytek.com">iflytek</maintainer>
-
许可证信息:<license>BSD</license>
-
<buildtool_depend>catkin</buildtool_depend> :声明构建工具依赖。
catkin
是ROS的构建系统,所有ROS功能包都必须依赖它。它提供了编译、链接和安装功能包的工具。 -
<build_depend>nav_msgs</build_depend> <build_depend>roscpp</build_depend> <build_depend>rospy</build_depend> <build_depend>std_msgs</build_depend> <!---- 声明构建时依赖。 nav_msgs:ROS中的一个标准消息包,专门用于导航相关的消息类型。提供与导航相关的消息类型(如地图、路径等)。在安装ROS时就已经包含在内。nav_msgs 提供了以下与导航相关的消息类型:OccupancyGrid:表示二维栅格地图,常用于SLAM和导航。Path:表示路径,包含一系列位姿(PoseStamped)。Odometry:表示里程计数据,包含机器人的位姿和速度。MapMetaData:表示地图的元数据(如分辨率、原点等)。 roscpp:ROS的C++客户端库,用于编写C++节点。 rospy:ROS的Python客户端库,用于编写Python节点。 std_msgs:ROS中的一个标准消息包,提供了许多基本的消息类型,例如字符串、整数、浮点数等。提供了以下常见的消息类型:std_msgs/String,std_msgs/Int8、std_msgs/Int16std_msgs/Float32、std_msgs/Float64等等 这些依赖在编译功能包时需要。例如,如果你的功能包使用了 nav_msgs 中的消息类型,或者调用了 roscpp 或 rospy 的API,就需要声明这些依赖。 ------>
-
<build_export_depend>nav_msgs</build_export_depend> <build_export_depend>roscpp</build_export_depend> <build_export_depend>rospy</build_export_depend> <build_export_depend>std_msgs</build_export_depend> <!--------- 声明导出依赖。 这些依赖会被传递给依赖当前功能包的其他功能包。例如,如果其他功能包依赖你的功能包,它们也会自动依赖 nav_msgs、roscpp 等。 ----------->
-
<exec_depend>nav_msgs</exec_depend> <exec_depend>roscpp</exec_depend> <exec_depend>rospy</exec_depend> <exec_depend>std_msgs</exec_depend> <!---------- 声明运行时依赖。 这些依赖在运行功能包时需要。例如,如果你的功能包在运行时使用了 nav_msgs 中的消息类型,或者调用了 roscpp 或 rospy 的API,就需要声明这些依赖。 ------------>
一般在package.xml文件中也要添加入如下依赖表示依赖move_base,amcl,map_server这些功能包(这些功能包包含了节点、库、消息类型和其他资源,用于实现特定的功能):
<exec_depend>move_base</exec_depend>
<exec_depend>amcl</exec_depend>
<exec_depend>map_server</exec_depend>
但是,如果你在launch文件中启动这三个节点,只要这些节点已经安装在系统中,ROS就能够找到并运行它们,而不需要在 package.xml
中显式声明依赖(,在ROS中,<node>
标签指定的节点(例如 move_base
、amcl
和 map_server
)会在运行时动态加载)。所以可以不添加这几个依赖。
CMakeLists.txt
CMakeLists.txt
文件是一个模板,用于配置和构建ROS功能包。大部分选项都被注释掉了,需要根据功能包的实际需求取消注释并修改。
主要功能包括:
-
定义项目名称和CMake版本。
-
查找Catkin和其他依赖。
-
生成消息、服务和动作。
-
配置Catkin包的导出信息。
-
声明和构建C++库和可执行文件。
-
安装文件。
-
添加测试。
我的CMakeLists.txt文件内容如下
cmake_minimum_required(VERSION 2.8.3)
project(my_navigation_params)
## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)
## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
nav_msgs
roscpp
rospy
std_msgs
)
## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)
## Uncomment this if the package has a setup.py. This macro ensures
## modules and global scripts declared therein get installed
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
# catkin_python_setup()
################################################
## Declare ROS messages, services and actions ##
################################################
## To declare and build messages, services or actions from within this
## package, follow these steps:
## * Let MSG_DEP_SET be the set of packages whose message types you use in
## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
## * In the file package.xml:
## * add a build_depend tag for "message_generation"
## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
## but can be declared for certainty nonetheless:
## * add a exec_depend tag for "message_runtime"
## * In this file (CMakeLists.txt):
## * add "message_generation" and every package in MSG_DEP_SET to
## find_package(catkin REQUIRED COMPONENTS ...)
## * add "message_runtime" and every package in MSG_DEP_SET to
## catkin_package(CATKIN_DEPENDS ...)
## * uncomment the add_*_files sections below as needed
## and list every .msg/.srv/.action file to be processed
## * uncomment the generate_messages entry below
## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
## Generate messages in the 'msg' folder
# add_message_files(
# FILES
# Message1.msg
# Message2.msg
# )
## Generate services in the 'srv' folder
# add_service_files(
# FILES
# Service1.srv
# Service2.srv
# )
## Generate actions in the 'action' folder
# add_action_files(
# FILES
# Action1.action
# Action2.action
# )
## Generate added messages and services with any dependencies listed here
# generate_messages(
# DEPENDENCIES
# nav_msgs# std_msgs
# )
################################################
## Declare ROS dynamic reconfigure parameters ##
################################################
## To declare and build dynamic reconfigure parameters within this
## package, follow these steps:
## * In the file package.xml:
## * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
## * In this file (CMakeLists.txt):
## * add "dynamic_reconfigure" to
## find_package(catkin REQUIRED COMPONENTS ...)
## * uncomment the "generate_dynamic_reconfigure_options" section below
## and list every .cfg file to be processed
## Generate dynamic reconfigure parameters in the 'cfg' folder
# generate_dynamic_reconfigure_options(
# cfg/DynReconf1.cfg
# cfg/DynReconf2.cfg
# )
###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if your package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES my_navigation_params
# CATKIN_DEPENDS nav_msgs roscpp rospy std_msgs
# DEPENDS system_lib
)
###########
## Build ##
###########
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
## Declare a C++ library
# add_library(${PROJECT_NAME}
# src/${PROJECT_NAME}/ucar_nav.cpp
# )
## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
# add_executable(${PROJECT_NAME}_node src/ucar_nav_node.cpp)
## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
# ${catkin_LIBRARIES}
# )
#############
## Install ##
#############
# all install targets should use catkin DESTINATION variables
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
## Mark executable scripts (Python etc.) for installation
## in contrast to setup.py, you can choose the destination
# install(PROGRAMS
# scripts/my_python_script
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
## Mark executables for installation
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html
# install(TARGETS ${PROJECT_NAME}_node
# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
## Mark libraries for installation
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html
# install(TARGETS ${PROJECT_NAME}
# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
# )
## Mark cpp header files for installation
# install(DIRECTORY include/${PROJECT_NAME}/
# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
# FILES_MATCHING PATTERN "*.h"
# PATTERN ".svn" EXCLUDE
# )
## Mark other files for installation (e.g. launch and bag files, etc.)
# install(FILES
# # myfile1
# # myfile2
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
# )
#############
## Testing ##
#############
## Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/test_ucar_nav.cpp)
# if(TARGET ${PROJECT_NAME}-test)
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)
cmake_minimum_required(VERSION 2.8.3)
project(my_navigation_params)
-
cmake_minimum_required
:指定CMake的最低版本要求(这里是2.8.3)。 -
project
:定义项目名称(这里是ucar_nav
)。
find_package(catkin REQUIRED COMPONENTS
nav_msgs
roscpp
rospy
std_msgs
)
find_package
:查找Catkin和其他依赖的功能包。
-
catkin
:ROS的构建系统。 -
nav_msgs
、roscpp
、rospy
、std_msgs
:功能包依赖的其他ROS功能包。
## Generate messages in the 'msg' folder
# add_message_files(
# FILES
# Message1.msg
# Message2.msg
# )
## Generate services in the 'srv' folder
# add_service_files(
# FILES
# Service1.srv
# Service2.srv
# )
## Generate actions in the 'action' folder
# add_action_files(
# FILES
# Action1.action
# Action2.action
# )
## Generate added messages and services with any dependencies listed here
# generate_messages(
# DEPENDENCIES
# nav_msgs
# std_msgs
# )
-
这些是注释掉的选项,用于生成ROS消息、服务和动作。
-
add_message_files
:添加自定义消息文件(.msg
)。 -
add_service_files
:添加自定义服务文件(.srv
)。 -
add_action_files
:添加自定义动作文件(.action
)。 -
generate_messages
:生成消息、服务和动作,并指定依赖。
-
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES my_navigation_params
# CATKIN_DEPENDS nav_msgs roscpp rospy std_msgs
# DEPENDS system_lib
)
-
catkin_package
:配置Catkin包的导出信息。-
INCLUDE_DIRS
:指定头文件目录。 -
LIBRARIES
:指定生成的库。 -
CATKIN_DEPENDS
:指定Catkin依赖的功能包。 -
DEPENDS
:指定系统依赖。
-
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
include_directories
:指定头文件的搜索路径。
-
${catkin_INCLUDE_DIRS}
:包含Catkin和其他依赖功能包的头文件路径。
2,Git 下载源码
cd ~/catkin_ws/src
git clone https://github.com/ros-planning/navigation.git
Navigation工具包依赖一些其他ROS功能包,可以使用 rosdep
安装依赖:
cd ~/catkin_ws
rosdep install --from-paths src --ignore-src -r -y
二,Navigation核心功能包原理
了解基本原理对于调节参数有很大的帮助
ROS Navigation工具包(Navigation Stack)是一个模块化的系统,由多个功能包和节点组成,共同实现机器人的自主导航功能。
1,amcl(自适应蒙特卡罗定位)
AMCL(Adaptive Monte Carlo Localization)是 ROS 中用于机器人在已知地图中进行自定位的功能包,基于自适应蒙特卡洛定位算法,该算法是蒙特卡洛定位(MCL)方法的一种升级版
粒子滤波是 AMCL 的核心技术。它实现定位的大体过程如下:
- 初始化粒子:在定位开始前,在状态空间中随机生成大量的粒子(初始时权重通常是相等的。)。这些粒子的分布应该尽可能地覆盖机器人可能出现的位置和姿态空间。例如,在一个已知地图的环境中,可以根据地图的范围和机器人的初始估计位置,均匀或按照一定的概率分布在地图上撒下粒子,每个粒子都代表着机器人可能的状态,包括位置(x, y)和姿态(角度)等信息。
- 重要性采样:根据机器人的运动模型,结合上一时刻粒子的状态和当前的控制输入(如里程计信息),预测当前时刻每个粒子可能的新状态。例如,如果机器人根据里程计数据向前移动了一定距离并旋转了一定角度,那么每个粒子也会按照相应的运动模型进行位置和姿态的更新。这个过程实际上是对粒子进行重要性采样,使得粒子能够根据机器人的运动趋势进行分布。
- 权重估计:利用传感器测量信息来计算每个粒子的权重。将粒子所代表的状态下预测的传感器观测值与实际的传感器测量值进行比较,两者之间的差异越小,说明该粒子与实际情况越接近,其权重就越高;反之,权重越低。以激光雷达为例,粒子所在位置根据地图信息模拟出的激光扫描数据与实际激光雷达扫描数据的匹配程度,可作为计算粒子权重的依据。通常使用概率分布函数来量化这种匹配程度,如基于正态分布的误差计算,以得到每个粒子的权重。
- 重采样:根据粒子的权重进行重采样操作,目的是淘汰掉权重较低的粒子,保留权重较高的粒子,并复制一些权重高的粒子,以生成新的粒子集。这样可以使新的粒子集更集中地分布在机器人可能的真实状态附近。重采样的方法有多种,如轮盘赌法、系统重采样法等。例如,轮盘赌法就是按照粒子权重占总权重的比例来确定每个粒子被选中的概率,然后通过随机抽样的方式选择粒子,组成新的粒子集合。
- 位姿估计:经过多次迭代的重要性采样、权重更新和重采样后,粒子会逐渐收敛到机器人的真实位置附近。此时,可以根据粒子的分布来估计机器人的位姿。常见的方法是计算所有粒子的加权平均位置和姿态,或者直接选择权重最高的粒子的状态作为机器人的估计位姿。这个估计位姿就是粒子滤波算法最终输出的机器人定位结果。
- 持续迭代:随着机器人的不断运动和传感器数据的持续获取,粒子滤波算法会不断重复上述步骤,即根据新的运动信息进行粒子的预测和根据新的传感器数据进行权重更新与重采样,从而实时地更新机器人的位姿估计,使其能够适应环境的变化和机器人的运动,实现精准定位。通过不断地迭代优化,粒子滤波能够在复杂的环境中,即使存在噪声和不确定性的情况下,也能较为准确地估计机器人的位置和姿态。
自适应采样:这是 AMCL 的一个关键优化机制。通过计算粒子权重分布的方差或熵来估计机器人当前定位的不确定性。当机器人位姿的不确定性较大时,如初始定位阶段或粒子分布发散阶段,增加粒子数量以覆盖更大的搜索空间;当位姿的不确定性较小时,如定位已收敛,减少粒子数量以节省计算资源。根据不确定性的大小,动态改变粒子的数量,并通过重采样算法生成新的粒子集,使其与当前定位精度需求相匹配。
2,map_server
map_server主要用于加载和发布地图数据。
map_server
通常支持两种常见的地图数据格式(我的文件中存放地图的文件maps):
- 图像文件(如
.pgm
、.png
):用于存储地图的占用信息,图像中的每个像素代表地图中的一个小网格,不同的像素值表示该网格的占用状态,例如白色表示空闲,黑色表示占用,灰色表示未知。 - YAML 配置文件(如
.yaml
):用于存储地图的元数据,包括地图图像文件的路径、地图分辨率(每个像素代表的实际距离)、地图的原点位置等信息。
当启动 map_server
节点时,它会执行以下初始化步骤:
- 读取 YAML 配置文件:节点首先会读取指定的 YAML 配置文件,从中获取地图图像文件的路径、地图分辨率、原点位置等关键信息。
- 加载地图图像:根据 YAML 文件中指定的图像文件路径,节点会加载相应的地图图像文件,并将其转换为内存中的地图数据结构。在这个过程中,节点会将图像中的像素值转换为对应的占用概率值。
map_server
使用 nav_msgs/OccupancyGrid
消息类型来表示地图数据。OccupancyGrid
消息包含以下重要字段:
header
:包含消息的时间戳和坐标系信息。info
:包含地图的元数据,如地图的宽度、高度、分辨率、原点位置等。data
:一个一维数组,存储地图中每个网格的占用概率值,取值范围为 -1(未知)、0(空闲)到 100(占用)。
初始化完成后,map_server
会通过 ROS 话题发布地图数据:
/map
话题:发布nav_msgs/OccupancyGrid
类型的消息,将地图数据广播给其他需要使用地图的节点,如导航节点、定位节点等。可以订阅此话题来显示地图。/map_metadata
话题:发布nav_msgs/MapMetaData
类型的消息,包含地图的元数据信息,如分辨率、原点位置等。其他节点可以通过订阅这个话题来获取地图的基本信息。
虽然 map_server
主要用于静态地图的加载和发布,但在某些情况下,也可以支持地图的动态更新。例如,通过接收其他节点发布的地图更新消息,map_server
可以对内存中的地图数据进行更新,并重新发布更新后的地图。
补充:代价地图
(1)基本概念
代价地图是ROS Navigation中的一个核心数据结构,用于表示机器人周围环境中的障碍物和可行走区域。它是一个二维网格地图,每个网格单元(cell)都有一个代价值(cost),用于表示该位置的“成本”或“风险”。代价值越高,表示该位置越不适合机器人通过。代价地图的主要作用是帮助机器人规划路径,实现实时避障,区分可行走区域和障碍物区域
(2)类型(全局和局部)
在ROS Navigation中,代价地图分为两种主要类型:
(1)全局代价地图(Global Costmap)
-
作用:用于全局路径规划(如A*、Dijkstra算法)。
-
范围:覆盖整个环境,基于静态地图(通常是通过SLAM生成的map)。
-
特点:
-
静态地图是基础,但可以结合传感器数据动态更新。
-
主要用于规划从起点到目标点的全局路径。
-
(2)局部代价地图(Local Costmap)
-
作用:用于局部路径规划和实时避障(如DWA算法)。
-
范围:仅覆盖机器人周围的局部区域。
-
特点:
-
基于传感器数据(如激光雷达、深度相机)实时更新。
-
主要用于处理动态障碍物和局部路径调整。
-
每个网格单元的代价值范围是0到255,具体含义如下:
(3)组成层
代价地图由多个“层”(Layers)组成,每层负责处理不同类型的信息。
(1)静态层(Static Layer)
-
基于静态地图(通常是SLAM生成的map)。
-
在全局代价地图中使用,表示环境中固定的障碍物。
(2)障碍物层(Obstacle Layer)
-
基于传感器数据(如激光雷达、深度相机)实时更新。
-
在局部代价地图中使用,用于检测动态障碍物。
(3)膨胀层(Inflation Layer)
-
在障碍物周围增加代价值,形成“安全缓冲区”。
-
防止机器人过于靠近障碍物,避免碰撞。
3,costmap_2d
costmap_2d
是 ROS Navigation 中用于处理二维代价地图的功能包
地图表示
costmap_2d
将地图表示为一个二维的网格数组,每个网格单元对应着实际环境中的一个小区域。网格数组中的每个元素存储着该区域的代价信息,代价越高,表示该区域对于机器人的通行越不利。同时,还会维护一些其他的属性,如是否被占用、是否是障碍物等。
地图更新
costmap_2d
会订阅机器人的传感器数据,如激光雷达、深度相机等发布的点云数据。当接收到新的传感器数据时,它会将传感器检测到的障碍物信息投影到二维代价地图上。例如,激光雷达扫描到的障碍物点会被转换为地图上对应的网格单元,并将这些单元标记为占用或设置相应的高代价。
根据机器人的运动状态,costmap_2d
会对地图进行相应的更新。比如,机器人移动到新的位置后,它周围的地图区域可能需要重新评估代价。如果机器人进入了一个之前未知的区域,该区域的地图会被初始化为默认的代价(通常是未知代价),然后随着传感器数据的不断输入逐渐更新。对于静态地图(已建完的地图)这个功能不使用
代价计算
对于检测到的障碍物,会在其周围的一定范围内设置较高的代价。通常采用膨胀算法,将障碍物实际占据的区域向外扩展一定的距离,在扩展区域内的网格单元都被赋予较高的代价,以确保机器人在规划路径时能够避开障碍物及其周围的危险区域。也就是我们上面提到的障碍物层
除了障碍物本身的代价,为了使机器人的路径规划更加平滑和安全,costmap_2d
还会对地图进行通货膨胀处理。这意味着即使是在没有直接检测到障碍物的区域,也会根据与障碍物的距离等因素设置一定的代价梯度。距离障碍物越近,代价越高,这样可以引导机器人在远离障碍物的区域选择路径。
分层结构
costmap_2d
采用分层的结构来管理地图信息,通常包括以下几种层:
- 静态地图层:用于存储静态的地图信息,如地图的边界、固定的障碍物等。这些信息在机器人运行过程中一般不会改变,可以从地图文件中加载得到。
- 障碍物层:主要负责根据传感器实时检测到的障碍物信息来更新地图。它会将传感器数据中的障碍物信息转换为地图上的代价信息,是动态更新地图的主要部分。
- 通货膨胀层:对障碍物层等其他层的代价进行通货膨胀处理,生成一个代价逐渐变化的区域,以引导机器人避开障碍物。
- 其他自定义层:根据具体的应用需求,可以添加其他自定义的层,如用于表示机器人足迹的层、用于表示目标区域的层等。每个层都有自己的更新策略和代价计算方法,最终这些层的代价会融合在一起,形成最终的代价地图,用于机器人的路径规划和导航。
4,global_planner
global_planner
是 ROS Navigation 中的全局路径规划功能包,其原理是基于搜索算法在给定的地图上找到一条从起始点到目标点的无碰撞路径,主要包括地图表示与搜索空间定义、路径搜索算法、路径优化等方面
地图表示与搜索空间
global_planner
使用costmap_2d
提供的二维代价地图作为基础。地图中的每个网格单元都有相应的代价,代表该位置对于机器人通行的难易程度。代价越高,说明该位置越难以通过,例如障碍物所在的网格单元代价就很高。
搜索空间通常是由地图中的一系列网格单元组成。规划器会在这个离散的搜索空间中寻找从起始点到目标点的路径。为了提高搜索效率,可能会对搜索空间进行一定的预处理,例如去除一些明显不可行的区域,或者将相邻的低代价区域合并为更大的搜索单元。
路径搜索算法
global_planner
通常采用一些经典的搜索算法来寻找路径,如 A算法、Dijkstra 算法等。以 A算法为例,它通过计算每个节点的估价函数f(n)=g(n)+h(n)来评估节点的优先级,其中g(n)是从起始点到节点n的实际代价,h(n)是从节点n到目标点的估计代价(启发式函数)。
算法从起始点开始,将其加入到一个开放列表中。然后,在每次迭代中,从开放列表中选择估价函数值最小的节点进行扩展,即检查它的相邻节点。如果相邻节点是未访问过的,并且不是障碍物,就将其加入到开放列表中,并计算其估价函数值。同时,记录每个节点的父节点,以便在找到目标点后能够回溯得到完整的路径。
这个过程不断重复,直到找到目标点或者开放列表为空(表示没有找到可行路径)。Dijkstra 算法与 A * 算法类似,但它没有启发式函数,只是单纯地计算从起始点到每个节点的最短路径代价,因此搜索效率可能相对较低,但在某些情况下可以保证找到全局最优路径。
路径优化
找到的初始路径可能不是最优的,或者在实际机器人运动中不够平滑。因此,global_planner
通常会对路径进行优化。一种常见的优化方法是路径平滑算法,它通过对路径上的点进行插值或者调整,使路径更加平滑,减少不必要的拐点和曲折,以便机器人能够更流畅地行驶。
另一种优化方式是考虑机器人的运动学和动力学约束。例如,根据机器人的最大转弯半径、加速度限制等因素,对路径进行调整,确保路径不仅在空间上是可行的,而且在机器人的运动能力范围内也是可执行的。
global_planner
与 ROS Navigation 中的其他组件密切协作。它从map_server
获取地图信息,从costmap_2d
获取实时更新的代价地图,以了解环境中的障碍物分布和通行代价。同时,它将规划好的路径发布给local_planner
,由local_planner
负责在局部范围内根据机器人的当前状态和实时传感器数据对路径进行进一步的细化和跟踪,实现机器人的实际导航。
5,dwa_local_planner
dwa_local_planner
(Dynamic Window Approach Local Planner)是 ROS Navigation 中用于局部路径规划和机器人控制的功能包,其原理是基于动态窗口概念,通过搜索机器人在当前状态下可能的运动轨迹,选择最优轨迹来实现机器人的局部导航。
动态窗口
在机器人运动规划里,机器人的运动状态通常用线速度 v 与角速度ω来描述。动态窗口就代表了在某一特定时刻,机器人在速度空间里能够达到的一组速度组合 (v, ω)。它是速度空间中的一个子集,所以可以把它视为一个速度集。它由机器人当前的速度、加速度限制以及时间间隔等因素决定。
动态窗口并非固定不变,而是依据机器人当前的运动状态、物理限制以及时间约束动态确定的
机器人当前的线速度 v 和角速度ω 也会对动态窗口产生影响。由于机器人存在加速度限制,它无法在瞬间从当前速度转变到最大或最小速度。所以,动态窗口会基于当前速度以及加速度限制,确定在短时间内能够达到的速度范围。
轨迹生成
在动态窗口内,dwa_local_planner
会生成一系列可能的运动轨迹。通常采用模拟机器人在不同速度组合下的运动来生成这些轨迹。
轨迹评价
6,nav_core
nav_core
是 ROS(机器人操作系统)中导航功能的核心框架,它为导航系统提供了一个标准化的接口和通用的架构,用于实现机器人的路径规划和控制。
nav_core
定义了一系列标准接口,包括BaseLocalPlanner
(局部路径规划器接口)、BaseGlobalPlanner
(全局路径规划器接口)和RecoveryBehavior
(恢复行为接口)等。这些接口规定了不同规划器和行为模块应具备的方法和功能,使得各种不同的路径规划算法和恢复策略能够以统一的方式集成到导航系统中。
基于 ROS 的插件机制,nav_core
允许在运行时动态加载不同的路径规划器和恢复行为插件。通过在配置文件中指定要使用的具体插件类,导航系统可以灵活地选择不同的算法实现,而无需修改核心代码(可以通过修改相关的yaml
参数来配置不同的算法和参数)。例如,可以根据具体的应用场景和机器人特性,选择不同的全局规划算法(如 A * 算法、Dijkstra 算法等)或局部规划算法(如dwa_local_planner
、teb_local_planner
等)来满足不同的导航需求。
在启动导航时,虽然通常不会直接显式地启动nav_core
节点,但nav_core
是导航系统的核心部分,相关的功能会在启动导航相关节点(如全局规划器节点、局部规划器节点等)时被间接调用和使用。这些节点基于nav_core
框架来实现具体的导航功能,所以nav_core
是导航系统中不可或缺的一部分,在导航启动过程中是会被加载和运行的。例如,当启动包含全局规划器和局部规划器的导航.launch 文件时,这些规划器节点会根据配置文件中指定的插件类型,加载nav_core
中相应的插件类,并调用nav_core
提供的接口来进行路径规划和控制等操作。
7,move_base
move_base
是 ROS(机器人操作系统)导航栈里的核心节点,其主要功能是接收目标点,然后综合全局路径规划和局部路径规划,指挥机器人安全且高效地移动到目标位置。
move_base
采用了分层规划与控制的架构,整体流程涵盖目标接收、全局路径规划、局部路径规划、运动控制以及异常处理等环节。具体流程如下:
- 目标接收:
move_base
通过订阅/move_base_simple/goal
话题来接收用户或者其他节点发布的目标位姿(目标位置和姿态)。一旦接收到目标,它就会启动路径规划与导航流程。 - 全局路径规划:
move_base
调用全局路径规划器(例如global_planner
或carrot_planner
),依据静态地图与当前机器人的位置,规划出一条从当前位置到目标位置的全局路径。全局路径规划器借助地图信息,运用搜索算法(像 A * 算法)来找出一条避开已知障碍物的路径。 - 局部路径规划:拿到全局路径后,
move_base
会调用局部路径规划器(例如dwa_local_planner
或teb_local_planner
)。局部路径规划器以全局路径为指引,结合机器人的实时传感器数据(如激光雷达、深度相机),在局部范围内规划出一条短期的、可执行的运动轨迹。局部路径规划要考虑到机器人的运动学约束、动态障碍物以及局部环境的变化。 - 运动控制:
move_base
将局部路径规划得到的轨迹转化为机器人的运动控制指令(线速度和角速度),并通过发布/cmd_vel
话题将这些指令发送给机器人的驱动系统,从而控制机器人的运动。 - 异常处理与恢复:在导航过程中,若机器人碰到障碍物、偏离路径或者局部规划失败等异常情况,
move_base
会触发恢复行为。恢复行为可以是一些预设的动作,例如原地旋转、后退等,旨在帮助机器人摆脱困境,然后重新进行路径规划和导航。
补充:move_base和nav_core
move_base
:是 ROS 导航栈中的一个具体节点,它实现了完整的机器人导航功能,包括接收目标、全局路径规划、局部路径规划、运动控制以及异常处理等一系列操作,是一个面向用户和应用层的导航功能集成节点,直接负责指挥机器人从当前位置移动到目标位置。move_base基于nav_core
框架实现了具体的导航逻辑。它通过调用nav_core
中定义的各种接口,如全局路径规划器接口、局部路径规划器接口和恢复行为接口等,来完成不同的导航任务。
nav_core
:是一个导航核心框架,主要提供了标准化的接口和通用的架构,用于集成各种路径规划算法和恢复行为等功能模块,它更侧重于为不同的导航相关组件提供统一的接口和交互机制,是导航系统内部的核心架构基础,不直接与用户或外部应用进行交互。
三,Navigation核心节点
在ROS中,功能包和节点的关系是灵活的,并不是所有功能包都包含可执行节点。有些功能包可能只提供库、接口、工具或配置文件,而有些功能包则包含可执行节点。每个C++节点通常对应一个可执行文件(如 amcl
节点对应 amcl_node
可执行文件)。每个Python节点是一个独立的脚本文件(如 .py
文件)。
move_base节点:
-
输入:
/move_base_simple/goal
(目标点,geometry_msgs/PoseStamped
) -
输出:
/cmd_vel
(速度指令,geometry_msgs/Twist
)
amcl节点:
-
输入:
/scan
(激光数据,sensor_msgs/LaserScan
)、/tf
(坐标变换) -
输出:
/amcl_pose
(估计的位姿,geometry_msgs/PoseWithCovarianceStamped
)
map_server节点:
-
输出:
/map
(地图数据,nav_msgs/OccupancyGrid
)
costmap_2d节点:
-
输入:
/scan
(激光数据)、/tf
(坐标变换) -
输出:
/global_costmap/costmap
(全局代价地图)、/local_costmap/costmap
(局部代价地图)
global_planner节点:
-
输入:
/map
(地图数据)、/move_base/goal
(目标点) -
输出:
/global_plan
(全局路径,nav_msgs/Path
)
dwa_local_planner节点 :
-
输入:
/scan
(激光数据)、/tf
(坐标变换) -
输出:
/cmd_vel
(速度指令,geometry_msgs/Twist
)
四,参数配置
可以在百度网盘查看我的完整文件,对于每个参数基本都给了解释
链接: https://pan.baidu.com/s/1jhGXXElmhy61LgYi3KRorA?pwd=1234 提取码: 1234
注意:move_base
发布的 /cmd_vel
话题(消息类型为 geometry_msgs/Twist
)只是向机器人底盘发送速度指令(线速度和角速度),但实际控制机器人底盘的运动需要你自己编写或使用现有的底盘驱动节点来解析这些指令并控制电机。底盘驱动的作用是将 /cmd_vel
的速度指令转换为电机控制信号(如PWM信号或CAN指令),从而驱动机器人移动。