Code

/* Include preprocessor directives */

#include <FEHLCD.h>

#include <FEHIO.h>

#include <FEHUtility.h>

#include <FEHMotor.h>

#include <FEHServo.h>

#include <FEHRPS.h>

#include <math.h>

#define TRANSITIONS_PER_ROTATION 318

#define WHEEL_RADIUS 1.25

// Width of the robot from center of back wheel to center of back wheel

#define WIDTH 7.5

#define ARM_MAX 106.0

#define ARM_MIN 16.0

// Declarations for encoders, motors, and CdS cell

DigitalEncoder rightEncoder(FEHIO::P0_1);

DigitalEncoder leftEncoder(FEHIO::P0_0);

FEHMotor rightMotor(FEHMotor::Motor2,9.0);

FEHMotor leftMotor(FEHMotor::Motor3,9.0);

FEHServo servoArm(FEHServo::Servo7);

AnalogInputPin cdsCell(FEHIO::P1_0);

/**

 * Moves the robot forward a set distance using percent force of motors.

 *

 * @parampercent

 *      how fast the motors move

 * @paraminches

 *      how far the motors move (in in.)

 * @requires

 *      -100 <= percent <= 100

 *      0 < inches

 * @ensures

 *      [the robot will move set inches forward +-1 in.]

*/

void moveForward(float percent, float inches) {

    // Reset encoder counts

    rightEncoder.ResetCounts();

    leftEncoder.ResetCounts();

    // Calculate needed counts

    float counts = (inches * TRANSITIONS_PER_ROTATION) / (2 * M_PI * WHEEL_RADIUS);

    // Set both motors to desired percent

    rightMotor.SetPercent(percent);

    leftMotor.SetPercent(percent);

    // While the average of the left and right encoder is less than counts,

    // keep running motors

    while(((leftEncoder.Counts() + rightEncoder.Counts()) / 2.0) < counts) {

        if(leftEncoder.Counts() > rightEncoder.Counts()) {

            rightMotor.SetPercent(1.05*percent);

            leftMotor.SetPercent(percent);

        }

        else if(leftEncoder.Counts() < rightEncoder.Counts()) {

            leftMotor.SetPercent(1.05*percent);

            rightMotor.SetPercent(percent);

        }

        else {

            leftMotor.SetPercent(percent);

            rightMotor.SetPercent(percent);

        }

    }

    // Turn off motors

    rightMotor.Stop();

    leftMotor.Stop();

}

/**

 * Moves the robot forward a set time using percent force of motors.

 *

 * @parampercent

 *      how fast the motors move

 * @paramseconds

 *      how long the motors move (in sec.)

 * @param waitTime

 *      how long the function waits to return after the motors move (in sec.)

 * @requires

 *      -100 <= percent <= 100

 *      0 < seconds

 *      0 < waitTime

 * @ensures

 *      [the robot will move forward for set seconds and will wait for waitTime seconds]

*/

void moveForward(float percent, float seconds, float waitTime) {

    // Reset encoder counts

    rightEncoder.ResetCounts();

    leftEncoder.ResetCounts();

    // Initialize seconds start to time now

    float secondsStart = TimeNow();

    // Set both motors to desired percent

    rightMotor.SetPercent(percent);

    // While the average of the left and right encoder is less than counts,

    // keep running motors

    while(TimeNow() - secondsStart < seconds) {

        if(leftEncoder.Counts() > rightEncoder.Counts()) {

            rightMotor.SetPercent(1.05*percent);

            leftMotor.SetPercent(percent);

        }

        else if(leftEncoder.Counts() < rightEncoder.Counts()) {

            leftMotor.SetPercent(1.05*percent);

            rightMotor.SetPercent(percent);

        }

        else {

            leftMotor.SetPercent(percent);

            rightMotor.SetPercent(percent);

        }

    }

    // Turn off motors

    rightMotor.Stop();

    leftMotor.Stop();

    Sleep(waitTime);

}

/**

 * Turns the robot directly right a set number of degrees using percent force of motors.

 *

 * @parampercent

 *      how fast the motors move

 * @paramdegrees

 *      how far the motors move (in degrees)

 * @requires

 *      -100 <= percent <= 100

 *      0 < degrees

 * @ensures

 *      [the robot will turn set degress right +-5 degrees]

*/

