M5Stack ボタンユニット

概要

M5Stack社のユニット紹介シリーズです。今回はボタンユニット。一番地味な?ユニットですね、、、

商品

単純なユニットなので、かなり安いですね。

インは普通に外側みたいです。

こんな感じのボタンになっています。M5StickCのBtnAと同じような感じになっていて、押すとカチカチ音がします。

スケッチ例

const int button = 33;  // M5StickC

void setup() {
  Serial.begin(115200);
  pinMode(button, INPUT);
}

void loop() {
  Serial.println(digitalRead(button));
  delay(100);
}

GPIOの値を単純に読み取って、押すとLOW(0)になるのを確認します。

M5StickCのボタンクラスを使う

#include <M5StickC.h>

const int button = 33;  // M5StickC

Button BtnGrove = Button(button, true, DEBOUNCE_MS);

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

void loop() {
  BtnGrove.read();
  if (BtnGrove.wasPressed()) {
    Serial.println("wasPressed");
  } else if (BtnGrove.wasReleased()) {
    Serial.println("wasReleased");
  }

  delay(100);
}

こんな感じになります。ただこのクラスは内部処理でプルアップしているのが気になるので非推奨です。

元になったライブラリを見てみたら、AVR用なので使うと警告でるんですよね。過去のPRみたらAVR用を消してくれと出ていましたが、リジェクトされていました。

まとめ

ちょっと離れた場所にボタンを設置したい場合には非常に便利なボタンです。値段も安いので持っていてもいいのかな?

M5Stack PM2.5 エアクォリティーセット

概要

M5Stack BASICとPM2.5用センサーが搭載されているボトムがセットになっている商品があったので購入してみました。

商品

こちらの商品になります。日本未発売かな?

たまーにある、本体セットじゃないと売っていない商品になります。M5Stack BASICを買おうと思ったのですが、どうせならということでこちらのセットにしてみました。

スタンド、M5Stack BASICにPM2.5ボトムのセットで、M5Stack BASICとPM2.5ボトムはくっついた状態で箱に入っています。ちなみにBASICの標準ボトムはついていません(涙)

おそらくこちらがM5Stack BASICに標準でついているバッテリー内蔵のボトムだと思います。まあ、バッテリーで動かすことないので必要ないのですが、他に購入するものがあるときに一緒に入手しておきたいと思います。

PM2.5ボトムはこんな感じの作りになっています。左上の場所にUSBを接続するコネクタがあります。

スタンドに立てた場合には、こちらにケーブルを接続するのを推奨しているはずです。

ボトムを分解したところ、こんな感じです。はじめての分解ですがしっかりささっていて、たしかに抜き差ししているとコネクタがもげるのもわかります。。。

固定用のネジがついていますが、このままだと長いので注意しましょう。このままネジを締めていくと画面を壊してしまいます!

このようにスタンドをつけて固定するための長さになっています。

スタンドはこんな感じです。

USBコネクタがあるのですが、PM2.5ボトムはセンサーの出っ張りがあるので使えなくなってしまいます。

裏側はこんな感じです。

このスタンドは別売りしていたの知っていたのですが、よく見ると回路が違うので別商品です!

どうやらPM2.5ボトムに温湿度センサーのSHT20が内蔵している関係で、スタンドにあったSHT30を削ったみたいです、、、後継であるSHT30の方が良かったな、、、

まとめ

PM2.5ボトムは単品では買えないので買ってみました。しかしながら欲しかったのはM5Stack BASICなのでPM2.5ボトムはあまり使っていません、、、

ただバッテリー内蔵していないのでUSBケーブル抜けば電源切れるってのは便利です!

M5Stack カラーセンサユニット

概要

M5Stack社のユニット紹介シリーズのカラーセンサユニットです。色を判定して取得することができます。

商品

赤のコネクタなのでI2C接続ですね。

使っているセンサーはTCS34725です。

まんなかの赤い部分がセンサーで、左右にLEDが並んでいます。LEDで光らせながらセンサーで読み取っていますので真っ暗な場所でも読み取ることができます。

UIFlowでの使い方

四角を画面において、その色を変更させています。背景色はRGB指定だと指定できないんですよね。

私の環境だと若干赤が弱かったですが、そこそこ色が判定できました。ただし紙みたいなもので画面上の色はちょっと難しかったです。

Arduinoでの使い方

ArduinoのサンプルスケッチではAdafruit_TCS34725を使っていますが、素のセンサーからの数値は取得できますが、一般的な色に変換するところがうまく動いていません。

