WSL2環境下で構築したOpen-RMFで複数ロボットとエレベータの連携をシミュレーションできる環境で遊んでみる　タスクステータス取得編

# 1. はじめに
　[WSL2環境下で構築したOpen-RMFで複数ロボットとエレベータの連携をシミュレーションできる環境で遊んでみる　軌跡プロット編](https://qiita.com/bebebefu/items/4f525708768c5be74bfd)の記事では、ロボットの現在地を時系列データとして取得し、それを3次元プロットしてロボットの軌跡を可視化することができました。
　ただ、それだけですとロボットが何をしていたかということがわかりませんので、シミュレーション結果の分析としては情報が足りません。そこで今回はロボットのタスクのステータスを取得して、保存するということに取り組みたいと思います。

# 2. 実行環境
- CPU: CORE i7 7th Gen
- メモリ: 32GB
- GPU: GeForce RTX 2070
- OSと構築した環境: Window11でWSL2にUbuntu22.04をインストールした環境
- ROS2: Humble
- Open-RMFの構築環境：[WSL2の環境下において、Traffic-Editorを使って複数ロボットとエレベータの連携をシミュレーションできる環境を構築してみた](https://qiita.com/bebebefu/items/32dcb43db1213e1a00e0)の記事で構築した環境

# 3. 方針
　[[1]](#参考記事やサイト)のサイトで紹介されていますが、Open-RMFではブラウザからロボットにタスクを投げたりそのステータスを取得できるような機能がデフォルトで提供されています(RMF Demos Panelと言うそうです)。
　そして[[2]](#参考記事やサイト)のサイトで述べられているように、APIのエンドポイントも用意されており、以下のコマンドを実行すればタスクのステータスも取得できるようです。そのためこのコマンドを実行して得られる結果を基にpythonのプログラムを作成していきたいと思います。

```:terminal
curl http://localhost:8083/task_list
```
なお、ros2 topicを調べたところ/task_summariesというトピックがあったのですが、[[3]](#参考記事やサイト)のサイトよりもう使われていないらしいとのことでAPIからのステータス取得にしました。

注：RMF Demos Panelでタスクのステータスやロボットのステータスを表示することが最初はできませんでしたが、[[4]](#参考記事やサイト)のサイトを参考に以下のコマンドを打つことでこの時は解決しました。
```:terminal
sudo apt remove python3-websockets 
python3 -m pip install websockets==10.4
python3 -m pip install asyncio 
```
```:terminal
cd ~/rmf_ws
source /opt/ros/humble/setup.bash
export CXX=clang++
export CC=clang
colcon build --mixin release lld
```

# 4. 作成したプログラム
以下が作成したpythonのプログラムになります。1分毎にタスクステータスを取得するようにしています。なんでこのようにしたかというと、シミュレーションがいつ終わるか予想がつかない場合を想定してほっといても自動で取得できるようにしようという考えによります。

```python:get_tinyRobot_taskstatus.py
import requests
import csv
import schedule
import time

url = "http://localhost:8083/task_list"
csv_file = 'tasks.csv'
csv_columns = ['task_id', 'description', 'done', 'end_time', 'fleet_name', 'priority', 'progress', 'robot_name', 'start_time', 'state', 'submited_start_time', 'task_type']

def fetch_and_update_tasks():
    response = requests.get(url)
    tasks = response.json()
    
    # 既存のタスクを読み込む
    existing_tasks = {}
    try:
        with open(csv_file, mode='r', newline='') as csvfile:
            reader = csv.DictReader(csvfile)
            for row in reader:
                existing_tasks[row['task_id']] = row
    except FileNotFoundError:
        print("CSV file not found. Creating a new one.")

    # 新しいタスクまたは更新されたタスクで既存のデータを更新する
    for task in tasks:
        existing_tasks[task['task_id']] = task

    # CSVファイルに更新されたタスクリストを保存
    try:
        with open(csv_file, mode='w', newline='') as csvfile:
            writer = csv.DictWriter(csvfile, fieldnames=csv_columns)
            writer.writeheader()
            for task_id in existing_tasks:
                writer.writerow(existing_tasks[task_id])
    except IOError:
        print("I/O error")

# スケジューラー設定: 1分毎にタスクリストを更新
schedule.every(1).minutes.do(fetch_and_update_tasks)

# プログラムを無限ループ
while True:
    schedule.run_pending()
    time.sleep(1)
```

# 5. タスクステータス取得結果
実施したシミュレーションの設定方法や詳細な結果については[WSL2環境下で構築したOpen-RMFで複数ロボットとエレベータの連携をシミュレーションできる環境で遊んでみる　簡単な配送シミュレーションと得られた知見編](https://qiita.com/bebebefu/items/9a40afc707b1f5b6cb2c)の記事で記載しておりますので、そちらを参照いただきたく思いますが、以下の条件にてシミュレーションを行いました。

- 建物環境：[[5]](#参考記事やサイト)の記事で構築したエレベータ付きの2階建ての建物
- 使用ロボット：tinyRobot
- ロボット台数：2台
- 配送対象物：コーラ缶（[[6]](#参考記事やサイト)の記事で記載したシミュレーション結果より選定）
- タスク：4つの配送タスク(delivery)と4つの巡回(loop)

そしてシミュレーションを終えた後のRMF Demos Panelの様子は以下です。右側にそれぞれのタスクの終了状況が表示されています。
![スクリーンショット 2024-03-24 182605.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3581920/8ed038bf-bda0-2e11-e5e4-a12be4645a61.png)

これらの情報を4章でお見せしたプログラムでcsvに保存しました。そしてその結果が以下になります。タスクの種類やどのロボットで対応したか、開始時間や終了時間などがわかります。
									
|task_id  |description  |done| end_time	|fleet_name|priority|progress|robot_name|start_time|state|submited_start_time|task_type|
|---|---|---|---|---|---|---|---|---|---|---|---|
|delivery.dispatch-1fe25d1e64 | Drop off nothing at [place:point_0_L2]| TRUE| 252.98|tinyRobot|0|100%|tinyRobot_1|28.13|Completed|25.94|Delivery|
|delivery.dispatch-ce589bbfe3| Drop off nothing at [place:point_1_L2]| FALSE| 199.46|tinyRobot|0|99%|tinyRobot_2|78.3|Standby|87.05|Delivery|
|patrol.dispatch-fa208c43ce	| Moving the robot from [place:tinyRobot_1_charger] to [place:point_0_L2]| FALSE| 682.04|tinyRobot|0|99%|tinyRobot_1|483.36|Standby|481.1|Patrol|
|patrol.dispatch-8e1efa45f6| Moving the robot from [place:tinyRobot_2_charger] to [place:point_1_L2]| FALSE| 609.3|tinyRobot|0|99%|tinyRobot_2|485.75|Standby|481.4|Patrol|
|delivery.dispatch-67547f4d75| Drop off nothing at [place:point_0_L2]| TRUE|1145.8|tinyRobot|0|99%|tinyRobot_1|927.61|Failed|925.32|Delivery|
|delivery.dispatch-fb83d11886| Drop off nothing at [place:point_1_L2]| TRUE| 1097.21|tinyRobot|0|99%|tinyRobot_2|977.78|Failed|985.72|Delivery|
|patrol.dispatch-f43798b4fe|Moving the robot from [place:tinyRobot_1_charger] to [place:point_0_L2]|FALSE| 1588.81|tinyRobot|0|99%|tinyRobot_1|1392.18|Standby|1389.89|Patrol|
|patrol.dispatch-1d93d99beb|Moving the robot from [place:tinyRobot_2_charger] to [place:point_1_L2]| FALSE| 1519.64|tinyRobot|0|99%|tinyRobot_2|1394.47|Standby|1390.19|Patrol|

# 6. まとめ
上記の手順にて今回の主目的であった、ロボットのタスクのステータスを取得して、保存することに成功したと考えられます。今後は、これを使って配送シミュレーションのデータ分析などをしていくことや、他のソフトウェアとの連携などを試してみたいと考えています。

# 参考記事やサイト
[1][open-rmf/rmf_demos](https://github.com/open-rmf/rmf_demos)
[2][rmf_demos/rmf_demos_panel/README.md](https://github.com/open-rmf/rmf_demos/blob/main/rmf_demos_panel/README.md)
[3][/task_summaries topic is no longer used? #189](https://github.com/open-rmf/rmf/discussions/189)
[4][[Humble, simple-api-server] Websockets 9.1 from ubuntu offical ppa doesn't seem to work #169 ](https://github.com/open-rmf/rmf_demos/issues/169#issuecomment-1331904134)
[5][WSL2の環境下において、Traffic-Editorを使って複数ロボットとエレベータの連携をシミュレーションできる環境を構築してみた](https://qiita.com/bebebefu/items/32dcb43db1213e1a00e0)
[6][WSL2環境下で構築したOpen-RMFのRMF Demosにおいて、tinyRobotに配送させるものを検討してみた](https://qiita.com/bebebefu/items/9d2081b62dbcc7d1cc1d)