ROS入门(九)——机器人自动导航(介绍、地图、定位和路径规划)

VIP ROS机器人自主导航详解 机器人在完成建图后即可在建立好的地图中进行导航,在ROS机器人中,导航使用到Navigation功能包集。Navigation包中最重要的就是Amcl与Move_base两个核心节点,本篇将详细讲解这两个核心节点及其参数。 开通可读全文·1w 阅读·12 点赞·184 收藏 阅读全文

所用的学习链接:

【奥特学园】ROS机器人入门课程《ROS理论与实践》零基础教程P289-314

【以上视频笔记见http://www.autolabor.com.cn/book/ROSTutorials/】

一、介绍

官方链接:https://www.ros.org/reps/rep-0105.html

1.实现导航的关键技术

 (1)全局地图

(全局概览图:定位+路径规划)

  • SLAM(实现地图构建和即时定位),也称为CML (Concurrent Mapping and Localization), 即时定位与地图构建,或并发建图与定位。SLAM问题可以描述为: 机器人在未知环境中从一个未知位置开始移动,在移动过程中根据位置估计和地图进行自身定位,同时在自身定位的基础上建造增量式地图,以绘制出外部环境的完全地图。(如红警起始一片黑,随着摸索出现地图)

ROS中保存地图的功能包是 map_server

  • 传感器:如果要完成 SLAM ,机器人必须要具备感知外界环境的能力,尤其是要具备获取周围环境深度信息的能力。感知的实现需要依赖于传感器,比如: 激光雷达、摄像头、RGB-D摄像头

(2)自身定位

(确定在地图中的位置)

  • amcl(adaptiveMonteCarloLocalization)自适应的蒙特卡洛定位,是用于2D移动机器人的概率定位系统。它实现了自适应(或KLD采样)蒙特卡洛定位方法,该方法使用粒子过滤器根据已知地图跟踪机器人的姿态。
  • 导航开始和导航过程中,机器人都需要确定当前自身的位置,室外可用GPS。室内、隧道、地下或一些特殊的屏蔽和弱化 GPS 信号的区域,前面的 SLAM 就可以实现自身定位,除此之外,ROS 中还提供了一个用于定位的功能包amcl

(3)路径规划

(全局+局部路径规划)

  • 全局路径规划(gloable_planner)

    根据给定的目标点和全局地图实现总体的路径规划,使用 Dijkstra 或 A* 算法进行全局路径规划,计算最优路线,作为全局路线

  • 局部路径规划(local_planner)

    在实际导航过程中,机器人可能无法按照给定的全局最优路线运行,比如:机器人在运行中,可能会随时出现一定的障碍物... 本地规划的作用就是使用一定算法(Dynamic Window Approaches) 来实现障碍物的规避,并选取当前最优路径以尽量符合全局最优路径

(4)运动控制

(控制速度和方向)

 导航功能包集假定它可以通过话题"cmd_vel"发布geometry_msgs/Twist类型的消息,这个消息基于机器人的基座坐标系,它传递的是运动命令。这意味着必须有一个节点订阅"cmd_vel"话题, 将该话题上的速度命令转换为电机命令并发送。

(5)环境感知

(感知周围环境)

感知周围环境信息,比如: 摄像头、激光雷达、编码器...,摄像头、激光雷达可以用于感知外界环境的深度信息,编码器可以感知电机的转速信息,进而可以获取速度信息并生成里程计信息。

在导航功能包集中,环境感知也是一重要模块实现,它为其他模块提供了支持。其他模块诸如: SLAM、amcl、move_base 都需要依赖于环境感知。

 2.坐标系

(1)里程计定位(odom)

  • 里程计定位:时时收集机器人的速度信息,计算并发布机器人坐标系与父级参考系的相对关系。
  • 优点:里程计定位信息是连续的,没有离散的跳跃。
  • 缺点:里程计存在累计误差,不利于长距离或长期定位。

【根据自己向什么方向走了多少路判断位置】

(2)传感器定位(map)

  • 传感器定位:通过传感器收集外界环境信息通过匹配计算并发布机器人坐标系与父级参考系的相对关系。
  • 优点:比里程计定位更精准;
  • 缺点:传感器定位会出现跳变的情况,且传感器定位在标志物较少的环境下,其定位精度会大打折扣。

 【根据自己周围环境判断位置】

(3)坐标系变换

上述两种定位实现中,机器人坐标系一般使用机器人模型中的根坐标系(base_link 或 base_footprint)

里程计定位时,父级坐标系一般称之为 odom

传感器定位时,父级参考系一般称之为 map。

当二者结合使用时,map 和 odom 都是机器人模型根坐标系的父级,这是不符合坐标变换中"单继承"的原则的,所以,一般会将转换关系设置为: map -> doom -> base_link 或 base_footprint。

3.硬软件需求

(1)硬件

虽然导航功能包集被设计成尽可能的通用,在使用时仍然有三个主要的硬件限制:

  • 它是为差速驱动的轮式机器人设计的。它假设底盘受到理想的运动命令的控制并可实现预期的结果,命令的格式为:x速度分量,y速度分量,角速度(theta)分量。 

  • 它需要在底盘上安装一个单线激光雷达。这个激光雷达用于构建地图和定位。

  • 导航功能包集是为正方形的机器人开发的,所以方形或圆形的机器人将是性能最好的。 它也可以工作在任意形状和大小的机器人上,但是较大的机器人将很难通过狭窄的空间。

(2)软件 

  • 安装 ROS

  • 当前导航基于仿真环境,先保证上一章的机器人系统仿真可以正常执行

  • 在仿真环境下,机器人可以正常接收 /cmd_vel 消息,并发布里程计消息,传感器消息发布也正常,也即导航模块中的运动控制和环境感知实现完毕

二、导航实现

1.准备工作

(1)安装功能包

  • gmapping 包(用于构建地图)
# sudo apt install ros-<ROS版本>-gmapping
sudo apt install ros-noetic-gmapping
  • 地图服务包(用于保存与读取地图)
# sudo apt install ros-<ROS版本>-map-server
sudo apt install ros-noetic-map-server
  • navigation 包(用于定位以及路径规划) 
