From 65d5e93308d81764e0ded86bf355ce67b22c9cad Mon Sep 17 00:00:00 2001 From: Dan Welch Date: Thu, 12 Dec 2024 10:46:33 -0700 Subject: [PATCH] Initiate magenetometer based compass calibration from button presses - only active for BMX160 accelerometers on RAK_4631 - replace automatic calibration on power on with button triggered calibration - set 5 presses to trigger 30s calibration - set 6 presses to trigger 60s calibration (useful if unit is not handheld, ie vehicle mounted) - show calibration time remaining on calibration alert screen --- protobufs | 2 +- src/ButtonThread.cpp | 12 ++++++++++++ src/graphics/Screen.h | 6 ++++++ src/motion/AccelerometerThread.h | 7 +++++++ src/motion/BMX160Sensor.cpp | 33 ++++++++++++++++++++++++++------ src/motion/BMX160Sensor.h | 1 + src/motion/MotionSensor.cpp | 8 ++++++++ src/motion/MotionSensor.h | 6 ++++++ 8 files changed, 68 insertions(+), 7 deletions(-) diff --git a/protobufs b/protobufs index 00c9c9932e..1eda884c39 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 00c9c9932ea50c14cdc44d497d2672a0031641ce +Subproject commit 1eda884c3962b7647aa6a2a3f98a23568cfcff1e diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index 3f64b3b3e2..664c3560f8 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -191,6 +191,18 @@ int32_t ButtonThread::runOnce() digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW); break; #endif + // 5 clicks: start accelerometer/magenetometer calibration for 30 seconds + case 5: + if (accelerometerThread) { + accelerometerThread->calibrate(30); + } + break; + // 6 clicks: start accelerometer/magenetometer calibration for 60 seconds + case 6: + if (accelerometerThread) { + accelerometerThread->calibrate(60); + } + break; // No valid multipress action default: break; diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 00884c5af9..95516bead2 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -278,6 +278,10 @@ class Screen : public concurrency::OSThread bool hasHeading() { return hasCompass; } long getHeading() { return compassHeading; } + + void setEndCalibration(uint32_t _endCalibrationAt) { endCalibrationAt = _endCalibrationAt; } + uint32_t getEndCalibration() { return endCalibrationAt; } + // functions for display brightness void increaseBrightness(); void decreaseBrightness(); @@ -593,6 +597,8 @@ class Screen : public concurrency::OSThread bool hasCompass = false; float compassHeading; + uint32_t endCalibrationAt; + /// Holds state for debug information DebugInfo debugInfo; diff --git a/src/motion/AccelerometerThread.h b/src/motion/AccelerometerThread.h index 95f09910fd..6e517d6b0f 100755 --- a/src/motion/AccelerometerThread.h +++ b/src/motion/AccelerometerThread.h @@ -48,6 +48,13 @@ class AccelerometerThread : public concurrency::OSThread setIntervalFromNow(0); }; + void calibrate(uint16_t forSeconds) + { + if (sensor) { + sensor->calibrate(forSeconds); + } + } + protected: int32_t runOnce() override { diff --git a/src/motion/BMX160Sensor.cpp b/src/motion/BMX160Sensor.cpp index 6562a651c6..8e483fc532 100755 --- a/src/motion/BMX160Sensor.cpp +++ b/src/motion/BMX160Sensor.cpp @@ -31,13 +31,14 @@ int32_t BMX160Sensor::runOnce() /* Get a new sensor event */ sensor.getAllData(&magAccel, NULL, &gAccel); -#if !defined(MESHTASTIC_EXCLUDE_SCREEN) - // experimental calibrate routine. Limited to between 10 and 30 seconds after boot - if (millis() > 12 * 1000 && millis() < 30 * 1000) { + if (doCalibration) { + if (!showingScreen) { + powerFSM.trigger(EVENT_PRESS); // keep screen alive during calibration showingScreen = true; screen->startAlert((FrameCallback)drawFrameCalibration); } + if (magAccel.x > highestX) highestX = magAccel.x; if (magAccel.x < lowestX) @@ -50,11 +51,20 @@ int32_t BMX160Sensor::runOnce() highestZ = magAccel.z; if (magAccel.z < lowestZ) lowestZ = magAccel.z; - } else if (showingScreen && millis() >= 30 * 1000) { - showingScreen = false; - screen->endAlert(); + + uint32_t now = millis(); + if (now > endCalibrationAt) { + doCalibration = false; + endCalibrationAt = 0; + showingScreen = false; + screen->endAlert(); + } + + // LOG_DEBUG("BMX160 min_x: %.4f, max_X: %.4f, min_Y: %.4f, max_Y: %.4f, min_Z: %.4f, max_Z: %.4f", lowestX, highestX, + // lowestY, highestY, lowestZ, highestZ); } +#if !defined(MESHTASTIC_EXCLUDE_SCREEN) int highestRealX = highestX - (highestX + lowestX) / 2; magAccel.x -= (highestX + lowestX) / 2; @@ -99,6 +109,17 @@ int32_t BMX160Sensor::runOnce() return MOTION_SENSOR_CHECK_INTERVAL_MS; } +void BMX160Sensor::calibrate(uint16_t forSeconds) +{ + + LOG_DEBUG("BMX160 calibration started for %is", forSeconds); + + doCalibration = true; + uint16_t calibrateFor = forSeconds * 1000; // calibrate for seconds provided + endCalibrationAt = millis() + calibrateFor; + screen->setEndCalibration(endCalibrationAt); +} + #endif #endif \ No newline at end of file diff --git a/src/motion/BMX160Sensor.h b/src/motion/BMX160Sensor.h index 26f4772719..9031b45042 100755 --- a/src/motion/BMX160Sensor.h +++ b/src/motion/BMX160Sensor.h @@ -23,6 +23,7 @@ class BMX160Sensor : public MotionSensor explicit BMX160Sensor(ScanI2C::FoundDevice foundDevice); virtual bool init() override; virtual int32_t runOnce() override; + virtual void calibrate(uint16_t forSeconds) override; }; #else diff --git a/src/motion/MotionSensor.cpp b/src/motion/MotionSensor.cpp index 242e3709f8..d87380085b 100755 --- a/src/motion/MotionSensor.cpp +++ b/src/motion/MotionSensor.cpp @@ -2,6 +2,8 @@ #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C +char timeRemainingBuffer[12]; + // screen is defined in main.cpp extern graphics::Screen *screen; @@ -37,6 +39,12 @@ void MotionSensor::drawFrameCalibration(OLEDDisplay *display, OLEDDisplayUiState display->setTextAlignment(TEXT_ALIGN_LEFT); display->setFont(FONT_MEDIUM); display->drawString(x, y, "Calibrating\nCompass"); + + uint8_t timeRemaining = (screen->getEndCalibration() - millis()) / 1000; + sprintf(timeRemainingBuffer, "( %02d )", timeRemaining); + display->setFont(FONT_SMALL); + display->drawString(x, y + 40, timeRemainingBuffer); + int16_t compassX = 0, compassY = 0; uint16_t compassDiam = graphics::Screen::getCompassDiam(display->getWidth(), display->getHeight()); diff --git a/src/motion/MotionSensor.h b/src/motion/MotionSensor.h index 78eec54cec..1848c472a1 100755 --- a/src/motion/MotionSensor.h +++ b/src/motion/MotionSensor.h @@ -40,6 +40,8 @@ class MotionSensor // Refer to /src/concurrency/OSThread.h for more information inline virtual int32_t runOnce() { return MOTION_SENSOR_CHECK_INTERVAL_MS; }; + virtual void calibrate(uint16_t forSeconds){}; + protected: // Turn on the screen when a tap or motion is detected virtual void wakeScreen(); @@ -53,6 +55,10 @@ class MotionSensor #endif ScanI2C::FoundDevice device; + + // Do calibration if true + bool doCalibration = false; + uint32_t endCalibrationAt; }; namespace MotionSensorI2C