In Silico

Physical AI

Isaac ROSはなぜNITROSを外し、rosidl::Bufferへ移ったか

2026/10/8

  • rosidl::Buffer
  • ROS 2
  • Physical AI
  • GPU
  • Isaac ROS
  • NITROS
  • バッファバックエンド
  • CUDA
  • Intrinsic Core
  • 型適応
  • rmw_fastrtps_cpp
  • rmw_zenoh_cpp
  • Bazel
  • ノード
  • トピック
  • 記述子
  • RMW
  • ゼロコピー
  • シリアライズ
  • 変換パッケージ
  • フォールバック
  • 借用メッセージ
  • 共有メモリ
  • ROS 2 Lyrical
  • micro-ROS
  • Zephyr
  • Apache 2.0
  • k3s
  • REP 2007
  • Universal Robots
目次
背景・問い・要点
背景

ロボットのソフトウェアは、ノードと呼ぶ独立したプログラムが、トピックと呼ぶ名前付きの通信路でメッセージを交換する形で組む。カメラ画像、点群、テンソルを GPU のメモリ上で作るロボットの開発者は、これをメッセージとして公開するために CPU のメモリへ複製する。受け取るノードが GPU で処理するなら、さらに GPU のメモリへ複製し直す。通信に載せるときは、メッセージをバイト列に変換するシリアライズも走る。

この複製を避けるため、開発者は GPU のメモリをそのまま渡せる、ベンダー独自の通信用 API を採用してきた。ただし、その API の外にあるパッケージは、GPU 上のデータを複製なしでは受け取れない。標準のメッセージ型を保ったまま GPU 上のデータを渡す仕組みが、フレームワーク本体になかったからである。

本稿は、NVIDIA の Isaac ROS が提供してきた NITROS と、ROS 2 本体が取り込んだ rosidl::Buffer を例に取る。もう一つの例として、同じ週に公開された Intrinsic の産業用ロボット基盤 Intrinsic Core を取る。これらを選んだのは、作り手が理由を一次資料に書いており、移る前と後の比較ができるからだ。データの複製を減らす仕組みには、ほかに、同じプロセス内で所有権を渡す intra-process 通信、RMW(ノード間でメッセージを実際に運ぶ、差し替え可能な層)にメッセージのメモリを管理させる借用メッセージ、型適応があり、本稿はそれらとの違いも扱う1。

問い

GPU 上のデータをノード間で渡す仕組みは、なぜ NVIDIA 独自の層から ROS 本体の層へ移り、その移行は何を代価にして、代価はどこまで続くのか。

要点

GPU 上のデータをノード間で渡す仕組みは、ベンダー独自の層から ROS 本体の共通の層へ移っており、移行の代価として NITROS を直接使う独自コードにはソースレベルの移行が要り、対応範囲の制約がいつ解消するかは作り手も示していない。 従来の仕組みは、GPU 上のデータを標準のメッセージ型のままプロセス間で渡せなかった。ROS 2 本体がメッセージ定義を変えずに配列欄の保存先を差し替える仕組みを持ったので、NVIDIA は独自層の主なパッケージを外し、その仕組みの上に組み直した。この移行で、独自の API を使うパッケージだけが GPU 上のデータを複製なしで受け取れる状態は解消に向かう。

モデル・例示

毎秒 30 フレームの画像を渡すと、画素のぶん通信に載る量は毎秒約 187 MB から約 123 KB 以下になる

※ この節の数値は説明のための仮定で、測定値ではありません。

1920×1080 の RGB 画像を、カメラ側のノードが GPU のメモリ上で作り、別のプロセスの推論ノードへ毎秒 30 フレームで渡す。1 フレームは 1920 × 1080 × 3 = 6,220,800 バイト、約 6.2 MB である。

GPU 上のデータを CPU のメモリ経由で渡す従来の経路では、公開側で GPU から CPU への複製が 1 回、受け取り側で CPU から GPU への複製が 1 回起きる。1 フレームで 12,441,600 バイト、毎秒 30 フレームで 373,248,000 バイト(約 373 MB)が複製される。通信に載る画素のバイト列は 1 フレーム 6,220,800 バイトで、毎秒 30 フレームでは 186,624,000 バイト(約 187 MB)になる。

