古いロボット掃除機をアップグレード！

# 要約
- ロボット掃除機に進入禁止エリア設定機能を自作実装
- 非公式(?)WebAPIを活用し、センサ・マイコンを追加搭載せず実現

:::note warn
本記事の内容は、[BESTEK ロボット掃除機 MAPi](http://www.bestek.co.jp/item/products/products03/2150) にのみ適用可能です。
:::

# 目次
1. [背景・目的](#1-背景目的)
2. [解決策の検討](#2-解決策の検討)
3. [解決策の実装](#3-解決策の実装)
    3.1. [設計](#31-設計)
    3.2. [実装](#32-実装)
    3.3. [動作確認](#33-動作確認)
4. [まとめ](#4-まとめ)
5. [(おまけ)パケット解析](#5-おまけパケット解析)

# 1. 背景・目的
2018年から[ロボット掃除機](http://www.bestek.co.jp/item/products/products03/2150)を愛用しているが、
最近住まいの間取りが変化したことを期に、進入禁止エリアを設定したい要求が出てきた。
最近のロボット掃除機は[SWで進入禁止エリアの設定](https://service.irobot-jp.com/1/keep_out_zone)や[バーチャルウォールの設置](https://store.irobot-jp.com/item/4491744.html)が可能らしいが、うちの子にはそのような機能はない。
[センサやマイコンを追加搭載して制御する方法](https://myenigma.hatenablog.com/entry/2019/08/18/135335)もあるようだが、電源周りや機器固定など設計要素が多そうで大変そう。そもそもうちの子はできるのか不明。
買い換えもありだが、未だ使える掃除機を捨てるのももったいない。

上記背景から、進入禁止エリアを設定する解決策を検討〜実装した。

# 2. 解決策の検討
ロボット掃除機の仕様と解決方針を示す。

## 2.1. ロボット掃除機の仕様

愛用中の[ロボット掃除機](http://www.bestek.co.jp/item/products/products03/2150)は、WebAPIで各種情報取得や状態制御が可能な機種である（2018年時点でここまでできる機種は本機のみだったと記憶している、私が調べた範囲だが）。

非公式ではあるものの、[先人がWebAPIを発見してくれており](https://deathon2legs.blogspot.com/2018/02/bestekmapi.html)、この知見をフル活用させていただく。

WebAPIを以下表にまとめる。
地図情報や自己位置情報、掃除済みエリア情報などの取得や、掃除開始・停止・ドック帰還などのざっくりした制御が可能であるが、細かい制御はできない。

| 用途 | WebAPI |
|-|-|
|ロボット掃除機の情報取得（名前など）|/get/robot_id|
|ステータスの取得（バッテリー残量など）|/get/status|
|イベントログの取得（全部）|/get/event_log?last_id=0|
|MAP系の取得|/get/feature_map|
||/get/n_n_polygons|
||/get/cleaning_grid_map|
||/get/rob_pose|
|掃除開始|/set/clean_start_or_continue?cleaning_parameter_set=1<br>(cleaning_parameter_set=2だとちょっと静か)|
|スポット掃除開始|/set/clean_spot?map_id=0&x1=999&y1=999&cleaning_parameter_set=1<br>(cleaning_parameter_set=2だとちょっと静か)|
|掃除停止|/set/stop|
|充電ドックへ戻る|/set/go_home|

## 2.2. 解決方針
大別すると①環境を改善するか or ②ロボットを改良するか、になると考え、
各要件や制約の観点から以下表で整理した。
今回は、コストがかからず手軽に実現できそうな __「②-2　ロボットを改良（SW変更）」__ で進めることにした。
不正アクセスで夜中にロボット掃除機が暴走して寝不足になるリスクはあるが、容認する。

||可用性|性能・拡張性|運用・保守性|移行性|セキュリティ|環境・エコロジー|コスト|備考|
|-|-|-|-|-|-|-|-|-|
|①-1 環境を改善（引っ越す）|o|o|o|o|o|o|x|今は無理|
|①-2 環境を改善（柵を設置する）|o|o|o|o|o|o|x|利便上、通路に柵は置きたくない|
|②-1 ロボットを改良（買い換える）|o|o|o|o|o|x|x|お財布と要相談|
|②-2 ロボットを改良（SW変更）|o|o|x|o|x|o|o|APIがあるから大雑把な制御は可能|
|②-3 ロボットを改良（HW&SW変更）|o|o|x|o|x|o|x|実装も保守も大変そうダナ|


# 3. 解決策の実装

設計〜実装していく。

## 3.1. 設計
処理フローは以下とする。とりあえず。

　1. WebAPIを使用して、地図・自己位置の情報を取得する
　2. 自己位置と進入禁止エリアを比較する
　3. 進入禁止エリアに入った場合、指定ポイントへ移動する

## 3.2. 実装
愚直に実装した。詳細は[GitHub](https://github.com/soyaoki/MAPi-Control)で。

あまり本筋ではないが、掃除済み情報のデコードで躓いた。
気になる人は以下からどうぞ。

<details><summary>掃除済み情報のデコードについて</summary>

API `curl -v 192.168.1.23:10009/get/cleaning_grid_map` を叩くと、以下が返される。
```
{
"map_id":2, 
"lower_left_x":-1548, 
"lower_left_y":-1714, 
"size_x": 43, 
"size_y": 50, 
"resolution": 40, 
"cleaned": [1,91,1,40,3,40,3,40,3,40,3,1360,2,1,4,36,8,35,8,35,8,35,7,36,6,37,6,37,7,36,8,38,5,39,3,89], 
"timestamp":9309238
}
```
ここで`cleaned`が掃除済みエリアを表しているわけだが、結局
- `lower_left_x`、`lower_left_y`を基準に、x方向に`size_x`マス、y方向に`size_y`マス、分解能を`resolution`とする格子状の地図を作る
- その地図において、左下のマスから`cleaned[0]`マス分右に"cleaned"、そこから`cleaned[1]`マス分右に"not cleaned yet"、そこから`cleaned[2]`マス分右に"cleaned"、…

初見だと何がなんだかわからなかった、1日使った。
データ量を圧縮する狙いなんだろうなと思う、気持ちはわかる開発者さん。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628135/04f3ccf4-8db8-4fe5-81c9-039c428c3398.png)


</details>

## 3.3. 動作確認
動いた。ハッピーハッピーハッピー。
黃星が自己位置、青ひし形がドック、赤破線より左、緑破線より下が進入禁止エリアとなっている。
赤破線を超えると、ドックに向って帰る。ちなみに青は掃除済みエリア。
![ezgif-3-911d5bc606.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628135/a9164475-628f-d913-2f71-a3bfd5077dc6.gif)


# 4. まとめ
- ロボット掃除機に進入禁止エリア設定機能を自作実装した
- 非公式(?)WebAPIを活用し、SWの追加変更だけで実現した
- 実装コスト(自分の稼働コストのみ) は、__¥2,000/h*約24h = 約¥48,000__
    - あれ、新しい掃除機買えたのでは…
- 現在はLaptopでの一時的な制御に留まる、今後は定置ラズパイ等で常時稼働させたい
    - あれ、新しい掃除機買えたのでは…

# 5. (おまけ)パケット解析

Wiresharkでパケットキャプチャしてみた。
MacBookに接続したiPhone/iPadで[本機制御アプリ](https://apps.apple.com/jp/app/xrobot-app/id1153466898)を使用しながらキャプチャした。
[こちら](https://zenn.dev/yken/articles/c00bbe7c365043)がとても参考になった。

![ezgif-7-85ba897a47.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628135/37b6abc3-3bc8-6933-d73e-c364d5337ebe.gif)

APIは前述の表がすべてのようです。