Rowma: ROSロボットネットワーク化システム

## Rowmaとは
RowmaはROSロボットの**ネットワーク化**を実現するシステムです。ロボットがやりとりするトピックの流れを**ロボット同士**、またはSDKにより実装された**アプリケーションとロボット間**で自由に**動的に組み替える**ことができます。なおRowmaはOSSであり[GitHubに公開](https://github.com/rowma)されています。

Rowmaにより既存のROSワークスペースを変更すること無く、簡単にROSベースロボット同士をインターネット越しに接続できます。

概要図をこんな感じに書いてみました。まず1つ目の図はRowmaネットワークに接続されたロボットやアプリケーションが相互にトピックをやり取りする様子です。任意のトピックを任意の宛先に送ることができます。

![image (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131581/9f95db2c-ece5-49de-7ca1-8acf78c31ea7.png)

次はロボット中で実行しているアプリケーションを切り替えながら実行する図になります。簡単に言うと遠隔rosrun/roslaunch実行にフォーカスした図です。Rowmaは実装開始当初ただの遠隔実行システムでした。

![image (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131581/e38ab3ab-8d89-fac6-232f-51b1f763630d.png)

最後にデータの向き先の変更についての図です。Rowmaでは接続しているロボットやアプリケーション同士で相互にデータを送り合えます。そして分岐によって別のデータを別の宛先に送るように変更することも可能です。

![image (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131581/b0df0d40-f89c-d3de-de37-a63aec0079d6.png)

詳しいドキュメントは[こちら](https://rowma.github.io/documentation/en/getting-started)になります。

## 機能
以下はRowmaの特徴、機能です。

* 既存ワークスペースへの簡単な組み込み
* スマホやWebブラウザからの**rosrun/roslaunchの遠隔実行**
* **ROSトピックの遠隔Publish/Subscribe**
* 新規ROSノードの遠隔追加(Pythonのみ)
* **ROSロボット同士**の遠隔トピック送受信
* **SDK**の提供

## 何ができるか
とりあえず作成者が思いつくあり得るユースケースをいくつか書きます。

* **複数ロボットでのマップ作成**
* サーバーサイドでのオンラインデータ処理
* ロボットによる別ロボットの操作
* スマホによるロボットの**遠隔操作**

## システムのウリ
「ロボット同士の接続ならROSやRTM等でもできるよ」などの意見があると思うのでそれに対する答えを書いておきます。

一番大きな違いは**SDKの存在**です。SDKがあることによりROSの環境不要でセンサーデータをやりとりできるようになります。例えばPython SDKを使うことにより、Pythonのスクリプト中でトピックのデータを送受信することができます。

他にも例えばROSも何もセットアップしていないmacOSのPCで`pip install rowmapy`をして簡単なサンプルスクリプトを実行するだけでROSのデータをそのPCでやり取りできます。

## 使い方
ひとまずRowmaを使ってみるために[PublicConsole](https://rowma.github.io/public-console/)というものを提供しています。

![image (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131581/c4277abe-6baf-8409-344c-47c6c1e7947c.png)

以下はチュートリアル動画です。(YouTube)

[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/qsg2IaK5GQU/0.jpg)](http://www.youtube.com/watch?v=qsg2IaK5GQU)

ここではPublic Consoleを使って任意のroslaunchコマンドを実行します。

### 1. ロボット側の操作
まずロボット側でRowma ROSパッケージをROSワークスペース中にインストールします。以下のコマンドをターミナルで実行してください。インストーラースクリプトが走ります。

```bash
$ python <(curl "https://raw.githubusercontent.com/rowma/rowma_ros/master/install.py" -s -N)
```

インストールが完了したら以下のコマンドでノードを起動します。roscoreは立ち上げておいてください。

```bash
$ rosrun rowma_ros rowma
```

立ち上げるとUUIDが表示されます。

### 2. Public Consoleでの操作
次に https://rowma.github.io/public-console/ にアクセスしてください。アクセスしたらまず一番上の`Network URL`が`https://rowma.moriokalab.com`であることを確認してConnectボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131581/0abb52a9-97dc-3dae-7be0-98c3ba0e50e1.png)

できたら次に`Select Your Robot's UUID`欄でロボットで表示されたUUIDにチェックを入れてConnectボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131581/d5a918f3-a2f3-144c-79de-9a515a98d3a6.png)

そして少し下にスクロールして`Select a roslaunch command`で任意のroslaunchコマンドを選択しExecuteボタンを押します。なお、roslauncコマンドが実行されるとログもブラウザに表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131581/de2f2213-8c64-0193-c0f9-590ce8f3971d.png)


## システム構成概要
Rowmaは**ConnectionManager、Rowma ROS、各種SDK**の3つで構成されています。ROSロボットとSDKで実装されたアプリケーションがConnectionManagerに接続され、ConnectionManagerを経由してデータがやり取りされます。通信には**WebSocket(Socket.io)**を使っています。
![image (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131581/afbd6bdb-5fc5-cd11-ad0e-2a38d9fc9765.png)

## ConnectionManager
ConnectionManagerは**WebSocketサーバー**であり、**ロボット**と**アプリケーション**を接続します。ネットワーク機器で言うとスイッチのような役割です。ConnectionManagerは接続されたロボットとアプリケーションに**UUID**を発行して管理します。

WebSocket関連は[Socket.io]()で実装しています。そしてWebSocketとROSの通信は[rosbridge](http://wiki.ros.org/rosbridge_suite)を使って行っています。便利です。

[GitHub rowma/rowma](https://github.com/rowma/rowma)

## RowmaROS
ロボットからRowmaに接続するためのWebSocketクライアントとしてRowma ROSを使います。Rowma ROSの主な役割は(1) `ROS_PACKAGE_PATH`から有効なワークスペースを調べrosrun/roslaunchで実行できるコマンドのリストを取得する、(2) ワークスペース情報やトピックやコマンドをConnectionManagerと送受信する、(3) ノードのキルと実行、等です。

[GitHub rowma/rowma_ros](https://github.com/rowma/rowma_ros)

## SDK
**JavaScript**と**Python**でSDKを提供しており、Rowmaアプリケーションを実装できます。RowmaアプリケーションもConnectionManagerにWebSocketクライアントとして接続し、接続ごとにUUIDが発行されます。

### JavaScript SDK
JS SDKは`npm install rowma_js`でインストールすることができます。JS SDKは主に**Webフロントエンド**の実装に使います。上述のPublicConsoleもこのSDKを使っています。

Reactと組み合わせるチュートリアル記事を書きました。[ROSトピックをインターネット経由で送受信できるWebフロントエンドの作成チュートリアル(React + ROS + Rowma)](https://qiita.com/asmsuechan/items/ed326ba28b05c4e415e1)

リンク: [GitHub](https://github.com/rowma/rowma_js), [ドキュメント](https://js.rowma.io)

### Python SDK
Python SDKは`pip install rowmapy`でインストールすることができます。

Publishのサンプルコードはこれです。**ROSいらずで任意のトピックをPublish**できます。Subscribeもできます(ドキュメント参照)。

```python
from rowmapy import Rowma
rowma = Rowma()
rowma.connect()

robot_uuid = 'xxxx-xxxx-xxxx'

rowma.publish(robot_uuid, '/chatter', { "data": "topic from python" })
```

リンク: [GitHub](https://github.com/rowma/rowmapy), [ドキュメント](https://python.rowma.io)

## その他
### 独自ConnectionManager
デフォルトだとRowmaROSもSDKも公開サーバーに接続します。公開サーバーは主に**テスト用のお試し環境**である想定で、公開サーバーに接続しているロボットは誰でも操作することができます。公開されると困る人は**自前でConnectionManagerを立ててプライベートサーバーを立てる必要があります**。

ConnectionManagerのリポジトリは[こちら](https://github.com/rowma/rowma)です。以下のコマンドでポート3000番にWebSocketサーバーが立ちます。

```bash
git clone https://github.com/rowma/rowma
cd rowma
npm i
npm run build && npm start # ポートを変えるならROWMA_PORT=3001 npm startとする
```

ロボットをlocalhostのサーバーに繋ぐには`ROWMA_SERVER_URL`に値をセットして接続します。

```bash
ROWMA_SERVER_URL=http://localhost:3000 rosrun rowma_ros rowma
```

デフォルトだとデータはプログラム中の配列に保存されます。ちなみに`ROWMA_DB=mongodb`とすると**mongodb**も使えます。使う場合はもちろん別でmongodbも立てます。

### 認証認可
**認証認可用のサーバー**を立てることでRowmaもこれを実現することができます。例えば「AdminであるAさんはトピックを送信できるがReadonly UserであるBさんはトピックの送信はできない」などです(認可の例)。具体的には`POST: /AUTHENTICATOR_URL/applications/authorize`を使います。実装は少しOPAの考え方を参考にしました。

### クラウド構成
公開サーバーはAWSの**Fargate**にCircleCIからデプロイしています。実質ただのWebSocketサーバーなのでALBには[Sticknessを設定](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/classic/elb-sticky-sessions.html)しています。

### Fluentd連携
トピックのデータをFluentdに流すことができます。連携するにはrowma_ros起動時に`ROWMA_FLUENTD_ENABLED=True ROWMA_FLUENTD_HOST=localhost ROWMA_FLUENTD_PORT=24224 rosrun rowma_ros rowma`のようにすれば連携できます。どのトピックをFluentdに流すかは次に示すrowma.yamlで指定できます。

### rowma.yaml
rowma.yamlによってRowma ROSのトピックの向き先やFluentdに転送するトピック名、ファイルに吐き出すトピック名を起動時に指定することができます。

`rosrun rowma_ros rowma ./rowma.yml`のようにrosrunの第三引数にファイルのパスを渡してやるとそれを読み込みます。なお、カレントディレクトリにrowma.ymlが存在する場合はデフォルトでそれを自動読み込みします。

```yaml:rowma.yml
topic_destinations:
  - destination:
      type: robot
      uuid: abc-abc*
    topic: /chatter
  - destination:
      type: robot
      uuid: abc-def-ghi
    topic: /test

fluentd_stream_topics:
  - topic: /piyo

file_outputs:
  - topic: /chatter
    filepath: ./topiclog
```

### 遅延
一応遅延は計測してあります。詳しくは[ここ](https://rowma.github.io/documentation/en/delay)をご覧くださいって感じなのですが、感覚的には北陽のLiDARを動かしても特に問題は感じなかった、という具合です。

ロボット同士で通信をする際の遅延の計測結果のグラフを下に示しておきます。横軸がデータのサイズ、縦軸が遅延時間です。遅延時間は往復時間を1つのPCで測っているので時間のズレによる誤差は発生していないはずです。黒い線がConnectionManagerをAWSに置いた環境での結果、青い点線が同じネットワーク内にConnectionManagerを置いた環境での結果です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131581/83c95bb0-1bfe-6606-a27a-0cd153279bef.png)

### ROS2対応
[rowma/rowma_ros2](https://github.com/rowma/rowma_ros2)がROS2用パッケージです。今の所ros-dashingでしか動きません。

## 終わりに
Rowmaはまだベータ版です。気になることがあればお気軽にコメントください。