M5StackでDCモーター制御

M5StackでのPWM制御はArduinoとは違うようなので記録。

① PWMのセットアップ(ledcSetup())を行う

② PWMの制御ピンを論理チャネルとコンバイン(ledcAttachPin())する

③ PWM制御信号を出力(ledcWrite())する

DCモーターの回転方向とブレーキを決める信号は通常のdigitalWrite()で実行。

/#include <m5stack.h>

const uint32_t PWM_Hz = 2000; // PWM freq.
const uint8_t PWM_level = 8;  // PWM resolution 8bit(1~256)
const uint8_t PWM_CH = 1;     // PWM channel

int pwm_a = 2;
int fw_a = 16;
int rv_a = 17;
int pwm_b = 26;
int fw_b = 5;
int rv_b = 25;

void setup() {
  M5.begin();
  M5.Power.begin();

  pinMode(pwm_b, OUTPUT);
  pinMode(fw_b, OUTPUT);
  pinMode(rv_b, OUTPUT);

  // set PWM_CH & resolution
  ledcSetup(PWM_CH, PWM_Hz, PWM_level);
  // combine PWM control pin to PWM_CH
  ledcAttachPin(pwm_b, PWM_CH);
}

void loop() {
  M5.update();

  if (M5.BtnA.wasPressed())
  {
    // PWM duty 0.25(64/256)
    ledcWrite(PWM_CH,128);
    digitalWrite(fw_b, LOW);
    digitalWrite(rv_b, HIGH);
  }
  else if (M5.BtnC.wasPressed())
  {
    // stop
    ledcWrite(PWM_CH,0);
  }

  delay(10); 
}

DIOのピンアサインは以下の通りです。M5StackはArduinoと違ってDIOの本数が限定させるので、他の信号と重複するのは致し方なし。

 

 

admin

ProcessingでM5StackのPoseをモデルに反映する

引き続いて、M5Stackのpitch/roll/yaw情報をUDPで送って、Processing上のモデルに反映してみます。

M5Stackからはpitch/roll/yaw情報をカンマ区切りのテキストで送ります。

このテキストをProcessingで受信して、直方体のモデルのposeに反映します。正負が逆になったx/z軸は値を反転。座標系の取り方でどうにでもなるような気もしますが。

Processingのソースは見ての通り単純です。最初3Dの描画できなくて調べたらベータ版では動かないようで4.1.1にアップデートしたらきちんと動作しました。

codeは、

https://github.com/chateight/processing/blob/main/sketch_221220b.pde

/*
read m5stack udp data(IMU data ; pitch, roll, yaw) and move the imaginary object

*/
import hypermedia.net.*;

UDP udp;
final String IP = "0.0.0.0";

PFont myFont;

float[] pry = new float[3];      // pitch, roll, yaw store work


void setup() {
  
  udp = new UDP(this, 3002);
  udp.listen( true );

  size(500,500,P3D);
  frameRate(30);
  loop();
}

void draw() {
  background(0);
 
  translate(width/2, height/2);
  rotateX(radians(-pry[1]));
  rotateY(radians(pry[0]));
  rotateZ(radians(-pry[2]));
  box(150, 150, 50);
}

void receive( byte[] data, String ip, int port ) {
  String message = new String( data );
  println( "received : \""+message+"\" from "+ip+" on port "+port );
  
  String[][] matchedTexts = matchAll(message, "[0-9|-]+.[0-9]+");

  if (matchedTexts != null) {
    int index = 0;
    for (String[] matchedText : matchedTexts){
      pry[index] = float(matchedText[0]);
      index++;
    }
  }
  println(pry[0], pry[1], pry[2]);    // pitch, roll, yaw
  
}

動かして見たのは、今のYouTube画面で参照ください。yawは時間経過とともにずれていくのでいくらか補正はしていますが、十分じゃ無いですね。

 

admin

Processingで受信データをグラフ化する

M5Stackからのデータを視覚化するのに、一番手軽に使えそうなツールだと思うProcessingでM5StackからUDPで送られてくる温度データを時系列でグラフ化してみました。Bluetoothで送るのは接続不安定でストレスになるから、簡単に送れるUDPを使います。電池寿命とか関係ないし、

<M5Stackから送られるメッセージ形式>

日時(秒まで)と温度データ

<Processingのコード>

メッセージから、温度部分を抜き出して表示しています。Processingの画像処理は専用のAPIになっています。正規化処理もJavaとは別物ですが、

receive()メソッドは、UDPリッスンで受信データがあれば起動されるでしょうが、drawの読み出し(val)と書き込みが競合すれば値は不定になる可能性はありそうですが、視覚的なものなので排他制御をするまでもないでしょう。

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             

import hypermedia.net.*;
import controlP5.*;

UDP udp;
final String IP = "0.0.0.0";

