ROSとROS2の違いと類似技術をご紹介ください。
ChatGPT:
了解しました。ROS(Robot Operating System)とROS 2について、その違いと類似技術を整理します。
✅ ROS(ROS 1)の概要
2007年ごろから Willow Garage を中心に開発。
分散ロボットソフトウェアフレームワークで、通信(Publish/Subscribe、Service/Action)、パッケージ管理、シミュレーション(Gazebo)、可視化(RViz)などをサポート。
言語:主に C++/Python。
産業利用よりも研究・教育用に普及。
✅ ROS 2 の概要
2014年以降、Open Robotics 主導で開発。
ROS 1 の課題(シングルマスター構成、リアルタイム性不足、セキュリティ不足)を解決するために再設計。
通信基盤に DDS(Data Distribution Service) を採用。
マルチロボット、マルチマスター、リアルタイム制御、安全性(QoS、セキュリティ)が強化。
産業利用(自動運転、医療ロボット、工場ロボットなど)を視野に置いている。
🔍 ROS 1 と ROS 2 の主な違い
項目 ROS 1 ROS 2
通信ミドルウェア 独自(ROS Master + TCPROS/UDPROS) DDSベース(RTPS, QoS制御可)
アーキテクチャ シングルマスター中心 マルチマスター / Peer-to-Peer
リアルタイム性 基本的に非対応 RTOS/リアルタイム対応可
セキュリティ ほぼなし DDS Security 機能あり
言語サポート C++/Python C++/Python/他(Rust, Javaなど拡張可能)
OS対応 Linux中心 Linux、Windows、macOS、RTOS(QNX、VxWorks)など
産業利用 主に研究用 産業システムを意識
✅ ROS と類似・競合する技術
- LCM (Lightweight Communications and Marshalling)
MIT発の通信ライブラリ。
ロボットや自律システム向けの軽量Pub/Subフレームワーク。
ROSよりシンプルだが、周辺ツール(可視化、シミュレータ)が少ない。- MOOS (Mission Oriented Operating Suite)
海洋ロボティクスでよく使われる。
ROSに比べ軽量だが、特定用途寄り。- YARP (Yet Another Robot Platform)
イタリアIIT開発。
ROSに近い通信フレームワークを持ち、ヒューマノイドロボット研究で利用。- OPC UA
産業オートメーションで標準的な通信規格。
ROS 2 と橋渡しするためのブリッジも開発されている。- DDS 単独利用
ROS 2 の通信基盤そのもの。
eProsima Fast DDS、RTI Connext DDS、Cyclone DDS など。
ROSを使わず、直接DDSでアプリケーションを組むことも可能。
✅ まとめ
ROS 1 → 研究・教育用で爆発的に普及。
ROS 2 → DDSを採用し、産業利用に耐える仕組みに進化。
類似技術は LCM, MOOS, YARP などがあるが、エコシステムの充実度はROSが圧倒的。
産業界では ROS 2 + DDS + OPC UA 連携が主流になりつつある。
ご希望があれば、次のステップとして
👉 ROS/ROS 2 のコード例比較(簡単なPublisher/Subscriber) を提示して、違いを実感できるように整理しましょうか?
DDSとSOME/IPの違いと、類似技術をご紹介ください。
ChatGPT:
良いテーマですね 👍
DDS と SOME/IP はどちらも 分散システムの通信ミドルウェア ですが、起源や適用領域が異なります。以下に整理します。
✅ DDS(Data Distribution Service)
OMG(Object Management Group)標準
Pub/Sub 型の データ中心通信ミドルウェア。
QoS 設定が非常に柔軟(信頼性、遅延、優先度、履歴、ライフサイクルなど)。
リアルタイム分散システム向け(自律ロボット、産業機械、防衛、航空宇宙、自動運転など)。
実装例:RTI Connext DDS、eProsima Fast DDS、Cyclone DDS、OpenDDS
✅ SOME/IP(Scalable service-Oriented MiddlewarE over IP)
AUTOSAR で標準化された通信方式。
車載ネットワーク上の サービス指向通信 に特化。
Ethernet/IP 上で動作し、サービス発見、メソッド呼び出し(RPC)、イベント通知をサポート。
ECU間通信(車載制御ユニット間の機能呼び出し、状態共有)を前提。
実装例:Vector、Elektrobit、AUTOSAR各社スタック
🔍 DDS と SOME/IP の主な違い
項目 DDS SOME/IP
標準化 OMG AUTOSAR
通信モデル Pub/Sub中心(データ配信) Service-Oriented(サービス発見+RPC+イベント)
QoS制御 非常に詳細(信頼性、優先度、寿命など20+種) 基本的な通信(信頼性、TTLなど)
リアルタイム性 強い(ミリ秒単位制御可) Ethernetベース、リアルタイムは限定的
対象分野 航空宇宙、防衛、産業機械、ロボット、自動運転 車載ECU、車内サービス通信
実装例 RTI Connext、Fast DDS、Cyclone DDS Vector、EB tresos、AUTOSAR Adaptive Platform
👉 まとめると:
DDS = 高度な分散システム向けのデータ配信基盤
SOME/IP = 車載向けに設計されたサービス呼び出し基盤
✅ 類似技術
🟦 DDS に類似する技術
MQTT(軽量Pub/Sub、IoT用、QoSは簡易)
AMQP(メッセージ指向、金融/IoTシステム)
ZeroMQ(超軽量メッセージング、QoS制御は弱い)
ROS 2 通信レイヤ(DDSがベースになっている)
🟦 SOME/IP に類似する技術
gRPC(Google RPCフレームワーク、サービス指向)
D-Bus(Linuxデスクトップでのサービス間通信)
Thrift(ApacheのクロスプラットフォームRPC)
AUTOSAR Classic CAN/LIN バス通信(サービス指向ではないがSOME/IPの前身的位置づけ)
✅ まとめ
DDS は「リアルタイム分散システムのデータ配信」に最適化。
SOME/IP は「車載ECU間のサービス通信」に特化。
両者は補完関係にあり、近年の自動運転車両では DDS(センサーデータ配信)+SOME/IP(車載サービス呼び出し) の組み合わせが増えています。
ご希望なら、
👉 DDS と SOME/IP を自動車システムの中でどう使い分けるか(ユースケース図付き) を整理してみましょうか?
はい。お願いします。
ChatGPT:
では、自動車システムの中で DDS と SOME/IP の使い分け を、ユースケースと図解イメージを交えて整理します 🚗⚡️
✅ 自動車における通信ニーズ
自動車(特に自動運転車両)では、大きく分けて 2 種類の通信が必要になります:
センサー・アクチュエータ系(リアルタイム・高スループット)
LiDAR, カメラ, レーダーなど大量データを周期的に送信
制御ECUがミリ秒単位で処理・判断する必要あり
→ DDS が適する
車載サービス系(機能呼び出し・イベント通知)
ECU間での「サービス発見」「メソッド呼び出し」「状態通知」
例:ドアロック制御、ナビゲーション情報取得、空調制御
→ SOME/IP が適する
✅ DDS と SOME/IP の使い分けユースケース
層 代表例 適用通信方式
センサー系 LiDAR → Perception ECU、カメラ映像ストリーミング DDS
制御系 Perception ECU → Path Planning ECU → Motion Control ECU DDS
車載サービス系 ナビECU → メータECU にルート情報を送信 SOME/IP
車内機能呼び出し スマートキーECU → ドアECU に解錠リクエスト SOME/IP
クラウド連携 車載ゲートウェイECU → クラウド(MQTTやHTTP経由) DDS or MQTT
✅ システム構成イメージ
┌──────────────┐
│ センサー層 (カメラ, LiDAR, Radar) │
└───────┬────────┘
DDS (高スループット, リアルタイム)
│
┌──────────────┐
│ 自動運転ECU群 (認識, 計画, 制御) │
└───────┬────────┘
DDS (周期データ共有)
│
┌──────────────┐
│ 車載サービス層 (ボディECU, IVI, HVAC) │
└───────┬────────┘
SOME/IP (サービス発見 & RPC)
│
┌──────────────┐
│ 車載ゲートウェイ (クラウド接続) │
└─────────────────┘
MQTT / HTTP / DDS
✅ まとめ
DDS:センサーや制御系の「データ配信(Pub/Sub, QoS重視)」に最適。
SOME/IP:車載サービスの「機能呼び出し(RPC, Service-Oriented)」に最適。
自動運転車では両者を 併用し、さらにクラウド連携には MQTT/HTTP が組み合わされる。
👉 ご希望なら、次は DDS と SOME/IP をブリッジする実際の実装例(AUTOSAR Adaptive での構成) についてもご紹介できますが、深掘りしますか?
はい。お願いします。
ChatGPT:
了解です。ここでは AUTOSAR Adaptive を前提に、車内で併用されがちな DDS ⇄ SOME/IP ブリッジの実装像を、設計手順・配置・コード例・QoS/時刻同期まで一気にまとめます。
全体像(役割分担)
[センサー/AD ECU 群] [ボディ/IVI/ゲートウェイ群]
DDS: 高頻度Pub/Sub ──→ [ブリッジ] ──→ SOME/IP: RPC + Event
↑ │
(逆方向も可) ←──────────────────────────────┘
DDS側:ObstacleList, Pose, PointCloud など高頻度トピック(QoS厳しめ)
SOME/IP側:サービス発見(SOME/IP-SD)、メソッド呼び出し、イベント配信(UIやボディ系ECUへ)
ブリッジ:両スタックを同一プロセス/ECU内で起動し、型変換・QoS/信頼性の橋渡しを行う ゲートウェイアプリ
実装手順(Adaptive Platform)
インタフェース定義を一元化
**共通IDL(OMG IDL or AUTOSAR Service Interface .arxml)**で型とAPIを一度だけ定義
例:ObstacleList(配列の上限、座標/速度のスケール、エンディアンなどを明示)
コード生成
DDS 側:IDL → TypeSupport / シリアライザ生成(Fast DDS / Cyclone DDS / Connext など)
SOME/IP 側:AUTOSAR Adaptive の ara::com(SOME/IPバインディング)向けにプロキシ/スケルトン生成
SOME/IP だけを素早く試すなら vsomeip でも可(本番はAPのバインディング推奨)
ブリッジプロセス開発
DDS→SOME/IP:DDS購読 → 型変換 → SOME/IP **サービス提供側(スケルトン)**でイベント更新
SOME/IP→DDS:SOME/IP **クライアント(プロキシ)**としてメソッド/イベント受信 → DDS発行
QoS/信頼性の写像
DDSのQoS(Reliability, Durability, History, Deadline, Liveliness…)を、SOME/IP側の
送信周期(Timer)、
再送/TTL、
バッファ深さ/ドロップ方針
に置き換える設計(下表参照)
時刻同期とタイムスタンプ
gPTP(802.1AS) などでECU時刻同期
メッセージに **時刻(sourceTime / receivedTime)**を必ず搭載し、跨ぎ遅延を観測・補正
典型配置(AUTOSAR Adaptive)
┌────────────────────────────────────────────┐
│ ECU(A) 自動運転ドメイン │
│ - DDS Participant │
│ - Bridge App (DDS Reader → SOME/IP Server)│
│ ├─ 型変換 / バリデーション │
│ ├─ レート制限 / ダウンサンプリング │
│ └─ モニタリング (メトリクス/ログ) │
└────────────────────────────────────────────┘
Ethernet/IP
┌────────────────────────────────────────────┐
│ ECU(B) ボディ/IVI/ゲートウェイ │
│ - SOME/IP Client (ara::com Proxy) │
│ - UI/制御アプリ │
└────────────────────────────────────────────┘
ミニコード例(概念・擬似コード)
実際のAPI名はスタック/コード生成結果で異なるため、流れ重視の擬似コードです。
- DDS → SOME/IP(イベント配信)
// DDS 初期化(Fast DDS 風の概念)
auto participant = create_dds_participant("PerceptionDomain");
auto topic = create_dds_topic(participant, "ObstacleList");
auto reader = create_dds_reader(topic, QoS{
.reliability = RELIABLE,
.history_depth = 5,
.deadline_ms = 50
});
// SOME/IP サービス(スケルトン=提供側)
ara::com::ServiceSkeleton svc; // 生成物
svc.OfferService(); // Service Discoveryに出す
reader.on_data([&](const ObstacleList& msg){
// 必要ならダウンサンプリング/クリッピング
PerceptionTypes::ObstacleList out = convert(msg);
// イベント(Field/Event)更新(生成コードのAPIに合わせて)
svc.obstacle_list_event.Update(out); // or Notify(out)
});- SOME/IP → DDS(メソッド結果をトピック化)
// SOME/IP クライアント(プロキシ=利用側)
ara::com::ServiceProxy proxy; // 生成物
proxy.FindServiceUntilAvailable(); // SDで見つかるまで待機
// DDS Publisher
auto pub_topic = create_dds_topic(participant, "RouteCommand");
auto writer = create_dds_writer(pub_topic, QoS{ .reliability = BEST_EFFORT });
auto new_route = proxy.CalculateRoute(current, goal).get(); // RPC的メソッド
writer.write(convert(new_route)); // DDSへ発行
QoS と動作のすり合わせ(要点)
観点 DDS 側 SOME/IP 側(設計で吸収)
信頼性 Reliable / Best-effort 再送有無、アプリ側の再通知、公知TTL
ヒストリ Keep last / keep all 送信バッファ深さ、最新化 or 欠落許容
レイテンシ Deadline/LatencyBudget 送信周期/スレッド優先度/Socket設定
耐久性 TransientLocal 等 起動直後の初期イベント送信(ラッチ風)
フロー制御 Reader backpressure レート制限、ドロップ戦略(最新優先等)
実務Tip
高頻度トピックは ダウンサンプリング(例:60Hz→20Hz)や 選択送信(ROI内だけ)で帯域/CPUを節約。
フィールド長に上限を設け、SOME/IPのPDUサイズを超えないよう 断片化回避。必要なら Large Payload設計(分割/連番/再構成)。
型変換・互換性チェック
数値型の幅/スケール(float32/64、固定小数、角度単位)
エンディアン(DDSは実装依存で透過、SOME/IPはネットワークバイトオーダー)
配列長上限(IDLのbounded、.arxmlのmaxElements)
バージョニング(メジャー/マイナーでの後方互換、予約フィールド)
デプロイ&運用
プロセス分離:ブリッジを単独アプリにして障害影響を局所化
時刻同期:gPTP/802.1AS + NTPヒエラルキで冗長構成
観測性:
DDS側:統計(reader/writerのmissed deadline等)
SOME/IP側:SD状態、イベント送出レート、RPCレイテンシ
ネットワーク:pcap/TSNスイッチ統計、WiresharkのSOME/IP/RTPSディセクタ
テスト:HILで負荷・障害(遅延/パケットロス/ECU再起動)注入、境界値のPDUサイズ
代替構成・発展
SOME/IP⇄DDSを二方向に別プロセス:片方向障害時の影響分離
OPC UA/REST/gRPC ともブリッジ:ゲートウェイECUでクラウド/工場設備と接続
TSN活用:カメラ等はAVB/TSN、メタデータはDDS、ボディはSOME/IPと帯域分割
まとめ(使い分け原則)
DDS:高頻度・低遅延・Pub/Sub(AD/センシング/制御)
SOME/IP:サービス発見・RPC/イベント(ボディ/IVI/ゲートウェイ)
ブリッジ:型定義を一元化し、QoS/周期/サイズ/時刻同期を“翻訳”する薄いアプリとして実装
必要なら、**雛形プロジェクト構成(CMake・コード生成の置き場・CIテスト項目)**もそのまま使える形でお作りします。どのスタック(Fast DDS / Cyclone / Connext、vsomeip or ara::comバインディング)で進める想定が近いですか?
はい。お願いします。
ChatGPT:
思考時間: 9s
いいですね — 実務でそのまま使える雛形プロジェクト構成(CMake・コード生成の置き場・CI テスト項目)を提示します。
想定スタックは (推奨)eProsima Fast DDS + vsomeip を基本に、商用なら RTI Connext を選ぶ流れで解説します(Cyclone DDS は ROS2 環境向けのオープン実装)。参考ドキュメントも添えます。
fast-dds.docs.eprosima.com
GitHub+1
community.rti.com
- 前提/推奨スタック
開発スタック(推奨)
DDS: eProsima Fast DDS(OSS、ツール群とドキュメントが充実)。
fast-dds.docs.eprosima.com
SOME/IP: vSomeIP (COVESA)(一般的なOSS実装、サンプル豊富)。
GitHub
AUTOSAR Adaptive(プロジェクトで使う場合のインタフェース生成はRTI等のツールが支援)。
community.rti.com
代替/用途別
軽量・ROS2連携なら Eclipse Cyclone DDS。
GitHub
商用サポートが必要なら RTI Connext(商用) を検討。
community.rti.com- リポジトリ/ディレクトリ雛形
vehicle-comm-gateway/
├─ cmake/ # 共通 CMake モジュール
│ └─ FindFastDDS.cmake (optional)
├─ tools/ # codegen スクリプト (IDL→型生成 等)
│ └─ generate_types.sh
├─ idl/ # 共通 IDL / ARXML / .srv 定義
│ ├─ ObstacleList.idl
│ └─ PerceptionService.arxml
├─ src/
│ ├─ bridge/ # ブリッジアプリ (DDS <-> SOME/IP)
│ │ ├─ CMakeLists.txt
│ │ ├─ dds_reader.cpp
│ │ └─ someip_server.cpp
│ └─ common/ # 型変換、utils, timestamper
├─ generated/ # 自動生成コード置き場(Git-ignore可)
│ ├─ dds_types/ # IDL -> DDS TypeSupport
│ └─ someip_stubs/ # SOME/IP proxy/skeleton
├─ tests/
│ ├─ unit/
│ └─ integration/
├─ docker/ # Compose ファイル (DDS broker / SD / テスト用)
│ └─ docker-compose.yml
├─ .github/workflows/ # CI (GitHub Actions)
│ └─ ci.yml
├─ CMakeLists.txt
└─ README.md
ポイント:generated/ は通常 CI やローカルで自動生成し Git に入れない(ただし初期開発では差分追跡のため一時的にコミットするチームもある)。- CMake の骨子(トップレベル & bridge 用) — 要点のみ
CMake 最低バージョン:3.16+(AUTOSAR生成ツールが 3.12 を要求するケースあり)。
MathWorks
外部依存は find_package() または FetchContent で取り込み。ローカル開発ではサブモジュール化すると安定。
トップの CMakeLists.txt(抜粋)
cmake_minimum_required(VERSION 3.16)
project(vehicle-comm-gateway LANGUAGES CXX)オプション
option(BUILD_TESTS "Build tests" ON)
依存パス
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
find Fast-DDS, vsomeip, etc.
find_package(Fast-DDS REQUIRED) # あるいは eProsima package names
find_package(vsomeip REQUIRED) # vsomeip が pkg-config / cmake サポートある場合
add_subdirectory(src/bridge)
if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
bridge の CMakeLists.txt(抜粋)
add_executable(dds_someip_bridge
dds_reader.cpp
someip_server.cpp
converter.cpp
)
target_include_directories(dds_someip_bridge PRIVATE ${CMAKE_SOURCE_DIR}/generated)
target_link_libraries(dds_someip_bridge PRIVATE FastDDS::fastdds vsomeip)
(各スタックの公式リポジトリに CMake/usage 例あり。参考:Fast DDS、Cyclone DDS、vsomeip の examples)。
GitHub +2
GitHub +2
4) コード生成(IDL / ARXML → 生成物)ワークフロー
仕様ソースを idl/(.idl / .arxml)で管理。
codegen スクリプト(tools/generate_types.sh) を CI とローカルで実行:
IDL → DDS TypeSupport(eProsima の fastrtpsgen / fastddsgen など)
fast-dds.docs.eprosima.com
ARXML → AUTOSAR 型 → DDS-IDL(RTI の rtiaragen 等)※商用ツール。
community.rti.com
SOME/IP 側はサービス IDL からプロキシ/スケルトン生成(vsomeip の例スクリプトやツールを利用)
生成物を generated/ に出力(CI で差分チェック or ビルド時自動生成)。
注意点:ツールごとに生成 API 名・名前空間が異なるため、converter.cpp(型変換レイヤ)を必ず置き、変換コードのみを集中管理する。
5) CI(GitHub Actions) — 推奨ジョブ一覧(ci.yml)
build
環境:Ubuntu-latest(または cross toolchain)
手順:checkout → install deps(Fast DDS/Cyclone/ vsomeip dev packages or build from source)→ run tools/generate_types.sh → cmake build → ctest
unit-tests
gtest(単体)を実行
integration (container)
起動:docker-compose (Cyclone/Fast-DDSのネットワーク設定、vsomeipサービス)→ ブリッジを起動 → シンプルな e2e テスト(例:DDS書き込み→SOME/IP側で受信確認)
static-analysis / lint
clang-tidy, cppcheck, include-what-you-use など
artifact(optional)
ビルド成果物(バイナリ、生成IDL)をアップロード
security scan(optional)
SAST / dependency-scan(oss-fuzz ではないが依存関係確認)
簡単な GitHub Actions のステップ雛形も作れます(必要なら提供します)。
6) テストケース候補(unit / integration)
Unit
型変換の境界(最大配列長・欠損フィールド)
タイムスタンプ補正ロジック(遅延補正)
Integration
DDS → SOME/IP のイベント伝播(正常系)
DDS側 QoS 不良時のフォールバック(再接続、ログ出力)
パケットロス注入(tc/netem)での動作(ダウンサンプリング・再試行)
再起動試験:ブリッジや片側スタックが再起動した時の再接続性
Stress/Perf
高スループット(カメラ/PointCloud相当)を一定時間流してメモリ/CPUを観測
PDUサイズ境界の試験(SOME/IP の PDU 上限)
7) 運用・デバッグ向け実装ポイント(実務Tip)
生成型ID管理:SOME/IP の Service / Event ID と IDL の整合を CI でチェック。
ロギング:ara::log(Adaptive)か共通の structured logging を利用し、相互に追跡できる trace-id を付与。
MathWorks
モニタリング:Fast DDS の statistics backend や Fast DDS Monitor でメトリクスを収集。
GitHub
時刻同期:gPTP (IEEE 802.1AS) + NTP を推奨。メッセージに必ず source timestamp を添付。
開発環境:Docker 化して CI・ローカルで同一イメージを使う(vscode devcontainer 等)。
8) 参考リンク(公式/実例)
eProsima Fast DDS (docs & examples).
fast-dds.docs.eprosima.com
GitHub
Eclipse Cyclone DDS (examples & CMake notes).
GitHub
サイクロンDDS
vSomeIP repository & “in 10 minutes” guide.
GitHub +1
RTI Adaptive codegen / AUTOSAR integration examples (rtiaragen).
community.rti.com
次のアクション(選んでください)
上の雛形を そのまま GitHub リポジトリのテンプレ として CMakeLists.txt と tools/generate_types.sh、GitHub Actions の ci.yml まで作成して差し上げます(実行可能な状態)。
まずは Fast DDS + vsomeip の最小 Hello-world ブリッジ(実実装の C++ ソース + CMake + Docker Compose)を作ってほしい。
他スタック(Cyclone DDS や RTI Connext)向けのバリエーションを同時に作る。
どれを作りますか?(1/2/3 の番号で教えてください。選ばれたら、即座にテンプレ生成を始めます。)
上の雛形を そのまま GitHub リポジトリのテンプレ として CMakeLists.txt と tools/generate_types.sh、GitHub Actions の ci.yml まで作成して差し上げます(実行可能な状態)。
ChatGPT:
了解しました ✅
では、先ほどの DDS ↔ SOME/IP ブリッジ雛形 をそのまま GitHub リポジトリのテンプレート として動作可能な状態にまとめます。以下に
CMakeLists.txt
tools/generate_types.sh
.github/workflows/ci.yml
をすべて記載します。
📂 ディレクトリ構成例
my_autosar_bridge/
├── CMakeLists.txt
├── src/
│ ├── dds_bridge.cpp
│ ├── someip_bridge.cpp
│ └── main.cpp
├── idl/
│ └── Example.idl
├── tools/
│ └── generate_types.sh
└── .github/
└── workflows/
└── ci.yml
📌 CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(my_autosar_bridge LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)DDS: FastDDS
find_package(fastrtps REQUIRED)
find_package(fastcdr REQUIRED)SOME/IP: vsomeip3
find_package(vsomeip3 REQUIRED)
include_directories(
${FASTDDS_INCLUDE_DIRS}
${FASTCDR_INCLUDE_DIRS}
${VSOMEIP3_INCLUDE_DIRS}
${CMAKE_CURRENT_BINARY_DIR}/generated
)IDL から型生成
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/generated)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated/ExamplePubSubTypes.cxx
${CMAKE_CURRENT_BINARY_DIR}/generated/ExamplePubSubTypes.h
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_types.sh
${CMAKE_CURRENT_SOURCE_DIR}/idl/Example.idl
${CMAKE_CURRENT_BINARY_DIR}/generated
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/idl/Example.idl
)
add_library(example_types
${CMAKE_CURRENT_BINARY_DIR}/generated/ExamplePubSubTypes.cxx
)
target_link_libraries(example_types
fastcdr fastrtps
)
add_executable(bridge
src/main.cpp
src/dds_bridge.cpp
src/someip_bridge.cpp
)
target_link_libraries(bridge
example_types
fastrtps fastcdr vsomeip3
)
📌 tools/generate_types.sh
#!/usr/bin/env bash
set -e
if [ $# -lt 2 ]; then
echo "Usage: $0 "
exit 1
fi
IDL_FILE=$1
OUT_DIR=$2
echo "[INFO] Generating DDS types from ${IDL_FILE} -> ${OUT_DIR}"
fastrtpsgen -d ${OUT_DIR} -example CMake ${IDL_FILE}
⚠️ 事前に fastrtpsgen が PATH にあることを想定しています。
📌 .github/workflows/ci.yml
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y cmake g++ openjdk-11-jre-headless
# FastDDS
sudo apt-get install -y libfastrtps-dev libfastcdr-dev
# vsomeip3 (ROS2準拠のパッケージはないので PPA or ソースビルドが必要)
sudo apt-get install -y libvsomeip3-dev || true
- name: Build
run: |
cmake -B build -S .
cmake --build build -- -j$(nproc)
- name: Run unit tests
run: |
echo "No tests yet. Placeholder."
📌 補足
idl/Example.idl は適当に以下のようなサンプルを置いてください:
struct Example {
long id;
string message;
};
src/main.cpp では DDS ↔ SOME/IP のブリッジを簡単に呼び出せるようにします(ダミーでOK)。
GitHub Actions の vsomeip3 パッケージはディストリによっては存在しないため、CI用にはソースビルドステップを追加することもあります。
👉 この状態で git push すれば、すぐに DDS 型生成 → ビルド → CI が走るテンプレになります。
ご希望なら、src/main.cpp に DDS 受信 → SOME/IP Publish のダミーコード も入れておきましょうか?
はい。お願いします。
ChatGPT:
了解しました ✅
では、src/main.cpp, src/dds_bridge.cpp, src/someip_bridge.cpp を追加して、DDS 受信 → SOME/IP Publish の簡単なダミー処理を動く形で示します。
📂 ディレクトリ(更新後)
my_autosar_bridge/
├── CMakeLists.txt
├── src/
│ ├── dds_bridge.cpp
│ ├── dds_bridge.hpp
│ ├── someip_bridge.cpp
│ ├── someip_bridge.hpp
│ └── main.cpp
├── idl/
│ └── Example.idl
├── tools/
│ └── generate_types.sh
└── .github/
└── workflows/
└── ci.yml
📌 src/dds_bridge.hpp
#pragma once
#include "ExamplePubSubTypes.h"
#include
class DDSBridge {
public:
using Callback = std::function;
DDSBridge();
~DDSBridge();
// DDS購読を開始
void start(Callback cb);
private:
Callback callback_;
};
📌 src/dds_bridge.cpp
#include "dds_bridge.hpp"
#include
#include
#include
DDSBridge::DDSBridge() {}
DDSBridge::~DDSBridge() {}
void DDSBridge::start(Callback cb) {
callback_ = cb;
// 本来は FastDDS Subscriber を起動するが、ここではダミー
std::thread(this {
for (int i = 0; i < 5; i++) {
Example msg;
msg.id(i);
msg.message("Hello from DDS " + std::to_string(i));
std::this_thread::sleep_for(std::chrono::seconds(1));
if (callback_) callback_(msg);
}
}).detach();
}
📌 src/someip_bridge.hpp
#pragma once
#include "ExamplePubSubTypes.h"
class SomeIPBridge {
public:
SomeIPBridge();
~SomeIPBridge();
// DDSメッセージをSOME/IPに転送(ダミー)
void publish(const Example& msg);
};
📌 src/someip_bridge.cpp
#include "someip_bridge.hpp"
#include
SomeIPBridge::SomeIPBridge() {}
SomeIPBridge::~SomeIPBridge() {}
void SomeIPBridge::publish(const Example& msg) {
// 本来は vsomeip の Application を初期化して send
std::cout << "[SOME/IP] Publish: id=" << msg.id()
<< ", message=" << msg.message() << std::endl;
}
📌 src/main.cpp
#include "dds_bridge.hpp"
#include "someip_bridge.hpp"
#include
int main(int argc, char** argv) {
std::cout << "Starting DDS <-> SOME/IP Bridge (Demo)" << std::endl;
DDSBridge dds;
SomeIPBridge someip;
dds.start([&someip](const Example& msg) {
std::cout << "[Bridge] DDS -> SOME/IP" << std::endl;
someip.publish(msg);
});
// メインスレッドは生存を維持
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(10));
}
return 0;
}
✅ 動作イメージ
ビルドして実行すると、DDS 側(ダミー生成メッセージ)が SOME/IP 側に「転送」されるログが出力されます:
Starting DDS <-> SOME/IP Bridge (Demo)
[Bridge] DDS -> SOME/IP
[SOME/IP] Publish: id=0, message=Hello from DDS 0
[Bridge] DDS -> SOME/IP
[SOME/IP] Publish: id=1, message=Hello from DDS 1
...
これで リポジトリのテンプレートとして push すれば、
CI がビルド確認
bridge バイナリを実行すると DDS → SOME/IP ダミー転送ログ
が動作します 🎉
👉 ご希望なら次は、vsomeip.json のサンプル設定ファイル(サービスID, インスタンスID 定義)も一緒に入れて、本物の vsomeip publish 版 に拡張しますか?
はい。お願いします。
ChatGPT:
了解です ✅
では、vsomeip.json を追加して、実際の vsomeip publish ができる構成に拡張します。
これで、DDS 側(ダミーのサブスクライバ)が受信したメッセージを、vsomeip のサービス (ServiceID, InstanceID, EventID) として配信できるようになります。
📂 ディレクトリ(更新)
my_autosar_bridge/
├── CMakeLists.txt
├── src/
│ ├── dds_bridge.cpp
│ ├── dds_bridge.hpp
│ ├── someip_bridge.cpp
│ ├── someip_bridge.hpp
│ └── main.cpp
├── idl/
│ └── Example.idl
├── config/
│ └── vsomeip.json
├── tools/
│ └── generate_types.sh
└── .github/
└── workflows/
└── ci.yml
📌 config/vsomeip.json (サンプル設定)
{
"unicast": "127.0.0.1",
"logging": {
"level": "info",
"console": "true"
},
"applications": [
{
"name": "my_someip_app",
"id": "0x1234"
}
],
"services": [
{
"service": "0x1111",
"instance": "0x2222",
"unreliable": "30509",
"events": [
{
"event": "0x3333",
"is_field": true
}
],
"eventgroups": [
{
"eventgroup": "0x4444",
"events": ["0x3333"]
}
]
}
]
}
ServiceID: 0x1111
InstanceID: 0x2222
EventID: 0x3333
EventGroupID: 0x4444
📌 src/someip_bridge.hpp(更新)
#pragma once
#include "ExamplePubSubTypes.h"
#include
#include
#include
class SomeIPBridge {
public:
SomeIPBridge();
~SomeIPBridge();
void init();
void start();
void publish(const Example& msg);
private:
std::shared_ptrvsomeip::application app_;
std::thread worker_;
bool running_;
const vsomeip::service_t SERVICE_ID = 0x1111;
const vsomeip::instance_t INSTANCE_ID = 0x2222;
const vsomeip::event_t EVENT_ID = 0x3333;
const vsomeip::eventgroup_t EVENTGROUP_ID = 0x4444;
};
📌 src/someip_bridge.cpp(更新)
#include "someip_bridge.hpp"
#include
SomeIPBridge::SomeIPBridge()
: app_(vsomeip::runtime::get()->create_application("my_someip_app")),
running_(false) {}
SomeIPBridge::~SomeIPBridge() {
running_ = false;
if (worker_.joinable())
worker_.join();
}
void SomeIPBridge::init() {
if (!app_->init()) {
std::cerr << "[SOME/IP] Application init failed!" << std::endl;
return;
}
app_->offer_service(SERVICE_ID, INSTANCE_ID);
app_->offer_event(
SERVICE_ID, INSTANCE_ID, EVENT_ID,
{EVENTGROUP_ID}, true
);
app_->notify_one(SERVICE_ID, INSTANCE_ID, EVENT_ID);
running_ = true;
}
void SomeIPBridge::start() {
worker_ = std::thread(this {
app_->start();
});
}
void SomeIPBridge::publish(const Example& msg) {
std::string payload_str =
"id=" + std::to_string(msg.id()) +
", message=" + msg.message();
std::shared_ptrvsomeip::payload payload =
vsomeip::runtime::get()->create_payload();
std::vectorvsomeip::byte_t pl_data(
payload_str.begin(), payload_str.end()
);
payload->set_data(pl_data);
app_->notify(SERVICE_ID, INSTANCE_ID, EVENT_ID, payload);
std::cout << "[SOME/IP] Published event: " << payload_str << std::endl;
}
📌 src/main.cpp(更新)
#include "dds_bridge.hpp"
#include "someip_bridge.hpp"
#include
int main(int argc, char** argv) {
std::cout << "Starting DDS <-> SOME/IP Bridge (Real SOME/IP)" << std::endl;
DDSBridge dds;
SomeIPBridge someip;
someip.init();
someip.start();
dds.start([&someip](const Example& msg) {
std::cout << "[Bridge] DDS -> SOME/IP" << std::endl;
someip.publish(msg);
});
// keep main alive
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(10));
}
return 0;
}
✅ 実行方法ビルド
cmake -B build -S .
cmake --build build環境変数で設定ファイルを指定
export VSOMEIP_CONFIGURATION=./config/vsomeip.json
export VSOMEIP_APPLICATION_NAME=my_someip_app実行
./build/bridge
これで、
DDS 側からのダミーメッセージが
vsomeip を通じて ServiceID=0x1111, InstanceID=0x2222, EventID=0x3333 で Publish
されます 🚗⚡️
👉 次のステップとして、vsomeip クライアント(Subscriber 側)のサンプルコードも追加して、イベントを受け取れるようにしましょうか?
はい。お願いします。
ChatGPT:
了解です ✅
それでは、先ほど作った SOME/IP Publisher (Bridge) のイベントを受け取るための SOME/IP Subscriber (Client) のサンプルコード を追加します。
これで「DDS → SOME/IP Publisher → SOME/IP Subscriber」という動作確認が可能になります。
📂 ディレクトリ(更新)
my_autosar_bridge/
├── CMakeLists.txt
├── src/
│ ├── dds_bridge.cpp
│ ├── dds_bridge.hpp
│ ├── someip_bridge.cpp
│ ├── someip_bridge.hpp
│ ├── main.cpp # Publisher (Bridge)
│ └── someip_client.cpp # NEW Subscriber
├── idl/
│ └── Example.idl
├── config/
│ └── vsomeip.json
├── tools/
│ └── generate_types.sh
└── .github/
└── workflows/
└── ci.yml
📌 src/someip_client.cpp
#include
#include
#include
class SomeIPClient {
public:
SomeIPClient()
: app_(vsomeip::runtime::get()->create_application("my_someip_client")) {}
void init() {
if (!app_->init()) {
std::cerr << "[Client] Application init failed!" << std::endl;
return;
}
// イベント通知を購読
app_->request_service(SERVICE_ID, INSTANCE_ID);
app_->subscribe(SERVICE_ID, INSTANCE_ID, EVENTGROUP_ID);
app_->register_message_handler(
SERVICE_ID, INSTANCE_ID, EVENT_ID,
std::bind(&SomeIPClient::on_message, this,
std::placeholders::_1)
);
}
void start() {
app_->start();
}
private:
std::shared_ptrvsomeip::application app_;
const vsomeip::service_t SERVICE_ID = 0x1111;
const vsomeip::instance_t INSTANCE_ID = 0x2222;
const vsomeip::event_t EVENT_ID = 0x3333;
const vsomeip::eventgroup_t EVENTGROUP_ID = 0x4444;
void on_message(const std::shared_ptr<vsomeip::message> &msg) {
auto payload = msg->get_payload();
std::string data(
reinterpret_cast<const char*>(payload->get_data()),
payload->get_length()
);
std::cout << "[Client] Received event: " << data << std::endl;
}
};
int main(int argc, char** argv) {
std::cout << "Starting SOME/IP Client" << std::endl;
SomeIPClient client;
client.init();
client.start();
return 0;
}
📌 CMakeLists.txt(一部追加)
Subscriber Client
add_executable(someip_client
src/someip_client.cpp
)
target_link_libraries(someip_client
vsomeip3
)
✅ 実行方法
ターミナルを2つ用意して、それぞれ以下を実行します。
1️⃣ Publisher (Bridge: DDS→SOME/IP)
export VSOMEIP_CONFIGURATION=./config/vsomeip.json
export VSOMEIP_APPLICATION_NAME=my_someip_app
./build/bridge
2️⃣ Subscriber (Client)
export VSOMEIP_CONFIGURATION=./config/vsomeip.json
export VSOMEIP_APPLICATION_NAME=my_someip_client
./build/someip_client
✅ 実行結果イメージ
Publisher 側:
Starting DDS <-> SOME/IP Bridge (Real SOME/IP)
[Bridge] DDS -> SOME/IP
[SOME/IP] Published event: id=0, message=Hello from DDS 0
...
Client 側:
Starting SOME/IP Client
[Client] Received event: id=0, message=Hello from DDS 0
[Client] Received event: id=1, message=Hello from DDS 1
...
🚗⚡️ これで DDS メッセージが SOME/IP で配信され、クライアントが購読できる ところまで実装できました。
👉 次に進めるとしたら、
双方向通信(Client → Publisher への RPC 呼び出し) を追加する
本物の DDS Subscriber(FastDDS) を組み込み、ダミーではなく実際の Pub/Sub を通す
のどちらを優先しますか?
あなた:
双方向通信(Client → Publisher への RPC 呼び出し) を追加する
ChatGPT:
👍 了解しました。
では次のステップとして、 SOME/IP の双方向通信 (Client → Publisher への RPC 呼び出し) を追加しましょう。
これにより、クライアントから Publisher(Bridge)に対して「メソッド呼び出し」ができ、Publisher 側がレスポンスを返す、という 典型的なサービス指向通信パターン が実装できます。
🔹 実装方針
ServiceID = 0x1111, InstanceID = 0x2222 はそのまま利用
これまでの Event (0x3333) に加えて、
MethodID = 0x5555 を追加(例:echo_request)
クライアント → サーバ(Bridge)へリクエストを送信
サーバ側がハンドラで受け取り → レスポンスを返す
📌 config/vsomeip.json(更新)
{
"unicast": "127.0.0.1",
"logging": {
"level": "info",
"console": "true"
},
"applications": [
{
"name": "my_someip_app",
"id": "0x1234"
},
{
"name": "my_someip_client",
"id": "0x2345"
}
],
"services": [
{
"service": "0x1111",
"instance": "0x2222",
"unreliable": "30509",
"events": [
{
"event": "0x3333",
"is_field": true
}
],
"eventgroups": [
{
"eventgroup": "0x4444",
"events": ["0x3333"]
}
],
"methods": [
{
"method": "0x5555"
}
]
}
]
}
📌 Publisher 側(Bridge: someip_bridge.* 更新)
someip_bridge.hpp に RPC 用定義を追加
private:
const vsomeip::method_t METHOD_ID = 0x5555;
void on_request(const std::shared_ptr<vsomeip::message> &request);
someip_bridge.cpp 更新
void SomeIPBridge::init() {
if (!app_->init()) {
std::cerr << "[SOME/IP] Application init failed!" << std::endl;
return;
}
app_->offer_service(SERVICE_ID, INSTANCE_ID);
// Event
app_->offer_event(SERVICE_ID, INSTANCE_ID, EVENT_ID,
{EVENTGROUP_ID}, true);
// Method (RPC)
app_->register_message_handler(
SERVICE_ID, INSTANCE_ID, METHOD_ID,
std::bind(&SomeIPBridge::on_request, this,
std::placeholders::_1)
);
app_->notify_one(SERVICE_ID, INSTANCE_ID, EVENT_ID);
running_ = true;
}
void SomeIPBridge::on_request(const std::shared_ptrvsomeip::message &request) {
auto payload = request->get_payload();
std::string data(
reinterpret_cast(payload->get_data()),
payload->get_length()
);
std::cout << "[SOME/IP] Received RPC request: " << data << std::endl;
// Echo back response
auto response = vsomeip::runtime::get()->create_response(request);
auto resp_payload = vsomeip::runtime::get()->create_payload();
std::string reply = "Echo: " + data;
std::vector<vsomeip::byte_t> pl_data(reply.begin(), reply.end());
resp_payload->set_data(pl_data);
response->set_payload(resp_payload);
app_->send(response);
std::cout << "[SOME/IP] Sent RPC response: " << reply << std::endl;
}
📌 Client 側(someip_client.cpp 更新)
クライアントで RPC 呼び出しを追加。
void send_request() {
auto rq = vsomeip::runtime::get()->create_request();
rq->set_service(SERVICE_ID);
rq->set_instance(INSTANCE_ID);
rq->set_method(METHOD_ID);
std::string msg = "Hello RPC!";
std::shared_ptr<vsomeip::payload> pl = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> data(msg.begin(), msg.end());
pl->set_data(data);
rq->set_payload(pl);
app_->send(rq);
std::cout << "[Client] Sent RPC request: " << msg << std::endl;
}
void init() {
if (!app_->init()) {
std::cerr << "[Client] Application init failed!" << std::endl;
return;
}
app_->request_service(SERVICE_ID, INSTANCE_ID);
// Subscribe event
app_->subscribe(SERVICE_ID, INSTANCE_ID, EVENTGROUP_ID);
app_->register_message_handler(SERVICE_ID, INSTANCE_ID, EVENT_ID,
std::bind(&SomeIPClient::on_message, this, std::placeholders::_1));
// RPC response handler
app_->register_message_handler(SERVICE_ID, INSTANCE_ID, METHOD_ID,
[this](const std::shared_ptr<vsomeip::message> &response) {
auto payload = response->get_payload();
std::string data(
reinterpret_cast<const char*>(payload->get_data()),
payload->get_length()
);
std::cout << "[Client] Received RPC response: " << data << std::endl;
});
}
✅ 実行シーケンス
Publisher (Bridge) 起動
export VSOMEIP_CONFIGURATION=./config/vsomeip.json
export VSOMEIP_APPLICATION_NAME=my_someip_app
./build/bridge
Client 起動(イベント購読+RPC呼び出し)
export VSOMEIP_CONFIGURATION=./config/vsomeip.json
export VSOMEIP_APPLICATION_NAME=my_someip_client
./build/someip_client
Client で送信 → Publisher で受信 → Publisher がレスポンス返却 → Client が受信
✅ 実行結果イメージ
Publisher
[SOME/IP] Received RPC request: Hello RPC!
[SOME/IP] Sent RPC response: Echo: Hello RPC!
Client
[Client] Sent RPC request: Hello RPC!
[Client] Received RPC response: Echo: Hello RPC!
🚗⚡️ これで 双方向通信(Client → Publisher RPC 呼び出し & 応答) まで完了しました!
👉 次の拡張ポイントとしては:
複数メソッド(例: GetStatus, SetConfig)の追加
DDS 側のデータに応じて RPC 応答内容を動的に変える
などがあります。
ご希望は「RPC メソッドを複数追加」か「DDS データと連携した応答」どちらを優先しますか?
あなた:
DDS 側のデータに応じて RPC 応答内容を動的に変える
ChatGPT:
了解です ✅
では、DDS 側の受信データを リアルタイムに RPC 応答に反映する仕組み を追加します。
目標は以下です:
DDSBridge が受信した Example メッセージを内部に保持
Client から RPC 呼び出しが来たら、最新の DDS データを返す
Event (通知) と RPC を連携させる
1️⃣ Publisher (Bridge) 側 更新
dds_bridge.hpp 更新
#pragma once
#include "ExamplePubSubTypes.h"
#include
#include
class DDSBridge {
public:
using Callback = std::function;
DDSBridge();
~DDSBridge();
void start(Callback cb);
// 最新データを取得(RPC 用)
Example get_latest_data();
private:
Callback callback_;
Example latest_msg_;
std::mutex mtx_;
};
dds_bridge.cpp 更新
#include "dds_bridge.hpp"
#include
#include
#include
DDSBridge::DDSBridge() {}
DDSBridge::~DDSBridge() {}
void DDSBridge::start(Callback cb) {
callback_ = cb;
std::thread([this]() {
for (int i = 0; i < 10; i++) {
Example msg;
msg.id(i);
msg.message("Hello from DDS " + std::to_string(i));
{
std::lock_guard<std::mutex> lock(mtx_);
latest_msg_ = msg;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
if (callback_) callback_(msg);
}
}).detach();
}
Example DDSBridge::get_latest_data() {
std::lock_guardstd::mutex lock(mtx_);
return latest_msg_;
}
someip_bridge.hpp 更新(DDSBridge への参照追加)
class SomeIPBridge {
public:
SomeIPBridge(DDSBridge& dds);
~SomeIPBridge();
void init();
void start();
void publish(const Example& msg);
private:
DDSBridge& dds_;
void on_request(const std::shared_ptr<vsomeip::message> &request);
std::shared_ptr<vsomeip::application> app_;
std::thread worker_;
bool running_;
const vsomeip::service_t SERVICE_ID = 0x1111;
const vsomeip::instance_t INSTANCE_ID = 0x2222;
const vsomeip::event_t EVENT_ID = 0x3333;
const vsomeip::eventgroup_t EVENTGROUP_ID = 0x4444;
const vsomeip::method_t METHOD_ID = 0x5555;
};
someip_bridge.cpp 更新(RPC 応答を DDS データで返す)
SomeIPBridge::SomeIPBridge(DDSBridge& dds) : dds_(dds),
app_(vsomeip::runtime::get()->create_application("my_someip_app")),
running_(false) {}
void SomeIPBridge::on_request(const std::shared_ptrvsomeip::message &request) {
// DDS 側の最新データを取得
Example latest = dds_.get_latest_data();
std::string reply = "DDS Echo: id=" + std::to_string(latest.id())
+ ", message=" + latest.message();
auto response = vsomeip::runtime::get()->create_response(request);
auto resp_payload = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> pl_data(reply.begin(), reply.end());
resp_payload->set_data(pl_data);
response->set_payload(resp_payload);
app_->send(response);
std::cout << "[SOME/IP] Sent RPC response: " << reply << std::endl;
}
main.cpp 更新
int main(int argc, char** argv) {
std::cout << "Starting DDS <-> SOME/IP Bridge (RPC linked to DDS)" << std::endl;
DDSBridge dds;
SomeIPBridge someip(dds);
someip.init();
someip.start();
dds.start([&someip](const Example& msg) {
std::cout << "[Bridge] DDS -> SOME/IP Event" << std::endl;
someip.publish(msg);
});
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(10));
}
return 0;
}
✅ 動作イメージ
DDS 側が Example メッセージを生成
Bridge が Event として SOME/IP に通知
Client から RPC を呼ぶと → 最新の DDS データを返す
Client 側出力例
[Client] Sent RPC request: Request latest DDS
[Client] Received RPC response: DDS Echo: id=3, message=Hello from DDS 3
これで、DDS の状態に応じた動的な RPC 応答 が可能になりました 🚗⚡️
💡 次のステップとして考えられる拡張:
RPC メソッドを複数追加して状態取得・制御系を分ける
Event と RPC の同期整合性(DDS 更新タイムスタンプと RPC 応答)を強化
複数 Client への同時応答(スレッド安全・QoS 管理)
希望はどれを優先しますか?
あなた:
RPC メソッドを複数追加して状態取得・制御系を分ける
ChatGPT:
了解です ✅
では、複数 RPC メソッドを追加して、状態取得系と制御系を分ける構成 を作ります。
目標は以下です:
MethodID=0x5555 → 状態取得 (GetLatestDDS)
MethodID=0x6666 → 制御コマンド (SetMessagePrefix)
Client から呼び出し可能で、Bridge 側で内部状態を更新・応答
DDS イベント通知はそのまま継続
1️⃣ Publisher (Bridge) 側更新
dds_bridge.hpp に制御用データ追加
#pragma once
#include "ExamplePubSubTypes.h"
#include
#include
#include
class DDSBridge {
public:
using Callback = std::function;
DDSBridge();
~DDSBridge();
void start(Callback cb);
Example get_latest_data();
void set_message_prefix(const std::string& prefix);
private:
Callback callback_;
Example latest_msg_;
std::mutex mtx_;
std::string prefix_ = "Hello from DDS";
};
dds_bridge.cpp 更新
void DDSBridge::start(Callback cb) {
callback_ = cb;
std::thread([this]() {
for (int i = 0; i < 10; i++) {
Example msg;
{
std::lock_guard<std::mutex> lock(mtx_);
msg.id(i);
msg.message(prefix_ + " " + std::to_string(i));
latest_msg_ = msg;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
if (callback_) callback_(msg);
}
}).detach();
}
Example DDSBridge::get_latest_data() {
std::lock_guardstd::mutex lock(mtx_);
return latest_msg_;
}
void DDSBridge::set_message_prefix(const std::string& prefix) {
std::lock_guardstd::mutex lock(mtx_);
prefix_ = prefix;
}
someip_bridge.hpp 更新(MethodID 追加)
private:
const vsomeip::method_t GET_LATEST_METHOD_ID = 0x5555;
const vsomeip::method_t SET_PREFIX_METHOD_ID = 0x6666;
void on_get_latest_request(const std::shared_ptr<vsomeip::message> &request);
void on_set_prefix_request(const std::shared_ptr<vsomeip::message> &request);
someip_bridge.cpp 更新(複数 RPC ハンドラ登録)
void SomeIPBridge::init() {
if (!app_->init()) {
std::cerr << "[SOME/IP] Application init failed!" << std::endl;
return;
}
app_->offer_service(SERVICE_ID, INSTANCE_ID);
// Event
app_->offer_event(SERVICE_ID, INSTANCE_ID, EVENT_ID,
{EVENTGROUP_ID}, true);
// RPC Handlers
app_->register_message_handler(
SERVICE_ID, INSTANCE_ID, GET_LATEST_METHOD_ID,
std::bind(&SomeIPBridge::on_get_latest_request, this, std::placeholders::_1)
);
app_->register_message_handler(
SERVICE_ID, INSTANCE_ID, SET_PREFIX_METHOD_ID,
std::bind(&SomeIPBridge::on_set_prefix_request, this, std::placeholders::_1)
);
app_->notify_one(SERVICE_ID, INSTANCE_ID, EVENT_ID);
running_ = true;
}
void SomeIPBridge::on_get_latest_request(const std::shared_ptrvsomeip::message &request) {
Example latest = dds_.get_latest_data();
std::string reply = "DDS Echo: id=" + std::to_string(latest.id())
+ ", message=" + latest.message();
auto response = vsomeip::runtime::get()->create_response(request);
auto resp_payload = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> pl_data(reply.begin(), reply.end());
resp_payload->set_data(pl_data);
response->set_payload(resp_payload);
app_->send(response);
std::cout << "[SOME/IP] Sent GetLatestRPC response: " << reply << std::endl;
}
void SomeIPBridge::on_set_prefix_request(const std::shared_ptrvsomeip::message &request) {
auto payload = request->get_payload();
std::string new_prefix(reinterpret_cast(payload->get_data()), payload->get_length());
dds_.set_message_prefix(new_prefix);
auto response = vsomeip::runtime::get()->create_response(request);
auto resp_payload = vsomeip::runtime::get()->create_payload();
std::string reply = "Prefix updated: " + new_prefix;
std::vector<vsomeip::byte_t> pl_data(reply.begin(), reply.end());
resp_payload->set_data(pl_data);
response->set_payload(resp_payload);
app_->send(response);
std::cout << "[SOME/IP] Sent SetPrefixRPC response: " << reply << std::endl;
}
2️⃣ Client 側 RPC 呼び出し追加
void send_get_latest_request() {
auto rq = vsomeip::runtime::get()->create_request();
rq->set_service(SERVICE_ID);
rq->set_instance(INSTANCE_ID);
rq->set_method(GET_LATEST_METHOD_ID);
app_->send(rq);
std::cout << "[Client] Sent GetLatestRPC request" << std::endl;
}
void send_set_prefix_request(const std::string& prefix) {
auto rq = vsomeip::runtime::get()->create_request();
rq->set_service(SERVICE_ID);
rq->set_instance(INSTANCE_ID);
rq->set_method(SET_PREFIX_METHOD_ID);
std::shared_ptr<vsomeip::payload> pl = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> data(prefix.begin(), prefix.end());
pl->set_data(data);
rq->set_payload(pl);
app_->send(rq);
std::cout << "[Client] Sent SetPrefixRPC request: " << prefix << std::endl;
}
メインなどで呼び出す例:
send_get_latest_request();
send_set_prefix_request("UpdatedPrefix");
send_get_latest_request();
3️⃣ 実行結果イメージ
Publisher (Bridge)
[SOME/IP] Sent SetPrefixRPC response: Prefix updated: UpdatedPrefix
[SOME/IP] Sent GetLatestRPC response: DDS Echo: id=3, message=UpdatedPrefix 3
Client
[Client] Sent SetPrefixRPC request: UpdatedPrefix
[Client] Received RPC response: Prefix updated: UpdatedPrefix
[Client] Sent GetLatestRPC request
[Client] Received RPC response: DDS Echo: id=3, message=UpdatedPrefix 3
✅ これで 複数 RPC メソッドを追加し、状態取得(GetLatestDDS)と制御系(SetMessagePrefix)を分離 できました。
次のステップとしては:
複数 Client から同時に RPC 呼び出しを受けても スレッド安全に処理
DDS Event の QoS に応じた Event 配信
RPC メソッドを JSON や IDL で自動生成して 拡張性を高める
どの方向を優先して進めますか?
あなた:
複数 Client から同時に RPC 呼び出しを受けても スレッド安全に処理
ChatGPT:
了解です ✅
では、複数 Client から同時に RPC 呼び出しが来てもスレッド安全に処理できる構成 を示します。
目標:
DDSBridge の内部状態を保護
latest_msg_ と prefix_ に対するアクセスは mutex で保護済み
SOME/IP Publisher (Bridge) の RPC ハンドラでスレッド安全に処理
複数 Client からの同時リクエストでも mutex を用いて状態参照・更新を安全にする
Event 送信もスレッド安全に
RPC と DDSイベント送信が同時に行われても競合しない
1️⃣ DDSBridge のスレッド安全化(再確認)
class DDSBridge {
public:
// ...
Example get_latest_data();
void set_message_prefix(const std::string& prefix);
private:
Example latest_msg_;
std::string prefix_;
std::mutex mtx_; // すべての状態に対して mutex で保護
};
Example DDSBridge::get_latest_data() {
std::lock_guardstd::mutex lock(mtx_);
return latest_msg_;
}
void DDSBridge::set_message_prefix(const std::string& prefix) {
std::lock_guardstd::mutex lock(mtx_);
prefix_ = prefix;
}
これで 状態取得・更新 はスレッド安全です。
2️⃣ SOME/IP Publisher 側 RPC ハンドラの安全化
RPC は複数 Client から同時に呼ばれることがあります。
on_get_latest_request と on_set_prefix_request は DDSBridge 内部で mutex が効いているので競合は防げます
Event 送信時も、vsomeip::application は内部的にスレッド安全に送信できるようになっています
必要であれば、RPC ハンドラ内部で mutex でアプリケーション送信も保護 するとより安全です。
void SomeIPBridge::on_get_latest_request(const std::shared_ptrvsomeip::message &request) {
Example latest = dds_.get_latest_data();
std::string reply = "DDS Echo: id=" + std::to_string(latest.id())
+ ", message=" + latest.message();
std::lock_guard<std::mutex> lock(send_mtx_); // RPC応答送信も保護
auto response = vsomeip::runtime::get()->create_response(request);
auto resp_payload = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> pl_data(reply.begin(), reply.end());
resp_payload->set_data(pl_data);
response->set_payload(resp_payload);
app_->send(response);
std::cout << "[SOME/IP] Sent GetLatestRPC response: " << reply << std::endl;
}
void SomeIPBridge::on_set_prefix_request(const std::shared_ptrvsomeip::message &request) {
auto payload = request->get_payload();
std::string new_prefix(reinterpret_cast(payload->get_data()), payload->get_length());
dds_.set_message_prefix(new_prefix);
std::string reply = "Prefix updated: " + new_prefix;
std::lock_guard<std::mutex> lock(send_mtx_);
auto response = vsomeip::runtime::get()->create_response(request);
auto resp_payload = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> pl_data(reply.begin(), reply.end());
resp_payload->set_data(pl_data);
response->set_payload(resp_payload);
app_->send(response);
std::cout << "[SOME/IP] Sent SetPrefixRPC response: " << reply << std::endl;
}
send_mtx_ は SomeIPBridge 内で定義:
std::mutex send_mtx_;
3️⃣ Client からの同時 RPC テスト
複数 Client を起動して、同時に RPC を送信しても安全:
./build/someip_client & # Client1
./build/someip_client & # Client2
./build/someip_client & # Client3
出力例:
[Client1] Sent GetLatestRPC request
[Client2] Sent GetLatestRPC request
[Client3] Sent SetPrefixRPC request: NewPrefix
[Client1] Received RPC response: DDS Echo: id=5, message=NewPrefix 5
[Client2] Received RPC response: DDS Echo: id=5, message=NewPrefix 5
[Client3] Received RPC response: Prefix updated: NewPrefix
latest_msg_ と prefix_ は mutex で保護
RPC 応答送信も mutex で保護
→ どの Client からのリクエストも安全に処理可能
✅ ポイントまとめ
内部状態の保護:DDSBridge の latest_msg_ と prefix_ に mutex を使用
RPC応答送信の保護:複数 Client 同時アクセスを考慮して send_mtx_ を導入
Event送信は vsomeip 側でスレッド安全
この構成で、複数 Client から同時に RPC 呼び出しされても安全に状態を取得・制御できる
💡 次の拡張アイデア:
RPC メソッドの自動生成:ID と型を JSON/IDL から生成して拡張性を高める
QoS 制御付き Event:複数 Client が Event を受信する際の信頼性・順序制御
複数 DDS Topic 対応:Bridge が複数 DDS Topic を扱い、RPC で個別取得
希望はどの方向を優先しますか?
あなた:
ここまでの技術を背景に、新しいROS3の規格案をご提示ください。
ChatGPT:
なるほどです。ここまでの DDS/SOME-IP 双方向通信、複数 Client RPC、スレッド安全性、イベント配信 の経験を踏まえて、次世代 ROS 3 の規格案を設計してみます。
ROS 3 (規格案) — 基本コンセプト
1️⃣ 目的
ROS 2 の DDS ベースの Pub/Sub と RPC を拡張
自動車・産業向けリアルタイム通信(SOME/IP との統合)に対応
マルチ Client/Server におけるスレッド安全性と QoS 管理を標準化
IDL/JSON ベースの自動型生成による拡張性を強化
2️⃣ アーキテクチャ
┌─────────────────────┐
│ ROS 3 Node │
│ ┌───────────────┐ │
│ │ Publisher │ │
│ │ Event / Topic │ │
│ └───────────────┘ │
│ ┌───────────────┐ │
│ │ Subscriber │ │
│ │ Event / Topic │ │
│ └───────────────┘ │
│ ┌───────────────┐ │
│ │ Service / RPC │<─┐
│ └───────────────┘ │ │
└─────────────────────┘ │
│ │
┌─────────┴─────────┐ │
│ DDS Layer │ │
│ (FastDDS / Cyclone)│ │
└───────────────────┘ │
┌───────────────────┐ │
│ SOME/IP Layer │────────┘
└───────────────────┘
特徴
DDS Layer
高速 Pub/Sub、リアルタイム QoS
Topic, QoS, Reliability, Latency を明示
SOME/IP Layer
Service RPC / Event 配信
自動車向けリアルタイム通信との互換性
Node 内部
Publisher, Subscriber, Service が統一 API
内部状態管理は mutex 保護
Event & RPC はスレッド安全
3️⃣ コア規格要素
要素 説明
Node ROS 3 の最小単位。Publisher / Subscriber / Service / Client を保持
Topic DDS 同期型メッセージ。QoS、型情報(IDL/JSON)管理
Event SOME/IP イベント。QoS、順序保証、複数 Client 同時通知
Service / RPC Client ↔ Server 双方向通信。スレッド安全、複数 Client サポート
Type System IDL + JSON による自動型生成(Pub/Sub & RPC 両対応)
QoS DDS QoS + Event Reliability + RPC Timeout を統一管理
Threading 内部状態(Publisher/RPC/Event)への同時アクセスは mutex 保護
4️⃣ 拡張案(ROS 3 新機能)
RPC メソッド自動生成
IDL/JSON から RPC と Event を自動生成
メソッドごとに QoS と優先度を設定可能
統合型 DDS/SOME-IP ブリッジ
DDS Topic を SOME/IP Event と自動同期
双方向 RPC → DDS 状態取得 / 制御
複数 Client 対応 RPC
Server 側でスレッド安全なキュー管理
Client ごとの優先度 / レイテンシ管理
リアルタイム安全
イベント配信の順序保証
DDS QoS と SOME/IP 信頼性統合
RPC タイムアウト & リトライ標準化
プラグイン可能型 Transport Layer
DDS, SOME-IP, ZeroMQ, MQTT などを抽象化
Node API は共通
5️⃣ サンプル ROS 3 Node API(規格案)
ros3::Node node("my_node");
// DDS Topic Publisher
auto pub = node.advertise("example_topic", QoS::Reliable);
// DDS Topic Subscriber
auto sub = node.subscribe("example_topic", [&](const Example& msg){
std::cout << "Received DDS message: " << msg.message() << std::endl;
});
// SOME/IP RPC Service
auto srv = node.advertise_service(
"GetLatestDDS",
[&](const Example& req) -> std::string {
return "Echo: " + req.message();
}
);
// SOME/IP RPC Client
auto cli = node.create_client("GetLatestDDS");
std::string resp = cli.call(Example{.id=1, .message="Hello"});
6️⃣ メリット
DDS と SOME/IP の長所を統合
複数 Client / RPC / Event を統一 API で管理
スレッド安全性を標準化
自動型生成で開発効率を大幅向上
IDL/JSON で型安全性と拡張性を両立
💡 補足
この ROS 3 規格案は、リアルタイム自動車通信を意識した DDS/SOME-IP ハイブリッド型であり、従来 ROS 2 よりも以下が改善されます:
複数 Client からの同時 RPC 安全性
Event と RPC の統一型 QoS
型安全な自動生成で開発効率向上
希望であれば、この ROS 3 規格をベースに、サンプル GitHub プロジェクト構造(Publisher/Subscriber/RPC/Client を統合したテンプレート)まで作ることも可能です。
作りますか?
あなた:
はい。おねがいします。
ChatGPT:
了解です ✅
では、先ほどの ROS 3 規格案 に沿った サンプル GitHub プロジェクト構造 を作ります。
目的:
DDS Topic Publisher / Subscriber
SOME/IP RPC Service / Client
複数 Client 同時 RPC でも安全
IDL/JSON 型定義を自動生成可能
1️⃣ ディレクトリ構造(ROS3 テンプレ)
ros3_sample/
├── CMakeLists.txt
├── src/
│ ├── main.cpp # Node 起動
│ ├── ros3_node.hpp
│ ├── ros3_node.cpp
│ ├── dds_bridge.hpp
│ ├── dds_bridge.cpp
│ ├── someip_bridge.hpp
│ ├── someip_bridge.cpp
│ └── someip_client.cpp
├── idl/
│ └── Example.idl # 型定義
├── config/
│ └── vsomeip.json
├── tools/
│ └── generate_types.sh # IDL→C++型自動生成
└── .github/
└── workflows/
└── ci.yml # GitHub Actions CI
2️⃣ CMakeLists.txt(サンプル)
cmake_minimum_required(VERSION 3.15)
project(ros3_sample)
set(CMAKE_CXX_STANDARD 17)
vsomeip, DDS ライブラリ
find_package(vsomeip3 REQUIRED)
find_package(fastrtps REQUIRED)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
Node 実行ファイル
add_executable(ros3_node src/main.cpp src/ros3_node.cpp src/dds_bridge.cpp src/someip_bridge.cpp)
target_link_libraries(ros3_node vsomeip3 fastrtps)
SOME/IP Client
add_executable(someip_client src/someip_client.cpp)
target_link_libraries(someip_client vsomeip3)
3️⃣ tools/generate_types.sh(IDL→C++ 型自動生成)
#!/bin/bash
mkdir -p src/generated
fastrtpsgen -d src/generated -example x64Linux2.6gcc Example.idl
echo "Generated DDS types for Example.idl"
4️⃣ .github/workflows/ci.yml(簡易 CI)
name: CMake CI
on:
push:
branches: [ main ]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup CMake
uses: jwlawson/actions-setup-cmake@v1
- name: Install dependencies
run: sudo apt-get install -y libvsomeip-dev libfastrtps-dev
- name: Build
run: |
mkdir build
cd build
cmake ..
make -j
5️⃣ サンプル Node API
#include "ros3_node.hpp"
int main() {
ROS3Node node("my_node");
// DDS Publisher
auto pub = node.advertise<Example>("example_topic");
// DDS Subscriber
auto sub = node.subscribe<Example>("example_topic", [](const Example& msg){
std::cout << "Received DDS message: " << msg.message() << std::endl;
});
// SOME/IP RPC Service
node.advertise_service<Example, std::string>("GetLatestDDS", [&](const Example& req){
return "Echo: " + req.message();
});
// SOME/IP RPC Client
auto cli = node.create_client<Example, std::string>("GetLatestDDS");
std::string resp = cli.call(Example{.id=1, .message="Hello"});
std::cout << "RPC Response: " << resp << std::endl;
node.spin(); // イベントループ
return 0;
}
6️⃣ 特徴
DDS と SOME/IP を 統合 Node API で扱える
複数 Client 同時 RPC でも mutex によるスレッド安全化済み
Event / RPC / Pub/Sub を単一 Node で統一管理
IDL/JSON 型から 自動生成 可能
この構成を使えば、すぐに ROS3 Node の開発テンプレート として GitHub に配置して CI も回せます。
💡 次のステップの提案:
複数 Topic / 複数 RPC メソッド追加テンプレート
QoS 設定を Node API で簡単指定できるラッパ
リアルタイムシミュレーション用の Docker 環境構築
どれを優先して作成しますか?
あなた:
リアルタイムシミュレーション用の Docker 環境構築
ChatGPT:
了解です ✅
では、先ほどの ROS3 GitHub テンプレ をベースに、リアルタイムシミュレーション用の Docker 環境 を作る案を示します。
1️⃣ Docker 環境の方針
Ubuntu 22.04 ベース(ROS/DDS/SOME-IP 対応)
必要パッケージ:CMake, g++, vsomeip3, FastDDS
リアルタイムカーネル設定は軽量化
ソースコードを /workspace にマウントしてホットリロード可能
docker-compose を使い、複数 Node / Client を同時起動可能
2️⃣ Dockerfile
ベースイメージ
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo
必要パッケージ
RUN apt-get update && apt-get install -y
build-essential cmake git wget curl
libboost-all-dev
libasio-dev
libtinyxml2-dev
libvsomeip-dev
libfastrtps-dev
sudo
python3 python3-pip
ワークスペース作成
RUN mkdir -p /workspace
WORKDIR /workspace
ROS3 ソースコードをコピー
COPY . /workspace
IDL型自動生成
RUN chmod +x tools/generate_types.sh && ./tools/generate_types.sh
ビルド
RUN mkdir -p build && cd build && cmake .. && make -j
ポート開放(SOME/IP デフォルト)
EXPOSE 30509
デフォルトコマンド
CMD ["bash"]
3️⃣ docker-compose.yml(複数 Node / Client 起動)
version: '3.8'
services:
ros3_bridge:
build: .
container_name: ros3_bridge
volumes:
- .:/workspace
command: bash -c "export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/ros3_node"
ros3_client1:
build: .
container_name: ros3_client1
depends_on:
- ros3_bridge
volumes:
- .:/workspace
command: bash -c "export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
ros3_client2:
build: .
container_name: ros3_client2
depends_on:
- ros3_bridge
volumes:
- .:/workspace
command: bash -c "export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
4️⃣ 使い方
Docker イメージビルド:
docker-compose build
Bridge + Client を起動:
docker-compose up
出力イメージ例:
[Bridge] DDS -> SOME/IP Event
[Client1] Sent RPC request
[Client1] Received RPC response: DDS Echo: id=3, message=Hello from DDS 3
[Client2] Sent RPC request
[Client2] Received RPC response: DDS Echo: id=3, message=Hello from DDS 3
5️⃣ 特徴
複数 Node/Client の同時起動が容易
DDS/SOME-IP の統合通信を Docker 内でテスト可能
ホットリロード対応(ソースマウント)で開発効率向上
GitHub Actions CI との連携も可能
💡 拡張案:
リアルタイムカーネル:linux-image-rt ベースの Docker イメージでリアルタイム性能向上
Network Simulation:Latency, Packet Loss, QoS を Docker ネットワークで再現
Multiple DDS Topics & RPC Methods:テンプレートを自動生成して Node を追加
希望であれば、次に リアルタイムカーネル+ネットワーク遅延シミュレーションを組み込んだ完全 ROS3 Docker シミュ環境 のサンプルまで作ることも可能です。
作りますか?
あなた:
はい。お願いします。
ChatGPT:
了解です ✅
では、リアルタイムカーネル+ネットワーク遅延シミュレーションを組み込んだ完全 ROS3 Docker シミュ環境 を作成する案を示します。
1️⃣ 方針
ベースイメージ:ubuntu:22.04-rt(リアルタイムカーネル)
DDS/SOME-IP/Pub-Sub/RPC をすぐ動かせる
Docker ネットワークで レイテンシやパケットロスをシミュ
docker-compose で Bridge + 複数 Client を起動
ホストとコンテナ間でソースマウント、ホットリロード対応
2️⃣ Dockerfile(リアルタイムカーネル対応)
ベースは Ubuntu 22.04 リアルタイムカーネル
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo
カーネルと必要パッケージ
RUN apt-get update && apt-get install -y
build-essential cmake git wget curl
linux-image-rt
libboost-all-dev libasio-dev libtinyxml2-dev
libvsomeip-dev libfastrtps-dev
iproute2 sudo python3 python3-pip net-tools iputils-ping
ワークスペース
RUN mkdir -p /workspace
WORKDIR /workspace
ソースコードコピー
COPY . /workspace
IDL型生成
RUN chmod +x tools/generate_types.sh && ./tools/generate_types.sh
ビルド
RUN mkdir -p build && cd build && cmake .. && make -j
SOME/IP デフォルトポート
EXPOSE 30509
CMD ["bash"]
3️⃣ docker-compose.yml(ネットワーク遅延・複数 Client)
version: '3.8'
networks:
ros3net:
driver: bridge
services:
ros3_bridge:
build: .
container_name: ros3_bridge
networks:
ros3net:
ipv4_address: 172.20.0.2
cap_add:
- NET_ADMIN # tc で遅延制御
command: bash -c "tc qdisc add dev eth0 root netem delay 10ms loss 1% && export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/ros3_node"
ros3_client1:
build: .
container_name: ros3_client1
networks:
ros3net:
ipv4_address: 172.20.0.3
cap_add:
- NET_ADMIN
depends_on:
- ros3_bridge
command: bash -c "tc qdisc add dev eth0 root netem delay 15ms loss 2% && export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
ros3_client2:
build: .
container_name: ros3_client2
networks:
ros3net:
ipv4_address: 172.20.0.4
cap_add:
- NET_ADMIN
depends_on:
- ros3_bridge
command: bash -c "tc qdisc add dev eth0 root netem delay 20ms loss 3% && export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
4️⃣ ネットワーク遅延/パケットロス制御
tc qdisc add dev eth0 root netem delay 10ms loss 1%
→ 遅延 10ms、パケット損失 1% をシミュレーション
Client ごとに異なる遅延・損失を設定可能
複数 Client から同時 RPC / Event をテスト可能
5️⃣ 起動手順
Docker イメージビルド
docker-compose build
Bridge + Clients 起動
docker-compose up
出力例
[Bridge] DDS -> SOME/IP Event
[Client1] Sent RPC request
[Client1] Received RPC response: DDS Echo: id=3, message=Hello from DDS 3
[Client2] Sent SetPrefixRPC request: FastPrefix
[Client2] Received RPC response: Prefix updated: FastPrefix
遅延・パケットロスも同時に発生
複数 Client の同時 RPC が正しく処理される
6️⃣ 特徴
リアルタイムカーネル対応でレイテンシが安定
ネットワーク条件をコンテナ単位でシミュレーション可能
複数 Node / Client 同時起動でスレッド安全性を確認可能
DDS/SOME-IP 統合 Node をそのまま開発・デバッグできる
💡 拡張案:
QoS 条件(DDS Reliability/Deadline/Latency)とネットワーク遅延の組み合わせで リアルタイム性能テスト
複数 DDS Topic & RPC メソッドを 自動生成テンプレート化
GitHub Actions と Docker Compose を組み合わせて CI 上で遅延テスト自動化
希望であれば、次に この Docker シミュ環境を使った自動テスト用スクリプト まで作って、GitHub Actions で自動化する構成も作れます。
作りますか?
あなた:
jはい。お願いします。
ChatGPT:
了解です ✅
では、ROS3 Docker シミュ環境を使った自動テストスクリプトと、GitHub Actions での自動化 構成を作ります。
1️⃣ 自動テストスクリプト例 (tools/run_test.sh)
#!/bin/bash
set -e
Docker Compose 起動
docker-compose up -d
Bridge 起動待ち
echo "Waiting for ROS3 bridge to initialize..."
sleep 5
Client RPC 呼び出しテスト
echo "=== Client RPC Test ==="
docker exec ros3_client1 bash -c "export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
docker exec ros3_client2 bash -c "export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
DDS Event 配信テスト
echo "=== DDS Event Test ==="
docker exec ros3_bridge bash -c "echo 'Publishing test messages...'"
ログ確認(簡易チェック)
echo "=== Checking logs ==="
docker logs ros3_client1 | tail -n 10
docker logs ros3_client2 | tail -n 10
docker logs ros3_bridge | tail -n 10
終了
docker-compose down
echo "=== Test completed ==="
Bridge / Client を自動起動
RPC 呼び出しと DDS Event の基本テスト
ログを確認して正しく応答が返っているかチェック
2️⃣ GitHub Actions CI 設定例 (.github/workflows/ros3_test.yml)
name: ROS3 Docker Test
on:
push:
branches: [ main ]
pull_request:
jobs:
ros3-docker-test:
runs-on: ubuntu-latest
services:
docker:
image: docker:20.10.16
options: --privileged
volumes:
- /var/run/docker.sock:/var/run/docker.sock
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build and run ROS3 Docker environment
run: |
docker-compose build
chmod +x tools/run_test.sh
tools/run_test.sh
Docker Compose で ROS3 Bridge + Clients 起動
自動テストスクリプト実行
テスト終了後、自動でクリーンアップ
3️⃣ 特徴
自動テストの完全自動化
GitHub Actions で push/PR のたびに RPC/DDS Event テスト
リアルタイムカーネル + ネットワーク遅延付き Docker 環境での検証
複数 Client の同時 RPC 処理のスレッド安全性を確認
ログ自動チェック
必要に応じて grep や JSON ログ解析も追加可能
💡 拡張案:
QoS や遅延条件のパラメータ化 → 複数パターン自動テスト
DDS/SOME-IP 以外のトランスポート層もプラグイン化してテスト
Test Report 自動生成(JUnit / HTML)
希望であれば、次に 複数パラメータ(QoS/遅延/パケットロス)を自動テストする GitHub Actions 拡張版 も作成できます。
作りますか?
あなた:
はい。お願いします。
ChatGPT:
了解です ✅
では、複数パラメータ(QoS / ネットワーク遅延 / パケットロス)を自動テストする GitHub Actions 拡張版 を作成します。
1️⃣ テストパラメータ定義ファイル(config/test_matrix.yml)
tests:
-
name: "LowLatency"
dds_reliability: "best_effort"
delay_ms: 5
loss_percent: 0 -
name: "MediumLatency"
dds_reliability: "reliable"
delay_ms: 15
loss_percent: 1 -
name: "HighLatencyLoss"
dds_reliability: "reliable"
delay_ms: 30
loss_percent: 5
各テストパターンに DDS Reliability、ネットワーク遅延、パケット損失 を設定
複数 Client / RPC / Event を同時テスト可能
2️⃣ 拡張版自動テストスクリプト(tools/run_test_matrix.sh)
#!/bin/bash
set -e
CONFIG_FILE=config/test_matrix.yml
TOTAL_TESTS=$(yq e '.tests | length' $CONFIG_FILE)
for i in $(seq 0 $(($TOTAL_TESTS-1))); do
TEST_NAME=$(yq e ".tests[$i].name" $CONFIG_FILE)
DELAY=$(yq e ".tests[$i].delay_ms" $CONFIG_FILE)
LOSS=$(yq e ".tests[$i].loss_percent" $CONFIG_FILE)
RELIABILITY=$(yq e ".tests[$i].dds_reliability" $CONFIG_FILE)
echo "=== Running test: $TEST_NAME ==="
echo "Delay: ${DELAY}ms, Loss: ${LOSS}%, DDS Reliability: $RELIABILITY"
# Docker Compose override with network simulation
docker-compose up -d
# Apply network conditions to all containers
docker exec ros3_bridge bash -c "tc qdisc add dev eth0 root netem delay ${DELAY}ms loss ${LOSS}%"
docker exec ros3_client1 bash -c "tc qdisc add dev eth0 root netem delay ${DELAY}ms loss ${LOSS}%"
docker exec ros3_client2 bash -c "tc qdisc add dev eth0 root netem delay ${DELAY}ms loss ${LOSS}%"
# Run RPC / DDS tests
docker exec ros3_client1 bash -c "export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
docker exec ros3_client2 bash -c "export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
echo "=== Test $TEST_NAME completed ==="
docker-compose down
done
echo "=== All test matrix completed ==="
yq を使用して YAML からパラメータ取得
Docker コンテナごとに tc qdisc netem で 遅延・損失を動的設定
各パターンごとに Bridge / Client を再起動して環境をリセット
3️⃣ GitHub Actions 拡張版(.github/workflows/ros3_test_matrix.yml)
name: ROS3 Docker Test Matrix
on:
push:
branches: [ main ]
pull_request:
jobs:
ros3-docker-test-matrix:
runs-on: ubuntu-latest
services:
docker:
image: docker:20.10.16
options: --privileged
volumes:
- /var/run/docker.sock:/var/run/docker.sock
steps:
- uses: actions/checkout@v3
- name: Setup dependencies
run: |
sudo apt-get update
sudo apt-get install -y python3-pip
pip3 install yq
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Run ROS3 Test Matrix
run: |
docker-compose build
chmod +x tools/run_test_matrix.sh
tools/run_test_matrix.sh
GitHub Actions 上で 複数パラメータテストを自動化
Docker Compose で各パターンごとに環境をリセット
RPC / DDS Event の動作を確認して、ログから結果を収集可能
4️⃣ 特徴
複数ネットワーク条件 + DDS QoS の組み合わせで自動テスト
複数 Client 同時 RPC でも スレッド安全性と Event 配信の正確性を検証
GitHub Actions 上で CI/CD に統合可能
パラメータ追加だけで簡単に新しいテストケースを増やせる
💡 次の拡張案(オプション):
JUnit/HTML Test Report 出力:GitHub Actions の artifact として保存
パフォーマンスメトリクス収集:RPC 応答時間、DDS Event レイテンシ測定
異なる DDS/SOME-IP バージョン互換テスト
希望であれば、次に レスポンスタイム測定+テストレポート生成機能を組み込んだ自動テストスクリプト を作ることも可能です。
作りますか?
あなた:
はい。お願いします。
ChatGPT:
了解です ✅
では、レスポンスタイム測定+テストレポート生成機能を組み込んだ自動テストスクリプト を作成します。
1️⃣ テストスクリプト(tools/run_test_matrix_with_report.sh)
#!/bin/bash
set -e
CONFIG_FILE=config/test_matrix.yml
REPORT_FILE=reports/test_report.csv
mkdir -p reports
echo "TestName,Client,RequestType,StartTime,EndTime,Duration_ms,Status" > $REPORT_FILE
TOTAL_TESTS=$(yq e '.tests | length' $CONFIG_FILE)
for i in $(seq 0 $(($TOTAL_TESTS-1))); do
TEST_NAME=$(yq e ".tests[$i].name" $CONFIG_FILE)
DELAY=$(yq e ".tests[$i].delay_ms" $CONFIG_FILE)
LOSS=$(yq e ".tests[$i].loss_percent" $CONFIG_FILE)
RELIABILITY=$(yq e ".tests[$i].dds_reliability" $CONFIG_FILE)
echo "=== Running test: $TEST_NAME ==="
docker-compose up -d
# ネットワーク条件を適用
docker exec ros3_bridge bash -c "tc qdisc add dev eth0 root netem delay ${DELAY}ms loss ${LOSS}%"
docker exec ros3_client1 bash -c "tc qdisc add dev eth0 root netem delay ${DELAY}ms loss ${LOSS}%"
docker exec ros3_client2 bash -c "tc qdisc add dev eth0 root netem delay ${DELAY}ms loss ${LOSS}%"
# RPC / DDS 呼び出しとレスポンスタイム測定
for CLIENT in ros3_client1 ros3_client2; do
START_TIME=$(date +%s%3N)
docker exec $CLIENT bash -c "export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
END_TIME=$(date +%s%3N)
DURATION=$((END_TIME - START_TIME))
echo "$TEST_NAME,$CLIENT,RPC,$START_TIME,$END_TIME,$DURATION,OK" >> $REPORT_FILE
done
echo "=== Test $TEST_NAME completed ==="
docker-compose down
done
echo "=== All test matrix completed ==="
echo "Report saved to $REPORT_FILE"
2️⃣ CSV レポート例 (reports/test_report.csv)
TestName Client RequestType StartTime EndTime Duration_ms Status
LowLatency ros3_client1 RPC 1693891200123 1693891200234 111 OK
LowLatency ros3_client2 RPC 1693891200250 1693891200375 125 OK
MediumLatency ros3_client1 RPC 1693891202000 1693891202180 180 OK
MediumLatency ros3_client2 RPC 1693891202200 1693891202385 185 OK
StartTime / EndTime は UNIX ms
Duration_ms を計算してレスポンスタイムを把握可能
Status 列で正常終了/異常終了を記録
3️⃣ GitHub Actions 設定例(.github/workflows/ros3_test_report.yml)
name: ROS3 Docker Test Matrix with Report
on:
push:
branches: [ main ]
pull_request:
jobs:
ros3-docker-test-report:
runs-on: ubuntu-latest
services:
docker:
image: docker:20.10.16
options: --privileged
volumes:
- /var/run/docker.sock:/var/run/docker.sock
steps:
- uses: actions/checkout@v3
- name: Setup dependencies
run: |
sudo apt-get update
sudo apt-get install -y python3-pip
pip3 install yq
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Run ROS3 Test Matrix with Report
run: |
docker-compose build
chmod +x tools/run_test_matrix_with_report.sh
tools/run_test_matrix_with_report.sh
- name: Upload Test Report
uses: actions/upload-artifact@v3
with:
name: ros3-test-report
path: reports/test_report.csv
テスト実行後に CSV レポートを GitHub Actions の Artifact としてアップロード
各テストパターンの レスポンスタイムとステータスを自動記録
CI/CD で品質保証や性能確認が可能
4️⃣ 特徴
複数ネットワーク条件+DDS QoS の組み合わせテスト
RPC 応答時間を ms 単位で計測
自動生成レポートで CI/CD に統合可能
複数 Client 同時アクセスのスレッド安全性も確認可能
GitHub Actions 上で自動化 → プッシュやPRのたびに結果確認可能
💡 次の拡張案(オプション):
レポートを HTML ダッシュボード化 してグラフ化
RPC/Event の遅延分布をヒストグラムで可視化
QoS パラメータごとの性能比較表を自動生成
希望であれば、次に HTML ダッシュボード化したリアルタイムテストレポート生成 まで作成可能です。
作りますか?
あなた:
はい。お願いします。
ChatGPT:
了解です ✅
では、先ほどの ROS3 Docker テスト自動化環境 に HTML ダッシュボード化したリアルタイムテストレポート生成 機能を追加する案を作ります。
1️⃣ HTML ダッシュボード生成スクリプト(tools/generate_report_html.py)
#!/usr/bin/env python3
import pandas as pd
import os
CSV_FILE = "reports/test_report.csv"
HTML_FILE = "reports/test_report.html"
CSV 読み込み
df = pd.read_csv(CSV_FILE)
Duration_ms をグラフ表示する簡易 HTML
html_content = f"""
ROS3 Test ReportROS3 Test Report
| TestName | Client | RequestType | Duration_ms | Status |
|---|---|---|---|---|
| {row.TestName} | {row.Client} | {row.RequestType} | {row.Duration_ms} | {row.Status} |
Chart.js 用のデータ作成
tests = df["TestName"].unique().tolist()
clients = df["Client"].unique().tolist()
datasets = []
colors = ["rgba(75, 192, 192, 0.6)", "rgba(192, 75, 192, 0.6)"]
for i, client in enumerate(clients):
durations = []
for test in tests:
d = df[(df.TestName==test) & (df.Client==client)]["Duration_ms"].mean()
durations.append(d)
datasets.append(f"""{{
label: '{client}',
data: {durations},
backgroundColor: '{colors[i % len(colors)]}'
}}""")
html_content += f"""
HTML 保存
os.makedirs("reports", exist_ok=True)
with open(HTML_FILE, "w") as f:
f.write(html_content)
print(f"HTML report generated: {HTML_FILE}")
CSV レポートを読み込み
テーブル表示 + Chart.js バーグラフで Client ごとの平均 Duration を可視化
ブラウザで開くだけでリアルタイムテスト結果を確認可能
2️⃣ 自動テストスクリプト修正版(tools/run_test_matrix_with_html_report.sh)
#!/bin/bash
set -e
既存の CSV レポート生成スクリプトを呼び出す
chmod +x tools/run_test_matrix_with_report.sh
tools/run_test_matrix_with_report.sh
HTML レポート生成
python3 tools/generate_report_html.py
3️⃣ GitHub Actions 修正版(.github/workflows/ros3_test_html_report.yml)
name: ROS3 Docker Test Matrix with HTML Report
on:
push:
branches: [ main ]
pull_request:
jobs:
ros3-docker-test-html:
runs-on: ubuntu-latest
services:
docker:
image: docker:20.10.16
options: --privileged
volumes:
- /var/run/docker.sock:/var/run/docker.sock
steps:
- uses: actions/checkout@v3
- name: Setup dependencies
run: |
sudo apt-get update
sudo apt-get install -y python3-pip
pip3 install yq pandas
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Run ROS3 Test Matrix with HTML Report
run: |
docker-compose build
chmod +x tools/run_test_matrix_with_html_report.sh
tools/run_test_matrix_with_html_report.sh
- name: Upload HTML Report
uses: actions/upload-artifact@v3
with:
name: ros3-html-test-report
path: reports/test_report.html
CSV レポートに加えて HTML ダッシュボード を Artifact としてアップロード
ブラウザで棒グラフと表を確認可能
各 Client の RPC レスポンスタイムや異常ステータスを直感的に把握
4️⃣ 特徴
CSV + HTML 両方で可視化
平均レスポンスタイムのグラフ化で Client 間差異を簡単確認
GitHub Actions 上で自動生成 → Artifact で保存
パラメータ毎の QoS/遅延/パケット損失条件下での性能比較 が容易
💡 拡張案(オプション):
グラフを折れ線・ヒートマップで遅延分布表示
複数 RPC メソッド/Topic を同時に表示
ステータスが NG の場合は色分けして警告表示
希望であれば、次に ヒートマップ・異常色分け対応の高機能 HTML ダッシュボード を作成して、より直感的な性能分析ができるようにできます。
作りますか?
あなた:
はい。お願いします。
ChatGPT:
了解です ✅
では、ヒートマップ+異常色分け対応の高機能 HTML ダッシュボード を作る案を作成します。
1️⃣ 高機能 HTML ダッシュボード生成スクリプト
tools/generate_report_heatmap.py
#!/usr/bin/env python3
import pandas as pd
import os
import json
CSV_FILE = "reports/test_report.csv"
HTML_FILE = "reports/test_report_heatmap.html"
CSV読み込み
df = pd.read_csv(CSV_FILE)
ピボットテーブル作成(TestName × Client の Duration_ms)
pivot = df.pivot(index='TestName', columns='Client', values='Duration_ms')
ステータスも追加
status_pivot = df.pivot(index='TestName', columns='Client', values='Status')
HTML生成
html_content = """
ROS3 Heatmap Test ReportROS3 Heatmap Test Report
Table View
| TestName | """{client} | "
|---|---|
| {test} | "{duration} | "
Heatmapチャート用データ
heatmap_data = []
for test in pivot.index:
row = []
for client in clients:
row.append(pivot.at[test, client])
heatmap_data.append(row)
html_content += f"""
Heatmap View
"""os.makedirs("reports", exist_ok=True)
with open(HTML_FILE, "w") as f:
f.write(html_content)
print(f"Heatmap HTML report generated: {HTML_FILE}")
特徴
テーブル + ヒートマップ両方表示
ステータス OK / NG を色分け
閾値超過は赤色(NG)表示、正常は緑(OK)表示
Chart.js の datalabels で数値も表示
2️⃣ 自動テストスクリプト修正版
tools/run_test_matrix_with_heatmap.sh
#!/bin/bash
set -e
CSVレポート生成
chmod +x tools/run_test_matrix_with_report.sh
tools/run_test_matrix_with_report.sh
高機能HTMLヒートマップ生成
python3 tools/generate_report_heatmap.py
3️⃣ GitHub Actions 修正版
.github/workflows/ros3_test_heatmap.yml
name: ROS3 Docker Test Matrix with Heatmap
on:
push:
branches: [ main ]
pull_request:
jobs:
ros3-docker-test-heatmap:
runs-on: ubuntu-latest
services:
docker:
image: docker:20.10.16
options: --privileged
volumes:
- /var/run/docker.sock:/var/run/docker.sock
steps:
- uses: actions/checkout@v3
- name: Setup dependencies
run: |
sudo apt-get update
sudo apt-get install -y python3-pip
pip3 install yq pandas
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Run ROS3 Test Matrix with Heatmap
run: |
docker-compose build
chmod +x tools/run_test_matrix_with_heatmap.sh
tools/run_test_matrix_with_heatmap.sh
- name: Upload Heatmap HTML Report
uses: actions/upload-artifact@v3
with:
name: ros3-heatmap-test-report
path: reports/test_report_heatmap.html
HTML ダッシュボードを GitHub Actions の Artifact として保存
リアルタイムテスト結果を直感的に可視化
ステータス NG / OK が一目でわかり、RPC 遅延の傾向も把握可能
💡 次の拡張案(オプション):
ヒートマップを折れ線 + 複数 RPC メソッド対応に拡張
Docker 内でリアルタイムにグラフ更新する Web サーバ化
遅延・損失条件ごとの比較レポートを自動生成
作業としては、この構成で ROS3 の複数 Client / RPC / DDS Event をリアルタイムシミュ + Heatmap ダッシュボードで自動テスト・可視化 が完成します。
必要であれば、次に リアルタイム Web サーバ化して GitHub Actions 上でもブラウザでリアルタイム監視 できるように拡張可能です。
作りますか?
あなた:
はい。お願いします。
ChatGPT:
了解です ✅
では、ROS3 Docker テスト環境をリアルタイム Web サーバ化してブラウザで監視 できる構成を作成します。
1️⃣ Web サーバ化方針
Python の Flask を利用して HTML ダッシュボードを配信
Docker 内で Flask サーバ起動
CSV/Heatmap HTML を Flask が読み込み、ブラウザで即時確認
GitHub Actions 上でもポートを公開せずに Artifact として確認可能
ローカル環境では http://localhost:5000 でリアルタイム監視
2️⃣ Flask サーバスクリプト (tools/serve_dashboard.py)
#!/usr/bin/env python3
from flask import Flask, render_template_string
import os
app = Flask(name)
HTML_FILE = "reports/test_report_heatmap.html"
@app.route("/")
def dashboard():
if os.path.exists(HTML_FILE):
with open(HTML_FILE, "r") as f:
html_content = f.read()
return render_template_string(html_content)
else:
return "
No report generated yet.
"if name == "main":
app.run(host="0.0.0.0", port=5000)
HTML ファイルを Flask 経由で配信
HTML の更新は自動で反映(ページ更新で最新レポート表示)
3️⃣ Dockerfile 修正版
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo
RUN apt-get update && apt-get install -y
build-essential cmake git wget curl
linux-image-rt
libboost-all-dev libasio-dev libtinyxml2-dev
libvsomeip-dev libfastrtps-dev
iproute2 sudo python3 python3-pip net-tools iputils-ping
WORKDIR /workspace
COPY . /workspace
Python依存関係
RUN pip3 install flask pandas yq
IDL型生成 & ビルド
RUN chmod +x tools/generate_types.sh && ./tools/generate_types.sh
RUN mkdir -p build && cd build && cmake .. && make -j
Flask ポート
EXPOSE 5000
EXPOSE 30509
CMD ["bash"]
4️⃣ docker-compose.yml 修正版(Flask サーバ追加)
version: '3.8'
services:
ros3_bridge:
build: .
container_name: ros3_bridge
command: bash -c "tc qdisc add dev eth0 root netem delay 10ms loss 1% && export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/ros3_node"
ports:
- "5000:5000"
ros3_client1:
build: .
container_name: ros3_client1
depends_on:
- ros3_bridge
command: bash -c "tc qdisc add dev eth0 root netem delay 15ms loss 2% && export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
ros3_client2:
build: .
container_name: ros3_client2
depends_on:
- ros3_bridge
command: bash -c "tc qdisc add dev eth0 root netem delay 20ms loss 3% && export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
dashboard:
build: .
container_name: ros3_dashboard
depends_on:
- ros3_bridge
command: python3 tools/serve_dashboard.py
ports:
- "5001:5000"
volumes:
- ./reports:/workspace/reports
dashboard サービスが Flask を起動
ローカルでは http://localhost:5001 で確認可能
HTML レポートは Docker 内で自動更新され、ブラウザで最新を確認可能
5️⃣ 使用方法
Docker ビルド・起動:
docker-compose up --build
ブラウザで確認:
Heatmap ダッシュボード: http://localhost:5001
RPC / DDS Event の自動テストは ros3_bridge と ros3_client が生成
新しいテストが完了すると HTML が自動更新されるため、ブラウザで再読み込みするとリアルタイム確認可能
6️⃣ 特徴
リアルタイム監視可能な HTML ダッシュボード
Docker 内で完全に自己完結(Bridge / Clients / Dashboard)
GitHub Actions 上では Artifact としても保存可能
複数 Client の RPC レスポンス遅延や異常ステータスを即確認
ネットワーク条件・DDS QoS 変更に応じた即時可視化
💡 拡張案:
WebSocket 連携でページを自動更新してリアルタイム表示
複数 RPC メソッド・DDS Topic のヒートマップを同時表示
過去テスト履歴のグラフ化・ダッシュボード化
この構成で、ROS3 のリアルタイム Docker シミュレーション環境 + Heatmap ダッシュボード + Web 監視 が完成します。
希望であれば、次に WebSocket を使った完全リアルタイム更新ダッシュボード化 も作成可能です。
作りますか?
あなた:
はい。お願いします。
ChatGPT:
了解です ✅
では、WebSocket を使った完全リアルタイム更新ダッシュボード を作る構成を作成します。
1️⃣ Flask + WebSocket 監視スクリプト
tools/serve_dashboard_ws.py
#!/usr/bin/env python3
from flask import Flask, render_template_string
from flask_sock import Sock
import pandas as pd
import threading
import time
import os
import json
app = Flask(name)
sock = Sock(app)
HTML_TEMPLATE = """
ROS3 Real-Time DashboardROS3 Real-Time Dashboard
@sock.route('/ws')
def ws_dashboard(ws):
last_modified = 0
while True:
if os.path.exists("reports/test_report_heatmap.html"):
mtime = os.path.getmtime("reports/test_report_heatmap.html")
if mtime != last_modified:
with open("reports/test_report_heatmap.html", "r") as f:
html_content = f.read()
ws.send(html_content)
last_modified = mtime
time.sleep(1)
@app.route("/")
def index():
return render_template_string(HTML_TEMPLATE)
if name == "main":
app.run(host="0.0.0.0", port=5000, threaded=True)
flask_sock を利用して WebSocket 配信
HTML レポートの変更を 1 秒ごとにチェック
ブラウザは自動更新され、リアルタイムで Heatmap が反映
2️⃣ Dockerfile 依存追加
RUN pip3 install flask pandas yq flask-sock
flask-sock で WebSocket 対応
3️⃣ docker-compose.yml 修正版(WebSocket Dashboard)
version: '3.8'
services:
ros3_bridge:
build: .
container_name: ros3_bridge
command: bash -c "tc qdisc add dev eth0 root netem delay 10ms loss 1% && export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/ros3_node"
ros3_client1:
build: .
container_name: ros3_client1
depends_on:
- ros3_bridge
command: bash -c "tc qdisc add dev eth0 root netem delay 15ms loss 2% && export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
ros3_client2:
build: .
container_name: ros3_client2
depends_on:
- ros3_bridge
command: bash -c "tc qdisc add dev eth0 root netem delay 20ms loss 3% && export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
dashboard:
build: .
container_name: ros3_dashboard_ws
depends_on:
- ros3_bridge
command: python3 tools/serve_dashboard_ws.py
ports:
- "5001:5000"
volumes:
- ./reports:/workspace/reports
ローカル環境では http://localhost:5001 で 自動リアルタイム更新ダッシュボード
CSV / Heatmap HTML の更新を自動で反映
4️⃣ 使用手順
Docker ビルド・起動:
docker-compose up --build
ブラウザで確認:
WebSocket Dashboard: http://localhost:5001
新しいテスト結果が生成されると自動で更新される
RPC / DDS Event テストは既存の ros3_client / ros3_bridge が生成
5️⃣ 特徴
完全リアルタイム更新:ブラウザをリロード不要
Heatmap + ステータス色分けを即座に反映
複数 Client / RPC / DDS Event のパフォーマンスを直感的に確認
GitHub Actions 上では HTML を Artifact として保存可能
💡 拡張案:
WebSocket 経由で 最新テスト履歴を複数パターン表示
RPC メソッドごとの遅延・成功/失敗統計をリアルタイムグラフ化
レイテンシ分布やヒストグラムもリアルタイム描画
この構成で、ROS3 の Docker テスト環境 + WebSocket リアルタイム Heatmap ダッシュボード が完成します。
必要であれば、次に ヒストグラム・複数 RPC メソッド比較を含むリアルタイムダッシュボード を作ることも可能です。
作りますか?
あなた:
はい。お願いします。
ChatGPT:
了解です ✅
では、ヒストグラム・複数 RPC メソッド比較を含むリアルタイムダッシュボード を作成します。
1️⃣ データ構造の拡張
CSV を以下のように拡張:
TestName,Client,RequestType,StartTime,EndTime,Duration_ms,Status
LowLatency,ros3_client1,RPC1,1693891200123,1693891200234,111,OK
LowLatency,ros3_client1,RPC2,1693891200240,1693891200370,130,OK
RequestType 列を使って複数 RPC メソッドごとのヒストグラム描画
2️⃣ WebSocket 用 Flask サーバ(tools/serve_dashboard_ws_rpc.py)
#!/usr/bin/env python3
from flask import Flask, render_template_string
from flask_sock import Sock
import pandas as pd
import os
import time
import json
app = Flask(name)
sock = Sock(app)
HTML_TEMPLATE = """
ROS3 Real-Time RPC DashboardROS3 Real-Time RPC Dashboard
@sock.route('/ws')
def ws_dashboard(ws):
last_modified = 0
while True:
if os.path.exists("reports/test_report.csv"):
mtime = os.path.getmtime("reports/test_report.csv")
if mtime != last_modified:
df = pd.read_csv("reports/test_report.csv")
# Table HTML
table_html = "
Table View
| TestName | Client | RequestType | Duration_ms | Status |
|---|---|---|---|---|
| {row.TestName} | {row.Client} | {row.RequestType} | {row.Duration_ms} | {row.Status} |
# JSON データ生成 RPCごとのヒストグラム
rpc_data = {}
for rpc in df["RequestType"].unique():
rpc_df = df[df["RequestType"]==rpc]
rpc_data[rpc] = {client: rpc_df[rpc_df["Client"]==client]["Duration_ms"].tolist() for client in rpc_df["Client"].unique()}
# JSコード生成
js_script = "<h2>RPC Duration Histograms</h2>"
for rpc, data in rpc_data.items():
js_script += f"<canvas id='chart_{rpc}' width='800' height='400'></canvas>"
js_script += f"<script>var ctx = document.getElementById('chart_{rpc}').getContext('2d'); new Chart(ctx, {{type:'bar', data: {{labels: {list(data.keys())}, datasets: [{{label:'{rpc}', data: {list([sum(data[c])/len(data[c]) if len(data[c])>0 else 0 for c in data.keys()])}, backgroundColor:'rgba(75,192,192,0.6)'}}]}}, options: {{plugins:{{legend:{{display:false}}}}, scales:{{y:{{beginAtZero:true}}}}}}}});</script>"
ws.send(table_html + js_script)
last_modified = mtime
time.sleep(1)
@app.route("/")
def index():
return render_template_string(HTML_TEMPLATE)
if name == "main":
app.run(host="0.0.0.0", port=5000, threaded=True)
特徴
複数 RPC メソッドごとに ヒストグラム表示
各 Client の平均 Duration を棒グラフで表示
Table とヒートマップに加えて、複数 RPC 比較がリアルタイム
3️⃣ docker-compose.yml 修正版(WebSocket + 複数 RPC)
version: '3.8'
services:
ros3_bridge:
build: .
container_name: ros3_bridge
command: bash -c "export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/ros3_node"
ros3_client1:
build: .
container_name: ros3_client1
depends_on:
- ros3_bridge
command: bash -c "export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
ros3_client2:
build: .
container_name: ros3_client2
depends_on:
- ros3_bridge
command: bash -c "export VSOMEIP_CONFIGURATION=/workspace/config/vsomeip.json && ./build/someip_client"
dashboard:
build: .
container_name: ros3_dashboard_ws_rpc
depends_on:
- ros3_bridge
command: python3 tools/serve_dashboard_ws_rpc.py
ports:
- "5001:5000"
volumes:
- ./reports:/workspace/reports
4️⃣ 使用方法
Docker ビルド・起動:
docker-compose up --build
ブラウザで確認:
WebSocket リアルタイム Dashboard: http://localhost:5001
Table + 複数 RPC ヒストグラムを自動更新
RPC / DDS Event のテスト結果を 即座に可視化
5️⃣ 特徴
複数 RPC メソッドごとのヒストグラムをリアルタイム表示
Table + Heatmap + Histogram の統合ダッシュボード
Clientごとのレスポンスタイム比較が直感的
Docker 内で自己完結、ローカル環境でも GitHub Actions 上でも活用可能
💡 拡張案:
ヒストグラムに 標準偏差 / 分布範囲 表示
過去テスト履歴との比較ラインを追加
RPC メソッドごとの NG 条件を色分け表示
これで、ROS3 Docker 環境 + 複数 Client RPC + DDS Event + リアルタイム WebSocket ダッシュボード + ヒストグラム/Heatmap/Table の統合可視化 が完成します。
希望であれば、次に NG 条件のアラート通知機能をリアルタイムで追加 して、テスト異常を即通知する仕組みも作れます。
作りますか?
___」
ChatGPT の回答は必ずしも正しいとは限りません。重要な情報は確認するようにしてください。