Fitbit code using RTOS
Dependencies: mbed PulseSensor2 SCP1000 mbed-rtos 4DGL-uLCD-SE LSM9DS1_Library_cal PinDetect FatFileSystemCpp GP-20U7
main.cpp
- Committer:
- dyu2021
- Date:
- 2020-04-22
- Revision:
- 4:158ea0c5531c
- Parent:
- 3:f3e1ee4aa5ec
File content as of revision 4:158ea0c5531c:
#include "mbed.h" #include "rtos.h" #include "LSM9DS1.h" #include "SCP1000.h" #include "PulseSensor.h" #include "PinDetect.h" #include "uLCD_4DGL.h" #include "GPS.h" #include "MSCFileSystem.h" SCP1000 scp1000(p5,p6,p7,p8); LSM9DS1 IMU(p9, p10, 0xD6, 0x3C); PulseSensor PPG(p17); uLCD_4DGL uLCD(p28,p27,p29); Serial pc(USBTX, USBRX); DigitalOut one = LED1; DigitalOut two = LED2; DigitalOut three = LED3; DigitalOut four = LED4; AnalogIn pot(p20); PinDetect pb(p21); GPS gps(p13, p14); #define FSNAME "msc" MSCFileSystem msc(FSNAME); int bpm; int steps = 0; int flights = 0; float distance = 0.0; float calories = 0; int oldSteps = 0; const int stepGoal = 100; float stride_length = 0.0; unsigned long pressure; float latitude = 0; float longitude = 0; float old_lat = 0; float old_lon = 0; #define PI 3.14159 unsigned long p_buff[4]; int count = 0; int mode = 1; int oldMode = 1; bool run = true; int gender; int weight; int age; int screen = 1; int oldScreen = 1; bool setup_state = true; Timer usb_timer; Thread thread1; Thread thread2; Thread thread3; Thread thread4; Thread thread5; Mutex serial_mtx; Mutex usb_mtx; // when the pushbotton is pressed the run flag is set to false and the main // function while loop exits so that the data file can be closed // so press the button when you're ready to be done collecting data void button (void) { run = false; } void next() { oldScreen = screen; screen++; if(screen == 4) { setup_state = false; } } // Reads the value of the potentiometer and averages over 3 readings to get rid // of random spikes/zero values. Returns either a 1, 2 or 3 based on which 3rd // of its range the potentiometer is in and which screen should be displayed void read_pot() { float m1; float m2; float m3; oldMode = mode; m1 = pot.read(); m2 = pot.read(); m3 = pot.read(); if(m1 < 0.2 && m2 < 0.2 && m3 < 0.2) { mode = 1; } else if(m1 >= 0.2 && m1 < 0.4 && m2 >= 0.2 && m2 < 0.4 && m3 >= 0.2 && m3 < 0.4) { mode = 2; } else if(m1 >= 0.4 && m1 < 0.6 && m2 >= 0.4 && m2 < 0.6 && m3 >= 0.4 && m3 < 0.6) { mode = 3; } else if(m1 >= 0.6 && m1 < 0.8 && m2 >= 0.6 && m2 < 0.8 && m3 >= 0.6 && m3 < 0.8) { mode = 4; } else if(m1 >= 0.8 && m2 >= 0.8 && m3 >= 0.8) { mode = 5; } //when the mode changes, clear the screen } //Display the time on the top void display_time() { while(1) { serial_mtx.lock(); uLCD.locate(1, 1); uLCD.color(WHITE); uLCD.text_width(2); uLCD.text_height(3); time_t seconds = time(NULL); char timeBuffer[32]; strftime(timeBuffer, 32, "%I:%M %p\r\n", localtime(&seconds)); uLCD.printf("%s", timeBuffer); serial_mtx.unlock(); Thread::wait(700); } } void setup_screen(void) { while(1) { serial_mtx.lock(); if (oldScreen != screen) { uLCD.filled_rectangle(0,0, 128, 128, BLACK); oldScreen++; } switch(screen) { case 1: //Gender uLCD.locate(2, 1); uLCD.text_width(2); uLCD.text_height(2); uLCD.puts("Gender"); uLCD.text_width(3); uLCD.text_height(3); uLCD.locate(1, 3); uLCD.putc('M'); uLCD.locate(4, 3); uLCD.putc('F'); if(pot.read() > 0.5) { gender = 0; uLCD.rectangle(13, 60, 48, 100, BLACK); uLCD.rectangle(75, 60, 110, 100, GREEN); } else { gender = 1; uLCD.rectangle(75, 60, 110, 100, BLACK); uLCD.rectangle(13, 60, 48, 100, GREEN); } break; case 2: //Weight uLCD.color(WHITE); uLCD.locate(9, 14); uLCD.text_width(1); uLCD.text_height(1); uLCD.puts("lbs"); uLCD.locate(2, 1); uLCD.text_width(2); uLCD.text_height(2); uLCD.puts("Weight"); weight = 0.45 * (90 + pot.read() * 210); char weight_string[3]; if(weight < 100) { sprintf(weight_string, " %d", weight); } else { sprintf(weight_string, "%d", weight); } uLCD.text_width(3); uLCD.text_height(3); uLCD.locate(2, 3); uLCD.color(GREEN); uLCD.puts(weight_string); uLCD.line(35, 100, 110, 100, WHITE); break; case 3: //Age uLCD.color(WHITE); uLCD.locate(3, 1); uLCD.text_width(2); uLCD.text_height(2); uLCD.puts("Age"); age = (int) (10 + pot.read() * 89); char age_string[2]; sprintf(age_string, "%d", age); uLCD.text_width(3); uLCD.text_height(3); uLCD.locate(2, 3); uLCD.color(GREEN); uLCD.puts(age_string); uLCD.line(40, 100, 90, 100, WHITE); break; } serial_mtx.unlock(); Thread::wait(100); } } void update_screen(void) { while(1) { read_pot(); serial_mtx.lock(); if (oldMode != mode) { uLCD.filled_rectangle(0,0, 128, 128, BLACK); } // print the information to the LCD display switch(mode) { case 1: //Step count //uLCD.media_init(); //uLCD.set_sector_address(0x0000, 0x0005); //uLCD.display_image(50, 45); uLCD.filled_rectangle(10, 110, 118, 115, BLACK); uLCD.locate(3, 11); uLCD.text_height(1); uLCD.text_width(1); uLCD.color(WHITE); uLCD.printf("%4d steps",steps); uLCD.filled_rectangle(10, 110, 10 + int(steps * (110/stepGoal)), 115, WHITE); break; case 2: // Heart rate //uLCD.media_init(); //uLCD.set_sector_address(0x0000, 0x000A); //uLCD.display_image(50, 45); uLCD.locate(5, 11); uLCD.text_height(1); uLCD.text_width(1); uLCD.color(WHITE); uLCD.printf("%3d BPM", bpm); break; case 3: //Distance //uLCD.media_init(); //uLCD.set_sector_address(0x0000, 0x000F); //uLCD.display_image(50, 45); uLCD.locate(6, 11); uLCD.text_height(1); uLCD.text_width(1); uLCD.color(WHITE); uLCD.printf("%4.2f ft", distance); break; case 4: //Calories //uLCD.media_init(); //uLCD.set_sector_address(0x0000, 0x0000); //uLCD.display_image(50, 45); uLCD.locate(4, 11); uLCD.text_height(1); uLCD.text_width(1); uLCD.color(WHITE); uLCD.printf("%4d cal", (int)calories); break; case 5: //Floors //uLCD.media_init(); //uLCD.set_sector_address(0x0000, 0x0014); //uLCD.display_image(50, 45); uLCD.locate(4, 11); uLCD.text_height(1); uLCD.text_width(1); uLCD.color(WHITE); uLCD.printf("%2d floors", flights); break; } serial_mtx.unlock(); Thread::wait(100); } } void readHR(){ while(1) { bpm = PPG.get_BPM(); //calories = calories + (.0083)*.239*(gender*(-55.0969+.6309*bpm+.1988*weight+.2017*age)+(1-gender)*(-20.4022+.4472*bpm-.1263*weight+.074*age)); calories = calories + (.0083)*0.239*(gender*(-55.0969+.6309*bpm+.1988*0.453592*weight +.2017*age)+(1-gender)*(-20.4022+.4472*bpm-.1263*0.453592*weight+.074*age)); //converted weight from lbs to kilograms //Alternate way to calculate distance (likely more accurate) //distance = distance + (steps - oldSteps)* stride_length; //oldSteps = steps; Thread::wait(500); } } void readBarometer() { while(1) { pressure = scp1000.readPressure(); if(count >= 0) count--; unsigned long dif; if(pressure < p_buff[0]) { dif = p_buff[0] - pressure; } else { dif = 0; } if(pressure != 0 && p_buff[0] != 0 && dif > 40 && dif < 60 && count < 0) { flights++; count = 2; } p_buff[0] = p_buff[1]; p_buff[1] = p_buff[2]; p_buff[2] = p_buff[3]; p_buff[3] = pressure; Thread::wait(2000); } } void readGPS(){ while(1) { serial_mtx.lock(); if(gps.connected()) { if(gps.sample()) { if(gps.ns == 'S') { longitude = gps.longitude*PI/180; } else { longitude = -gps.longitude*PI/180; } if(gps.ew == 'W') { latitude = gps.latitude*PI/180; } else { latitude = -gps.latitude*PI/180; } if(latitude != 0 && longitude != 0 && old_lat != 0 && old_lon != 0) { float a = sinf(old_lat)*sinf(latitude)+cosf(old_lat)*cosf(latitude)*cosf(longitude-old_lon); if(a > 1) a = 1; distance = distance + (.75*acosf(a)); } old_lat = latitude; old_lon = longitude; //pc.printf("%f, %f, %f\r\n", latitude, longitude, distance); } } serial_mtx.unlock(); Thread::wait(10000); } } void saveData() { // Save the data to the usb flash drive and print to the terminal FILE *fp = fopen( "/msc/data.txt", "a"); if(fp == NULL) { error("Could not open file for write\n"); } time_t seconds = time(NULL); char date[32]; strftime(date, 32, "%m/%d/%y", localtime(&seconds)); fprintf(fp, "%s\t%d\t%d\t%0.2f\t%0.2f\n\r", date, steps, flights, calories, distance); pc.printf("%s\t%d\t%d\t%0.2f\t%0.2f\n\r", date, steps, flights, calories, distance); fclose(fp); } int main() { //Set RTC time set_time(1256729737); // Next screen button pb.mode(PullUp); pb.attach_deasserted(&next); pb.setSampleFrequency(); //set up the display uLCD.baudrate(3000000); uLCD.background_color(BLACK); uLCD.cls(); thread1.start(setup_screen); while(setup_state) { pc.printf("%d\r\n", screen); } thread1.terminate(); // Off button pb.attach_deasserted(&button); // set up the display uLCD.cls(); thread1.start(update_screen); thread2.start(display_time); // LED indicates whether or not data is being collected one = 0; two = 0; three = 0; four = 0; // Start sensors int sample_num = 1; PPG.start(); IMU.begin(); IMU.calibrate(1); float ax; float ay; float az; float mag = 0; float buffer[2] = {0}; float avg_buffer[2] = {0}; float avg; // Initialize data file on usb flash drive usb_mtx.lock(); FILE *fp = fopen( "/msc/data.txt", "r+"); if(fp == NULL) { error("Could not open file for write\n"); } //Check to see if file is empty, not working right now fseek (fp, 0, SEEK_END); int size = ftell(fp); if (0 == size) { fprintf(fp, "Date\tSteps\tFloors\tCalories\tDistance (ft)\r\n"); pc.printf("Data.txt rewritten\r\n"); } fclose(fp); usb_mtx.unlock(); thread3.start(readBarometer); thread4.start(readGPS); thread5.start(readHR); usb_timer.start(); while(run) { // Read Sensors IMU.readAccel(); ax = IMU.calcAccel(IMU.ax); ay = IMU.calcAccel(IMU.ay); az = IMU.calcAccel(IMU.az); // Calculate the 3 point moving average of the magnitude of the // acceleration vector mag = sqrt((ax*ax) + (ay*ay) + (az*az)); avg = (buffer[0] + buffer[1] + mag) / 3; buffer[0] = buffer[1]; buffer[1] = mag; // Count a step if the previous point was a maximum (greater than the // current point and 2 points back) and was greater than the threshold // value of 1.05 if(sample_num > 1) { float dif1 = avg_buffer[1] - avg_buffer[0]; float dif2 = avg_buffer[1] - avg; float peak_prominence = 0.01; if(dif1 > peak_prominence && dif2 > peak_prominence) { steps++; } } avg_buffer[0] = avg_buffer[1]; avg_buffer[1] = avg; sample_num++; one = !one; // Sampling rate of ~200 Hz if(usb_timer.read() >= 30) { //pc.printf("Starting USB Write\r\n"); usb_mtx.lock(); saveData(); usb_mtx.unlock(); usb_timer.stop(); usb_timer.reset(); usb_timer.start(); } Thread::wait(200); } one = 0; }