このセンサーは明るさと赤、緑、青の4種類のセンサーが搭載されていますが、色ごとに感度が違うのでそのままの数値だと人間がみた色にはなりません。このへんはRGB LEDとかも色ごとに調整が必要なのと変わらないと思います。

AdafruitのセンサーとはLEDの色温度とか特性が違っていて、取得できる色も違うのではと思いますがよくわからないです。UIFlowではそれなりに色が取得できたので、なにか独自の補正をしていると思いますが、Arduinoのコード例はありません。

Arduinoで使いたい場合には素のセンサーの値をいろいろな色でどうなるか調べてみて、自分で補正をしてあげる必要がありそうです。ちょっといじってみたところ、明るさのCの値が重要そうですが時間かかる感じなのでまた今度にしたいと思います。。。

まとめ

んー、ちょっと使いにくい感じでした。最近だとマリオのLEGOが色センサー使っていましたね。クリボーとかの色を足の下のセンサーで読み取っているみたいです。

あの使い方だと、使っている色をすべて調べてテーブルにしておけば問題なさそうですね。

無印良品 タグツール・ルーペ ホワイト/3倍・7倍(M5StickC用ケース)

概要

さいきん話題になっている無印良品のM5StickC用ケースこと、タグツールをやっと購入してみました。ケースだけだと寂しいのでルーペも買ってみました。

商品

タグツールとは無印良品の展開するトラベル用品のシリーズで、5色のシリコンケースとその中に入れるツールになります。

中身はルーペーの他にLEDライトや静電気除去ツールなど、いろいろあります。ケースは290円で中身は490円ぐらいからあります。

M5StickCにつけてみた

厚みはピッタリですが、縦に伸ばして付ける感じになります。ちょっと伸びているので真ん中がゆがんでしまいますね。

ちなみに底には穴が空いているのでケーブルもささります。

ルーペ

とりあえず一つぐらいはと思って買ってみました。案外便利につかえています。

レンズは2種類で3倍と7倍です。7倍は1.8cmの距離なのでかなり近づけないと見えないので使いにくいです。3倍は使いやすいですね。

写真にとるのは非常に難しいですが、こんな感じです。ちなみにiPhoneのカメラでそのまま拡大したほうが見やすいかもしれませんが、やっぱり直接目で見るのもいいものです。

まとめ

Bluetoothビーコン的な使い方とかでM5StickCを大量にばらまくときなどに、このケースに入れておくとかするとかわいいと思います。

M5Stack VH3.96 – 4ピンユニット

概要

M5Stack社のユニット紹介シリーズです。今回はちょっと変わり種の3.96ユニット!

商品

価格は日本で発売しているユニットでは最安値だったのですが、最近ちょっと値上がりしました。ちなみに一番安いのが70穴のプロトユニットです。本家には40穴があって、少し前は最安値だったのですが値段が上がって70穴と同じ値段になってしまいました。

中に入っているのはユニット本体と、スクリューターミナルにGroveケーブルです。このターミナルが3.96ミリピッチでVH3.96とか、HT396Kって規格みたいです。ATOMとかでも使われていますね。

たぶんこのコネクタかな?

日本だとあまり使われていない規格で、ほぼ国内だと手に入りません。ebayにもあまり取り扱いがなかったので、中国ローカルの規格かもしれませんね。

このユニットはGroveケーブルからVH3.96コネクタに変換するだけの機能になります。ケーブルと端子の対応がクロスになっているので注意して使ってください。Grove端子ではないセンサーなどをVH3.96コネクタを使って接続するのに便利なユニットになります。

VH3.96コネクタがちょっと手に入りにくいのが難点ですが、複数用意しておけば差し替えて使えるので便利かもしれません。ちょっとした接続にはスクリューターミナルの方が手軽ですしね。

端子はこんな感じでしっかり接続を固定することができます。

差し込んだ状態です。2本爪のようなものがありますが、がっちりとは固定せずにバネみたいな感じで抜けを防いでいる感じです。

まとめ

Groveケーブルを自分で作ればいいのですが、圧着ではなくスクリューターミナルで取り外しができる用途であればかなり便利に使えると思います。値段も安いので何個か持っていてもいいのかもしれません。

M5StickCとM5StickC Plusの違い

概要

M5StickCとM5StickC Plusを主にArduino IDEで開発する場合の違いを調べてみました。

上記の記事も参考にしてください。

スペックの違い

