The Problem
I've noticed during my testing that I'm getting to many false positives about my curved posture during walking.
Objective
Ignore curved posture detection during walking.
Solution
I've decided to use a built-in pedometer to detect walking, so the app can receive movement information from MCU using the new BLE pedometer characteristic.
IMU of LSM6DS3 has a built-in capability to measure steps. It shouldn't increase significantly MCU power consumption and memory footprint.
And to get access to this low level function I've switched to another Arduino library and start using SparkFunLSM6DS3 library. The library comes with a pedometer example https://github.com/sparkfun/SparkFun_LSM6DS3_Arduino_Library/tree/master/examples/Pedometer. It made my work a bit simpler.
I've added a function to configure IMU to enable the pedometer function:
void setupIMU()
{
//Call .beginCore() to configure the IMU
if( myIMU.beginCore() != 0 )
{
Serial.println("Error at beginCore() configure the IMU.");
}
else
{
Serial.println("IMU beginCore() passed.");
}
//Error accumulation variable
uint8_t errorAccumulator = 0;
uint8_t dataToWrite = 0; //Temporary variable
//Setup the accelerometer******************************
dataToWrite = 0; //Start Fresh!
// dataToWrite |= LSM6DS3_ACC_GYRO_BW_XL_200Hz;
dataToWrite |= LSM6DS3_ACC_GYRO_FS_XL_2g;
dataToWrite |= LSM6DS3_ACC_GYRO_ODR_XL_26Hz;
// //Now, write the patched together data
errorAccumulator += myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, dataToWrite);
//Set the ODR bit
errorAccumulator += myIMU.readRegister(&dataToWrite, LSM6DS3_ACC_GYRO_CTRL4_C);
dataToWrite &= ~((uint8_t)LSM6DS3_ACC_GYRO_BW_SCAL_ODR_ENABLED);
// Enable embedded functions -- ALSO clears the pdeo step count
errorAccumulator += myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL10_C, 0x3E);
// Enable pedometer algorithm
errorAccumulator += myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_CFG1, 0x40);
// Step Detector interrupt driven to INT1 pin
errorAccumulator += myIMU.writeRegister( LSM6DS3_ACC_GYRO_INT1_CTRL, 0x10 );
if( errorAccumulator )
{
Serial.println("Problem configuring the IMU.");
}
else
{
Serial.println("IMU O.K.");
}
}
I've added the new BLE characteristic :
// Custom BLE Posture Position Characteristic
BLEUnsignedCharCharacteristic postureChar("b7469627-3ad1-4b96-8684-ff4d6cb73014", // custom 128-bit characteristic UUID
BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes
int oldPosture = EI_STRAIGHT; // last posture position reading from EI inference
int oldPedometer = 0; // last pedometer reading from IMUAnd registered it:
postureService.addCharacteristic(postureChar); // add the posture position characteristic
I've added a new function to update this characteristic using reading from the pedometer:
void updatePedometer()
{
uint8_t readDataByte = 0;
uint16_t stepsTaken = 0;
//Read the 16bit value by two 8bit operations
myIMU.readRegister(&readDataByte, LSM6DS3_ACC_GYRO_STEP_COUNTER_H);
stepsTaken = ((uint16_t)readDataByte) << 8;
myIMU.readRegister(&readDataByte, LSM6DS3_ACC_GYRO_STEP_COUNTER_L);
stepsTaken |= readDataByte;
//Display steps taken
Serial.print("Steps taken: ");
Serial.println(stepsTaken);
if (stepsTaken != oldPedometer) { // if the pedometer value has changed
pedometerChar.writeValue(stepsTaken); // and update the battery level characteristic
oldPedometer = stepsTaken; // save the level for next comparison
Serial.println("Pedometer notification sent");
}
}Than I've added additional code in my Android app to read and process this new characteristic. And I added vibration (line 14) , so you can feel when your posture need correction.
var data = new Uint8Array(buffer);
console.log("Data value " + data[0]);
if (data[0] == trakcore.STRAIGHT) {
resultDiv.innerHTML = "Good Posture";
resultDiv.style.backgroundColor = "initial";
navigator.vibrate(0);
}
else if (pedometerSteps == oldPedometerSteps) { // no movement - most likely sitting
resultDiv.innerHTML = "WARNING: Adjust Posture";
resultDiv.style.backgroundColor = "red";
// Vibrate for 1s, wait 1s, vibrate for 2s, wait 1s, vibrate for 3s
navigator.vibrate([1000, 1000, 2000, 1000, 3000]);
} else {
oldPedometerSteps = pedometerSteps; // moving??
const start = Date.now();
setTimeout(() => { // trigger verification of posture in 5 seconds
const millis = Date.now() - start;
ble.read(deviceId, trakcore.serviceUUID, trakcore.postureCharUUID, app.onData, app.onError1);
console.log(`seconds elapsed = ${Math.floor(millis / 1000)}`);
}, 5000); //check in 5 seconds
}
if (subscribedPedometer == false) {
ble.startNotification(deviceId, trakcore.serviceUUID, trakcore.pedometerCharUUID, app.onMovement, app.onError2);
}
},
onMovement: function (buffer) {
subscribedPedometer = true;
var data = new Uint16Array(buffer);
pedometerSteps = data[0];
console.log("Move value " + pedometerSteps);
moveDiv.innerHTML = "Steps: " + pedometerSteps;
moveDiv.style.backgroundColor = "initial";
},
Result
False positives of curved posture has been eliminated and I've added additional field on the app dashboard to show steps:
Challenges
- Cordova BLE plugin function ble.startNotification on Android requires a special attention as it may not get registered on the first attempt when more than one characteristic needs to be registered. It took me some time to find a workaround.
- After I switch LSM6DS3 IMU library my anomaly score for the posture went up significantly. So I temporary removed it from my rules. I need to identify why it went up.