# sudo apt install ros-<ROS版本>-navigation
sudo apt install ros-noetic-navigation

(2)新建功能包

①右键 7.19_demo01/src ,新建package catkin ,命名【nav_demo】,导入dependences: gmapping map_server amcl move_base

②在nav_demo文件夹下新建文件夹launch、map、param、config

2.SLAM建图

官方链接:http://wiki.ros.org/gmapping

(1)gmapping相关

SLAM算法有多种,当前我们选用gmapping。

gmapping 是ROS开源社区中较为常用且比较成熟的SLAM算法之一,gmapping可以根据移动机器人里程计数据和激光雷达数据来绘制二维的栅格地图。

gmapping 功能包中的核心节点是:slam_gmapping。为了方便调用,需要先了解该节点订阅的话题、发布的话题、服务以及相关参数。

  • 订阅的Topic

tf (tf/tfMessage):用于雷达、底盘与里程计之间的坐标变换消息。

scan(sensor_msgs/LaserScan):SLAM所需的雷达信息。

  • 发布的Topic

map_metadata(nav_msgs/MapMetaData):地图元数据,包括地图的宽度、高度、分辨率等,该消息会固定更新。

map(nav_msgs/OccupancyGrid):地图栅格数据,一般会在rviz中以图形化的方式显示。

~entropy(std_msgs/Float64):机器人姿态分布熵估计(值越大,不确定性越大)。

  • 服务

dynamic_map(nav_msgs/GetMap):用于获取地图数据。

  • 常用参数

~base_frame(string, default:"base_link"):机器人基坐标系。

~map_frame(string, default:"map"):地图坐标系。

~odom_frame(string, default:"odom"):里程计坐标系。

~map_update_interval(float, default: 5.0):地图更新频率,根据指定的值设计更新间隔。

~maxUrange(float, default: 80.0):激光探测的最大可用范围(超出此阈值,被截断)。

 激光探测的最大范围。

  • 所需的坐标变换

雷达坐标系→基坐标系:一般由 robot_state_publisher 或 static_transform_publisher 发布。

基坐标系→里程计坐标系:一般由里程计节点发布。

  • 发布的坐标变换

地图坐标系→里程计坐标系:地图到里程计坐标系之间的变换。

(2)建图代码

在nav_demo01/launch文件夹下新建 t1_slam.launch

<launch>
    <!-- 设置为true表示当前环境是仿真环境 -->
    <param name="use_sim_time" value="true" />
    <!-- gamping 节点 -->
    <node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen">
        <!-- 设置雷达话题 -->
        <remap from="scan" to="scan" />

        <!-- 关键参数:坐标系 -->
        <param name="base_frame" value="base_footprint" /> <!--底盘坐标系-->
        <param name="odom_frame" value="odom" /> <!--里程计坐标系-->
        <param name="map_frame" value="map" /> <!--地图坐标系-->

        <param name="map_update_interval" value="5.0" />
        <param name="maxUrange" value="16.0" />
        <param name="sigma" value="0.05" />
        <param name="kernelSize" value="1" />
        <param name="lstep" value="0.05" />
        <param name="astep" value="0.05" />
        <param name="iterations" value="5" />
        <param name="lsigma" value="0.075" />
        <param name="ogain" value="3.0" />
        <param name="lskip" value="0" />
        <param name="srr" value="0.1" />
        <param name="srt" value="0.2" />
        <param name="str" value="0.1" />
        <param name="stt" value="0.2" />
        <param name="linearUpdate" value="1.0" />
        <param name="angularUpdate" value="0.5" />
        <param name="temporalUpdate" value="3.0" />
        <param name="resampleThreshold" value="0.5" />
        <param name="particles" value="30" />
        <param name="xmin" value="-50.0" />
        <param name="ymin" value="-50.0" />
        <param name="xmax" value="50.0" />
        <param name="ymax" value="50.0" />
        <param name="delta" value="0.05" />
        <param name="llsamplerange" value="0.01" />
        <param name="llsamplestep" value="0.01" />
        <param name="lasamplerange" value="0.005" />
        <param name="lasamplestep" value="0.005" />
    </node>

    <node pkg="joint_state_publisher" name="joint_state_publisher" type="joint_state_publisher" />
    <node pkg="robot_state_publisher" name="robot_state_publisher" type="robot_state_publisher" />

    <!-- <node pkg="rviz" type="rviz" name="rviz" /> -->
    <!-- 使用之前保存过的 rviz 配置-->
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdf_gazebo)/config/t7_car.rviz" />

</launch>

(3)启动 

①运行相关启动命令

ctrl+shift+b   # 编译

# 终端1
roscore

# 终端2(启动之前的gazebo)
roslaunch urdf_gazebo t7_gazebo.launch

# 终端3(启动新建的地图绘制 launch )
roslaunch nav_demo t1_slam.launch

# 外部新终端1(启动键盘控制)
rosrun teleop_twist_keyboard teleop_twist_keyboard.py

 ②在Rviz中 Add → Map → Topic :/map

可以看见rviz中出现了地图。控制小车移动,可以进一步绘制地图

③打开TF → Frames → 勾选 map、odom、base_footprint

勾选后会显示起始点的 map 和 odm 坐标,base_footprint可显示当前位置和原点的距离关系,其他选项根据需要自行调整

 3.地图保存和读取

官方链接:http://wiki.ros.org/map_server

map_server功能包中提供了两个节点: map_saver 和 map_server,前者用于将栅格地图保存到磁盘,后者读取磁盘的栅格地图并以服务的方式提供出去。

(1)map_sarver相关

  • 订阅的Topic

map(nav_msgs/OccupancyGrid):订阅此话题用于生成地图文件。

(2)map_server相关

  • 发布的Topic

map_metadata(nav_msgs / MapMetaData):发布地图元数据。

map(nav_msgs / OccupancyGrid):地图数据。

  • 服务

static_map(nav_msgs / GetMap):通过此服务获取地图。

  • 常用参数

〜frame_id(字符串,默认值:“map”):地图坐标系。

(3)地图保存

①新建用于地图保存的 t2_map_save.launch文件

