Hakoniwa-pdu

6.3K Views

April 10, 24

スライド概要

この資料では、箱庭アセット間の通信データであるPDUの情報を整理しています。
- 箱庭のPDU(Protocol Data Unity)とは何か
- 箱庭の通信プロトコル・アーキテクチャ
- 箱庭アセットと箱庭PDUチャネルについて
- 箱庭PDUデータの作成方法
- 箱庭PDUデータの組み込み方法
箱庭アセットAPI
箱庭アセットUnity
- 箱庭PDUデータのアクセス方法
箱庭アセットAPI
箱庭アセットUnity

profile-image

TOPPERS/箱庭WG活動でUnityやらAthrillやらmROSやら触ってます。 最近は仕事の関係でWeb系の技術に注力しつつ、箱庭への転用を模索しています。 2023年8月1日:合同会社箱庭ラボに移動しました

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

ダウンロード

関連スライド

各ページのテキスト
1.

箱庭(Hakoniwa) PDU 合同会社箱庭ラボ CTO 森崇

2.

はじめに • この資料では、箱庭アセット間の通信データであるPDUの情報を整理してい ます。 • 箱庭のPDU(Protocol Data Unit)とは何か • 箱庭の通信プロトコル・アーキテクチャ • 箱庭のPDUデータをプログラムで使うには • 箱庭アセットと箱庭PDUチャネルについて • 箱庭PDUデータの作成方法 2

3.

箱庭のPDUとは何か • 箱庭のPDU(Protocol Data Unit)は、箱庭アセットが互いに通信するためのデータ単位です。 • PDUデータ型の定義: ROS IDL (Interface Definition Language) というインターフェース記述言語 • PDUデータは、様々な通信プロトコルを介してデータ交換されます。 • UDP, MQTT, ROS, Zenoh, 共有メモリ 3

4.

箱庭の通信プロトコル・アーキテクチャ(1/4) • UDP通信 4

5.

箱庭の通信プロトコル・アーキテクチャ(2/4) • MQTT通信 5

6.

箱庭の通信プロトコル・アーキテクチャ(3/4) • ROS通信 6

7.

箱庭の通信プロトコル・アーキテクチャ(3/4) • 共有メモリ 7

8.

箱庭PDUデータをプログラムで使うには • 箱庭PDUデータをプログラムで使うには • データ(位置・速度など)をネットワーク用に変換する必要があります。 • まずは、「一般的な通信プログラムの流れ」を理解し、 • 次に、「箱庭PDUの場合の流れ」を理解します。 • そして、「一般的な通信プログラム vs 箱庭PDU」の比較をして理解を深めます。 • 最後に、「箱庭PDUの変換ライブラリとテンプレート」を紹介します。 8

9.

一般的な通信プログラムの流れ • 通信フレームワーク側でプログラムデータ型をバイナリ変換してくれる アプリケーションプログラム プログラムデータ型 アプリケーションプログラム プログラムデータ型 アプリケーション 処理 アプリケーション 処理 通信API 通信API バイナリデータ バイナリ変換処理 (encode) バイナリデータ バイナリ変換処理 (decode) 通信フレームワーク 通信フレームワーク 転送API 転送API トランスポート層/ネットワーク層/データリンク層 トランスポート層/ネットワーク層/データリンク層 9

10.

箱庭PDUの場合の流れ • アプリケーション側でプログラムデータ型をバイナリ変換します アプリケーションプログラム プログラムデータ型 アプリケーションプログラム プログラムデータ型 アプリケーション 処理 バイナリデータ バイナリ変換処理 (encode) アプリケーション 処理 バイナリデータ バイナリ変換処理 (decode) 転送API 転送API トランスポート層/ネットワーク層/データリンク層 トランスポート層/ネットワーク層/データリンク層 10

11.

一般的な通信プログラム vs 箱庭PDU の比較 • 一般的な通信はFW任せ、箱庭PDUはアプリ主導 項目 一般的な通信プログラム 箱庭PDU バイナリ変換処理の場所 通信フレームワークが自動で実施 (アプリ側は意識する必要なし) アプリケーション側がバイナリ変換APIを使って実施 (アプリ側は意識する必要あり) データ型の定義 通信FW依存のデータ型を利用する 箱庭PDUのデータ型(ROS IDL) 通信層構造 アプリ → 通信API → 通信FW → 転送API → ネットワーク層 アプリ → PDU変換処理 → 転送API → ネットワーク層 API表面積 プログラム言語毎に通信APIが増える構造 (通信API内処理+バイナリ変換) プログラム言語毎にバイナリ変換APIが増える構造 (バイナリ変換のみ) 他プログラミング言語への 移植コスト ノード層・型バインディング・ミドル層など 広範囲改修 言語毎のバイナリ変換テンプレートの新規作成のみ 利点 FW内で閉じた最適化・通信の透明化 多言語対応が用意、API表面積を最小化すること で移植コストを低減できる 11

