notes
Tools

rosbag と一緒に「その時の状態」を残す (launch wrapper)

git rev + dirty diff + param snapshot + ros env を録画時に自動で残す。sidecar dir か MCAP 内蔵。実装は rc26 流儀の XML 1 ファイル + shell script (Option B) を採用

要点: rosbag 単体は「後で見たとき何が動いていたか」を残さない。録画起動時に git rev + dirty diff + ros2 param dump の snapshot + ros env を残す launch wrapper を書く。標準ツールは無い。採用: Option B (rc26 流儀の XML 1 ファイル + shell script)。sidecar dir と MCAP 内蔵の両方に吐く。

問題#

rosbag に入るのは topic データだけ。抜けるのは:

  1. git rev + dirty diff (commit していないコードで走った場合の再現)
  2. 各ノードの実効パラメータ (yaml + launch override + 実行中 set 済みの合成後)
  3. launch args
  4. ROS_DOMAIN_ID / RMW_IMPLEMENTATION / DDS 設定
  5. インストール済み ros-* パッケージの版
  6. ハード状態 (CAN if 名、カメラ s/n)

どこに保存するか#

sidecar dir (手元開発向け)#

bag_2026-08-28_abc1234/
├── rosbag2_2026_08_28-.../   # rosbag2 出力
└── manifest/
    ├── git_rev.txt
    ├── git.patch              # dirty tree の再現に必須
    ├── params_snapshot.yaml   # ros2 param dump 全ノード
    ├── ros_env.txt
    ├── nodes.txt / topics.txt
    └── rosdep.txt

grep しやすい。ディレクトリごと配る必要がある。

MCAP 内蔵 (配布向け)#

MCAP は Attachment (任意ファイル埋め込み: name / media_type / log_time / create_time / data) と Metadata (key-value マップ) を第一級 record 型で持つ。.mcap 1 ファイルに snapshot を全部詰められる。Foxglove Studio の "Data source info" panel から一覧・DL 可能。

mcap attach bag.mcap --file manifest/git.patch \
  --name git.patch --media-type text/x-diff
mcap attach bag.mcap --file manifest/params_snapshot.yaml \
  --name params.yaml --media-type application/yaml
mcap metadata add bag.mcap --name run \
  --key git_rev=abc1234 --key branch=main --key host=$(hostname)

mcap info bag.mcap                        # summary
mcap list attachments bag.mcap
mcap get attachment bag.mcap --name git.patch --output /tmp/git.patch

フラグ名は版で微妙にブレる。mcap --help で確認。

rosbag2_snapshot は名前が紛らわしいが循環バッファ用途 (異なる問題)。混同注意。

両方吐くのが実務#

sidecar は手元 grep 用、MCAP 内蔵は配布用。post-hoc で mcap attach を呼ぶだけなので実装コストは大差ない。両方吐くのが結局最適。

Option 比較#

Python (A)XML+shell (B, 採用)純 XML (C)
フック機構TimerAction / OnProcessExit / OpaqueFunction 全部揃うshell の trap<event_handler> のみ
読みやすさ意図が構文に出るshell 部分は分離分かりにくい
rc26 流儀との整合別枠同じ (<executable> 1 発)同じ
デバッグPython debuggerbash -xXML の展開ログ頼み

Bを採用する理由: rc26 の rosbag_record.launch.xml が <executable> 1 発の流儀。XML は形を揃えて中身は shell で書く方が後から読みやすい。Python launch は機能豊富だが、この用途では shell の trap で十分。C は罠が多い (TimerAction 相当が無い、<let> の評価タイミングが読みにくい)。

Option B の実装#

XML (rc26 の rosbag_record.launch.xml と同形):

<launch>
  <arg name="rosbag_base" default="$(env HOME)/rosbags"/>
  <executable
    cmd="$(find-pkg-share salamander_bringup)/scripts/rosbag_with_manifest.sh $(var rosbag_base)"
    output="screen"/>
</launch>

shell (実体):

#!/bin/bash
BAG_DIR="$1/rosbag2_$(date +%Y_%m_%d-%H_%M_%S)"
MANIFEST="$BAG_DIR/manifest"
mkdir -p "$MANIFEST"

# pre-record snapshot
cd "${WS_ROOT:-$HOME/ros2_ws}"
git rev-parse HEAD              > "$MANIFEST/git_rev.txt"
git rev-parse --abbrev-ref HEAD >> "$MANIFEST/git_rev.txt"
git diff HEAD                   > "$MANIFEST/git.patch"
env | grep -E '^ROS_|^RMW_'     > "$MANIFEST/ros_env.txt"
ros2 node list -a               > "$MANIFEST/nodes.txt"       2>/dev/null || true
ros2 topic list -t              > "$MANIFEST/topics.txt"      2>/dev/null || true
dpkg -l 'ros-*' | awk '/^ii/{print $2,$3}' > "$MANIFEST/rosdep.txt" || true

# post-hoc (record 終了時)
finish() {
  for f in "$BAG_DIR"/*.mcap; do
    [ -f "$f" ] || continue
    mcap attach "$f" --file "$MANIFEST/git.patch"            --name git.patch    --media-type text/x-diff       2>/dev/null || true
    mcap attach "$f" --file "$MANIFEST/params_snapshot.yaml" --name params.yaml  --media-type application/yaml   2>/dev/null || true
    mcap attach "$f" --file "$MANIFEST/ros_env.txt"          --name ros_env.txt  --media-type text/plain         2>/dev/null || true
    mcap metadata add "$f" --name run \
      --key "git_rev=$(cat "$MANIFEST/git_rev.txt" | head -1)" \
      --key "host=$(hostname)"                                                                                   2>/dev/null || true
  done
}
trap finish EXIT INT TERM

# param dump は 5s 後 (ノード立ち上がり待ち)
( sleep 5
  for n in $(ros2 node list 2>/dev/null); do
    echo "# --- $n ---"
    ros2 param dump "$n" 2>/dev/null
  done > "$MANIFEST/params_snapshot.yaml" ) &

# record — exec しない (trap を効かせるため)
ros2 bag record -a --storage mcap -o "$BAG_DIR"

注意: exec ros2 bag record にすると trap が効かなくなる。裸で呼ぶ。

補助: /parameter_events を bag に含める#

param dump snapshot と組み合わせて、実行中の param set 変更を record 期間中は追える。

ros2 bag record --include-hidden-topics ...
# または明示
ros2 bag record /parameter_events /topic1 ...

限界: /parameter_events は set のときしか流れない。開始前に declare 済みのパラメータは初期スナップショットとして流れてこない。真の snapshot は ros2 param dump (上記) で取る。

復元#

レビュー時:

  1. manifest/git.patch を git apply (または mcap get attachment bag.mcap --name git.patch --output /tmp/git.patch)
  2. params_snapshot.yaml で launch override
  3. これで「その時の状態」が再現。CI で自動 replay 基盤にもなる

関連#

  • [[rosbag-analysis-workflow]] — 記録した bag をどう解析するかの三層分担
最終更新:

On this page