ナビゲーションでは、自律移動ロボットが、作成した地図に基づき、自己位置を認識し、目標位置への経路を計画し移動します。
自律移動ロボット(AMR)のマッピング
上の画像は、シミュレータGazeboの画面(左)と、RViz2の画面(右)
マッピングでは、自律移動ロボット(AMR)を移動させて、部屋の地図を作成します。
シミュレータ上で地図作成の準備
シミュレータGazeboを起動します。willowgarageの部屋を使います。
ros2 launch hajimecart_gazebo willowgarage_world.launch.py
willowgarage_world.launch.py
import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch.actions import IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource from launch_ros.actions import Node from launch_ros.parameter_descriptions import ParameterValue from launch.substitutions import Command, LaunchConfiguration def generate_launch_description(): pkg_gazebo_ros = get_package_share_directory('gazebo_ros') pkg_my_gazebo = get_package_share_directory('hajimecart_gazebo') worlds = os.path.join(pkg_my_gazebo, 'worlds', 'willowgarage.world') urdf_model_dir = get_package_share_directory('hajimecart_description') urdf_model_path = os.path.join(urdf_model_dir, 'urdf', 'hajimecart_gazebo.urdf') model_arg = DeclareLaunchArgument(name='model', default_value=str(urdf_model_path), description='Absolute path to robot urdf file') robot_description = ParameterValue(Command(['xacro ', LaunchConfiguration('model')]), value_type=str) # Gazebo launch gazebo = IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join(pkg_gazebo_ros, 'launch', 'gazebo.launch.py'), ) ) spawn_entity = Node(package='gazebo_ros', executable='spawn_entity.py', arguments=['-entity', 'hajimecart', '-topic', '/robot_description', '-x', '8', '-y', '-8', '-z', '0', '-Y', '3.141592654'], output='screen') robot_state_publisher = Node( package='robot_state_publisher', executable='robot_state_publisher', parameters=[{'robot_description': robot_description}] ) return LaunchDescription([ DeclareLaunchArgument( 'world', default_value=[worlds, ''], description='SDF world file'), model_arg, gazebo, spawn_entity, robot_state_publisher ])
地図作成プログラムを起動します。
ros2 launch hajimecart_navigation online_async_launch.py use_sim_time:=True
online_async_launch.py
import os from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node from ament_index_python.packages import get_package_share_directory def generate_launch_description(): use_sim_time = LaunchConfiguration('use_sim_time') slam_params_file = LaunchConfiguration('slam_params_file') default_params_file = os.path.join(get_package_share_directory("hajimecart_navigation"), 'config', 'mapper_params_online_async.yaml') declare_use_sim_time_argument = DeclareLaunchArgument( 'use_sim_time', default_value='true', description='Use simulation/Gazebo clock') declare_slam_params_file_cmd = DeclareLaunchArgument( 'slam_params_file', default_value=default_params_file, description='Full path to the ROS2 parameters file to use for the slam_toolbox node') start_async_slam_toolbox_node = Node( parameters=[ slam_params_file, {'use_sim_time': use_sim_time} ], package='slam_toolbox', executable='async_slam_toolbox_node', name='slam_toolbox', output='screen') ld = LaunchDescription() ld.add_action(declare_use_sim_time_argument) ld.add_action(declare_slam_params_file_cmd) ld.add_action(start_async_slam_toolbox_node) return ld
willowgarage.world
<?xml version="1.0" ?> <sdf version="1.6"> <world name="default"> <include> <uri>model://sun</uri> </include> <include> <uri>model://ground_plane</uri> </include> <include> <uri>model://willowgarage</uri> </include> </world> </sdf>
地図作成の様子を画面に表示するために、RViz2を起動します。
ros2 launch hajimecart_description display_nav.launch.py use_sim_time:=True
シミュレータ上で地図作成
キーボードで自律移動ロボットを操縦して、部屋を周ります。
ros2 run teleop_twist_keyboard teleop_twist_keyboard
RViz2の画面上に生成されている地図が表示されます。
自律移動ロボットが動いていくと地図が生成されていきます。画面を見ながら地図の出来具合を確認します。
作成した地図を保存
地図がよい具合に出来上がったら、地図を保存します。この例では、ファイル名 my_map-willowに地図を出力します。
ros2 run nav2_map_server map_saver_cli -f my_map-willow
作成した地図です。
画像で、黒線が占有領域(壁や障害物)、白色が自由領域(移動可能)、グレーが未知領域です。
動画
地図作成の様子を動画にしました。
シミュレーションによる自律移動ロボットの地図作成 (ROS2 Humble)
自律移動ロボット(AMR)のナビゲーション
上の画像は、シミュレータGazeboの画面(左)と、RViz2の画面(右)
ナビゲーションでは、自律移動ロボット(AMR)が、自己位置を認識し、目標位置への経路を計画し移動します。
シミュレータを起動
シミュレータGazeboを起動します。地図作成に使用したwillowgarageの部屋を使います。
ros2 launch hajimecart_gazebo willowgarage_world.launch.py
シミュレータでナビゲーションを起動
ナビゲーションプログラムを起動します。地図は上で作成した地図を指定します。
ros2 launch hajimecart_navigation navigation2.launch.py use_sim_time:=True map:=${HOME}/hajimecart_ws/src/hajimecart_navigation/maps/my_map-willow.yaml
navigation2.launch.py
import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch.actions import IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource from launch.substitutions import LaunchConfiguration def generate_launch_description(): use_sim_time = LaunchConfiguration('use_sim_time', default='false') map_dir = LaunchConfiguration( 'map', default=os.path.join( get_package_share_directory('hajimecart_navigation'), 'maps', 'my_map.yaml')) param_dir = LaunchConfiguration( 'params_file', default=os.path.join( get_package_share_directory('hajimecart_navigation'), 'params', 'nav2_params.yaml')) nav2_launch_file_dir = os.path.join(get_package_share_directory('nav2_bringup'), 'launch') return LaunchDescription([ DeclareLaunchArgument( 'map', default_value=map_dir, description='Full path to map file to load'), DeclareLaunchArgument( 'params_file', default_value=param_dir, description='Full path to param file to load'), DeclareLaunchArgument( 'use_sim_time', default_value='True', description='Use simulation (Gazebo) clock if true'), IncludeLaunchDescription( PythonLaunchDescriptionSource([nav2_launch_file_dir, '/bringup_launch.py']), launch_arguments={ 'map': map_dir, 'use_sim_time': use_sim_time, 'params_file': param_dir}.items(), ) ])
画面表示および操作用にRViz2を起動します。
ros2 launch hajimecart_description display_nav.launch.py use_sim_time:=True
display_nav.launch.py
import os from ament_index_python.packages import get_package_share_path from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch_ros.actions import Node from launch_ros.parameter_descriptions import ParameterValue from launch.substitutions import Command, LaunchConfiguration def generate_launch_description(): use_sim_time = LaunchConfiguration('use_sim_time', default='True') urdf_model_dir = get_package_share_path('hajimecart_description') urdf_model_path = os.path.join(urdf_model_dir, 'urdf', 'hajimecart.urdf') model_arg = DeclareLaunchArgument(name='model', default_value=str(urdf_model_path), description='Absolute path to robot urdf file') rviz_config_dir = get_package_share_path('hajimecart_description') rviz_config_path = os.path.join(rviz_config_dir, 'rviz', 'nav2_default_view.rviz') # rviz_config_path = os.path.join(rviz_config_dir, 'rviz', 'slam_toolbox_default.rviz') rviz_arg = DeclareLaunchArgument(name='rvizconfig', default_value=str(rviz_config_path), description='Absolute path to rviz config file') rviz_node = Node( package='rviz2', executable='rviz2', name='rviz2', output='screen', arguments=['-d', LaunchConfiguration('rvizconfig')], ) robot_description = ParameterValue(Command(['xacro ', LaunchConfiguration('model')]), value_type=str) robot_state_publisher_node = Node( package='robot_state_publisher', executable='robot_state_publisher', parameters=[{'use_sim_time': use_sim_time, 'robot_description': robot_description}] ) return LaunchDescription([ model_arg, rviz_arg, rviz_node, robot_state_publisher_node ])
RViz2を起動すると、画面上に地図が現れます。
自律移動ロボットの現在位置と向きを設定
自律移動ロボットの現在位置と向きを設定します。
RViz2の上のメニューから「2D Pose Estimate」をクリックします。
表示された緑色の矢印で、矢印の起点がロボットの位置、矢印の先がロボットの向きになるように設定します。
設定したロボットの現在位置の周りに、緑色の点群が表示されます。
<自己位置の推定>
車輪の回転量から計算した位置(オドメトリ)と、LiDARの情報と地図を照らし合わせて、確率な方法で求めます。
地図の黒線の周囲が水色とピンク色で表示されます。
<グローバル・コストマップ>
地図にある障害物の情報を管理します。
ロボット近辺ではコストマップの色が濃くなります。
<ローカル・コストマップ>
センサ(LiDAR)による障害物の情報を管理します。
自律移動ロボットの目標位置と向きを設定
目標地点を設定します。
RViz2の上のメニューから「Nav2 Goal」をクリックします。
表示された緑色の矢印で、ロボットの目標位置と向きを設定します。
現在位置と目標位置の間に、赤い線が引かれます。
<グローバル・パス(経路)>
地図に基づき、障害物を避けて(グローバル・コストマップ)、目標位置までの経路です。
ロボットはおおむね赤い線に沿って進みます。
<ローカル・パス(経路)>
円弧状の青い線はグローバルの経路に沿うように、障害物を避けて(ローカル・コストマップ) 、ロボットの加速度を考慮した経路です。
自律移動ロボットの移動
径路が計算されると、自律移動ロボットは移動を始めます。
ロボットには、移動機構による移動方向の制限、速度や加速度の制限があります。それらを考慮し、さらに、LiDARにより検出された地図にない新たな障害物を避けて進みます。
目標位置と向きに到達するとロボットは停止します。
動画
自律移動ロボットでナビゲーションにより移動するシミュレーション(ROS2 Humble使用)