M5Stackの多機種対応について
https://i.gyazo.com/490a3fc89b2ba9d5e588cbb09993b5d5.jpg
はじめに
その中で、経験したことを、備忘録としてまとめておきます。
機種の自動判定
Arduino IDEでは、ツール→ボードを選択すると自動的にARDUINO_*マクロが定義されます。
これを使って、#ifdefやdefined()などで場合わけが可能になります。
これらは、以下のようにboards.txtに、*.build.boardとして定義されています。
code:shell
% grep build.board ~/Library/Arduino15/packages/m5stack/hardware/esp32/2.0.2/boards.txt|grep M5
m5stack-core-esp32.build.board=M5Stack_Core_ESP32
m5stack-fire.build.board=M5STACK_FIRE
m5stick-c.build.board=M5Stick_C
m5stick-c-plus.build.board=M5Stick_C_PLUS
m5stack-atom.build.board=M5Stack_ATOM
m5stack-core2.build.board=M5STACK_Core2
m5stack-tough.build.board=M5STACK_Tough
m5stack-timer-cam.build.board=M5Stack-Timer-CAM
m5stack-unit-cam.build.board=M5Stack-Unit-CAM
m5stack-poe-cam.build.board=M5Stack-PoE-CAM
m5stack-paper.build.board=M5Stack_Paper
m5stack-coreink.build.board=M5Stack_CoreInk
% grep build.board ~/Library/Arduino15/packages/Seeeduino/hardware/samd/1.8.1/boards.txt|grep TERMINAL
seeed_wio_terminal.build.board=WIO_TERMINAL
この情報をまとめると、以下の表のようになります。
table:ボード選択で定義されるARDUINOマクロ
M5Stack Basic, Gray ARDUINO_M5Stack_Core_ESP32 M5Stack.h
M5Stack Fire ARDUINO_M5STACK_FIRE M5Stack.h
M5StickC ARDUINO_M5Stick_C M5StickC.h
M5StickC plus ARDUINO_M5Stick_C_PLUS M5StickCPlus.h
ATOM Matrix ARDUINO_M5Stack_ATOM M5Atom.h
ATOM Lite ARDUINO_M5Stack_ATOM M5Atom.h ATOM Matrixと切り分けできない
M5Stack Core 2 ARDUINO_M5STACK_Core2 M5Core2.h
M5Stack Tough ARDUINO_M5STACK_Tough M5Tough.h
M5Paper ARDUINO_M5Stack_Paper M5EPD.h
M5Stack Unit CAM M5Stack-Unit-CAM M5Stack.h(?)
M5Stack PoE CAM M5Stack-PoE-CAM (?)
M5Stamp Pico STAMP_PICO (?)
M5Stamp C3 STAMP_C3 (?)
Wio Terminal ARDUINO_WIO_TERMINAL 参考情報
例えば、ヘッダファイルの読み込み部分では、以下のようなコードを書くことになります。
code:M5Scratch.ino
#if defined(ARDUINO_M5Stack_Core_ESP32) // M5Stackの場合 #elif defined(ARDUINO_M5STACK_Core2) // Core2の場合 #elif defined(ARDUINO_M5Stick_C) // M5StickCの場合 #elif defined(ARDUINO_M5Stick_C_PLUS) // M5StickC Plusの場合 #elif defined(ARDUINO_M5Stack_ATOM) // ATOM Matrix/Liteの場合 #elif defined(ARDUINO_M5STACK_Tough) // Toughの場合 M5.begin()による初期化
M5.begin()による初期化も、機種によって異なる部分です。
経験上、以下のように初期化すると問題が起こらないと思います。
code:M5.begin.ino
#if defined(ARDUINO_M5Stack_ATOM) M5.begin(true, false, true);
#elif defined(ARDUINO_M5STACK_TOUGH) M5.begin(true, true, true, true);
M5.begin();
画面描画まわりの対応
画面まわりのコードでは、LCDの横と縦のピクセル数を表すM5.Lcd.width()とM5.Lcd.height()を使って画面の大きさの違いを吸収可能です。
画面の向きをLandscapeやPortrateに変更する場合には、M5.Lcd.setRotation()を適切に設定します。
フォントのサイズの吸収に関しては、良い方法がわからないので、固定値で行っています。
機種ごとの差異を気にしないコードを書きたい場合は、LovyanGFXを利用することも検討してください。 LovyanGFXは、ESP32用のイケてるグラフィックスライブラリです。
以下のような特徴があります。
高速
高機能
たくさんのデバイスに対応: しかも、多くは自動認識
キャラクタを動かす例は、サンプル例 → LovyanGFX → Sprite → MovingIconsをベースに使うのが一番良いと思います。 ボタンスイッチの対応
ボタンスイッチも機種により数が違ったりするので、対応に注意が必要です。
ボタンが3つの機種では、BtnA, BtnB, BtnCが、2つの機種ではBtnA, BtnBが、1つの機種ではBtnが使えます。
このため、以下のような場合分けを書くことになります。
code:button.ino
#if defined(ARDUINO_M5Stack_ATOM) // ATOMはボタン1つ uint8_t btnA = M5.Btn.wasPressed();
uint8_t btnA = M5.BtnA.wasPressed();
uint8_t btnB = M5.BtnB.wasPressed();
#if defined(ARDUINO_M5Stack_Core_ESP32) // M5Stack Basicなどはボタンが3つ uint8_t btnC = M5.BtnC.wasPressed();
IMUの対応
加速度やジャイロを取得できる6軸IMUは、(MPU6886を使っている機種では?)簡単にコードの共有ができます。
M5.IMU.Init()で初期化し、M5.IMU.getAccelData(&ax, &ay, &az)やM5.IMU.getGyroAdc(&gx, &gy, &gz)、M5.IMU.getTempData(&temp)で値を取得します。
code:6axis_IMU.ino
void setup() {
M5.IMU.Init();
}
void loop() {
M5.IMU.getAccelData(&ax, &ay, &az);
M5.IMU.getGyroAdc(&gx, &gy, &gz);
M5.IMU.getTempData(&temp);
}
9軸IMUであるMPU9250で地磁気も取得したい場合は、加速度やジャイロの取得も自分で行う必要があります。
大体、以下のようなコードになると思います。
code:IMU9250.ino
MPU9250 Imu;
void setup() {
Imu.MPU9250SelfTest(Imu.SelfTest);
Imu.calibrateMPU9250(Imu.gyroBias, Imu.accelBias);
Imu.initMPU9250();
delay(500);
Imu.initAK8963(Imu.magCalibration);
}
void loop() {
if (Imu.readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01)
{
// get accel
Imu.readAccelData(Imu.accelCount); // Read the x/y/z adc values
Imu.getAres();
ax = (float)Imu.accelCount0 * Imu.aRes; // - accelBias0; ay = (float)Imu.accelCount1 * Imu.aRes; // - accelBias1; az = (float)Imu.accelCount2 * Imu.aRes; // - accelBias2; // get gyro
Imu.readGyroData(Imu.gyroCount);
Imu.getGres();
gyroX = (float)Imu.gyroCount0 * Imu.gRes; gyroY = (float)Imu.gyroCount1 * Imu.gRes; gyroZ = (float)Imu.gyroCount2 * Imu.gRes; // get magnetic
Imu.readMagData(Imu.magCount);
Imu.getMres();
mx = (float)Imu.magCount0 * Imu.mRes * Imu.magCalibration0; my = (float)Imu.magCount1 * Imu.mRes * Imu.magCalibration1; mz = (float)Imu.magCount2 * Imu.mRes * Imu.magCalibration2; // get temp
Imu.tempCount = Imu.readTempData();
temp = ((float) Imu.tempCount) / 333.87 + 21.0;
Imu.updateTime();
}
}
おわりに
とりあえず、自分の備忘録としてまとめてみました。
おかしい点などがあると、ご指摘していただければうれしいです。
Enjoy happy M5Stack Life!!