M5StickCM5StickC Plus
TFTコントローラーST7735SST7789
液晶サイズ0.96インチ1.14 インチ
画面サイズ80×160135×240
6軸IMUSH200Q or MPU6886MPU6886
ブザーなしGPIO2
バッテリー95 mAh @ 3.7V120 mAh @ 3.7V
PINポートG0, G36, G26, G32, G33G0, G25/G36, G26, G32, G33

まず本体サイズは同じなのですが、液晶サイズが異なっています。また、解像度が上がっている関係で同じ画面を表示してもM5StickC Plusの方が小さく表示されます。また、コントローラーが違うので同じライブラリでは動作しません。

またM5StickCの初期はIMUにSH200Qが使われていましたが、現在はMPU6886のみになっています。初期のM5StickCに対応する場合には注意が必要です。

M5StickC Plusにはブザー(GPIO2)とGPIO25が増えています。ブザーは圧電ブザー的なのが内蔵されており、ちょっとした音を出すことができます。GPIO2はDAC出力できる端子ではないので、音声などを喋らせることはできません。またGPIO25が追加されていますが、GPIO36と同じピンにでていますので同時に利用することができませんので注意しましょう。GPIO36を利用する場合にはGPIO25をpinMode(25, INPUT)にしてハイインピーダンスにしておく必要があります。

ライブラリの違い

M5StickCとM5StickC Plusは利用するライブラリが異なります。しかしながら同じように使うことができるようにはなっています。

M5StickC PlusでM5StickCのFactoryTestを動かしてみる

includeを書き換える

//#include <M5StickC.h>
#include <M5StickCPlus.h>

利用するライブラリを切り替えるために、上記の行を書き換えます。基本的にはこれで大体のスケッチが動くのですが、IMU周りの差異でこのままだと動かない場合があります。

IMU周りの対応

M5StickCはIMUが違う端末がある関係でSH200QクラスとMPU6886クラスがあり、自動判定をして呼び分けるIMUクラスもあります。基本的にIMUクラスを読み出せば内部で自動判定をする形なのですが、直接MPU6886クラスを呼び出すことも可能です。また、IMUクラスにはどっちのIMUかを判定する関数などが追加されています。

M5StickC PlusはIMUがMPU6886の端末しかありませんので、MPU6886クラスしかありません。しかし、呼び出しはM5.IMUになります。そのためM5.MPU6886で呼び出しているスケッチは書き直す必要があります。

M5StickCのFactoryTestはM5.MPU6886を呼び出しているのでこのままだとエラーになります。。。GitHubにある最新バージョンはM5.IMUを呼び出すように変更されているのですが、逆にIMUの判定をしている関数を呼び出しているのでそのままだと動きません、、、

#include <M5StickCPlus.h>
#define MPU6886 IMU

M5.MPU6886でエラーがでた場合には上記のようにIMUに書き換えるか、M5.MPU6886をM5.IMUに置換してください。

        //if(M5.IMU.imuType == M5.IMU.IMU_SH200Q)
        //{
        //    imuName = "SH200Q";
        //}
        //else if(M5.IMU.imuType == M5.IMU.IMU_MPU6886)
        //{
        //    imuName = "MPU6886";
        //}

M5.IMU.imuTypeでエラーが出た場合には、エラーがでた場所をコメントアウトしてみてください。

FastLED関係

M5StickCのFactoryTestで誤ってFastLEDが読み込まれています。FastLEDをインストールするか該当部分をコメントアウトしてください。

//#include <FastLED.h>

//#define NUM_LEDS 3
//CRGB leds[NUM_LEDS];

上記の3行になります。ここ結構ハマっている人が多いのでご注意を、、、

GitHubの最新版だとここが削られています。

パーティションテーブル変更

/*
    note: need add library FastLED from library manage
    Github: https://github.com/FastLED/FastLED

    note: Change Partition Scheme(Default -> NoOTA or MinimalSPIFFS)
*/

M5StickCのFactoryTestには一番上にこのコメントがあります。このコメント見落としている人が多いのですが、そのままビルドするとフラッシュが足りなくてエラーになります!

パーティションテーブルを変更してください。ちなみにGitHubの最新版だとがんばって圧縮してデフォルト設定でビルドできるようになっています。

MahonyAHRSに注意

M5StickCにはありますが、M5StickC Plusには存在しませんので注意してください。

全般的にバージョンが、、、

In_eSPIクラスの中身がちょっと違うので、サポートしている関数が違ったりしています。完全互換性はありませんので注意してください。。。

