💻

nanoFrameworkでNode-REDにMQTT通信してみた

2022/12/20に公開

はじめに

Zennは初投稿です。
私は 東京電機大学未来科学部 情報メディア学科 実空間コンピューティング研究室 に所属するmattunです。
普段はC#をこよなく愛し、Unityで食って生きています。

この記事は CPSLab Advbent Calendar 202218日目の記事です。(遅刻)

本稿では nanoFramework で Node-RED に MQTT通信でM5StackCore2のジャイロセンサーと加速度胃センサーの値を送ってみたいと思います。

nanoFrameworkとは

https://www.nanoframework.net/

nanoFrameworkとはざっくり言うと、C#でESP32系のマイコンを制御できるフレームワークです。
GPIOやI2C、PWMなどメジャーどころはほとんどサポートしており、(技術的には)ArduinoやC、MicroPythonと同等のことが可能であり、また保守性と記述の柔軟性を両取りしたC#でマイコンプログラミングができる夢のような環境です()

Microsoftが提供するAzure系サービスとの連携が楽だったりするようなので、それ系のサービスを使うときは視野に入れてもいいかもですね。

ちなみに、デメリットを列挙すると

  • C/Cppのネイテイブコードに変換されるため、Genericsやasync/awaitなどの機能がサポートされていない(GenericsがサポートされていないということはLinqも動かない...)
  • Visual Studioでしか基本的に動作しない (VSCやRiderでも非公式プラグインが一応ありますが動作は不安定)
  • 実機への書き込みがArduinoやUIFlow系に比べてとても遅い

って感じです。LinqこそC#の醍醐味だと思っているので、それが使えないのは個人的にめちゃくちゃ痛いですね。

Node-REDとは

https://nodered.jp/

Node-REDはフローベースドプログラミング(flow-based programming)ツールであり、元はIBM Emerging Technology Servicesチームによって開発され、JS Foundation配下のプロジェクトを経て、2019年3月よりNode.js FoundationとJS Foundationが合併して設立されたOpenJS Foundationにホストされています。

(公式サイトから引っ張ってきた文言そのまんまです)
要するにNode.jsの実行環境上で動くノーコードの主にIoT関連で使われているいい感じに見える化してくれたり中継してくれる環境のことですね。
デフォルトでMQTTなどをサポートしているのでハンズオンなどで使われていることが多いイメージですね。
(研究室で布教された感じなのであんまり詳しいわけではないです)

バージョン情報

  • Microsoft Visual Studio Community 2022 (64 ビット) - Current
    Version 17.3.6
  • Node.js v16.14.0
  • Node-RED バージョン: v3.0.2
  • M5Stack Core2
nanoFramework周り

nanoFramework.CoreLibrary.1.12.0
nanoFramework.Graphics.1.1.13
nanoFramework.Hardware.Esp32.1.4.8
nanoFramework.Iot.Device.Axp192.1.2.153
nanoFramework.Iot.Device.Bmm150.1.2.153
nanoFramework.Iot.Device.Button.1.2.153
nanoFramework.Iot.Device.Common.NumberHelper.1.2.141
nanoFramework.Iot.Device.Ft6xx6x.1.2.141
nanoFramework.Iot.Device.Mpu6886.1.2.153
nanoFramework.Iot.Device.Rtc.1.2.153
nanoFramework.Iot.Device.Sht3x.1.2.153
nanoFramework.Json.2.2.63
nanoFramework.M5Core2.1.1.86
nanoFramework.ResourceManager.1.2.7
nanoFramework.Runtime.Events.1.11.1
nanoFramework.Runtime.Native.1.5.4
nanoFramework.System.Buffers.Binary.BinaryPrimitives.1.2.141
nanoFramework.System.Collections.1.4.0
nanoFramework.System.Device.Adc.1.0.2
nanoFramework.System.Device.Dac.1.4.3
nanoFramework.System.Device.Gpio.1.1.22
nanoFramework.System.Device.I2c.1.0.3
nanoFramework.System.Device.Model.1.2.141
nanoFramework.System.Device.Pwm.1.0.1
nanoFramework.System.Device.Spi.1.3.22
nanoFramework.System.Device.Wifi.1.5.37
nanoFramework.System.Diagnostics.Stopwatch.1.2.141
nanoFramework.System.IO.FileSystem.1.1.15
nanoFramework.System.IO.Ports.1.1.46
nanoFramework.System.IO.Streams.1.1.27
nanoFramework.System.Math.1.5.18
nanoFramework.System.Net.1.10.38
nanoFramework.System.Net.Http.1.5.54
nanoFramework.System.Numerics.1.2.144
nanoFramework.System.Text.1.2.22
nanoFramework.System.Threading.1.1.8
UnitsNet.nanoFramework.ElectricCurrent.4.148.0
UnitsNet.nanoFramework.ElectricPotential.4.148.0
UnitsNet.nanoFramework.Power.4.148.0
UnitsNet.nanoFramework.RelativeHumidity.4.148.0
UnitsNet.nanoFramework.Temperature.4.148.0

