背景・目的
前回、MCAPについて下記の記事で整理しました。
MCAPは、下記の特徴があります。
- 多様なシリアライズ形式のサポート
- 高性能な書き込みと読み取り
- メッセージスキーマやメタデータをファイル内に含む自己完結型の構造を持っています。これにより、外部の依存関係なしにデータの解釈や再生が可能
- 堅牢性とデータの回復性
今回、ros2とMCAPを操作しながら理解を進めます。
まとめ
ROS2の基本的概念
用語 | 説明 |
---|---|
ノード(node) | 処理の単位(例:カメラ、センサ) 1つのプロセス(アプリケーションの単位) |
トピック(topic) | ノード間で送受信されるメッセージのチャネル |
パブリッシャー | メッセージを送る側 |
サブスクライバー | メッセージを受け取る側 |
コマンド
下記にコマンドの特徴をまとめます。
カテゴリ | コマンド | 概要 | 補足 |
---|---|---|---|
トピック | ros2 topic list | 現在アクティブな トピック名の一覧 を表示する | 現在通信中または作成済のトピックが対象 |
ros2 topic info <トピック> | トピックの 型や Publisher/Subscriber 数 を確認する | 通信の方向性や型が確認できる | |
ノード | ros2 run <パッケージ名> <ノード> | 指定した ROS 2 パッケージに含まれる ノードスクリプトを起動する (例: Python ノード) |
ノードの自作・動作確認に使う |
Publisher | ros2 topic pub | 指定したトピックに 手動でメッセージを Publish(送信)する | デバッグや簡易送信に利用 |
ros2 bag play | bag ファイルの内容を 再度トピックに Publish(再生)する | 録画データのリプレイ用途 | |
Subscriber | ros2 topic echo <トピック> | 指定したトピックのメッセージを リアルタイムで表示する | データ確認・デバッグに有効 |
ros2 bag record | 指定したトピックのメッセージを ファイル(bag形式)に記録する | デバッグ・検証・再利用のために記録 | |
ros2 bag info | bag ファイルの メタ情報(トピック名・件数・時間など)を表示する | 記録内容の確認用 |
データフロー
上記のコマンドや概念を整理するとかきのようにあなります。
概要
MCAPについて
下記にまとめましたので、よろしければご参照ください。
ROS2
下記にまとめましたので、よろしければご参照ください。
あらためて、下記にも記載します。
- ROS 2は、Robot Operating System 2の略
- ロボットアプリケーションの開発を支援するためのオープンソースのミドルウェアフレームワーク
- ROS 1の後継として開発され、リアルタイム性やセキュリティ、マルチプラットフォーム対応などの機能強化が図られている
- 主な特徴は下記の通り
- モジュール性:ノード、トピック、サービスなどの概念により、機能を分割して開発・管理できる
- DDS(Data Distribution Service)ベース:リアルタイム通信やQoS(Quality of Service)の設定が可能
- マルチプラットフォーム対応:Linux、Windows、macOSなど、複数のOSで動作する
- セキュリティ強化:通信の暗号化や認証機能が追加されている
- ROS 2は、ロボットの制御、センサーの統合、データ処理など、ロボティクスアプリケーション全体の開発を支援するための包括的なフレームワーク
MCAPとROS2の関連性
項目 | MCAP | ROS 2 |
---|---|---|
種類 | ファイルフォーマット | ミドルウェアフレームワーク |
目的 | データの記録・保存 | ロボットアプリケーションの開発支援 |
データの扱い | タイムスタンプ付きのメッセージの保存 | ノード間の通信、センサー統合、制御など |
対応データ形式 | Protobuf、JSON、ROS 1/2メッセージなど | ROSメッセージ(ROS 1/2) |
関連性 | ROS 2のデータ記録フォーマットとして利用可能 | MCAPをデータ記録フォーマットとして利用可能 |
- MCAP:ロボティクス分野でのデータ記録・保存に特化したファイルフォーマット
- ROS 2:ロボットアプリケーション全体の開発を支援するミドルウェアフレームワーク
ROS2の基本的概念
用語 | 説明 |
---|---|
ノード(node) | 処理の単位(例:カメラ、センサ) 1つのプロセス(アプリケーションの単位) |
トピック(topic) | ノード間で送受信されるメッセージのチャネル |
パブリッシャー | メッセージを送る側 |
サブスクライバー | メッセージを受け取る側 |
実践
前提
下記を使用しています。
- Mac
- UTM
環境の準備
下記を基に環境を作ります。
- UTMを起動します
- 「ubuntu-24.04.2-live-server-amd64.iso」を基にインストールします
- インストールできました
~$ ros2 --help usage: ros2 [-h] [--use-python-default-buffering] Call `ros2 <command> -h` for more detailed usage. ... ros2 is an extensible command-line tool for ROS 2. options: -h, --help show this help message and exit --use-python-default-buffering Do not force line buffering in stdout and instead use the python default buffering, which might be affected by PYTHONUNBUFFERED/-u and depends on whatever stdout is interactive or not Commands: action Various action related sub-commands bag Various rosbag related sub-commands component Various component related sub-commands daemon Various daemon related sub-commands doctor Check ROS setup and other potential issues interface Show information about ROS interfaces launch Run a launch file lifecycle Various lifecycle related sub-commands multicast Various multicast related sub-commands node Various node related sub-commands param Various param related sub-commands pkg Various package related sub-commands run Run a package specific executable security Various security related sub-commands service Various service related sub-commands topic Various topic related sub-commands wtf Use `wtf` as alias to `doctor` Call `ros2 <command> -h` for more detailed usage. :~$
トピックの確認と送受信
- トピック一覧の確認をします。parameter_eventsとresoutがありました(デフォルトのようです)
$ ros2 topic list /parameter_events /rosout $
- ターミナルを2つ起動します(ここではターミナルAとターミナルBと呼びます)
送信(ターミナルA)
- 下記のコマンドでパブリッシュします
ros2 topic pub /hello_std_msgs std_msgs/String "data: 'Hello ROS 2'" publishing #1: std_msgs.msg.String(data='Hello ROS 2') publishing #2: std_msgs.msg.String(data='Hello ROS 2') publishing #3: std_msgs.msg.String(data='Hello ROS 2') publishing #4: std_msgs.msg.String(data='Hello ROS 2') publishing #5: std_msgs.msg.String(data='Hello ROS 2') ・・・・
※ パラメータは下記のとおりです。
- 特に引数を指定しない場合、送信し続けます
- topic:
- topic関連のコマンド
- pub:
- publish.指定したトピックにメッセージを送る
- /hello_std_msgs:
- 宛先とするトピック名(任意)
- std_msgs/Strings
- 送信するメッセージの型
- 標準の文字列型を指定
- "data: 'Hello ROS 2'"
- 送信するメッセージのbody
- dataフィールドに'Hello ROS2'を入れている
- topic:
受信(ターミナルB)
- 下記のコマンドでサブスクライブします
ros2 topic echo /hello_std_msgs data: Hello ROS 2 --- data: Hello ROS 2 --- data: Hello ROS 2 --- data: Hello ROS 2 --- data: Hello ROS 2 --- ・・・
※ echoにより、リアルタイムに出力されていることが確認できます
トピックの確認
-
ターミナルAで送信中に、ターミナルBでリストします。/hello_std_msgsトピックが表示されました
$ ros2 topic list /hello_std_msgs /parameter_events /rosout $
-
ターミナルAからの送信を止めます。(Ctrl+Cで抜けます)
-
ターミナルBで再びリストします。先ほど見えていた /hello_std_msgsトピック は消えました
ubuntu@ubuntu:~$ ros2 topic list /parameter_events /rosout ubuntu@ubuntu:~$
※ 一時的なトピックのため、送信を止めると消えるようです。Publisherである自分自身がノードを作っているようです。トピックを維持しているノードがいないと消えるようです。
※ /parameter_events
や/rosout
などは、ROS2が管理しており常に存在しているようです
ノードの操作
Pythonでノードを作成
テンプレート作成
-
srcディレクトリを作成します
~$ mkdir -p ~/ros2_ws/src ~$ cd ~/ros2_ws/src/ ~/ros2_ws/src$
-
サンプルノードを作成します
ros2 pkg create --build-type ament_python my_py_node --dependencies rclpy std_msgs === $ ros2 pkg create --build-type ament_python my_py_node --dependencies rclpy std_msgs going to create a new package package name: my_py_node destination directory: /home/ubuntu/ros2_ws/src package format: 3 version: 0.0.0 description: TODO: Package description maintainer: ['ubuntu <ubuntu@todo.todo>'] licenses: ['TODO: License declaration'] build type: ament_python dependencies: ['rclpy', 'std_msgs'] creating folder ./my_py_node creating ./my_py_node/package.xml creating source folder creating folder ./my_py_node/my_py_node creating ./my_py_node/setup.py creating ./my_py_node/setup.cfg creating folder ./my_py_node/resource creating ./my_py_node/resource/my_py_node creating ./my_py_node/my_py_node/__init__.py creating folder ./my_py_node/test creating ./my_py_node/test/test_copyright.py creating ./my_py_node/test/test_flake8.py creating ./my_py_node/test/test_pep257.py [WARNING]: Unknown license 'TODO: License declaration'. This has been set in the package.xml, but no LICENSE file has been created. It is recommended to use one of the ament license identifiers: Apache-2.0 BSL-1.0 BSD-2.0 BSD-2-Clause BSD-3-Clause GPL-3.0-only LGPL-3.0-only MIT MIT-0 $
-
ros2 pkg create
: ROS2パッケージを新規作成 -
--build-type ament_python
: Python を使ってビルドされることを指定 -
my_py_node
:パッケージ名 -
--dependencies rclpy std_msgs
:パッケージが依存しているライブラリを指定-
rclpy
:ROS 2 の Pythonクライアントライブラリ -
std_msgs
:標準のメッセージ型(String, Int32など)
-
-
-
以下の構成ができました
$ tree . └── my_py_node ├── my_py_node │ └── __init__.py ├── package.xml ├── resource │ └── my_py_node ├── setup.cfg ├── setup.py └── test ├── test_copyright.py ├── test_flake8.py └── test_pep257.py 5 directories, 8 files $
ソースを作成
- my_py_node/my_py_node/talker.py を以下の内容で作成します
import rclpy from rclpy.node import Node from std_msgs.msg import String class TalkerNode(Node): def __init__(self): super().__init__('talker') self.publisher_ = self.create_publisher(String, 'hello', 10) self.timer = self.create_timer(0.5, self.timer_callback) self.count = 0 def timer_callback(self): msg = String() msg.data = f'Hello ROS 2: {self.count}' self.publisher_.publish(msg) self.get_logger().info(f'Publishing: "{msg.data}"') self.count += 1 def main(args=None): rclpy.init(args=args) node = TalkerNode() rclpy.spin(node) rclpy.shutdown() if __name__ == '__main__': main()
- ノード名 talker で起動
- トピック /hello に、0.5秒ごとに Hello ROS 2: 0, Hello ROS 2: 1, ... のようなメッセージが送信される
- 0.5秒ごとに、timer_callback()を呼び出し、メッセージを出力している
- rclpy.spin(node)により、timer_callback()が定期的に呼び出される
setup.pyにエントリーポイントを追記
-
my_py_node.talker:main
を追記しますentry_points={ 'console_scripts': [ 'talker = my_py_node.talker:main', ], },
-
全体像は下記のとおりです
$ cat my_py_node/setup.py from setuptools import find_packages, setup package_name = 'my_py_node' setup( name=package_name, version='0.0.0', packages=find_packages(exclude=['test']), data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), ], install_requires=['setuptools'], zip_safe=True, maintainer='ubuntu', maintainer_email='ubuntu@todo.todo', description='TODO: Package description', license='TODO: License declaration', tests_require=['pytest'], entry_points={ 'console_scripts': [ 'talker = my_py_node.talker:main', ], }, ) $
ビルド
- ビルドします
$ colcon build --symlink-install [0.488s] WARNING:colcon.colcon_ros.prefix_path.ament:The path '/home/ubuntu/ros2_ws/install/my_py_node' in the environment variable AMENT_PREFIX_PATH doesn't exist [0.488s] WARNING:colcon.colcon_ros.prefix_path.ament:The path '/home/ubuntu/ros2_ws/install' in the environment variable AMENT_PREFIX_PATH doesn't contain any 'local_setup.*' files. Starting >>> my_py_node Finished <<< my_py_node [3.55s] Summary: 1 package finished [3.95s] $
publish(ターミナルA)
- メッセージを送信します
$ ros2 run my_py_node talker [INFO] [1746423555.971515959] [talker]: Publishing: "Hello ROS 2: 0" [INFO] [1746423556.434968269] [talker]: Publishing: "Hello ROS 2: 1" [INFO] [1746423556.936578724] [talker]: Publishing: "Hello ROS 2: 2" [INFO] [1746423557.437360531] [talker]: Publishing: "Hello ROS 2: 3" [INFO] [1746423557.936618063] [talker]: Publishing: "Hello ROS 2: 4" [INFO] [1746423558.436830477] [talker]: Publishing: "Hello ROS 2: 5" [INFO] [1746423558.938511280] [talker]: Publishing: "Hello ROS 2: 6" [INFO] [1746423559.437847548] [talker]: Publishing: "Hello ROS 2: 7" [INFO] [1746423559.935977189] [talker]: Publishing: "Hello ROS 2: 8" [INFO] [1746423560.437838697] [talker]: Publishing: "Hello ROS 2: 9" [INFO] [1746423560.938195209] [talker]: Publishing: "Hello ROS 2: 10" [INFO] [1746423561.437847674] [talker]: Publishing: "Hello ROS 2: 11" ・・・
subscribe(ターミナルB)
- トピックを確認します
$ ros2 topic list /hello /parameter_events /rosout $
- echoで表示します。受信できました!
$ ros2 topic echo /hello 2025-05-05 05:42:53.997 [XMLPARSER Error] getcwd failed No such file or directory -> Function loadDefaultXMLFile data: 'Hello ROS 2: 438' --- data: 'Hello ROS 2: 439' --- data: 'Hello ROS 2: 440'
MCAP形式で記録する
-
下記のコマンドを実行します
$ ros2 bag record -o my_bag --storage mcap /hello [INFO] [1746455410.390757527] [rosbag2_recorder]: Press SPACE for pausing/resuming [INFO] [1746455410.422411606] [rosbag2_recorder]: Listening for topics... [INFO] [1746455410.422631740] [rosbag2_recorder]: Event publisher thread: Starting [INFO] [1746455410.423877678] [rosbag2_recorder]: Recording... [INFO] [1746455801.472895556] [rosbag2_recorder]: Pausing recording. [INFO] [1746455801.480338694] [rosbag2_cpp]: Writing remaining messages from cache to the bag. It may take a while [INFO] [1746455801.489244086] [rosbag2_recorder]: Event publisher thread: Exiting [INFO] [1746455801.490517203] [rosbag2_recorder]: Recording stopped [INFO] [1746455801.571788548] [rclcpp]: signal_handler(signum=2) $
- -o my_bag: 保存先フォルダ名
- --storage mcap:MCAP形式で記録
- /hello: 記録対象のトピック名
-
別ターミナルで確認します。my_bagフォルダができています
$ ls -l total 24 drwxrwxr-x 3 XXX XXX 4096 May 5 05:37 build drwxrwxr-x 2 XXX XXX 4096 May 5 14:39 hello_bag drwxrwxr-x 3 XXX XXX 4096 May 5 05:37 install drwxrwxr-x 3 XXX XXX 4096 May 5 05:37 log drwxrwxr-x 2 XXX XXX 4096 May 5 14:39 my_bag drwxrwxr-x 3 XXX XXX 4096 May 5 05:32 src $
-
中身は、空でした
$ ls -l my_bag/ total 0 -rw-rw-r-- 1 XXX XXX 0 May 5 14:39 my_bag_0.mcap $ cat my_bag/my_bag_0.mcap $
-
下記のコマンドでメッセージを送信します
ubuntu@ubuntu:~/ros2_ws$ ros2 run my_py_node talker [INFO] [1746456624.855327989] [talker]: Publishing: "Hello ROS 2: 0" [INFO] [1746456625.321653404] [talker]: Publishing: "Hello ROS 2: 1" [INFO] [1746456625.817827820] [talker]: Publishing: "Hello ROS 2: 2" [INFO] [1746456626.317045072] [talker]: Publishing: "Hello ROS 2: 3" [INFO] [1746456626.818447231] [talker]: Publishing: "Hello ROS 2: 4" [INFO] [1746456627.319625612] [talker]: Publishing: "Hello ROS 2: 5" [INFO] [1746456627.819363865] [talker]: Publishing: "Hello ROS 2: 6" [INFO] [1746456628.317733225] [talker]: Publishing: "Hello ROS 2: 7" [INFO] [1746456628.813893643] [talker]: Publishing: "Hello ROS 2: 8" [INFO] [1746456629.312155996] [talker]: Publishing: "Hello ROS 2: 9" [INFO] [1746456629.811090218] [talker]: Publishing: "Hello ROS 2: 10" [INFO] [1746456630.314374421] [talker]: Publishing: "Hello ROS 2: 11" [INFO] [1746456630.819625907] [talker]: Publishing: "Hello ROS 2: 12" [INFO] [1746456631.314952955] [talker]: Publishing: "Hello ROS 2: 13" [INFO] [1746456631.810452367] [talker]: Publishing: "Hello ROS 2: 14" [INFO] [1746456632.312873593] [talker]: Publishing: "Hello ROS 2: 15" [INFO] [1746456632.810239991] [talker]: Publishing: "Hello ROS 2: 16" [INFO] [1746456633.320642098] [talker]: Publishing: "Hello ROS 2: 17" [INFO] [1746456633.819014478] [talker]: Publishing: "Hello ROS 2: 18" [INFO] [1746456634.311467673] [talker]: Publishing: "Hello ROS 2: 19" [INFO] [1746456634.818081860] [talker]: Publishing: "Hello ROS 2: 20" [INFO] [1746456635.313023067] [talker]: Publishing: "Hello ROS 2: 21" [INFO] [1746456635.811034489] [talker]: Publishing: "Hello ROS 2: 22"
-
Ctrl+Cをします
-
ファイルの内容を確認します
$ ros2 bag info my_bag Files: my_bag_0.mcap Bag size: 36.0 KiB Storage id: mcap ROS Distro: jazzy Duration: 214.495901362s Start: May 5 2025 14:50:24.818789035 (1746456624.818789035) End: May 5 2025 14:53:59.314690397 (1746456839.314690397) Messages: 430 Topic information: Topic: /hello | Type: std_msgs/msg/String | Count: 430 | Serialization Format: cdr Service: 0 Service information: $
- Files:使用されているバッグファイル
- Bag size:データ全体のファイルサイズ
- Storage id:記録形式(mcap)
- ROS Distro:使用されたROS 2ディストリビューション(例: jazzy)
- Duration:記録された時間の長さ(開始から終了までの合計時間)
- Start / End:記録の開始時刻と終了時刻
- Messages:430
- Topic information :トピックごとの詳細(トピック名、型、件数など)
-
再生します
$ ros2 bag play my_bag [INFO] [1746457477.260023213] [rosbag2_player]: Set rate to 1 [INFO] [1746457477.666327399] [rosbag2_player]: Adding keyboard callbacks. [INFO] [1746457477.666606203] [rosbag2_player]: Press SPACE for Pause/Resume [INFO] [1746457477.666824385] [rosbag2_player]: Press CURSOR_RIGHT for Play Next Message [INFO] [1746457477.667502398] [rosbag2_player]: Press CURSOR_UP for Increase Rate 10% [INFO] [1746457477.667742370] [rosbag2_player]: Press CURSOR_DOWN for Decrease Rate 10% [INFO] [1746457477.668139344] [rosbag2_player]: Playback until timestamp: -1 $
- ros2 bag record:記録したROSメッセージを再度Publishする
考察
今回、ROS2とMCAPについて簡単に試してみました。
次回は、ツールを使用してMCAPファイルのかしkを試してみます。
参考