1バイナリで対応したい場合

M5StickCとM5StickC Plusを同じバイナリファイルで対応いたい場合には、公式ライブラリを使うのを諦める必要があります。

グラフィックライブラリにはLovyanGFXを利用すると、内部で自動判定してくれますので画面サイズが違うだけで、同じようにプログラムを組めますし高速描画が可能です。

#include <LGFX_TFT_eSPI.hpp>
#include "AXP192.h"
#include "utility/Config.h"
#include "utility/SH200Q.h"
#include "utility/MPU6886.h"
#include "utility/Button.h"
#include "utility/CommUtil.h"
#include "RTC.h"
#include "IMU.h"

#define BLACK               0x0000
#define NAVY                0x000F
#define DARKGREEN           0x03E0
#define DARKCYAN            0x03EF
#define MAROON              0x7800
#define PURPLE              0x780F
#define OLIVE               0x7BE0
#define LIGHTGREY           0xC618
#define DARKGREY            0x7BEF
#define BLUE                0x001F
#define GREEN               0x07E0
#define CYAN                0x07FF
#define RED                 0xF800
#define MAGENTA             0xF81F
#define YELLOW              0xFFE0
#define WHITE               0xFFFF
#define ORANGE              0xFD20
#define GREENYELLOW         0xAFE5
#define PINK                0xF81F

class M5StickCBoth {
  public:
    void begin(bool LCDEnable = true, bool PowerEnable = true, bool SerialEnable = true) {
      if (SerialEnable) {
        Serial.begin(115200);
        Serial.flush();
        delay(50);
        Serial.print("M5StickC initializing...");
      }
      if (PowerEnable) {
        Axp.begin();
      }
      if (LCDEnable) {
        Lcd.begin();
      }
      if (SerialEnable) {
        Serial.println("OK");
      }
      Rtc.begin();
    }
    void update() {
      BtnA.read();
      BtnB.read();
    }
    TFT_eSPI Lcd;
    AXP192 Axp = AXP192();
    const int DEBOUNCE_MS = 10;
    Button BtnA = Button(BUTTON_A_PIN, true, DEBOUNCE_MS);
    Button BtnB = Button(BUTTON_B_PIN, true, DEBOUNCE_MS);
    RTC  Rtc;
    IMU Imu;
    CommUtil I2C = CommUtil();
    MPU6886 Mpu6886;
    SH200Q Sh200Q;
};

static M5StickCBoth M5;

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

void loop() {
  M5.Lcd.fillScreen(WHITE);
  delay(1000);
  M5.Lcd.fillScreen(BLACK);
  delay(1000);
}

ざっくりM5StickCのライブラリ互換で、LovyanGFXを利用するサンプルです。とはいえ、実際にはM5StickCのライブラリも内部にあって、無駄に容量を食ってしまいます。

本当はAXP192、RTC、IMU周りのクラスが独立してあればM5StickCライブラリに依存しないのですが、今の所個別ライブラリがないんですよね、、、

何故かRTCとAXP192の初期化部分は独立して使えるライブラリを開発中なので、IMUまわりの互換ライブラリも作って公開するかもしれません。そうすればM5Stackの公式ライブラリではなく、互換ライブラリを自分で組み合わせて使えるようになってハッピーな人が増えるかもしれません、、、

まとめ

M5StickCとM5StickC Plusのライブラリが別なのはちょっとがっかりでした。最近Arduinoライブラリの整備が遅れている気がするので、そろそろ公式ライブラリを捨ててもいいかなって思うようになってきました。

M5StickCは結構プルリクエストを書いて、取り込んでもらいましたが公開がなかなかされないんですよね。ATOMも色がおかしいのが修正されませんし、M5Stackのライブラリも混沌としている気がします、、、

M5Stack 振動モーターユニット

概要

M5Stack社のユニット紹介シリーズです。今回はバイブレーションユニットです。振動でお知らせしたいときには便利だと思います。

商品

FANユニットは日本語に訳していなかったのですが、バイブレーションユニットはスイッチサイエンスさんの商品名が日本語になっている!

コネクタが黒なのでI2Cではありません。

こちらもFANユニットと同じくN20モーターを利用しています。上に見えるのが偏芯オモリで、回転することで振動させます。

裏側です。

偏芯オモリのアップです。ここまで見てわかったと思いますが、FANユニットと同じものに偏芯オモリをつけたものになります。値段も同じです!

スケッチ例

