Roving robot using the RS-EDP.
Dependencies: mbed RSEDP_AM_MC1_lib SDFileSystem
Diff: Rover.cpp
- Revision:
- 0:8d15dc761944
- Child:
- 1:ffef6386027b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Rover.cpp Mon Aug 16 09:46:28 2010 +0000 @@ -0,0 +1,538 @@ +/** + * @author Aaron Berk + * + * @section LICENSE + * + * Copyright (c) 2010 ARM Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * RS-EDP Rover application class. + * + * Demonstrates four action states: moving {forward, backward}, + * rotating {clockwise, counter-clockwise}. + * + * Logs heading and left and right motor position and velocity data. + * + * Performs PID velocity control on the motors. + * + * --------------- + * CONFIGURATION + * --------------- + * + * The set up assumes the H-bridge being used has pins for: + * + * - PWM input + * - Brake + * - Direction + * + * The constructor arguments will need to be changed if a different type of + * H-bridge is used. + * + * The PID controllers are configured using the #defines below. + * + * The set up also assumes two quadrature encoders are used, each using the + * default X2 encoding. + * + * The constructor arguments will need to be changed if a different number + * of encoders are used or if a different encoding is required. + */ + +/** + * Includes + */ +#include "Rover.h" + +Serial pc2(USBTX, USBRX); + +Rover::Rover(PinName leftMotorPwm, + PinName leftMotorBrake, + PinName leftMotorDirection, + PinName rightMotorPwm, + PinName rightMotorBrake, + PinName rightMotorDirection, + PinName leftQeiChannelA, + PinName leftQeiChannelB, + PinName leftQeiIndex, + int leftPulsesPerRev, + PinName rightQeiChannelA, + PinName rightQeiChannelB, + PinName rightQeiIndex, + int rightPulsesPerRev) : + leftMotors(), + rightMotors(), + leftQei(leftQeiChannelA, + leftQeiChannelB, + leftQeiIndex, + leftPulsesPerRev), + rightQei(rightQeiChannelA, + rightQeiChannelB, + rightQeiIndex, + rightPulsesPerRev), + leftController(Kc, Ti, Td, PID_RATE), + rightController(Kc, Ti, Td, PID_RATE), + stateTicker(), + logTicker(), + imu(IMU_RATE, + GYRO_MEAS_ERROR, + ACCELEROMETER_RATE, + GYROSCOPE_RATE) { + + //--------------------------------- + // Left motors and PID controller. + //--------------------------------- + + //Motors. + leftMotors.setPwmPin(leftMotorPwm); + leftMotors.setBrakePin(leftMotorBrake); + leftMotors.setDirectionPin(leftMotorDirection); + leftMotors.initialize(); + leftMotors.setDirection(BACKWARD); + leftMotors.setBrake(BRAKE_OFF); + + //PID. + leftController.setInputLimits(PID_IN_MIN, PID_IN_MAX); + leftController.setOutputLimits(PID_OUT_MIN, PID_OUT_MAX); + leftController.setBias(PID_BIAS); + leftController.setMode(AUTO_MODE); + leftPulses_ = 0; + leftPrevPulses_ = 0; + leftPwmDuty_ = 1.0; + leftVelocity_ = 0.0; + + //---------------------------------- + // Right motors and PID controller. + //---------------------------------- + + //Motors. + rightMotors.setPwmPin(rightMotorPwm); + rightMotors.setBrakePin(rightMotorBrake); + rightMotors.setDirectionPin(rightMotorDirection); + rightMotors.initialize(); + rightMotors.setDirection(FORWARD); + rightMotors.setBrake(BRAKE_OFF); + + //PID. + rightController.setInputLimits(PID_IN_MIN, PID_IN_MAX); + rightController.setOutputLimits(PID_OUT_MIN, PID_OUT_MAX); + rightController.setBias(PID_BIAS); + rightController.setMode(AUTO_MODE); + rightPulses_ = 0; + rightPrevPulses_ = 0; + rightPwmDuty_ = 1.0; + rightVelocity_ = 0.0; + + //-------------------- + // Working Variables. + //-------------------- + positionSetPoint_ = 0.0; + headingSetPoint_ = 0.0; + heading_ = 0.0; + prevHeading_ = 0.0; + degreesTurned_ = 0.0; + leftStopFlag_ = 0; + rightStopFlag_ = 0; + + //-------- + // BEGIN! + //-------- + state_ = STATE_STATIONARY; + stateTicker.attach(this, &Rover::doState, PID_RATE); + startLogging(); + +} + +void Rover::move(int distance) { + + positionSetPoint_ = distance; + + //Moving forward. + if (distance > 0) { + + enterState(STATE_MOVING_FORWARD); + + } + //Moving backward. + else if (distance < 0) { + + enterState(STATE_MOVING_BACKWARD); + + } + + //If distance == 0, then do nothing, i.e. stay stationary. + +} + +void Rover::turn(int degrees) { + + headingSetPoint_ = abs(degrees); + + //Rotating clockwise. + if (degrees > 0) { + + enterState(STATE_ROTATING_CLOCKWISE); + + } + //Rotating counter-clockwise. + else if (degrees < 0) { + + enterState(STATE_ROTATING_COUNTER_CLOCKWISE); + + } + + //If degrees == 0, then do nothing, i.e. stay stationary. + +} + +Rover::State Rover::getState(void) { + + return state_; + +} + +void Rover::startLogging(void) { + + logFile = fopen("/sd/roverlog.csv", "w"); + fprintf(logFile, "leftPulses, rightPulses, leftVelocity, rightVelocity, heading, degreesTurned\n"); + logTicker.attach(this, &Rover::log, LOG_RATE); + +} + +void Rover::stopLogging(void) { + + fclose(logFile); + +} + +void Rover::log(void) { + + fprintf(logFile, "%i,%i,%f,%f,%f,%f\n", + leftPulses_, rightPulses_, leftVelocity_, rightVelocity_, imu.getYaw(), degreesTurned_); + +} + +void Rover::doState(void) { + + switch (state_) { + + //We're not moving so don't do anything! + case (STATE_STATIONARY): + break; + + case (STATE_MOVING_FORWARD): + + //If we haven't hit the position set point yet, + //perform velocity control on the motors. + if (leftPulses_ < positionSetPoint_) { + + leftPulses_ = leftQei.getPulses(); + leftVelocity_ = (leftPulses_ - leftPrevPulses_) / PID_RATE; + leftPrevPulses_ = leftPulses_; + leftController.setProcessValue(leftVelocity_); + leftPwmDuty_ = leftController.getRealOutput(); + + } else { + leftStopFlag_ = 1; + } + + leftMotors.setPwmDuty(leftPwmDuty_); + + if (rightPulses_ < positionSetPoint_) { + + rightPulses_ = rightQei.getPulses(); + rightVelocity_ = (rightPulses_ - rightPrevPulses_) / PID_RATE; + rightPrevPulses_ = rightPulses_; + rightController.setProcessValue(rightVelocity_); + rightPwmDuty_ = rightController.getRealOutput(); + + } else { + rightStopFlag_ = 1; + } + + rightMotors.setPwmDuty(rightPwmDuty_); + + //We've hit the end position set point. + if (leftStopFlag_ == 1 && rightStopFlag_ == 1) { + leftPwmDuty_ = 1.0; + rightPwmDuty_ = 1.0; + leftMotors.setPwmDuty(leftPwmDuty_); + rightMotors.setPwmDuty(rightPwmDuty_); + enterState(STATE_STATIONARY); + } + + break; + + case (STATE_MOVING_BACKWARD): + + //If we haven't hit the position set point yet, + //perform velocity control on the motors. + if (leftPulses_ > positionSetPoint_) { + leftPulses_ = leftQei.getPulses(); + leftVelocity_ = (leftPulses_ - leftPrevPulses_) / PID_RATE; + leftPrevPulses_ = leftPulses_; + leftController.setProcessValue(fabs(leftVelocity_)); + leftPwmDuty_ = leftController.getRealOutput(); + } else { + leftStopFlag_ = 1; + } + + leftMotors.setPwmDuty(leftPwmDuty_); + + if (rightPulses_ > positionSetPoint_) { + rightPulses_ = rightQei.getPulses(); + rightVelocity_ = (rightPulses_ - rightPrevPulses_) / PID_RATE; + rightPrevPulses_ = rightPulses_; + rightController.setProcessValue(fabs(rightVelocity_)); + rightPwmDuty_ = rightController.getRealOutput(); + + } else { + rightStopFlag_ = 1; + } + + rightMotors.setPwmDuty(rightPwmDuty_); + + //We've hit the end position set point. + if (leftStopFlag_ == 1.0 && rightStopFlag_ == 1.0) { + leftPwmDuty_ = 1.0; + rightPwmDuty_ = 1.0; + leftMotors.setPwmDuty(leftPwmDuty_); + rightMotors.setPwmDuty(rightPwmDuty_); + enterState(STATE_STATIONARY); + } + + break; + + case (STATE_ROTATING_CLOCKWISE): + + //If we haven't hit the position set point yet, + //perform velocity control on the motors. + if (degreesTurned_ < headingSetPoint_) { + + heading_ = fabs(imu.getYaw()); + degreesTurned_ += fabs(heading_ - prevHeading_); + prevHeading_ = heading_; + + leftPulses_ = leftQei.getPulses(); + leftVelocity_ = (leftPulses_ - leftPrevPulses_) / PID_RATE; + leftPrevPulses_ = leftPulses_; + leftController.setProcessValue(leftVelocity_); + leftPwmDuty_ = leftController.getRealOutput(); + + rightPulses_ = rightQei.getPulses(); + rightVelocity_ = (rightPulses_ - rightPrevPulses_) / PID_RATE; + rightPrevPulses_ = rightPulses_; + rightController.setProcessValue(fabs(rightVelocity_)); + rightPwmDuty_ = rightController.getRealOutput(); + + leftMotors.setPwmDuty(leftPwmDuty_); + rightMotors.setPwmDuty(rightPwmDuty_); + + } else { + + leftPwmDuty_ = 1.0; + rightPwmDuty_ = 1.0; + leftMotors.setPwmDuty(leftPwmDuty_); + rightMotors.setPwmDuty(rightPwmDuty_); + enterState(STATE_STATIONARY); + + } + + break; + + case (STATE_ROTATING_COUNTER_CLOCKWISE): + + //If we haven't hit the position set point yet, + //perform velocity control on the motors. + if (degreesTurned_ < headingSetPoint_) { + + heading_ = fabs(imu.getYaw()); + degreesTurned_ += fabs(heading_ - prevHeading_); + prevHeading_ = heading_; + + leftPulses_ = leftQei.getPulses(); + leftVelocity_ = (leftPulses_ - leftPrevPulses_) / PID_RATE; + leftPrevPulses_ = leftPulses_; + leftController.setProcessValue(fabs(leftVelocity_)); + leftPwmDuty_ = leftController.getRealOutput(); + + rightPulses_ = rightQei.getPulses(); + rightVelocity_ = (rightPulses_ - rightPrevPulses_) / PID_RATE; + rightPrevPulses_ = rightPulses_; + rightController.setProcessValue(rightVelocity_); + rightPwmDuty_ = rightController.getRealOutput(); + + leftMotors.setPwmDuty(leftPwmDuty_); + rightMotors.setPwmDuty(rightPwmDuty_); + + } else { + + leftPwmDuty_ = 1.0; + rightPwmDuty_ = 1.0; + leftMotors.setPwmDuty(leftPwmDuty_); + rightMotors.setPwmDuty(rightPwmDuty_); + enterState(STATE_STATIONARY); + + } + + break; + + //If we've fallen into a black hole, the least we can do is turn + //the motors off. + default: + + leftMotors.setPwmDuty(1.0); + rightMotors.setPwmDuty(1.0); + + break; + + } + +} + +void Rover::enterState(State state) { + + switch (state) { + + //Entering stationary state. + //1. Turn motors off. + //2. Reset QEIs. + //3. Reset PID working variables. + //4. Reset PIDs. + //5. Reset set points and working variables. + //7. Set state variable. + case (STATE_STATIONARY): + + leftMotors.setPwmDuty(1.0); + rightMotors.setPwmDuty(1.0); + + leftQei.reset(); + rightQei.reset(); + + leftPulses_ = 0; + leftPrevPulses_ = 0; + leftPwmDuty_ = 1.0; + leftVelocity_ = 0.0; + + rightPulses_ = 0; + rightPrevPulses_ = 0; + rightPwmDuty_ = 1.0; + rightVelocity_ = 0.0; + + leftController.setSetPoint(0.0); + leftController.setProcessValue(0.0); + rightController.setSetPoint(0.0); + rightController.setProcessValue(0.0); + + positionSetPoint_ = 0.0; + headingSetPoint_ = 0.0; + heading_ = 0.0; + prevHeading_ = 0.0; + degreesTurned_ = 0.0; + leftStopFlag_ = 0; + rightStopFlag_ = 0; + + state_ = STATE_STATIONARY; + + break; + + //Entering moving forward state. + //1. Set correct direction for motors. + //2. Set velocity set point. + //3. Set state variable. + case (STATE_MOVING_FORWARD): + + leftMotors.setDirection(BACKWARD); + rightMotors.setDirection(FORWARD); + + //Velocity control. + leftController.setSetPoint(1000); + rightController.setSetPoint(1000); + + state_ = STATE_MOVING_FORWARD; + + break; + + //Entering moving backward state. + //1. Set correct direction for motors. + //2. Set velocity set point. + //3. Set state variable. + case (STATE_MOVING_BACKWARD): + + leftMotors.setDirection(FORWARD); + rightMotors.setDirection(BACKWARD); + + //Velocity control. + leftController.setSetPoint(1000); + rightController.setSetPoint(1000); + + state_ = STATE_MOVING_BACKWARD; + + break; + + //Entering rotating clockwise state. + //1. Set correct direction for motors. + //2. Set velocity set point. + //3. Set working variables. + //4. Set state variable. + case (STATE_ROTATING_CLOCKWISE): + + leftMotors.setDirection(BACKWARD); + rightMotors.setDirection(BACKWARD); + + leftController.setSetPoint(500); + rightController.setSetPoint(500); + + degreesTurned_ = 0.0; + heading_ = fabs(imu.getYaw()); + prevHeading_ = heading_; + + state_ = STATE_ROTATING_CLOCKWISE; + + break; + + //Entering rotating clockwise state. + //1. Set correct direction for motors. + //2. Set velocity set point. + //3. Set working variables. + //4. Set state variable. + case (STATE_ROTATING_COUNTER_CLOCKWISE): + + leftMotors.setDirection(FORWARD); + rightMotors.setDirection(FORWARD); + + leftController.setSetPoint(500); + rightController.setSetPoint(500); + + degreesTurned_ = 0.0; + heading_ = fabs(imu.getYaw()); + prevHeading_ = heading_; + + state_ = STATE_ROTATING_COUNTER_CLOCKWISE; + + break; + + default: + + break; + + } + +}