ROSとRTミドルウエアの比較

RTミドルウエアとROSについて,ysugaも比較してみました.

2015年10月2日修正

まず,

RTミドルウエアとROSは比較しても・・・ね?

RTミドルウエアという言葉は,ロボット用のミドルウエアの総称のようなものです.細かく言えば,RTミドルウエアって言葉が指すものは,RTミドルウエアのプロジェクトで提案された通信規格に準拠しているミドルウエアの総称でしょうから,つまり,OpenRTM-aistやOpenRTM.NET,OROCOS,OpROS, Gostai-RTC, miniRTC, microRTC, RTC on Androidなどなど,RTミドルウエア規格に準拠/一部準拠するソフトウエアの総称なので,実装レベルで動いているROSと比較するのは結構ナンセンスだと思っています.

RTミドルウェアの規格とは,Object Management Group (OMG) という国際的な規格化団体で定義された<"Robotics Technology Component (RTC)"の規格を主に指しており,2015年10月現在はバージョン1.1が公開されています.この規格のメンテナンスのために,現在も産業技術総合研究所 (AIST) の研究者の方々はOMGの会議への出張を年に数回行っており,結果を学会やロボット工業会の会議で報告しています.メンテナンス,というのは,AIST自らが開発しているOpenRTM-aistの運用や,利用者の声から,規格を変更するなどして,より良いロボット要素モジュールの通信規格を作ろうとしているわけです.

この規格というのを,ざっくりと説明すると,

  • ロボットをモジュールに分割して一つ一つをRobotics Technology Component (RTC) と呼ぼう
  • RTC状態マシンを持つ
    • 実行直後はCREATED状態になり,初期化が終わるとINACTIVE状態になる
    • INACTIVE状態からツールなどで命令を受け取るとACTIVE状態になる.ツールでまたINACTIVEに戻すことができる
    • RTC内部でエラーが起きたらERROR状態になりましょう
  • RTCの状態マシンは実行コンテキスト (Execution Context, EC) が管理する
    • いろんなECを作ることができ,それぞれを入れ替えることができる
    • たとえばPeriodicなECではACTIVE状態では繰りかえしon_executeという関数が呼ばれることとして,ここにループ処理を書きましょう
    • PeriodicなECをリアルタイムOS対応にすればリアルタイムでループ処理ができる
    • PeriodicなECをシミュレータと同期すればシミュレーション時間と同期して実行できる
  • RTCはポートを持つ.ポートとポートを繋げると通信できる
    • ポートはインターフェースを持っており,同じインターフェースであれば接続することができる
    • 接続 (Connection) はプロパティを持っており,これを編集することで通信をコンフィグレーションすることができる
    • たとえば通信時のバッファを入力側に置くか,出力側に置くか,読み込んだ場合に最新のデータを返すか,バッファの最前列を返すか,などなど

実装する人から見れば,本当にざっくりとしたことが書いてあります.
ここに従ってプログラムを書くと,お互いに通信できないんじゃないか,と思った人,その指摘はほぼ正しいです.
確かに直接通信するには,これ以上により細かいプロトコルを規定しないといけませんが,細かいプロトコルは他の規格を使えば,直接通信が簡単になりそうですよね.
低位のプロトコルが違っても,状態マシンやポートとインターフェースといった要素がそろっているなら,ブリッジを作ることが容易になりますから,相互に通信しやすい,というのが実際のところです.
たとえば,OpenRTM-aistは,OpenRTM.NET (.NET frameworkを使ったRTミドルウェア)miniRTCやmicroRTC (軽量版RTCで,ZigBeeやCANバス上で動く独自通信プロトコル)は,相互に通信できるようです.
僕もRTnoというArduino用のRTM的なものを作りましたが,ポートや状態マシンの概念さえそろっていれば,変換ツールは簡単に出来ちゃいます.

RTミドルウエアはCORBAだからなぁ,とか言っている人はこの辺を勘違いしているんだと思います.たしかにOpenRTM-aistは基本はCORBAを使っていますが,産総研のジェフさんによって,DDSやROSの通信などに対応したデータポートを実装することもできます.ポートを入れ替えれば,別の規格と直接通信ができるようにOpenRTM-aistは準備されています.
RTミドルウエアはただの規格なんです.

他にもCAN-openという主にCANバス上で通信するプロトコルとRTC規格をブリッジする規格が,CAN-openを決めるCiA (CAN in Automation)で定められています (CiA318やCiA460).
その実装も芝浦工業大学の水川研究室(今は,安藤研)で管理されてます.
最近では,ホンダでもRTC規格に準拠したRTミドルウェア 「H-RTM」を実装して,その中で得られた知見をOMGで規格として提案しているらしいです.

