SORACOMとモーターモジュール "KeiganMotor" で作る「どこでもリモート雲台」

[IoTLT アドベントカレンダー 2020](https://qiita.com/advent-calendar/2020/iotlt)のアンカーでございます。
まずは無事に掲載できることを心から安堵しております。なんせ、完全見切り発車でエントリーしたもんだから。

## やったことは「KeiganMotorでリモート雲台」

KeiganMotorをMQTTでリモート操作できるようにしました。

![やったこと.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22754/0da67cdd-67f7-1595-13d9-53005235c052.gif)

### 構成

<img src="https://docs.google.com/drawings/d/e/2PACX-1vQwjXBQokrrhajXhZBxe8OjUH7V2gBiae28Mqs1DjRF3J1LrpgJ5tcT73zolw0uT9JOnWlVl55CUMa9/pub?w=898&amp;h=307">

LTEモデム搭載しているマイコン「[Wio LTE JP Version](https://soracom.jp/products/module/wio_lte/) (以下、Wio LTE)」とKeiganMotorをI2Cで接続し、IoT データ通信「[SORACOM Air](https://soracom.jp/services/air/)」とデータ転送サービス「[SORACOM Beam](https://soracom.jp/services/air/)」を使ってMQTT経由でKeiganMotorを操作します。

## 各要素の解説

### KeiganMotor

<img src="https://docs.google.com/drawings/d/e/2PACX-1vTXwf6NsxSbuca8FCIUufOw8wSgDeNI-fZbG8huCer2NzV355vj9YjXU0pTCDawqXQ1aJF6npACa4J7/pub?w=247&amp;h=196">

[KeiganMotor](https://keigan-motor.com/)は BLE / USBシリアル / I2C で操作できるモーターモジュールです。
"0.3N･m" というトルク(力)で動くそうです。このトルク、全然イメージがわかないので比較を探すと、見つかったのはミニ四駆のモーターでした。[ライトダッシュモーターPRO](https://www.tamiya.com/japan/products/15402/index.html)[^1]のトルクは1.9mN･m(0.0019N･m[^2])とのことで、あのミニ四駆のモーターよりも力強く動くという理解です。

[^1]: 私はハイパーミニモーター世代です。
[^2]: 単位変換は[オリエンタルモーターさんのページ](https://www.orientalmotor.co.jp/tech/support_tool/torque/)を利用しました。ありがとうございます。

### Wio LTE JP Version

<img src="https://docs.google.com/drawings/d/e/2PACX-1vRU9uR5fASUxvfKlB-KUnqlc0ZzcfPMVHtIESU3P9vt6bBaEo4TeYr_86Ib-YPkGkPBUUhkhP30G6Y3/pub?w=282&amp;h=225">

Wio LTE JP Version(以下、Wio LTE)は、LTEモデム搭載のマイコンです。
Arduino IDEやPlatform IOで開発できます。Groveコネクタを持っており、色々なセンサーやモジュールを接続できます。UARTやI2Cもあるため、それらのI/Fを持った機器との通信にも活用できます。

Wio LTEは3.3V動作です。I2CはPULLUPされているため、[M5Stackと同様に](https://github.com/keigan-motor/Arduino-I2C-KM1/blob/master/readme_ja.md#m5stack)直接接続が可能できました。

### SORACOM Air / Beam

SORACOM Airは[SORACOM](https://soracom.jp/)が提供しているデータ通信サービスです。IoTデバイスで3G/LTEやSigfoxが利用できるようになります。
また通信だけでなく、暗号化や通信先(エンドポイント)の管理を行ってくれるデータ転送サービス「[SORACOM Beam](https://soracom.jp/services/beam/)」を始めとした、IoT開発の面倒なところを肩代わりしてくれるプラットフォームサービスが利用できます。

今回はSORACOM AirはLTE通信に、そしてSORACOM Beamはエンドポイント管理の肩代わりとして使っています。shiftr.io(後述)への接続情報であるアドレスやトークンをWio LTEのスケッチから無くすことができるので、コードをそのまま公開できますし、アドレスやトークンが変わってしまってもスケッチを編集しなくても対応できます。

### shiftr.io

[shiftr.io](https://www.shiftr.io/)はデバイス間メッセージングプラットフォームです。いわゆるマネージドMQTTサービスです。MQTT(S)/HTTP(S)/WebSocket(S)をサポートしています。

手軽なMQTTサービスが無いかと探していたら [MQTTブローカー shiftr.io の新バージョンをチェックしてみる！ 〜デスクトップアプリ編〜](https://qiita.com/youtoy/items/8cbc9e6fa1cd46ca2c3c)を発見し、SORACOM Beamでの接続チェックをしたら一瞬でつながったので利用してみました。

## 仕組み

コードは[Gistで公開](https://gist.github.com/ma2shita/4a694778ed4058283ebccd4c92e31847)しています。

Wio LTEからSORACOM Beamを経由してMQTT接続してトピック `/DEVICE_ID/command` をsubscribeします。PC等の他環境から `/DEVICE_ID/command` に対してJSONをpublishし、Wio LTEで受け取ったら中身に応じて実行する流れです。

### KeiganMotor のマウント

KeiganMotorは底面に[UNC1/4インチねじ穴](https://panproduct.com/blog/?p=114925)[^4]がありまして、カメラ用の機材と接続可能です。

[^4]: UNC1/4インチねじ穴なんて、初めて知った

また、私が購入した [[KM-1U] カメラアダプタキット](https://keiganmotor.myshopify.com/products/km-1u_camera_adapter_kits?variant=32688437559343)なら、KeiganMotorの上部に同様にUNC1/4インチねじ穴による取り付けができます。

GoPro(TM)のマウンターも使えるようになるので、いろんなものを付けられるのではないでしょうか。
エッジAIカメラ「[S+ Camera Basic](https://soracom.jp/soracom_plus/camera_basic/)」を取り付けた時の様子を動画にしておきました。
![mounter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22754/3eecfa32-14f9-d647-1c3a-30b0afa107d6.gif)


### KeiganMotor を Wio LTE を I2C で接続する

前述した通り、Wio LTEは3.3V動作で I2C がPULLUPされているため直接接続できました。
ケーブルは[Keigan社から販売されているI2Cケーブル](https://keiganmotor.myshopify.com/products/i2c)を利用し、Groveケーブルとジャンパワイヤーで直結です。ここ、いい感じの方法が無いものか🤔
電源は不要なので接続していません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22754/c0eee58c-3a8a-fa08-03d2-9c52c4f6f525.png)

ケースは[Wio LTE用 SORACOM UG ロゴバージョン](https://make.dmm.com/item/946661/)です。ずーーとお世話になっております！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22754/0380fd3f-d8a5-42b9-dc3c-070c9da1e150.png)

### KeiganMotor操作のためのコマンド体系(JSON)

実装をシンプルにするため、KeiganMotorをArudinoから操作するライブラリ [Arduino-I2C-KM1](https://docs.keigan-motor.com/apiDocument/Arduino-I2C-KM1/class_keigan_motor.html)のメソッドを直接実行するコマンド体系としました。
パースには[ArduinoJson](https://arduinojson.org/)を利用しています。

```json
{"method": "FOO", "params": [10.5, true]}
```

例えば現在地から角度を指定して回転させる [`moveByDistanceDegree()`](https://docs.keigan-motor.com/apiDocument/Arduino-I2C-KM1/class_keigan_motor.html#aad6d88a40224e460fe678c5e55aadf97) なら

```json
{"method": "moveByDistanceDegree", "params": [120, 6]}
```

で、120度を6rpmで回転します。[^3]

[^3]: RubyやPythonのように `eval()` や `Obj.send("method_name")` ができないので、"method" に対応して一対一で実装しました。

### 実装済みメソッド

* [readMotorMeasurement()](https://docs.keigan-motor.com/apiDocument/Arduino-I2C-KM1/class_keigan_motor.html#aece605d412876848f01830e5aa6bd748)
* [moveByDistanceDegree()](https://docs.keigan-motor.com/apiDocument/Arduino-I2C-KM1/class_keigan_motor.html#aad6d88a40224e460fe678c5e55aadf97)
* [reboot()](https://docs.keigan-motor.com/apiDocument/Arduino-I2C-KM1/class_keigan_motor.html#ae9541f7e433d2c23a15be206ad2173b3)

### SORACOM Beam 設定

SORACOM Beamはデバイスとクラウドでデータ変換やエンドポイントが可能です。
今回はTLS化(MQTT => MQTTS)と、エンドポイント(アドレスやトークン)の管理と2つの目的で利用しました。

設定画面は以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22754/1a574100-2cb4-ec5f-c808-9867e6dd327d.png)

このように設定することでデバイスからは `beam.soracom.io:1883` へ MQTT 接続すると、 `**.cloud.shiftr.io:8883` に中継してくれます。
shiftr.ioを無料枠で使おうとすると比較的頻繁にアドレスやトークンの変更が必要となります。その都度マイコン側のコードを書き換えることなく、サービス側の変化に対応できます。

一般的なMQTTブローカーだけでなく、AWS IoT Core や Azure IoT Hubなどなど、様々なサービスに対応しています。

## `error_t` の競合でコンパイルに失敗したら (Arduino-I2C-KM1 を Wio LTE で動かすためには)

Arduino IDE のライブラリ管理からインストールできる [Arduino-I2C-KM1](https://github.com/keigan-motor/Arduino-I2C-KM1) 2.0.2 を使って Wio LTE 向けにコンパイルすると以下のエラーが発生します。

```
In file included from C:\Users\A\non-sync\Arduino\WioLTE_KeiganMotor_bridge\WioLTE_KeiganMotor_bridge.ino:7:
C:\Users\A\non-sync\Arduino\libraries\Arduino-I2C-KM1\src/KM1_I2C.h:34:3: error: conflicting declaration 'typedef struct error_t error_t'
 } error_t;
   ^~~~~~~
In file included from c:\users\A\appdata\local\arduino15\packages\seeedjp\tools\arm-none-eabi-gcc\8.2.1-1.7\arm-none-eabi\include\c++\8.2.1\cerrno:42,
                 from c:\users\A\appdata\local\arduino15\packages\seeedjp\tools\arm-none-eabi-gcc\8.2.1-1.7\arm-none-eabi\include\c++\8.2.1\ext\string_conversions.h:44,
                 from c:\users\A\appdata\local\arduino15\packages\seeedjp\tools\arm-none-eabi-gcc\8.2.1-1.7\arm-none-eabi\include\c++\8.2.1\bits\basic_string.h:6400,
                 from c:\users\A\appdata\local\arduino15\packages\seeedjp\tools\arm-none-eabi-gcc\8.2.1-1.7\arm-none-eabi\include\c++\8.2.1\string:52,
                 from c:\users\A\appdata\local\arduino15\packages\seeedjp\tools\arm-none-eabi-gcc\8.2.1-1.7\arm-none-eabi\include\c++\8.2.1\stdexcept:39,
                 from c:\users\A\appdata\local\arduino15\packages\seeedjp\tools\arm-none-eabi-gcc\8.2.1-1.7\arm-none-eabi\include\c++\8.2.1\array:39,
                 from c:\users\A\appdata\local\arduino15\packages\seeedjp\tools\arm-none-eabi-gcc\8.2.1-1.7\arm-none-eabi\include\c++\8.2.1\tuple:39,
                 from c:\users\A\appdata\local\arduino15\packages\seeedjp\tools\arm-none-eabi-gcc\8.2.1-1.7\arm-none-eabi\include\c++\8.2.1\functional:54,
                 from C:\Users\A\AppData\Local\Arduino15\packages\SeeedJP\hardware\stm32\1.4.0\cores\arduino/WInterrupts.h:25,
                 from C:\Users\A\AppData\Local\Arduino15\packages\SeeedJP\hardware\stm32\1.4.0\cores\arduino/wiring.h:39,
                 from C:\Users\A\AppData\Local\Arduino15\packages\SeeedJP\hardware\stm32\1.4.0\cores\arduino/Arduino.h:32,
                 from sketch\WioLTE_KeiganMotor_bridge.ino.cpp:1:
c:\users\A\appdata\local\arduino15\packages\seeedjp\tools\arm-none-eabi-gcc\8.2.1-1.7\arm-none-eabi\include\errno.h:5:13: note: previous declaration as 'typedef int error_t'
 typedef int error_t;
             ^~~~~~~
exit status 1

ボードSeeed Wio LTE Cat.1に対するコンパイル時にエラーが発生しました。
```

原因は `error_t` という型の競合です。
すでに https://github.com/keigan-motor/Arduino-I2C-KM1/commit/cb8ac567588667ae9f7dda5e379e921c28c4fecf で修正がされていますので、すぐに使いたい場合はZIPからインストールしてください。

Arduino-I2C-KM1 側のエラー構造体は `km_error_t` にリネームされていますのでご注意を。

## なぜLTE通信？

KenganMotorは無線で[BLE](https://docs.keigan-motor.com/software_dev/blelow/kmblef/keigan-motor-service)、有線で[USBシリアルとI2C](https://docs.keigan-motor.com/software_dev/ports_on_wire)で制御できます。I2Cは[ケーブルの販売](https://keiganmotor.myshopify.com/products/i2c)もされており、工作の手間もありません。

USBシリアルとRaspberry Piを組み合わせれば簡単にKeiganMotorを操作できるのですが、「リモート雲台」には通信の手段が必要です。ネット接続にWi-Fiを考えた場合、(今年は規模縮小だったけど) Maker Faireといった展示会の2.4GHz/5GHzの嵐の中で動かすのは至難の業であることは、これを見ている方ならご存知の通りでしょう。

3G/LTEとったセルラー通信であれば混線の心配なく通信が可能です。Raspberry Piであれば[USBドングル型モデム](https://soracom.jp/products/module/)が使えるので、これで後は中継システムを検討すればOKとなります。
って、ここまで書いてて、なんでRaspberry Piにしなかったんだろう🤔まあいいか。

## あとがき

なんとかアンカー分をかき揚げることができて良かったです。
来年もよろしくお願いします！

![よいお年を.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22754/bb1d51ae-8311-145e-54fa-a8cb1bbfab1a.gif)

EoT