💫
LED Matrixで砂シミュレーション機をつくろう
以前、X(旧twitter)でみた砂シュミュレーション機に一目惚れしました。
@witnessmenowさんの公開されているFalling-Sand-Matrixを参考に、
自分でもLED Matrixと加速度センサーを使った砂シュミュレーション機を作りました。
参照プロジェクト
🔧パーツ一覧
機材名 | 備考 |
---|---|
ESP32 DevKitC | 秋月電子 |
ledマトリックスモジュールパネル屋内rgb 64 x 64ドット | Amazonで購入, AliExpress等でも販売 |
3軸加速度センサー - MPU6050 | Amazonで購入 |
モバイルバッテリ | Amazonで購入(cheero Slim 10000mAh IoT機器対応 大容量 モバイルバッテリ) |
ジャンパーケーブル | 適量 |
木材・ネジ | 適量 - 固定用 |
接続図
- LEDマトリクスは、下記のコネクタがあります
ESP32とLEDマトリクス(入力コネクタ、出力コネクタ)
ESP32 | LED Mat. IN | LED Mat. OUT |
---|---|---|
- | R1 | R0 |
- | G0 | R1 |
- | G1 | G0 |
- | B0 | G1 |
- | B1 | B0 |
19 | A | - |
23 | B | - |
18 | C | - |
5 | D | - |
25 | LAT | - |
16 | OE | - |
14 | CLK | - |
13 | R0 | - |
GND | GND | - |
電源周り
モバイルバッテリーからの5V/GNDをLEDマトリクスとESP32に接続します。
ESP32と加速度センサー
ESP32 | MPU6050 |
---|---|
3V3 | VCC |
22 | SCL |
21 | SDA |
GND | GND |
💻環境
Arduino IDEを使用します。
- Arduino IDE
- Version:2.1.1
ライブラリ
LEDマトリクスのライブラリは、下記となります。
また、動作確認した際の各ライブラリのバージョンは以下となります。
Library | Version | Note |
---|---|---|
PxMatrix LED MATRIX library | 1.8.2 | 上記のライブラリ |
Adafruit BusIO | 1.14.3 | - |
Adafruit GFX Library | 1.11.7 | - |
Arduino-MPU6050 | patch-1 |
witnessmenow/Arduino-MPU6050 修正は後述 |
📝作業ログ
いくつかハマったので、作業内容を時系列で記載します。
ピン番号の変更
- fallingSand/fallingSand.inoを上記の接続に修正します
- ピン番号をこの基板用に変更します
-
failingSand.ino
#define P_LAT 25 // myboard // #define P_LAT 22 //original #define P_A 19 #define P_B 23 #define P_C 18 #define P_D 5 #define P_E 15 #define P_OE 16 // 2
-
- また、I2Cのピン設定も接続図に合わせます
-
failingSand.ino
while (!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_4G, MPU6050_ADDRESS, 21, 22)) //myboard // while (!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_4G, MPU6050_ADDRESS, 27, 33)) //original
-
動作確認1 - I2C周りの修正
- 修正自体は、上記で終わりのため、動作を確認しました。
- 電源を入れたところ、LEDが光りません。
- print文で追ったところ、上記のMPU6050初期化のmpu.begin()の処理が抜けないことがわかりました
- 追うと、I2Cのread処理にて停止していることがわかりました
- STOP Conditionが発行されていない???
- Wireライブラリのサンプルコードをもとに修正しました
- 修正前
Arduino-MPU6050/MPU6050.cpp(before)// Read 8-bit from register uint8_t MPU6050::readRegister8(uint8_t reg) { uint8_t value; Wire.beginTransmission(mpuAddress); Wire.write(reg); Wire.endTransmission(); Wire.beginTransmission(mpuAddress); Wire.requestFrom(mpuAddress, 1); while (!Wire.available()) { }; value = Wire.read(); Wire.endTransmission(); return value; }
- 修正後
Arduino-MPU6050/MPU6050.cpp(after)// Read 8-bit from register uint8_t MPU6050::readRegister8(uint8_t reg) { uint8_t value; Wire.beginTransmission(mpuAddress); Wire.write(reg); Wire.endTransmission(); Wire.beginTransmission(mpuAddress); Wire.endTransmission(true); uint8_t bytesReceived = Wire.requestFrom(mpuAddress, 1); if( bytesReceived ) { Wire.readBytes(&value, bytesReceived); } Wire.endTransmission(); return value; }
- 同じ処理が MPU6050::fastRegister8(uint8_t reg)にもあるため、同じように修正しました
- 上記の修正に伴い、MPU6050.cpp/hをローカルに移動し、各インクルード文を修正しますMPU6050.cpp/fallingSandRep.ino
// #include <MPU6050.h> #include "MPU6050.h"
動作確認2-加速度センサー軸の修正
- 上記の修正を行い、再度動作を確認しました
- 無事にLEDが点灯しましたが、傾けた方向と逆に砂が転がります
- 加速度センサーの取り付け方にて、転がる向きが変わってしまうため、下記のコードを追加しましたfallingSandRep.ino
ImgBufferGFX imgWrapper(img, WIDTH, HEIGHT); #define MPU6050_CHANGE_X_Y 1 //add - X/Y軸の入れ替え #define MPU6050_CHANGE_SIGN_X 1 //add - X方向の反転 #define MPU6050_CHANGE_SIGN_Y 0 //add - Y方向の反転 float xOffset = -1350; float yOffset = -2590; 略 void pixelTask(void *param) { 略 #if MPU6050_CHANGE_SIGN_X float xOffset = (accelVector.XAxis) * -1; #else float xOffset = (accelVector.XAxis * -1) * -1; #endif #if MPU6050_CHANGE_SIGN_Y float yOffset = (accelVector.YAxis) * -1; #else float yOffset = (accelVector.YAxis * -1) * -1; #endif #if MPU6050_CHANGE_X_Y float tmpOffset = xOffset; xOffset = yOffset; yOffset = tmpOffset; #endif while (true) { 略 #if MPU6050_CHANGE_SIGN_X float accelX = (accelVector.XAxis) + xOffset; #else float accelX = (accelVector.XAxis * -1) + xOffset; #endif #if MPU6050_CHANGE_SIGN_Y float accelY = (accelVector.YAxis) + yOffset; #else float accelY = (accelVector.YAxis * -1) + yOffset; #endif float accelZ = accelVector.ZAxis; #if MPU6050_CHANGE_X_Y float accelTmp = accelX; accelX = accelY; accelY = accelTmp; #endif
- 上記の場合、LEDパネルと加速度センサーの位置関係は以下となります
- 最終的なファイル構成は、下記となります
- ./fallingSandRep/
- fallingSandRep.ino
- imgBufferGFX.h
- MPU6050.cpp
- MPU6050.h
- ./fallingSandRep/
以上で、うまく動作することができました🎉。
📄メモ
- 当たり判定や表示の仕組みは、コメントに詳しく記載されています
- 気になったことを列挙します
64x32に変更する場合
- 64x32のLEDパネルにする場合、下記の修正が必要です
- 該当箇所は、以下です
- 表示サイズの定義fallingSand.ino
// 64x64 #define WIDTH 64 // Display width in pixels #define HEIGHT 64 // Display height in pixels // 64x32 #define WIDTH 64 // Display width in pixels #define HEIGHT 32 // Display height in pixels
- PxMATRIXの初期化fallingSand.ino
// 64x64 PxMATRIX display(64, 64, P_LAT, P_OE, P_A, P_B, P_C, P_D, P_E); // 64x32 PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D);
- 行指定fallingSand.ino
// 64x64 display.begin(32); // 64x32 display.begin(16);
- 表示サイズの定義
RGBの順番変更
- メーカによってRGBの順番が異なるようです
- 下記にて変更できますfallingSand.ino
// RGB display.setColorOrder(RRGGBB); // GBR display.setColorOrder(GGBBRR);
mapと当たり判定
- img[]がmapとなっている
- uint16_t img[WIDTH * HEIGHT]; // Internal 'map' of pixels
- 本配列が衝突の判定のmapとなっている
- imgWrapper経由で描画した文字列を描画した場合、その部分は壁になる
- 壁 : imgWrapper.print("HI");
- 表示 : display.print("HI");
- 例:HIを描画した場合の動作
- 動画を取る
さいごに
久しぶりに電子工作をして楽しかったです。
目に見えるものは、わかりやすくていいですね。
Discussion