1. はじめに
前回の記事では、OpenRoboticsの tower_crane.dae を base(土台)と upper(ジブ)に分割し、ジブが Z 軸まわりに旋回するモデルを作りました。今回はより実際の動きに近づけるため、前回記事の旋回モデルに **トロリ(横行)とフック(巻上げ・巻き下げ)**の機能 を追加して、(θ, r, h) の3軸で動かせるようにしてみました。
タワークレーンの動作は、円筒座標 (θ, r, h) に分けられます。
- θ(旋回) … ジブが Z 軸まわりに回る ← 前回
- r(横行) … トロリがジブに沿って前後する ← 今回
- h(巻上げ) … フックが上下する ← 今回
完成すると、こんな動きになります:
最終的には以下のリンクの論文「Automating the Tower Crane: Integrating the Development and Simulation of Path Planning and Trajectory Tracking of Tower Crane in ROS Framework」(ISARC 2024) に倣って、ROS で自動搬送を再現したいと考えています。
2. 実行環境
| 項目 | 内容 |
|---|---|
| OS | Ubuntu 22.04 LTS |
| シミュレータ | Gazebo Classic 11.10.2 / SDF 1.6 |
- メッシュは
.dae(COLLADA) ではなく.objを使います(後述:DAE が重いと gzclient が固まることがあるため)。
3. 関節の構成
3つの関節を、親子関係で繋ぎます。**トロリもフックもジブの「子」**なので、旋回(θ)させると一緒に連れ回り、その上で横行(r)・巻上げ(h)が独立して動きます。
world
└─(fixed)─ base_link … マスト(土台)
└─(yaw_joint / revolute Z)─ upper_link … ジブ(旋回 θ)
└─(trolley_joint / prismatic)─ trolley_link … トロリ(横行 r)
└─(hoist_joint / prismatic Z)─ hook_link … フック(巻上げ h)
4. トロリ・フックは元データに入っていた
「トロリとフックは自分でモデリングするか…」と思っていたのですが、tower_crane.dae を確認すると、ジブの下にトロリ+滑車ブロック+フックがちゃんと存在していました。
そこで、前回 base/upper を分割したのと同じ要領で、Blender でルーズパーツから該当部品だけを抽出し、軽量な OBJ として書き出して使います。
-
trolley.obj… トロリ -
hook.obj… フック(ワイヤ+シーブ+鉤)
抽出したトロリ/フックはマテリアルを外して書き出します。こうするとタワー本体と同じ Gazebo 標準グレーで描画され、色が浮きません。また、ジブ側(upper)に残っている元のフック形状は削除**しておきます(残すと可動フックと二重に見えるため)。
5. model.sdf にトロリ・フックを追加する
yaw_joint の後ろに、以下を追記します。
<!-- ===== トロリ(ジブ下弦に沿って横行 r)===== -->
<link name="trolley_link">
<pose>0.06 -10 28.3 0 0 0</pose> <!-- ジブ下弦の直下に配置 -->
<gravity>false</gravity>
<inertial>
<mass>50</mass>
<inertia><ixx>10</ixx><iyy>10</iyy><izz>10</izz>
<ixy>0</ixy><ixz>0</ixz><iyz>0</iyz></inertia>
</inertial>
<visual name="trolley_vis">
<geometry>
<mesh><uri>model://tower_crane_rot/meshes/trolley.obj</uri></mesh>
</geometry>
</visual>
</link>
<joint name="trolley_joint" type="prismatic">
<parent>upper_link</parent> <!-- ジブの子。だから旋回に追従する -->
<child>trolley_link</child>
<axis>
<xyz>0 -1 0</xyz> <!-- ジブ長手(-Y)方向 -->
<limit>
<lower>-8</lower> <!-- スポーン(y=-10)基準で根元寄り -->
<upper>12</upper> <!-- 先端寄り -->
<effort>5000</effort>
<velocity>2.0</velocity>
</limit>
<dynamics><damping>50.0</damping></dynamics>
</axis>
</joint>
<!-- ===== フック(巻上げ h:トロリ直下を昇降)===== -->
<link name="hook_link">
<pose>0.06 -10 27.9 0 0 0</pose> <!-- トロリ直下 -->
<gravity>false</gravity>
<inertial>
<pose>0 0 -1.4 0 0 0</pose> <!-- CoG をフック実体中央へ -->
<mass>10</mass>
<inertia><ixx>2</ixx><iyy>2</iyy><izz>2</izz>
<ixy>0</ixy><ixz>0</ixz><iyz>0</iyz></inertia>
</inertial>
<visual name="hook_vis">
<geometry>
<mesh><uri>model://tower_crane_rot/meshes/hook.obj</uri></mesh>
</geometry>
</visual>
</link>
<joint name="hoist_joint" type="prismatic">
<parent>trolley_link</parent> <!-- トロリの子。θ・r に h を追加 -->
<child>hook_link</child>
<axis>
<xyz>0 0 -1</xyz> <!-- 下向き正=巻き下げ -->
<limit>
<lower>0</lower> <!-- h=0:巻き上げ最上 -->
<upper>24</upper> <!-- 最大 ~24m 巻き下げ -->
<effort>5000</effort>
<velocity>2.0</velocity>
</limit>
<dynamics><damping>20.0</damping></dynamics>
</axis>
</joint>
このSDFでやること
-
trolley_joint(prismatic)でトロリをジブ長手方向(0 -1 0)にスライドさせる -
hoist_joint(prismatic)でフックを鉛直(0 0 -1)に昇降させる(--pos-tの値が吊り下げ量[m]) - どちらも親が
upper_link/trolley_linkなので、旋回(θ)に自動で追従する
6. 動かしてみる
ターミナルを 2つ 使います。
ステップ1:ターミナルA で Gazebo を起動
cd ~/tower_crane_ws
gazebo --verbose tower_crane_rot.world
クレーンが表示されます。このターミナルは開いたままにします。
ステップ2:ターミナルB を開いて、最初に1回だけ
source /usr/share/gazebo-11/setup.sh
これで gz コマンドが使えるようになります。
ステップ3:トロリを横行させる(r)
# ジブ先端へ
gz joint -m tower_crane_rot -j trolley_joint --pos-t 10 --pos-p 1e3 --pos-i 50 --pos-d 5e3
# 根元へ戻す
gz joint -m tower_crane_rot -j trolley_joint --pos-t -6 --pos-p 1e3 --pos-i 50 --pos-d 5e3
トロリ(とフック)がジブに沿って動きます。--pos-t の値は -8(根元)〜 +12(先端)。
ステップ4:フックを巻き下げ/巻き上げする(h)
# 巻き下げ(12m 下ろす)
gz joint -m tower_crane_rot -j hoist_joint --pos-t 12 --pos-p 5e2 --pos-i 20 --pos-d 2e3
# 巻き上げ(最上へ戻す)
gz joint -m tower_crane_rot -j hoist_joint --pos-t 0 --pos-p 5e2 --pos-i 20 --pos-d 2e3
ステップ5:ジブを旋回させる(θ)
# 右旋回
gz joint -m tower_crane_rot -j yaw_joint --pos-t 0.6 --pos-p 2e5 --pos-d 1.2e6
# 左旋回
gz joint -m tower_crane_rot -j yaw_joint --pos-t -0.6 --pos-p 2e5 --pos-d 1.2e6
--pos-t はラジアン。ここで見るべきポイント:旋回させた状態で横行させると、トロリは「グローバルなY軸」ではなく「回転後のジブ方向」に動きます。トロリ・フックがジブの子になっているおかげです。
7. ハマりどころ
実際に動かすまでに、いくつかエラーがでまして以下のような対応をとりました。
-
スポーン位置を可動範囲(limit)の内側にする
prismatic 関節は、リンクの初期位置が<limit>の外側だと、起動直後に限界補正の大きな力がかかってシミュレーションが発散します。hoist_jointの<lower>を0(=初期位置)にするなどして、初期姿勢を必ず範囲内に収めます。 -
PID ゲインは控えめに
gz joint --pos-tは力ベースの PID です。ゲインを上げすぎると(特に旋回)振動して上部が吹っ飛びます。上記の値あたりから始めるのが安全です。 -
慣性をきちんと与える
ジブにトロリがぶら下がるので、upper_linkに十分な<inertial>を与えないと旋回時に倒れます。重心(CoG)はジブの高さ・旋回軸上に置くのがコツです。 -
DAE が重いと gzclient が固まる
Blender から書き出した COLLADA(.dae) が数十 MB に肥大化し、gzclient が読み込みでフリーズしました。OBJ で書き出すと数百 KB に収まり、安定して表示できました。
8. まとめ
前回の 旋回(θ) に加えて、今回 横行(r) と 巻上げ(h) を追加し、タワークレーンの基本動作 (θ, r, h) をひと通り動かせるようになりました。トロリ・フックは元の tower_crane.dae に入っていた部品をそのまま使えたので、見た目も自然にできているかなと思います。
今後は ISARC 2024 の論文を参考に、ROS / ROS2 から軌道計画 → 関節指令を送り、荷物を A 地点から B 地点へ自動搬送するところまで取り組みたいと思っています。
ライセンス / クレジット
本記事で使用した3Dモデル「tower_crane」は、Open Robotics による
Gazebo モデルデータベース(osrf/gazebo_models)に含まれるもので、
Creative Commons Attribution 3.0 Unported (CC BY 3.0) で提供されています。
- 原著作物: tower_crane (Open Robotics)
- 出典: https://github.com/osrf/gazebo_models/tree/master/tower_crane
- ライセンス: CC BY 3.0 — https://creativecommons.org/licenses/by/3.0/
- 改変: base/upper/トロリ/フックへの分割、旋回・横行・巻上げジョイントの追加、
.obj への変換を行いました(改変あり)。