const int motor_pin = 32; // M5StickC
const int ledChannel = 0;

void setup() {
  Serial.begin(115200);

  // PWMで速度を制御
  ledcSetup(ledChannel, 12000, 8);
  ledcAttachPin(motor_pin, ledChannel);
}

void loop() {
  // 始動は20%以上で15ミリ秒以上必要
  ledcWrite(ledChannel, 256 * 0.2);
  delay(15);

  // 回り始めれば10%でも動く
  ledcWrite(ledChannel, 256 * 0.1);
  delay(2000);

  // 停止
  ledcWrite(ledChannel, 0);
  delay(1000);
}

FANユニットと全く同じ使い方です。

まとめ

FANユニットと同時に紹介したほうがいい気も下のですが、ユニット別の紹介ページを作ろうとおもったので、別に紹介しています。

M5StickC Plusでバックグラウンド音楽再生

概要

M5StickC Plusに搭載されているブザーを、マルチタスクを利用してバックグラインド再生を試してみました。実際の音楽データはBLE-MIDIを使って、レコーディングしました。

BLE-MIDIでレコーディング

再生する元データを作るって結構面倒ですよね?

なので、今回はBLE-MIDIを使ってパソコンから音データをM5Stick Plusに流し込んで、そのデータを使って再生することにしました。

スケッチ

#include <M5StickCPlus.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

#define MIDI_SERVICE_UUID         "03b80e5a-ede8-4b33-a751-6ce34ec4c700"
#define MIDI_CHARACTERISTIC_UUID  "7772e5db-3868-4112-a1a9-f2669d106bf3"
#define DEVIVE_NAME               "M5StickC"

BLEServer *pServer;
BLEAdvertising *pAdvertising;
BLECharacteristic *pCharacteristic;
int pos = 0;
char midi[5];

uint16_t frequency_list[] = {
  9, // 0
  9, // 1
  9, // 2
  10, // 3
  10, // 4
  11, // 5
  12, // 6
  12, // 7
  13, // 8
  14, // 9
  15, // 10
  15, // 11
  16, // 12
  17, // 13
  18, // 14
  19, // 15
  21, // 16
  22, // 17
  23, // 18
  24, // 19
  26, // 20
  28, // 21
  29, // 22
  31, // 23
  33, // 24
  35, // 25
  37, // 26
  39, // 27
  41, // 28
  44, // 29
  46, // 30
  49, // 31
  52, // 32
  55, // 33
  58, // 34
  62, // 35
  65, // 36
  69, // 37
  73, // 38
  78, // 39
  82, // 40
  87, // 41
  92, // 42
  98, // 43
  104, // 44
  110, // 45
  117, // 46
  123, // 47
  131, // 48
  139, // 49
  147, // 50
  156, // 51
  165, // 52
  175, // 53
  185, // 54
  196, // 55
  208, // 56
  220, // 57
  233, // 58
  247, // 59
  262, // 60
  277, // 61
  294, // 62
  311, // 63
  330, // 64
  349, // 65
  370, // 66
  392, // 67
  415, // 68
  440, // 69
  466, // 70
  494, // 71
  523, // 72
  554, // 73
  587, // 74
  622, // 75
  659, // 76
  698, // 77
  740, // 78
  784, // 79
  831, // 80
  880, // 81
  932, // 82
  988, // 83
  1047, // 84
  1109, // 85
  1175, // 86
  1245, // 87
  1319, // 88
  1397, // 89
  1480, // 90
  1568, // 91
  1661, // 92
  1760, // 93
  1865, // 94
  1976, // 95
  2093, // 96
  2217, // 97
  2349, // 98
  2489, // 99
  2637, // 100
  2794, // 101
  2960, // 102
  3136, // 103
  3322, // 104
  3520, // 105
  3729, // 106
  3951, // 107
  4186, // 108
  4435, // 109
  4699, // 110
  4978, // 111
  5274, // 112
  5588, // 113
  5920, // 114
  6272, // 115
  6645, // 116
  7040, // 117
  7459, // 118
  7902, // 119
  8372, // 120
  8870, // 121
  9397, // 122
  9956, // 123
  10548, // 124
  11175, // 125
  11840, // 126
  12544, // 127
};