ROSにもAPIやTCPROSなどの通信規格と呼べるものがありますが,この辺の後方互換性についてはどこかでしっかりと宣言してほしいですし,もう少し抽象化した規格があれば,XML-RPCではなく,独自のAPIサービスを実装して超軽量版ROSを作成することも可能になると思います.この辺がROSの弱み.
ただ,ROS2からは,すこし改善するみたい. さっきも出てきたDDSやIoTで注目されている通信プロトコル上にROSを実装しようとする動きになっていて,今もメーリスで議論が行われている感じ.規格を2層化するところとか,RTCに似てくるんだろうな,と伝え聞いているところですが,既存のROSの軽快さは,それはそれで好きだし,いろいろ影響を受けたんだけどな.

OpenRTM-aistとROSの比較

さて,実装レベルではOpenRTM-aistとROSで比較するとどうでしょうか.

分散システム

まず,OpenRTM-aistもROSも同じ分散システム指向なシステム開発を行います.
分散システムはシステムの一部がエラー等で終了した場合においても,システム全体のシャットダウンなどにつながらない堅牢なシステムを提供する枠組みです.

OpenRTM-aistはRTコンポーネントという単位

OpenRTM-aistではRTコンポーネント(RTC)という単位の組み合わせで実行されます.
RTCは他のRTCと接続するためのエンドポイントとなる「ポート」を持っており,これで分散システムを構築します.
RTCは必ずしも一つのプロセスに一つのRTCではありません.これはCORBA上にRTミドルウエアを実現したOpenRTM-aistの特徴の一つといえます.

ROSはノード

ROSはノード単位です.
ノードは一つのプロセスに一つのノードが一般的です.Pythonコード側(rospy)しか読んでませんが,シングルトンを多用しているので,一つのプロセスに複数のノードを実現するのは難しいと思います.

違い

この時点では大差は感じません.

対応プラットフォームと言語

ROSもOpenRTMも,どちらもミドルウエアとしての性格を持っています.
ミドルウエアとは,OSや実装言語の違いを吸収して,ユニバーサルに通信を行うためのライブラリを指しています.

OpenRTM-aistは対応するOSや言語が広い

OpenRTM-aistは対応するOSがWindows, Linux, Mac OSと幅広いです.さらに,Toppers (TRON系OS)や,VxWorksへのポーティングが報告されていますので,リアルタイムシステム上での実行が可能です.

