move_base包
在总体框架图中可以看到、move_base提供ROS导航的配置,运行、交互接口、它主要包括两个部分:
(1)全局路径规划(global planner):根据给定的目标位置进行总体路径的规划
(2)本地实时规划(local planner):根据附近的障碍物进行躲避路线规划。
一、数据结构
ROS中定义了MoveBaseActionGoal数据结构来存储导航的目标位置数据,其中最重要的就是位置坐标(position)和方向(orientation)
rosmsg show MoveBaseActionGoal
[move_base_msgs/MoveBaseActionGoal]:
std_msgs/Header header
uint32 seq
time stamp
string frame_id
actionlib_msgs/GoalID goal_id
time stamp
string id
move_base_msgs/MoveBaseGoal goal
geometry_msgs/PoseStamped target_pose
std_msgs/Header header
uint32 seq
time stamp
string frame_id
geometry_msgs/Pose pose
geometry_msgs/Point position
float64 x
float64 y
float64 z
geometry_msgs/Quaternion orientation
float64 x
float64 y
float64 z
float64 w
二、配置文件
move_base使用前需要配置一些参数:运行成本,机器人半径、到达目标位置、机器人移动的速度、这些参数都在rbx1_nav包的以下几个配置文件中:
? base_local_planner_params.yaml
? costmap_common_params.yaml
? global_costmap_params.yaml
? local_costmap_params.yaml
三、全局路径规划(global planner)
在ROS的导航中,首先会通过全局路径规划,计算出机器人到目标位置的全局路线。这一功能是navfn这个包实现的。
navfn通过Dijkstra最优的算法,计算costmap上的最小花费路径、作为机器人的全局路线。将来在算法上应该还会加入A*算法。
四、本地实时规划(local planner)
本地的实时规划是利用base_local_planner包实现的。该包使用Trajectory Rollout和Dynamic Window approaches算法计算机器人每个周期内应该行驶的速度和角度(dx、dy、dtheta velocities)
base_local_planner这个包通过地图数据,通过算法搜索到达目标的多条路径,利用一些评价标准(是否会撞击障碍物,所需要的时间等等)选取最优的路径,并且计算所需要的实时速度和角度。
其中、Trajectory Rollout和Dynamic Window approaches 算法的主要思路如下:
(1)采样机器人当前的状态(dx,dy,dtheta)
(2)针对每个采样的速度、计算机器人以该速度行驶一段时间后的状态,得出一条行驶的路线。
(3)利用一些评价标准为多条路线打分
(4)根据打分、选择最优路径
(5)重复上面过程。
五、控制系统架构
关于机器人导航与定位的系统架构,在《ros by example》chapter 7 一章中介绍了控制机器人的5个层次。这里笔者请按照自己的理解以及开发经验给出三个层次。
**最底层:**机器人本身的电机驱动部分(DSP可实现,51单片机也可以满足),该部分通过串口接收电脑端输出的左右轮速度、对左右轮分别进行PID控速。同时、定时采样电机码盘值,并转化为左右轮速度值通过串口上传给电脑。当然PID控速这一部分也可以放到电脑ROS端,这样电脑串口输出的是直接的PWM值而不是之前的期望速度
**中间通信层:**电脑端和底层电机的控制通信、以及将传感器发布给ROS的通信。这一层主要通过串口(ros已经集成了pyserial操作这个模块进行串口控制)收集左右轮速度值、用航迹推演法将左右轮速度转化为机器人的x轴方向速度和机器人的旋转速度、然后发布/odom主题,好让ROS的对应package收到这个消息,进行机器人位置的估计。同时,这一部分还要关注ROS相应部分发出的机器人控制指令、转化为左右轮的期望速度、再通过串口传给DSP,这一层需要自己写程序完成。
**决策层:**就是与导航有关的了,建立地图和定位,然后用move_base根据发布的传感器信息做出路径规划以及机器人的速度和转向控制。这一部分为ROS相应的package以及完成,我们只需要调用即可.
在这个系列里、我们只关注如何用move_base package做出的控制对机器人进行实际控制。文章接下来的部分将按照从上到下的顺序,一个问题一个问题介绍如何使用move_base控制实际机器人。
1.move_base package系统介绍
ROS提供的move_base包让我们能够在已建立好的地图中指定目标位置和方向后,move_base根据机器人的传感器信息控制机器人到达我们想要的目标位置。它主要功能包括:结合机器人码盘推算出的odometry信息,做出路径规划,输出前进速度。这两个速度是根据你在配置文件里设定的最大速度和最小速度而自动做出加减速度决策。下面的白色底色方框内就是move_base的内容:
图中我们可以看到move_base package 的输入和输出。要使得它能运转起来,我们就得构建好这些输入何荣输出。
必要的输入:
goal:期望机器人在地图中的目标位置。
tf : 各个坐标系之间的转换关系。(具体/map frame–>/odom frame、/odom frame --> /base_link frame)
odom:根据机器人左右轮速度推算出航向信息(即/odom坐标系中机器人x,y坐标以及航向角yaw、下面具体介绍)
LaserScan:激光传感器的信息,用于定位。(在这个系列教程中、我们没有用到这个激光信息,而是在一个假的空白地图上对机器人进行控制、并假定/map坐标系和/odom坐标系完全重合,在后面会有关于这两个坐标系的介绍)
输出:
cmd_vel:在cmd_vel这个主题上发布Twist消息,这个消息包含的就是机器人的期望前进速度和转向速度。
再整理下思路:move_base收到goal以后,将目标goal通过基于actionlib的client(客户端)向服务器根据你的tf关系以及发布的odom消息不断反馈机器人状态(feedbackcall)到客户端,让move_base做路径规划和控制twist。
知道了move_base的这些外围消息接口后,move_base的运行还需要一些内部的配置参数,如机器人最大最小速度,已经路径规划的最大转弯半径等。
至此,我们已经熟悉了move_base各种接口,它订阅了什么消息,会发布什么消息都已经清楚了。因此让move_base控制实际的机器人最主要的就是要解决实际机器人如何发布这些消息给move_base,以及如何接受move_base发出的消息。
2. Twist 消息转化为机器人左右轮期望速度。
首先,假设move_base能够正常工作了,它将把控制命令Twist发布到cmd_vel这个主题上。我们现在来解决如何利用这个Twist消息来对机器人进行控制。
在ROS by example 一书中的第七章开头就规定了机器人自身的坐标系系统,如下图。注意两个坐标系的建立都是右手坐标系,左图中的右手就是机器人本身,x轴就是前进的方向,垂直于两轮之间的轴连线,Y轴就是两个轮之间的轴连线。右图表示机器人的旋转坐标系,大拇指指向Z轴,逆时针方向为正值。
清楚了坐标系以后,再来看看Twist这个消息里包含的是什么东西。
使用ctrl + alt + t 打开一个新的终端以后,输入如下命令,就可以查看Twist的消息类型了。
rosmsg show geometry_msgs/Twist
其中linear 的x就是代表前进方向的速度,单位为m/s。angular 的z就代表机器人的绕中心旋转的角速度,单位为 弧度/s (rad/s)。
因此,我们只要在自己写的中间通信层程序中订阅cmd_twist这个主题(topic),就可以收到move_base发出的命令了。 下面给出一个如何订阅cmd_twist主题的demo。
六、下载move_base导航包
sudo apt-get install ros-kinetic-navigation
1.新建(修改)Rgmapping.launch启动文件
nvidia@tegra-ubuntu:~/roborts_ws/src/roborts_bringup/launch$
<launch>
<master auto="start"/>
<rosparam command="load" file="$(find roborts_base)/config/roborts_base_parameter.yaml" />
<!-- Run the Base Node -->
<node pkg="roborts_base" type="roborts_base_node" name="roborts_base_node" output="screen" respawn="true" />
<!-- Run the rplidar Node -->
<node name="rplidarNode" pkg="rplidar_ros" type="rplidarNode" output="screen">
<param name="serial_port" type="string" value="/dev/ttyUSB4"/>
<param name="serial_baudrate" type="int" value="115200"/><!--A1/A2 -->
<!--param name="serial_baudrate" type="int" value="256000"--><!--A3 -->
<param name="frame_id" type="string" value="base_laser_link"/>
<param name="inverted" type="bool" value="false"/>
<param name="angle_compensate" type="bool" value="true"/>
</node>
<!--static_transform_publisher x y z yaw pitch roll frame_id child_frame_id-->
<node pkg="tf2_ros" type="static_transform_publisher" name="base_link_base_laser_link_broadcaster"
args="0.0 0.0 0.00 0.0 0.0 0.0 base_link base_laser_link" />
<!-- Run the slam gmapping -->
<include file="$(find roborts_bringup)/launch/slam_gmapping.xml"/>
<!-- 运行rviz -->
<node pkg="rviz" type="rviz" name="rviz" args="-d $(find roborts_bringup)/rviz/Rmapping.rviz"/>
</launch>
1.启动roscore
2.启动rosbase结点也就是地盘结点
3.启动激光雷达结点,激光雷达配置需要注意串口和激光雷达坐标系(相等于基坐标系)base_link
4.tf转换把地盘坐标和激光雷达坐标tf转换
5.启动slam_gmapping.xml实现slam建图
6.启动rviz .rviz文件在roborts_bringup/rviz/Rmapping.rviz
2.新建(修改)slam_gmapping.xml
nvidia@tegra-ubuntu:~/roborts_ws/src/roborts_bringup/launch$
<launch>
<node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen">
<param name="odom_frame" value="odom"/>
<param name="map_update_interval" value="30.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.01"/>
<param name="srt" value="0.02"/>
<param name="str" value="0.01"/>
<param name="stt" value="0.02"/>
<param name="linearUpdate" value="0.5"/>
<param name="angularUpdate" value="0.436"/>
<param name="temporalUpdate" value="-1.0"/>
<param name="resampleThreshold" value="0.5"/>
<param name="particles" value="80"/>
<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>
</launch>
需要注意坐标系odom和激光雷达名称scan
3.新建(修改)base_local_planner_params.yaml
nvidia@tegra-ubuntu:~/roborts_ws/src/roborts_bringup/launch/mbot$
controller_frequency: 3.0
recovery_behavior_enabled: false
clearing_rotation_allowed: false
TrajectoryPlannerROS:
max_vel_x: 0.5
min_vel_x: 0.1
max_vel_y: 0.0 # zero for a differential drive robot
min_vel_y: 0.0
max_vel_theta: 1.0
min_vel_theta: -1.0
min_in_place_vel_theta: 0.5
escape_vel: -0.1
acc_lim_x: 1.5
acc_lim_y: 0.0 # zero for a differential drive robot
acc_lim_theta: 1.2
holonomic_robot: false
yaw_goal_tolerance: 0.1 # about 6 degrees
xy_goal_tolerance: 0.1 # 10 cm
latch_xy_goal_tolerance: false
pdist_scale: 0.9
gdist_scale: 0.6
meter_scoring: true
heading_lookahead: 0.325
heading_scoring: false
heading_scoring_timestep: 0.8
occdist_scale: 0.1
oscillation_reset_dist: 0.05
publish_cost_grid_pc: false
prune_plan: true
sim_time: 1.0
sim_granularity: 0.025
angular_sim_granularity: 0.025
vx_samples: 8
vy_samples: 0 # zero for a differential drive robot
vtheta_samples: 20
dwa: true
simple_attractor: false
4.新建(修改)costmap_common_params.yaml
nvidia@tegra-ubuntu:~/roborts_ws/src/roborts_bringup/launch/mbot$
obstacle_range: 2.5
raytrace_range: 3.0
footprint: [[0.175, 0.175], [0.175, -0.175], [-0.175, -0.175], [-0.175, 0.175]]
footprint_inflation: 0.01
robot_radius: 0.175
inflation_radius: 0.15
max_obstacle_height: 0.6
min_obstacle_height: 0.0
observation_sources: scan
scan: {data_type: LaserScan, topic: /scan, marking: true, clearing: true, expected_update_rate: 0}
5.新建(修改)global_costmap_params.yaml
nvidia@tegra-ubuntu:~/roborts_ws/src/roborts_bringup/launch/mbot$
global_costmap:
global_frame: map
robot_base_frame: base_link
update_frequency: 1.0
publish_frequency: 1.0
static_map: true
rolling_window: false
resolution: 0.01
transform_tolerance: 1.0
map_type: costmap
需要注意输出的map和base_link
6.新建(修改)local_costmap_params.taml
nvidia@tegra-ubuntu:~/roborts_ws/src/roborts_bringup/launch/mbot$
local_costmap:
global_frame: odom
robot_base_frame: base_link
update_frequency: 3.0
publish_frequency: 1.0
static_map: true
rolling_window: false
width: 6.0
height: 6.0
resolution: 0.01
transform_tolerance: 1.0
需要注意odom和base_link
nvidia@tegra-ubuntu:~/roborts_ws/src/roborts_bringup/launch$
roslaunch roborts_bringup Rgmapping.launch
roslaunch roborts_bringup Rmove_base.launch
roslaunch mbor_teleop mbot_teleop.launch
rostopic echo /odom
rostopic list
命令终端内容
结点网络图
rviz内的效果