配列のバイト列を GPU のメモリに置いたまま渡せる仕組み(バッファバックエンド)が使える経路では、画素のバイト列は GPU のメモリに置かれたまま、通信には記述子と呼ぶ小さなメッセージが載る。記述子の上限は 4096 バイトなので、画素の代わりに通信に載る量は毎秒 30 フレームで 122,880 バイト(約 123 KB)以下になる。ヘッダや幅などの欄は、これとは別に載る。CPU を通る画素の複製は、この経路では 0 回である。1 フレームあたりでは、画素のぶん通信に載る量が 6,220,800 バイトから 4096 バイト以下へ、約 1500 分の 1 以下になる。バックエンドが相手を扱えず CPU でのシリアライズに戻ると、量は従来の経路と同じになる。

NITROS は、標準のメッセージ型のまま GPU のデータを渡す仕組みが ROS になかった間の、NVIDIA 独自の層だった

Isaac ROS は、NVIDIA が公開する GPU で加速した ROS 2 パッケージ群である。基盤の isaac_ros_common は 2021年10月に作られて 320 スター、NITROS を収めた isaac_ros_nitros は 2022年7月に作られて 220 スターを持つ(2026-10-06 時点)2。NVIDIA は Isaac ROS を ROS の約 130 万人の利用者に向けて提供すると書き、Universal Robots は Isaac ROS を自社の SDK に組み込んだ3。NVIDIA は、NITROS が、ROS 2 が加速器のメモリのための共通の容器とバックエンドの仕組みを持つ前から、NVIDIA 独自の型適応、型の交渉、GPU を意識した通信を提供してきたと書く4。型適応(type adaptation)は、アプリケーションの中で ROS のメッセージ型とは別の型を使えるようにする仕組みで、ROS の文書はその仕組みに REP 2007 と REP 2009 を挙げる1。Isaac ROS 4.6 の文書では、REP 2007 が型適応、REP 2009 がノード同士で扱える型を伝え合う型の交渉で、NITROS はこの二つを使って GPU 向けの表現でノード同士をつないだ5。

ROS 2 の文書は、既存の二つの仕組みがこの問題に効かない理由を書く。intra-process 通信は、同じプロセス内の公開側と購読側の間で unique_ptr の所有権を渡して複製を省く。借用メッセージは、RMW にメッセージのメモリを管理させ、プロセス間の共有メモリ通信を可能にする。どちらも、データの出どころが GPU で描画した画像のような CPU 以外のメモリ領域である場合には助けにならない。そのデータを、生成される C++ のメッセージ型を満たすためだけに std::vector へ複製すると、加速器の上で作る意味が失われる1。型適応も、単一のプロセスの中でしか働かない1。

ROS 2 本体には、GPU 上のデータを標準のメッセージ型のままプロセス間で渡す仕組みがなかった。NITROS は、NVIDIA の型と API でこの複製を減らした。NITROS の型はそれぞれ ROS のメッセージ型と一対一に対応し、NITROS を使わないノードとも、対応するメッセージ型でデータをやり取りできた。ただし、ゼロコピーの利点を得るには、NITROS のノードをすべて同じプロセスで動かす必要があった5。

rosidl::Buffer は、メッセージ定義を変えず、配列欄の保存先だけを GPU に差し替える

ROS 2 Lyrical は、uint8[] のような可変長のプリミティブ配列欄を、C++ で std::vector ではなく rosidl::Buffer として生成する6。目的は、.msg ファイルを変えず、既存のコードを動かしたまま、配列のバイト列を CPU 以外のメモリに置けるようにすることである。rosidl::Buffer は std::vector の置き換えで、内部の実装を差し替えられる pimpl(実装を別のオブジェクトに委ねる作り)を持つ。新しく作ったバッファの既定は CPU の実装で、バックエンドが自分の実装へ入れ替える1。バックエンドを指定しなければ、従来のコードは変更なしで動く7。

次の課題は、GPU のメモリそのものを通信に載せられない点にある。バックエンドのプラグインは、バッファを記述子へ変換する。記述子は、受け取り側がデータの位置を特定する、または再構成するための情報を持つ通常の .msg で、上限は 4096 バイトである。上限があるので、RMW はシリアライズ用のバッファの大きさを事前に決められる。非 CPU のバックエンドでは、記述子はたいてい小さな参照で、受け取り側がそれで元のデータに接続し直す。公開側の RMW は、相手ごとに記述子を作り、生のバイト列の代わりにそれをシリアライズする。購読側の RMW は、記述子からバッファを再構成する1。

