チュートリアル用メディアの撮影手順
docs/images/ に置いているスクリーンショット・動画(GIF)を、toio_gazeboシミュレーションから撮り直す/追加する手順。すべてホストのX11ディスプレイ上でGazebo・RVizを動かし、画面を取り込む。以下のコマンドは docs/ ディレクトリで実行する前提で、出力先を images/ 相対で書いている。
前提ツール
sudo apt-get install -y ffmpeg imagemagick scrot xdotool wmctrl fonts-noto-cjk
ffmpeg… 画面録画(x11grab)とGIF変換import(imagemagick)… ウィンドウ単位のスクリーンショットxdotool/wmctrl… ウィンドウの前面化・座標取得fonts-noto-cjk… 端末風PNG(05_bidding_log.png)の日本語描画
sim起動(録画対象)
source /opt/ros/jazzy/setup.bash
source ~/dev_ws/install/setup.bash
ros2 launch toio_rmf_bringup toio_rmf.launch.py mat:=a3 run_sim:=true use_sim_time:=true
RVizの表示がマット向けに正しく出るにはrmf_visualization のsmall-mapsパッチが必要(未適用だとfootprint/vicinityの巨大な円柱がnavグラフを覆う)。手順はdocs/SETUP.mdの「rmf_visualizationパッチ」を参照。
ウィンドウ単位のスクリーンショット
export DISPLAY=:1
# 対象ウィンドウIDを調べる(RViz / Gazebo Sim)
wmctrl -lG | grep -iE 'rviz|gazebo'
# 前面化して取り込む
WID=0xXXXXXXXX
xdotool windowactivate $WID; xdotool windowraise $WID; sleep 0.5
import -window $WID images/00_setup_rviz.png
画面録画 → GIF
ffmpeg のx11grabで対象ウィンドウの矩形を録画する。幅・高さは偶数にすること(libx264は奇数サイズを拒否する。RViz既定1853x1025 → 1852x1024)。
# 位置とサイズ: xdotool getwindowgeometry <WID> で確認
ffmpeg -y -f x11grab -framerate 15 -video_size 1852x1024 -i :1.0+81,118 \
-t 16 -pix_fmt yuv420p /tmp/clip.mp4
# mp4 -> GIF(パレット生成で発色を良く。横幅は 926 程度に縮小)
ffmpeg -y -i /tmp/clip.mp4 -vf "fps=10,scale=926:-2:flags=lanczos,palettegen" /tmp/pal.png
ffmpeg -y -i /tmp/clip.mp4 -i /tmp/pal.png \
-lavfi "fps=10,scale=926:-2:flags=lanczos[x];[x][1:v]paletteuse" images/04_patrol.gif
動きを確実に写すには「タスク投入 → 数秒待って走り出してから録画開始」。タスク完了後に撮ると静止画になる(GIFがほとんど変化せず数KBほどのファイルになっていたら、これが原因)。
合成GIF(左RViz / 右Gazebo)
04_patrol.gif / 06_traffic.gif はRVizとGazeboを左右に並べた合成GIF。「スケジュール(RViz)」と「実際のキューブの動き(Gazebo)」を同時に見せるため。同一走行からRVizとGazeboの両ウィンドウを毎フレーム同時にグラブするので、左右のパネルはフレーム単位で同期する。ffmpeg が使えない環境向けに、Pythonだけで撮影・合成する手順も用意した。
pip install --user mss imageio python-xlib # 画面グラブ / GIF / ウィンドウ操作
前提: RVizをマットスケールで綺麗に写すため、rmf_visualization のsmall-mapsパッチを適用しておく(docs/SETUP.md)。未適用だとfootprint/vicinityの巨大マーカーがnavグラフを覆う。
- simをGUI付きで起動(
toio_rmf.launch.pyをrmf_headlessを付けずに実行 →Gazebo GUIとRMF可視化RVizが両方:1に出る)。実GPU付きのX(:1)ならヘッドレス寄りの環境でもGUIは描画される。 - 2つのウィンドウを重ならないように左右へ配置(
python-xlibの_NET_MOVERESIZE_WINDOW/_NET_ACTIVE_WINDOW)。 - タスクを投入し、走り出すまで数秒(交通調停なら約5秒)待ってから録画を始める。毎フレームRVizとGazeboの両矩形を
mssでグラブし、描画部分をcropして連番PNGのペアで保存する(10fps × 180フレーム=18秒)。trafficは片道で終わると後半が静止するので、2台を逆向きに周回(例:patrol_B patrol_Cとpatrol_C patrol_B)させて全編クロスし続ける画にする。 - RVizを左、Gazeboを右に置いて横並び合成し、ラベル(
RViz2/Gazebo)を焼き込む(Pillow)。両パネルは同じフレーム番号=同時刻なので同期する。 - GIF軽量化のコツ: 静止部の微小レンダノイズで色indexがブレるとフレーム間圧縮が効かず数MBに膨れる。
ImageOps.posterize(5)でノイズを丸め、共有パレット・ディザ無効・disposal=1(前フレームに差分だけ上書き)で保存すると、180フレームでも1〜2MBに収まる。
RVizのカメラ(フィット/センタリング)
rviz/toio_rmf.rviz の Views > Current(TopDownOrtho)で決まる:
| キー | 値 | 意味 |
|---|---|---|
Scale |
2200 |
px/m相当。大きいほど拡大。A3マットが画面に収まる値 |
X / Y |
0.2 / -0.15 |
注視点(マット中央) |
A4マットで撮るときは Scale を上げ気味に、X/Y をA4の中央へ合わせる。
既知の注意点
- タスク開始直後にnavグラフ/床面図が一度消えることがある。navgraph visualizerが起動直後にDELETEALLを送り、RVizがそれを受けてクリアするため(publisher側のlatchデータは生きている)。撮影前にRVizを一度リロードしておくと、再購読でnavグラフが復活し、以後はタスク中も残って安定する。
- Gazeboウィンドウはマップを見失わないので、「実行中の様子」を確実に撮るにはGazebo側が手堅い。
各メディアの撮り方(対応表)
| ファイル | 対象 | 撮り方 |
|---|---|---|
00_setup_gazebo.png |
Gazebo | 起動直後、2台がチャージャー上の全景 |
00_setup_rviz.png |
RViz | 同上のnavグラフ全景(idle) |
03_go_to_place.gif |
RViz+Gazebo(合成) | dispatch_go_to_place -p patrol_B -R toio1 で対角に移動する様子を左RViz/右Gazeboで同時グラブ(上記「合成GIF」参照) |
04_patrol_rviz.png |
RViz | patrol投入後、スケジュール経路帯が出た瞬間 |
04_patrol.gif |
RViz+Gazebo(合成) | patrol走行を左RViz/右Gazeboで並べた合成GIF(上記「合成GIF」参照) |
05_bidding_log.png |
端末風PNG | dispatch_patrol の -R有/無 の実出力を並べて描画(scripts外の生成物) |
06_traffic_rviz.png |
RViz | 2台に別タスクを投入、経路帯が交錯した瞬間 |
06_traffic.gif |
RViz+Gazebo(合成) | 2台の交差を左RViz/右Gazeboで並べた合成GIF(上記「合成GIF」参照) |
07_battery_charge.gif |
RViz+Gazebo(合成) | publish_battery:=true(放電を速めた例)でpatrol → 残量低下 → チャージャーで充電 → 復帰。左RViz/右Gazeboを同時グラブし、左下にtoio1の残量バー(/fleet_states の battery_percent)を焼き込む(上記「合成GIF」参照) |
08_delivery.gif |
RViz+Gazebo(合成) | deliveryを投入し、pickup→dropoffの移動と各地点の保持を左RViz/右Gazeboで同時グラブ(上記「合成GIF」参照) |
09_fleet_action.gif |
RViz+Gazebo(合成) | dispatch_action を複数投入し、pickup(緑)/dropoff(青)のLED点灯と移動を左RViz/右Gazeboで同時グラブ(上記「合成GIF」参照) |
10_footprint_vicinity.png |
RViz | ScheduleMarkers の participant location 0/1 を表示に切り替え、稼働中の円が出た状態 |
10_dashboard_robots.png |
ブラウザ | rmf-webのRobotsタブ。別途コンテナ起動が要る(docs/DASHBOARD.md) |
07_battery_charge.gifは残量バーを焼き込むため、フレームごとに/fleet_statesのbattery_percentを記録しながら両ウィンドウをグラブし、合成時にバー(緑/黄/赤 +CHARGING表示)を描く。放電が速すぎると0%まで落ちてから充電に入るので、battery_discharge_rateは0%に達する前に帰還・充電が見える程度(例0.03)に抑える。残量の既定は10%刻みなので、滑らかなバーにするにはbattery_quantize_steps:=0を付ける。
図版(SVG)の原本
images/navgraph_a3.svg / navgraph_a4.svg / initial_placement_a4.svg は撮影物ではなく手描きのSVGで、原本はtoio_rmf_bringupのdocs/images/にある(bringup側のREADME・SETUP.md・TASKS.mdからも参照されるため)。変更するときはbringup側を更新し、このリポジトリへコピーして同期する。