ControlP5 cp5;
Chart chart_tmp;
final int NUM_GRAPH_DATA = 200;

PFont myFont;

float val;

void setup() {

  size(650, 700);
  myFont = createFont("Arial", 30); 
  
  udp = new UDP(this, 3002);
  udp.listen( true );

  frameRate(10);
  cp5 = new ControlP5(this);
  
  chart_tmp = cp5.addChart("tmp sensor");
  chart_tmp.setView(Chart.LINE)                             
            .setRange(20, 22)                         
            .setSize(600, 200)                               
            .setPosition(10, 250)                           
            .setColorCaptionLabel(color(0,0,255))          
            .setStrokeWeight(1.5)                            
            .getColor().setBackground(color(224, 224, 224))  
            ;
  chart_tmp.addDataSet("temp");
  chart_tmp.setData("temp", new float[NUM_GRAPH_DATA]);
  chart_tmp.setColors("temp", color(0, 0, 192), color(255,255,128));

}

void draw() {
  
  background(255);
  fill(0);

  chart_tmp.unshift("temp", val);
}

void receive( byte[] data, String ip, int port ) {
  String message = new String( data );
  println( "received : \""+message+"\" from "+ip+" on port "+port );
  
  String[] matchedTexts = match(message, "[0-9|-]*.[0-9]*$");

  if (matchedTexts != null) {
    println(matchedTexts[0]);
    val = float(matchedTexts[0]);
  }

}

動画はこちらを参照ください、グラフ下端が20℃、上端が22℃で範囲を拡大して見やすくしています。

processing – SD 480p

 

admin

 

 

M5StackのBluetooth Serial(追加)

以前にやった時もそうですが、接続が安定しない原因は何なのかの単純化ですが、相変わらずロジックは分かりません。

M5stack Bluetoothでのmacとの送受信

Arduino IDEで以下のようなソースを動作、

#include <M5Stack.h>
#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

int cnt = 0;

void setup() {
  Serial.begin(115200);
  SerialBT.begin("ESP32");
}

void loop() {
  SerialBT.println("Hello World : " + String(cnt));
  cnt += 1;
  delay(1000);
}

ここで、ArduinoIDEのシリアルをBluetoothに選択、

 

すると、コンソールに結果出力されますが、この状態でMacのコンソールを開く(つまりコンソールが2台ある状態)だと、両方のコンソールにランダム風に結果が出力されます。これはまともでしょう、

いずれの状態でもMac本体のBluetoothはペアリングはしていない。

これだけシンプルでも、再コンパイルとかで期待したように動かなくなります。回避方法はMacの再起動のみ。

再起動すると、以下のようにBluetooth接続も復活しますが。

この後でArduinoIDE側のシリアルをUSBに切り替えて、Macコンソールを起動、

ここまでは正常ですが、ここでM5Stackをリセットすると接続が切れて復旧しない。これはArduinoIDE側のシリアルをBluetoothにしていても同じだから、Macを立ち上げて最初にBluetoothシリアル使うまではいいけれども、その後なんらかのアクションをすると必ずMacをリブートしなければいけないという不条理な状態になっています。

 

admin

バランスロボット

二輪で、本体の傾きをセンスしてバランスをとりながら倒れないように制御するロボット(倒立振子というらしい)ですが、イメージとしては秋田の竿燈みたいなものか。竿燈は二次元の制御だけど、二輪ロボットは一軸制御だから制御は相対的には楽そうに見えます。

回転モーメントが大きいほど、つまり高さ方向が長いほどフィードバック時間に余裕がありそうに思えますね。

原理は、

https://matome.eternalcollegest.com/post-2136401209031725401

完成品としては、

https://docs.m5stack.com/en/app/bala2fire

や、

https://www.switch-science.com/products/8297

あたりがありそうですが、M5stack使って自作するというのもありそうです。

例えばこれとか、

https://maker.pro/arduino/projects/build-arduino-self-balancing-robot

PID制御はカットアンドトライでパラメータを決めるのが現実らしい。PIDライブラリというのがArduinoには用意されていて、Arduino IDEのライブラリで検索するとたくさん出てきます。

 

admin

M5stackでTelloを制御

M5stackでUDPが使えるから、Telloのコマンド制御もできるよねと思いましが、既に先人のコードができてます。

https://qiita.com/Mitsu-Murakita/items/b86ad79d3590adb3b5b9

TelloのSSIDだけを追加すれば動きましたが、動作がイマイチもっさり、というのはスイッチの反応が遅くて多少長押ししないとtake offもしない。

で時間待ちの500msを150msにするとほぼイメージ通りに動きますが、疑問点が一つ。

wasPressed()関数って、ボタン押されたことを記憶できる関数のはずなのになぜ長押ししないといけないか?