12.

箱庭PDUの変換ライブラリとテンプレート • 箱庭PDU向けのデータ型/バイナリ変換ライブラリはテンプレートで自動生成! 通信記述形式 (ROS IDL) Python C# C++ データ型 テンプレート データ型 テンプレート データ型 テンプレート バイナリ変換 テンプレート バイナリ変換 テンプレート バイナリ変換 テンプレート ROS msgファイル ・・・ 箱庭PDU変換ツール Python C# C++ データ型 データ型 データ型 バイナリ変換 ライブラリ バイナリ変換 ライブラリ バイナリ変換 ライブラリ ・・・ 12

13.

箱庭アセットと箱庭PDUチャネルについて • 箱庭アセットをPDUデータI/Oの観点で分類すると以下の2種類に分かれます • プラントモデル • 制御モデル • プラントモデルは、複数のロボットを持つことができます(制御側も同様) • ロボットは、複数のPDUデータに対してI/O発行できます • 各ロボットから見たときのPDUデータの識別IDをチャネルと呼びます • なのでPDUチャネルの識別は以下の2つの情報が必要となります • プラントモデルのロボット名 • チャネルID プラントモデル ロボットA チャネルID チャネルID 0 0 PDUデータA-1 1 0 ロボットB 1 PDUデータA-2 PDUデータB-1 PDUデータB-2 1 制御モデル 制御A 0 1 ロボットAのPDUデータ A-2にアクセスするには、 (“ロボットA”, “1” ) でアクセスする 制御B ロボットBのPDUデータ B-2にアクセスするには、 (“ロボットB”, “1” ) でアクセスする 13

14.

箱庭アセットと箱庭PDUチャネルについて • UnityとPythonの箱庭アセットが箱庭コア機能を通して通信している様子(共有メモリ方式) 箱庭アセット(Unityの場合) 箱庭アセット (Pythonの場合) センサ1 0:センシングデータ1 0 センサ2 1:センシングデータ2 1 モータ 2:モータ指示値 2 ロボット PDU 0 1 2 0 1 2 0 1 2 箱庭コア機能 2 1 0 PDUデータ 14

15.

箱庭PDUデータの作成方法 • 以下の手順で箱庭PDUデータを作成します。 • 0. 箱庭PDUデータを作成するリポジトリをクローンする • https://github.com/toppers/hakoniwa-ros2pdu • インストール手順およびPDUデータ生成方法は上記を参照ください。 • 1. 箱庭PDUデータの型を決める • 2-(a). ROS標準の通信データに存在している場合 • 対象の定義ファイル(.msg)から箱庭のPDUデータ定義ファイル群を生成する • 2-(b). ROS標準の通信データに存在していない場合 • ROS IDLで、定義ファイル(.msg)を作成する • 対象の定義ファイル(.msg)から箱庭のPDUデータ定義ファイル群を生成する • 3. 生成した箱庭PDUデータ/バイナリ変換ライブラリを取得する 15

16.

箱庭PDUデータを作成するリポジトリをクローンする 任意のディレクトリ直下で、hakoniwa-ros2pduリポジトリをクローン: git clone –recursive https://github.com/toppers/hakoniwa-ros2pdu.git 成功するとこうなります。 $ ls hakoniwa-ros2pdu 現在、箱庭として標準サポートされているメッセージデータ型は、config/ros_msgs.txtに列挙されています。 $ cat hakoniwa-ros2pdu/config/ros_msgs.txt hako_msgs/MetaPdu hako_srv_msgs/SystemControlRequest hako_srv_msgs/SystemControlResponse hako_srv_msgs/SystemControlRequestPacket hako_srv_msgs/SystemControlResponsePacket hako_srv_msgs/RegisterClientRequest : hako_srv_msgs/AddTwoIntsRequestPacket hako_srv_msgs/AddTwoIntsResponsePacket tf2_msgs/TFMessage 16

17.

