Allows the M3Pi to be used as a Sumo robot, using the sharp 100 distance sensors on the front.

Dependencies:   mbed

main.cpp

Committer:
p07gbar
Date:
2012-03-14
Revision:
0:342c14fb10c0

File content as of revision 0:342c14fb10c0:

/**
Author: Giles Barton-Owen
Name: mbed ranger
Description:

This program keeps a m3pi inside a ring, and has 6 (4 Active) different game modes.
It relies on a Sharp Digital Distance sensor (GP2Y0D810) attached to pin 30 and 11 
(the two headers on the right and left of the board). The system refreshes at 10Hz
when it reads the line sensors on the 3pi and the distance states. The states are
then handled in a big FSM to reach the conclusions.

To keep the robot saving itself for longer a timeout was programmed, such that the
robot belives itself on a line (as was reported when the timeout was set) until 
0.3 seconds has elapsed. This could be adjusted.

The fore-ground loop just switches the LEDs on the board as instructed. The current
state of the robot is reported on line 2 of the LCD screen on the 3pi, displaying
first mode and the last character being line detection state (none, front, back).


**/

#include "mbed.h"
#include "SharpDigiDist100.h"
#include "m3pi.h"

DigitalOut Left[2] = {LED1,LED2};           //Some indicator LEDs for the range finders
DigitalOut Right[2] = {LED4,LED3};

SharpDigiDist100 right(p30);                // The range finder class initialisations
SharpDigiDist100 left(p11);

m3pi m3pi;                                  // Initialise the m3pi

InterruptIn button(p21);                    // SW1 on the shield, for stratergy switching

Ticker guidance;                            // The main guidance caller

Serial pc(USBTX, USBRX);                    // For debugging and pc messages, uses commented out to prevent hanging

Timer debounce;                             // To debounce the switch

int previousLine;                           // A set of variables to sort out the line detection, previousLine is pretty much not used
int isLine;
int lineCatch;

Timeout liner;                              // A timeout to stop it ignoring the line

void CycleMode();                           // Function defs
void guideCall();
void clearLiner();

enum Stratergies {                          // The enum for stratergies
    Off,
    Dormant,
    RunMid,
    RunNear,
    AttackMid,
    AttackFar,
    Hunt
};

void updateScreen(int line, enum Stratergies stratergy);

enum Stratergies stratMode = Off;       // The current stratergy

int main() {
    guidance.attach(&guideCall,0.1);        // Sets up the control loop
    
    button.mode(PullUp);                    // Sets the internal pull up on SW1
    button.fall(&CycleMode);                // Attaches an interupt for when it is pressed
    
    m3pi.locate(0,0);                       // Write the name to the screen
    m3pi.printf("m3PiRngr");                
    
    m3pi.get_white_levels();                // Saves the current levels of the sensors to know what is white
    
    debounce.start();                       // Starts the debounce timer so that the switch thinks it isnt a bounce first time
    
    //pc.printf("\n\n\rMbedRanger\n\r");      // Prints a hello to the computer
    
    while (1) {
        //pc.printf("Loop\n\r");
        switch (right.getDistance()) {      // Sets up the distance indicator LEDs for the right side
            case SharpDigiDist100::Far :
                Right[0] = true;
                Right[1] = false;
                break;
            case SharpDigiDist100::Near :
                Right[1] = true;
                Right[0] = false;
                break;
            case SharpDigiDist100::Mid :
                Right[0] = true;
                Right[1] = true;
                break;
            default:
                break;
        }
        switch (left.getDistance()) {       // Sets up the distance indicator LEDs for the left side
            case SharpDigiDist100::Far :
                Left[0] = true;
                Left[1] = false;
                break;
            case SharpDigiDist100::Near :
                Left[1] = true;
                Left[0] = false;
                break;
            case SharpDigiDist100::Mid :
                Left[0] = true;
                Left[1] = true;
                break;
            default:
                break;
        }
        /*int calibrated[5];
        m3pi.get_raw_sensors(calibrated);
         pc.printf("Sensors read:");
        for (int i = 0; i<5;i++) {
            pc.printf(" %i ",calibrated[i]);
        }
        if (m3pi.is_line() > 0) {
            pc.printf("LINE");
            m3pi.locate(0,1);
            m3pi.printf("LINE");
        }
        pc.printf("\n\r");
        wait(0.1);*/
    }
}