Node-REDまわり

先に Node-RED の設定をしてしまいます。

Node-RED インストール~立ち上げ

一番初めに Node-RED をインストールします。

$ npm install node-red -g

で入りますね。
入ったら、

$ node-red

で立ち上がります。
立ち上がったらブラウザで、 http://127.0.0.1:1880/ にアクセスしてください。

多分こんな画面です。

ノード作成 & デプロイ

ここから色々設定していきます。

右上のメニューからパレットの管理で

ノードを追加します。

  • cn-dashboard-nodes

  • node-red-contrib-aedes

この2つが追加できたら、下記の画像の3つを使って、


こんな感じのノードを作りましょう。

あとは MQTT in のノードをクリックして、最終的にこの様になるように設定します。

サーバ部分に何もない場合はペンマークをクリックし、

新たにプロファイルを作ってしまいましょう。

ここまでできたら右上の デプロイ をクリックし、デプロイしてください。

これで Node-RED 側の設定は完了です。

ファームウェアの書き込み

nanoFrameworkを利用するためにはM5Stackに専用のファームウェアを書き込む必要があります。
生贄となる M5Stack Core2 を一つ用意してください。

Git Bash でも CMD でも PowerShell でも何でもいいので .NET6 の PATH が通っているコマンドラインを立ち上げましょう。

$ dotnet tool install --global nanoff

で nanoFramework 用のファームウェア書き込みツールが入ります。

nanoff --target M5Core2 --update --serialport COM17

で M5StackCore2 に nanoFramework のファームウェアが書き込まれます。

この状態で M5Stack を起動しても反応は無いですので、死んだと思わずに先に進みましょう。

nanoFramework周り

プロジェクト設定

とりあえず、Visual Studioで 拡張機能 -> 拡張機能の管理で ".NET nanoFramework Extension" をダウンロードして適応すると nanoFrameworkのテンプレートでプロジェクトを作成できるようになります。

 
画像の Blank Application を選択してプロジェクトを作ってしまいましょう。

プロジェクトができたら プロジェクト -> NuGetパッケージの管理 で 

  • nanoFramework.M5Core2
  • nanoFramework.System.Net
  • nanoFramework.System.Device.WiFi
  • nanoFramework.Json
  • nanoFramework.M2MQTT

をインストールしましょう。

実装

Program.csで下のコードを記述してください。

using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Numerics;
using nanoFramework.M5Stack;
using nanoFramework.Networking;
using nanoFramework.Json;
using nanoFramework.M2Mqtt;
using Console = nanoFramework.M5Stack.Console;

const string uri = "Your Address";
const int port = 1883;
const string ssid = "Your SSID";
const string password = "Your Password";
MqttClient client;
Setup();
ConnectWifi();

while (true)
{
    Loop();
    Thread.Sleep(500);
}

