1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ROS2でプロセス間通信をもっと軽量にしたい!DDS・Zenoh・共有メモリ・Compositionを比較

Posted at

ROS2を使っていると、「ノード間の通信、もうちょっと軽くならないかな……」と思う場面、多くないですか?
今回は、ROS2の通信を高速・軽量化するために試した Zenoh, 共有メモリ通信, Composition の3つの手法をざっくり紹介しつつ、実際にやってみた結果を共有します。

検証環境

項目 内容
ROS2 バージョン jazzy
OS Ubuntu 20.04 上の Ubuntu 22.04 Docker コンテナ
rmw_zenoh_cpp 0.2.3
rmw_dds_common 3.1.0
rmw_cyclonedds_cpp 2.2.2
rmw_fastrtps_shared_cpp 8.4.1

Zenoh:軽量・分散・リアルタイムな通信プロトコル

Zenoh は、Pub/Sub・Query(リクエスト/リプライ)・データ保存までを1つでこなす通信ミドルウェア。IoTやロボットなどのリアルタイム・分散通信にピッタリの設計になっています。

特徴

特徴 説明
Pub/Sub + Query対応 必要なデータだけオンデマンド取得も可能
超軽量・低レイテンシ エッジ環境でもサクサク動く
ピアツーピア通信 ブローカー不要でスケーラブル
ROS2対応 Zenoh-Bridgeやrmw_zenohで統合可能

導入方法(2パターン)

① Zenoh Bridge for DDS

既存のROS2ノード(DDS)を変更せず、Bridge経由でZenoh通信が可能。段階的な導入に向いています。

cargo install zenohd  # Rustが必要
cargo install zenoh-plugin-dds # binが無いと言われるので、buildが必要
sudo apt install build-essential clang

git clone https://github.com/eclipse-zenoh/zenoh.git
git clone https://github.com/eclipse-zenoh/zenoh-plugin-dds.git
cd zenoh
cargo build --release
cd ../zenoh-plugin-dds
cargo build --release

ただし、docker container環境では立ち上げできなかったので、深追いしてない。

② rmw_zenoh

DDSを完全にZenohに置き換える方法。軽量&高速が必要なローカル環境、またはマルチキャスト不可なネットワークで有効。

以下apt installだと、zenoh-c のbuildが必要になり、buildしても動かなかったので、sourceからbuildした。

sudo apt update
sudo apt install ros-jazzy-rmw-zenoh-cpp
$ ros2 run demo_nodes_cpp talker
/opt/ros/jazzy/lib/demo_nodes_cpp/talker: symbol lookup error: /opt/ros/jazzy/lib/librmw_zenoh_cpp.so: undefined symbol: zc_reply_keyexpr_default
[ros2run]: Process exited with failure 127

sourceからbuild

mkdir ~/ws_rmw_zenoh/src -p && cd ~/ws_rmw_zenoh/src
git clone https://github.com/ros2/rmw_zenoh.git -b jazzy
cd ~/ws_rmw_zenoh
rosdep install --from-paths src --ignore-src --rosdistro jazzy -y
source /opt/ros/jazzy/setup.bash
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release

source ~/ws_rmw_zenoh/install/setup.bash

動かし方

zenoh router起動

# terminal 1
ros2 run rmw_zenoh_cpp rmw_zenohd
# terminal 2
export RMW_IMPLEMENTATION=rmw_zenoh_cpp
ros2 run demo_nodes_cpp talker
# terminal 3
export RMW_IMPLEMENTATION=rmw_zenoh_cpp
ros2 run demo_nodes_cpp listener

共有メモリ通信:ゼロコピーの爆速IPC

共有メモリを使うと、複数のプロセスが同じメモリ領域を参照できるため、シリアライズ・コピー不要の超高速通信が可能になります。

実装例(SysV API)

ROS2ではないが、Linuxの実装を試してみると、以下の感じ。

DDSごとの対応状況

DDS実装 共有メモリ対応 備考
Fast DDS ✅ 独自SHM対応(XML設定)
Cyclone DDS ✅ Iceoryx連携(RouDi必要)
RTI Connext 一部対応(商用、Iceoryx非連携)

fastDDSでの設定

