Help us understand the problem. What is going on with this article?

【IoT初級者へ】M5StickC ではじめる MQTT 通信

この記事は CPS Lab Advent Calendar 2019 1日目の記事です.
2日目の記事は 生活の全てをトラッキングする計画v0.1 です.

ついに始まりました!今年も一番槍を拝命した Rone Loreto です.

初日なので CPS Lab (実空間コンピューティング研究室) っぽい記事です.

しょっぱなから遅刻投稿ですみません.二日酔いが悪い

背景

せっかちな方は 概要 にお進みください.


最近 IoT というワードをよく聞くと思います.
IoT (InterNet of Things),すなわち モノをインターネットと接続すること です.
これが台頭してきた背景には『無線通信の高速化』『機器の小型化』『機器のコスト低下』などがあります.特に『機器のコスト低下』は凄まじいです.ESP32を搭載したM5Stackの販売,RISC-V搭載のマイコン登場など……数千円の小型マイコンで色々なことが誰でも出来るようになりました.

黎明期から流行期となった今,様々な場所で IoT を使った機器・製品・システムが見られるようになりました.実際,今年の CEATEC でも IoT を活用した展示が数多くされており「どんどん界隈がアツくなっているな!」とテンションが上がりっぱなしでした.

さて,界隈がアツくなる = はじめる人が増える です.

はじめた人,はじめようとしている人にお伝えしておきます.
IoT は初めが一番つまづきやすい です.
とにかく知らない単語が出てきます.デバッグもソフト・ハードを両方見なればならないので大変です.

本記事は中でも ネットワークの活用 にスポットを当てています.
「ネットワーク使って〇〇やりたいのに!!」と辛い思いをしている方の助けになれば幸いです.

概要

本記事は MQTT を使ったことがない 方に

  • ネットワーク経由でセンサデータをやり取りするイチ手法の共有をする
    • ThingSpeak によるデータの可視化
  • MQTT のイメージを掴んでもらう

ことを主眼としています.

MQTTをガチでやっている 方には「それもう知ってるが……」という内容です.
ブラウザバックした方が時間の節約になります.

逆に MQTTを触り始めたばかり の方には「そうそうこういうのだよね!」「へぇこういうやり方もあるの」くらいの知見にはなる内容を目指しました.
ザーッと読みすすめることをオススメします.

MQTT (Message Queue Telemetry Transport) ってナニモノ?

通信プロトコルです.
ざっくり図示すると以下のようになります.

MQTT.png

  • Publisher: データを発信するところ
  • Subscriber: データを受信するところ
  • Broker: サーバみたいなもの.データのやり取りを中継する.

この方式は Publish/Subscribe Model と呼ばれています.

オーバヘッドが小さい等の利点から,IoT機器・システムによく用いられています.
もっと詳しく知りたい方は,MQTT の基本知識 - IBM がオススメです.

今回つくるシステム構成

というわけで,今回は MQTT 通信を使ったシステムを作ってみます.

システム構成.png

【Pubisher】 M5StickC

image.png
M5StickC - スイッチサイエンス

ESP32内蔵.Wi-Fi接続ができる.6軸(ジャイロ・加速度)センサが入っている.Grove・ジャンパ線経由でセンサを接続することもできる.液晶も付いている.

なのに2000円で買える……化け物マイコンです.

プログラムは Arduino IDE を使って書きます.

【Broker&Subcriber】 ThingSpeak

image.png

データをクラウドでやり取りできるWebアプリケーションで,MQTT 通信ができます.
今回は簡単にするためコレを用いて,データの可視化 まで行ないます.

MATLABなどで有名なMathWorks製.
アカウントが必要です.持っていない方はコチラから.

IoT Analytics - ThingSpeak Internet of Things
ThingSpeak Documentation - MathWorks 日本

今回のゴール

M5StickC のジャイロ値が ThingSpeak で見られる.

→ ThingSpeakで見られるところまで行けば,あとは任意のセンサに置き換えるだけ.
自分の使いたいセンサでも ThingSpeak を 使った MQTT 通信ができるようになります.

※「自分で Broker 立てたいんだが……」というレベルの方.Mosquitto を使いましょう.

手順

以下の手順をおって進めます.

1. M5StickCでジャイロ値を取れるようにする.

まずはジャイロ値を取れるようにしましょう.
ジャイロ値とは,傾きを示した値です.
M5StickC にジャイロ値を取れるセンサが内蔵されているので,使っていきます.

スケッチの作成

M5StickC.h のライブラリをArduinoIDEに追加し,以下のコードを書いたスケッチを作成します.
作成後,ツール > ボード「M5Stick-C」を選択し,書き込みしましょう.

ジャイロ値を液晶に表示するコード

m5stickcImuTest.ino
#include <M5StickC.h>

// グローバル変数の設定
float gyroCurtX, gyroCurtY, gyroCurtZ;  // ジャイロ値

// 関数宣言
void currentGyro();

void setup() {
  M5.begin();
  M5.MPU6886.Init();
}

void loop() {
  currentGyro();
  delay(500);     // 0.5秒間隔でloopさせる
}

