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:
Sat Apr 18 17:54:15 2020 +0000
Revision:
24:841ceaf2cf69
Parent:
23:1971e5cb6e3f
Child:
25:41ec16a87ebd
added pictures to LCD and improved step counting algorithm

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