int frequency = 0;
int duration = 0;
unsigned long startTime = 0;

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      M5.Lcd.setTextSize(1);
      M5.Lcd.setCursor(10, 0);
      M5.Lcd.printf("BLE MIDI Connected. ");
    };

    void onDisconnect(BLEServer* pServer) {
      M5.Lcd.setTextSize(1);
      M5.Lcd.setCursor(10, 0);
      M5.Lcd.printf("BLE MIDI Disconnect.");
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = pCharacteristic->getValue();
      pos = 0;

      if (rxValue.length() > 0) {
        for (int i = 0; i < rxValue.length(); i++) {
          midi[pos] = rxValue[i];
          pos++;
          if (pos == 5) {
            M5.Lcd.setTextSize(3);
            M5.Lcd.setCursor(10, 30);
            M5.Lcd.printf("%02x %02x %02x", midi[2], midi[3], midi[4]);
            pos = 0;
            if (midi[2] == 0x80) {
              // Note Off
              ledcWriteTone(1, 0);
              int duration = millis() - startTime;
              Serial.printf("{%5d, %5d},\n", frequency, duration);
              frequency = 0;
              startTime = millis();
            } else if (midi[2] == 0x90) {
              // Note On
              if (startTime) {
                int duration = millis() - startTime;
                Serial.printf("{%5d, %5d},\n", frequency, duration);
              }
              frequency = frequency_list[midi[3]];
              ledcWriteTone(1, frequency);
              startTime = millis();
            }
          }
        }
      }
    }
};

void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(WHITE, BLACK);
  M5.Lcd.setTextSize(1);
  M5.Lcd.setCursor(10, 0);
  M5.Lcd.printf("BLE MIDI Disconnect.");

  BLEDevice::init(DEVIVE_NAME);
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  BLEService *pService = pServer->createService(BLEUUID(MIDI_SERVICE_UUID));
  pCharacteristic = pService->createCharacteristic(
                      BLEUUID(MIDI_CHARACTERISTIC_UUID),
                      BLECharacteristic::PROPERTY_READ   |
                      BLECharacteristic::PROPERTY_WRITE  |
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_WRITE_NR
                    );
  pCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();

  BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
  oAdvertisementData.setFlags(0x04);
  oAdvertisementData.setCompleteServices(BLEUUID(MIDI_SERVICE_UUID));
  oAdvertisementData.setName(DEVIVE_NAME);
  pAdvertising = pServer->getAdvertising();
  pAdvertising->setAdvertisementData(oAdvertisementData);
  pAdvertising->start();

  pinMode(2, OUTPUT);
  ledcSetup(1, 12000, 8);
  ledcAttachPin(2, 1);

}

void loop() {
  delay(1);
}

長いのは音に対する周波数一覧です。他の処理はほぼ昔のブログのままになります。

M5StickC Plusにスケッチを入れて動かして、パソコンからBLEの追加をすると「M5StickC」がいるので追加します。MIDIberryを使って、出力先を「M5StickC」を選択します。左上にあるボタンを押すと鍵盤がでますので、チャンネルを1してから鍵盤を叩くと音がでます。

{    0,  3299},
{  349,   300},
{    0,   240},
{  392,   240},
{    0,   240},
{  440,   780},
{    0,   240},
{  392,   180},
{    0,   300},
{  349,   120},
{    0,   720},
{  349,   239},
{    0,   240},
{  392,   180},
{    0,   240},
{  440,   179},
{    0,   240},
{  392,   179},
{    0,   300},
{  349,   179},
{    0,   300},
{  392,   779},

シリアル出力に、上記のようなログがでますのでこちらを利用します。1つ目の数値が周波数で、2つ目が継続時間です。周波数0が無音になります。

最初の0が長いところは無音なのでカットして、2行目から下がレコーディングされた音楽となります。

バックグラインド再生

再生したいデータをキューに送ることで再生を実現しています。停止はキューの中身を空にしています。他にも方法はあると思いますが、キューを使うのが単純なわりに排他処理などが安全になります。

スケッチ

#include <M5StickCPlus.h>

struct BeepData {
  uint16_t frequency;
  uint16_t duration;
};

BeepData sound1[] = {
  {  349,   300},
  {    0,   240},
  {  392,   240},
  {    0,   240},
  {  440,   780},
  {    0,   240},
  {  392,   180},
  {    0,   300},
  {  349,   120},
  {    0,   720},
  {  349,   239},
  {    0,   240},
  {  392,   180},
  {    0,   240},
  {  440,   179},
  {    0,   240},
  {  392,   179},
  {    0,   300},
  {  349,   179},
  {    0,   300},
  {  392,   779},
};

#define QUEUE_BEEP_LENGTH 1000