<launch>
    <!-- nav 文件夹可以不创建 -->
    <arg name="filename" value="$(find nav_demo)/map/nav" />
    <node name="map_save" pkg="map_server" type="map_saver" args="-f $(arg filename)" />
</launch>

②建完图后,运行 t2_map_save.launch

# 新终端
roslaunch nav_demo t2_map_save.launch

③查看

在nav_demo/map目录下,会看到生成了两个地图文件

 

  • xxx.pgm 本质是一张图片

直接使用图片查看程序即可打开。

  • xxx.yaml 保存的是地图的元数据信息

用于描述图片,内容格式如下:

# 图片路径,可以是绝对路径也可以是相对路径
image: /home/netceor_ros/ROS/7.19_demo1/src/nav_demo/map/nav.pgm
# 分辨率(单位: m/像素)、地图刻度尺单位
resolution: 0.050000
# 地图位姿,相对于rviz中原点位姿。(x,y,偏航)偏航为逆时针旋转(偏航= 0表示无旋转)
origin: [-50.000000, -50.000000, 0.000000]
# 取反:是否应该颠倒白色/黑色自由/占用的语义
negate: 0
# 占用阈值:占用概率大于此阈值的像素被视为完全占用
occupied_thresh: 0.65
# 空闲阈值:占用率小于此阈值的像素被视为完全空闲
free_thresh: 0.196
  • map_server 中障碍物计算规则

a.地图中的每一个像素取值在 [0,255] 之间,白色为 255,黑色为 0,该值设为 x;

b.map_server 会将像素值作为判断是否是障碍物的依据,首先计算比例: p = (255 - x) / 255.0,白色为0,黑色为1(negate为true,则p = x / 255.0);

c.根据步骤2计算的比例判断是否是障碍物,如果 p > occupied_thresh 那么视为障碍物,如果 p < free_thresh 那么视为无物。

(4)地图读取

①新建用于地图读取的 t3_map_load.launch文件

<launch>
    <!-- 设置地图的配置文件 -->
    <arg name="map" default="nav.yaml" />
    <!-- 运行地图服务器,并且加载设置的地图-->
    <node name="map_server" pkg="map_server" type="map_server" args="$(find nav_demo)/map/$(arg map)" />
</launch>

②启动命令

ctrl+shift+b  # 编译

# 集成终端1,运行完后地图信息就被发布
roslaunch nav_demo t3_map_load.launch

# 外部新终端2,开启一个rviz
rviz

# 外部新终端3,查看话题,如果有map相关就说明成功发布
# rostopic list

③ Rviz 中 → Add → Map → Topic:/map

【这里我第一次启动的时候没有map话题,把vscode重新启动后就有用了】

4.定位

官方链接:http://wiki.ros.org/amcl

(1)amcl 相关

定位就是推算机器人自身在全局地图中的位置。SLAM中也包含定位算法实现,不过SLAM的定位是用于构建全局地图的,是属于导航开始之前的阶段,而当前定位是用于导航中。导航中,机器人需要按照设定的路线运动,通过定位可以判断机器人的实际轨迹是否符合预期。在ROS的导航功能包集navigation中提供了 amcl 功能包,用于实现导航中的机器人定位。

AMCL(adaptive Monte Carlo Localization) 是用于2D移动机器人的概率定位系统,它实现了自适应(或KLD采样)蒙特卡洛定位方法,可以根据已有地图使用粒子滤波器推算机器人位置。

  • 订阅的Topic

scan(sensor_msgs/LaserScan):激光雷达数据。

tf(tf/tfMessage):坐标变换消息。

initialpose(geometry_msgs/PoseWithCovarianceStamped):用来初始化粒子滤波器的均值和协方差。

map(nav_msgs/OccupancyGrid):获取地图数据。

  • 发布的Topic

amcl_pose(geometry_msgs/PoseWithCovarianceStamped):机器人在地图中的位姿估计。

particlecloud(geometry_msgs/PoseArray):位姿估计集合,rviz中可以被 PoseArray 订阅然后图形化显示机器人的位姿估计集合。

tf(tf/tfMessage):发布从 odom 到 map 的转换。

  • 服务

global_localization(std_srvs/Empty):初始化全局定位的服务。

request_nomotion_update(std_srvs/Empty):手动执行更新和发布更新的粒子的服务。

set_map(nav_msgs/SetMap):手动设置新地图和姿态的服务。

  • 调用的服务

static_map(nav_msgs/GetMap):调用此服务获取地图数据。

  • 常用参数

~odom_model_type(string, default:"diff"):里程计模型选择: "diff","omni","diff-corrected","omni-corrected" (diff 差速、omni 全向轮)

~odom_frame_id(string, default:"odom"):里程计坐标系。

~base_frame_id(string, default:"base_link"):机器人极坐标系。

~global_frame_id(string, default:"map"):地图坐标系。

(2)坐标变换

里程计本身也是可以协助机器人定位的,不过里程计存在累计误差且一些特殊情况时(车轮打滑)会出现定位错误的情况,amcl 则可以通过估算机器人在地图坐标系下的姿态,再结合里程计提高定位准确度。

  • 里程计定位:只是通过里程计数据实现 /odom_frame 与 /base_frame 之间的坐标变换。
  • amcl定位: 可以提供 /map_frame 、/odom_frame 与 /base_frame 之间的坐标变换。

 (3)使用amcl和运行

①amcl节点相关的 t4_amcl.launch文件

