知的好奇心 for IoT

IoT関連の知的好奇心を探求するブログです

M5StackのBALA-CミニセルフバランスカーをMQTTで操作できるようにサンプルコードを改造する方法

1年ぐらい前に次のような記事を書いたのですが、Blynkで新規アカウント登録ができなくなってしまったため、BalaCもMQTTで動かせるようにしてみました。

と、いっても、このBalaCも製造停止になってしまい、在庫でしか入手できなくなっているんですけどね。

 

動作ビデオ

とりあえず、どんな感じか動作ビデオを見てみてください。


Blynkとそんなに変わらないんじゃないかと思います。

 

MQTT Joystickコントローラー

Blynkの代わりとなるMQTT対応のJoystickコントローラーアプリを色々と探してみましたが、Androidにしか対応してないこのアプリしか見つけることができませんでした。

なので、iOSユーザーの方は今回は使うことができません。

まぁ、以前紹介したAndroidアプリプレーヤー(エミュレーター)のBlueStacksを使えば、PCで使うことはできます。(マウスだと操作が難しいです。)

 

アプリはすごくシンプルで、設定画面などはなく、この画面の赤枠左側にブローカーアドレス、右側にパブリッシュするトピックを指定するだけで使えます。

f:id:IntellectualCuriosity:20211205160652p:plain

例えばトピックに

hiro/BalacMQTT/Joystick

と指定した場合、左のJoystickを動かすと

hiro/BalacMQTT/Joystick/left

というトピックでパブリッシュされ、右のJoystickを動かすと

hiro/BalacMQTT/Joystick/right

というトピックでパブリッシュされます。

 

値は「<角度> <速度>」というフォーマットで文字列で送られます。

角度は真右が0度となり、時計と逆周りの順で360度まで(0度)です。

速度は真ん中が0で、一番端が100です。

 

このMQTT Joystickコントローラーの注意点は「手を離したときの値が送られていないことがある」ということで、手を話すと真ん中に戻るのですが、その値(0 0)が送られないことがあります。なので、なるべる指を付けたままで操作することをお勧めします。

 

サンプルコードの改造

サンプルコードは次のURLからダウンロードできます。

https://raw.githubusercontent.com/m5stack/M5-ProductExampleCodes/master/App/BalaC/Arduino/Balac/Balac.ino

 

12行目に次のコードを追加

#include <wifi.h>                       // WiFiライブラリ
#include <pubsubclient.h>               // MQTTライブラリ
#define WIFI_SSID       "この文字列をWiFiSSIDで置き換えます"
#define WIFI_PASS       "この文字列をWiFiのパスワードで置き換えます"
// MQTT設定
#define MQTT_TOPIC_ID   "xxxxxx"    // トピック識別用ID
#define MQTT_DEVICE_ID  MQTT_TOPIC_ID "-1"   // デバイスID(ユニークなID)
#define MQTT_BROKER_ADDR "broker.hivemq.com" // MQTTブローカーのアドレス
#define MQTT_TOPIC_RIGHT MQTT_TOPIC_ID "/BalacMQTT/Joystick/right" // 右のトピック
#define MQTT_TOPIC_LEFT  MQTT_TOPIC_ID "/BalacMQTT/Joystick/left"  // 左のトピック
// グローバル変数/オブジェクト
WiFiClient wclient;                     // WiFi接続用オブジェクト
PubSubClient client(MQTT_BROKER_ADDR, 1883, wclient); // MQTT接続用オブジェクト

f:id:IntellectualCuriosity:20211205182755p:plain


83行目に次のコードを追加

  client.setCallback(callback);         // データを受信した時に呼び出される関数

f:id:IntellectualCuriosity:20211205183903p:plain

 

92行目に次のコードを追加

  connectMQTT();                        // MQTT接続/接続確認

f:id:IntellectualCuriosity:20211205184228p:plain


133行目に次のコードを追加

// 購読しているトピックを受信した時に呼び出される関数
void callback(char* topic, byte* payload, unsigned int length) {
  // 受信データ取得
  int angle = 0;                        // Joystickの角度
  int speed = 0;                        // Joystickのスピード
  bool findSpace = false;
  for (int i=0; i<length; i++) {
    if ((char)payload[i] == 0x20) {
      findSpace = true;
    } else {
      if (!findSpace) {
        angle = angle * 10;
        angle += ((char)payload[i] - 0x30);
      } else {
        speed = speed * 10;
        speed += ((char)payload[i] - 0x30);
      }
    }
  }
  //Serial.printf("angel:%d speed:%d\n", angle, speed);

  // モーター制御
  moveRate = 0.0;
  spinContinuous = false; 
  spinStep = 0.0;
  if (speed > 40) {
    if (90-20<angle && angle<90+20)             // 前
      moveRate = -2.0;
    else if (270-20<angle && angle<270+20)      // 後
      moveRate = 2.0;
    else if (360-20<angle || angle<0+20) {      // 右
      moveRate = -2.0; 
      spinContinuous = true; 
      spinStep = -40.0*clk; 
    } else if (180-20<angle && angle<180+20) {  // 左
      moveRate = -2.0; 
      spinContinuous = true; 
      spinStep = 40.0*clk; 
    }
  } 
}

// WiFiに接続
void connectWiFi() {
  if (WiFi.status() != WL_CONNECTED) {  // WiFiが繋がっていなかったら
    Serial.print("\nConnecting to " WIFI_SSID); // ログにWiFiSSIDを表示
    WiFi.begin(WIFI_SSID, WIFI_PASS);   // WiFiに接続
    while (WiFi.status() != WL_CONNECTED) { // WiFiが繋がるまでループ
      delay(1000);                      // 1秒待つ
      Serial.print(".");                // ログに「.」を表示
    }
    Serial.println("connected");        // ログに「WiFi connected」を表示
  }
}

// MQTT接続/接続確認
void connectMQTT() {
  connectWiFi();                        // WiFiに接続/接続確認
  while (!client.connected()) {         // MQTTブローカーの接続確認
    Serial.print("Attempting MQTT connection...");
    if (client.connect(MQTT_DEVICE_ID)) { // MQTT接続ブローカーに接続
      Serial.println("connected");
    } else {
      Serial.print("Retying in 5 seconds - failed, rc=");
      Serial.println(client.state());
      delay(5000);
    }
    client.subscribe(MQTT_TOPIC_RIGHT); // 指定トピックを購読
    client.subscribe(MQTT_TOPIC_LEFT);  // 指定トピックを購読
  }
  client.loop();                        // 接続維持用
}

f:id:IntellectualCuriosity:20211205192551p:plain

f:id:IntellectualCuriosity:20211205192710p:plain

 

開発環境

最後に開発環境について書いておきます。

  • Arduino IDE 1.8.16
  • Arduino core for the ESP32 1.0.6 - ボード

    f:id:IntellectualCuriosity:20211205194501p:plain

  • M5StickC 0.2.5 - ライブラリ

    f:id:IntellectualCuriosity:20211205194707p:plain

  • PubSubClient 2.8.0 - ライブラリ

    f:id:IntellectualCuriosity:20211205194326p:plain