Mbed project to control a hoverboard

Dependencies:   mbed wave_player Servo 4DGL-uLCD-SE LSM9DS1_Library_cal HC_SR04_Ultrasonic_Library

main.cpp

Committer:
msafwan3
Date:
2020-04-29
Revision:
3:bf0c46975248
Parent:
2:726636c1c83c

File content as of revision 3:bf0c46975248:

#include "mbed.h"
#include "wave_player.h"
#include "SDFileSystem.h"
#include "Servo.h"
#include "ultrasonic.h"
#include "uLCD_4DGL.h"
#include "LSM9DS1.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);


Servo dcmotorBottom(p21); // pwm
Servo servoBottom(p23); // pwm
Servo dcmotorBack(p22); // 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);
DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);
DigitalOut exled1(p19);
DigitalOut exled2(p26);


// 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;
    wait(0.5); //ESC detects signal
    //Required ESC Calibration/Arming sequence  
    //sends longest and shortest PWM pulse to learn and arm at power on
    dcmotorBottom = 1.0; //send longest PWM
    dcmotorBack = 1.0; //send longest PWM
    wait(8);
    dcmotorBottom = 0.0; //send shortest PWM
    dcmotorBack = 0.0; //send shortest PWM
    wait(8);
}


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);
//have updates every .1 seconds and a timeout after 1
//second, and call dist when the distance changes

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;
}



int main()
{   
    uLCD.reset();
    //calibrate motors
    servoBottom.calibrate(range, position);
    col_ESC();
    
    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();
        // 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);
                }
            }
            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++;
                
            }
             
        }
        
    }
}