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、1.1.0のリリースノート、1.0のリリース記事、0.xからの移行ガイドと、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との違いで解説しているZenohで直接つながります。公式は、この分離のおかげで高負荷のデータフローでもdora stopが遅くならないと説明しています。
Apache Arrow配列と4KB境界の共有メモリ
doraのメッセージはすべてApache Arrow配列です。Pythonノードが作ったpyarrow配列を、下流のRustノードは同じバイト列のままarrow配列として受け取るため、言語ごとのメッセージ形式へ詰め替える必要がありません。1.0では送受信の単位が自己記述型のArrow IPCストリームになり、移行ガイドは送信経路のコピーを1回以下と説明しています。Arrowのまま届くので、画像フレームや点群をPolarsとは?pandasとの違い・高速化の仕組みと実務での採用判断【実装目線】や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月時点】で解説しているので、ここでは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にあるベンチマークで、両フレームワークに同一の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つはブリッジのガイドにある制約で、ブリッジはHumble向けの設定でビルドされており、Iron以降とはノード発見(グラフ探索)の識別子の長さが合いません。トピック・サービス・アクションのペイロード自体はディストリをまたいで通ります。
Nav2やMoveIt 2のようなROS 2のパッケージ群を中核に据える構成なら、ROS 2を主にしてdoraを一部のAI推論パイプラインに使う程度に留めるのが無難です。ROS 1とROS 2の世代差はROS1とROS2の違いを徹底比較|2026年の移行判断とディストリ選び方を参照してください。
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と==の指定を外すか、リリース一覧で確かめた版に書き換えてください。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に書かせる設計で、障害対策のガイドに設定項目がまとまっています。
| 設定 | 単位 | 働き |
|---|---|---|
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のリリース一覧で確かめるのが確実です。
dora-rsが向く構成と見送るべき構成
doraが合うのは、カメラ・物体検出・LLM・音声合成のようなAIの部品をPython中心に試しながら、重い処理だけRustやC++へ置き換えていく構成です。言語をまたいでもArrow配列のまま渡るので、ノードを書き換えても辺の定義は変わりません。Node Hubには、カメラやYOLO、LLM、TTS向けの既製ノードが揃っています。エッジ機でAI推論を回す構成なら、NVIDIA Jetsonとは?Orin・Thorの違いと選定基準・量産判断を実装視点で解説【2026年版】のようなLinux ARM64機がdoraの「First-class」対象に入ります。推論パイプラインの設計から実機への組み込みまでを外部に任せる場合は、生成AI開発・AI受託開発のような開発支援の範囲になります。
次の条件に当てはまるなら、採用を見送るかROS 2と併用してください。
- Nav2・MoveIt 2などROS 2のパッケージが中核:ブリッジは実験的扱いで、1.xの互換保証の対象外。Iron以降とはノード発見も噛み合わない。ROS 2の構築手順はROS 2の環境構築|Ubuntu 22.04へのHumbleインストールとcolconビルド手順【2026年8月時点】にまとめています。
- 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のソフトウェアを組み立てる開発者向けのオープンソースで、アプリストアからは入手しません。