loop()の中でボタン機能の確認コードを作って確認してみると、どうもdelay()中にボタンを押してもwasPressed()には反映されない模様です、だからdelay()で設定した時間以上にボタンを押していないといけないようです、仕様として変だと思いますが。

~~~
  if ( M5.BtnA.wasPressed() ) {
    Serial.println("BtnA.wasPressed() == TRUE");
  }
  //Serial.println("loop");

  delay(300);
~~~

 

あとフリップ動作は、イマイチスイッチを押すタイミングとM5stackを傾けるタイミングが掴めない。

 

admin

オランダの320Kbpsラジオ局

ベートーベン・チャネルとは言ってますが、正確にはベートーベン同時代古典派の作曲家の曲を流すと言った方が正確でしょう。間違ってもロマン派とかイタリア、ロシアの作曲家の曲は流れてきません。

MozartやHydnも流れてきますが、画像にあるようにオランダオーケストラの曲で時々のアナウンスでもNetherlandからと言ってます。おおむねどこのラジオ局でもラジオ局が属する国の楽団の演奏を流すのは、自国の文化の宣伝という意味のほかに著作権料でも優遇されるからなのかも知れません。

 

admin

Nodeと関連技術

Nodeに関連して検索したサイトと自分用のメモです。

 

○ WebSocketのURL形式

通信時に指定するURLは、

ws://www.sample.com、あるいはセキュア接続ならwas://www.sample.com

明に使うことはあまりないだろうけども

 

○ Node.jsでソケット通信

<socket.ioのインストール>(アプリを作成するディレクトリで)

% npm install socket.io 

もはやdgramはインストール不要らしい

 

○ websocket動かすには

Node.jsとExpressの他にwsライブラリのインストールも必要、本当?

<HTTP serverとclientサンプル>

socket.ioを使った、

以下の二つはGitHubのサンプル動かしているのでセット

https://qiita.com/kouji0705/items/cf16044c7d825d09d707

https://github.com/neroneroffy/webSocketDemo

https://ai-soldier.work/websocket-node-ws/#

これ動かしてみたけど、ラズパイでも軽快に動く

 

○ Express

<documents>

https://expressjs.com

<解説>

https://qiita.com/mml/items/3cc90479df033c0998e4

https://qiita.com/ganyariya/items/85e51e718e56e7d128b8

<起動>

$ npm start

 

○ pug(HTMLテンプレート)について

<pugの概要>

https://and-ha.com/coding/what-is-pug/

こんなこともできる(markdownをincludeしてHTML出力)

https://ytyaru.hatenablog.com/entry/2018/05/01/000000

<pugの拡張>

https://qiita.com/zenno04/items/d16f881170170b567b16

Template Inheritance

https://pugjs.org/language/inheritance.html

 

○ wsサーバーの起動

Express serverとWebSocket severそれぞれ別に起動で良い

$ node ws_server.js

実際の運用は起動スクリプトに書くから個別起動で問題ない

 

○ Javascript(chart.js)でグラフ作成

json使いましょう

https://www.web-development-kb-ja.site/ja/javascript/chartjsでjsonデータを表示する/833307193/

 

○ JSからEJSへ

https://fukuno.jig.jp/2819

use strict : ESM(ES module)有効なら指定不要だったよね

 

admin

ラズパイでWebSocket通信(その3)

 

https://isehara-3lv.sakura.ne.jp/blog/2022/11/29/ラズパイでwebsocket通信(その2)/

の続編で、

① M5stackからラズパイにUDPでデータ送信して、

② ラズパイとクライアント間でweb_socket使ってリアルタイムのデータ更新(今は5秒毎にM5stackから送信)、

③ 受信データをchart.js使ってグラフ化(データ最大5回分)、

します。

WebSocketで送られるデータ形式は汎用性考慮してjson形式を使っています。

全体のコードは、

M5stack側、

https://github.com/chateight/multi_sensor_udp_comm

ラズパイ側、

https://github.com/chateight/web_socket

となります。現状、測定値を送信するのはthermo_sensorのコードだけですが、他のセンサーでも同じルーチン(udp_loop(String))呼び出せば送信できます。

web_socketはセッションが有効な時しか働かないので、セッションが切れればデータは更新されません。

ブラウザ画面の表示はこちらを、

m5stack_ws – 720WebShareName

 

admin

Davide of mimic

これもネットラジオ曲ですが、イギリスからの高音質(320Kbps)のラジオ。

https://www.davideofmimic.com

しばらく中断していましたが、再開されてます。

広告なしでどうやって運営してるのかは気になるところ、オペーレーティング費用の他に著作権料の支払いも必要なわけだし。ドネーションだけで全て賄ってる?

無料のspotifyは音質イマイチで広告入るから最近あまり使わない。サブスクするまでも無さそうだし、

 

admin