void turnRightDirect(float percent, float degrees) {

    // Reset encoder counts

    rightEncoder.ResetCounts();

    leftEncoder.ResetCounts();

    // Calculate needed distance (with compensation for friction) and then counts

    float inches = ((degrees * M_PI) / 180.0) * ((WIDTH / 2) + .3);

    float counts = ((inches * TRANSITIONS_PER_ROTATION) / (2 * M_PI * WHEEL_RADIUS));

    // Set both motors to desired percent

    rightMotor.SetPercent(percent*-1.0);

    leftMotor.SetPercent(percent);

    // While the average of the left and right encoder is less than counts,

    // keep running motors

    while((rightEncoder.Counts() + leftEncoder.Counts()) / 2.0 < counts) {

        if(leftEncoder.Counts() > rightEncoder.Counts()) {

            rightMotor.SetPercent(-1.05*percent);

            leftMotor.SetPercent(percent);

        }

        else if(leftEncoder.Counts() < rightEncoder.Counts()) {

            leftMotor.SetPercent(1.05*percent);

            rightMotor.SetPercent(-1.0*percent);

        }

        else {

            leftMotor.SetPercent(percent);

            rightMotor.SetPercent(-1.0*percent);

        }

    }

    // Turn off motors

    rightMotor.Stop();

    leftMotor.Stop();

}

/**

 * Turns the robot directly left a set number of degrees using percent force of motors.

 *

 * @parampercent

 *      how fast the motors move

 * @paramdegrees

 *      how far the motors move (in degrees)

 * @requires

 *      -100 <= percent <= 100

 *      0 < degrees

 * @ensures

 *      [the robot will turn set degress left +-5 degrees]

*/

void turnLeftDirect(float percent, float degrees) {

    // Reset encoder counts

    rightEncoder.ResetCounts();

    leftEncoder.ResetCounts();

    // Calculate needed distance (with compensation for friction) and then counts

    float inches = ((degrees * M_PI) / 180.0) * ((WIDTH / 2) + .3);

    float counts = ((inches * TRANSITIONS_PER_ROTATION) / (2 * M_PI * WHEEL_RADIUS));

    //Set both motors to desired percent

    rightMotor.SetPercent(percent);

    leftMotor.SetPercent(percent*-1.0);

    // While the average of the left and right encoder is less than counts,

    // keep running motors

    while((rightEncoder.Counts() + leftEncoder.Counts()) / 2.0 < counts) {

        if(leftEncoder.Counts() > rightEncoder.Counts()) {

            rightMotor.SetPercent(1.05*percent);

            leftMotor.SetPercent(-1.0*percent);

        }

        else if(leftEncoder.Counts() < rightEncoder.Counts()) {

            leftMotor.SetPercent(-1.05*percent);

            rightMotor.SetPercent(percent);

        }

        else {

            leftMotor.SetPercent(-1.0*percent);

            rightMotor.SetPercent(percent);

        }

    }

    // Turn off motors

    rightMotor.Stop();

    leftMotor.Stop();

}

/**

 * Turns the robot with the left wheel a set number of degrees using percent force of motors.

 *

 * @parampercent

 *      how fast the motors move

 * @paramdegrees

 *      how far the motor will move (in degrees)

 * @requires

 *      -100 <= percent <= 100

 *      0 < degrees

 * @ensures

 *      [the robot will turn set degress right +-5 degrees]

*/

void turnRightOneWheel(float percent, float degrees) {

    // Reset encoder counts

    leftEncoder.ResetCounts();

    // Calculate needed distance and then counts

    float inches = ((degrees * M_PI) / 180.0) * (WIDTH);

    float counts = ((inches * TRANSITIONS_PER_ROTATION) / (2 * M_PI * WHEEL_RADIUS));

    // Set motor to desired percent

    leftMotor.SetPercent(percent);

    // Keep running motors until counts is reached

    while(leftEncoder.Counts() < counts) {}

    // Turn off motors

    leftMotor.Stop();

}

/**

 * Turns the robot with the right wheel a set number of degrees using percent force of motors.

 *

 * @parampercent

 *      how fast the motors move

 * @paramdegrees

 *      how far the motor will move (in degrees)

 * @requires

 *      -100 <= percent <= 100

 *      0 < degrees

 * @ensures

 *      [the robot will turn set degress left +-5 degrees]

*/

void turnLeftOneWheel(float percent, float degrees) {

    // Reset encoder counts

    rightEncoder.ResetCounts();

    // Calculate needed distance and then counts

    float inches = ((degrees * M_PI) / 180.0) * (WIDTH);

    float counts = ((inches * TRANSITIONS_PER_ROTATION) / (2 * M_PI * WHEEL_RADIUS));

    // Set motor to desired percent

    rightMotor.SetPercent(percent);

    // Keep running motors until counts is reached

    while(rightEncoder.Counts() < counts) {}

    // Turn off motors

    rightMotor.Stop();

}

