今回は、ArduinoIDEのシリアルモニタで、シリアル通信メッセージを送って、これを受信したM5StackがJSON形式に変換して、Wi-Fi(MQTT)で、ラズパイに送る方法を紹介します。
想定ケースは、車両のECUからの車両情報を、M5Stack経由で、AWSなどのクラウドへアップロードするケースです。シリアル通信部分を、CANやLIN、SPI等の通信に差し替えることで、様々な用途があると思っています。
前提
・M5Stack
・Raspberry Pi4
ラズパイには、MQTTブローカであるmosquitto、MQTTクライアントのmosquitto-clientsがインストールされていることが前提です。
M5StackとRaspberry Piは、同じWi-Fiを使います。
M5StackとラズパイをWi-Fi(MQTT)で繋ぎ、JSONデータを通信する方法
構成
ArduinoIDEに、必要なライブラリをインストールする
ライブラリは、以下をインストールします。
・PubSubClient
・ArduinoJSON
ArduinoIDEの「スケッチ」-「ライブラリをインクルード」-「ライブラリを管理」を選択する
ライブラリマネージャでは、「PubSubClient」と入力すると、PubSubClientを見つけられます。インストールボタンがありますので、これを押してインストールします。
「ArdunioJSON」ライブラリも、同様にインストールします。
サンプルコード(M5Stack)
ArduinoIDEを起動して、以下のサンプルコードをコピーしてください。
#define M5STACK_MPU6886
#include <WiFi.h>
#include <PubSubClient.h>
#include <M5Stack.h>
#include <stdio.h>
#include <string.h>
#include <ArduinoJson.h>
////////////////////////////////////////////////////////////////////////////////
// Wi-FiのSSID
char *ssid = "**********";
// Wi-Fiのパスワード
char *password = "************";
// MQTTの接続先(ラズパイ)のIP
const char *endpoint = "***.***.***.***";
// MQTTのポート
const int port = 1883;
// デバイスID デバイスIDは機器ごとにユニークにします
char *deviceID = "M5Stack";
// メッセージを知らせるトピック
char *pubTopic = "/pub/M5Stack";
// メッセージを待つトピック
char *subTopic = "/sub/M5Stack";
////////////////////////////////////////////////////////////////////////////////
WiFiClient httpsClient;
PubSubClient mqttClient(httpsClient);
// シリアル通信の初期化
void setup_serial(){
Serial.begin(115200);
while (!Serial) continue;
}
// Wi-Fiモジュールの初期化と開始
void setup_wifi(){
Serial.println("Connecting to ");
Serial.print(ssid);
// WiFi接続性改善のため、いったん切断
WiFi.disconnect( true, true ); //WiFi OFF, eraseAP=true
delay(500);
// WiFi開始
WiFi.begin(ssid, password);
// Wi-Fi接続待ち
while (WiFi.status() != WL_CONNECTED){
delay(500);
M5.Lcd.print(".");
}
// WiFi接続成功メッセージの表示
Serial.println("\nWiFi Connected.");
M5.Lcd.setCursor(10, 40);
M5.Lcd.setTextSize(2);
M5.Lcd.println("WiFi Connected.");
// M5StackのIPアドレスを表示
M5.Lcd.print("IP address: ");
M5.Lcd.println(WiFi.localIP());
}
void setup(){
// M5Stack objectの初期化
M5.begin();
M5.Power.begin();
M5.IMU.Init();
setup_serial();
// 画面初期設定
M5.Lcd.fillScreen(TFT_NAVY);
M5.Lcd.setCursor(10, 10);
M5.Lcd.setTextSize(3);
M5.Lcd.printf("START");
// Wi-Fi処理の開始
setup_wifi();
// MQTTクライアントの初期化
mqttClient.setServer(endpoint, port);
// MQTT接続開始
connectMQTT();
}
// MQTT接続処理
void connectMQTT(){
// MQTT接続待ち
while (!mqttClient.connected()){
if (mqttClient.connect(deviceID)){
// 所定のデバイスと接続した
Serial.println("Connected.");
int qos = 0;
mqttClient.subscribe(subTopic, qos);
Serial.println("Subscribed.");
}else{
// 所定のデバイスと接続失敗 ⇒ 再トライする
Serial.print("Failed. Error state=");
Serial.print(mqttClient.state());
// Wait 5 seconds before retrying
delay(5000);
}
}
}
// MQTT接続管理
void mqttLoop(){
// MQTT接続状態を監視し、切断されていたら、再接続を試みる
if (!mqttClient.connected()){
connectMQTT();
}
// MQTTクライアント側の定期処理の実行
mqttClient.loop();
}
// 文字列 = split(元の文字列,分割文字列,分割した後何番目の文字列か)
String split(String data, char separator, int index){
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = data.length();
int endcheck = false;
for(int i=0; i < maxIndex; i++){
if( data.charAt(i) == separator ){
found++;
if ( found == index ){ strIndex[0] = i+1; }
if ( found == index+1 ){ strIndex[1] = i; endcheck=true; }
if(endcheck){ break; }
}
}
return (strIndex[1]==-1) ? data.substring(strIndex[0]) : data.substring(strIndex[0], strIndex[1]);
}
//分割文字の数
int Keywordcounter(String Original,char Keyword){
int Keywordcount = 0;
for (int i = 0; i < Original.length(); i++){
if (Original.charAt(i) == Keyword) {
Keywordcount++;
}
}
return Keywordcount;
}
void loop(){
StaticJsonDocument<500> doc;
char pubMessage[256];
// MQTT接続監視
mqttLoop();
// シリアル通信受信時にメッセージを送信する
int recieved_byte_size = Serial.available();
if (recieved_byte_size){
String recieveData = Serial.readStringUntil('\n');
//描画!
M5.Lcd.fillScreen(TFT_DARKGREEN);
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(0,10);
M5.Lcd.println(recieveData);
Serial.println("シリアル通信データ:" + String(recieveData));
//分割文字の数
int count = Keywordcounter(recieveData, ',');
String part[count+1];
// シリアルデータの分割
for (int i = 0; i < count+1; i++){
part[i] = split(recieveData,',',i);
}
// JSONメッセージの作成
JsonArray idValues = doc.createNestedArray("ID");
idValues.add(part[0]);
JsonArray dataValues = doc.createNestedArray("data");
dataValues.add(part[1]);
serializeJson(doc, pubMessage);
// メッセージの画面表示
Serial.print("topic= ");
Serial.println(pubTopic);
Serial.print("Message= ");
Serial.println(pubMessage);
M5.Lcd.print(pubMessage);
// メッセージのPublish
mqttClient.publish(pubTopic, pubMessage);
Serial.println("Published.");
Serial.println("");
}else{
}
}
M5Stackへの書き込みが完了し起動をすると、M5Stackは、Wi-Fiルータと接続 → MQTTの接続を行い、PCからのシリアル通信を待ち受けます。
JSONデータを作成するのに、ArduinoJSONというライブラリを使いました。とても簡単に、JSONデータを扱うことができ、とても便利です。
ラズパイ側のmosquittoを起動する
ラズパイのコンソールを起動して、mosquittoを動作させます。
> mosquitto_sub -d -t /pub/M5Stack
PCのArduinoIDEのシリアルモニターからメッセージを送信する
ArduinoIDEのシリアルモニターを起動させます。
上部の欄に、以下を入力して、Enterを押します。
123,1122334455
ラズパイのコンソールに、以下のメッセージが表示され、シリアル通信メッセージが、ラズパイに伝わっていることがわかります。
Received message 'b'{"ID":["123"],"data":["1122334455"]}'' on topic '/pub/M5Stack' with QoS 0
まとめ
今回は、ArduinoIDEのシリアルモニタで、シリアル通信メッセージを送って、これを受信したM5StackがJSON形式に変換して、Wi-Fi(MQTT)で、ラズパイに送る方法を紹介します。
コメント