ルンバをM5 Atomでお手軽ハックしてラジコン化する

ルンバのシリアルインタフェースにM5 Atom liteを接続してハックします

Atom liteを使用しますがUARTが使えるマイコンなら何でも大丈夫だと思います

色々な事ができるのですがまずルンバをラジコン化してみました

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ルンバをPS3コントローラでラジコン化できました＼(^o^)／<br><br>シリアルポートとGPIOを直結してUARTでコマンド送るだけで簡単に制御できました(ﾟ∀ﾟ)<br><br>これQiitaの記事にまとめた方がいいですかね？🤔<a href="https://twitter.com/hashtag/M5Stack?src=hash&amp;ref_src=twsrc%5Etfw">#M5Stack</a> <a href="https://twitter.com/hashtag/M5ATOM?src=hash&amp;ref_src=twsrc%5Etfw">#M5ATOM</a> <a href="https://t.co/3CVb3t1xRt">pic.twitter.com/3CVb3t1xRt</a></p>&mdash; もけ@ムギ㌠ (@coppercele) <a href="https://twitter.com/coppercele/status/1368281460981915648?ref_src=twsrc%5Etfw">March 6, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

##使用するデバイス##

ATOM Lite - スイッチサイエンス
https://www.switch-science.com/catalog/6262/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/71d7a92e-6e3c-ecd1-9881-32d1a900ab9d.png)
M5Stackシリーズの中で最もコンパクトな開発モジュールで、サイズはわずか24 x 24 mmです。M5StickCに比べGPIOピンを多く持ち、小型の組み込みデバイス開発に適しています。メインコントローラとして、ESP32-PICO-D4チップを搭載しているので、Wi-FiとBluetooth、4 MBの内蔵SPIフラッシュメモリを利用できます。(スイッチサイエンスさんから引用)

M5シリーズの中で一番小さくて手軽なAtom liteを使用しました
Atom liteで出来るなら他のマイコンでも使えるだろうと思ったので

##ルンバとマイコンを接続する##

ルンバにはOpen Interface (OI)という規格があり仕様が公開されています

これは自分が所有してる600番系ルンバの仕様書です。バリエーションによっていくつかPDFがあるようです
iRobot Roomba 600 Open Interface Spec
https://www.irobotweb.com/~/media/MainSite/PDFs/About/STEM/Create/iRobot_Roomba_600_Open_Interface_Spec.pdf

下調べでこちらのサイトなどを参考にさせていただきました

ルンバの制御用USBシリアルケーブルを綺麗に作りたいときのメモ - cvl-robot's diary
https://cvl-robot.hateblo.jp/entry/2017/08/28/173943
ルンバにスピッツを演奏させてみた | curious4dev
http://curious4dev.mydns.jp/post-1463/

まずルンバの上ブタを外すとmini DIN7ピンのシリアルポートが出てきます
フタは爪で止まっているので壊さない程度に力づくで外しましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/5d0f14ff-eaa2-f646-711c-fc029584514d.png)

仕様書を見ると7がGND,4がTXD,3がRXDだと分かります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/65f859d5-e0af-2863-b5b7-91ffc15c750e.png)

ジャンパケーブルを使ってマイコンと接続します
自分はAtom mateという基板を介して接続しましたがGPIOが上に向いてるマイコンだったら直接つないでもいいと思います

ATOM Mate - スイッチサイエンス
https://www.switch-science.com/catalog/6532/


**注意：ルンバのRX,TXは5Vなので本来3.3VのAtom liteを接続するときはレベルシフタ、ロジックレベルコンバータを使いましょう！**
**ESP32は5Vトレラントじゃないはずなのになぜか壊れないのですがメーカー非推奨なので自己責任で**

NTB0104 レベルシフタ ピッチ変換済みモジュール - スイッチサイエンス
https://www.switch-science.com/catalog/2351/