# 可查看模板
# roscd amcl
# ls examples
# 该目录下会列出两个文件: amcl_diff.launch 和 amcl_omni.launch 文件,前者适用于差分移动机器人,后者适用于全向移动机器人
# gedit examples/amcl_diff.launch
# 复制并修改
<launch>
    <node pkg="amcl" type="amcl" name="amcl" output="screen">
        <!-- Publish scans from best pose at a max of 10 Hz -->
        <param name="odom_model_type" value="diff" /> <!-- 里程计模式为差分 -->
        <param name="odom_alpha5" value="0.1" />
        <param name="transform_tolerance" value="0.2" />
        <param name="gui_publish_rate" value="10.0" />
        <param name="laser_max_beams" value="30" />
        <param name="min_particles" value="500" />
        <param name="max_particles" value="5000" />
        <param name="kld_err" value="0.05" />
        <param name="kld_z" value="0.99" />
        <param name="odom_alpha1" value="0.2" />
        <param name="odom_alpha2" value="0.2" />
        <!-- translation std dev, m -->
        <param name="odom_alpha3" value="0.8" />
        <param name="odom_alpha4" value="0.2" />
        <param name="laser_z_hit" value="0.5" />
        <param name="laser_z_short" value="0.05" />
        <param name="laser_z_max" value="0.05" />
        <param name="laser_z_rand" value="0.5" />
        <param name="laser_sigma_hit" value="0.2" />
        <param name="laser_lambda_short" value="0.1" />
        <param name="laser_lambda_short" value="0.1" />
        <param name="laser_model_type" value="likelihood_field" />
        <!-- <param name="laser_model_type" value="beam"/> -->
        <param name="laser_likelihood_max_dist" value="2.0" />
        <param name="update_min_d" value="0.2" />
        <param name="update_min_a" value="0.5" />

        <param name="odom_frame_id" value="odom" /> <!-- 里程计odom坐标系 -->
        <param name="base_frame_id" value="base_footprint" /> <!-- 添加机器人基坐标系 -->
        <param name="global_frame_id" value="map" /> <!-- 添加地图map坐标系 -->

        <param name="resample_interval" value="1" />
        <param name="transform_tolerance" value="0.1" />
        <param name="recovery_alpha_slow" value="0.0" />
        <param name="recovery_alpha_fast" value="0.0" />
    </node>
</launch>

 ②编写测试 amcl 的 t5_amcl_test.launch 文件

amcl文件无法单独运行,需要新建一个启动文件

<launch>
    <!-- 运行rviz -->
    <node pkg="rviz" type="rviz" name="rviz" />
    <node pkg="joint_state_publisher" name="joint_state_publisher" type="joint_state_publisher" />
    <node pkg="robot_state_publisher" name="robot_state_publisher" type="robot_state_publisher" />
    <!-- 加载地图服务 -->
    <include file="$(find nav_demo)/launch/t3_map_load.launch" />
    <!-- 启动AMCL节点 -->
    <include file="$(find nav_demo)/launch/t4_amcl.launch" />
</launch>

③运行

ctrl+shift+b  # 编译

# 启动gazebo
roslaunch urdf_gazebo t7_gazebo.launch

# 启动键盘
rosrun teleop_twist_keyboard teleop_twist_keyboard.py

# 启动 t5_amcl_test.launch
roslaunch nav_demo t5_amcl_test.launch

④Rviz 中 → Add → Map → Topic:/map

⑤Rviz 中 → Add → RobotModel 

⑥Rviz 中 → Add → PoseArray → Topic:/particlecloud

控制小车运动起来,红色线越密集处,小车处于该位置的概率越大。

5.路径规划

官方链接:http://wiki.ros.org/move_base

(1)move_base相关

move_base 功能包提供了基于动作(action)的路径规划实现,move_base 可以根据给定的目标点,控制机器人底盘运动至目标位置,并且在运动过程中会连续反馈机器人自身的姿态与目标点的状态信息。move_base主要由全局路径规划与本地路径规划组成。

move_base已经被集成到了navigation包

【动作可以为机器人的行动提供实时反馈】

  • 动作订阅

move_base/goal(move_base_msgs/MoveBaseActionGoal):move_base 的运动规划目标。

move_base/cancel(actionlib_msgs/GoalID):取消目标。

  • 动作发布

move_base/feedback(move_base_msgs/MoveBaseActionFeedback):连续反馈的信息,包含机器人底盘坐标。

move_base/status(actionlib_msgs/GoalStatusArray):发送到move_base的目标状态信息。

move_base/result(move_base_msgs/MoveBaseActionResult):操作结果(此处为空)。

  • 订阅的Topic

move_base_simple/goal(geometry_msgs/PoseStamped):运动规划目标(与action相比,没有连续反馈,无法追踪机器人执行状态)。

  • 发布的Topic

cmd_vel(geometry_msgs/Twist):输出到机器人底盘的运动控制消息。

  • 服务

~make_plan(nav_msgs/GetPlan):请求该服务,可以获取给定目标的规划路径,但是并不执行该路径规划。

~clear_unknown_space(std_srvs/Empty):允许用户直接清除机器人周围的未知空间。

~clear_costmaps(std_srvs/Empty):允许清除代价地图中的障碍物,可能会导致机器人与障碍物碰撞,请慎用。

(2)代价地图相关

机器人导航(尤其是路径规划模块)是依赖于地图的。ROS中的地图其实就是一张图片,这张图片有宽度、高度、分辨率等元数据,在图片中使用灰度值来表示障碍物存在的概率。不过SLAM构建的地图在导航中是不可以直接使用的,因为:

  • SLAM构建的地图是静态地图,而导航过程中,障碍物信息是可变的,可能障碍物被移走了,也可能添加了新的障碍物,导航中需要时时的获取障碍物信息;
  • 在靠近障碍物边缘时,虽然此处是空闲区域,但是机器人在进入该区域后可能由于其他一些因素,比如:惯性、或者不规则形体的机器人转弯时可能会与障碍物产生碰撞,安全起见,最好在地图的障碍物边缘设置警戒区,尽量禁止机器人进入...

所以,静态地图无法直接应用于导航,其基础之上需要添加一些辅助信息的地图,比如时时获取的障碍物数据,基于静态地图添加的膨胀区等数据。

代价地图有两张:global_costmap(全局代价地图) 和 local_costmap(本地代价地图),前者用于全局路径规划,后者用于本地路径规划。

两张代价地图都可以多层叠加,一般有以下层级:

  • Static Map Layer:静态地图层——SLAM构建的静态地图。

  • Obstacle Map Layer:障碍地图层——导航中传感器感知的障碍物信息。

  • Inflation Layer:膨胀层——在以上两层地图上进行膨胀(向外扩张),以避免机器人的外壳会撞上障碍物。

  • Other Layers:自定义costmap——根据业务设置的地图数据,临时模拟。

多个layer可以按需自由搭配。

(3)碰撞算法

