目前为止, 我们都旨在构建一个能够自主运行的机器人,这个就研究方向更加合理的名词应该叫自主移动机器人. 推荐一本个人觉得很不错的书 Ronald C. Arkin – 2011- Introduction to Autonomous Mobile Robots. 本文的主要目的是先把框架搭起来, 采用原型模式, 然后在此基础上循环的进行深化, 望能够起到抛砖引玉的作用.
Part 5 机器人环境探索与避障
一个完整的自主移动机器人应该是一个see-think-act的环路, 包括机器人感知, 定位与制图, 路径规划, 运动控制.
导航规划部分可以分为全局的目标导航(路径规划), 和局部的导航(避障). 机器人刚开始进入环境. 没有明确的终点设定, 机器人在环境中进行自由探索, 主要依赖避障来控制机器人的运动. Turtlebot提供Kinect相机可以用于避障, 对于RGB-D深度相机的避障可分为两类. 第一就是直接采用Kinect点云避障, 可以使用SBPL (Search-based planning library), OMPL (Open Motion Planning Library)等库. 第二类, 将点云转换为平面的laser scan, 类似于gmapping, cartographer, 采用DWA (Dynamic Window Approach) 或者 TEB (Timed Elastic Band algorithm)避障. 这里我们采用一种更加简单的方式, 将点云进行裁剪, 然后在水平方向求和, 根据左右两边障碍物点云判断向左向右运动, 参考robot-photographer.
1 架构
本文中所述的自主移动机器人采用turtlebot, 从Kinect 采集点云传入obstacle avoidance 节点中,给出避障转向; navigation节点根据机器人避障转向信息和收到的指令信息做出最终的控制决策,传入到locomotion节点; 最后locomotion节点给出机器人的运动控制命令.
在明白框架后, 故事就很清晰了, 毕竟没有怎么涉及理论的东西,
2 软件
整个project中, 包含四个文件夹turtlebotslam_gazebo, turtlebotslam_obstacle_avoidance, turtlebotslam_navigation, turtlebotslam_locomotion, 其目录如下所示:
├── turtlebotslam_gazebo
│ ├── CMakeLists.txt
│ ├── launch
│ │ ├── gmapping_demo.launch
│ │ ├── includes
│ │ │ ├── create.launch.xml
│ │ │ ├── kobuki.launch.xml
│ │ │ └── roomba.launch.xml
│ │ ├── keyboard_teleop.launch
│ │ ├── keyop.launch
│ │ ├── turtlebotslam_gazebo.launch
│ │ └── turtlebotslam_rviz.launch
│ ├── package.xml
│ ├── rviz
│ │ └── navigation.rviz
│ ├── src
│ └── worlds
│ ├── barrier.world
│ ├── cafe.world
│ ├── corridor.world
│ ├── empty.world
│ └── playground.world
├── turtlebotslam_locomotion
│ ├── CMakeLists.txt
│ ├── CMakeLists.txt~
│ ├── include
│ │ ├── direction_source.h
│ │ ├── driving_direction.h
│ │ ├── locomotion.hpp
│ │ ├── locomotion_state.h
│ │ └── turtlebotslam_locomotion
│ ├── launch
│ │ └── locomotion.launch
│ ├── package.xml
│ ├── param
│ │ └── keyop_smoother.yaml
│ └── src
│ └── locomotion.cpp
├── turtlebotslam_navigation
│ ├── CMakeLists.txt
│ ├── CMakeLists.txt~
│ ├── include
│ │ ├── direction_source.h
│ │ ├── driving_direction.h
│ │ └── navigation.hpp
│ ├── launch
│ │ └── navigation.launch
│ ├── package.xml
│ └── src
│ └── navigation.cpp
├── turtlebotslam_obstacle_avoidance
│ ├── CMakeLists.txt
│ ├── CMakeLists.txt~
│ ├── include
│ │ ├── driving_direction.h
│ │ ├── obstacle_avoidance.hpp
│ │ └── turtlebotslam_control
│ ├── launch
│ │ └── obstacle_avoidance.launch
│ ├── package.xml
│ └── src
│ └── obstacle_avoidance.cpp
我将所有需要启动的部分全部打包到一个单一的launch文件, 包括Gazebo 环境, 机器人模型, 以及深度图像到点云的转换等利用ROS自带基础库的配置部分. 也包括rviz, 避障, 导航, 运动控制, 及gmapping功能部分, 见turtlebotslam_gazebo.launch
<?xml version="1.0"?>
<launch>
<!-- <arg name="world_file" default="$(env TURTLEBOT_GAZEBO_WORLD_FILE)"/> -->
参数说明
<arg name="base" value="$(optenv TURTLEBOT_BASE kobuki)"/> <!-- create, roomba -->
<arg name="battery" value="$(optenv TURTLEBOT_BATTERY /proc/acpi/battery/BAT0)"/> <!-- /proc/acpi/battery/BAT0 -->
<arg name="gui" default="true"/>
<arg name="stacks" value="$(optenv TURTLEBOT_STACKS hexagons)"/> <!-- circles, hexagons -->
<arg name="3d_sensor" value="$(optenv TURTLEBOT_3D_SENSOR kinect)"/> <!-- kinect, asus_xtion_pro -->
在Gazebo中启动world
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="use_sim_time" value="true"/>
<arg name="debug" value="false"/>
<arg name="gui" value="$(arg gui)" />
<!--arg name="world_name" value="$(arg world_file)"/-->
<arg name="world_name" value="$(find turtlebotslam_gazebo)/worlds/barrier.world"/>
<!--remap from="/camera/rgb/image_raw/compressed" to="/stlucia/camera/image/compressed"/-->
</include>
机器人描述文件
<include file="$(find turtlebotslam_gazebo)/launch/includes/$(arg base).launch.xml">
<arg name="base" value="$(arg base)"/>
<arg name="stacks" value="$(arg stacks)"/>
<arg name="3d_sensor" value="$(arg 3d_sensor)"/>
</include>
<node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher">
<param name="publish_frequency" type="double" value="30.0" />
</node>
深度图像到laser scan
<!-- Fake laser -->
<node pkg="nodelet" type="nodelet" name="laserscan_nodelet_manager" args="manager"/>
<node pkg="nodelet" type="nodelet" name="depthimage_to_laserscan"
args="load depthimage_to_laserscan/DepthImageToLaserScanNodelet laserscan_nodelet_manager">
<param name="scan_height" value="10"/>
<param name="output_frame_id" value="/camera_depth_frame"/>
<param name="range_min" value="0.45"/>
<remap from="image" to="/camera/depth/image_raw"/>
<remap from="scan" to="/scan"/>
</node>
启动rviz
<include file="$(find turtlebotslam_gazebo)/launch/turtlebotslam_rviz.launch">
</include>
避障
<include file="$(find turtlebotslam_obstacle_avoidance)/launch/obstacle_avoidance.launch">
</include>
导航
<include file="$(find turtlebotslam_navigation)/launch/navigation.launch">
</include>
运动控制
<include file="$(find turtlebotslam_locomotion)/launch/locomotion.launch">
</include>
制图
<include file="$(find turtlebotslam_gazebo)/launch/gmapping_demo.launch">
</include>
</launch>
工程的源码下载地址请见: 在ROS中开始自主机器人仿真 – 5 机器人环境探索与避障
3 仿真结果
至此, 一个简易的自主移动机器人便可以工作了. 下面的命令便可启动整个仿真过程:
roslaunch turtlebotslam_gazebo turtlebotslam_gazebo.launch
运行结果如下:
4 Reference
- Obstacle Detection and Avoidance Using TurtleBot Platform and XBox Kinect
- An Autonomous Robot Photographer
- Autonomous mobile robots 2nd edition
- GeRoNa: Generic Robot Navigation
- http://wiki.ros.org/teb_local_planner