💭

知能ロボコンのGazeboワールド作成メモ

2024/06/09に公開

大まかな手順

  1. 3D CAD(Autodesk Fusion)でワールドの元になるデータを作る
  2. Blenderを使ってデータをGazeboで使えるデータに変換する
  3. Gazeboワールドを構築する
  4. ROS 2で使えるようにする
  5. 動作確認

もうちょっと詳しく

3D CAD(Autodesk Fusion)でワールドの元になるデータを作る

情報収集

作るものが「知能ロボコンの競技場」なのでその情報を得ます。知能ロボコン2024のルールブック
もうちょっと実物イメージがほしい方は過去の競技動画を探しましょう。YouTubeにあります。

Fusionで競技場データを作る

Fusionでやることは以下。

  1. 競技場を作る(頑張りましょう)
  2. 次工程のBlenderにインポートするためにデータ形式.fbxでエクスポートしローカルPCに保存(Fusionはデータは基本的にクラウドに置かれる)。

Fusionの操作方法がわからない方は、ググったりYouTubeで勉強しましょう。私は「やのすけ【初心者向けFusion360解説】」を参考にしました。Fusionの使い方だけでなく3D CAD自体がわからなかった自分でも作れるようになったのでおすすめです。良質な資料を残してくれる方々には感謝しかありません。

Fusionのライセンスは非商用の個人ライセンスを使ってます。

ライントレースの線は0.1mmの高さのBodyにしました。色付けは、正直良くわかりません。外観で色を付けられますが、Gazeboで表示させるとうまく色が出てなかったり、謎。

ということで、出来上がった競技場をエクスポートしローカルPCに保存しましょう。

Blenderを使ってデータをGazeboで使えるデータに変換する

ここでやることは以下。

  1. Fusionで作った.fbxをインポート
  2. データの向き・大きさがあってるかどうか確認。間違っていたら回転させたりスケールを変えたりして整える。Gazeboは単位がメートルなのでそれに合わせたほうが良い(と思う)。
  3. ファイル形式.stlと.dae形式でエクスポートしローカルPCに保存

Blenderの操作方法の習得は…頑張りましょう。私にとってBlenderはFusionより遥かに難易度が高く正直使いたくない(最初にスプラッシュ・スクリーンと立方体オブジェクトを消すまでが立ち上げ手順、とか意味不明)。

自分がよくやる操作は以下です。それ以外はわかりません。

  1. 右上の「シーンコレクション」ペインでインポートしたオブジェクトをクリック
  2. 右下のペインで「トランスフォーム」を表示させ、回転角度を変える
  3. 上記「トランスフォーム」でスケールを変える
  4. 左側にある定規ボタンをクリックして長さがあってるかどうかを確認する
  5. 上のメニューバーで「ファイル」>「エクスポート」で所望の形式でファイルを書き出す

なお、私はBlenderはWindows版を使っています。

Gazeboワールドを構築する

本メモ作成時点では、ROS 2(Humble)を使っており、それを前提で進めます。

Blenderで変換した.stlと.daeファイルをUbuntuPCにデータを入れます(自分の場合Windows機とUbuntu機は別)。

ディレクトリ構成

ファイルは~/ros2_ws/src/square/square_gazebo以下に作るようにしました。
ROS 2パッケージ名はsquare_gazeboとしました。

完成状態のsquare_gazeboディレクトリは以下のようになりました。

├── CMakeLists.txt
├── launch
│   └── irc.launch.py
├── models
│   └── irc_table
│       ├── meshes
│       │   ├── irc_table.dae
│       │   └── irc_table.stl
│       ├── model.config
│       └── model.sdf
├── package.xml
└── worlds
    └── irc.world

Blenderで変換した.daeと.stlはそれぞれmodels/irc_table/meshesディレクトリ以下のirc_table.daeirc_table.stlです。

ということで、作成が必要なファイルは以下です。

  • model.config
  • model.sdf
  • irc.world
  • irc.launch.py
  • CMakeLists.txt

model.configを書く

model.configはほぼ固定した書き方ではないかと思います。

model.config
<?xml version="1.0"?>

<model>
  <name>irc_table</name>
  <version>1.0</version>
  <sdf version="1.6">model.sdf</sdf>

  <author>
    <name>XXYYZZ</name>
    <email>XXYYZZ@XXYYZZ</email>
  </author>

  <description>
   IRC table
  </description>
</model>

model.sdfを書く

model.sdfは以下としました。

