TFC-Mentoring-Matters-Abstraction

Dependencies:   FRDM-TFC

RaceCar/Modes.cpp

Committer:
mrkeithcyr
Date:
2014-07-16
Revision:
0:0699eb71778e

File content as of revision 0:0699eb71778e:

#include "common.h"
#include "TheDetails.h"

/****** RunMode0() *************************************************************
Purpose: Mode 0 is used for some very basic tests. It will test to see that the
    car is "turned on" by printing a message to the computer telling us that it
    is on. This mode also allows us to check that push buttons 'A' and 'B' are
    working and that the LEDs on the board are working.
    Most importantly, however, this quick and simple code will show us whether
    or not our CODE is working before we spend too much time writing the rest of
    the code.
Parameters: None
Returns: None
*******************************************************************************/
void RunMode0()
{
    // print out a message to our computer so we know what mode we're in
    TERMINAL_PRINTF("The car is currently turned on and in MODE 0\r\n");

    // next we want to 
    DISABLE_THE_MOTORS;

    // this mode tests the push buttons and LEDs
    if(BUTTON_A_IS_PRESSED)
    { //then
        TURN_ON_LED_0;  // and
        TURN_ON_LED_1;
    }
    else
    { // if button A is not pressed
        TURN_OFF_LED_0;  // and
        TURN_OFF_LED_1;
    }
    
    if(BUTTON_B_IS_PRESSED)
    { // then
        TURN_ON_LED_2;  // and
        TURN_ON_LED_3;
    }
    else
    { // if button B is not pressed
        TURN_OFF_LED_2;  // and
        TURN_OFF_LED_3;
    }
}

/****** RunMode1() *************************************************************
Purpose: Mode 1 isolates the drive motors on the rear wheels. The potentiometers
    on the board allow each motor to be adjusted individually. The numerical
    value that the pot represents is output to our computer so that we can
    gather some information about how the different values used for the drive
    settings will affect the direction and/or speed of the wheels.
Parameters: None
Returns: None
*******************************************************************************/
void RunMode1()
{
    // These variables will hold the values that the potentiometers on the board
    // are set to.
    float pot_1_value;
    float pot_2_value;

    // These variables will be the values that we send to the motors in order to
    // control them and see how different values will cause the motors to 
    // behave.
    float right_drive;
    float left_drive;

    // Print out a message to our computer so we know what mode we're in
    TERMINAL_PRINTF("The car is currently in MODE 1\r\n");

    // Next we want to 
    ENABLE_THE_MOTORS;
    // because that's what Mode 1 tests.

    // Then we check what the pots on the board are set to right now
    pot_1_value = CHECK_POT_1_VALUE;
    pot_2_value = CHECK_POT_2_VALUE;

    // it turns out that we want to use these pot values as our drive settings
    right_drive = pot_1_value;
    left_drive = pot_2_value;

    // We can print out to the computer what those values are so that we can
    // actually see them as numbers.
    TERMINAL_PRINTF("Left drive setting = %1.2f\t\t", left_drive);
    TERMINAL_PRINTF("Right drive setting = %1.2f\r\n", right_drive);

    // Let's give those drive settings to the motors and see what happens.
    GiveDriveSettingsToMotors(right_drive, left_drive);
}

/****** RunMode2() *************************************************************
Purpose: Mode 2 isolates the steering servo. We are able to use a potentiometer
    on the board to adjust the steering settings left and right. The values
    being given to the steering servo are printed out to the computer so that
    they can be recorded and used later if necessary.
Parameters: None
Returns: None
*******************************************************************************/
void RunMode2()
{
    // This variable will hold the value that potentiometer number 0 on the
    // board is set to.
    float steering_value;

    // Next we want to 
    DISABLE_THE_MOTORS;

    // Use pot 1 to adjust the steering value.
    steering_value = CHECK_POT_1_VALUE;

    // Give the steering value to the steering servo.
    GiveSteeringSettingTo(SERVO_NUMBER_1, steering_value);

    // We only want the computer to give us information every 200mS so let's
    // start a clock. Our clock counts every 2ms, so if it counts to 50 then
    // 100 * 2ms = 200ms and the computer has some work to do.
    if(CLOCK_NUMBER_1 >= 100)
    {
        // First we need to reset the clock so we get another 100ms break.
        CLOCK_NUMBER_1 = 0;

        // Print out a message to our computer so we know what mode we're in
        TERMINAL_PRINTF("The car is currently in MODE 2 to test steering.\r\n");

        // Let's display our steering setting on the computer to record it.
        TERMINAL_PRINTF("The current steer setting is= %1.2f\r\n",
                        steering_value);
    }
}

