Guides the user to their classes
Dependencies: 4DGL-uLCD-SE Course SDFileSystem mbed PinDetect LSM9DS1_Library_cal MBed_Adafruit-GPS-Library
main.cpp
- Committer:
- nkela6
- Date:
- 2016-12-08
- Revision:
- 13:0eb9fbd63fb2
- Parent:
- 11:e28acc7bf487
- Child:
- 14:d8a6134cafa3
File content as of revision 13:0eb9fbd63fb2:
// Class Scheduler #include "mbed.h" #include "uLCD_4DGL.h" #include <string> #include <vector> #include "Course.h" #include "SDFileSystem.h" #include "MBed_Adafruit_GPS.h" #include "LSM9DS1.h" #include "PinDetect.h" #define PI 3.14159 #define DECLINATION -4.94 // Declination (degrees) in Atlanta,GA. SDFileSystem sd(p5, p6, p7, p8, "sd"); // the pinout on the mbed Cool Components workshop board Serial pc(USBTX, USBRX); uLCD_4DGL uLCD(p13,p14,p15); // serial tx, serial rx, reset pin; PinDetect left(p20); PinDetect right(p18); Serial * gps_Serial; int update; vector<Course> courseVec; void readClassFile(vector<Course>& cVec); int getNextClass(vector<Course>& cVec); void displayCourseVec(); float calculateHeading(float mx, float my), computeAngleToDestination(float diffLat, float diffLong); float longToDecimal(float longitudeInDDMM, char eastOrWest), latToDecimal(float latitudeInDDMM, char northOrSouth); int xEnd, yEnd = 0.0; int currHour, currMinute, currSecond = 0; int hoursToNextClass, minutesToNextClass, secondsToNextClass = 0; int nextClass = 0; int currClass = -1; const int refresh_Time = 1000; //refresh time in ms bool screen_refreshed = false; int volatile current_screen = 0; bool volatile screen_change = false; void timeToNextClass(); float displacement(float diffLat,float diffLong); float calc_eta(float displacement, float speed); bool late(float eta); void left_callback(void) { if (courseVec.size() != 0) { current_screen = (3 + current_screen - 1)%3; screen_change = true; } else current_screen = 0; currClass = -1; uLCD.cls(); } void right_callback(void) { if (courseVec.size() != 0) { current_screen = (3 + current_screen + 1)%3; screen_change = true; } else current_screen = 0; currClass = -1; uLCD.cls(); } int main() { LSM9DS1 IMU(p9, p10, 0xD6, 0x3C); float h = 0.0; float angleToDest = 0.0; IMU.begin(); if (!IMU.begin()) { pc.printf("Failed to communicate with LSM9DS1.\n"); } uLCD.cls(); uLCD.printf("Place IMU flat"); IMU.calibrate(1); uLCD.cls(); uLCD.printf("Rotate IMU 360\ndegrees in \nhorizontal plane"); IMU.calibrateMag(0); left.mode(PullUp); right.mode(PullUp); left.attach_deasserted(&left_callback); right.attach_deasserted(&right_callback); left.setSampleFrequency(); right.setSampleFrequency(); readClassFile(courseVec); gps_Serial = new Serial(p28,p27); //serial object for use w/ GPS Adafruit_GPS myGPS(gps_Serial); //object of Adafruit's GPS class char c; //when read via Adafruit_GPS::read(), the class returns single character stored here Timer refresh_Timer; //sets up a timer for use in loop; how often do we print GPS info? const int refresh_Time = 2000; //refresh time in ms myGPS.begin(9600); //sets baud rate for GPS communication; note this may be changed via Adafruit_GPS::sendCommand(char *) //a list of GPS commands is available at http://www.adafruit.com/datasheets/PMTK_A08.pdf myGPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); //these commands are defined in MBed_Adafruit_GPS.h; a link is provided there for command creation myGPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); myGPS.sendCommand(PGCMD_ANTENNA); float myLat = 33.775991; float myLong = -84.397128; float destinationLat = courseVec[1].getLat(); float destinationLong = courseVec[1].getLong(); screen_change = true; pc.baud(9600); c = myGPS.read(); //queries the GPS currHour = myGPS.hour - 5; //for eastern time zone if (currHour < 0) currHour += 24; currMinute = myGPS.minute; currSecond = myGPS.seconds; nextClass = getNextClass(courseVec); refresh_Timer.start(); //starts the clock on the timer while(1) { c = myGPS.read(); //queries the GPS //if (c) { pc.printf("%c", c); } //this line will echo the GPS data if not paused //check if we recieved a new message from GPS, if so, attempt to parse it, if ( myGPS.newNMEAreceived() ) { if ( !myGPS.parse(myGPS.lastNMEA()) ) { continue; } } if (refresh_Timer.read_ms() >= refresh_Time) { refresh_Timer.reset(); if (myGPS.fix) { myLat = latToDecimal(myGPS.latitude, myGPS.lat); myLong = longToDecimal(myGPS.longitude, myGPS.lon); } currHour = myGPS.hour - 5; //for eastern time zone if (currHour < 0) currHour += 24; currMinute = myGPS.minute; currSecond = myGPS.seconds; nextClass = getNextClass(courseVec); timeToNextClass(); destinationLat = courseVec[nextClass].getLat(); destinationLong = courseVec[nextClass].getLong(); float diffLat = destinationLat - myLat; float diffLong = destinationLong - myLong; float dis = displacement(diffLat,diffLong); float speed = 3.1; //mph. Source:https://lmgtfy.com/?q=average+human+walking+speed float eta = calc_eta(dis,speed)*60;//(miles, mph)*60 if(late(eta)==1) { uLCD.background_color(RED); uLCD.text_mode(TRANSPARENT); } else { uLCD.background_color(BLACK); uLCD.text_mode(TRANSPARENT); } switch(current_screen) { case 0: wait(.2); if (screen_change) { displayCourseVec(); screen_change = false; } break; case 1: IMU.readMag(); h = calculateHeading(IMU.calcMag(IMU.mx), IMU.calcMag(IMU.my)); pc.printf("Heading: %f\n", h); angleToDest = computeAngleToDestination(diffLat, diffLong); h = angleToDest - h; h = h - 90; if (h < 0) h = h + 360; if (h > 360) h = h - 360; xEnd = 0; yEnd = 0; float rads = 0.0; //uLCD.cls(); if (h < 90) { rads = h * PI / 180; xEnd = floor(63 * sin(rads) + .5); yEnd = floor(63 * cos(rads) + .5); xEnd = 63 + xEnd; yEnd = 63 + yEnd; } else if (90 < h < 180) { h = h - 90; rads = h * PI / 180; xEnd = floor(63 * cos(rads) + .5); yEnd = floor(63 * sin(rads) + .5); xEnd = 63 + xEnd; yEnd = 63 - yEnd; } else if (180 < h < 270) { h = h - 180; rads = h * PI / 180; xEnd = floor(63 * sin(rads) + .5); yEnd = floor(63 * cos(rads) + .5); xEnd = 63 - xEnd; yEnd = 63 - yEnd; } else if (270 < h) { h = h - 270; rads = h * PI / 180; xEnd = floor(63 * cos(rads) + .5); yEnd = floor(63 * sin(rads) + .5); xEnd = 63 - xEnd; yEnd = 63 + yEnd; } uLCD.cls(); uLCD.line(63, 63, xEnd, yEnd, WHITE); break; case 2: //uLCD.cls(); uLCD.locate(0,2); uLCD.printf(" "); uLCD.locate(0,3); uLCD.printf("Time to next class"); uLCD.locate(0, 4); uLCD.printf("%02dhrs %02dminutes", hoursToNextClass, minutesToNextClass); uLCD.locate(0, 5); uLCD.printf("%02dseconds", secondsToNextClass); uLCD.locate(0, 0); uLCD.printf("Next class "); if (nextClass != currClass) { uLCD.locate(0, 1); uLCD.printf(" "); uLCD.locate(0, 1); uLCD.printf("%s", courseVec[nextClass].getDisplayString()); } currClass = nextClass; break; } } } } void readClassFile(vector<Course>& cVec) { cVec.clear(); FILE *readFp = fopen("/sd/classdir/classes.txt", "r"); char line[15]; char buildingBuf[4]; char hourBuf[3]; int hour; char minuteBuf[3]; int minute; char ampmBuf[3]; uLCD.cls(); uLCD.locate(0, 1); uLCD.printf("Reading class file..."); memset(buildingBuf, 0, sizeof(buildingBuf)); memset(hourBuf, 0, sizeof(hourBuf)); memset(minuteBuf, 0, sizeof(minuteBuf)); memset(ampmBuf, 0, sizeof(ampmBuf)); memset(line, 0, sizeof(line)); if (readFp == NULL) return; else { while (!feof(readFp)) { fgets(line, 15, readFp); if(line[8] == NULL) continue; memcpy(buildingBuf, line, 3); memcpy(hourBuf, &line[4], 2); memcpy(minuteBuf, &line[7], 2); memcpy(ampmBuf, &line[10], 2); string building = buildingBuf; hour = atoi(hourBuf); minute = atoi(minuteBuf); string ampm = ampmBuf; Course temp(building, hour, minute, ampm); cVec.push_back(temp); } } fclose(readFp); return; } void displayCourseVec() { if (courseVec.size() == 0) { uLCD.cls(); uLCD.locate(0,0); uLCD.printf("No classes input!"); uLCD.locate(0,1); } else { uLCD.cls(); uLCD.locate(0,1); for (int i = 0; i < courseVec.size(); i++) { uLCD.locate(0, i); uLCD.printf("%s", courseVec[i].getDisplayString()); } } } float calculateHeading(float mx, float my) { float heading = 0.0; if (my == 0.0) heading = (mx < 0.0) ? 180.0 : 0.0; else heading = atan2(mx, my)*360.0/(2.0*PI); //pc.printf("heading atan=%f \n\r",heading); heading -= DECLINATION; //correct for geo location if(heading>180.0) heading = heading - 360.0; else if(heading<-180.0) heading = 360.0 + heading; else if(heading<0.0) heading = 360.0 + heading; // Convert everything from radians to degrees: //heading *= 180.0 / PI; //pc.printf("Magnetic Heading: %f degress\n\r",heading); return heading; } float computeAngleToDestination(float diffLat, float diffLong) { float angle = 0.0; if (diffLat > 0) { if (diffLong > 0) { // in quadrant 1 angle = 180*atan2(diffLat,diffLong)/PI; } else { // in quadrant 2 angle = 180*atan2(diffLat,-1 * diffLong)/PI; angle = 180 - angle; } } else { if (diffLong > 0) { // in quadrant 4 angle = 180*atan2(-1*diffLat, diffLong)/PI; angle = 360 - angle; } else { // in quadrant 3 angle = 180*atan2(-1*diffLat, -1*diffLong)/PI; angle = 180 + angle; } } //pc.printf("Angle to Destination: %f degress\n\r",angle); return angle; } int getNextClass(vector<Course>& cVec) { int numIterations = 0; for (int i = 0; i < cVec.size(); i++) { numIterations++; pc.printf("Iteration : %i\ncurrHour: %i\ncourseHour: %i\n", numIterations, currHour, cVec[i].getHour_inMilitaryTime()); if (courseVec[i].getHour_inMilitaryTime() < currHour) continue; else if (courseVec[i].getHour_inMilitaryTime() > currHour) return i; else if (courseVec[i].getHour_inMilitaryTime() == currHour) { if (courseVec[i].getMinute() <= currMinute) continue; else if (courseVec[i].getMinute() > currMinute) { return i; } } if (numIterations == cVec.size()) return 0; } return 0; } void timeToNextClass() { hoursToNextClass = courseVec[nextClass].getHour_inMilitaryTime() - currHour; if (hoursToNextClass < 0) hoursToNextClass += 24; minutesToNextClass = courseVec[nextClass].getMinute() - currMinute; if (minutesToNextClass < 0) { hoursToNextClass--; minutesToNextClass += 60; } secondsToNextClass = 60 - currSecond; minutesToNextClass--; if (minutesToNextClass < 0) { hoursToNextClass--; minutesToNextClass += 60; } if (hoursToNextClass < 0) hoursToNextClass += 24; } // convert from DDMM.mmmm to decimal float latToDecimal(float latitudeInDDMM, char northOrSouth) { float latInDec = 0.0; float temp = 0.0; latInDec = latitudeInDDMM / 100; temp = latInDec - floor(latInDec); temp = temp / .6; latInDec = floor(latInDec) + temp; if (northOrSouth == 'S') return -1 * latInDec; return latInDec; } float displacement(float diffLat,float diffLong) { d = sqrt(diffLat*diffLat+diffLong*diffLong); return d; } float calc_eta(float displacement, float speed) { float eta = displacement/speed; // for displacement. take average speed // convert to minutes later eta = eta+ 0.25*eta; //adding delay for distance vs displacement and traffic lights return eta; float longToDecimal(float longitudeInDDMM, char eastOrWest) { float longInDec = 0.0; float temp = 0.0; longInDec = longitudeInDDMM / 100; temp = longInDec - floor(longInDec); temp = temp / .6; longInDec = floor(longInDec) + temp; if (eastOrWest == 'E') return longInDec; return -1 * longInDec; } bool late(float eta) { float totalMinutes = hoursToNextClass*60+ minutesToNextClass+ secondsToNextClass/60; if(totalMinutes>eta) { return 1; } else { return 0; } }