---
title: "dora-rsとは？Rust製ロボット向けデータフロー基盤の使い方とROS 2との違い【1.1対応】"
url: "https://www.issoh.co.jp/tech/details/8827/"
published: 2025-09-16
updated: 2026-10-24
categories: ["Rust"]
publisher: "株式会社一創"
---

# dora-rsとは？Rust製ロボット向けデータフロー基盤の使い方とROS 2との違い【1.1対応】

**dora-rs**（プロジェクト名はdora）は、ロボットとAIのアプリケーションを「小さなプログラム同士がデータを渡し合うグラフ」として組み立てるための、Rust製オープンソースのフレームワークです。グラフはYAMLファイル1本で宣言し、各ノードはRust・Python・C・C++のどれで書いてもかまいません。2026年9月2日の1.0でワイヤ形式と公開ノードAPIが1.x系列のあいだ凍結され、10月8日に最初のマイナー版1.1.0が出ました。1.0は0.xと一切相互運用できないため、0.x時代の日本語解説（ノード定義に`custom:`キーを使うものなど）はそのままでは動きません。この記事では1.1.0を前提に、仕組み、ROS 2との違い、インストールと最小データフローの実行、落ちる・固まるノードへの備え、版ごとの変更点を順に説明します。なお「Dora AI」などのWebサイト生成・動画生成アプリは同名の別製品で、本記事の対象ではありません。

## まとめ：dora-rs 1.1の要点

- **正体**：ロボット・AI向けのデータフロー基盤。ノード（プロセス）とその接続をdataflow.ymlに書き、`dora run`で起動する。ライセンスはApache-2.0、リポジトリは`github.com/dora-rs/dora`。
- **最新版**：1.1.0（2026年10月8日）。1.0から公開APIとワイヤ形式は変わらず、1.0で書いたノードは入れ替えなしで1.1.0のデーモンにつながる。中身はバグ修正143件が中心で、新機能はノードの起動待ちを打ち切る`startup_timeout`など5件。
- **ROS 2との最大の違い**：各言語のノードAPIでApache Arrow形式を共通利用し、同一マシンで共有メモリ経路が利用可能なら、既定で4KiB以上のメッセージをゼロコピー配送する。公式はPython同士の比較でrclpyより遅延が10〜17倍小さいと主張し、ベンチマークをリポジトリに置いている。
- **インストール**：`cargo install dora-cli`（Rust 1.95以上）か`pip install dora-rs-cli`。PythonノードのAPIは`pip install dora-rs`で、CPython 3.11以上が必須。PyPIの`dora`は無関係の別パッケージ。Intel Macにはビルド済みのCLIもwheelも無い。
- **0.xからの移行**：0.xのノード・CLIは1.xのデーモン・コーディネーターと通信できない。全コンポーネントを止めて入れ替え、YAMLの`custom:`などを書き換える必要がある。

