ROS2におけるシミュレータ
大阪大学 中島優作
↑ シミュレータで表示した例。一見、前章のモデル表示と同じに見えますが、中身はまったく違います
前章と本章の決定的な違いは
「制御」しているかどうか です。
GUIでパラメーターを変えて、
単に「表示」を動かしていただけ。
コントローラ(制御プログラム)が
計算して「ロボット」を制御します。
💡 ここでのコードは、設定を切り替えるだけで「実機」でもそのまま動きます。
| 比較項目 | 簡易シミュレーション | 物理シミュレータ |
|---|---|---|
| ツール名 | Mock Components (ros2_control) |
Gazebo |
| 仕組み | 物理演算 なし 指令通りに動いたことにする |
物理演算 あり 重力・摩擦・衝突を計算 |
| 特徴・用途 | 動作が非常に軽い 動作・通信の確認に最適 |
処理が重い より現実に近い検証が可能 |
※多くの場合は簡易シミュレーションで十分です。物理シミュレータはシミュレーション上での学習等で使います。
→ 全画面表示
↑ 見かけは実機のロボットを動かすときと全く同じです
↓以下で説明
Mock Components が起動しない場合、controller_manager と
realtime_tools の不整合で落ちることがあります。まず関連パッケージを更新します。
sudo apt update &&
sudo apt install --reinstall \
ros-humble-realtime-tools \
ros-humble-controller-manager \
ros-humble-ros2-control \
ros-humble-ros2-controllers \
ros-humble-joint-state-broadcaster \
ros-humble-joint-trajectory-controller \
ros-humble-ros2controlcli
Ur5eの例
ros_study/launch/ur5e_bringup_with_mock_components.launch.py
を参照してください
ros_study/config/ur_joint_trajectory_controller.yaml を用意します⚠️ このxacroはシミュレータ (mock_components) 専用であり、実機では使用できません。
ros_study/urdf/ur5e_with_ee_mock_components.xacro が mock
components 用の canonical source です
cd ~/ros2_ws
colcon build
source install/setup.bash
ros2 launch ros_study ur5e_bringup_with_mock_components.launch.py
ros2 run rqt_joint_trajectory_controller rqt_joint_trajectory_controller
↑ RVizの設定例
worldやbase_linkフレームがデフォルトrobot_descriptionに設定/joint_states は joint_state_broadcaster が配信$ ros2 run rqt_gui rqt
(Plugins > Robot Tools > Joint Trajectory Controller)
$ ros2 topic info /joint_states
Type: sensor_msgs/msg/JointState
Publisher count: 1 (joint_state_broadcaster)
※データフローの詳細は「ros2_control」の章で解説します。
↓以下で説明
※図をクリックすると拡大表示されます
# [A-1] Mock用 (緑: Simulator)
control_node_mock = Node(
package="controller_manager",
executable="ros2_control_node",
parameters=[robot_description, controllers_file_param],
condition=IfCondition(use_fake_hardware),
)
# [A-2] 実機用 (紫: Real Robot)
control_node_real = Node(
package="ur_robot_driver",
executable="ur_ros2_control_node",
parameters=[robot_description, controllers_file_param],
condition=UnlessCondition(use_fake_hardware),
)
# [D/E] コントローラ起動 (水色: Controller)
joint_state_broadcaster_spawner = Node(
package="controller_manager",
executable="spawner",
arguments=["joint_state_broadcaster", ...],
)
initial_joint_controller_spawner = Node(
package="controller_manager",
executable="spawner",
arguments=[initial_joint_controller, ...],
)
# [B/C] ロボット表示・RViz (赤: Display)
robot_state_publisher_node = Node(
package="robot_state_publisher",
parameters=[robot_description],
)
rviz_node = Node(
package="rviz2",
arguments=["-d", rviz_config_file],
)
名前がややこしいので、検索するときは区別に注意しましょう
(通称: 旧Gazebo / Gazebo 11)
gazebo(旧称: Ignition Gazebo)
gz simROS 2とGazeboを通信させるためのパッケージをインストールします
1. モダンなGazebo (推奨) の場合
本スライドではこっちを使います
# ros_gz: ブリッジやシミュレータ本体
sudo apt-get install ros-${ROS_DISTRO}-ros-gz
# ros2_control 連携: Gazebo上のロボットを controller_manager で動かす
sudo apt-get install ros-${ROS_DISTRO}-gz-ros2-control
2. Gazebo Classic (旧) の場合
# gazebo_ros_pkgs (Classic用の関連パッケージ)
sudo apt-get install ros-${ROS_DISTRO}-gazebo-ros-pkgs
インストールが完了したら、gazeboを起動
(Gazebo Fortress)
# コマンドは "ign" です
ign gazebo shapes.sdf
(Gazebo Harmonic)
# コマンドは "gz" です
gz sim shapes.sdf
初めて起動する際はモデルデータのダウンロードが行われるため、 画面が出るまでに数分間、真っ暗な状態が続くことがあります。 故障ではないのでそのまま待ってください。
package://... や model://... の解決に必要な
GZ_SIM_RESOURCE_PATH / IGN_GAZEBO_RESOURCE_PATH が不足していることがあります。
export GZ_SIM_RESOURCE_PATH=/opt/ros/${ROS_DISTRO}/share:~/zero_ros/ros2_ws/install/ros_study/share
export IGN_GAZEBO_RESOURCE_PATH=$GZ_SIM_RESOURCE_PATH
mesh 解決エラーが出ると、ロボットが一部だけ表示されたり、まったく見えないことがあります。
どちらのGazeboを使う場合でも、ros2_control経由で動かすという基本構成は変わりません。
gazebo_ros2_control プラグインを使用gz_ros2_control プラグインを使用※本講座では、環境構築の手軽さから Gazebo (New) を使用します。
Gazeboで動かすには、ロボットの記述(URDF)に
「Gazebo用の設定」を追記する必要があります。
urdf/ros2_control.xacro
<hardware>
<plugin>mock_components/GenericSystem</plugin>
</hardware>
<hardware>
<plugin>gz_ros2_control/GazeboSimSystem</plugin>
</hardware>
GazeboSimSystem
というプラグインを指定することで、
「実在しないハードウェア」ではなく「Gazebo上のロボット」として認識されます。
robot.urdf.xacro の末尾に、Gazebo から ROS 2 制御を呼ぶタグを追加します。
<gazebo>
<plugin filename="gz_ros2_control-system"
name="gz_ros2_control::GazeboSimROS2ControlPlugin">
<parameters>
$(find ros_study)/config/ur_joint_trajectory_controller.yaml
</parameters>
</plugin>
</gazebo>
⚠️ ハマるポイント
このタグがないと表示だけされて、controller_manager が起動せず動きません。
Gazeboを起動し、そこにロボットを登場させる(Spawn)
ためのLaunchファイルを作成します。
# 1. Gazebo Sim の起動
gazebo = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[PathJoinSubstitution([FindPackageShare("ros_gz_sim"),
"launch", "gz_sim.launch.py"])]
),
launch_arguments={"gz_args": "-r empty.sdf"}.items(),
)
# 2. ロボットのSpawn (出現させる)
spawn_entity = Node(
package="ros_gz_sim", executable="create",
arguments=[
"-topic", "robot_description", # URDFを読み込む
"-name", "my_robot",
"-z", "0.1", # 地面へのめり込み防止
],
output="screen",
)
# 3. ブリッジ (ROS2 <-> Gazebo 通信)
bridge = Node(
package="ros_gz_bridge", executable="parameter_bridge",
arguments=[
# クロック(時間)の同期
"/clock@rosgraph_msgs/msg/Clock[gz.msgs.Clock",
],
output="screen",
)
※コントローラの起動部分はMockの時と同じなので省略しています
ros_study/urdf/ur5e_with_ee_gazebo.xacro
gz_ros2_control/GazeboSimSystem を使います<gazebo> タグで controller 設定ファイルを Gazebo 側へ渡します
ur5e_bringup_with_gazebo.launch.py に起動処理を集約しています/clock bridge、controller 起動までを担当します
cd ~/ros2_ws
source install/setup.bash
ros2 launch ros_study ur5e_bringup_with_gazebo.launch.py
動かない場合:
「再生ボタン(▶)」が押されているか確認してください。
Gazeboは起動直後、一時停止状態の場合があります。
controller が出ない場合:
ros2 control list_controllers がつながらないときは、
gz_ros2_control 未導入かresource path不足が多いです。
とくに mesh 解決エラーが出る場合は
GZ_SIM_RESOURCE_PATH / IGN_GAZEBO_RESOURCE_PATH
を確認してください。
gz_ros2_control 未導入: /controller_manager
が立たず、spawner が待ち続ける
ros2 topic echo /clock --once
ros2 action list | grep scaled_joint_trajectory_controller
/clock と controller の両方が見えていれば、Gazebo 側の最小構成は概ね正常です。
なぜ「ブリッジ」が必要なのか?
その仕組みとデータの流れを図解で理解します。
ROS 2とGazeboは、裏側で使っている通信の仕組み(ミドルウェア)が異なります。
通信方式: DDS
通信方式: Gz Transport
直接は会話できないため、翻訳機(ros_gz_bridge)が必要です。
実際の記述例(関節の状態)
/joint_states@sensor_msgs/msg/JointState[gz.msgs.Model
計算負荷しだいで、時間の進む速さが現実と違う
/clockuse_sim_time:=Trueノードは「現実の何時か」ではなく
「シミュレーション世界の何秒目か」を基準に動く
ロボットを何もない空間(Empty World)ではなく、
障害物や壁がある環境で動かす方法を学びます。
Gazebo (New) には「Resource
Browser」があり、
オンライン上のモデルライブラリ(Fuel)から物体を呼び出せます。
💡 Tips:
配置した環境は、左上のメニューから
File > Save World as... で保存(.sdfファイル)できます。
Launchファイルで empty.sdf の代わりに読み込ませる
オリジナルの世界ファイル(例:
my_world.sdf)を作ります。
<sdf version="1.6">
<world name="my_custom_world">
<physics name="1ms" type="ignored">
<max_step_size>0.001</max_step_size>
<real_time_factor>1.0</real_time_factor>
</physics>
<plugin filename="gz-sim-physics-system"
name="gz::sim::systems::Physics"></plugin>
<include>
<uri>https://fuel.gazebosim.org/1.0/OpenRobotics/models/Sun</uri>
</include>
<include>
<uri>https://fuel.gazebosim.org/1.0/OpenRobotics/models/Ground Plane</uri>
</include>
<model name="box_obstacle">
<pose>2.0 0 0.5 0 0 0</pose>
<link name="box_link">
<collision name="collision">
<geometry><box><size>1 1 1</size></box></geometry>
</collision>
<visual name="visual">
<geometry><box><size>1 1 1</size></box></geometry>
<material><ambient>1 0 0 1</ambient></material>
</visual>
</link>
</model>
</world>
</sdf>
作ったWorldファイルを読み込むように変更します。
# launch/gazebo_sim.launch.py
gazebo = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[PathJoinSubstitution([FindPackageShare("ros_gz_sim"),
"launch", "gz_sim.launch.py"])]
),
launch_arguments={
# "empty.sdf" を自作ファイルに変更
"gz_args": "-r " + os.path.join(
get_package_share_directory('ros_study'),
'worlds', 'obstacle_world.sdf')
}.items(),
)
※ worlds フォルダを
CMakeLists.txt
でインストールする設定を忘れずに!
Gazeboに障害物を置くだけでは、
ロボット (MoveIt) は障害物を認識しません。
MoveItが衝突判定に使うのは Planning Scene に入っている物体だけ。
反映できているか RViz で必ず確認しましょう。
※ どちらの方法でも、RViz の MotionPlanning 表示で障害物が見えていればOK
ロボットアームの関節は主に以下のいずれかで制御されます
Mock Hardware → 位置・速度制御で十分
Gazebo 等の物理シミュレータ → トルク制御が基本
なぜ変わるのか? ↓
トルク制御で学習・動作確認
力・摩擦がなめらかに変化
→ 制御が発散しにくい
多くは位置制御で動作
位置を直接いじるので急激な変化
→ 不安定になりやすい
例: Simで強化学習した動作を実機に移すと、挙動が変わる
Simと現実の差は制御方式の違いからも生じることを意識しよう。
Mock Components や Gazebo で「表示は出るが動かない」「TF がつながらない」ときは、まず次を確認します。
# TF tree
ros2 run tf2_tools view_frames
ros2 run tf2_ros tf2_echo world base_link
ros2 run tf2_ros tf2_echo base_link tool0
# Joint state
ros2 topic echo /joint_states --once
# ros2_control
ros2 control list_controllers
ros2 control list_hardware_interfaces
# 必要なら GUI
sudo apt update &&
sudo apt install ros-${ROS_DISTRO}-ros2controlcli ros-${ROS_DISTRO}-rqt-controller-manager
rqt_controller_manager