<?xml version="1.0" encoding="UTF-8" ?>
<dds>
  <profiles>
    <!-- SHM トランスポート定義 -->
    <transport_descriptors>
      <transport_descriptor>
        <transport_id>shm_transport</transport_id>
        <type>SHM</type>
        <segment_size>2536870912</segment_size> 
      </transport_descriptor>
    </transport_descriptors>
    <!-- Participant プロファイル -->
    <participant profile_name="shm_profile" is_default_profile="true">
      <rtps>
        <userTransports>
          <transport_id>shm_transport</transport_id>
        </userTransports>
      </rtps>
    </participant>
  </profiles>
</dds>

export FASTRTPS_DEFAULT_PROFILES_FILE=/path/fastdds_shm_profile.xml

cycloneDDSでの設定 / 立ち上げ

<?xml version="1.0" encoding="UTF-8" ?>
<CycloneDDS xmlns="https://cdds.io/config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://cdds.io/config https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/iceoryx/etc/cyclonedds.xsd">
    <Domain id="any">
        <SharedMemory>
            <Enable>true</Enable>
            <LogLevel>info</LogLevel>
        </SharedMemory>
    </Domain>
</CycloneDDS>
export CYCLONEDDS_URI=/path/cyclonedds.xml
  • iceoryx roudiの事前の立ち上げが必要
iox-roudi
  • talker
export CYCLONEDDS_URI=file://$PWD/cyclonedds.xml
. ~/ros2_ws/install/local_setup.bash
RMW_IMPLEMENTATION=rmw_cyclonedds_cpp ros2 run demo_nodes_cpp talker
  • listener
export CYCLONEDDS_URI=file://$PWD/cyclonedds.xml
. ~/ros2_ws/install/local_setup.bash
RMW_IMPLEMENTATION=rmw_cyclonedds_cpp ros2 run demo_nodes_cpp listener

おそらくcyclone DDSでの共有メモリは、さらに設定をしないと、大容量通信で使えず今回検証では使用していない。追って要調整。

Composition:ノードを1プロセスにまとめて効率化!

Compositionを使えば、複数のノードを同じプロセス内で動かせるため、起動時間短縮・通信最適化・メモリ削減が期待できます。

  • 起動高速化(プロセス1つ)
  • DDSのloan機能でゼロコピー通信も可能
  • シンプルなノード統合が可能

ベンチマークしてみた!

環境

  • CPU
    • 11th Gen Intel(R) Core(TM) i7-1195G7 @ 2.90GHz
  • mem
    • 32GB

検証データ

100MBデータをPub/Sub (1Hz)

RMW実装 CPU使用率 備考
Fast DDS pub 4〜10% / sub 3〜6%
CycloneDDS pub 10%〜28% / sub 10〜20%
Zenoh pub 10〜20% / sub 7〜12% 200MB超でSubscribeできなくなった
Fast DDS + SHM pub 1〜6% / sub 3〜6%
Composition pub/sub 3〜5%

1GBデータをPub/Sub(1Hz)

RMW実装 CPU メモリ
Fast DDS pub 40〜50% / sub 80% pub 35% / sub 35%
CycloneDDS 通信不可 -
Zenoh 通信不可 -
Fast DDS + SHM pub 10〜30% / sub 50% pub 11% / sub 17%
Composition pub/sub 30〜40% pub/sub 14%

100kHzで「Hello world」Pub/Subしたとき

RMW実装 CPU使用率
Fast DDS pub/sub 60%
CycloneDDS pub/sub 50%
Zenoh pub 130% / sub 100%(落ちた)
Fast DDS + SHM pub/sub 60%

Rviz2での表示可否

実装 Rviz表示可?
Fast DDS ✅ OK
CycloneDDS ✅ OK
Zenoh ✅ OK
Fast DDS + SHM ✅ OK

まとめ

結論としては、

Composition > Fast DDS + SHM > Fast DDS ≒ CycloneDDS >> Zenoh
  • Zenoh は現時点では大容量/高速通信に弱く、発展途上な印象でした。
  • 共有メモリはシンプル&高速だけど、やはり普通にcompositionにしたほうが早いので、使いどころが難しい
  • 軽量・高速通信が求められるロボットやIoT開発では、DDSだけでなくZenohや共有メモリの活用も重要です。
    この記事が少しでもROS2のチューニングの参考になれば嬉しいです!
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?