電源はルンバのVpwrの15vを降圧させるのが王道かと思いますが
USBかTailbat(Atom liteの下につながってる細長い奴)から供給しています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/0ae7623c-ec87-198a-507e-d9a5a952cf45.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/b586df40-b0ec-9c14-c3df-d88224116ebb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/e5b51809-4b89-257e-7517-73bf0630a250.png)

##ルンバと通信する##
仕様書に通信の仕様が載っているので設定を合わせればUARTで通信できます

基本的にはOPcodeに続いて必要ならDataByteを送信するだけという簡単なプロトコルになっています
ルンバを自由に操作するにはsefe modeに入れないといけないので
Start(128)の後にSafe(131)コマンドを送ります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/1310910a-55fd-b57c-ec98-a07f5c224cbc.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/22c34a32-94e9-7fda-d3fa-973d59f7a018.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/7361e222-3ddc-a070-1c73-cc50785bf374.png)


```cpp

void setup() {
  M5.begin();
 
  // UART通信設定
  Serial1.begin(115200, SERIAL_8N1, 25, 21);
  // start
  Serial1.write(128);
  delay(50);
  // safe mode
  Serial1.write(131);
  delay(50);
  Serial.println("inited");
}
```
Safe modeに入ったらあとはコマンドを送れば何でもできるのですが、
今回はラジコンとして操作して遊んでみるので吸引(144)と移動(146)のコマンドを使用します

Opcodeに続けてDataBytesを送ることで実行できます

参考にしたサイトではDataBytesの間にdelay入れてたけど自分の環境ではなぜか動作がおかしくなったので入れてませんが
上手く動かないようならdelayを入れてもいいかもしれません

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/b995b6a1-9fd2-8d30-810f-ab701e3f3e98.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/33589e62-8f8d-5f3d-a00f-2b3a8b93293b.png)

```cpp
void move(int16_t left, int16_t right) {
  // 移動
  Serial1.write(146);
  //   delay(20);
  Serial1.write((right & 0xFF00) >> 8);
  //   delay(20);
  Serial1.write(right & 0xFF);
  //   delay(20);
  Serial1.write((left & 0xFF00) >> 8);
  //   delay(20);
  Serial1.write(left & 0xFF);
}

void vacuum(bool on) {
  Serial1.write(144);
  //   delay(20);
  Serial1.write(on ? 100 : 0);
  //   delay(20);
  Serial1.write(on ? 100 : 0);
  //   delay(20);
  Serial1.write(on ? 100 : 0);
}
```

##コントローラで操作する##
コントローラとしての送信機についてはスマホのバーチャルパッドやジャイロで操作したりといろいろあると思いますが
いろいろ試した結果物理コントローラが最適だと思ってます(異論は認める)
小学生に操作させてみると動かす対象に目が行ってしまうので手元がおろそかになって思い通りに動かせないんですよね

皆さんはPS3コントローラにこだわる必要はないと思いますのでBlynkとかM5StickCのジャイロとか好きな方法で動かしてください

そして物理コントローラにもBLE HIDとかBT classicいろいろあるのですが入手性と安定性を重視してPS3コントローラを使用します

ライブラリマネージャからインストールできるので手軽です
詳しくはこちらの記事を参照してください

ESP32(M5StickC)をPS3コントローラで操作する - Qiita
https://qiita.com/coppercele/items/0724b0b951868044223b

十字ボタンで移動、スタートボタンで吸引開始、セレクトボタンで吸引停止という動作にするとこのような実装になります