在ROS中,计算代价值的方法如图

上图中,横轴是距离机器人中心的距离,纵轴是代价地图中栅格的灰度值。

  • 致命障碍:栅格值为254,此时障碍物与机器人中心重叠,必然发生碰撞;
  • 内切障碍:栅格值为253,此时障碍物处于机器人的内切圆内,必然发生碰撞;
  • 外切障碍:栅格值为[128,252],此时障碍物处于其机器人的外切圆内,处于碰撞临界,不一定发生碰撞;
  • 非自由空间:栅格值为(0,127],此时机器人处于障碍物附近,属于危险警戒区,进入此区域,将来可能会发生碰撞;
  • 自由区域:栅格值为0,此处机器人可以自由通过;
  • 未知区域:栅格值为255,还没探明是否有障碍物。

膨胀空间的设置可以参考非自由空间。

(4)配置和代码

 路径规划算法在move_base功能包的move_base节点中已经封装完毕了,但是还不可以直接调用,因为算法虽然已经封装了,但是该功能包面向的是各种类型支持ROS的机器人,不同类型机器人可能大小尺寸不同,传感器不同,速度不同,应用场景不同....最后可能会导致不同的路径规划结果,那么在调用路径规划节点之前,我们还需要配置机器人参数。

①配置文件 costmap_common_params.yaml

在 param 文件夹下新建 costmap_common_params.yaml

#机器人几何参,如果机器人是圆形,设置 robot_radius,如果是其他形状设置 footprint
robot_radius: 0.12 #圆形
# footprint: [[-0.12, -0.12], [-0.12, 0.12], [0.12, 0.12], [0.12, -0.12]] #其他形状

obstacle_range: 3.0 # 用于障碍物探测,比如: 值为 3.0,意味着检测到距离小于 3 米的障碍物时,就会引入代价地图
raytrace_range: 3.5 # 用于清除障碍物,比如:值为 3.5,意味着清除代价地图中 3.5 米以外的障碍物


#膨胀半径,扩展在碰撞区域以外的代价区域,使得机器人规划路径避开障碍物
inflation_radius: 0.2
#代价比例系数,越大则代价值越小
cost_scaling_factor: 3.0

#地图类型
map_type: costmap
#导航包所需要的传感器
observation_sources: scan
#对传感器的坐标系和数据进行配置。这个也会用于代价地图添加和清除障碍物。例如,你可以用激光雷达传感器用于在代价地图添加障碍物,再添加kinect用于导航和清除障碍物。
scan: {sensor_frame: laser, data_type: LaserScan, topic: scan, marking: true, clearing: true}

②配置文件 global_costmap_params.yaml

在 param 文件夹下新建 global_costmap_params.yaml

global_costmap:
  global_frame: map #地图坐标系
  robot_base_frame: base_footprint #机器人坐标系
  # 以此实现坐标变换

  update_frequency: 1.0 #代价地图更新频率
  publish_frequency: 1.0 #代价地图的发布频率
  transform_tolerance: 0.5 #等待坐标变换发布信息的超时时间

  static_map: true # 是否使用一个地图或者地图服务器来初始化全局代价地图,如果不使用静态地图,这个参数为false.

③配置文件 local_costmap_params.yaml

在 param 文件夹下新建 local_costmap_params.yaml

local_costmap:
  global_frame: odom #里程计坐标系
  robot_base_frame: base_footprint #机器人坐标系

  update_frequency: 10.0 #代价地图更新频率
  publish_frequency: 10.0 #代价地图的发布频率
  transform_tolerance: 0.5 #等待坐标变换发布信息的超时时间

  static_map: false  #不需要静态地图,可以提升导航效果
  rolling_window: true #是否使用动态窗口,默认为false,在静态的全局地图中,地图不会变化
  width: 3 # 局部地图宽度 单位是 m
  height: 3 # 局部地图高度 单位是 m
  resolution: 0.05 # 局部地图分辨率 单位是 m,一般与静态地图分辨率保持一致

④配置文件 base_local_planner_params.yaml

在 param 文件夹下新建 base_local_planner_params.yaml

TrajectoryPlannerROS:

# Robot Configuration Parameters
  max_vel_x: 0.5 # X 方向最大速度
  min_vel_x: 0.1 # X 方向最小速速

  max_vel_theta:  1.0 # 
  min_vel_theta: -1.0
  min_in_place_vel_theta: 1.0

  acc_lim_x: 1.0 # X 加速限制
  acc_lim_y: 0.0 # Y 加速限制
  acc_lim_theta: 0.6 # 角速度加速限制

# Goal Tolerance Parameters,目标公差
  xy_goal_tolerance: 0.10
  yaw_goal_tolerance: 0.05

# Differential-drive robot configuration
# 是否是全向移动机器人
  holonomic_robot: false

# Forward Simulation Parameters,前进模拟参数
  sim_time: 0.8
  vx_samples: 18
  vtheta_samples: 20
  sim_granularity: 0.05

⑤参数配置技巧(如果跟着步骤,则无需操作)

以上配置在实操中,可能会出现机器人在本地路径规划时与全局路径规划不符而进入膨胀区域出现假死的情况。

全局路径规划与本地路径规划虽然设置的参数是一样的,但是二者路径规划和避障的职能不同,可以采用不同的参数设置策略:

  • 全局代价地图可以将膨胀半径和障碍物系数设置的偏大一些;
  • 本地代价地图可以将膨胀半径和障碍物系数设置的偏小一些。

这样,在全局路径规划时,规划的路径会尽量远离障碍物,而本地路径规划时,机器人即便偏离全局路径也会和障碍物之间保留更大的自由空间,从而避免了陷入“假死”的情形。

 以及几个可能会调整的参数

  •  costmap_common_params.yaml

a.robot_radius【如圆形机器人大小0.1,设置为0.12】

b.sensor_frame

  •  global_costmap_params.yaml

a.global_frame

d.robot_base_frame

  •  local_costmap_params.yaml

a.global_frame

d.robot_base_frame

⑥ 新建 t6_movebase.launch 文件