void Setup()
{
    M5Core2.InitializeScreen();
    Console.Clear();
    Console.ForegroundColor = nanoFramework.Presentation.Media.Color.White;
    client = new MqttClient(uri, port, false, null, null, MqttSslProtocols.None);
    var clientId = Guid.NewGuid().ToString();
    client.Connect(clientId);
}
void Loop()
{
    var ag = M5Core2.AccelerometerGyroscope;
    ag.Calibrate(100);
    var acc = ag.GetAccelerometer();
    var gyr = ag.GetGyroscope();
    Console.Clear();
    Console.WriteLine($"Accelerometer data x:{acc.X} y:{acc.Y} z:{acc.Z}");
    Console.WriteLine($"Gyroscope data x:{gyr.X} y:{gyr.Y} z:{gyr.Z}\n");
    var data = new NineAxisData
    {
        acceleromet = Vec3ToFloatArray(acc),
        gyroscope = Vec3ToFloatArray(gyr)
    };
    var postDataJson = JsonSerializer.SerializeObject(data, false);
    Debug.WriteLine(postDataJson);

    try
    {
        client.Publish("nanoM5", Encoding.UTF8.GetBytes(postDataJson));
    }
    catch (Exception e)
    {
        Console.WriteLine("Network Error");
    }
}
float[] Vec3ToFloatArray(Vector3 vector)
{
    float[] returnValue = { (float)vector.X, (float)vector.Y, (float)vector.Z };
    return returnValue;
}

void ConnectWifi()
{
    CancellationTokenSource cs = new(60000);

    var success = WifiNetworkHelper.ConnectDhcp(ssid, password, requiresDateTime: true, token: cs.Token);
    if (!success)
    {
        Debug.WriteLine($"Can't connect to the network, error: {WifiNetworkHelper.Status}");
        if (WifiNetworkHelper.HelperException != null)
        {
            Debug.WriteLine($"ex: {WifiNetworkHelper.HelperException}");
        }
    }
    else
    {
        Debug.WriteLine("Wifi Connected!");
    }
}
[Serializable]
public class NineAxisData
{
    public float[] acceleromet { get; set; }
    public float[] gyroscope { get; set; }
}

ソースを見て、これがC#...?ってなった方も多いでしょう。
これが、.NET6 で新たに実装されたコーディングスタイルなのです。
しかし、Pythonみたいに動的にコンパイルされるというわけではないので、それらと同じ感じで書いたらふつーにエラーが出ます。
詳しくは (公式ドキュメント)[https://learn.microsoft.com/ja-jp/dotnet/core/tutorials/top-level-templates] を御覧ください。
(というかあんまり使う機会は今のところないです)

書き込み

書き込むためには Diveice Exlorer ウィンドウで書き込むポートを指定する必要があります。

探すのがめんどくさので、Ctrl + Q で Device Explorer で検索して表示させてしまいましょう。

画像のように、先程書き込んだM5Stackが出ていればOKです。

あとは選択した状態で、上部の .NET nanoFramework Device を押しましょう。

待っていれば書き込まれます。

確認

M5Stackのディスプレイに加速度やジャイロセンサーの値が表示されていれば問題なく動作しています。

では、Node-RED上で確認してみましょう。
右上の虫マークをクリックしてください。

値がJSON形式で送られているのがわかると思います。

本稿での解説は以上です。

感想

いかがでしたでしょうか?
nanoFrameworkを使ってみた感想ですが、Visual Studioでしか開発できないのは痛いなというのが私の率直な感想です。
M5Stackならイテレーションの速度的にもはUIFlowが一番楽だなと感じています。
機会があればその話もできたらいいと思っていますが、UIFlowに関してはn番煎じが過ぎるので多分しないでしょう。

とりあえずCPSLab2022 AdventCalendar 18日目 は以上です。
明日は @naokiさん になります!

是非、弊研究室の闇を感じてもらえると幸いです。

Discussion