Pedometer
Dependencies: MPU9250
main.cpp
- Committer:
- mynameisteodora
- Date:
- 2019-01-17
- Revision:
- 2:6d3c59b866aa
- Parent:
- 1:a192c8fd3da3
File content as of revision 2:6d3c59b866aa:
#include "mbed.h" #include "inttypes.h" #include "MPU9250.h" #include "math.h" #include <events/mbed_events.h> #include "ble/BLE.h" #include "ble/Gap.h" #include "ble/services/HeartRateService.h" #include "us_ticker_api.h" DigitalOut led1(LED1, 1); const static char DEVICE_NAME[] = "Pedometer"; static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE}; static HeartRateService *hrServicePtr; static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE); MPU9250 mpu9250(P0_26, P0_27); Serial pc(USBTX, USBRX); // tx, rx float accel_bias[3], gyro_bias[3]; float ax, ay, az, gx, gy, gz, mag_accel, mag_gyro; short mag_accel_int = 0; int og_mag_accel; float aRes = mpu9250.aRes; float gRes = mpu9250.gRes; uint8_t step = 0; uint8_t test = 0; float x_avg, y_avg, z_avg; // threshold should be dynamic, obtained by (max+min)/2 float threshold = 80.0f; float dynamic_threshold_x = 80.0f; float dynamic_threshold_y = 80.0f; float dynamic_threshold_z = 80.0f; // the first time the low_pass function is called, xm1 is 0 // then it will be updated with values from the previous call float xm1_x = 0, xm1_y = 0, xm1_z = 0; float max_lp = 120.0f; float min_lp = -40.0f; float threshold_lp = 80.0f; void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) { BLE::Instance().gap().startAdvertising(); // restart advertising } // simple low-pass filter with two registers float low_pass(float *x, float *y, int M, float xm1) { int n; y[0] = x[0] + xm1; for(n = 1; n < M; n++) { y[n] = x[n] + x[n-1]; } return x[M-1]; } void updateSensorValue() { int16_t accel_data[3] = {0}; int window_size = 20; int M = window_size/2; // 0 - x, 1 - y, 2 - z int most_active_axis = 0; int flag = 0; float in_x[window_size]; float in_y[window_size]; float in_z[window_size]; float out_x[window_size]; float out_y[window_size]; float out_z[window_size]; // collect n = window_size samples and detect most active axis float min_x = 0.0f, min_y = 0.0f, min_z = 0.0f; float max_x = 0.0f, max_y = 0.0f, max_z = 0.0f; float peak_to_peak_x = 0.0f, peak_to_peak_y = 0.0f, peak_to_peak_z = 0.0f; for(int i = 0; i < window_size; i++) { mpu9250.readAccelData(accel_data); in_x[i] = accel_data[0] - x_avg; in_y[i] = accel_data[1] - y_avg; in_z[i] = accel_data[2] - z_avg; pc.printf("Accel_x: %d\n", in_x[i]); pc.printf("Accel_y: %d\n", in_y[i]); pc.printf("Accel_z: %d\n", in_z[i]); if(in_x[i] > max_x) { max_x = in_x[i]; } if(in_y[i] > max_y) { max_y = in_y[i]; } if(in_z[i] > max_z) { max_z = in_z[i]; } if(in_x[i] < min_x) { min_x = in_x[i]; } if(in_y[i] < min_y) { min_y = in_y[i]; } if(in_z[i] < min_z) { min_z = in_z[i]; } } peak_to_peak_x = max_x - min_x; peak_to_peak_y = max_y - min_y; peak_to_peak_z = max_z - max_z; if(peak_to_peak_x > peak_to_peak_y) { if(peak_to_peak_x > peak_to_peak_z) { dynamic_threshold_x = (min_x + max_x)/2; most_active_axis = 0; pc.printf("Most active axis: X\n"); } else { dynamic_threshold_z = (min_z + max_z)/2; most_active_axis = 2; pc.printf("Most active axis: Z\n"); } } else if(peak_to_peak_y > peak_to_peak_z) { dynamic_threshold_y = (min_y + max_y)/2; most_active_axis = 1; pc.printf("Most active axis: Y\n"); } else { dynamic_threshold_z = (min_z + max_z)/2; most_active_axis = 2; pc.printf("Most active axis: Z\n"); } if(most_active_axis == 0) { // low pass on x-axis xm1_x = low_pass(in_x, out_x, M, xm1_x); xm1_x = low_pass(&in_x[M], &out_x[M], M, xm1_x); pc.printf("Low passed axis X\n"); // now analyse the output data, out_x, to see if the threshold has been passed for(int i = 1; i < window_size; i++) { // if the threshold is being crossed from the upper half to the lower half and the flag is set to 0 if(out_x[i] < out_x[i-1] && out_x[i] < dynamic_threshold_x && out_x[i-1] > dynamic_threshold_x && flag == 0) { step = 1; flag = 1; pc.printf("Step!\n"); hrServicePtr->updateHeartRate(step); wait(0.50); } else if (out_x[i] < out_x[i-1] && out_x[i] < dynamic_threshold_x && out_x[i-1] > dynamic_threshold_x && flag == 1) { // do nothing } // if the threshold is being crossed from the lower half to the upper half and the flag is set to 1 else if (out_x[i] > out_x[i-1] && out_x[i] > dynamic_threshold_x && out_x[i-1] < dynamic_threshold_x && flag == 1) { // this is a step but we are counting gaits // however, we need to set the flag to 0 flag = 0; } } } else if(most_active_axis == 1) { // low pass on y-axis xm1_y = low_pass(in_y, out_y, M, xm1_y); xm1_y = low_pass(&in_y[M], &out_y[M], M, xm1_y); pc.printf("Low passed axis Y\n"); // now analyse the output data, out_y, to see if the threshold has been passed for(int i = 1; i < window_size; i++) { // if the threshold is being crossed from the upper half to the lower half and the flag is set to 0 if(out_y[i] < out_y[i-1] && out_y[i] < dynamic_threshold_y && out_y[i-1] > dynamic_threshold_y && flag == 0) { step = 1; flag = 1; pc.printf("Step!\n"); hrServicePtr->updateHeartRate(step); wait(0.50); } else if (out_y[i] < out_y[i-1] && out_y[i] < dynamic_threshold_y && out_y[i-1] > dynamic_threshold_y && flag == 1) { // do nothing } // if the threshold is being crossed from the lower half to the upper half and the flag is set to 1 else if (out_y[i] > out_y[i-1] && out_y[i] > dynamic_threshold_y && out_y[i-1] < dynamic_threshold_y && flag == 1) { // this is a step but we are counting gaits // however, we need to set the flag to 0 flag = 0; } } } else if(most_active_axis == 2) { // low pass on z-axis xm1_z = low_pass(in_z, out_z, M, xm1_z); xm1_z = low_pass(&in_z[M], &out_z[M], M, xm1_z); pc.printf("Low passed axis Z\n"); // now analyse the output data, out_z, to see if the threshold has been passed for(int i = 1; i < window_size; i++) { // if the threshold is being crossed from the upper half to the lower half and the flag is set to 0 if(out_z[i] < out_z[i-1] && out_z[i] < dynamic_threshold_z && out_z[i-1] > dynamic_threshold_z && flag == 0) { step = 1; flag = 1; pc.printf("Step!\n"); hrServicePtr->updateHeartRate(step); wait(0.50); } else if (out_z[i] < out_z[i-1] && out_z[i] < dynamic_threshold_z && out_z[i-1] > dynamic_threshold_z && flag == 1) { // do nothing } else if (out_z[i] > out_z[i-1] && out_z[i] > dynamic_threshold_z && out_z[i-1] < dynamic_threshold_z && flag == 1) { // this is a step but we are counting gaits // however, we need to set the flag to 0 flag = 0; } } } } void periodicCallback(void) { led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */ if (BLE::Instance().getGapState().connected) { eventQueue.call(updateSensorValue); } } void onBleInitError(BLE &ble, ble_error_t error) { (void)ble; (void)error; /* Initialization error handling should go here */ } void printMacAddress() { /* Print out device MAC address to the console*/ Gap::AddressType_t addr_type; Gap::Address_t address; BLE::Instance().gap().getAddress(&addr_type, address); printf("DEVICE MAC ADDRESS: "); for (int i = 5; i >= 1; i--){ printf("%02x:", address[i]); } printf("%02x\r\n", address[0]); } void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) { BLE& ble = params->ble; ble_error_t error = params->error; if (error != BLE_ERROR_NONE) { onBleInitError(ble, error); return; } if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { return; } ble.gap().onDisconnection(disconnectionCallback); /* Setup primary service. */ hrServicePtr = new HeartRateService(ble, mag_accel_int, HeartRateService::LOCATION_FINGER); /* Setup advertising. */ ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR); ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); ble.gap().setAdvertisingInterval(1000); /* 1000ms */ ble.gap().startAdvertising(); printMacAddress(); } void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) { BLE &ble = BLE::Instance(); eventQueue.call(Callback<void()>(&ble, &BLE::processEvents)); } int main() { pc.baud(9600); mpu9250.resetMPU9250(); pc.printf("MPU reset\n"); mpu9250.calibrateMPU9250(accel_bias, gyro_bias); pc.printf("Library calibration done!\n"); // Implement own calibration to estimate the threshold values int sum_x = 0, sum_y = 0, sum_z = 0; int xvals[100] = {0}, yvals[100] = {0}, zvals[100] = {0}; int16_t local_accel_data[3] = {0}; for(int i = 0; i < 100; i++) { mpu9250.readAccelData(local_accel_data); xvals[i] = local_accel_data[0]; yvals[i] = local_accel_data[1]; zvals[i] = local_accel_data[2]; sum_x += xvals[i]; sum_y += yvals[i]; sum_z += zvals[i]; } x_avg = sum_x/100.0f; y_avg = sum_y/100.0f; z_avg = sum_z/100.0f; pc.printf("Accel_x average: %f\n", x_avg); pc.printf("Accel_y average: %f\n", y_avg); pc.printf("Accel_z average: %f\n", z_avg); pc.printf("Accel bias: %f\n", accel_bias[0]); mpu9250.initMPU9250(); pc.printf("Initialisation successful!\n"); mpu9250.getAres(); pc.printf("Accel sensitivity: %f\n", aRes); // the sensor readings are updated every second eventQueue.call_every(1000, periodicCallback); BLE &ble = BLE::Instance(); pc.printf("BLE instance created!\n"); ble.onEventsToProcess(scheduleBleEventsProcessing); pc.printf("BLE events scheduled!\n"); ble.init(bleInitComplete); pc.printf("BLE init complete!\n"); eventQueue.dispatch_forever(); pc.printf("Dispatched"); return 0; }