Xbeat beta code as published by Andre Moehl ( http://mbed.org/users/hoppel/ ) With a slightly modified serial port definition

Dependencies:   mbed

main.cpp

Committer:
n0p
Date:
2011-02-04
Revision:
0:badcd0d61c7b

File content as of revision 0:badcd0d61c7b:

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @file  main.c
 * @author     andre moehl
 * @date   01/2011
 *
 *
 * Implements the main functionalty and als programs for the XBeat.
 */

/*--- Includes ------------------------------*/
#include "mbed.h"
#include "SRF05.h"
#include "drive.h"
#include "button.h"


/*--- Defines -------------------------------*/
#define DEBUG 1

#define TTLSERIAL 1 //use the ttl(p13,p14) serial port or the native USB serial port if 0
#define BAUDRATE 19200

#define OFF 0
#define ON 1

// Battery measure
#define UBAT_R_FACTOR 3.1363636 //resistor divider
//#define UBAT_LOW 66       //6,6V 
#define UBAT_LOW 72         //7,2V - more adequate value to protect lipos


// Servo Zero Position Offset
#define OFFSET_L -35
#define OFFSET_R 45



/*--- Global Variables ----------------------*/
/* Hardware Definitions */
DigitalOut led1(LED1);      ///< Leds on mbed board
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
DigitalOut Speaker(p12);    ///< Loudspeaker
AnalogIn   ubat(p15);       ///< LiPo Voltage Measurement
DigitalOut T6(p29);         ///< FET for Bottom IR-LEDs
DigitalOut T7(p30);         ///< FET for Side IR-LEDs
AnalogIn   IRL(p16);        ///< IR-Transistor Bottom Left
AnalogIn   IRM(p17);        ///< IR-Transistor Bottom Middle
AnalogIn   IRR(p18);        ///< IR-Transistor Bottom Right
AnalogIn Left(p19);         ///< IR-Transistor Left Side
AnalogIn Right(p20);        ///< IR-Transistor Right Side
Button SW1(p10);            ///< Button Outer Side
Button SW2(p9);             ///< Button Inner Side

#ifdef TTLSERIAL
Serial pc (p13,p14);        ///< Serial Interface via TTL Port
#else
Serial pc(USBTX, USBRX);  ///< Serial Intervace via USB Port (tx, rx)
#endif

/** Timer and Tickers */
Ticker LiPoTicker;  //ticker for checking LiPoVoltage
Ticker tick_1ms;    //Ticker for checking Button

/*--- Flags ---------------------------------*/

int SW1_state=0;    // Current State of SW1
int SW1_old=0;      // Previous State of SW1
int SW2_state=0;    // Current State of SW2
int SW2_old=0;      // Previous State of SW2
int start=0;        // indicate to start a program
int stop=1;         // indicate to stop a program
int programm_counter=1; // Counts the number of SW2 samples to select a program
uint8_t firstUnderVoltage;  // set to 1 when the battery measure is first time under the limit


/**--- predeclarared Functions --------------*/
void setLed(int led);
float getLiPoVoltage();

/**--- Functions ----------------------------*/

////// PROGRAMM LINE FOLLOW ///////////////////////////////////////////

#define LFDUTYCYCLE 0.001
/**
* @brief Programm LineFollow follows lines on paper. Uses the IR-Transistors to detect.
* @parameter mode Fast or Slow
*/
void LineFollow() {
    Drive XBeat(p21,p22);                                       //Left, Right Servo Motor
    int i;
    int ML=0, MR=0;                                             //Motor set-points
    int MaxSpeed=0;                                             ///< Maximum Speed in Percent
    unsigned short left=0, right=0, mid=0;                      // current measured values
    unsigned short  soll_left=0, soll_right=0, soll_mid=0;      // must values
    signed int error_r=0,error_l=0,error_m=0;                   // setpoint errors
    signed int prev_error_r=0, prev_error_l=0, prev_error_m=0;  // previous setpoint errors
    signed int dmeas_r=0, dmeas_l=0, dmeas_m=0;                 // derive error
    signed int pid_r=0, pid_l=0, pid_m=0;                       // calced controller values


    MaxSpeed = 100;                                             //Set Maximum Line Follow Speed

    pc.printf("Program \"Line Follow\"\n\r\n\r");
    XBeat.setoffset(OFFSET_L,OFFSET_R);
    T6 = ON; //switch IR-Leds on

    //read values for calc the set point values
    soll_left = IRL.read_u16()/100;
    soll_right = IRM.read_u16()/100;
    soll_mid = IRM.read_u16()/100;
    for (i=30;i>0;i--) {
        soll_left = (soll_left + IRL.read_u16()/100)/2;
        soll_right = (soll_right + IRR.read_u16()/100)/2;
        soll_mid = (soll_mid + IRM.read_u16()/100)/2;
    }
    //debug
    pc.printf("Sollwert Links: %d\n\r", soll_left);
    pc.printf("Sollwert Rechts: %d\n\r", soll_right);
    wait(2);
    //peep
    Speaker = 1;
    wait (0.1);
    Speaker = 0;
    //acceleration
    int ms = 500/MaxSpeed;
    for (i=0; i<MaxSpeed; i+=2) {
        XBeat.move(i,i);
        wait_ms(ms);
    }

    //drive until pressing stop button
    while (!stop) {
        //set SetPoint
        MR = MaxSpeed;
        ML = MaxSpeed;

        //get sensor data
        left = IRL.read_u16()/100;
        right = IRR.read_u16()/100;
        mid = IRM.read_u16()/100;

        //calc controller (PD)
        error_l = soll_left - left;
        dmeas_l = (error_l - prev_error_l)/2;
        prev_error_l = error_l;
        error_r = soll_right - right;
        dmeas_r = (error_r - prev_error_r)/2;
        prev_error_r = error_r;
        error_m = soll_mid - mid;
        dmeas_m = (error_m - prev_error_m)/2;
        prev_error_m = error_m;

        pid_l = (2*error_l + dmeas_l)/20;
        pid_r = (2*error_r + dmeas_r)/20;
        pid_m = (2*error_m + dmeas_m)/10;

        //Limit controller output
        if (pid_l >= MaxSpeed) pid_l = MaxSpeed;
        if (pid_l <= -MaxSpeed) pid_l = -MaxSpeed;
        if (pid_r >= MaxSpeed) pid_r = MaxSpeed;
        if (pid_r <= -MaxSpeed) pid_r = -MaxSpeed;
        //debug
        pc.printf("pidL %d, pidR%d\n\r", pid_l, pid_r);

        if (pid_l > 2) ML = ML + pid_m;
        if (pid_r > 2) MR = MR + pid_m;

        ML = ML - pid_l;// - pid_r/2;
        MR = MR - pid_r;// - pid_l/2;
        if (ML > MaxSpeed) {
            ML = MaxSpeed;
            MR = MR + pid_l;
        }
        if (MR > MaxSpeed) {
            MR = MaxSpeed;
            ML = ML + pid_r;
        }
        //Bottom Limit Motor values
        if (ML < -10) ML = -10;
        if (MR < -10) MR = -10;

        pc.printf("ML %d, MR%d\n\r", ML, MR);

        //set Motor values
        XBeat.move(ML, MR); //set motor speed
        wait(LFDUTYCYCLE);
    }
    //Finished
    T6 = OFF;
    start = 0;
    stop = 1;
    pc.printf("Program \"Line Follow\" stopped\n\r");
}

////// PROGRAMM REMOTE CONTROL //////////////////////////////////////////

/**
* @brief Control the XBeat via remote
*/
void RemoteControl() {
    Drive XBeat(p22,p21);       //Left, Right Servo Motor
    pc.printf("Program \"Remote Control\" started\n\r");
    XBeat.setoffset(OFFSET_L,OFFSET_R);
    pc.printf("Currently not implemented.\n\r");
    start = 0;
    stop = 1;
    pc.printf("Program \"Remote Control\" stopped\n\r");
}


////// PROGRAMM MAZE SOLVER /////////////////////////////////////////////

#define MAZE_SPEED 60
#define MAZEDUTYCYCLE 0.01
/**
 * @brief drives the XBeat thru a maze
 * made for 27C3 Maze Logo
 */
void MazeSolver() {
    Drive XBeat(p22,p21);       //Left, Right Servo Motor
    pc.printf("Program \"Maze Solver\" started\n\r");
    XBeat.setoffset(OFFSET_L,OFFSET_R);
    pc.printf("The Implementation is currently not finished. I working on it and release this later.\n\r");
    start = 0;
    stop = 1;
    pc.printf("Program \"Maze Solver\" stopped\n\r");
}

///// PROGRAMM DRIVE AND TURN /////////////////////////////////////////////

void driver() {
    SRF05 srf(p6, p5);          // Front Sensor
    Drive XBeat(p21,p22);       // Left, Right Servo Motor
    signed int m1=0,m2=0;       // Motor Set values
    float front=0, front_old=0; // measured value from front sensor
    int turn=0;                 // flag for indicate a turn
    int ticks=0;                // loop counter for turn

    pc.printf("\n\rJust Moving\n\r\n\r");
    XBeat.setoffset(OFFSET_L,OFFSET_R);

    while (!stop) {
        if (!turn) {
            if ((front < front_old) && (front > 8.0)) { //close to a front wall, slow stopping
                if (m1 < 0) m1 = m1-1;
                if (m2 < 0) m2 = m2-1;
                pc.printf("1\n\r");
            } else {
                if (m1 < 100) m1++;
                if (m2 < 100) m2++;
            }
            front_old = front;
        }

        if (turn) {
            ticks++;
            if (ticks <= 300) {
                if (m1 < 50) m1++;
                if (m2 > -50) m2--;
            } else {
                if (m1 >= 0) m1--;
                if (m2 <= 0) m2++;
                if (m1 == 0 || m2 == 0) {
                    turn=0;
                    ticks=0;
                }
            }
        }

        if (front < 8.0 && !turn) {
            m1=0;
            m2=0;
            turn=1;
            ticks=0;
        }
        XBeat.move(m1,m2);
    }
    start = 0;
    stop = 1;
    pc.printf("Program \"Driving\" stopped\n\r");
}


/////// Sensor Data ///////////////////////////////////////////////////////

/**
*   @brief Writing Sensor Data to UART, for debugging purpose
*/
void SensorData() {
    SRF05 srf(p6, p5);
    T6 = ON;
    T7 = ON;
    pc.printf("Sensor Data\n\r\n\r");
    while (!stop) {
        pc.printf("IR-Left %d, IR-Right %d, SRF05 %f\n\r", Left.read_u16()/100, Right.read_u16()/100, srf.read());
        pc.printf("IRL %d, IRM %d, IRR %d\n\r", IRL.read_u16()/100, IRM.read_u16()/100, IRR.read_u16()/100);
        pc.printf("LiPo Voltage %f\n\r\n\r", getLiPoVoltage() );
        wait (1);
    }
    T7 = OFF;
    T6 = OFF;
    start = 0;
    stop = 1;
}


/////// RECALLED FUNCTIONS ////////////////////////////////////
/**
 * @brief function called ervery 1ms to read the button states
 */
void checkButtons () {
    //int c=0;
    if (SW1) {
        SW1_state = 1;
    } else SW1_state = 0;
    if (SW1_old == 1 && SW1_state == 0) {       //falling edge
        /** Add Code to do when Button 1 is pressed */
        start = !start;
        stop = !start;
    }
    SW1_old = SW1_state;

    if (SW2) SW2_state = 1;
    else SW2_state = 0;
    if (SW2_old == 1 && SW2_state == 0) {       //falling edge
        /** Add Code to do when Button 2 is pressed */
        if (stop) {
            if (programm_counter < 5) programm_counter++;
            else programm_counter = 1;

            switch (programm_counter) {
                case 1:
                    pc.printf("Programm %d:  Line Follow\n\r", programm_counter );
                    break;
                case 2:
                    pc.printf("Programm %d:  Maze Solver\n\r", programm_counter );
                    break;
                case 3:
                    pc.printf("Programm %d:  Driving\n\r", programm_counter );
                    break;
                case 4:
                    pc.printf("Programm %d:  Remote Control\n\r", programm_counter );
                    break;
                case 5:
                    pc.printf("Programm %d:  Sensor Data\n\r", programm_counter );
                    break;
            }
            if (programm_counter == 5) {
                led1=1;
                led4=1;
            } else    setLed(programm_counter);
        }
    }
    SW2_old = SW2_state;
}



/** @brief calculates the battery voltage
*   @return real voltage als float */
float getLiPoVoltage() {
    return ((ubat*UBAT_R_FACTOR*3.3)+0.79);
}

/**@brief function called every 1s to check LiPo Voltage */
void LiPo_Warning() {
    int c = 0;
    //LiPo Undervoltage Emergency Stop
    if ((getLiPoVoltage()*10) < UBAT_LOW) {

        start=0;
        stop=1;
        if (firstUnderVoltage) { //need to return 1st time to stop the motors
            firstUnderVoltage = 0;
            return;
        } else {
            while (1) { //stay here
                Speaker = 1;
                led4 = 1;
                wait(0.1);
                led4 = 0;
                Speaker = 0;
                wait(1);
                if (c++ == 5) {
                    pc.printf("LiPo Voltage: %fV\n\r",getLiPoVoltage());
                    c=0;
                }
            }
        }
    }
}

//////// HELPER ///////////////////////////////////////////////////////////
/** @ brief set the LEDs on the mbed dev board
 * @parameter led - LED Number (1-4)
 */
void setLed(int led) {
    led1=OFF;
    led2=OFF;
    led3=OFF;
    led4=OFF;

    switch (led) {
        case 1:
            led1 = ON;
            break;
        case 2:
            led2 = ON;
            break;
        case 3:
            led3 = ON;
            break;
        case 4:
            led4 = ON;
            break;
    }
}




/** @brief Initializations */
void init() {
    pc.baud(BAUDRATE);                          //set uart baudrate
    tick_1ms.attach_us(&checkButtons, 1000);    //ervery 1ms
    firstUnderVoltage = 1;                      // set flag
    LiPoTicker.attach(&LiPo_Warning,1);         //check LiPo voltage every second
}

///////// MAIN  ///////////////////////////////////////////////////////////

/**
*   @brief main function
*/
int main() {
    init();
    setLed(programm_counter);
    pc.printf("---- XBeat ----\n\r\n\r");
    pc.printf("Initial Program 1: Line Follow\n\r");
    while (1) {
        wait(0.1);
        if (start) {
            switch (programm_counter) {
                case 1:
                    LineFollow();
                    setLed(programm_counter);
                    break;
                case 2:
                    MazeSolver();
                    setLed(programm_counter);
                    break;
                case 3:
                    driver();
                    setLed(programm_counter);
                    break;
                case 4:
                    RemoteControl();
                    setLed(programm_counter);
                    break;
                case 5:
                    SensorData();
                    setLed(programm_counter++);
                    break;
                default:
                    break;
            }
        }
    }
}