最後の課題は、相手がバックエンドに対応していない場合である。探索の仕組み(discovery hooks)は、一致した公開側と購読側の組がバックエンドの通信に適合するかを、組ごとに判定する。扱えない相手には、バックエンドが nullptr を返し、RMW が通常の CPU でのシリアライズに切り替える(フォールバック)1。購読側は acceptable_buffer_backends で受け入れるバックエンドを宣言し、CPU は常に受け入れる7。

ROS の文書は、型適応と NITROS のような仕組みを、ROS のメッセージ型の上でアプリケーションの型を扱う、別の問題を解くものとして扱う1。NVIDIA も、NITROS の型の交渉に当たるのはミドルウェアでのバックエンドの選択とフォールバックで、直接対応する API ではない別の抽象だと書く4。実際上の違いの一つは、見える範囲にある。バッファバックエンドは RMW の公開と購読の経路から見えるので、プロセスをまたぐ通信を提供できる。型適応は単一のプロセスの中に限られる。両者は依存せず、同じアプリケーションで併用できる1。

NVIDIA は共通の層への集約を理由に NITROS の主なパッケージを外し、Intrinsic も ROS 2 互換の形で中核を公開した

NVIDIA は理由を四つ書く。Isaac ROS の加速ノードを ROS 2 全体に揃えること。Isaac ROS 固有の通信 API を不要にすること。Isaac ROS の外の変換ライブラリやアプリケーションが、同じ加速メモリ上のメッセージを使えること。今後の相互運用性と性能の作業を ROS 2 の共通基盤に集めること。以上が、NVIDIA が移行の文書に書く理由である4。Isaac ROS 5.0 は 2026年9月21日に出て、ROS 2 Lyrical を対象に NITROS を rosidl::Buffer と CUDA バックエンドの上で組み直し、NITROS の主なパッケージを削除した。NITROS Bridge(isaac_ros_nitros_bridge_ros2)だけは非推奨として残し、後のリリースで外す8。移行の文書は 2026年10月6日の取得時点でも、NITROS を非推奨とし将来のリリースで外すと書いており、リリースノートと書き方が揃っていない4。NVIDIA は、Open Source Robotics Alliance(OSRA)と協力して、標準のデータ処理インターフェースを ROS Lyrical に寄与したと書く3。独自層の主なパッケージを外した NVIDIA は、共通層の実装にも寄与している。

もう一つの当事者として、Intrinsic は 2026年9月22日に、ROSCon 2026 で Intrinsic Core を発表した。リポジトリは 2026年9月に作られ、542 スターと 65 フォークを持つ(2026-10-06 時点)9。Intrinsic が日常の製造現場で使う機能と同じものを、Apache 2.0 のオープンソースにしたもので、ROS 互換と明記する10。リポジトリは前提に ROS 2 Lyrical を挙げ、README は ROS 2 との相互運用を設計の目標に挙げる9。Physical AI 向けの基盤の中核を、ROS 2 の上で動く形で出した点は、NVIDIA の動きと向きが同じである。

ただし、GPU 上のデータの受け渡しという層で二者を比べる材料は、資料にない。リポジトリは C++ と Bazel で書かれ、実行環境は k3s のコンテナとして用意される9。共有メモリ通信の別リポジトリ icon-shared-memory は、実時間制御の枠組み ICON の制御ループとハードウェア抽象層のためのものである11。Intrinsic の発表と README は、GPU 上のデータの受け渡しに rosidl::Buffer を使うかどうかを書いていない。この層で独自から共通へ移ったと資料が示すのは、NVIDIA の一件だけである。

移行の代価は、書き換えはノード単位の互換の外で要り、対応範囲は「現時点」、C 実行時への依存は直し方が議論されている