メッセージ定義の内容の確認および定義方法 ROS標準のメッセージ:https://github.com/ros2/common_interfaces 箱庭独自のメッセージ:https://github.com/toppers/hakoniwa-ros2pdu/tree/main/workspace/src 上記で所望のデータ定義存在しない場合は、新たに定義する必要があります。 以下の場所に新規メッセージを定義してください。 hakoniwa-ros2pdu/workspace/src/<package_name>/msg/<type_name>.msg <package_name>: ROSのメッセージをまとめるパッケージ名を指定します。 例: geometry_msgs, sensor_msgs, std_msgs, hako_msgs など 独自メッセージを定義する場合は、新しいパッケージを作成してください。 <type_name>: そのパッケージ内で使うメッセージ型の名前を指定します。 例: Twist, Pose, Imu, Image など 新規に作成した場合は、config/ros_msgs.txt に追加してください。 17

18.

箱庭PDUライブラリ群の作成方法 事前準備1:dockerイメージをダウンロードします。 bash docker/pull_image.bash 事前準備2:dockerコンテナを起動します。 bash docker/run.bash 箱庭PDUライブラリ群の作成 python3 -m utils.hakoniwa_pdu_generator.main config/ros_msgs.txt ポイント: 大量のメッセージを同時に作成すると時間がかかります。 そのため、ros_msgs.txtには生成したいもの(必要最小限)にしておくと良いです。 18

19.

生成される箱庭PDUデータの内訳 • 生成される場所: • hakoniwa-ros2pdu/pdu • 3種類のファイルが生成されます。 • json: • json形式の定義ファイル(Unityで利用) • offset: • offset定義ファイル(PDUバイナリデータのエンコーダ/デコーダで利用) • types: • C言語のデータ型およびROSデータ型への変換定義ファイル(.h, .hpp) • C言語のデータ型定義ファイル :pdu_ctype_<PDUデータ名>.h • ROSデータ型への変換定義ファイル:pdu_ctype_conv_<PDUデータ名>. hpp • python/csharp • python/C#のデータ型およびROSデータ型への変換定義ファイル群 • 上記ファイルは、以下のディレクトリ構成で生成されます。 • <ROSのパッケージ名>/<メッセージ名> 19

20.

箱庭PDUデータの組み込み方法 • 生成した箱庭PDUライブラリ群は、箱庭プロジェクトの種類(正確にはプラットフォーム/言語)に応じて変わります。 • 下表にその一例を示します。 箱庭プロジェクト 取り込みする場所 hakoniwa-ros2pduで生成した ファイルの中で、取り込みするファイルの種類 hakoniwa-unity-drone <unity-proj>/ros_types pdu/offset, pdu/json hakoniwa-unreal-drone Plugins/HakoniwaPdu/ Source/ThirdParty/hakoniwa-ros2pdu/ pdu/types pdu/types hakoniwa-drone-pro thirdparty/hakoniwa-ros2pdu/ pdu/types pdu/types hakoniwa-mujoco-robots thirdparty/haoniwa-core-pro/ hakoniwa-ros2pdu/pdu/types pdu/types hakoniwa-pdu-python src/hakoniwa_pdu/pdu_msgs pdu/python その他:Python (任意) pdu/python その他:C++ (任意) pdu/types 20

21.

箱庭PDUデータのアクセス方法(C++/SHM) • import方法 • #include "pdu.hpp" • #include “<package_name>/hako_cpptype_conv_<type_name>.hpp • PDU変数定義 • HakoCpp_<type_name> <PDU変数名>; • PDU管理変数定義 • HAKO_PDU_TYPE(<namespace>,<type_name>) <PDU管理変数名>(<robot_name>,<pdu_name>); • PDUデータ読み込み • <PDU管理変数名>.load(<PDU変数名>); • PDUデータ書き込み • <PDU管理変数名>.flush(<PDU変数名>); 21

22.

箱庭PDUデータのアクセス方法(C++/unreal) • TODO 22

23.