/**

 * The robot goes to a given position.

 *

 * @param xPos

 *      x-position robot goes to

 * @param yPos

 *      y-position robot goes to

 * @param heading

 *      heading robot will face

 * @requires

 *      [xPos, yPos, and heading are all valid values for the course]

 *      [The robot has no obstructions on a straight line path to the position]

 * @ensures

 *      [The robot will go to the given position and heading within 1 in. in each direction and 1 degree]

*/

void goTo(float xPos, float yPos, float heading, float motorPercent) {

    // Wait and get valid current position

    Sleep(0.5);

    float currentX = RPS.X();

    float currentY = RPS.Y();

    float currentHeading = RPS.Heading();

   

    // Check robot is far away from position

    if (abs(xPos-currentX) > 1 || abs(yPos-currentY) > 1) {

        // Calculate needed heading

        float neededHeading;

        if (currentX != xPos) {

            neededHeading = 360 * atan((yPos-currentY)/(xPos-currentX)) / M_PI;

        } else {

            neededHeading = 90 * (yPos-currentY)/abs(yPos-currentY);

        }

   

        // Turn to needed heading

        if (abs(neededHeading-currentHeading) > 180) {

            turnLeftDirect(motorPercent*(neededHeading-currentHeading)/abs(neededHeading-currentHeading), 360 - abs(neededHeading - currentHeading));

        } else {

            turnLeftDirect(motorPercent*(neededHeading-currentHeading)/abs(neededHeading-currentHeading), abs(neededHeading-currentHeading));

        }

       

        // Calculate needed distance

        float distance = sqrt(pow(xPos - currentX, 2) + pow(yPos - currentY, 2));

        // Go the needed distance

        moveForward(motorPercent, distance);

        // Recursively go to the position again to verify position

        goTo(xPos, yPos, heading, motorPercent);

    }

    else if (abs(heading-currentHeading) > 1) {

        // Initialize motor percent

        float motorPercentTurning = 20;

        // Repeat turning until heading is correct

        while (abs(heading-currentHeading) > 5 && abs(heading-currentHeading) < 355) {

            if (abs(heading-currentHeading) > 180) {

                turnLeftDirect(motorPercentTurning*(heading-currentHeading)/abs(heading-currentHeading), 360 - abs(heading - currentHeading));

            } else {

                turnLeftDirect(motorPercentTurning*(heading-currentHeading)/abs(heading-currentHeading), abs(heading-currentHeading));

            }

            Sleep(0.5);

            currentHeading = RPS.Heading();

        }

    }

}

/**

 * Completes the boarding pass button task.

 *

 * @requires

 *      [Robot is at the upper level of the course]

 * @ensures

 *      [Boarding pass task will be completed]

*/

void boardingPass() {

    // Boarding pass nose

    moveForward(25, 2.5, 0);

    moveForward(-25, 6.5);

    turnRightDirect(25, 93);

    moveForward(25, 13.5);

    Sleep(.5);

    if (cdsCell.Value() > .65) { // Blue/red light checker

        LCD.Clear();

        LCD.SetBackgroundColor(BLUE);

        LCD.WriteLine("Blue");

        turnRightDirect(25, 90);

        moveForward(25, 4.5);

        turnLeftDirect(25, 90);

        moveForward(40, 1.5, .5);

        moveForward(-25, 6.5);

        turnRightDirect(25, 90);

        moveForward(25, 1.5);

        // Update horizontal position for C

        if (RPS.CurrentRegionLetter() == 'C') {

            moveForward(-25, 0.25);

        }

        turnLeftDirect(25, 96);

    } else {

        LCD.Clear();

        LCD.SetBackgroundColor(RED);

        LCD.WriteLine("Red");

        turnRightDirect(25, 90);

        moveForward(25, 9.5);

        turnLeftDirect(25, 90);

        moveForward(40, 1.5, .5);

        moveForward(-25, 6.5);

        turnLeftDirect(25, 93);

        moveForward(25, 2.5);

        // Update horizontal position for C

        if (RPS.CurrentRegionLetter() == 'C') {

            moveForward(25, 0.25);

        }

        turnRightDirect(25, 90);

    }

   

}

/**

 * Completes the fuel lever task.

 *

 * @requires

 *      [robot is in position for the task]

 * @ensures

 *      [the fuel lever task is completed]

*/