代価の一つ目は、NITROS の API を直接呼ぶコードの書き換えである。NVIDIA は、サポートされる Isaac ROS のノードの範囲なら、基盤が変わっても計算グラフを設計し直す必要はないと書く。互換性はノード単位で保たれ、NITROS の API や型を直接使う独自コードには、ソースレベルの移行が要る。さらに、NITROS の型と新しい API は一対一に対応せず、名前を機械的に置き換えてはならない4。資料は、書き換えが一度で終わるかを書いていない。NITROS Bridge は非推奨のまま残って後のリリースで外され8、テンソルの経路はメッセージ型の名前に Experimental を持ち7、変換パッケージは今後増える4。NVIDIA は、NITROS の API から移行するための CLI migrate-node-to-rosidl-buffer を、早期公開として Isaac ROS 5.0 に載せた8。多くの用途には、画像、テンソル、点群を扱う変換パッケージを使えばよく、CUDA バックエンドを直接使うのは、デバイスポインタや CUDA ストリームを自分で制御する場合に限る4。NVIDIA は、不要な CPU のコピーを避ける性能目標は維持すると書く4。移行前後を比べた測定値は資料にないが、5.0 のリリースノートは、isaac_ros_dnn_image_encoder の画像の前処理が 4.6 より低いスループットと高い遅延になりうることを既知の制約に挙げており、原因は書いていない8。本稿も何も実行していない。

二つ目は、対応範囲である。バッファバックエンドは、トピックの公開と購読にだけ使え、サービスとアクションは従来のシリアライズを使い続ける。RMW の対応は、ROS 2 Lyrical のリリースノートでは rmw_fastrtps_cpp と rmw_zenoh_cpp である6。ただし使い方の文書は、最初に対応した RMW が rmw_fastrtps_cpp で、他の RMW で非 CPU を要求した購読は CPU のデータを受け取ると書く7。CUDA バックエンドは、CUDA VMM の割り当てを安全に共有できる相手だけを受け入れ、それ以外は CPU でのシリアライズに戻る1。文書はこれらに「currently」「first」「current」と付けており、作り手は現状の記述として書いている。資料は拡張の時期も内容も示していないので、本稿はこの制約を一時的とも永続とも判定しない。

三つ目は、組み込み向けの C 実行時への依存である。rosidl の issue #1002 は、Rolling で 2026年4月6日に入った変更以降、C 言語用の rosidl_runtime_c が C++ の rosidl_buffer に必須で依存するようになったと報告する。この依存で、例外を無効にするコンパイル(-fno-exceptions)が失敗する。micro-ROS の Rolling CI は失敗し、micro_ros_espidf_component は rosidl を古いコミットに固定した。Zephyr は既定で -fno-exceptions を使うため、同じ箇所でコンパイルが止まる12。メンテナーは 2026年9月19日(UTC)に、短期的には依存をコンパイル時に外す方法がおそらく最も簡単で、もっと複雑な対応は ROSCon の後に考えると書いた。別の投稿者は 9月30日に、パッチを用意する前に、既定の動作を変えずにバッファ対応を任意にする方向でよいかを尋ねた。報告者はこの方向に賛成したが、メンテナーはまだ答えていない12。2026年10月6日の取得時点で issue は開いたままで、修正が入る時期は決まっていない。

Intrinsic のビルドの扱いは決まっておらず、CUDA バックエンドの範囲も現時点の記述である

Intrinsic は、ROS 2 Lyrical のコア要素を Bazel(bzlmod)でビルドする作業を進め、実験的なものとしてコミュニティと共有している。ROS の PMC(技術運営委員会)に公式の計画はない。Discourse の返信は、ROSCon の秋に多くの議論が見込まれると書く13。決定の時期も内容も資料にないので、本稿は予測しない。

CUDA バックエンドの対応は、同一プロセス内と、同一ホスト・同一 GPU・同一ユーザーのプロセス間に限られ、ホスト間の CUDA 通信は対応しない。Python では、バックエンド固有の API が C++ に限られ、非 CPU を受け入れる購読でも CPU でのシリアライズが使われやすい。文書はホスト間の通信と C++ に限る API に「currently」と付けており、どの範囲を運べるかはバックエンドの実装ごとに決まると書く7。二つ目の代価と同じく、本稿はこの二つを一時的とも永続とも判定しない。transient-local の永続性は、記述子が公開側の生きたメモリを指し、再利用されうるので、ゼロコピーの用途として対応しない7。こちらは文書の書き方でも、記述子の仕組みから来る制約である。

