Mbed project to control a hoverboard
Dependencies: mbed wave_player Servo 4DGL-uLCD-SE LSM9DS1_Library_cal HC_SR04_Ultrasonic_Library
Diff: main.cpp
- Revision:
- 2:726636c1c83c
- Parent:
- 1:de52879ff5ec
--- a/main.cpp Wed Apr 29 08:33:11 2020 +0000 +++ b/main.cpp Wed Apr 29 22:40:56 2020 +0000 @@ -5,27 +5,64 @@ #include "ultrasonic.h" #include "uLCD_4DGL.h" #include "LSM9DS1.h" -#include "rtos.h" + +volatile bool global_running = true; //1 = display distance, 0 = avoid collision +float range = 0.0005; // for servo/motors calibration +float position = 0.5; // for servo/motors calibration +unsigned int frame_limiter = 0; // Limits the framerate of the lcd Serial pc(USBTX, USBRX); uLCD_4DGL uLCD(p13,p14,p11); // serial tx, serial rx, reset pin; +LSM9DS1 IMU(p9, p10, 0xD6, 0x3C); -DigitalOut led1(p26); -DigitalOut led2(p19); -LSM9DS1 IMU(p9, p10, 0xD6, 0x3C); + Servo dcmotorBottom(p21); // pwm +Servo servoBottom(p23); // pwm Servo dcmotorBack(p22); // pwm -Servo servoBottom(p23); // pwm + +// Setup to play wav file from SD Card AnalogOut DACout(p18); wave_player waver(&DACout); SDFileSystem sd(p5, p6, p7, p8, "sd"); //SD card + +// Setup for bluetooth Serial blue(p28,p27); -BusOut myleds(LED1,LED2,LED3,LED4); +DigitalOut myled1(LED1); +DigitalOut myled2(LED2); +DigitalOut myled3(LED3); +DigitalOut myled4(LED4); +DigitalOut exled1(p19); +DigitalOut exled2(p26); + -char bnum=0;//for blue -Mutex my_mutex; -int dist_flag = 0; +// Setup for IMU +#define PI 3.14159 +// Earth's magnetic field varies by location. Add or subtract +// a declination to get a more accurate heading. Calculate +// your's here: +// http://www.ngdc.noaa.gov/geomag-web/#declination +#define DECLINATION -4.94*PI/180 // Declination (radians) in Atlanta,GA. +// Calculate heading. +// Heading calculations taken from this app note: +// http://www51.honeywell.com/aero/common/documents/myaerospacecatalog-documents/Defense_Brochures-documents/Magnetic__Literature_Application_notes-documents/AN203_Compass_Heading_Using_Magnetometers.pdf +float calculateHeading(float mx, float my) +{ +// touchy trig stuff to use arctan to get compass heading + mx = -mx; + float heading; + if (my == 0.0) + heading = (mx < 0.0) ? PI : 0.0; + else + heading = atan2(mx, my); + //pc.printf("heading atan=%f \n\r",heading); + heading -= DECLINATION; //correct for geo location + if(heading>PI) heading = heading - 2*PI; + else if(heading<-PI) heading = 2*PI + heading; + else if(heading<0.0) heading = 2*PI + heading; + return heading; +} +// ESC/ Brushless DC Motor setup void col_ESC() { dcmotorBottom = 0.0; dcmotorBack = 0.0; @@ -40,215 +77,229 @@ wait(8); } - void dist(int distance) -{ - while(1){ - //put code here to execute when the distance has changed - printf("Distance %d mm\r\n", distance); - if(distance <50){ - dist_flag=1; + +void dist(int distance) +{ + // Set global running flag based on distance to sonar + if(distance < 100){ + global_running = false; + } + else{ + if (global_running == false){ + global_running = true; + // Wait 2 seconds before starting again + //wait(2); } } + // If there is an obstruction, print the distance until it is clear + if(!global_running){ + // Only update once every 4 loops + if (frame_limiter % 2 == 0){ + uLCD.cls(); + uLCD.printf("Distance:\r\n%dmm\r\n", distance); //print to uLCD + } + frame_limiter++; + } + } -ultrasonic mu(p15, p16, .1, 1, &dist); //sonar -#define PI 3.14159 -#define DECLINATION -4.94 // Declination (degrees) in Atlanta,GA. -double x2; -double y2; -int x_c; -int y_c; -int r; -int z; -float printAttitude(float ax, float ay, float az, float mx, float my, float mz) -{ - float roll = atan2(ay, az); - float pitch = atan2(-ax, sqrt(ay * ay + az * az)); -// touchy trig stuff to use arctan to get compass heading (scale is 0..360) - mx = -mx; - float heading; - 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; - +ultrasonic mu(p15, p16, .1, 1, &dist); +//have updates every .1 seconds and a timeout after 1 +//second, and call dist when the distance changes - // Convert everything from radians to degrees: - //heading *= 180.0 / PI; - pitch *= 180.0 / PI; - roll *= 180.0 / PI; - - pc.printf("Pitch: %f, Roll: %f degress\n\r",pitch,roll); - pc.printf("Magnetic Heading: %f degress\n\r",heading); - return heading; -} - -void display_compass() -{ - while(!IMU.tempAvailable()); - IMU.readTemp(); - while(!IMU.magAvailable(X_AXIS)); - IMU.readMag(); - while(!IMU.accelAvailable()); - IMU.readAccel(); - while(!IMU.gyroAvailable()); - IMU.readGyro(); - pc.printf("\nIMU Temperature = %f C\n\r",25.0 + IMU.temperature/16.0); - pc.printf(" X axis Y axis Z axis\n\r"); - pc.printf("gyro: %9f %9f %9f in deg/s\n\r", IMU.calcGyro(IMU.gx), IMU.calcGyro(IMU.gy), IMU.calcGyro(IMU.gz)); - pc.printf("accel: %9f %9f %9f in Gs\n\r", IMU.calcAccel(IMU.ax), IMU.calcAccel(IMU.ay), IMU.calcAccel(IMU.az)); - pc.printf("mag: %9f %9f %9f in gauss\n\r", IMU.calcMag(IMU.mx), IMU.calcMag(IMU.my), IMU.calcMag(IMU.mz)); - float heading = printAttitude(IMU.calcAccel(IMU.ax), IMU.calcAccel(IMU.ay), IMU.calcAccel(IMU.az), IMU.calcMag(IMU.mx), - IMU.calcMag(IMU.my), IMU.calcMag(IMU.mz)); - double a = heading * 0.0174533; //deg to rad - x2 = x_c + r*cos(a); - y2 = y_c + r*sin(a); - uLCD.cls(); - uLCD.circle(x_c, y_c, r, WHITE); - uLCD.line(x_c, y_c, (int)x2, (int)y2, BLUE); - wait(0.001); +void honk(){ + FILE *wave_file; + wave_file=fopen("/sd/honk.wav","r"); + waver.play(wave_file); + fclose(wave_file); + myled1=!myled1; + myled2=!myled2; + myled3=!myled3; + myled4=!myled4; } -void IMU_fun(void const *args){//thread 1 - x_c = 60; - y_c = 60; - r = 30; - uLCD.circle(x_c, y_c, r, WHITE); - z = 0; - x2 = x_c + r*cos((double)z); - y2 = x_c + r*sin((double)z); - uLCD.line(x_c, y_c, (int)x2, (int)y2, BLUE); - - IMU.begin(); - if (!IMU.begin()) { - pc.printf("Failed to communicate with LSM9DS1.\n"); - } - IMU.calibrate(1); - IMU.calibrateMag(0); - while(1){ - if(dist_flag==0){ - display_compass(); - } - - } -} -void dcmotorBottom_fun(void const *args){//thread2 - while (1) { - if(dist_flag ==0){ - for (float p=0.0; p<=0.9; p += 0.05) { //Throttle up slowly to full throttle - dcmotorBottom = p; - wait(1.0); - } - } - if(dist_flag ==1){ - for (float p=0.9; p>=0.0; p -= 0.05) { //Throttle down slowly from full throttle - dcmotorBottom = p; - wait(1.0); - } - } - } -} -void dist_flag1(void const *args){//thread3 - while(1) { - if(dist_flag==1){ - for(int i=0; i<4; ++i) { - //open wav file and play it - FILE *wave_file; - printf("\n\n\nHello, wave world!\n"); - wave_file=fopen("/sd/beep.wav","r"); - waver.play(wave_file); - fclose(wave_file); - Thread::wait(1925); - } - led1 =!led1; - led2 =!led2; - wait(0.25); - } - - - }//while -}//fun - -void Blue_control(void const *args){//thread4 - float servo_p = 0.5; - while(1) { - if(bnum=='1'){ - dist_flag =0; - } - if(dist_flag==0){ - if(bnum =='2'){ - for(int i=0; i<4; ++i) { - //open wav file and play it - FILE *wave_file; - printf("\n\n\nHello, wave world!\n"); - wave_file=fopen("/sd/honk.wav","r"); - waver.play(wave_file); - fclose(wave_file); - Thread::wait(1925); - } - } - if(bnum=='3'){ - led1 =!led1; - led2 =!led2; - } - if(bnum=='5'){ - for (float p=0.0; p<=0.3; p += 0.025) { //Throttle up slowly to full throttle - dcmotorBack = p; - wait(1.0); - } - } - if(bnum=='6'){ - for (float p=0.3; p>=0.3; p -= 0.025) { //Throttle dowm slowly from full throttle - dcmotorBack = p; - wait(1.0); - } - } - if(bnum=='7' && servo_p>0.0){ - servo_p = servo_p+0.05; - servoBottom = servo_p; - } - if(bnum=='8' && servo_p<1.0){ - servo_p = servo_p-0.05; - servoBottom = servo_p; - } - } - - }//while(1) -}//func - - -int main()//thread5 -{ - mu.startUpdates();//start measuring the distance +int main() +{ + uLCD.reset(); + //calibrate motors + servoBottom.calibrate(range, position); col_ESC(); - led1=0; - led2=0; - Thread t1(IMU_fun); //start thread1 - Thread t2(dcmotorBottom_fun); //start thread2 - Thread t3(dist_flag1); //start thread2 - Thread t4(Blue_control); //start thread2 - char bhit=0;//for blue - while(1) - { + + Ticker honk_int; + + char bnum = 0; + char bhit = 0; + float speed = 0.3; + uLCD.baudrate(BAUD_3000000); //jack up baud rate to max for fast display + wait(0.5); + + IMU.begin(); + if (!IMU.begin()) { + // red circle of death + uLCD.circle(63,63, 51, RED); + } + IMU.calibrate(1); + uLCD.cls(); + uLCD.printf("Calibrating:\r\nSpin Me!\r\n"); //print to uLCD + IMU.calibrateMag(0); + uLCD.cls(); + + int x=0; + int y=50; + mu.startUpdates();//start measuring the distance + bool start_motor = true; + bool moving = false; + + + while(1) + { + // Check for collision mu.checkDistance(); - my_mutex.lock(); - if (blue.getc()=='!') { - if (blue.getc()=='B') { //button data packet - bnum = blue.getc(); //button number - bhit = blue.getc(); //1=hit, 0=release - if (blue.getc()==char(~('!' + 'B' + bnum + bhit))) { //checksum OK? - my_mutex.unlock(); - myleds = bnum - '0'; //current button number will appear on LEDs - - } + // If the motor is stopped and there are no collisions, start the motor + if (global_running && start_motor){ + for (float p=0.0; p<=0.9; p += 0.1) { //Throttle up slowly to full throttle + dcmotorBottom = p; + wait(0.2); + } + // Draw the circle for the compass on the LCD + uLCD.cls(); + uLCD.circle(63,63, 51, WHITE); + start_motor = false; + + } + if (global_running){ + // Update the compass reading + // Only update once every 150000 loops + if (frame_limiter % 100000 == 0){ + if(IMU.magAvailable(X_AXIS)){ + IMU.readMag(); + int prev_x = x; + int prev_y = y; + float heading = calculateHeading(IMU.mx, IMU.my); + x = 63+50*sin(heading+PI)+ 0.5; + y = 63+50*cos(heading+PI)+ 0.5; + uLCD.line(63, 63, prev_x, prev_y, BLACK); + uLCD.line(63, 63, x, y, RED); + uLCD.printf("%.2f\r", heading*180/PI); } } - }//for while(1) -}//for int main() + frame_limiter++; + // Read bluetooth controller input + if (blue.readable()){ + if (blue.getc() == '!') { + if (blue.getc() == 'B') { //button data packet + bnum = blue.getc(); //button number + bhit = blue.getc(); //1=hit, 0=release + if (blue.getc() == char(~('!' + 'B' + bnum + bhit))) { //checksum OK? + switch (bnum) { + case '1': //number button 1: Increase max speed + if (bhit=='1') { + //add hit code here + if(speed < 0.3){ + speed = speed + 0.06; + } + } else { + // When button is released, set rear motor to max speed + // if it is currently running + if(moving) dcmotorBack = speed; + } + break; + case '2': //number button 2: Decrease max speed + if (bhit=='1') { + //add hit code here + if(speed > 0.06){ + speed = speed - 0.06; + } + } else { + // When button is released, set rear motor to max speed + // if it is currently running + if(moving) dcmotorBack = speed; + } + break; + case '3': //number button 3: light the external leds + if (bhit=='1') { + exled1 = !exled1; + exled2 = !exled2; + } else { + //add release code here + } + break; + case '4': //number button 4: play honking sound + if (bhit=='1') { + honk(); + } else { + //add release code here + } + break; + case '5': //button 5 up arrow: turn on bottom servo and back motor + if (bhit=='1') { + //add hit code here + for (float p=0.0; p<=speed; p += 0.06) { //Throttle up slowly to full throttle + dcmotorBack = p; + wait(0.2); + } + moving = true; + + } else { + //add release code here + dcmotorBack = 0.0; + moving = false; + } + break; + case '6': //button 6 down arrow: switch it off (turn off back motor) + if (bhit=='1') { + + } else { + //add release code here + } + break; + case '7': //button 7 left arrow: turns servo leftwards + if (bhit=='1') { + servoBottom = 1.0; + } else { + //add release code here + servoBottom = 0.5; + } + break; + case '8': //button 8 right arrow: turns servo rightwards + if (bhit=='1') { + servoBottom = 0.0; + } else { + //add release code here + servoBottom = 0.5; + } + break; + default: + break; + } + } + } + }// End of bluetooth controller loop + } + } + else + { + // Collision detection: Stop all motors and honk until obstruction is cleared + dcmotorBack = 0.0; + dcmotorBottom = 0.0; + servoBottom = 0.5; + start_motor = true; + moving = false; + unsigned int honk_limiter = 0; + while(!global_running){ + // Check if the obstruction is clear + mu.checkDistance(); + // Honk every once in a while + if(honk_limiter % 6000000 == 0){ + honk(); + } + honk_limiter++; + + } + + } + + } +} \ No newline at end of file