void fuelLever() {

    // 0 - Left, 1 - Middle, 2 - Right

    int lever = RPS.GetCorrectLever();

    if (lever == 1) {

        lever += (0.5/3.5);

    }

    // Go to correct x-position

    moveForward(25, 21.5 + 3.5 * lever);

    if(lever == 2) {

        moveForward(-25, .2);

    }

    // Set arm to up position

    servoArm.SetDegree(ARM_MAX);

    // Go to lever

    turnLeftDirect(25, 94);

    if(lever == 2) {

        turnRightDirect(25, 11);

    }

    moveForward(-25, 3.0);

    // Flip lever and go back

    servoArm.SetDegree(21.0);

    Sleep(.5);

    moveForward(-25, 3);

    servoArm.SetDegree(ARM_MIN);

    Sleep(.5);

    // Flip lever back

    moveForward(25, 3);

    Sleep(4.5);

    servoArm.SetDegree(76.0);

    Sleep(.5);

    // Reset position

    moveForward(-25, 3);

    servoArm.SetDegree(ARM_MAX);

    if (lever == 2) {

        turnLeftDirect(25, 6);

    }

   

}

/**

 * Completes the stamp task.

 *

 * @requires

 *      [robot is in position near top of slope.]

 * @ensures

 *      [stamp task is completed.]

*/

void stampingPass() {

    // Go to boarding pass

    servoArm.SetDegree(ARM_MIN-13);

    // Move up boarding pass

    turnRightDirect(25, 87);

    servoArm.SetDegree(ARM_MIN+30);

    turnLeftDirect(50, 45);

    // Move away from boarding pass

    moveForward(-25, 2.0);

    servoArm.SetDegree(ARM_MIN-10);

    moveForward(-25, 4.0);

    servoArm.SetDegree(ARM_MAX);

}

/**

 * Completes the luggage drop off task.

 *

 * @requires

 *      [robot is in position near top of right ramp]

 * @ensures

 *      [luggage task is completed]

*/

void luggage() {

    // Set up position

    turnLeftDirect(25, 90*1.15);

    moveForward(-30, 3.0, .25);

    moveForward(25, 20.0);

    turnLeftDirect(25, 90*1.13);

    moveForward(25, 1.0, .25);

    moveForward(-25, 2.0);

    // Set luggage in position and move away

    servoArm.SetDegree(30);

    Sleep(1.0);

    leftMotor.SetPercent(-40);

    rightMotor.SetPercent(-40);

    Sleep(1.0);

    leftMotor.SetPercent(0);

    rightMotor.SetPercent(0);

    Sleep(.125);

    servoArm.SetDegree(ARM_MAX);

    moveForward(40, 2.0, .125);

}

int main() {

    // For touch screen

    float xTouch, yTouch;

    // Set servo min and max

    servoArm.SetMin(500);

    servoArm.SetMax(2267);

    servoArm.SetDegree(ARM_MAX+10);

    RPS.InitializeTouchMenu();

    // Initialize the screen

    LCD.Clear(BLACK);

    LCD.SetFontColor(WHITE);

    LCD.WriteLine("Robot Test");

    LCD.WriteLine("Touch the screen");

    // Wait for screen to be pressed

    while(!LCD.Touch(&xTouch, &yTouch)) {

        LCD.WriteLine(cdsCell.Value());

        Sleep(.1);

        LCD.Clear();

    }

    // Wait for screen to be unpressed

    while(LCD.Touch(&xTouch,&yTouch));

    LCD.Clear();

    LCD.WriteLine("Waiting for CdS cell signal");

    while(cdsCell.Value() > 1.5) {}

    servoArm.SetDegree(ARM_MAX);

    turnRightDirect(25, 45*1.15);

    moveForward(25, 9.0);

    turnLeftDirect(25, 90*1.15);

    moveForward(-40, 2.0, .125);

    moveForward(25, 4.5);

    turnRightDirect(25, 90*1.1);

    moveForward(25, 28.0);

    luggage();

    moveForward(-25, 3.0);

    turnRightDirect(25, 90);

    boardingPass();

    stampingPass();

    turnRightDirect(25, 135);

    moveForward(40, 2.5, .125);

    moveForward(-25, 3.0);

    turnLeftDirect(25, 90);

    moveForward(35, 3.5, .25);

    moveForward(-25, 2.5);

    turnRightDirect(25, 90);

    moveForward(25, 26.0);

    turnRightDirect(25, 90);

    moveForward(-40, 1.5, .25);

    fuelLever();

    moveForward(25, 5.5);

    turnLeftDirect(25, 90);

    moveForward(40, 3.0, 0);

    moveForward(-25, 3.0);

    turnRightDirect(25, 90);

    moveForward(40, 999, 0);

    LCD.Clear();

    LCD.WriteLine("Test Completed");

    return 0;

}