<launch>
    <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen" clear_params="true">
        <rosparam file="$(find nav_demo)/param/costmap_common_params.yaml" command="load" ns="global_costmap" />
        <rosparam file="$(find nav_demo)/param/costmap_common_params.yaml" command="load" ns="local_costmap" />
        <rosparam file="$(find nav_demo)/param/local_costmap_params.yaml" command="load" />
        <rosparam file="$(find nav_demo)/param/global_costmap_params.yaml" command="load" />
        <rosparam file="$(find nav_demo)/param/base_local_planner_params.yaml" command="load" />
    </node>
</launch>

⑦ 新建 t7_346.launch 文件

<launch>
    <!-- 启动rviz -->
    <node pkg="rviz" type="rviz" name="rviz" />
    <node pkg="joint_state_publisher" name="joint_state_publisher" type="joint_state_publisher" />
    <node pkg="robot_state_publisher" name="robot_state_publisher" type="robot_state_publisher" />
    <!-- 地图服务 -->
    <include file="$(find nav_demo)/launch/t3_map_load.launch" />
    <!-- 启动AMCL节点 -->
    <include file="$(find nav_demo)/launch/t4_amcl.launch" />
    <!-- 运行move_base节点 -->
    <include file="$(find nav_demo)/launch/t6_movebase.launch" />
</launch>

(5)自动导航

①编译、运行gazebo、运行rviz

ctrl+shift+b  # 编译

# 启动gazebo
roslaunch urdf_gazebo t7_gazebo.launch

# 启动 rviz
roslaunch nav_demo t7_346.launch

② Rviz 中 → Add 添加组件

  • RobotModel 
  • Map → Topic:/map
  • PoseArray → Topic:/particlecloud
  •  LaserScan → Topic:/scan
  •  Odometry → Topic:/odom → 取消勾选 Covariance
  • Map(重命名为Map_global)→  Topic:/move_base/global_costmap/costmap → Color Scheme:costmap【与前面的map不同,可以看到全局代价地图的结果】
  • Map(重命名为Map_local)→  Topic:/move_base/local_costmap/costmap → Color Scheme:costmap【与前面的map不同,可以看到局部代价地图的结果】
  • Path(重命名为Path_global)→ Topic:/move_base/NavfnROS/plan【会出现指向目的地的线条】
  • Path(重命名为Path_local)→ Topic:/move_base/TrajectoryPlannerROS/local_plan【会出现小段前进方向的线条,可调整颜色为方便区分】

③自动导航实现

选中菜单栏 " 2D Nav Goal ",任意选择一个位置,机器人开始自动导航

三、导航建图

在前文的建图中,我们通过键盘控制小车运动,得到完整的地图模型,学习了自动导航之后,可以开始尝试使用自动导航来实现地图构建

1. launch文件

由于SLAM建图过程中本身就会时时发布地图信息,所以无需再使用map_server,SLAM已经发布了话题为 /map 的地图消息了,且导航需要定位模块,SLAM本身也是可以实现定位的。

因此当前launch文件实现,无需调用map_server的相关节点,只需要启动SLAM节点与move_base节点。

新建一个 t8_slam_auto.launch 来集成slam和自动导航。

由于slam文件中已有打开rviz的语句,因此在t8中不需要这个语句。

但要修改 t1_slam.launch文件中关于启动rviz的相关参数,导入上一博客中保存好的 nav_test.rviz 环境

  • 新建 t8_slam_auto.launch
<!-- 集成slam和导航,机器人自动导航建图 -->
<launch>
    <!-- 启动SLAM节点 -->
    <include file="$(find nav_demo)/launch/t1_slam.launch" />
    <!-- 运行move_base节点 -->
    <include file="$(find nav_demo)/launch/t6_movebase.launch" />
</launch>
  • 修改 t1_slam.launch
# 原句子
# <node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdf_gazebo)/config/t7_car.rviz" />

# 替换为    
<node pkg="rviz" type="rviz" name="rviz" args="-d $(find nav_demo)/config/nav_test.rviz" />

2.自动导航建图

 (1)启动

ctrl+shift+b  # 编译

# 启动gazebo
roslaunch urdf_gazebo t7_gazebo.launch

# 启动 rviz
roslaunch nav_demo t8_slam_auto.launch

(2) 自动导航

在rviz中通过2D Nav Goal设置目标点,机器人开始自主移动并建图

(3)保存地图

建图完成后,使用map_server保存地图,详情参考本文的二、3

机器人模型搭建参考链接:

ROS入门(五)——仿真机器人一(URDF+Rviz)

ROS入门(六)——仿真机器人二(Xacro+Rviz+Arbotix小车运动)

ROS入门(七)——仿真机器人三(Gazebo+Xacro)

ROS入门(八)——仿真机器人四(Gazebo+Rviz+雷达、摄像头、kinet仿真显示)

VIP 从零搭建一台基于ROS的自动驾驶车-----5.路径规划与导航 在之前的几篇教程中,我们已经可以通过ROS来控制底盘小车的运动,还建立了一张全局静态地图,以及实现了机器人在全局静态地图中的定位,这篇教程将讲述最后一篇路径规划与导航。在ROS中提供了一个可以实现导航的功能包navigation,路径规划是导航中的核心功能之一,在ROS的导航功能包集navigation中提供了 move_base 功能包,用于实现此功能。 开通可读全文·1.1w 阅读·17 点赞·219 收藏 阅读全文

相关推荐

ROS 2 中的 robot_state_publisher 和 joint_state_publisher 详解

ROS 2中的机器人状态管理主要由joint_state_publisher和robot_state_publisher两个组件协作完成。joint_state_publisher负责收集并发布机器人的关节状态消息,提供GUI交互式控制功能,适合演示调试;robot_state_publisher则根据URDF模型和关节状态计算坐标变换(TF),维护整个机器人坐标系系统,为Rviz等组件提供准确的坐标数据。两者通过/joint_states消息进行通信,形成完整的状态发布流程:joint_state_pub

i宏的博客 1937

教程 Re:Zero ROS (七/完) —— 建图&定位&导航 - 代价地图&路径规划