void CycleMode() {                      // Cycles through the modes, probably could have written this with a simple ++ statement...
    debounce.stop();                    // Stops and reads the timer since the last press of the button
    if (debounce.read_ms() > 100) {     // If it was more than 100ms ago it treats it as a button press, otherwise it just ignores it
        switch (stratMode) {
            case Off:
                stratMode = Dormant;
                m3pi.locate(0,1);
                m3pi.printf("\nDormant ");
                break;
            case Dormant:
                stratMode = RunMid;
                m3pi.locate(0,1);
                m3pi.printf("\nRunMid ");
                break;
            case RunMid:
                stratMode = RunNear;
                m3pi.locate(0,1);
                m3pi.printf("\nRunNear ");
                break;
            case RunNear:
                stratMode = AttackMid;
                m3pi.locate(0,1);
                m3pi.printf("\nTakNear ");
                break;
            case AttackMid:
                stratMode = AttackFar;
                m3pi.locate(0,1);
                m3pi.printf("\nTakFar ");
                break;
            case AttackFar:
                stratMode = Hunt;
                m3pi.locate(0,1);
                m3pi.printf("\nHUNTING! ");
                break;
            case Hunt:
                stratMode = Off;
                m3pi.printf("\nOFF ");
                break;
        }
    }
    debounce.reset();
    debounce.start();
}