```cpp
#include <Arduino.h>
#include <M5Atom.h>
#include <Ps3Controller.h>

void move(int16_t left, int16_t right) {
  Serial1.write(146);
  //   delay(50);
  Serial1.write((right & 0xFF00) >> 8);
  //   delay(50);
  Serial1.write(right & 0xFF);
  //   delay(50);
  Serial1.write((left & 0xFF00) >> 8);
  //   delay(50);
  Serial1.write(left & 0xFF);
}

void vacuum(bool on) {
  Serial1.write(144);
  //   delay(50);
  Serial1.write(on ? 100 : 0);
  //   delay(50);
  Serial1.write(on ? 100 : 0);
  //   delay(50);
  Serial1.write(on ? 100 : 0);
}

bool up;
bool down;
bool right;
bool left;

void notify() {
  if (Ps3.event.button_up.select) {
    Serial.println("Released the select button");
    vacuum(false);
  }

  if (Ps3.event.button_up.start) {
    Serial.println("Released the start button");
    vacuum(true);
  }

  if (Ps3.event.button_down.up) {
    Serial.println("Started pressing the up button");
    up = true;
  }
  if (Ps3.event.button_up.up) {
    Serial.println("Released the up button");
    up = false;
  }

  if (Ps3.event.button_down.right) {
    Serial.println("Started pressing the right button");
    right = true;
  }
  if (Ps3.event.button_up.right) {
    Serial.println("Released the right button");
    right = false;
  }

  if (Ps3.event.button_down.down) {
    Serial.println("Started pressing the down button");
    down = true;
  }
  if (Ps3.event.button_up.down) {
    Serial.println("Released the down button");
    down = false;
  }

  if (Ps3.event.button_down.left) {
    Serial.println("Started pressing the left button");
    left = true;
  }
  if (Ps3.event.button_up.left) {
    Serial.println("Released the left button");
    left = false;
  }
  // ナナメ
  if (up && right) {
    move(100, 50);
    return;
  }
  if (up && left) {
    move(50, 100);
    return;
  }
  if (down && right) {
    move(-100, -50);
    return;
  }
  if (down && left) {
    move(-50, -100);
    return;
  }

  if (up) {
    move(100, 100);
    return;
  }
  if (down) {
    move(-100, -100);
    return;
  }
  if (right) {
    move(50, -50);
    return;
  }
  if (left) {
    move(-50, 50);
    return;
  }
  // 何も押されてなければ停止
  move(0, 0);
}

void onConnect() { Serial.println("Connected!."); }
void onDisconnect() { Serial.println("Disconnected!."); }
void setup() {
  //   Serial.begin(115200);
  M5.begin();
  Serial1.begin(115200, SERIAL_8N1, 25, 21);
  // start
  Serial1.write(128);
  delay(50);
  // safe mode
  Serial1.write(131);
  delay(50);
  Serial.println("inited");

  // PS3コントローラ設定
  // notifyで動作
  Ps3.attach(notify);
  Ps3.attachOnConnect(onConnect);
  Ps3.attachOnDisconnect(onDisconnect);
  // 接続するESP32のBLEアドレスに変更する
  Ps3.begin("00:01:02:03:04:05:06");
}

void loop() {
  delay(1);
}

```

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ルンバをPS3コントローラでラジコン化できました＼(^o^)／<br><br>シリアルポートとGPIOを直結してUARTでコマンド送るだけで簡単に制御できました(ﾟ∀ﾟ)<br><br>これQiitaの記事にまとめた方がいいですかね？🤔<a href="https://twitter.com/hashtag/M5Stack?src=hash&amp;ref_src=twsrc%5Etfw">#M5Stack</a> <a href="https://twitter.com/hashtag/M5ATOM?src=hash&amp;ref_src=twsrc%5Etfw">#M5ATOM</a> <a href="https://t.co/3CVb3t1xRt">pic.twitter.com/3CVb3t1xRt</a></p>&mdash; もけ@ムギ㌠ (@coppercele) <a href="https://twitter.com/coppercele/status/1368281460981915648?ref_src=twsrc%5Etfw">March 6, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

おそらく思ってるより簡単にルンバをハックできると思います
音楽を演奏したりAlexaで清掃モードに入れたりなんてこともできるのでいろいろ楽しみましょう！(ﾟ∀ﾟ)

M5StickC赤外線リモコンをAlexaに対応させよう - Qiita
https://qiita.com/coppercele/items/8c962dabadf33d52709b