/****** RunMode3() *************************************************************
Purpose: This function runs the camera test mode for the car. It disables the
    motors and steering servo to prevent damage to that hardware while isolating
    the camera output. First we check to see if the camera has an image ready
    for us to see and then we decode the camera image and translate it into a
    picture that can be displayed on the computer screen.  The image on the
    screen can be used to focus the camera lens. Dip switch 4 can be turned off 
    to output the original camera code to the screen if it is needed to test the
    camera in this mode.
Parameters: None
Returns: None
*******************************************************************************/
void RunMode3()
{
    // We are going to use these variables to count a couple of things
    uint32_t i = 0;
    uint32_t j = 0;

    // next we want to 
    DISABLE_THE_MOTORS;
    // since we are only working with the camera in this mode

    // We only want the computer to give us information every 1s, and only if
    // there is a picture ready. So let's start a clock. Our clock counts every
    // 2ms, so if it counts to 500 then 500 * 2ms = 1s. Once a second has passed
    // we'll check if the camera is ready. If so, then the computer has some
    // work to do.
    if(CLOCK_NUMBER_1 > 500 && CAMERA_READY > 0)
    {
        // First we need to reset the clock so we get another 1s break.
        CLOCK_NUMBER_1 = 0;

        // Since we are going to use the camera, we'll reset the camera to start
        // taking the next image.
        ResetCamera();

        // Let's see which type of data we want to send to the computer.
        if (LINE_IMAGE) // is what we want to see, then dip switch 4 must be ON
        {
            // These 'for loops' look at each little piece of the image that the
            // camera sees and translates it for us. The pieces that the camera
            // gives us are actually numbers that have a code of their own. By
            // decoding the camera image we can decide if the piece should look
            // like an asterisk or a blank space in the computer terminal. The
            // result is grid printed out to the computer that is 20 rows by 128
            // columns that tells us where the camera sees the line.
            for(j = 20; j > 0; j--) // For each of 20 Rows...
            {
                for(i = 0; i < 128; i++) // ...do this for all 128 Columns.
                {
                    if (THE_PIECE_OF_IMAGE[i] <= LOOKS_IMPORTANT * j
                        && (THE_PIECE_OF_IMAGE[i] >= LOOKS_IMPORTANT * (j - 1)))
                    {   // then print an asterisk in this space
                        TERMINAL_PRINTF("*");
                    }   // otherwise print nothing in this space
                    else
                        TERMINAL_PRINTF(" ");
                }

                // At the end of the row we need to start printing out to
                // the next row down on the computer screen.
                TERMINAL_PRINTF("\r\n");
            }
        }

        // if we don't want to translate the camera's coded numbers into a
        // computer image, we can just print out the numbers themselves.
        else    
        {
            // there are a lot of these numbers so we are only going to print
            // one line worth of data (128 numbers) at a time.
            for(i=0;i<128;i++)
            {
                TERMINAL_PRINTF("%d",THE_PIECE_OF_IMAGE[i]);
                // when last data reached put in line return
                if(i==127) 
                    TERMINAL_PRINTF("\r\n",THE_PIECE_OF_IMAGE[i]);
                else
                    TERMINAL_PRINTF(",",THE_PIECE_OF_IMAGE[i]);
            }
            TERMINAL_PRINTF("=============================================="
                        "==============================================\r\n");
            
            // We can pause the computer display here by entering how many
            // milliseconds we want to wait.
            wait_ms(10); // Waits for .1 second
        }
    }
}

/****** RunMode4() *************************************************************
Purpose: Mode 4 is the first track mode. It takes all of the parts that we
    tested in modes 0 thru 3 and puts them together to [hopefully] make our car
    race around the track. Since we are still just testing the car, Mode 4 will
    limit the top speed of the car just in case something doesn't work. We don't
    want the car to crash into something too fast and break.
Parameters: None
Returns: None
*******************************************************************************/
void RunMode4()
{
    // Let's set that slow speed right away.
    GoSlow();

    // We can still look at data some data on the computer in this mode by
    // turning dip switch number 4 on, so let's check here if that switch is on.
    bool if_we_want_data = DEPENDS_ON_DIP_SWITCH_4;

    // Getting Data takes a little while, so if we want data we make mode 4 wait
    // for 2 whole seconds to run each time, but if we don't want data, then
    // mode 4 runs as fast as the camera can get each image to us! There is also
    // a way here to create fake images that are always ready. They allow us to
    // test the car operation based on a certain image even if we don't have the
    // track to race on at the time.
    if((CLOCK_NUMBER_1 > 2000 || !if_we_want_data)
        && (CAMERA_READY || USE_FAKE_IMAGES))
    {
        // Just like in the other modes, we have to reset things each time we
        // use them:
        // Reset the clock to make sure we get long enough to use our data.
        CLOCK_NUMBER_1 = 0;
        // Reset the camera so that it can start working on the next image.
        ResetCamera();
        // This mode also looks at how bright the lights are on the track for
        // each picture it takes. We have to reset the light intensity readings
        // each time too, so we do that here.
        ResetMaximumLightReading();
        ResetMinimumLightReading();

        // We also need the image that the camera told us it had ready. Let's go
        // get it. If we are using fake images, this function will go get us the
        // fake image.
        GetTheImageToUse();

        // Now that we have our image, let's see if the board can spot the line
        // anywhere in the image. This will take a couple steps, first we have
        // to get all the numbers that the camera uses to code its image
        // (remember in mode 3?)
        GetCameraData();
        // Remember how we just reset the light readings, let's adjust them
        // again for this new image before we try to find the line edges in the
        // image.
        adjustLights();
        // We can now find out where the line is in the image.
        FindTheLine();
        //Let's look real close at that line and see exactly where the edges of
        // the line are.
        reviewEdges();

        // We can print what we have so far on the computer it we have selected
        // to print data.
        if (if_we_want_data)
        {
            PrintOutSomeData();
        }

        // At this point we should know where the line is and what the car
        // should do to stay on the track. We'll call that "Track Status."

        // Let's update things based on latest Track Status
        // This means we can adjust the steering and speed or even stop the car!
        ActOnTrackStatus();

        // Wouldn't it be nice if we could easily tell when the car was "seeing 
        // the line" as it went around the track? Let's use those LEDs from
        // mode 0 to show us:
        // If the car sees the line, the middle 2 LEDs turn on
        // If the car can't find the line then all the LEDs are off
        feedbackLights();

        // Let's use this function to control our speeds around corners and such
        SpeedControl();

        // Now that ALL OUR SETTINGS are ready to go, let's turn on the motors!
        Drive();

        // Some of the functions above will print more things out to the
        // computer, so now that they are all complete let's print a line to
        // tell ourselves that mode 4 has completed this time through.
        if (if_we_want_data)
        {
            TERMINAL_PRINTF("\r\n**************************"
                            "END********************************\r\n");
        }
    }
}