QueueHandle_t xQueueBeep;     // キュー
TaskHandle_t taskBeepHandle;  // タスク管理

// タスク
void taskBeep(void *pvParameters) {
  while (1) {
    BeepData data;
    xQueueReceive(xQueueBeep, &data, portMAX_DELAY);
    ledcWriteTone(1, data.frequency); // Play
    delay(data.duration);
    ledcWriteTone(1, 0);              // Mute
  }
}

void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
 
  M5.Lcd.setTextSize(3);
  M5.Lcd.setCursor(0, 0);
  M5.Lcd.println("Beep Test");
  M5.Lcd.println();
  M5.Lcd.println("BtnA : PLAY");
  M5.Lcd.println("BtnB : STOP");
  
  pinMode(2, OUTPUT);
  ledcSetup(1, 12000, 8);
  ledcAttachPin(2, 1);

  // キュー作成
  xQueueBeep = xQueueCreate(QUEUE_BEEP_LENGTH, sizeof(BeepData));

  // Core1の優先度3でタスク起動
  xTaskCreateUniversal(
    taskBeep,         // タスク関数
    "taskBeep",       // タスク名(あまり意味はない)
    8192,             // スタックサイズ
    NULL,             // 引数
    3,                // 優先度(大きい方が高い)
    &taskBeepHandle,  // タスクハンドル
    APP_CPU_NUM       // 実行するCPU(PRO_CPU_NUM or APP_CPU_NUM)
  );
}

void loop() {
  M5.update();
  if (M5.BtnA.wasPressed()) {
    // Play
    for (int i = 0; i < sizeof(sound1) / sizeof(BeepData); i++) {
      xQueueSend(xQueueBeep, &sound1[i], 0);
    }
  }
  if (M5.BtnB.wasPressed()) {
    // Stop
    BeepData data;
    while (xQueueReceive(xQueueBeep, &data, 0)) {
      // 空にする
    }
    ledcWriteTone(1, 0); // Mute
  }

  M5.Lcd.setCursor(0, 108);
  M5.Lcd.println(millis());

  delay(1);
}

1000個まで入るキューを作成して、再生したい音のリストを登録すると再生します。マルチタスクで動いていますので、再生中に他の処理もできます。

ちなみに再生時はキューに追加だけしているので、どんどん後ろに追加されています。本当は今のを消してから追加したほうが好ましいと思います。

おまけ UIFlowでのブザー

こんな感じでPWMをGPIO2に鳴らしたい音を周波数にセットして50%で出力することで音ができます。ただし、PWM出力中に再起動をした場合になりっぱなしになります!

初期化処理でPWMを止める処理が入っていないんですよね、、、なのでアプリ起動直後に音を止める処理を入れないと意図せずなりっぱなしになりますので注意してください。

こんな感じで、起動直後にPWMの初期化をして、その直後に停止をすると安全です。音を鳴らす場合には関数化して呼び出すと便利だと思います。処理の途中で音を鳴らすと処理が止まってしまうので、ボタン系のイベントの中か、タイマー処理などを使って別スレッドで動かすようにしたほうがいいと思います。

この辺はUIFlowの標準ブロックで今後サポートしてくれるとは思います!

まとめ

音楽データ作成は本当はMIDIファイル(SMF)を解析しようとして途中まで作業していたのですが、そもそも単音のデータがほとんどないのと、結構変なデータがあったので諦めました。。。

サンプルの音は、へろへろですがあまりちゃんとした曲をいれると、いろいろあれなんで、、、

M5Stack FANユニット

概要

ユニット紹介シリーズのFANユニットです。モーターに羽をつけることで、扇風機的なことができます。

商品

上記の商品になります。N20という小さいDCモーターが内蔵されています。

こんな商品かな? かなり小さいですね。

外見はこんな感じです。コネクタが黒なのでその他の接続ですね。

中身はユニット本体と、羽が2個です。羽の方向が違うので、風の方向が選べるみたいです。単位は5Vの隣ですので内側を使っています。SEEED社のGroveは外側から使うので、この辺が差なんですよね。

DCモーターなので、速度制御は通常はPWMになります。ATOMシリーズは該当ピンがGPIO26なのでアナログ出力でも制御が可能です。

モーターの軸が直接でているので、FAN以外も接続することはできそうです。

FANをつけた状態です。

スケッチ例

const int motor_pin = 32; // M5StickC
const int ledChannel = 0;

