Roving robot using the RS-EDP.
Dependencies: mbed RSEDP_AM_MC1_lib SDFileSystem
Rover.cpp
- Committer:
- aberk
- Date:
- 2010-08-26
- Revision:
- 1:ffef6386027b
- Parent:
- 0:8d15dc761944
File content as of revision 1:ffef6386027b:
/** * @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" 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; logIndex = 0; //-------- // BEGIN! //-------- state_ = STATE_STATIONARY; stateTicker.attach(this, &Rover::doState, PID_RATE); startLogging(); } void Rover::move(float distance) { //Convert from metres into millimetres. distance *= 1000; //Work out how many pulses are required to go that many millimetres. distance *= PULSES_PER_MM; //Make sure we scale the number of pulses according to our encoding method. distance /= ENCODING; 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) { //Correct the amount to turn based on deviation during last segment. headingSetPoint_ = abs(degrees) + (endHeading_ - startHeading_); //In case the rover tries to [pointlessly] turn >360 degrees. if (headingSetPoint_ > 359.8){ headingSetPoint_ -= 359.8; } //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("/local/roverlog.csv", "w"); fprintf(logFile, "leftPulses, rightPulses, leftVelocity, rightVelocity, heading\n"); //logTicker.attach(this, &Rover::log, LOG_RATE); } void Rover::stopLogging(void) { //logFile = fopen("/local/roverlog.csv", "w"); //fprintf(logFile, "leftPulses, rightPulses, leftVelocity, rightVelocity, heading, degreesTurned\n"); //fprintf(logFile, "leftVelocity, rightVelocity\n"); //for(int i = 0; i < 1024; i++){ // fprintf(logFile, "%f, %f\n", leftVelocityBuffer[i], rightVelocityBuffer[i]); //} 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.compute(); } else { leftStopFlag_ = 1; } leftMotors.setPwmDuty(leftPwmDuty_); if (rightPulses_ < positionSetPoint_) { rightPulses_ = rightQei.getPulses(); rightVelocity_ = (rightPulses_ - rightPrevPulses_) / PID_RATE; rightPrevPulses_ = rightPulses_; rightController.setProcessValue(rightVelocity_); rightPwmDuty_ = rightController.compute(); } 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_); endHeading_ = imu.getYaw(); 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.compute(); } 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.compute(); } 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.compute(); rightPulses_ = rightQei.getPulses(); rightVelocity_ = (rightPulses_ - rightPrevPulses_) / PID_RATE; rightPrevPulses_ = rightPulses_; rightController.setProcessValue(fabs(rightVelocity_)); rightPwmDuty_ = rightController.compute(); 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.compute(); rightPulses_ = rightQei.getPulses(); rightVelocity_ = (rightPulses_ - rightPrevPulses_) / PID_RATE; rightPrevPulses_ = rightPulses_; rightController.setProcessValue(rightVelocity_); rightPwmDuty_ = rightController.compute(); 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; } if (logIndex < 1024) { headingBuffer[logIndex] = imu.getYaw(); leftVelocityBuffer[logIndex] = leftVelocity_; rightVelocityBuffer[logIndex] = rightVelocity_; leftPositionBuffer[logIndex] = leftPulses_; rightPositionBuffer[logIndex] = rightPulses_; logIndex++; } } 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; for (int i = 0; i < logIndex; i++) { fprintf(logFile, "%i, %i, %f, %f, %f\n", leftPositionBuffer[i], rightPositionBuffer[i], leftVelocityBuffer[i], rightVelocityBuffer[i], headingBuffer[i]); } logIndex = 0; imu.reset(); 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); logIndex = 0; startHeading_ = imu.getYaw(); 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); logIndex = 0; 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_; logIndex = 0; 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_; logIndex = 0; state_ = STATE_ROTATING_COUNTER_CLOCKWISE; break; default: state_ = STATE_STATIONARY; break; } }