根拠にしたのは[公式リポジトリのREADME](https://github.com/dora-rs/dora)、[1.1.0のリリースノート](https://github.com/dora-rs/dora/releases/tag/v1.1.0)、[1.0のリリース記事](https://github.com/dora-rs/dora/blob/main/docs/blog/2026-09-02-dora-1.0.md)、[0.xからの移行ガイド](https://github.com/dora-rs/dora/blob/main/docs/migration-from-0.x.md)と、1.1.0での実行結果です。

## dora-rsの仕組み：CLI・コーディネーター・デーモン・ノードの役割分担

1.0のリリース記事によると、doraを構成するプロセスは4種類です。`dora`コマンド（CLI）はポート6013のWebSocketでコーディネーターに指示を出し、自身は状態を持ちません。コーディネーターはデプロイ全体に1つで、どのマシンにどのノードがいるかを管理します。デーモンはマシンごとに1つ動き、ノードのプロセスを起動・監視し、`restart_policy`に従って再起動します。ノードは利用者が書くプログラムそのものです。

コーディネーターの状態の置き場所は、公式文書の間で記述が食い違っています。リリース記事は「既定でredbデータベースに永続化する」と書き、`docs/fault-tolerance.md`は「既定はメモリ上で、`--store redb`で永続化する」と書いています。v1.1.0のソース（`binaries/cli/src/command/coordinator.rs`）では`--store`の既定値が`"redb"`なので、実装はリリース記事のとおり`~/.dora/coordinator.redb`に書きます。既定ではデータフローの記録が再起動後も残ります。ただし、実行中のデータフローを再接続後に管理下へ戻す機能には制約があり、記録の永続化だけで稼働継続が保証されるわけではありません。

制御とデータの経路は分かれています。起動・停止・ログ・メトリクスはコーディネーターを通りますが、ペイロードはコーディネーターを通りません。同じマシン上のノード同士は共有メモリで、別マシンのノードとは[Zenohとは？Pub/Sub・Queryの実装とzenohdの使い方・MQTT/DDSとの違い](/tech/details/6210/)で解説しているZenohで直接つながります。公式は、この分離のおかげで高負荷のデータフローでも`dora stop`が遅くならないと説明しています。

### Apache Arrow配列と4KB境界の共有メモリ

doraのメッセージはすべてApache Arrow配列です。Pythonノードが作った`pyarrow`配列を、下流のRustノードは同じバイト列のまま`arrow`配列として受け取るため、言語ごとのメッセージ形式へ詰め替える必要がありません。1.0では送受信の単位が自己記述型のArrow IPCストリームになり、移行ガイドは送信経路のコピーを1回以下と説明しています。Arrowのまま届くので、画像フレームや点群を[Polarsとは？pandasとの違い・高速化の仕組みと実務での採用判断【実装目線】](/tech/details/13618/)やnumpy、DuckDBへそのまま渡せる点も公式が挙げる利点です。

既定では4KiB（4,096バイト）以上のメッセージで、同一マシン上の共有メモリ経路が利用可能な場合にZenohの共有メモリを使い、受信側は送信側が書いたページをマップするだけで、ペイロードはコピーされません。公式ベンチマークでは4KBから4MBまで遅延がほぼ横ばいです。4KB未満はヒープにコピーします。共有メモリはページ単位で扱うため、小さなメッセージではページを用意するコストのほうがコピーより高くつくからで、しきい値は環境変数`DORA_ZERO_COPY_THRESHOLD`で変更できます。

## dora-rsとROS 2の違い：型定義・起動方法・性能主張の根拠

比較対象として最も多く挙がるのがROS 2です。ROSそのものの構造は[ROS（Robot Operating System）とは？ノードとDDS通信の構造・ROS 2世代の選び方を実装者目線で解説【2026年8月時点】](/tech/details/16824/)で解説しているので、ここではdoraとの差分に絞ります。

| 観点      | dora 1.x                | ROS 2                 |
| ------- | ----------------------- | --------------------- |
| 接続の定義   | dataflow.ymlの`inputs`   | トピック名で実行時に接続          |
| メッセージ型  | Arrow配列（IDL不要）          | .msg/.srv/.actionから生成 |
| ビルド     | 各ノードの`build:`コマンド       | colcon＋ワークスペースのsource |
| 起動      | `dora run dataflow.yml` | `ros2 launch`         |
| 同一マシン通信 | 既定4KiB以上・利用可能時に共有メモリ    | RMW実装（DDS等）に依存        |
| ノードの再起動 | YAMLの`restart_policy`   | launchの`respawn`      |
| エコシステム  | Node Hub（互換保証の対象外）      | Nav2・MoveIt 2など大規模    |

リリース記事は「メッセージ定義言語もコード生成もsourceするワークスペースもない。PythonノードはPythonスクリプトで、Rustノードはバイナリだ」と説明しています。ROS 2で`.msg`を追加するたびにパッケージを再ビルドしていた手間が、doraでは発生しません。その代わり型の整合はYAMLの任意の型注釈（`output_types`）と`dora validate`で確かめる方式で、書かなければ検査されません。

### 「ROS 2より10〜17倍速い」の測定条件

公式READMEとリリース記事は、同じPythonワークロードでノード間遅延がrclpyより10〜17倍小さいと述べています。根拠は[examples/ros2-comparison](https://github.com/dora-rs/dora/tree/main/examples/ros2-comparison)にあるベンチマークで、両フレームワークに同一のPython送受信ノードを置き、ペイロード0Bから4MBまでの10段階を各100メッセージ（5ms間隔）送って遅延を、間隔なしの100メッセージでスループットを測ります。ROS 2側の前提はHumble以降です。

この数字はPython同士の比較である点に注意してください。公式自身が「言語の速度ではなくフレームワークのオーバーヘッドを測る」ためと説明しており、C++で書いたROS 2ノード（rclcpp）やRMW実装の違いは比較に含まれていません。自社の構成で差を見積もるなら、`run_comparison.sh`を自分の機材で回すのが確実です。

### ROS 2資産との併用：ブリッジは実験的扱い

doraにはトピック・サービス・アクションを双方向に中継するROS 2ブリッジがあり、READMEはDDSと`rmw_zenoh_cpp`互換のZenohの両方に対応すると書いています。ブリッジは`rcl`や`rclcpp`をリンクしない純Rust実装（`ros2-client`と`rustdds`）で、ROS 2のインストールは要りませんが、メッセージ定義を読むために`AMENT_PREFIX_PATH`は必要です。

注意点は2つあります。1つ目は互換性で、READMEの言語対応表ではROS 2（Foxy以降）は「Experimental」で、1.xの互換保証の対象外（マイナーリリースで変わりうる）です。実際に1.1.0では、メッセージ側で省略した可変長シーケンスが1要素（上限付きは上限数）で埋めて送られていた不具合が直り、空のシーケンスとして送られるようになりました。1.0.xで「省略しても動いていた」配線は、受け側が要素を前提にしていると挙動が変わります。もう1つは[ブリッジのガイド](https://github.com/dora-rs/dora/blob/v1.1.0/docs/ros2-bridge.md)にある制約で、ブリッジはHumble向けの設定でビルドされており、Iron以降とはノード発見（グラフ探索）の識別子の長さが合いません。トピック・サービス・アクションのペイロード自体はディストリをまたいで通ります。

Nav2やMoveIt 2のようなROS 2のパッケージ群を中核に据える構成なら、ROS 2を主にしてdoraを一部のAI推論パイプラインに使う程度に留めるのが無難です。ROS 1とROS 2の世代差は[ROS1とROS2の違いを徹底比較｜2026年の移行判断とディストリ選び方](/tech/details/3812/)を参照してください。

## dora-rsのインストール手順：CLIとPython APIの入れ方

doraは「CLI」と「ノードを書くためのAPI」を別々に入れます。1.1.0の公式手順は次のとおりです。

```
# CLI（doraコマンド）：どれか1つ
cargo install dora-cli --version 1.1.0 --locked   # Rust 1.95以上が必要
pip install dora-rs-cli==1.1.0

# PythonノードのAPI（import名は dora）
pip install dora-rs==1.1.0

# macOS（Apple Silicon）/ Linux 向けインストーラ
curl --proto '=https' --tlsv1.2 -LsSf \
  https://github.com/dora-rs/dora/releases/download/v1.1.0/dora-cli-installer.sh | sh
```

本記事の検証に合わせて版を1.1.0に固定しています。新しい版を入れるときは`--version`と`==`の指定を外すか、[リリース一覧](https://github.com/dora-rs/dora/releases)で確かめた版に書き換えてください。CLIとPythonのAPIは同じ版にそろえます。

つまずきやすい点が3つあります。第一に、PyPIのパッケージ名は`dora-rs`で、`pip install dora`は無関係のパッケージを入れてしまいます（READMEに太字で警告があります）。第二に、1.xのwheelは`abi3-py311`でビルドされ、CPython 3.11以上が必須です。0.xは3.8から動いたので、古いPythonのままでは入りません。リリース記事は、この下限を1.xの途中で上げないことも互換保証の一部だと書いています。

第三に、対応プラットフォームの偏りです。PyPIに上がっている1.1.0のwheel（`dora-rs`・`dora-rs-cli`とも）はLinux（x86\_64・aarch64・armv7l・i686）、Windows（amd64）、macOS（arm64）向けで、リリースに添付されたビルド済みCLIも`aarch64-apple-darwin`・Linux 2種・Windowsの4種です。Intel Mac向けはどちらにも無いため、インストーラも使えず、Rustでソースからビルドすることになります。READMEのプラットフォーム表でも、Linuxが「First-class（PR-gated）」、macOS（ARM64）が「First-class（nightly-gated）」、WindowsとWSLは「Best effort」です。

Intel Mac（macOS x86\_64、rustc 1.99.1）で`cargo install dora-cli --version 1.1.0 --locked`を実行したところ、依存クレート567個のコンパイルを含めて完了まで22分52秒かかり（別のRustビルドと並行した状態）、`dora --version`は`dora-cli 1.1.0`を返しました。1.0.1のときも同じ機材で約26分かかっており、今回の所要時間は、この機材と並行ビルド条件での参考値であり、CPU性能やビルドキャッシュ、同時実行する処理によって変わります。対応OSならインストーラかwheelを使うほうが早く済みます。

## dora-rsの使い方：dataflow.ymlとRustノードによる最小データフローの実行

ここでは、200ミリ秒ごとに数を1つ増やして送る`counter`ノードと、それを表示する`printer`ノードを、Cargoワークスペースに置いて動かします。以下のコードは1.1.0で実際にビルド・実行したものです。空のディレクトリで2つのクレートを作り、ルートにワークスペース用のCargo.tomlを置きます。

```
cargo new counter --bin
cargo new printer --bin
```

```
# ルートの Cargo.toml
[workspace]
members = ["counter", "printer"]
resolver = "2"
```

### dataflow.yml：ノードの接続とタイマー入力の定義

次のdataflow.ymlを同じルートに保存します。

```
nodes:
  - id: counter
    build: cargo build -p counter
    path: target/debug/counter
    inputs:
      tick: dora/timer/millis/200
    outputs:
      - count

  - id: printer
    build: cargo build -p printer
    path: target/debug/printer
    inputs:
      count: counter/count
```

`inputs`は「入力名: 送信元ノードID/出力名」の形で書き、これがグラフの辺になります。`dora/timer/millis/<N>`と`dora/timer/hz/<N>`は組み込みのタイマーです。`build:`は`dora run`や`dora build`のときに実行されるコマンドで、`path:`が起動する実行ファイル（Pythonならスクリプト）です。1.xではノードIDに使える文字が`[a-zA-Z0-9_.-]`に制限され、空文字と先頭のピリオドは禁止です。また、`dora`というIDは予約済みです。

### Rustノードの実装：送信側と受信側

各ノードのCargo.tomlに`dora-node-api`を足します。1.0でArrowが公開APIから外れ、Arrowのメジャー版は`arrow-v58`か`arrow-v59`のフィーチャーで選ぶ方式になりましたが、移行ガイドによると必要なのはArrow型を直接扱う場合だけです。この例のように`into_arrow()`と`try_from`でプリミティブ値をやり取りするだけなら付けなくてよく、検証もフィーチャー無しでビルドしています。

```
[dependencies]
dora-node-api = "=1.1.0"
eyre = "0.6"
```

送信側の`counter/src/main.rs`です。タイマーの`tick`が届くたびに数を送り、5回送ったら終了します。

```
use dora_node_api::{DoraNode, Event, IntoArrow, dora_core::config::DataId};

fn main() -> eyre::Result<()> {
    let (mut node, mut events) = DoraNode::init_from_env()?;
    let output = DataId::from("count".to_owned());
    let mut count: u64 = 0;

    while let Some(event) = events.recv() {
        match event {
            Event::Input { id, metadata, .. } if id.as_str() == "tick" => {
                count += 1;
                node.send_output(output.clone(), metadata.parameters, count.into_arrow())?;
                if count == 5 {
                    break;
                }
            }
            Event::Stop(_) => break,
            _ => {}
        }
    }
    Ok(())
}
```

受信側の`printer/src/main.rs`です。Arrow配列から`u64`へ`try_from`で取り出します。

```
use dora_node_api::{DoraNode, Event};

fn main() -> eyre::Result<()> {
    let (_node, mut events) = DoraNode::init_from_env()?;

    while let Some(event) = events.recv() {
        match event {
            Event::Input { id, data, .. } if id.as_str() == "count" => {
                let value = u64::try_from(&data)?;
                println!("received count={value}");
            }
            Event::InputClosed { id } => println!("input `{id}` closed"),
            Event::Stop(_) => break,
            _ => {}
        }
    }
    Ok(())
}
```

ワークスペースのルートで`dora run dataflow.yml`を実行すると、各ノードの`build:`が走ったあと2つのプロセスが起動し、次の出力が得られました。

```
09:18:10 INFO   [dora]: daemon all nodes are ready, starting dataflow
09:18:10 stdout printer: received count=1
09:18:10 stdout printer: received count=2
09:18:11 stdout printer: received count=3
09:18:11 stdout printer: received count=4
09:18:11 stdout printer: received count=5
09:18:11 stdout printer: input `count` closed
09:18:11 INFO   counter: daemon counter finished successfully
09:18:11 INFO   printer: daemon printer finished successfully
```

送信側が5回で終了すると、受信側には`InputClosed`イベントが届き、入力が全部閉じたノードもループを抜けて終了します。上流ノードの終了が下流へ伝わるため、終了処理を自分で配線する必要はありません。ノードの`println!`はログに`stdout`付きで集約されます。YAMLの配線だけを先に確かめたいときは`dora validate dataflow.yml`が使えます。この構成では「Input/output wiring OK.」「Descriptor config OK.」「All type annotations OK.」の3行が返りました。1.0.1向けに書いた同じコードは、依存の版を`1.1.0`に上げるだけで、警告もなくビルド・実行できています。

### Pythonノードの実装：Arrow配列の受信とイベント処理

Pythonでは`Node()`を作ってイベントを反復するだけです。次は公式Pythonガイドの受信ノードで、`event["value"]`は`pyarrow`配列として届きます。

```
from dora import Node

node = Node()
for event in node:
    if event["type"] == "INPUT":
        values = event["value"].to_pylist()
        print(f"Received {event['id']}: {values}")
    elif event["type"] == "STOP":
        break
```

YAML側では`path: receiver.py`のようにスクリプトを指定します。1ファイルのデータフローの中でRustノードとPythonノードを混ぜてもよく、ノードは隣のノードが何の言語で書かれているかを知りません。なお本記事の検証環境はIntel MacでPythonのwheelが無いため、Pythonノードは実行していません。

## 落ちる・固まるノードへの備え：restart\_policyとstartup\_timeout

カメラドライバの異常終了やモデル読み込み中の停止に備えるには、異常終了後の再起動と、起動完了を待つ時間の上限を設定します。doraはこの対処をノードのコードではなくYAMLに書かせる設計で、[障害対策のガイド](https://github.com/dora-rs/dora/blob/v1.1.0/docs/fault-tolerance.md)に設定項目がまとまっています。

| 設定                                  | 単位     | 働き                                |
| ----------------------------------- | ------ | --------------------------------- |
| `restart_policy`                    | ノード    | `never`（既定）／`on-failure`／`always` |
| `max_restarts`・`restart_window`     | ノード    | 「M秒にN回まで」の再起動上限                   |
| `restart_delay`・`max_restart_delay` | ノード    | 倍々で伸びる待ち時間とその上限                   |
| `health_check_timeout`              | ノード    | 接続後に無反応が続いたら強制終了                  |
| `startup_timeout`（1.1.0〜）           | ノード    | 起動から接続までの期限                       |
| `health_check_interval`             | データフロー | 上の2つを点検する間隔（既定5秒）                 |
| `input_timeout`                     | 入力     | 初回受信後の無通信を検出し、再受信で復帰              |

`input_timeout`は上流が途切れずに送り続ける入力向けです。サービスの応答やアクションの結果など、要求したときだけ届く入力に付けると、ふつうの待ち時間を上流の停止と取り違えて遮断が働きます。

`on-failure`は終了コードが0以外のときだけ再起動し、`always`は正常終了でも再起動します。ただし`always`でも、利用者が`dora stop`やCtrl-Cで止めたときと、入力が全部閉じて再起動が無効化されたときは、終了コードにかかわらず再起動しません。上の最小例では、入力が全部閉じた下流の`printer`は再起動されません。一方、タイマー入力を持つ`counter`に`restart_policy: always`と`max_restarts: 2`を付けて動かすと、5回送って正常終了するたびに「restarting node after successful exit」で起こし直され、`printer`はcount=1〜5を3周受け取りました。再起動の可能性がある間は出力が閉じられないため、下流には`InputClosed`が届きません。仕事を終えたら止まるべきノードには`on-failure`を使ってください。

### 1.1.0で入ったstartup\_timeoutの効き方

1.0までの`health_check_timeout`は、ノードがデーモンに接続した後の無反応しか見ません。ガイドは、`Node::init`に届く前のimportや初期化でデッドロックしたノードはこの監視では刈り取れず、データフローが待機状態のまま止まると書いていました。1.1.0の`startup_timeout`はこの穴を埋める設定で、プロセスを起動してから指定秒数以内に接続しなければ、デーモンが警告を出してSIGKILLし、`restart_policy`を評価します。

挙動を確かめるため、`DoraNode::init_from_env()`の前で30秒眠るノードを作り、`startup_timeout: 5.0`を付けて`dora run`で起動しました。前の章のワークスペースで`cargo new slowstart --bin`を実行し、ルートのCargo.tomlの`members`に`"slowstart"`を足して、`counter`と同じ依存（`dora-node-api = "=1.1.0"`と`eyre`）を書きます。`slowstart/src/main.rs`は次のとおりです。

```
use dora_node_api::{DoraNode, Event};
use std::{thread, time::Duration};

fn main() -> eyre::Result<()> {
    // 初期化前に固まるノードを模擬する（モデル読み込みのハングなど）
    println!("loading model...");
    thread::sleep(Duration::from_secs(30));
    let (_node, mut events) = DoraNode::init_from_env()?;
    while let Some(event) = events.recv() {
        if let Event::Stop(_) = event {
            break;
        }
    }
    Ok(())
}
```

このノードを次のYAML（startup.yml）で起動します。

```
nodes:
  - id: slowstart
    build: cargo build -p slowstart
    path: target/debug/slowstart
    startup_timeout: 5.0
    inputs:
      tick: dora/timer/millis/500
```

```
09:18:19 DEBUG  slowstart: spawner spawned node with pid 28427
09:18:21 stdout slowstart: loading model...
WARN node `slowstart` failed to connect within 5s (elapsed: 9999ms), killing
INFO fault tolerance stats restarts=0 health_kills=0 startup_kills=1 ...
09:18:29 ERROR  slowstart: daemon exited because of signal SIGKILL with stderr output:
process killed: startup_timeout exceeded before node connected
```

ノードはSIGKILLで止められ、`dora run`は終了コード1で返りました。ログの`elapsed: 9999ms`が示すとおり、5秒の期限に対して実際に殺されたのは起動から約10秒後です。期限は`health_check_interval`（既定5秒）の刻みで点検されるためで、データフローの最上位に`health_check_interval: 1.0`を書いて同じノードを動かすと、`elapsed: 5988ms`で止まりました。`restart_policy: on-failure`と`max_restarts: 2`を足した場合は、約10秒ごとに2回起こし直したあと「max restarts (2) exceeded, giving up」で打ち切られ、統計の`startup_kills`は3になりました。

値の決め方には注意が要ります。まず、期限を点検間隔ごとに確認するため、通常は点検間隔1回分程度の遅れが生じ得ます。高負荷時のスケジューリング遅延まで含めた厳密な上限ではありません。数秒単位で期限を効かせたいなら`health_check_interval`も一緒に縮めてください（短くするほど点検の負荷は増えます）。もう1つは、正当に遅いノードとの区別がつかない点です。大きなモデルを読み込んでから`init`するPythonノードに短い期限を付けると、読み込みのたびに殺されて再起動を繰り返します。モデルの読み込みを初期化前に行う場合は、読み込み時間の実測値に余裕を足して`startup_timeout`を設定してください。初期化後に回す場合も、`health_check_timeout`を設定していれば読み込み中の無通信が監視対象になるため、その時間を許容する値が必要です。

## dora CLIの使い分け：開発はdora run、本番はdora up/start

`dora run`はコーディネーターを立てず、デーモンを内蔵した1プロセスでデータフローを手元で動かす開発用のモードです。`dora top`や`dora topic echo`などの観察系コマンドはコーディネーターに問い合わせるため、`dora up`と`dora start`で起動したデータフローにしか使えません。さらに`dora topic echo`や`dora topic hz`で流れるデータを見るには、`dora start dataflow.yml --debug`のように`--debug`を付けてデバッグ用トピックを有効にしておく必要があります（YAMLの`debug: {enable_debug_inspection: true}`と同じ効果）。

| 用途           | コマンド                                         |
| ------------ | -------------------------------------------- |
| 手元で1回実行      | `dora run dataflow.yml`                      |
| 常駐基盤の起動・停止   | `dora up` ／ `dora down`                      |
| データフローの開始・停止 | `dora start dataflow.yml` ／ `dora stop <ID>` |
| 一覧・ログ        | `dora list` ／ `dora logs <ID> --node <名前>`   |
| リソース監視       | `dora top`                                   |
| 流れるデータの確認    | `dora topic echo` ／ `dora topic hz`          |
| 記録と再生        | `dora record` ／ `dora replay`                |
| YAMLの検査・可視化  | `dora validate` ／ `dora graph`               |
| 環境診断         | `dora doctor`                                |

本番運用で効くのは記録と再生です。`dora record`は全出力を`.drec`ファイルに書き出すノードをデータフローへ足し、`dora replay`は記録元のノードを再生ノードに差し替えて、残りのノードはそのまま動かします。ロボット上で取得した出力データをノートPCで繰り返し再生し、修正したノードの動作確認に使えます。1.1.0では`dora replay --speed`に不正な値を渡すと黙って等倍で再生していた不具合や、記録ノードがクラッシュしたときに失うデータ量が無制限だった点が修正されています。複数台構成は、ノードごとに`deploy: {machine: robot}`のように配置先を指定し、各マシンで`dora daemon --coordinator-addr <IP> --machine-id robot`のようにデーモンを起動します。ノードのコード自体は1台構成のときから変わりません。

## dora-rsのバージョン履歴：0.xから1.0の非互換と1.1.0の変更点

| 版     | 公開日        | 位置づけ                                |
| ----- | ---------- | ----------------------------------- |
| 0.x系  | 〜2026年     | APIが版ごとに変わる開発版（最終状態は`v0.x-final`タグ） |
| 1.0.0 | 2026-09-02 | ワイヤ形式・公開API・YAMLスキーマを凍結             |
| 1.0.1 | 2026-09-03 | パッチ版                                |
| 1.1.0 | 2026-10-08 | 最初のマイナー版。startup\_timeout追加・修正143件  |

### 0.xの記事から1.xへ移るときの非互換点

日本語で読めるdora-rsの解説は、2025年頃の0.x系を前提にしたものがほとんどです。公式の移行ガイドは「互換モードもローリングアップグレードも無い。全コンポーネントを止め、すべて更新してから起動し直す」と書いています。古い手順をそのまま1.xに当てると次の箇所で止まります。

| 箇所          | 0.x                 | 1.x                     |
| ----------- | ------------------- | ----------------------- |
| YAMLのノード定義  | `custom:`の下に`path`等 | ノード直下に書く（`custom:`はエラー） |
| 分散配置の指定     | `_unstable_deploy`  | `deploy`                |
| 通信設定        | `communication:`    | 削除（エラー）                 |
| 制御ポート       | 6012・6013・53290     | WebSocketの6013のみ        |
| コーディネーターの待受 | `0.0.0.0`           | `127.0.0.1`（既定）         |
| Python      | 3.8以上               | 3.11以上                  |
| Rust        | 1.85                | 1.95                    |
| Rustのエラー型   | `eyre::Result`      | `NodeResult`            |
| CLI         | `dora version`      | `dora --version`        |

0.x形式の`custom:`を含むYAMLを`dora validate`に通すと、次のエラーで止まります（1.1.0での実行結果から抜粋）。

```
nodes[0]: unknown field `custom`, expected one of `id`, `name`, `description`, `path`, ... `deploy`, `startup_timeout` at line 3 column 5
```

エラーが原因の欄名を示すので、古い記事のYAMLを流用したときは`custom:`の中身をノード直下へ移せば解消します。特に見落としやすいのはコーディネーターの待受アドレスです。0.xは全インターフェースで待ち受けていたため、複数台構成が設定なしで動いていました。1.xは既定でループバックにしか応じないので、`--interface <IP>`か環境変数`DORA_COORDINATOR_INTERFACE`を指定しないと、別マシンのデーモンが接続でタイムアウトします。また0.xのノードを1.xのデーモンにつなぐと、親切なバージョン不一致のメッセージではなくデコードエラーが出ます。エンコーディングがbincodeからpostcardに変わり、バージョン確認より前にデコードが失敗するためです。

なお、1.0は`dora-rs/adora`というフォークを統合して作られています。`adora-rs`というPyPIパッケージを入れていた場合は、再公開されないので削除してから`dora-rs`を入れ直すよう移行ガイドは指示しています。

### 1.0.xから1.1.0への更新：互換保証の範囲と変更点

1.0から1.1.0への更新は、0.xからの移行とは別物です。リリース記事は「1.0向けに書いたノードは2.0まで、ビルドが通り続け、デーモンと通信し続ける」と約束しており、CLIとデーモン、各ノードのクレートを順に上げていけば済みます。ただし凍結の対象は`dora-node-api`（Rust・C・C++）、Pythonの`dora`モジュール、ワイヤ形式、`dora`コマンドとYAMLスキーマで、`ros2:`ブリッジ、オペレーター、`hub:`、MAVLinkブリッジ、テンソルプールは対象外です。1.1.0で利用者に見える変更は次のとおりです。

- **`startup_timeout`の追加**：前の章のとおり。付けなければ1.0と同じ挙動。
- **ROS 2ブリッジのシーケンス既定値**：省略した可変長シーケンスが空で送られるようになった。ブリッジを使っているなら受け側の前提を確認する。
- **C++ノードのスレッド安全な`send_output`**：ワーカースレッドから出力を送れるハンドルが加わった。C++ノードから再起動を検知する手段も追加。
- **依存の脆弱性対応**：rustlsを0.23.45へ上げ、RUSTSEC-2026-0285を解消。ネットワーク越しにデーモンをつなぐ構成なら、これだけでも上げる理由になる。
- **Rustノード向けの追加**：`Vec<bool>`の`IntoArrow`実装、テスト用`MockNode`が凍結済みの全メソッドを模擬するように。

公式サイト（dora-rs.ai）のFAQには、2026年10月時点でも1.0を「リリース候補（1.0.0-rc1）」と書いた記述が残っています。版の状況は[GitHubのリリース一覧](https://github.com/dora-rs/dora/releases)で確かめるのが確実です。

## dora-rsが向く構成と見送るべき構成

doraが合うのは、カメラ・物体検出・LLM・音声合成のようなAIの部品をPython中心に試しながら、重い処理だけRustやC++へ置き換えていく構成です。言語をまたいでもArrow配列のまま渡るので、ノードを書き換えても辺の定義は変わりません。Node Hubには、カメラやYOLO、LLM、TTS向けの既製ノードが揃っています。エッジ機でAI推論を回す構成なら、[NVIDIA Jetsonとは？Orin・Thorの違いと選定基準・量産判断を実装視点で解説【2026年版】](/tech/details/16173/)のようなLinux ARM64機がdoraの「First-class」対象に入ります。推論パイプラインの設計から実機への組み込みまでを外部に任せる場合は、[生成AI開発・AI受託開発](/service/ai/development/)のような開発支援の範囲になります。

次の条件に当てはまるなら、採用を見送るかROS 2と併用してください。

- **Nav2・MoveIt 2などROS 2のパッケージが中核**：ブリッジは実験的扱いで、1.xの互換保証の対象外。Iron以降とはノード発見も噛み合わない。ROS 2の構築手順は[ROS 2の環境構築｜Ubuntu 22.04へのHumbleインストールとcolconビルド手順【2026年8月時点】](/tech/details/16826/)にまとめています。
- **Windowsが本番環境**：公式の対応はBest effortで、C/C++テンプレートは自動テストの対象外。
- **開発機がIntel Mac中心のチーム**：ビルド済みCLIもPythonのwheelも無く、Pythonノードを手元で動かすにはソースビルドが要る。
- **オペレーター（同一プロセス内で動く軽量関数）やNode Hubに依存したい**：どちらも1.xの凍結範囲外で、マイナーリリースで変わりうる。

## よくある質問

### dora-rsとROS 2は何が違いますか？

doraはノードの接続をdataflow.ymlに宣言し、Apache Arrow形式でデータを扱います。同一マシンでは条件に応じて共有メモリを使い、別マシン間はZenohで通信します。ROS 2のような.msgファイルとコード生成、colconワークスペースはありません。Nav2やMoveIt 2を中核に据えるならROS 2を軸にしてください。doraのROS 2ブリッジは実験的扱いで、互換保証の対象外です。

### dora-rsはRustでしか書けませんか？Pythonは使えますか？

Pythonも第一級の対応言語です。`pip install dora-rs`で入れ、`from dora import Node`で使います。1.0からはCPython 3.11以上が必要です。C・C++のノードAPIもあり、1つのデータフローで複数の言語を混ぜられます。

### dora-rsのソースコードやGitHubはどこですか？

`github.com/dora-rs/dora`がリポジトリで、ライセンスはApache-2.0です。2026年10月時点のスター数は約4,000で、最新リリースは1.1.0（2026年10月8日）です。0.x系の最終状態は`v0.x-final`タグに残されています。

### dora-rsのCLIで最初に覚えるコマンドは何ですか？

開発中は`dora run dataflow.yml`だけで足ります。常駐させて監視やログを使うときは`dora up`で基盤を立て、`dora start`で開始、`dora stop`で停止、`dora down`で基盤を落とします。0.xの`dora destroy`は`dora down`の別名として残っています。

### 「Dora AI」などのdoraアプリとdora-rsは関係がありますか？

関係ありません。Dora AI（dora.run）はテキストからWebサイトを生成するSaaSとして提供されていたサービスです。App Storeの「Dora – AI動画生成」なども別の製品です。dora-rsはロボットとAIのソフトウェアを組み立てる開発者向けのオープンソースで、アプリストアからは入手しません。

## 関連記事

- [ROS（Robot Operating System）とは？ノードとDDS通信の構造・ROS 2世代の選び方を実装者目線で解説【2026年8月時点】](/tech/details/16824/)
- [ROS1とROS2の違いを徹底比較｜2026年の移行判断とディストリ選び方](/tech/details/3812/)
- [Zenohとは？Pub/Sub・Queryの実装とzenohdの使い方・MQTT/DDSとの違い](/tech/details/6210/)
- [NVIDIA Jetsonとは？Orin・Thorの違いと選定基準・量産判断を実装視点で解説【2026年版】](/tech/details/16173/)

---

出典: [dora-rsとは？Rust製ロボット向けデータフロー基盤の使い方とROS 2との違い【1.1対応】](<https://www.issoh.co.jp/tech/details/8827/>)（株式会社一創）