/****** RunMode5() *************************************************************
Purpose: Mode 5 does exactly what mode 4 does, except that it does it FASTER.
    This makes the code VERY easy to write for Mode 5
Parameters: None
Returns: None
*******************************************************************************/
void RunMode5()
{
    // Let's set the motors for race speed.
    GoFast();

    // We can still look at data some data on the computer in this mode by
    // turning dip switch number 4 on, so let's check here if that switch is on.
    bool if_we_want_data = DEPENDS_ON_DIP_SWITCH_4;

    // Getting Data takes a little while, so if we want data we make mode 4 wait
    // for 2 whole seconds to run each time, but if we don't want data, then
    // mode 4 runs as fast as the camera can get each image to us! There is also
    // a way here to create fake images that are always ready. They allow us to
    // test the car operation based on a certain image even if we don't have the
    // track to race on at the time.
    if((CLOCK_NUMBER_1 > 2000 || !if_we_want_data)
        && (CAMERA_READY || USE_FAKE_IMAGES))
    {
        // Just like in the other modes, we have to reset things each time we
        // use them:
        // Reset the clock to make sure we get long enough to use our data.
        CLOCK_NUMBER_1 = 0;
        // Reset the camera so that it can start working on the next image.
        ResetCamera();
        // This mode also looks at how bright the lights are on the track for
        // each picture it takes. We have to reset the light intensity readings
        // each time too, so we do that here.
        ResetMaximumLightReading();
        ResetMinimumLightReading();

        // We also need the image that the camera told us it had ready. Let's go
        // get it. If we are using fake images, this function will go get us the
        // fake image.
        GetTheImageToUse();

        // Now that we have our image, let's see if the board can spot the line
        // anywhere in the image. This will take a couple steps, first we have
        // to get all the numbers that the camera uses to code its image
        // (remember in mode 3?)
        GetCameraData();
        // Remember how we just reset the light readings, let's adjust them
        // again for this new image before we try to find the line edges in the
        // image.
        adjustLights();
        // We can now find out where the line is in the image.
        FindTheLine();
        //Let's look real close at that line and see exactly where the edges of
        // the line are.
        reviewEdges();

        // We can print what we have so far on the computer it we have selected
        // to print data.
        if (if_we_want_data)
        {
            PrintOutSomeData();
        }

        // At this point we should know where the line is and what the car
        // should do to stay on the track. We'll call that "Track Status."

        // Let's update things based on latest Track Status
        // This means we can adjust the steering and speed or even stop the car!
        ActOnTrackStatus();

        // Wouldn't it be nice if we could easily tell when the car was "seeing 
        // the line" as it went around the track? Let's use those LEDs from
        // mode 0 to show us:
        // If the car sees the line, the middle 2 LEDs turn on
        // If the car can't find the line then all the LEDs are off
        feedbackLights();

        // Let's use this function to control our speeds around corners and such
        SpeedControl();

        // Now that ALL OUR SETTINGS are ready to go, let's turn on the motors!
        Drive();

        // Some of the functions above will print more things out to the
        // computer, so now that they are all complete let's print a line to
        // tell ourselves that mode 4 has completed this time through.
        if (if_we_want_data)
        {
            TERMINAL_PRINTF("\r\n**************************"
                            "END********************************\r\n");
        }
    }
}