M5StickS3 #2
https://gyazo.com/90fa55736eaebca37e7277404f50d69b
M5StickS3をキーボードにする
code:keyboard.cpp
#include <M5Unified.h>
#include "USB.h"
#include "USBHIDKeyboard.h"
USBHIDKeyboard Keyboard;
bool lastA = false;
bool lastB = false;
uint32_t lastDraw = 0;
void drawScreen(const char* line1, const char* line2 = "", const char* line3 = "", const char* line4 = "") {
M5.Display.fillScreen(BLACK);
M5.Display.setTextColor(WHITE, BLACK);
M5.Display.setCursor(10, 10);
M5.Display.setTextSize(2);
M5.Display.println(line1);
M5.Display.setCursor(10, 35);
M5.Display.setTextSize(2);
M5.Display.println(line2);
M5.Display.setCursor(10, 70);
M5.Display.setTextSize(2);
M5.Display.println(line3);
M5.Display.setCursor(10, 95);
M5.Display.setTextSize(2);
M5.Display.println(line4);
}
void setup() {
auto cfg = M5.config();
M5.begin(cfg);
M5.Display.setRotation(0);
drawScreen("USB", "KEYBOARD", "Starting...", "");
Keyboard.begin();
USB.begin();
delay(300);
drawScreen("USB", "KEYBOARD", "BtnA = a", "BtnB = b");
}
void loop() {
M5.update();
bool nowA = M5.BtnA.isPressed();
bool nowB = M5.BtnB.isPressed();
if (nowA && !lastA) {
Keyboard.write('a');
}
if (nowB && !lastB) {
Keyboard.write('b');
}
lastA = nowA;
lastB = nowB;
if (millis() - lastDraw > 100) {
M5.Display.fillRect(0, 120, 240, 80, BLACK);
M5.Display.setCursor(10, 120);
M5.Display.print("A : ");
M5.Display.print(nowA ? "ON" : "OFF");
M5.Display.setCursor(10, 145);
M5.Display.print("B : ");
M5.Display.print(nowB ? "ON" : "OFF");
lastDraw = millis();
}
delay(10);
}
M5StickS3をマウスにする
code:mouse.cpp
#include <M5Unified.h>
#include "USB.h"
#include "USBHIDMouse.h"
USBHIDMouse Mouse;
bool lastA = false;
bool lastB = false;
uint32_t lastDraw = 0;
void drawScreen(const char* line1, const char* line2 = "", const char* line3 = "", const char* line4 = "") {
M5.Display.fillScreen(BLACK);
M5.Display.setTextColor(WHITE, BLACK);
M5.Display.setCursor(10, 10);
M5.Display.setTextSize(2);
M5.Display.println(line1);
M5.Display.setCursor(10, 35);
M5.Display.setTextSize(2);
M5.Display.println(line2);
M5.Display.setCursor(10, 70);
M5.Display.setTextSize(2);
M5.Display.println(line3);
M5.Display.setCursor(10, 95);
M5.Display.setTextSize(2);
M5.Display.println(line4);
}
void setup() {
auto cfg = M5.config();
M5.begin(cfg);
M5.Display.setRotation(0);
drawScreen("USB", "MOUSE", "Starting...", "");
Mouse.begin();
USB.begin();
delay(300);
drawScreen("USB", "MOUSE", "A = LEFT", "B = RIGHT");
}
void loop() {
M5.update();
bool nowA = M5.BtnA.isPressed();
bool nowB = M5.BtnB.isPressed();
if (nowA && !lastA) {
Mouse.press(MOUSE_LEFT);
delay(20);
Mouse.release(MOUSE_LEFT);
}
if (nowB && !lastB) {
Mouse.press(MOUSE_RIGHT);
delay(20);
Mouse.release(MOUSE_RIGHT);
}
lastA = nowA;
lastB = nowB;
float ax, ay, az;
M5.Imu.getAccel(&ax, &ay, &az);
const float deadzone = 0.18f;
const float gain = 12.0f;
int dx = 0;
int dy = 0;
if (fabs(ax) > deadzone) dy = (int)(ax * gain);
if (fabs(ay) > deadzone) dx = -(int)(ay * gain);
if (dx != 0 || dy != 0) {
Mouse.move(dx, dy);
}
if (millis() - lastDraw > 100) {
M5.Display.fillRect(0, 120, 240, 120, BLACK);
M5.Display.setCursor(10, 120);
M5.Display.print("A : ");
M5.Display.println(nowA ? "ON" : "OFF");
M5.Display.setCursor(10, 145);
M5.Display.print("B : ");
M5.Display.println(nowB ? "ON" : "OFF");
M5.Display.setCursor(10, 170);
M5.Display.print("dx: ");
M5.Display.println(dx);
M5.Display.setCursor(10, 195);
M5.Display.print("dy: ");
M5.Display.println(dy);
lastDraw = millis();
}
delay(10);
}
M5StickS3をキーボードとマウスにする
code:k+m.cpp
#include <M5Unified.h>
#include "USB.h"
#include "USBHIDMouse.h"
#include "USBHIDKeyboard.h"
USBHIDMouse Mouse;
USBHIDKeyboard Keyboard;
bool lastA = false;
bool lastB = false;
uint32_t lastDraw = 0;
// 振ったときのA入力の連打防止
uint32_t lastShakeTime = 0;
const uint32_t shakeCooldown = 700; // 次の検出まで 700ms あける
const float shakeThreshold = 2.2f; // 強く振った判定のしきい値
void drawScreen(const char* line1, const char* line2 = "", const char* line3 = "", const char* line4 = "") {
M5.Display.fillScreen(BLACK);
M5.Display.setTextColor(WHITE, BLACK);
M5.Display.setCursor(10, 10);
M5.Display.setTextSize(2);
M5.Display.println(line1);
M5.Display.setCursor(10, 35);
M5.Display.setTextSize(2);
M5.Display.println(line2);
M5.Display.setCursor(10, 70);
M5.Display.setTextSize(2);
M5.Display.println(line3);
M5.Display.setCursor(10, 95);
M5.Display.setTextSize(2);
M5.Display.println(line4);
}
void setup() {
auto cfg = M5.config();
M5.begin(cfg);
M5.Display.setRotation(0);
drawScreen("USB", "M +KEY", "Starting...", "");
Mouse.begin();
Keyboard.begin();
USB.begin();
delay(300);
drawScreen("USB", "M+KEY", "A=Lc B=Rc", "SHAKE = A");
}
void loop() {
M5.update();
bool nowA = M5.BtnA.isPressed();
bool nowB = M5.BtnB.isPressed();
if (nowA && !lastA) {
Mouse.press(MOUSE_LEFT);
delay(20);
Mouse.release(MOUSE_LEFT);
}
if (nowB && !lastB) {
Mouse.press(MOUSE_RIGHT);
delay(20);
Mouse.release(MOUSE_RIGHT);
}
lastA = nowA;
lastB = nowB;
float ax, ay, az;
M5.Imu.getAccel(&ax, &ay, &az);
const float deadzone = 0.18f;
const float gain = 12.0f;
int dx = 0;
int dy = 0;
if (fabs(ax) > deadzone) dy = (int)(ax * gain);
if (fabs(ay) > deadzone) dx = -(int)(ay * gain);
if (dx != 0 || dy != 0) {
Mouse.move(dx, dy);
}
// 強く振ったらキーボードで A を入力
float accelMagnitude = sqrt(ax * ax + ay * ay + az * az);
if (accelMagnitude > shakeThreshold && millis() - lastShakeTime > shakeCooldown) {
Keyboard.write('A');
lastShakeTime = millis();
}
if (millis() - lastDraw > 100) {
M5.Display.fillRect(0, 120, 240, 140, BLACK);
M5.Display.setCursor(10, 120);
M5.Display.setTextSize(2);
M5.Display.print("A : ");
M5.Display.println(nowA ? "ON" : "OFF");
M5.Display.setCursor(10, 145);
M5.Display.print("B : ");
M5.Display.println(nowB ? "ON" : "OFF");
M5.Display.setCursor(10, 170);
M5.Display.print("dx: ");
M5.Display.println(dx);
M5.Display.setCursor(10, 195);
M5.Display.print("dy: ");
M5.Display.println(dy);
M5.Display.setCursor(10, 220);
M5.Display.print("g : ");
M5.Display.println(accelMagnitude, 2);
lastDraw = millis();
}
delay(10);
}
M5StickS3にセンサをつなぐ
https://shop.m5stack.com/products/ultrasonic-distance-unit-i2c-rcwl-9620 をキーボード入力する
code:sonic.cpp
#include <M5Unified.h>
#include <Unit_Sonic.h>
#include "USB.h"
#include "USBHIDKeyboard.h"
USBHIDKeyboard Keyboard;
SONIC_I2C sonic;
constexpr uint8_t I2C_SDA = 9;
constexpr uint8_t I2C_SCL = 10;
constexpr uint8_t SONIC_ADDR = 0x57;
// 距離レンジ mm
constexpr float NEAR_MAX_MM = 150.0; // 2〜15cm
constexpr float MID_MAX_MM = 400.0; // 15〜40cm
constexpr float FAR_MAX_MM = 800.0; // 40〜80cm
// キー送信間隔
constexpr unsigned long SEND_INTERVAL_MS = 600;
// センサー読み取り間隔
constexpr unsigned long READ_INTERVAL_MS = 200;
// 同じキーの連続送信を防ぐ
int lastZone = -999;
unsigned long lastSendMs = 0;
unsigned long lastReadMs = 0;
float lastDistanceMm = 4500.0;
int currentZone = -1;
enum Zone {
ZONE_INVALID = -1,
ZONE_NEAR = 0,
ZONE_MID = 1,
ZONE_FAR = 2,
ZONE_OUT = 3
};
int distanceToZone(float mm) {
// センサー仕様上 20mm〜4500mm 程度を有効範囲として扱う
if (mm < 20.0 || mm >= 4500.0) {
return ZONE_INVALID;
}
if (mm <= NEAR_MAX_MM) return ZONE_NEAR;
if (mm <= MID_MAX_MM) return ZONE_MID;
if (mm <= FAR_MAX_MM) return ZONE_FAR;
return ZONE_OUT;
}
const char* zoneName(int zone) {
switch (zone) {
case ZONE_NEAR:
return "NEAR";
case ZONE_MID:
return "MID";
case ZONE_FAR:
return "FAR";
case ZONE_OUT:
return "OUT";
default:
return "INVALID";
}
}
const char* keyNameForZone(int zone) {
switch (zone) {
case ZONE_NEAR:
return "1";
case ZONE_MID:
return "2";
case ZONE_FAR:
return "3";
case ZONE_OUT:
return "0";
default:
return "-";
}
}
void sendKeyForZone(int zone) {
switch (zone) {
case ZONE_NEAR:
Keyboard.print("1");
break;
case ZONE_MID:
Keyboard.print("2");
break;
case ZONE_FAR:
Keyboard.print("3");
break;
case ZONE_OUT:
Keyboard.print("0");
break;
default:
break;
}
}
void drawStatus(float distanceMm, int zone, bool keySent) {
M5.Display.fillRect(0, 30, 240, 105, BLACK);
M5.Display.setCursor(0, 30);
M5.Display.printf("Dist: %.1f mm\n", distanceMm);
M5.Display.printf("Zone: %s\n", zoneName(zone));
M5.Display.printf("Key : %s\n", keyNameForZone(zone));
if (keySent) {
M5.Display.println("Sent");
} else {
M5.Display.println("Watching...");
}
}
void setup() {
auto cfg = M5.config();
M5.begin(cfg);
// Grove / HY2.0-4P 側へ5Vを供給
// これがないと Unit が起動せず No I2C device になることがあります
M5.Power.setExtOutput(true);
M5.Display.setRotation(1);
M5.Display.setTextSize(2);
M5.Display.fillScreen(BLACK);
M5.Display.setCursor(0, 0);
M5.Display.println("Sonic HID");
// I2C 初期化
Wire.begin(I2C_SDA, I2C_SCL);
Wire.setClock(100000);
// Ultrasonic Unit 初期化
sonic.begin(&Wire, SONIC_ADDR, I2C_SDA, I2C_SCL, 100000L);
// USB HID Keyboard 初期化
Keyboard.begin();
USB.begin();
delay(1000);
M5.Display.fillRect(0, 20, 240, 20, BLACK);
M5.Display.setCursor(0, 15);
M5.Display.println("Ready");
}
void loop() {
M5.update();
unsigned long now = millis();
bool keySent = false;
// 一定間隔で距離を読む
if (now - lastReadMs >= READ_INTERVAL_MS) {
lastReadMs = now;
lastDistanceMm = sonic.getDistance();
currentZone = distanceToZone(lastDistanceMm);
// 有効な距離で、かつゾーンが変わった時だけキー送信
if (currentZone != ZONE_INVALID &&
currentZone != lastZone &&
now - lastSendMs >= SEND_INTERVAL_MS) {
sendKeyForZone(currentZone);
lastZone = currentZone;
lastSendMs = now;
keySent = true;
}
drawStatus(lastDistanceMm, currentZone, keySent);
}
}
他のセンサ
https://shop.m5stack.com/collections/unit/UNIT-SENSOR?page=1
https://www.switch-science.com/collections/all/cat-メーカー-ブランド_m5stack+cat-拡張基板-その他基板_unit