model.sdf
<?xml version="1.0" ?>
<sdf version="1.6">
  <model name="measurement">
    <static>true</static>
    <link name="link">
      <collision name="collision">
        <geometry>
          <mesh>
            <scale>1 1 1</scale>
            <uri>model://irc_table/meshes/irc_table.stl</uri>
          </mesh>
        </geometry>
        <surface>
          <friction>
            <ode>
              <mu>1.2</mu>
              <mu2>1.2</mu2>
            </ode>
          </friction>
        </surface>
      </collision>
      <visual name="visual">
        <geometry>
          <mesh>
            <scale>1 1 1</scale>
            <uri>model://irc_table/meshes/irc_table.dae</uri>
          </mesh>
        </geometry>
      </visual>
    </link>
  </model>
</sdf>

worldファイルを作る

worldファイルをコピー

turtlebot3_gazeboパッケージのempty_world.worldファイルを元ネタとして作ります。

cd ~/ros2_ws/src/square/square_gazebo
cp /opt/ros/humble/share/turtlebot3_gazebo/worlds/empty_world.world worlds/irc.world

競技場を追加

irc.worldに追加します。

irc.world
    <model name="irc_table">
      <static>1</static>
      <include>
        <uri>model://irc_table</uri>
      </include>
    </model>

ボールの生成

irc.worldに追加します。
競技場内にボールが15個置かれるのがルールですが、ここでは1個だけを記載します。2個め以降は同様に書けばできるはずなので省略します。

以下の記述は

  • C1エリアのだいたい左半分
  • ボール(球)の半径0.033[m]
  • ボールの色は赤(本当は赤・青・黄色の3色をランダムに生成したいけどわからないので決め打ち)
  • ボールの生成場所はランダム(座標(x,y,z)=(0.250,-1.070,0.29)を中心、領域サイズ(0.240,0.120,0.01))
  • ボールの生成個数は1

となります。

irc.world
    <!-- C1 -->
    <population name="ball_population_1">
      <model name="ball_1">
        <link name='obstacle_1'>
          <collision name='obstacle_1'>
            <geometry>
              <sphere>
                <radius>0.033</radius>
              </sphere>
            </geometry>
            <max_contacts>10</max_contacts>
            <surface>
              <bounce/>
              <friction>
                <ode/>
              </friction>
              <contact>
                <ode/>
              </contact>
            </surface>
          </collision>

          <visual name='obstacle_1'>
            <geometry>
              <sphere>
                <radius>0.033</radius>
              </sphere>
            </geometry>
            <material>
              <script>
                <uri>file://media/materials/scripts/gazebo.material</uri>
                <name>Gazebo/Red</name>
              </script>
            </material>
          </visual>
        </link>
      </model>
      <pose>0.250 -1.070 0.29 0 0 0</pose>
      <box>
        <size>0.240 0.120 0.01</size>
      </box>
      <model_count>1</model_count>
      <distribution>
        <type>random</type>
      </distribution>
    </population>

ROS 2で使えるようにする

launchファイルの作成

irc.launch.pyファイルは以下のとおりです。gzserverにworldファイルをパラメータとして渡せばよいようです。

irc.launch.py
import os

from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration


def generate_launch_description():
    launch_file_dir = os.path.join(get_package_share_directory('square_gazebo'), 'launch')
    pkg_gazebo_ros = get_package_share_directory('gazebo_ros')

    use_sim_time = LaunchConfiguration('use_sim_time', default='true')
    world = os.path.join(
        get_package_share_directory('square_gazebo'),
        'worlds',
        'irc.world'
    )

    gzserver_cmd = IncludeLaunchDescription(
        PythonLaunchDescriptionSource(
            os.path.join(pkg_gazebo_ros, 'launch', 'gzserver.launch.py')
        ),
        launch_arguments={'world': world}.items()
    )

    gzclient_cmd = IncludeLaunchDescription(
        PythonLaunchDescriptionSource(
            os.path.join(pkg_gazebo_ros, 'launch', 'gzclient.launch.py')
        )
    )

    ld = LaunchDescription()

    # Add the commands to the launch description
    ld.add_action(gzserver_cmd)
    ld.add_action(gzclient_cmd)

    return ld

CMakeFilesの作成

CMakeFiles.txtは以下のとおりです。インストールすべきディレクトリをinstall(以下に書けばよいようです。

CMakeFiles.txt
cmake_minimum_required(VERSION 3.8)
project(square_gazebo)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)

install(
  DIRECTORY launch worlds models
  DESTINATION share/${PROJECT_NAME}
)

ament_package()

動作確認

ビルド

cd ~/ros2_ws
colcon build
ros2 launch square_gazebo irc.launch.py

上記スクリーンショットはボールを15個出してあります。worldファイルを頑張って作れば出せます。
ロボットのspawnやros2_controlによるロボット制御は今後書くかも?

最後に

屋外でロボット実機を動かしたいです。資金はありませんが。

参考

Gazebo: 自作stl modelの作り方と表示方法
Gazebo: CADモデル、Actorを使用して自作worldを作成してみる

Discussion