骨折して入院して車椅子になりました。関連した困りごとを実装してみました。
IoTLTでの発表内容補足的な感じです。
https://speakerdeck.com/n0bisuke2/gu-zhe-toru-yuan-toiot-number-iotlt
骨折しました。
骨折して入院して車椅子になりました。
車椅子以外と疲れる問題
入院中は車椅子での移動だったのですが、車椅子は意外と疲れます。
疲れるんですけど、ヘルスケアアプリでの活動量はだいぶ低いという結果に。
車椅子でどれくらい移動しているかを計測したいなと思いました。
松葉杖よりは疲れないです。今のところ松葉杖が最上級。
車椅子にAtomS3を取り付け
たまたま持っていたAtomS3を取り付けました。
実際のコード
M5Unifiedを使っています。
GPT-4oに聞きながらやってみましたが、M5unifideでの書き方もバッチリでした。
#include <M5Unified.h>
float gyroZOffset = 0.0;
void calibrateGyro() {
const int numReadings = 1000;
float sum = 0.0;
for (int i = 0; i < numReadings; i++) {
float gyroX, gyroY, gyroZ;
M5.Imu.getGyro(&gyroX, &gyroY, &gyroZ);
sum += gyroZ;
delay(1);
}
gyroZOffset = sum / numReadings;
}
void setup(void) {
auto cfg = M5.config();
M5.begin(cfg);
M5.Display.setTextSize(2); // 文字サイズを1.5倍に設定
const char* name;
switch (M5.getBoard()) {
case m5::board_t::board_M5AtomS3:
name = "ATOM S3";
break;
default:
name = "Who am I ?";
break;
}
M5.Display.startWrite();
M5.Display.print("Core:");
M5.Display.println(name);
Serial.printf("core:%s\n", name);
switch (M5.Imu.getType()) {
case m5::imu_t::imu_mpu6886:
name = "MPU6886";
break;
default:
name = "none";
break;
}
M5.Display.print("IMU:");
M5.Display.println(name);
M5.Display.endWrite();
Serial.printf("imu:%s\n", name);
// Calibrate the gyro
calibrateGyro();
}
float calculateRotationAngle(float gyroRate, float deltaTime) {
return gyroRate * deltaTime;
}
void loop(void) {
delay(1);
int h = M5.Display.height() / 8;
M5.update();
static constexpr const int colors[] = { TFT_WHITE, TFT_CYAN, TFT_RED, TFT_YELLOW, TFT_BLUE, TFT_GREEN };
static constexpr const char* const names[] = { "none", "wasHold", "wasClicked", "wasPressed", "wasReleased", "wasDeciedCount" };
M5.Display.startWrite();
auto state = M5.BtnA.wasHold() ? 1
: M5.BtnA.wasClicked() ? 2
: M5.BtnA.wasPressed() ? 3
: M5.BtnA.wasReleased() ? 4
: M5.BtnA.wasDeciedClickCount() ? 5
: 0;
if (state) {
Serial.printf("BtnA:%s count:%d\n", names[state], M5.BtnA.getClickCount());
if (!M5.Display.displayBusy()) {
M5.Display.fillRect(0, h * 3, h, h - 1, colors[state]);
M5.Display.setCursor(0, h * 3);
M5.Display.printf("%d", M5.BtnA.getClickCount());
}
}
M5.Display.endWrite();
static float accumulatedAngle = 0;
static int rotationCount = 0;
static int partialTurns = 0;
if (M5.Imu.isEnabled()) {
float gyroX, gyroY, gyroZ;
M5.Imu.getGyro(&gyroX, &gyroY, &gyroZ);
// Apply gyro offset and reverse the sign
gyroZ = - (gyroZ - gyroZOffset);
static unsigned long lastTime = 0;
unsigned long currentTime = millis();
float deltaTime = (currentTime - lastTime) / 1000.0; // delta time in seconds
lastTime = currentTime;
// Assuming the wheelchair rotates around the Z-axis (yaw)
float rotationAngle = calculateRotationAngle(gyroZ, deltaTime);
accumulatedAngle += rotationAngle;
// Keep accumulatedAngle within 0 to 359 degrees
if (accumulatedAngle >= 360.0) {
rotationCount++;
accumulatedAngle -= 360.0;
} else if (accumulatedAngle < 0.0) {
rotationCount--;
accumulatedAngle += 360.0;
}
// Calculate partial turns within the range of 0 to 59
partialTurns = static_cast<int>(accumulatedAngle / 6.0); // 1/60 turn = 6 degrees
M5.Display.startWrite();
M5.Display.setCursor(0, h * 5);
M5.Display.printf("Rotations: %d", rotationCount);
M5.Display.setCursor(0, h * 6);
M5.Display.printf("Partial Turns: %d", partialTurns);
M5.Display.endWrite();
Serial.printf("Rotations: %d, Partial Turns: %d\n", rotationCount, partialTurns);
}
M5.Display.display();
}
結構良い感じに計測ができました
今後
計測した値をスプレッドシートに記録するなどやりたいですが、病院で使えるWi-Fiがなかったのでそこは断念してました。
上手いやり方検討したい。。