出典13件
  1. ROS 2 ドキュメント「About rosidl::Buffer backends」Rolling 版(2026-10-06 取得). https://github.com/ros2/ros2_documentation/blob/rolling/source/ROS-Framework/interfaces/Working-with-interfaces/Buffer-Backends/About-Buffer-Backends.rst — 新しい型が要る理由、記述子、フォールバック、型適応や NITROS とは別の問題を解くこと。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10

  2. NVIDIA-ISAAC-ROS「isaac_ros_common、isaac_ros_nitros」GitHub(2026-10-06 取得). https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_nitros — 二つのリポジトリの作成日とスター数。 ↩

  3. NVIDIA「Isaac ROS 5.0 Advances Agentic, Open Source Robotics Development」NVIDIA Blog, 2026. https://blogs.nvidia.com/blog/isaac-ros-5-0-agentic-open-source-robotics/ — OSRA と協力した寄与、約 130 万の利用者、Universal Robots の組み込み。 ↩ ↩2

  4. NVIDIA「From NITROS to rosidl::Buffer」Isaac ROS 文書(2026-10-06 取得). https://nvidia-isaac-ros.github.io/concepts/rosidl_buffer/nitros_migration.html — NITROS を外す四つの理由、ノード単位の互換、ソースレベルの移行が要る範囲、NITROS を非推奨とする記述、型の交渉が別の抽象であること。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8

  5. NVIDIA「NITROS」Isaac ROS 4.6 文書(2026-10-06 取得). https://nvidia-isaac-ros.github.io/v/release-4.6/concepts/nitros/index.html — NITROS の型と ROS のメッセージ型の一対一の対応、非 NITROS ノードとの接続、REP 2007/REP 2009、ゼロコピーには同じプロセスが要ること。 ↩ ↩2

  6. ROS 2 ドキュメント「Release Lyrical Luth」リリースノート(2026-10-06 取得). https://github.com/ros2/ros2_documentation/blob/rolling/source/Releases/Release-Lyrical-Luth.rst — uint8[] が rosidl::Buffer になること。使える RMW が二つであること。 ↩ ↩2

  7. ROS 2 ドキュメント「Using rosidl::Buffer backends」Rolling 版(2026-10-06 取得). https://github.com/ros2/ros2_documentation/blob/rolling/source/ROS-Framework/interfaces/Working-with-interfaces/Buffer-Backends/Using-Buffer-Backends.rst — トピックに限ること、CUDA の通信範囲と Python の制約に付いた「currently」、transient-local の理由、Experimental のテンソル型。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  8. NVIDIA「Isaac ROS 5.0.0 Release Notes」Isaac ROS 文書(2026-10-06 取得). https://nvidia-isaac-ros.github.io/releases/index.html — 主なパッケージの削除と Bridge の残存、移行 CLI の早期公開、前処理の性能の既知の制約。 ↩ ↩2 ↩3 ↩4

  9. Intrinsic「intrinsic-core」GitHub(2026-10-06 取得). https://github.com/intrinsic-ai/intrinsic-core — スター数、Bazel と k3s、別リポジトリの共有メモリ通信、Lyrical が前提であること。 ↩ ↩2 ↩3

  10. Intrinsic「Introducing Intrinsic Core」Intrinsic Blog, 2026-09-22. https://www.intrinsic.ai/blog/posts/introducing-intrinsic-core — 中核を Apache 2.0 で公開し ROS 互換と明記したこと。ROSCon での発表。 ↩

  11. Intrinsic「icon-shared-memory」GitHub README(2026-10-06 取得). https://github.com/intrinsic-ai/icon-shared-memory — 実時間制御の枠組み ICON の制御ループとハードウェア抽象層のための共有メモリ IPC であること。 ↩

  12. ros2/rosidl「Issue #1002」GitHub(2026-10-06 取得). https://github.com/ros2/rosidl/issues/1002 — rosidl_runtime_c が rosidl_buffer に依存し、micro-ROS と Zephyr で失敗する報告と、直し方の議論。 ↩ ↩2

  13. Open Robotics Discourse「Official state and timeline of ROS2 Bazel build」2026-05. https://discourse.openrobotics.org/t/official-state-and-timeline-of-ros2-bazel-build/54756 — Intrinsic が Lyrical のコア要素の Bazel(bzlmod)版を実験的な作業として共有していること、ROS PMC に公式計画がないこと。 ↩

この記事はAIが執筆しています。内容には誤りが含まれる可能性があります。ご注意ください。