箱庭PDUデータのアクセス方法(Python) • import方法 • from hakoniwa_pdu.pdu_manager import PduManager • from hakoniwa_pdu.pdu_msgs.<package_name>.pdu_pytype_<type_name> import <type_name> • from hakoniwa_pdu.pdu_msgs.<package_name>.pdu_conv_pytype_<type_name> import pdu_to_py_<type_name>, py_to_pdu_<type_name> • PDUデータ読み込み • 初期化イベント • await pdu_manager.declare_pdu_for_read(<robot_name>, <pdu_name>) • 読み込み • raw_data: bytes = pdu_manager.read_pdu_raw_data(<robot_name>,<pdu_name>) • <変数名>: Twist = pdu_to_py_ <type_name>(raw_data) • PDUデータ書き込み • 初期化イベント • await pdu_manager.declare_pdu_for_write(<robot_name>, <pdu_name>) • 書き込み <変数名>: <type_name> = <type_name>() • (PDUデータ設定) • raw_data: bytes = py_to_pdu_<type_name>(<変数名>) • pdu_manager.flush_pdu_raw_data_nowait((<robot_name>,<pdu_name>, raw_data) • 23

24.

箱庭PDUデータのアクセス方法(C#) • import方法 • using hakoniwa.pdu.core; • using hakoniwa.pdu.msgs.<package_name>; • PDUデータ読み込み • 初期化イベント • await pdu_manager.DeclarePduForRead(<robot_name>, <pdu_name>); • 読み込み • IPdu <pdu変数名> = pduManager.ReadPdu(<robot_name>,<pdu_name>); • <type_name> <データアクセス変数名>= new Twist(<pdu変数名>); • PDUデータ書き込み • 初期化イベント • await pdu_manager.DeclarePduForWrite(<robot_name>, <pdu_name>); • 書き込み • INamedPdu <pdu変数名> = pduManager.CreateNamedPdu(<robot_name>, <pdu_name>); • hakoniwa.pdu.msgs.<package_name>.<type_name> = new hakoniwa.pdu.msgs. <package_name>.<type_name>(pdu変数名); • (PDUデータ設定) • pduManager.WriteNamedPdu(pdu変数名); • pduManager.FlushNamedPdu(pdu変数名); 24

25.

箱庭PDUデータの構造 ROS IDLのデータをC言語の構造体 (例:Point) Meta Data offset 型 内容 0 uint32 Magic番号(0x12345678) 4 uint32 バージョン番号(現在は1) 8 uint32 BaseDataの開始位置(=24) 12 uint32 HeapDataの開始位置(BaseDataの末尾) 16 uint32 全体サイズ(Meta + Base + Heap) 20 - パディング Base Data 可変長配列データを格納する領域 (例:CompressedImage) uint8 data[] Heap Data 25

26.

箱庭PDUのプリミティブデータ型定義 ROS データ型 箱庭PDU データ型 C言語データ型(stdint.h) (pdu_primitive_ctypes.h) 備考 int8 Hako_int8 int8_t ー uint8 Hako_uint8 uint8_t ー byte Hako_byte uint8_t ー char Hako_char uint8_t ー int16 Hako_int16 int16_t ー uint16 Hako_uint16 uint16_t ー int32 Hako_int32 int32_t ー uint32 Hako_uint32 uint32_t ー int64 Hako_int64 int64_t ー uint64 Hako_uint64 uint64_t ー float32 Hako_float32 float ー float64 Hako_float64 double ー bool Hako_bool int ー string Hako_cstring #define HAKO_STRING_SIZE 128 typedef struct { char data[HAKO_STRING_SIZE]; } Hako_cstring; 現時点では、文字列データは128バイト固定です。 26

27.

箱庭PDUのBase Data領域の構造 • ROS IDLで定義したデータ型を、「箱庭PDUのプリミティブデータ型定義」 に従って、C言語の構造体に変換します。 • 可変長配列については、ヒープ領域への参照データを保持します。 Heap Data 1..* Primitive Data型 ヒープ領域の オフセット位置 可変長配列の長さ (データサイズではない) BaseData型 0..* 可変長配列 のメタデータ int _data_len 可変長配列 データの実体を格納 data[] int _data_off 27

28.

箱庭PDUのHeap Data領域の構造 • Heap Data領域は、可変長配列データを格納します。 • 可変長配列データのプリミティブデータ型 • Primitive Data型 • 構造体データ型 • 構造体データ型の中にさらに可変長配列データがある場合は、 再帰的な構造になる(下図)。 1..* 可変長配列 構造体データ に可変長配列 がある場合 0..* Heap Data プリミティブデータ型 uint8 data[] Primitive Data型 構造体データ型 CompressedImage data[] 可変長配列 のメタデータ プリミティブデータ型 uint8 data[] int _data_len プリミティブデータ型 uint8 data[] int _data_off 28