**前情提要:已经建立了odom与base_footprint的关系,并可使用按键检验 ** 《教程 Re:Zero ROS (六)—— 获取&编写&检验 -> odom坐标系》 https://blog.youkuaiyun.com/Lovely_him/article/details/107948765 教程 Re:Zero ROS (七) —— 1. slam_gmapping 建图 0)本篇大部分内容都是中科院教程中讲到过的,建议先看完中科院最后两课——第九、十课的9个视频,.

Lovely_him的博客 8666

ROS导航实现之路径规划

ROS学习笔记,move_base路径规划实现流程指南

weixin_45205599的博客 4957

【ROS问题】joint_state_publisher和robot_state_publisher的区别和联系

问题描述 在使用moveit!对机械臂进行运动规划时,joint_state_publiser和robot_state_publisher各有什么作用,它们之间又有什么联系? 解决方案 运行一个moveit!package,在命令行输入rqt_graph,输出计算图如下: joint_state_publiser:这个节点负责输出关节信息,并发布/joint_sta...

Rot_Tianers 1万+

【ROS2】机器人导航仿真

主要介绍导航的完整性实现,旨在掌握机器人导航的基本流程,该章涉及的主要内容如下:SLAM建图(选用较为常见的gmapping)、地图服务(可以保存和重现地图)、机器人定位、路径规划。上述流程介绍完毕,还会对功能进一步集成实现探索式的SLAM建图。

guilin 3312

ROS实践(五)机器人自动导航(robot_navigation)

本文系统介绍了机器人自主导航的关键技术框架,主要包括定位、路径规划和避障三大核心模块。在定位方面,详细阐述了AMCL定位算法及其参数配置;路径规划部分分解为全局规划(A*/Dijkstra算法)和局部规划(DWA/TEB算法)两个层级;避障技术则通过代价地图(costmap)机制实现。文章还完整呈现了ROS导航栈的软件架构,包括move_base、amcl等核心功能包的作用与交互关系,并提供了从实验准备到参数配置的完整导航实现方案,其中包含8个关键的YAML配置文件详解。该技术体系通过多传感器融合和分层规划

qq_1033275663的博客 2933

随手笔记——ROS下joint_state_publisher、robot_state_publisher节点的简要说明

简单记录一下oint_state_publisher、robot_state_publisher节点的功能及使用 2. joint_state_publisher joint_state_publisher功能包为机器人发布sensor_msgs/JointState消息,该包从参数服务器读取robot_description参数,查找所有非固定关节,并发布定义了所有这些关节的JointState消息。File: sensor_msgs/JointState.msg Raw Message Definiti

曾经也曾立志 9956

当使用视觉SLAM对一个环境建图之后,如何让机器人能够“理解”地图并导航呢?

摘要:该研究探讨了轮式机器人自主导航的优化方法,通过改进视觉SLAM算法(如ORB-SLAM3)和融合多传感器数据提升定位精度。针对动态环境和复杂场景,提出了结合深度学习与几何方法的动态物体过滤技术(SegGeo-SLAM)以及多特征融合方案(LR-SLAM)。在路径规划方面,采用TEB算法实现实时避障,并通过强化学习(如改进PPO算法)和分层优化框架(CO-DOSP)提升运动规划的效率和稳定性。实验验证了这些方法在ROS平台和Gazebo仿真环境中的有效性,显著提高了导航精度和鲁棒性。

CyberSoma的博客 2058

SLAM导航机器人零基础实战系列:(六)SLAM建图与自主避障导航——3.ros-navigation机器人自主避障导航...

SLAM+语音机器人DIY系列:(六)SLAM建图与自主避障导航——3.ros-navigation机器人自主避障导航 摘要 通过前面的基础学习,本章进入最为激动的机器人自主导航的学习。在前面的学习铺垫后,终于迎来了最大乐趣的时刻,就是赋予我们的miiboo机器人能自由行走的生命。本章将围绕机器人SLAM建...

小虎哥哥爱学习-优快云 1万+

无人驾驶(三)---teleop_twist_keyboard控制底盘运动

底盘控制文件启动后,可以通过teleop_twist_keyboard 和 cmd_vel 控制底盘运动

weixin_51157015的博客 7104

ros2/ros1使用teleop_twist_keyboard控制差速电机机器人运动

【代码】teleop_twist_keyboard。

2337

ROS学习7:ROS机器人导航仿真

ROS学习7:ROS机器人导航仿真

qq_42994487的博客 3554

Abaqus 气动软体抓取器:从超弹性材料建模到抓取力仿真全流程解析

本文详细解析了Abaqus在气动软体抓取器仿真中的应用全流程,涵盖超弹性材料建模、接触设置优化到抓取力仿真等关键环节。通过实战案例分享Yeoh模型参数拟合、不可伸展层建模技巧及收敛优化策略,帮助工程师高效解决有限元仿真中的常见问题,提升软体机器人研发效率。

weixin_28689193的博客 236

导航和路径规划-论文心得

导航技术前言: 导航技术的移动机器人技术的核心和关键技术。自主移动机器人的导航就是让机器人可以自主按照内部预定的信息,或者依据传感器获取外部环境进行相应的引导,从而规划出一条适合机器人在环境中行走的路径。定位,就是机器人通过已经观测到的环境信息,结合自身已知的状态进行准确的极端出自身的位姿信息。室内移动机器人导航框架图: 、 导航过程首先要获得相关的地图信息,然后进行路径规划,最后发送数据给机

DavidHan008 3万+

如何利用VS2017创建一个简单的窗口

#如何利用VS2017创建一个简单的窗口 1、新建->Windows桌面向导 2、应用程序类型->桌面应用程序,点击确定 3、点击调试->开始调试 可建立如下图的窗口 4、可以在生成的项目文件的中找到windows17_2的应用程序,打开界面如下: 注:新建空白项目也可以,注意在解决方案资源器中添加.cpp文件,如源.cpp文件,下载代码见博文 ...

weixin_46894139的博客 2914

ESP32开发环境避坑指南:用Thonny烧录MicroPython固件时常见的5个错误及解决方法

本文针对ESP32开发新手,详细解析了使用Thonny IDE烧录MicroPython固件时最常见的5个错误及其解决方案。内容涵盖驱动安装、端口识别、固件烧录失败、版本兼容性、连接不稳定以及文件系统操作异常等核心痛点,并提供硬件层面的深度排查指南,帮助开发者高效搭建稳定的ESP32开发环境。