void guideCall() {

    isLine = m3pi.is_line();            // Gets whether the m3pi is on a line, and if so front/back
    
    if (lineCatch == 0) {               // Has it been off a line for long enough?
        isLine = isLine;                // Yes - then go ahead
    } else {
        isLine = lineCatch;             // No - pretend to still be on that line
        
    }
    float position;                     
    
    switch (isLine) {
        case 0:                         // No line, not even recently so go ahead with the stratergies
            
            updateScreen(isLine, stratMode);
            bool atRight = false;
            bool atLeft = false;
            
            switch (stratMode) {
                case Off:               // No motors
                case Dormant:           // Will take action against lines though
                    m3pi.stop();
                    break;

                case RunNear:           // Runs if something is near
                    if (right.getDistance() == SharpDigiDist100::Near) {
                        atRight = true;
                    } else atRight = false;
                    if (left.getDistance() == SharpDigiDist100::Near) {
                        atLeft = true;
                    } else atLeft = false;

                case RunMid:            // Runs if something is in the middle distance

                    if (right.getDistance() == SharpDigiDist100::Mid) {
                        atRight = true;
                    }
                    if (left.getDistance() == SharpDigiDist100::Mid) {
                        atLeft = true;
                    }


                    if (atRight && atLeft) {
                        m3pi.backward(0.5);
                    } else {
                        if (atRight == true) {
                            m3pi.left_motor(-0.3);
                            m3pi.right_motor(-0.5);
                        } else {
                            if (atLeft == true) {
                                m3pi.left_motor(-0.5);
                                m3pi.right_motor(-0.3);
                            } else {
                                m3pi.stop();
                            }
                        }
                    }
                    break;

                case AttackMid:         // Attacks something in the middle distance
                    if (right.getDistance() == SharpDigiDist100::Mid) {
                        atRight = true;
                    }
                    if (left.getDistance() == SharpDigiDist100::Mid) {
                        atLeft = true;
                    }


                    if (atRight && atLeft) {
                        m3pi.forward(0.6);
                    } else {
                        if (atRight == true) {
                            m3pi.left_motor(0.5);
                            m3pi.right_motor(0.7);
                        } else {
                            if (atLeft == true) {
                                m3pi.left_motor(0.7);
                                m3pi.right_motor(0.5);
                            } else {
                                m3pi.stop();
                            }
                        }
                    }

                    if (right.getDistance() == SharpDigiDist100::Near) {
                        atRight = true;
                    } else atRight = false;
                    if (left.getDistance() == SharpDigiDist100::Near) {
                        atLeft = true;
                    } else atLeft = false;


                    if (atRight && atLeft) {
                        m3pi.forward(0.5);
                    } else {
                        if (atRight == true) {
                            m3pi.left_motor(0.1);
                            m3pi.right_motor(0.2);
                        } else {
                            if (atLeft == true) {
                                m3pi.left_motor(0.2);
                                m3pi.right_motor(0.1);
                            }
                        }
                    }

                    break;

                case AttackFar:

                    break;
                case Hunt:                  // Runs forward until something is really close

                    if (right.getDistance() == SharpDigiDist100::Mid || right.getDistance() == SharpDigiDist100::Near) {
                        atRight = true;
                    } else atRight = false;
                    if (left.getDistance() == SharpDigiDist100::Mid || left.getDistance() == SharpDigiDist100::Near) {
                        atLeft = true;
                    } else atLeft = false;

                    if (atRight && atLeft) {
                        m3pi.stop();
                    } else {
                        if (atRight == true) {
                            m3pi.left_motor(0.1);
                            m3pi.right_motor(0.2);
                        } else {
                            if (atLeft == true) {
                                m3pi.left_motor(0.2);
                                m3pi.right_motor(0.1);
                            } else {
                                m3pi.forward(0.3);
                            }
                        }
                    }
                    break;
                default:
                    break;
            }
            break;

        case 1:                 // Line in front, reverse
            if(stratMode != Off)
            {
            if (lineCatch == 0) {
                lineCatch = 1;

                liner.attach(&clearLiner, 0.3);
            }

            position = m3pi.line_position();
            if (position < 0) {
                m3pi.left_motor(-1);
                m3pi.right_motor(-0.8);
            } else if (position == 0) {
                m3pi.backward(1);
            } else if (position > 0) {
                m3pi.left_motor(-0.8);
                m3pi.right_motor(-1);
            }

            //m3pi.locate(0,1);
            //m3pi.printf("LINE_FWD");
            }
            else
            {
                m3pi.stop();
            }
            updateScreen(isLine, stratMode);
            break;

        case -1:            // Line behind, forward
            if(stratMode != Off)
            {
            if (lineCatch == 0) {
                lineCatch = -1;
                liner.attach(&clearLiner, 0.3);
            }


            position = m3pi.line_position();
            if (position < 0) {
                m3pi.left_motor(1);
                m3pi.right_motor(0.8);
            } else if (position == 0) {
                m3pi.forward(1);
            } else if (position > 0) {
                m3pi.left_motor(0.8);
                m3pi.right_motor(1);
            }
            }
            else
            {
                m3pi.stop();
            }
            //m3pi.locate(0,1);
            //m3pi.printf("LINE_BKD");
            updateScreen(isLine, stratMode);
            break;
    }

    //previousLine = isLine;
}

void clearLiner() {             // Gets called a bit after a line is detected
    lineCatch = 0;
    //pc.printf("Cleared liner\n\r");
}

void updateScreen(int line, enum Stratergies stratergy) {       // Update the bottom line with the running info
    m3pi.locate(0,1);
    
    char lineState;
    
    switch (line) {
        case 0:
            lineState = 'N';
            break;
        case 1:
            lineState = 'F';
            break;
        case -1:
            lineState = 'B';
            break;
        default:
            break;
    }

    char strat[6];
    switch (stratergy) {
        case Off:
            sprintf(strat,"OFF   ");
            break;
        case Dormant:
            sprintf(strat,"DORMNT");
            break;
        case RunMid:
            sprintf(strat,"RUNMID");

            break;
        case RunNear:
            sprintf(strat,"RNNEAR");

            break;
        case AttackMid:
            sprintf(strat,"TAKMID");

            break;
        case AttackFar:
            sprintf(strat,"TAKFAR");

            break;
        case Hunt:
            sprintf(strat,"HUNTER");

            break;
    }

    m3pi.printf("%s %c",strat,lineState);
}