言語はC++,Java,Pythonに対応しています.一応,OpenRTM-aist互換のライブラリとして,OpenRTM.NETがあり,.NET Frameworkを使ってプログラミング出来ます.(つまり,VB,C#,F#などでの実装が可能).
拙作のRTC-scilabを使えば,scilab言語(フリーのMATLABといえばわかりやすいですかね?)でのRTC作成が可能です.

ROSは対応OSの幅が狭いか?

ROSは基本的にLinux上での運用を前提としています.
もちろんMacやWindows (Cygwin) にもインストールすることが出来ますが,ROSの恩恵を一番に受けるのはCUIでのスピーディなプロトタイピングだと思います.

ROSの開発言語はC++, Python, Java (rosjava)ですが,これ以外にもoctave (フリーのMATLAB)から利用が可能です.僕はC++とPythonしか試したことがありませんが・・・

ROS2からはWindowsも正式な形でサポートするみたいだけど,正式リリースにならないとわからないですね.

比較

開発する言語は,OpenRTM-aistではC++, Python, Java.で,互角といえるでしょう.

OpenRTM-aistの方が動作するプラットフォームとしては充実しています.Windowsが必要なのか?という議論もあると思いますが,使いこなしてみれば,逆にLinuxじゃなきゃいけない理由もないです.リアルタイムカーネルとか使うときぐらいだと思います.
Windowsでロボットを動かしているという人も,すくなくとも日本国内では少なくありません.Visual Studioはかなり優秀なツールだと思いますけどどうですか?図書館の案内システムとかWindowsで作られていますよね?いずれサービスロボットがそういう世界に触れるときのことを考えると,Windowsは無視できませんよ.

開発方法

この辺でROSとOpenRTM-aistの違いが浮き彫りになってきます.

OpenRTM-aist

OpenRTM-aistのツールはグラフィカルな開発ツールが非常に充実しています.
基本的にすべてEclipse上で動くGUIツールですが,設計,ドキュメント作成,スケルトンコードの生成,コーディング,運用がEclipseに統合されています(一部 Visual Studioでコンパイルする必要がありますが,最新バージョン1.1ではEclipseでコンパイルできるようになるらしい).

OpenRTM-aistではまず,RTCをEclipse上のツールで設計し,スケルトンコードを作成します (RTC-Builder).
スケルトンコードはRTCの状態マシンを実装してあるクラスを継承したクラスのコードであり,このクラスの特定のメソッドが,RTCの状態マシンのコールバックになっています.

なので,開発者は特定のタイミングで呼ばれるコールバック関数上に機能を実装します.

RTCにメイン関数はありません.RTCを実行する実行ファイルを生成するコードも同時に排出されますが,RTCは後述するマネージャから実行すると使いやすいものになります.

ROSの場合はパッケージ

ROSではパッケージという単位で開発を行います.ROSではコマンドラインから実行できるツールが非常に充実しています.

まず,パッケージを作成,管理するためのコマンドroscreate-pkgやrospackなどがあります.また,パッケージの特定のノードを実行するためのrosrunコマンドや,マスターに登録されているトピックやサービスを確認するためのrostopic, rosservice,トピックやサービスに関する情報を収集するためのrosmsg, rossrvなどがあります.

*この辺のコマンドラインから実行できるツールとしてはOpenRTM-aistにもrtshellなどのツールが生まれてきましたが,ROSとは前提としている部分が違うので,使い心地は異なります.

ROSではまず,パッケージを作成してから,パッケージ内にノードとなるコードを作成します.パッケージを作成した時点で,コンパイル用のMakefileや依存関係を表すmanifest.xml,サービスやトピックを宣言するための仕組みなどが作成され,rosmakeコマンドでパッケージごとビルドすることが出来ます.
パッケージには複数のノードを作ることが出来,roslaunchの設定ファイルを使って,同時に複数起動したりすることもできます.
ただし,ノードのスケルトンとなるコードが生成されることはありませんので,自分でmainから記述する必要があります.
rosで提供されるのは,基本的にサービスやトピックを利用するための仕組みであり,それ以外の部分,たとえばノードごとのデプロイサービスなどはパッケージを管理するOSやシェルのレベルでのツールで提供されます.

通信の仕組み

OpenRTM-aistはポートを使って通信

OpenRTM-aistにはポートというデータ通信用のエンドポイントとして,「サービスポート」と「データポート」が提供されています.

データポートはデータを送受信するためのポートです.データポートは「型」を持っており,同じ型同士のデータポートは接続することが出来ます.データ型はLongやFloatなどの組み込みのデータ型だけでなく,独自にIDLというファイルを使ってデータ型を宣言することが出来ます.IDLはオブジェクト指向言語のインターフェース設計のためのメタ言語であり,CORBAやRMIのサービスを宣言するときに使うのが一般的でしょうか(僕はその程度しか使わないけど?)

サービスポートはデータの送受信だけでなく,特定の関数をリモートから実行させる仕組みと考えて下さい.サービスのリクエストに対して,その成否結果を返すことが出来ます.

また,コンフィグレーションという機能を使えば,RTCの実行時におけるパラメータを編集することが出来ます.簡単な例だと,モーターコントローラのゲインなどを実行中に変更する仕組み,でしょうか.データポートでも数値を変更する仕組みを提供できますが,コンフィグレーションはもっと簡易で,通信頻度の低い通信を指向しており,ツールなどから変更することを前提としています.

ROSではトピックで通信

ROSでは,データの送受信はトピックを使います.トピックはROSの世界に漠然と存在するクラウド的サービスと考えて下さい.ですので,ROSの世界にはノード間の接続という概念はありません(正確に言うとあるんですが).ノードは必要なトピックにアクセスして,データを受け取ります.マスターを中心としたシステムにカメラ画像などのサービスが存在していれば,それをサブスクライブすることで受け取ることが出来ます.
同種のトピックが多数あるときは,トピックのネームスペースを変更して対応します.たとえばロボットの左右のカメラを/left/image, /right/imageなどに分けてトピックとして立てておくことが出来ます.

また,「サービス」という仕組みが提供されています.これは,データの送受信ではなく,ある操作に対して,そのレスポンスを受け取るような場合に使います.
サービスも同様のクラウド的な仕組みを提供しています.サービスポートのように接続を必要とするものではありません.

またパラメータという仕組みはOpenRTM-aistにおけるコンフィグレーションと同じようなサービスを提供します.

比較

提供する機能としては大きな差はありません.データの送受信にはデータポートとトピック,それ以外のやり取りにはサービスポートやサービスという枠組みがあり,コンフィグレーションやパラメータの仕組みで細かい調整が出来ます.
トピックを使った発行購読モデルのROSには接続の面倒さが無いようですが,実際は実行時にネームスペースを指定したりするので面倒さは同じです.roslaunchなどのツールで自動化できますが,これもrtshellがありますし,自作の接続ツールを作るのは簡単です.このサイトの入門記事をご覧くださいね.

実行

OpenRTM-aistではManager

OpenRTM-aistではRTCを実行する仕組みとしてManagerというツールがあります.
Managerで実行する場合は,C++ではDLLとしてRTCを作成し,ManagerからRTCを読み込み,実行します.PythonではPythonスクリプトを直接読み込めます.JavaではJarファイルにしてManagerから読みだします.
このManagerが提供するサービスは複数のRTCを同時に実行する場合に非常に強力で,マネージャーのコンフィグレーションファイルを編集することで設定できます.

ただ,これだけではOpenRTM-aistのシステムは実行されません.RTC間の接続やコンフィグレーション,状態マシンのアクティベーションが必要で,この部分はEclipse上のグラフィカルなツールを使うか,rtshellというコマンドラインツールを使います.どちらも接続やコンフィグレーションを記述してあるRTシステムプロファイル (RTSP) というxml形式のファイルに対応しているので,一度システムを接続してプロファイルを保存しておけば,実行はそれほど大変ではありません.

ROSはroslaunch

ROSには接続という概念がありませんので(正確にはある),ノードの実行と,ネームスペースのリマッピングがすべてです.これを行うroslaunchという仕組みがあります.

launchファイルと呼ばれるxml形式のファイルを書くと,そこに書かれたノードが一発で起動します.
また,トピックやパラメータをリマップすることができ,またパラメータの初期値も設定できるので,このroslaunch一発でシステムを構築できます.
論文によっては,起動時の順序などが設定できないのが不満点らしいです.機能安全とか考えると問題になるようで.

if節とか使うと,一つのファイルで設定をいろいろ変えたりできたり便利なんですが,これ自体が新しいプログラミング言語と化してて,そこまで使うなら別ファイルにした方がいいですね.
includeを使えるのがRTSPよりも素晴らしい点かな.

naoqiと比較

Pepperが有名になって,naoqiについて書かれているページも増えてきました.それに伴いROSとかRTMとかに言及する評論家がいたりしますが,結構,トンチンカンなことを書いてたりして,それをまず修正するのが大変,というのがありました.
naoqiも一応はミドルウェアという性格を持っています.言語としては,Java, Python, C++で書けます.OSもWindows, Linux, OSXです.昔はC#やMATLABをサポートしていて素晴らしかったのですが,もうサポートする気がないのかな・・・

ネットワーク越しに分散システムを構築できる点ではROSやRTMと変わりませんが,独自のデータ型を作ることができず,使えるデータ型が,整数,実数とその配列という程度です.これが不便.
たとえば,カメラ画像を受け取る時に,配列でデータが来て,0番目が幅,1番目が高さ・・・などと配列で送ってきます.
正直,不便だし,いちいちマニュアルみないといけないので,まあ,PepperやNAOを触る部分だけこれで書いて,あとはROSにつなげましょうよ,という雰囲気です.
RTMからもnaoqiに接続することができます.尾形研でPython版のコンポーネントを公開してます.

そのほか

OpenRTM-aistの強みは,RTコンポーネントという国際規格に準拠しているだけあって,用語の整理や実行管理の仕組みが非常に洗練されています.特に実行コンテキストを使った実行状態管理が秀逸です.
OMGが管理するので,多くのオブジェクト指向言語からこのRTコンポーネントモデルを利用することが可能であり,コーディングスタイルまで共有することが出来ます.
実行コンテキストはRTCの実行をつかさどるオブジェクトで,RTCの状態変化時や周期実行タイミング時に呼ばれる各種のコールバックを呼び出します.実行時に実行コンテキストを変更することにより,作成されたRTCをシミュレータと同期しながら実行したり,リアルタイム周期実行したりすることが出来ます.
状態マシンを持っていることも重要で,RTCを遠隔から管理することが出来ます.

ROSは反対に,通信の仕組みを提供しているのみであり,状態管理などは各ノードの開発者に任せられています.多くのコードはPythonで書かれているため,通信の仕様自体もPython言語に親和性が高いようです.
チュートリアルを見ると,Pythonで書かれた場合と,C++で書かれた場合によってコードのスタイルが大きく異なります.Pythonの仕組みをC++に持ってくることはかなり面倒ですし,PythonはPythonなりに書ければいいんだというのは,Pythonプログラマの観点からは同意しますが,これから先,多くの,しかも玉石混交の後輩たちにROSを勧めるには二の足を踏む部分です.
特に僕のようなメカ系出身のロボット屋にROSに入りこませるのはかなりハードルが高いのでは,と思うのです.

OpenRTM-aistはPython版も提供していますが,こっちは逆にC++のRTCのコーディングに準拠した形になっていて,Python初心者でも見やすいです.
この辺で,プログラミングのモデル,コードの両方のレベルでOpenRTM-aist(RTミドルウエア)の方が持続性を感じます.

最近は自分の会社の仕事でもROSやRTMを使っていますが,ここで感じるのは文書化であったり,文書の正当性を担保するための方法という点で,RTMはかなりアドバンテージがあります.
RTMではコンポーネントのソースコードをコンパイルして実行した状態で,RTCの名前やポート名だけでなく,カテゴリなどの細かい情報を収集することができます.この情報と,コード生成時に使ったRTコンポーネントプロファイルを照らし合わせて,その正当性を担保することができます.また,RTCPから文書を自動生成することができるので,ドキュメント通りのRTCができていることを,自動的に保証することができます.
また,RTSPを使えばシステム全体の接続や実行時のコンフィグレーションも合わせて文書化できるため,非常に便利です.

ROSではノードを起動すると,トピックなどの情報は得られますが,サービスに関しては,サービスを利用する側の情報が手に入らないです.また,ROSLaunchでノードを複数起動すると,リマッピングされたパラメータがどのノードで利用されているのか,よくわからなくなります.僕はSysMLで設計した情報からROSのパッケージを生成するツールを作りましたが,逆変換は現状では暗礁に乗り上げた状態ですので,納品物のドキュメントの生成は手動でやらなくてはならないのが現状です.

で,結局,どうよ?

長く書いたので,結局どうよ?,と聞きたい(と思うのですが,あまりまとまらなかった・・・)でしょ?

自分でもいろいろと作ってきて,仕事でも使っていますが,特にロボット用ミドルウェアの指定がなければRTMを勧めます.以前は移動ロボットだとROSの方が強いと思っていましたが,自分や,早稲田大学の尾形研究室 (研究員してます)でナビゲーションに使うためのツールを揃えたので,それほど差を感じません.移動に関しては,まだROSの方がデフォルトで使えるものが多いのですが,お客さんの用意してる環境だと,環境に特化したナビゲーションがやっぱり必要になり,結局ゼロからというモジュールも少なくないのです.この場合,作ったものを文書化することなど踏まえて,RTMの方が楽ですね.また株式会社セックさんみたいなロボットソフトウェアをサポートしてくれる会社もあるので,お客さんに製品として長くサポートできるのはどっち,と聞かれると迷わずRTMと答えてます.機能安全RTMなんてのもあるので,説明がつきやすいです.ありがとう,NEDO知能化プロジェクト.

ただ,ROSの方が使えるモジュールが圧倒的に多いです.こんなのシラネーヨ,というデバイスがROSに対応してたりします.お客さんから「◯◯はROSのノードは見つかるんだけど,RTM用はないの?」と聞かれることがありますが,レアで高価なデバイスだとなかなか見つかりませんね.メーカーの人は自社製品をRTM対応したければ,当社にご連絡ください(笑)
それに,書き捨て,と割り切ればROSはかなり使いやすいです.研究者の人たちがROSが好きなのはよくわかりますね.
RTMでもPython版がありますし,書き捨て的に書くこともできますが,ROSは学ぶことが少ない状態でそこに入れるのが強みです.ただ,そうやって書いたものを後で持ってこられても,コード読むだけで時間かかるし,mainに全部書くなよ,というのをよく見ます.RTMだと,どこにどんな処理を書く,というのが決まってるので,汚くてもそれなりに意図を汲めます.

僕だと,RTCの状態で技術を貯めていって,ROSでもそれを利用できるようにする,というのが正解だと思っています.ROS2には激しく期待していますが,裏切られることもあるので・・・
だからRTCをROSから使う,という技術は僕ももう少し作りこみたいと思っています.東京オープンソースロボティクス協会がメンテナンスしてるRTM-ROS変換というのもありますが,もうすこしコンパクトなツールを用意できると思っていて,そのうち作ります.