Skip to content

Commit

Permalink
Initiate magenetometer based compass calibration from button presses
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
danwelch3 committed Dec 12, 2024
1 parent 03770b7 commit 65d5e93
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 7 deletions.
12 changes: 12 additions & 0 deletions src/ButtonThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions src/graphics/Screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -593,6 +597,8 @@ class Screen : public concurrency::OSThread

bool hasCompass = false;
float compassHeading;
uint32_t endCalibrationAt;

/// Holds state for debug information
DebugInfo debugInfo;

Expand Down
7 changes: 7 additions & 0 deletions src/motion/AccelerometerThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
33 changes: 27 additions & 6 deletions src/motion/BMX160Sensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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
1 change: 1 addition & 0 deletions src/motion/BMX160Sensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/motion/MotionSensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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());

Expand Down
6 changes: 6 additions & 0 deletions src/motion/MotionSensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -53,6 +55,10 @@ class MotionSensor
#endif

ScanI2C::FoundDevice device;

// Do calibration if true
bool doCalibration = false;
uint32_t endCalibrationAt;
};

namespace MotionSensorI2C
Expand Down

0 comments on commit 65d5e93

Please sign in to comment.