void setup() {
  Serial.begin(115200);

  // PWMで速度を制御
  ledcSetup(ledChannel, 12000, 8);
  ledcAttachPin(motor_pin, ledChannel);
}

void loop() {
  // 始動は20%以上で15ミリ秒以上必要
  ledcWrite(ledChannel, 256 * 0.2);
  delay(15);

  // 回り始めれば10%でも動く
  ledcWrite(ledChannel, 256 * 0.1);
  delay(2000);

  // 停止
  ledcWrite(ledChannel, 0);
  delay(1000);
}

DCモーターなので、該当ピンに電圧を出力することで回ります。そのままだと速度制限ができないので、PWM制御を入れてみました。

8ビット精度のPWM制御なので0から256までの出力が選べます。いろいろ試したところ、20%相当の出力がないと、停止している状態から回りませんでした。一度回ってしまえばもう少し低い出力でも回すことができます。

50%ぐらいで動かすとかなりうるさいのでびっくりします。。。

まとめ

かなり面白いユニットですよね。とはいえ、あまり使っている人はいません。ちょっと扱いにくいというか、モータードライバーとモーターを直接使う人が多いのかな?

GPIOの電力だとモーターを動かすのには不足するので、一般的には上記みたいなモータドライバを利用します。外部電源を接続して、GPIOは制御用になります。このFANユニットも同じような動きなのですが、複数のモーターを組み込んで利用する場合にはモーター単品の方が組み込みやすいのかもしれません。

M5StickC Plusが販売されました

概要

スイッチサイエンスさんはすでに品切れです。公式ストアは送料高いのでおすすめしません。AliExpressの公式ストアは一ヶ月かかるのですがまだ追加されていませんでした。Digi-Keyで今後販売されるかな?

今回は本体のみで付属品なしです。そのため袋に入れた状態で販売されています。ATOMの際にパッケージにシール貼ってあったのが不評だったからかな?

スッキリなパッケージです。ケーブルがついていないので、USB Type-C端子のケーブルがないと接続できません。

裏にはシリアルが書いてあります。

今回は画面とバッテリーが大きくなりましたが、筐体のサイズは変わっていません。

無印と並べたところです。IMUは同じMPU6886ですが色が変わっていますね。

こちら側は変更無し。

本体に張ってあるシリアルがなくなっています。また、GPIO36が入力専用だったので、GPIO25も同じ端子に出ています。

画面の大きさはこんな感じで、結構違います。

開発環境

なんと、いままでと違うライブラリになりました。しかも中身がちょっと古いですね。

GitHubからCodeをクリックして、中にある「Download ZIP」でファイルをダウンロードします。

Arduino IDEの「スケッチ」→「ライブラリをインクルード」→「.ZIP形式のライブラリをインストール」からダウンロードしたZIPファイルを選択すれば使えるようになります。

スケッチ例

FactoryTestしかいまは入っていません。ボタンを押すことで音がなって画面が切り替わります。

ブザーの使い方

#include "M5StickCPlus.h"

void setup() {
  M5.begin();
  M5.Beep.setBeep(4000, 100); // ビープ音設定(初期値)
}

void loop() {
  M5.update();                // ボタンの状態更新
  M5.Beep.update();           // tone関数で鳴らした音が指定時間経過していたら止める

  if (M5.BtnA.wasPressed()) {
    // ピーと鳴らす
    M5.Beep.beep();
  }
  if (M5.BtnB.wasPressed()) {
    // 音の周波数と長さを指定して鳴らす
    M5.Beep.tone(440, 500);
  }
}

M5.Beepクラスが追加されています。

tone()関数はPWMを使って音を鳴らします。PWMのチャンネル0を内部で使っているので、他の用途にPWMを使う場合には注意してください。ノンブロック関数で音を鳴らしたら即終了します。音を止めるのは定期的にM5.Beep.update()を呼び出す必要があるので注意してください。

beep()関数でピーと音がでます。setBeep()関数で違う音にもできます。デフォルトは4000Hzを100ミリ秒になっていました。内部はtone()関数を呼び出しているだけです。M5.Beep.tone(4000, 100)と同じ結果になります。

音は結構きれいなのですが、GPIO25ではないのでボイスなどの再生はできません。外にでているGPIO25がここに繋がっていればよかったのに、、、

まとめ

個人的にはライブラリがライブラリマネージャーからダウンロードできないことと、既存と別になっていて、中身のバージョンが微妙に違うので今後ちゃんと整備されていくのかが心配です。。。

もうちょっと突っ込んだ解析も今後していきたいと思います。