ECE 4180 Fitbit Project / Mbed 2 deprecated 4180_Fitness_Tracker

Dependencies:   mbed PulseSensor2 SCP1000 mbed-rtos 4DGL-uLCD-SE LSM9DS1_Library_cal PinDetect FatFileSystemCpp GP-20U7

Committer:
memig3
Date:
Sun Apr 19 01:22:01 2020 +0000
Revision:
25:41ec16a87ebd
Parent:
24:841ceaf2cf69
Child:
31:3363c6923beb
added main_ticker.cpp which is a main function that records GPS latitude and longitude and has step and floor counting implemented. It uses tickers instead of rtos because of issues with too many serial devices when adding GPS

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dyu2021 0:ae05ad9e2610 1 #include "mbed.h"
dyu2021 20:adb9e6e1ad22 2 #include "rtos.h"
Richard_Xiong 7:fb47593628be 3 #include "LSM9DS1.h"
dyu2021 20:adb9e6e1ad22 4 #include "SCP1000.h"
dyu2021 20:adb9e6e1ad22 5 #include "MSCFileSystem.h"
dyu2021 20:adb9e6e1ad22 6 #include "PulseSensor.h"
dyu2021 20:adb9e6e1ad22 7 #include "PinDetect.h"
Richard_Xiong 7:fb47593628be 8 #include "uLCD_4DGL.h"
memig3 24:841ceaf2cf69 9
dyu2021 20:adb9e6e1ad22 10 SCP1000 scp1000(p5,p6,p7,p8);
dyu2021 20:adb9e6e1ad22 11 LSM9DS1 IMU(p9, p10, 0xD6, 0x3C);
memig3 24:841ceaf2cf69 12 PulseSensor PPG(p17);
memig3 24:841ceaf2cf69 13 uLCD_4DGL uLCD(p28,p27,p29);
dyu2021 20:adb9e6e1ad22 14 Serial pc(USBTX, USBRX);
memig3 24:841ceaf2cf69 15 DigitalOut one = LED1;
memig3 24:841ceaf2cf69 16 DigitalOut two = LED2;
memig3 24:841ceaf2cf69 17 DigitalOut three = LED3;
memig3 24:841ceaf2cf69 18 DigitalOut four = LED4;
memig3 24:841ceaf2cf69 19 AnalogIn pot(p20);
memig3 24:841ceaf2cf69 20 PinDetect pb(p21);
memig3 24:841ceaf2cf69 21
dyu2021 20:adb9e6e1ad22 22 #define FSNAME "msc"
dyu2021 20:adb9e6e1ad22 23 MSCFileSystem msc(FSNAME);
memig3 24:841ceaf2cf69 24
dyu2021 20:adb9e6e1ad22 25 volatile int bpm;
dyu2021 20:adb9e6e1ad22 26 volatile int steps = 0;
dyu2021 20:adb9e6e1ad22 27 volatile int flights = 0;
dyu2021 20:adb9e6e1ad22 28 volatile float distance = 0.0;
dyu2021 20:adb9e6e1ad22 29 volatile int calories = 0;
memig3 24:841ceaf2cf69 30 volatile unsigned long pressure;
memig3 24:841ceaf2cf69 31
dyu2021 20:adb9e6e1ad22 32 volatile int mode = 1;
dyu2021 20:adb9e6e1ad22 33 volatile int oldMode = 1;
memig3 24:841ceaf2cf69 34
dyu2021 20:adb9e6e1ad22 35 Thread thread1;
dyu2021 20:adb9e6e1ad22 36 Thread thread2;
dyu2021 20:adb9e6e1ad22 37 Thread thread3;
dyu2021 20:adb9e6e1ad22 38 Thread thread4;
dyu2021 20:adb9e6e1ad22 39 Thread thread5;
memig3 24:841ceaf2cf69 40
dyu2021 20:adb9e6e1ad22 41 bool run = true;
memig3 24:841ceaf2cf69 42 Mutex mtx;
memig3 24:841ceaf2cf69 43
dyu2021 20:adb9e6e1ad22 44 // when the pushbotton is pressed the run flag is set to false and the main
dyu2021 20:adb9e6e1ad22 45 // function while loop exits so that the data file can be closed
dyu2021 20:adb9e6e1ad22 46 // so press the button when you're ready to be done collecting data
dyu2021 20:adb9e6e1ad22 47 void button (void) {
dyu2021 20:adb9e6e1ad22 48 run = false;
memig3 24:841ceaf2cf69 49 thread1.terminate();
memig3 24:841ceaf2cf69 50 thread2.terminate();
memig3 24:841ceaf2cf69 51 thread3.terminate();
memig3 24:841ceaf2cf69 52 thread4.terminate();
memig3 24:841ceaf2cf69 53 thread5.terminate();
dyu2021 20:adb9e6e1ad22 54 }
memig3 24:841ceaf2cf69 55
dyu2021 20:adb9e6e1ad22 56 // Reads the value of the potentiometer and averages over 3 readings to get rid
dyu2021 20:adb9e6e1ad22 57 // of random spikes/zero values. Returns either a 1, 2 or 3 based on which 3rd
dyu2021 20:adb9e6e1ad22 58 // of its range the potentiometer is in and which screen should be displayed
dyu2021 20:adb9e6e1ad22 59 void read_pot() {
dyu2021 20:adb9e6e1ad22 60 float m1;
dyu2021 20:adb9e6e1ad22 61 float m2;
dyu2021 20:adb9e6e1ad22 62 float m3;
dyu2021 20:adb9e6e1ad22 63 while(1) {
dyu2021 20:adb9e6e1ad22 64 oldMode = mode;
dyu2021 20:adb9e6e1ad22 65 m1 = pot.read();
dyu2021 20:adb9e6e1ad22 66 m2 = pot.read();
dyu2021 20:adb9e6e1ad22 67 m3 = pot.read();
dyu2021 20:adb9e6e1ad22 68 if(m1 < 0.2 && m2 < 0.2 && m3 < 0.2) {
dyu2021 20:adb9e6e1ad22 69 mode = 1;
dyu2021 20:adb9e6e1ad22 70 } else if(m1 >= 0.2 && m1 < 0.4 && m2 >= 0.2 && m2 < 0.4 && m3 >= 0.2 && m3 < 0.4) {
dyu2021 20:adb9e6e1ad22 71 mode = 2;
dyu2021 20:adb9e6e1ad22 72 } else if(m1 >= 0.4 && m1 < 0.6 && m2 >= 0.4 && m2 < 0.6 && m3 >= 0.4 && m3 < 0.6) {
dyu2021 20:adb9e6e1ad22 73 mode = 3;
dyu2021 20:adb9e6e1ad22 74 } else if(m1 >= 0.6 && m1 < 0.8 && m2 >= 0.6 && m2 < 0.8 && m3 >= 0.6 && m3 < 0.8) {
dyu2021 20:adb9e6e1ad22 75 mode = 4;
dyu2021 20:adb9e6e1ad22 76 } else if(m1 >= 0.8 && m2 >= 0.8 && m3 >= 0.8) {
dyu2021 20:adb9e6e1ad22 77 mode = 5;
dyu2021 20:adb9e6e1ad22 78 }
dyu2021 20:adb9e6e1ad22 79 //when the mode changes, clear the screen
dyu2021 20:adb9e6e1ad22 80 if (oldMode != mode) {
dyu2021 20:adb9e6e1ad22 81 mtx.lock();
dyu2021 20:adb9e6e1ad22 82 uLCD.filled_rectangle(0,0, 128, 128, BLACK);
dyu2021 20:adb9e6e1ad22 83 mtx.unlock();
dyu2021 20:adb9e6e1ad22 84 }
dyu2021 20:adb9e6e1ad22 85 Thread::wait(200);
dyu2021 20:adb9e6e1ad22 86 }
dyu2021 20:adb9e6e1ad22 87 }
memig3 24:841ceaf2cf69 88
dyu2021 20:adb9e6e1ad22 89 //Display the time on the top
dyu2021 20:adb9e6e1ad22 90 void display_time() {
dyu2021 20:adb9e6e1ad22 91 while(1) {
dyu2021 20:adb9e6e1ad22 92 mtx.lock();
dyu2021 20:adb9e6e1ad22 93 uLCD.locate(1, 1);
dyu2021 20:adb9e6e1ad22 94 uLCD.color(WHITE);
dyu2021 20:adb9e6e1ad22 95 uLCD.text_width(2);
dyu2021 20:adb9e6e1ad22 96 uLCD.text_height(3);
dyu2021 20:adb9e6e1ad22 97 time_t seconds = time(NULL);
dyu2021 20:adb9e6e1ad22 98 char timeBuffer[32];
dyu2021 20:adb9e6e1ad22 99 strftime(timeBuffer, 32, "%I:%M %p\r\n", localtime(&seconds));
dyu2021 20:adb9e6e1ad22 100 uLCD.printf("%s", timeBuffer);
dyu2021 20:adb9e6e1ad22 101 mtx.unlock();
dyu2021 20:adb9e6e1ad22 102 Thread::wait(500);
dyu2021 20:adb9e6e1ad22 103 }
dyu2021 20:adb9e6e1ad22 104 }
memig3 24:841ceaf2cf69 105
memig3 24:841ceaf2cf69 106 /*
memig3 24:841ceaf2cf69 107 //Make sure program still alive
memig3 24:841ceaf2cf69 108 void blink_led() {
memig3 24:841ceaf2cf69 109 while(1) {
memig3 24:841ceaf2cf69 110 led2 = !led2;
memig3 24:841ceaf2cf69 111 Thread::wait(1000);
memig3 24:841ceaf2cf69 112 }
memig3 24:841ceaf2cf69 113 }
memig3 24:841ceaf2cf69 114 */
memig3 24:841ceaf2cf69 115
dyu2021 20:adb9e6e1ad22 116 void update_screen(void) {
dyu2021 20:adb9e6e1ad22 117 while(1) {
dyu2021 20:adb9e6e1ad22 118 mtx.lock();
dyu2021 20:adb9e6e1ad22 119 // print the information to the LCD display
dyu2021 20:adb9e6e1ad22 120 switch(mode) {
dyu2021 20:adb9e6e1ad22 121 case 1:
dyu2021 20:adb9e6e1ad22 122 //Step count
dyu2021 20:adb9e6e1ad22 123 uLCD.media_init();
memig3 24:841ceaf2cf69 124 uLCD.set_sector_address(0x0000, 0x0005);
memig3 24:841ceaf2cf69 125 uLCD.display_image(50, 45);
dyu2021 20:adb9e6e1ad22 126 uLCD.filled_rectangle(10, 110, 118, 115, BLACK);
dyu2021 20:adb9e6e1ad22 127 uLCD.locate(3, 11);
dyu2021 20:adb9e6e1ad22 128 uLCD.text_height(1);
dyu2021 20:adb9e6e1ad22 129 uLCD.text_width(1);
dyu2021 20:adb9e6e1ad22 130 uLCD.color(WHITE);
dyu2021 20:adb9e6e1ad22 131 uLCD.printf("%4d steps",steps);
memig3 24:841ceaf2cf69 132 //uLCD.filled_rectangle(10, 110, 118, 115, WHITE);
dyu2021 20:adb9e6e1ad22 133 break;
dyu2021 20:adb9e6e1ad22 134 case 2:
dyu2021 20:adb9e6e1ad22 135 // Heart rate
memig3 24:841ceaf2cf69 136 uLCD.media_init();
memig3 24:841ceaf2cf69 137 uLCD.set_sector_address(0x0000, 0x000A);
memig3 24:841ceaf2cf69 138 uLCD.display_image(50, 45);
dyu2021 20:adb9e6e1ad22 139 uLCD.locate(5, 11);
dyu2021 20:adb9e6e1ad22 140 uLCD.text_height(1);
dyu2021 20:adb9e6e1ad22 141 uLCD.text_width(1);
dyu2021 20:adb9e6e1ad22 142 uLCD.color(WHITE);
dyu2021 20:adb9e6e1ad22 143 uLCD.printf("%3d BPM", bpm);
dyu2021 20:adb9e6e1ad22 144 break;
dyu2021 20:adb9e6e1ad22 145 case 3:
dyu2021 20:adb9e6e1ad22 146 //Distance
memig3 24:841ceaf2cf69 147 uLCD.media_init();
memig3 24:841ceaf2cf69 148 uLCD.set_sector_address(0x0000, 0x000F);
memig3 24:841ceaf2cf69 149 uLCD.display_image(50, 45);
dyu2021 20:adb9e6e1ad22 150 uLCD.locate(6, 11);
dyu2021 20:adb9e6e1ad22 151 uLCD.text_height(1);
dyu2021 20:adb9e6e1ad22 152 uLCD.text_width(1);
dyu2021 20:adb9e6e1ad22 153 uLCD.color(WHITE);
dyu2021 20:adb9e6e1ad22 154 uLCD.printf("%4.2f MI", distance);
dyu2021 20:adb9e6e1ad22 155 break;
dyu2021 20:adb9e6e1ad22 156 case 4:
dyu2021 20:adb9e6e1ad22 157 //Calories
memig3 24:841ceaf2cf69 158 uLCD.media_init();
memig3 24:841ceaf2cf69 159 uLCD.set_sector_address(0x0000, 0x0000);
memig3 24:841ceaf2cf69 160 uLCD.display_image(50, 45);
dyu2021 20:adb9e6e1ad22 161 uLCD.locate(4, 11);
dyu2021 20:adb9e6e1ad22 162 uLCD.text_height(1);
dyu2021 20:adb9e6e1ad22 163 uLCD.text_width(1);
dyu2021 20:adb9e6e1ad22 164 uLCD.color(WHITE);
dyu2021 20:adb9e6e1ad22 165 uLCD.printf("%4d cal", calories);
dyu2021 20:adb9e6e1ad22 166 break;
dyu2021 20:adb9e6e1ad22 167 case 5:
dyu2021 20:adb9e6e1ad22 168 //Floors
memig3 24:841ceaf2cf69 169 uLCD.media_init();
memig3 24:841ceaf2cf69 170 uLCD.set_sector_address(0x0000, 0x0014);
memig3 24:841ceaf2cf69 171 uLCD.display_image(50, 45);
dyu2021 20:adb9e6e1ad22 172 uLCD.locate(4, 11);
dyu2021 20:adb9e6e1ad22 173 uLCD.text_height(1);
dyu2021 20:adb9e6e1ad22 174 uLCD.text_width(1);
dyu2021 20:adb9e6e1ad22 175 uLCD.color(WHITE);
dyu2021 20:adb9e6e1ad22 176 uLCD.printf("%2d floors", flights);
dyu2021 20:adb9e6e1ad22 177 break;
dyu2021 20:adb9e6e1ad22 178 }
dyu2021 20:adb9e6e1ad22 179 mtx.unlock();
dyu2021 20:adb9e6e1ad22 180 Thread::wait(100);
dyu2021 20:adb9e6e1ad22 181 }
dyu2021 20:adb9e6e1ad22 182 }
memig3 24:841ceaf2cf69 183
dyu2021 20:adb9e6e1ad22 184 //Read heart rate sensor, only want to read it if in heart rate mode
dyu2021 20:adb9e6e1ad22 185 void read_heartRate() {
dyu2021 20:adb9e6e1ad22 186 while(mode == 2 && run) {
dyu2021 20:adb9e6e1ad22 187 bpm = PPG.get_BPM();
dyu2021 20:adb9e6e1ad22 188 Thread::wait(400);
dyu2021 20:adb9e6e1ad22 189 }
dyu2021 20:adb9e6e1ad22 190 }
memig3 24:841ceaf2cf69 191
dyu2021 20:adb9e6e1ad22 192 //Read barometer and count floors
dyu2021 23:1971e5cb6e3f 193 void read_barometer() {
memig3 24:841ceaf2cf69 194 unsigned long pressure_buff[10] = {0};
dyu2021 20:adb9e6e1ad22 195 while(run) {
dyu2021 20:adb9e6e1ad22 196 pressure = scp1000.readPressure();
dyu2021 20:adb9e6e1ad22 197 //Floor counting algo here
memig3 24:841ceaf2cf69 198 /*if(pressure != 0 && pressure_buff[0] != 0 && pressure - pressure_buff[0] > 100) {
memig3 24:841ceaf2cf69 199 flights++;
memig3 24:841ceaf2cf69 200 }
memig3 24:841ceaf2cf69 201 for(int i = 0; i < (sizeof pressure_buff) - 1; i++) {
memig3 24:841ceaf2cf69 202 pressure_buff[i] = pressure_buff[i + 1];
memig3 24:841ceaf2cf69 203 }
memig3 24:841ceaf2cf69 204 pressure_buff[9] = pressure;*/
dyu2021 20:adb9e6e1ad22 205 Thread::wait(200);
dyu2021 20:adb9e6e1ad22 206 }
dyu2021 20:adb9e6e1ad22 207 }
dyu2021 20:adb9e6e1ad22 208
dyu2021 0:ae05ad9e2610 209 int main() {
dyu2021 20:adb9e6e1ad22 210 // Off button
dyu2021 20:adb9e6e1ad22 211 pb.mode(PullUp);
dyu2021 20:adb9e6e1ad22 212 pb.attach_deasserted(&button);
dyu2021 20:adb9e6e1ad22 213 pb.setSampleFrequency();
dyu2021 20:adb9e6e1ad22 214
Richard_Xiong 6:29ccbdd09706 215 // set up the display
dyu2021 20:adb9e6e1ad22 216 uLCD.baudrate(3000000);
Richard_Xiong 2:0c1c9795bfc4 217 uLCD.background_color(BLACK);
Richard_Xiong 2:0c1c9795bfc4 218 uLCD.cls();
dyu2021 20:adb9e6e1ad22 219
dyu2021 20:adb9e6e1ad22 220 //Set RTC time
dyu2021 20:adb9e6e1ad22 221 set_time(1256729737);
Richard_Xiong 5:874e0af6fb50 222
dyu2021 20:adb9e6e1ad22 223 // LED indicates whether or not data is being collected
memig3 24:841ceaf2cf69 224 one = 0;
dyu2021 20:adb9e6e1ad22 225 // Start sensors
memig3 24:841ceaf2cf69 226 int sample_num = 1;
dyu2021 20:adb9e6e1ad22 227 PPG.start();
dyu2021 20:adb9e6e1ad22 228 IMU.begin();
dyu2021 20:adb9e6e1ad22 229 IMU.calibrate(1);
dyu2021 20:adb9e6e1ad22 230 float ax;
dyu2021 20:adb9e6e1ad22 231 float ay;
dyu2021 20:adb9e6e1ad22 232 float az;
dyu2021 20:adb9e6e1ad22 233 float mag = 0;
dyu2021 20:adb9e6e1ad22 234 float buffer[2] = {0};
dyu2021 20:adb9e6e1ad22 235 float avg_buffer[2] = {0};
dyu2021 20:adb9e6e1ad22 236 float avg;
memig3 24:841ceaf2cf69 237
dyu2021 20:adb9e6e1ad22 238 // Initialize data file on usb flash drive
dyu2021 20:adb9e6e1ad22 239 FILE *fp = fopen( "/msc/data.txt", "w");
dyu2021 20:adb9e6e1ad22 240 if(fp == NULL) {
dyu2021 20:adb9e6e1ad22 241 error("Could not open file for write\n");
dyu2021 20:adb9e6e1ad22 242 }
memig3 24:841ceaf2cf69 243 fprintf(fp, "Sample Number, Pressure (Pa), Acceleration Magnitude (Gs), Heart Rate (bpm)\n");
dyu2021 20:adb9e6e1ad22 244
dyu2021 20:adb9e6e1ad22 245 //Start threads
dyu2021 20:adb9e6e1ad22 246 thread1.start(update_screen);
dyu2021 20:adb9e6e1ad22 247 thread2.start(display_time);
dyu2021 20:adb9e6e1ad22 248 thread3.start(read_pot);
dyu2021 20:adb9e6e1ad22 249 thread4.start(read_heartRate);
dyu2021 20:adb9e6e1ad22 250 thread5.start(read_barometer);
Richard_Xiong 5:874e0af6fb50 251
dyu2021 20:adb9e6e1ad22 252 while(run) {
dyu2021 20:adb9e6e1ad22 253 // Read Sensors
dyu2021 20:adb9e6e1ad22 254 //bpm = PPG.get_BPM();
dyu2021 20:adb9e6e1ad22 255 //pressure = scp1000.readPressure();
dyu2021 20:adb9e6e1ad22 256 IMU.readAccel();
dyu2021 20:adb9e6e1ad22 257 ax = IMU.calcAccel(IMU.ax);
dyu2021 20:adb9e6e1ad22 258 ay = IMU.calcAccel(IMU.ay);
dyu2021 20:adb9e6e1ad22 259 az = IMU.calcAccel(IMU.az);
dyu2021 20:adb9e6e1ad22 260 // Calculate the 3 point moving average of the magnitude of the
dyu2021 20:adb9e6e1ad22 261 // acceleration vector
dyu2021 20:adb9e6e1ad22 262 mag = sqrt((ax*ax) + (ay*ay) + (az*az));
dyu2021 20:adb9e6e1ad22 263 avg = (buffer[0] + buffer[1] + mag) / 3;
dyu2021 20:adb9e6e1ad22 264 buffer[0] = buffer[1];
dyu2021 20:adb9e6e1ad22 265 buffer[1] = mag;
dyu2021 20:adb9e6e1ad22 266 // Count a step if the previous point was a maximum (greater than the
dyu2021 20:adb9e6e1ad22 267 // current point and 2 points back) and was greater than the threshold
dyu2021 20:adb9e6e1ad22 268 // value of 1.05
dyu2021 20:adb9e6e1ad22 269 if(sample_num > 1) {
memig3 24:841ceaf2cf69 270 float dif1 = avg_buffer[1] - avg_buffer[0];
memig3 24:841ceaf2cf69 271 float dif2 = avg_buffer[1] - avg;
memig3 24:841ceaf2cf69 272 float peak_prominence = 0.03;
memig3 24:841ceaf2cf69 273 if(dif1 > peak_prominence && dif2 > peak_prominence) {
dyu2021 20:adb9e6e1ad22 274 steps++;
dyu2021 20:adb9e6e1ad22 275 }
dyu2021 20:adb9e6e1ad22 276 }
dyu2021 20:adb9e6e1ad22 277 avg_buffer[0] = avg_buffer[1];
dyu2021 20:adb9e6e1ad22 278 avg_buffer[1] = avg;
memig3 24:841ceaf2cf69 279
dyu2021 20:adb9e6e1ad22 280 // Save the data to the usb flash drive and print to the terminal
memig3 24:841ceaf2cf69 281 fprintf(fp, "%d, %lu, %f, %d\r\n", sample_num, pressure, avg, bpm);
memig3 24:841ceaf2cf69 282 pc.printf("%d, %lu, %f, %d\r\n", sample_num, pressure, avg, bpm);
dyu2021 20:adb9e6e1ad22 283 sample_num++;
memig3 24:841ceaf2cf69 284 one = !one;
dyu2021 20:adb9e6e1ad22 285 // Sampling rate of ~200 Hz
dyu2021 20:adb9e6e1ad22 286 Thread::wait(50);
dyu2021 0:ae05ad9e2610 287 }
dyu2021 20:adb9e6e1ad22 288 fclose(fp);
memig3 24:841ceaf2cf69 289 one = 0;
dyu2021 20:adb9e6e1ad22 290 }