void currentGyro() { // ジャイロ値を計算し表示する関数
  float gyroRawX, gyroRawY, gyroRawZ; // ジャイロ生データ
  M5.MPU6886.getGyroData(&gyroRawX, &gyroRawY, &gyroRawZ);

  gyroCurtX = gyroRawX * M5.MPU6886.gRes;
  gyroCurtY = gyroRawY * M5.MPU6886.gRes;
  gyroCurtZ = gyroRawZ * M5.MPU6886.gRes;

  M5.Lcd.setCursor(0, 30);
  M5.Lcd.printf("Gyro\nX: %7.2f\nY: %7.2f\nZ: %7.2f\n          mg",
                gyroCurtX, gyroCurtY, gyroCurtZ);
}

実行結果

m5stickcGyro.gif

表示できました!
M5StickCを色々な方向に傾けると X, Y, Z の値がそれぞれ変化するはずです.
(机などに置いていても微妙に値が動き続けると思います.この症状を直す手段について書くと,それだけで一つの記事になるので今回はこのまま行きます.)

2. ThingSpeak側の設定を行なう.

BrokerとSubscriberを務めるThingSpeakの設定をしていきます.
(アカウント作成の手順は省きます.すみません)

ログイン

まずここからログインしましょう.
ログインしたら次のような画面に進むと思います.

MyChannel.png

チャネル作成

初めて使う人は項目がまっさらなはずなので,チャネルを作成していきます.
左上の「New Channel」をクリックしてください.

NewChannel.png

こんな画面が出てきます.
今回は次のように設定します.

ChannelSetting.png

  • Name: チャネルの名前.今回は「M5stickC_Gyro」としました.
  • Field1〜3: グラフの名前.順に「gyroX」「gyroY」「gyroZ」とします.それぞれX,Y,Z軸方向のジャイロ値のグラフとします.

入力したら「Save Channel」をクリック.

ChannelInfo.png

これがチャネルの画面です.
グラフが3つ作成されています.
この各グラフに送られてきたジャイロ値が表示されていきます.

この画面の左上に表示されている「Channel ID」は後で使います.メモっておいてください.

Write API Keyの確認

では,他に必要な値を確認していきましょう.
「API Keys」をクリックしてください.

APIKey.png

ここの「Write API Key」の値を後で使います.Read API Key は今回使いません.

MQTT API Key の確認

次に,画面右上の「Account > My Profile」を開き,

MQTTKey.png

MQTT API Key」もメモっておいてください.

以上で準備は完了です!
実際にコードを書いていきましょう.

3. M5StickC で取得したジャイロ値を ThingSpeak に MQTT 通信で送る.

いよいよ本題です.
M5StickC を無線接続し,MQTT 通信で ThingSpeak にジャイロ値を送ります.

無線接続するため,Wi-Fi 環境が必要です.
また,Wi-Fi 接続と MQTT 通信を行なえるようにするため,WiFi.hPubSubClient.h のライブラリをArduinoIDEに追加してください.

PubSubClientは次のリンクからZIPでダウンロードし「ZIP形式のライブラリをインストール」より追加してください.
knolleary/pubsubclient: A client library for the Arduino Ethernet Shield that provides support for MQTT.

スケッチの作成

WiFi 設定は自分が使う環境のものに書き換えてください.
設定するものはSSIDとWiFiのパスワードです.
なお,M5StickCは5GHz帯(a/ac/ad/ax)のWi-Fi接続に対応していないので,2.4GHz帯(b/g/n)のものを使用してください.

MQTT 設定は先ほどメモった内容にそれぞれ書き換えてください.

たとえば,

  • 「Channel Name」: M5stickC_Gyro
  • 「MQTT API Key」: HOGEAHOGEAHOGEAB
  • 「Write API Key」 : HUGAAHUGAAHUGAB
  • 「Channel ID」: 000000

ならば

// MQTT 設定 (subscriber:ThingSpeak)
const char mqttUserName[] = "M5stickC_Gyro";
const char mqttPass[] = "HOGEAHOGEAHOGEAB";
const char writeApiKey[] = "HUGAAHUGAAHUGAB";
const long channelID = 000000;

のようにしてください.

ジャイロ値を ThingSpeak に MQTT 通信で送るコード

m5stickcThingspeakMqtt.ino
#include <M5StickC.h>
#include <WiFi.h>
#include <PubSubClient.h>

// WiFi 設定
const char ssid[] = "yourssid";         // yourssid→使うWiFiのSSIDに書き換える
const char password[] = "yourwifissid"; // yourwifissid→使うWiFiのパスワードに書き換える
WiFiClient wifiClient;

// MQTT 設定 (subscriber:ThingSpeak)
const char mqttUserName[] = "name";   // name→設定した名前に書き換える
const char mqttPass[] = "pass";       // pass→設定されたmqttパスに書き換える
const char writeApiKey[] = "apikey";  // apikey→設定されたwriteAPIキーに書き換える
const long channelID = 000000;        // 000000→設定されたチャネルIDに書き換える