weixin_29189003的博客 404

ROS2极简总结-导航简介-自定位

本节主要介绍导航所涉及的基础概念和一些相关内容。 参考:Navigation using ROS 2 - Introduction 机器人在环境中运动方向的路径规划要回答三个问题: 我在哪?(Localization) 我要去哪里?(Goal) 我怎么走?(PathPlan) 如果要细分问题更多,就以此为基础吧。看如下: Gazebo Webots ROS2的navigation2功能包,支持Linux、Windows和MacOS,并且适用于各类仿真环境如Gazebo、Webots等,同..

zhangrelay的专栏 7183

keil4.72添加GD32F10x芯片

1. 下载 GD32F10x_AddOn_V2.0.1.rar,解压缩。 2. 安装 运行GigaDevice.GD32F10x_AddOn.2.0.0.exe 安装位置 再新建工程,发现已经有GD32F10x 3. 增加的文件分析 运行GigaDevice.GD32F10x_AddOn.2.0.0.exe后,在keil文件夹种增加文件如下: ...

TrueLink的博客 2762

ROS理论与实践学习笔记——6 ROS机器人导航(仿真)之导航实现

ROS机器人导航(仿真)主要包括机器人设置、SLAM构图、代价地图和导航模块四个部分。机器人首先通过里程计和激光雷达(或深度相机)提供运动数据和环境感知信息,接着使用Gmapping算法构建二维栅格地图。在此基础上,生成全局和本地代价地图,代价地图包含静态地图层、障碍物层和膨胀层等信息,用于路径规划和避障。最终,move_base 模块通过全局路径规划生成长距离的最优路径,并利用本地路径规划实时调整和避障,使机器人安全地到达目标点。

心有所信,方能远行! 4548

Aitoearn内容营销的最佳开源 AI 代理,创建 · 发布 · 互动 · 副业一站式平台,支持渠道:抖音、小红书(红点)、微信通道、快手、哔哩哔哩、微信公众号、抖音等等

Aitoearn内容营销的最佳开源 AI 代理,创建 · 发布 · 互动 · 副业一站式平台,支持渠道:抖音、小红书(红点)、微信通道、快手、哔哩哔哩、微信公众号、抖音等等

struggle2025的博客 1749

从Starlink看NTN:SSB波束数量少,用户体验真的会差吗?

当SpaceX的Starlink以每月新增上百颗卫星的速度扩张其星座时,一个有趣的技术现象正在引发行业讨论:为何这个全球最大的低轨卫星网络选择使用相对较少的波束数量?波束数量的选择远非简单的技术参数,而是系统设计哲学、商业策略与终端用户体验的复杂平衡。传统地面网络可以依赖密集基站实现精准覆盖,而卫星通信必须面对一个根本性挑战:如何在数百公里的高空,用有限的射频资源服务广阔的地理区域。当我们在撒哈拉沙漠测试不同波束方案时,发现了一个关键洞见:最佳波束数量不是固定的技术参数,而是随网络发展阶段变化的动态值。

weixin_32308101的博客 332

ROS学习笔记08、机器人导航仿真(slam、map_server、amcl、move_base与导航消息介绍)

马上开学,目前学校很多实验室都是人工智能这块,大部分都是和机器人相关,然后软件这块就是和cv、ros相关,就打算开始学习一下。本章节是虚拟机安装Ubuntu18.04以及安装ROS的环境。学习教程:【Autolabor初级教程】ROS机器人入门,博客中一些知识点是来源于赵老师的笔记在线笔记,本博客主要是做归纳总结,如有侵权请联系删除。视频中的案例都基本敲了遍,这里给出我自己的源代码文件: 所有博客文件目录索引:博客目录索引(持续更新)关键技术有如下五点:SLAM问题可以描述为: 机器人在未知环境中从一个未知

每个人都是独一无二的,把握好自己的节奏,跟着自己的心走。 5475

如何免费访问和使用Gemini API?

Gemini Ultra具有最先进的性能,在几个指标上超过了GPT-4的性能。它是第一个在大规模多任务语言理解基准测试中超越人类专家的模型,该基准测试57个不同学科的世界知识和解决问题的能力。Gemini是谷歌迄今为止开发的最先进、最庞大的AI模型。它为多模态而建,理解并处理不同类型的数据,比如文本、代码、音频、图像和视频。下面我们将加载Masood Aslami的图像,并用它来测试Gemini Pro Vision的多模态性。有了Gemini可以为查询提供图像、音频和文本,获得几乎完美的答案。

java_cjkl的博客 1万+

【ROS】通过Gmapping完成机器人在特定地图下的导航

ros_control 是一套机器人控制的中间件,是一套规范,不同的机器人平台只要按照这套规范实现,那么就可以保证 与ROS 程序兼容,通过这套规范,实现了一种可插拔的架构设计,大大提高了程序设计的效率与灵活性。导航 = 建图 + 定位,上一步的建图中其实也包含定位的功能,但建图中的定位是用来构建全局地图的,而现在的定位需要应用于导航过程中,通过定位判断机器人的轨迹是否符合预期,这里我采用acml功能包用于机器人的定位。在Gazebo中可以通过添加组件的方式在空世界中创建自定义地图,这里我找到了一个。

apple_53697949的博客 2587

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

ROS理论与实践学习笔记——6 ROS机器人导航(仿真)

在机器人自主导航领域,ROS(Robot Operating System)提供了一套强大的导航功能包集,帮助机器人在复杂环境中实现自主定位、路径规划和障碍物避让等任务。ROS 导航功能集成了全局路径规划、局部路径调整和运动控制等模块,使得机器人能够在仿真环境中进行全方位的导航测试。

心有所信,方能远行! 3044

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

上一篇: ROS入门(八)——仿真机器人四(Gazebo+Rviz+雷达、摄像头、kinet仿真显示)
下一篇: ROS入门(十)——两只小乌龟(乌龟跟随C++实现)
Netceor
博客等级 码龄9年 1046粉丝 306原创
评论 22
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值