static const char alphanum[] ="0123456789"
                              "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                              "abcdefghijklmnopqrstuvwxyz";  // クライアントIDをランダム生成するための文字列

PubSubClient mqttClient(wifiClient);
const char* server = "mqtt.thingspeak.com";

unsigned long lastConnectionTime = 0; 
const unsigned long postingInterval = 10L * 1000L; // Publish の間隔を10秒にする

// グローバル変数の設定
float gyroCurtX, gyroCurtY, gyroCurtZ;  // ジャイロ値

// 関数宣言
void currentGyro();
void reConnect();
void mqttPublish();

void setup() {
  M5.begin();
  M5.MPU6886.Init();

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  mqttClient.setServer(server, 1883); 
}

void loop() {
  reConnect();

  mqttClient.loop();

  // 最後に Publish した時間から postingInterval が経過すると動作する
  if (millis() - lastConnectionTime > postingInterval) {
    currentGyro();
    mqttPublish();
  }
}


/* 
 * ----- 以下loop内で用いる関数 -----
 */
void currentGyro() { // ジャイロ値を計算し表示する関数
  float gyroRawX, gyroRawY, gyroRawZ; // ジャイロ生データ
  M5.MPU6886.getGyroData(&gyroRawX, &gyroRawY, &gyroRawZ);

  gyroCurtX = gyroRawX * M5.MPU6886.gRes;
  gyroCurtY = gyroRawY * M5.MPU6886.gRes;
  gyroCurtZ = gyroRawZ * M5.MPU6886.gRes;

  M5.Lcd.setCursor(0, 30);
  M5.Lcd.printf("Gyro\nX: %7.2f\nY: %7.2f\nZ: %7.2f\n          mg",
                gyroCurtX, gyroCurtY, gyroCurtZ);
}

void reConnect() { // 接続が切れた際に再接続する
  char clientID[10];

  // 接続まで繰り返す
  while (!mqttClient.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Generate ClientID
    for (int i = 0; i < 8; i++) {
        clientID[i] = alphanum[random(51)];
    }

    // MQTT broker に接続する
    if (mqttClient.connect(clientID,mqttUserName,mqttPass)) {
      Serial.print("Connected with Client ID:  ");
      Serial.print(String(clientID));
      Serial.print(", Username: ");
      Serial.print(mqttUserName);
      Serial.print(" , Passwword: ");
      Serial.println(mqttPass);
    }
    else {
      Serial.print("failed, rc=");
      // http://pubsubclient.knolleary.net/api.html#state に state 一覧が書いてある
      Serial.print(mqttClient.state());
      Serial.println("try again in 5 seconds");
      delay(5000);
    }
  }
}

void mqttPublish() {
  // ThingSpeak に Publish するための文字列データを作成する
  String data = ("field1=" + String(gyroCurtX) + "&field2=" + String(gyroCurtY) + "&field3=" + String(gyroCurtZ));

  int length = data.length();
  char msgBuffer[length];
  data.toCharArray(msgBuffer,length+1);

  // topic 文字列を作成し ThingSpeak の channel feed にデータを Publish する
  String topicString ="channels/" + String(channelID) + "/publish/" + String(writeApiKey);
  length = topicString.length();
  char topicBuffer[length];
  topicString.toCharArray(topicBuffer, length+1);
  mqttClient.publish(topicBuffer, msgBuffer);

  lastConnectionTime = millis(); // 最後に Publish した時間からのカウント
}

実行結果

result.png

できました!
10秒間隔でX, Y, Z 軸のジャイロ値が表示されています.

まとめ

これで MQTT 通信が一応使えるようになりました.
晴れて皆さんは IoT初心者 → 初級者 へステップアップです.

今回はM5StickC搭載済みのジャイロセンサを用いましたが,勿論他のセンサでも MQTT 通信でデータのやり取りを行なうことができます.

具体的に.

void mqttPublish() {
  // ThingSpeak に Publish するための文字列データを作成する
  String data = ("field1=" + String(gyroCurtX) + "&field2=" + String(gyroCurtY) + "&field3=" + String(gyroCurtZ));

ここのString(gyroCurtX)等のgyroCurtXを任意センサで取得した値を格納する変数に変更し,field数を合わせてやれば良いだけです.fieldについては2つ目以降&field2=等と&をつける必要がありますので注意してください.
(勿論任意センサの値を取得するコードは自分で実装する必要があります)

という辺りで,今回は終わりとさせてさせていただきます.
みなさんも快適な MQTT 通信ライフを!

備考: M5StickCの開発で役に立つリンク

m5stack/M5StickC: M5Stack Arduino Library
→公式のGitHubリポジトリ

M5Stack
→上記リポジトリ内にもある公式Doc.若干情報が古い……
 (例: IMUがMPU6886ではなく前のSH200Qについての記述になっている)

M5StickC非公式日本語リファレンス
→非公式のリファレンス.MPU6886に対応している点が良い.

M5StickC: 総合概要
→詳細が載っている.自分でも網羅し切れていない程に詳しく書かれている.

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした