Control for RenBuggy
Dependencies: PID PinDetect mbed
RenBuggy_PID.cpp
- Committer:
- salatron
- Date:
- 2014-03-06
- Revision:
- 2:cd7543fdcb8c
- Parent:
- 1:8a2a7adb3c5d
File content as of revision 2:cd7543fdcb8c:
/******************************************************************************* * RenBED PID Motor Control for RenBuggy * * Copyright (c) 2014 Sally Brown & Liz Lloyd * * * * 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. * * * * PID_Controller.cpp * * * *******************************************************************************/ #ifndef _PIDCONTROLLER_C #define _PIDCONTROLLER_C #include "RenBuggy_PID.h" PID_Stripes::PID_Stripes(PinName motorL, PinName motorR, PinName brakeL, PinName brakeR, PinName sensorL, PinName sensorR) : PID_Controller(motorL, motorR, brakeL, brakeR), m_senseL(sensorL), m_senseR(sensorR) { m_senseL.setSampleFrequency(1000); m_senseR.setSampleFrequency(1000); //If this is playing up, consider changing this to 1001? //It's 5 samples before it recognises it's held on. m_senseL.setSamplesTillHeld(5); m_senseR.setSamplesTillHeld(5); PID_Controller* basePointer = dynamic_cast<PID_Stripes*>(this); //Only when it's been held high and then goes low will it increment the number of counts. m_senseL.attach_deasserted_held(basePointer, &PID_Controller::countL); m_senseR.attach_deasserted_held(basePointer, &PID_Controller::countR); } PID_Magnet::PID_Magnet(PinName motorL, PinName motorR, PinName brakeL, PinName brakeR, PinName sensorL, PinName sensorR) : PID_Controller(motorL, motorR, brakeL, brakeR), m_senseL(sensorL), m_senseR(sensorR) { PID_Controller* basePointer = dynamic_cast<PID_Magnet*>(this); m_senseL.fall(basePointer, &PID_Controller::countL); m_senseR.fall(basePointer, &PID_Controller::countR); } PID_Controller::PID_Controller ( PinName motorL, PinName motorR, PinName brakeL, PinName brakeR ) : m_controllerL(1.0, 0.0, 0.0, RATE), //Kc, Ti, Td, interval m_controllerR(1.0, 0.0, 0.0, RATE), m_motorL(motorL), m_motorR(motorR), m_brakeL(brakeL), m_brakeR(brakeR), m_countsPerRev(16), //Default to 16 stripes m_wheelCircumference(16.96), //Default to 16.96 m_axleLength(13), m_stripesL(0), //Initialise the number of stripes to 0. m_stripesR(0), m_turnLeft(false), m_turnRight(false), m_fProportionLeft(0.0), m_fProportionRight(0.0) { setUpControllers(); } void PID_Controller::SetUpConstants(int countsPerRev, float wheelCircumference, float axleLength) { m_countsPerRev = countsPerRev; m_wheelCircumference = wheelCircumference; m_axleLength = axleLength; } void PID_Controller::Forwards(int distanceForward) { m_turnRight = false; m_turnLeft = false; bool moving = true; int CountsForward = distanceForward * (m_countsPerRev/m_wheelCircumference); m_rate.attach(this, &PID_Controller::doSomePID, RATE); //Attach the counter if it hasn't gone too far. Then hopefully just sit in a loop. m_stripesL = m_stripesR = 0; m_brakeR = m_brakeL = 0; m_fProportionLeft = m_fProportionRight = 1.0; while(moving) { if (CountsForward < m_stripesL) { m_motorL = 0.0; m_brakeL = 1; } if (CountsForward < m_stripesR) { m_motorR = 0.0; m_brakeR = 1; } if(CountsForward < m_stripesR && CountsForward < m_stripesL) { m_rate.detach(); moving = false; } } Stop(); return; } void PID_Controller::Left(int AngleLeft, int RadiusLeft) { m_turnRight = false; //Turning left, NOT turning right m_turnLeft = true; bool turning = true; m_rate.attach(this, &PID_Controller::doSomePID, RATE); m_brakeR = m_brakeL = 0; //Turning off the brakes is often quite fun. m_stripesL = m_stripesR = 0; int halfAxleLength = (m_axleLength + 1)/2; RadiusLeft = RadiusLeft < halfAxleLength ? halfAxleLength : RadiusLeft; AngleLeft = AngleLeft > 90 ? 90 : AngleLeft; float m_fDistanceL = (2*pi*(RadiusLeft - halfAxleLength))*(m_countsPerRev/m_wheelCircumference)/(360/AngleLeft); float m_fDistanceR = (2*pi*(RadiusLeft + halfAxleLength))*(m_countsPerRev/m_wheelCircumference)/(360/AngleLeft); //gives the length of the arc over which the wheel will travel, and translates that into a number of wheel stripes int LeftWheelDist = (int) m_fDistanceL; //Cast the distance into an int int RightWheelDist = (int) m_fDistanceR; m_fProportionLeft = (float)LeftWheelDist/(float)RightWheelDist; m_fProportionRight = (float)RightWheelDist/(float)LeftWheelDist; //When turning right, you only use the left wheel's proportion while (turning) { if (LeftWheelDist <= m_stripesL) //If the left motor has gone far enough { m_motorL = 0.0; //Stop the motor m_brakeL = 1; //Apply the brakes } if (RightWheelDist <= m_stripesR) { m_motorR = 0.0; m_brakeR = 1; } if(RightWheelDist <= m_stripesR && LeftWheelDist <= m_stripesL) { m_rate.detach(); turning = false; break; } } Stop(); } void PID_Controller::Right(int AngleRight, int RadiusRight) { m_turnRight = true; m_turnLeft = false; bool turning = true; m_rate.attach(this, &PID_Controller::doSomePID, RATE); m_brakeR = m_brakeL = 0; //Turning off the brakes is often quite fun. m_stripesL = m_stripesR = 0; int halfAxleLength = (m_axleLength + 1)/2; RadiusRight = RadiusRight < halfAxleLength ? halfAxleLength : RadiusRight; AngleRight = AngleRight > 90 ? 90 : AngleRight; float m_fDistanceL = (2*pi*(RadiusRight + halfAxleLength))*(m_countsPerRev/m_wheelCircumference)/(360/AngleRight); //Forcing it to an int beforehand didn't work. It twitches instead of going argh no, but it still doesn't really work. float m_fDistanceR = (2*pi*(RadiusRight - halfAxleLength))*(m_countsPerRev/m_wheelCircumference)/(360/AngleRight); int LeftWheelDist = (int) m_fDistanceL; int RightWheelDist = (int) m_fDistanceR; m_fProportionLeft = (float)LeftWheelDist/(float)RightWheelDist; m_fProportionRight = (float)RightWheelDist/(float)LeftWheelDist; while (turning) { if (LeftWheelDist <= m_stripesL) //If the left motor has gone far enough { m_motorL = 0.0; //Stop the motor m_brakeL = 1; //Apply the brakes } if (RightWheelDist <= m_stripesR) { m_motorR = 0.0; m_brakeR = 1; } if(RightWheelDist <= m_stripesR && LeftWheelDist <= m_stripesL) { m_rate.detach(); turning = false; break; } } Stop(); } void PID_Controller::Stop() { m_stripesL = 0; m_stripesR = 0; m_motorL = 0.0; m_motorR = 0.0; m_brakeL = 1; m_brakeR = 1; m_rate.detach(); } void PID_Controller::doSomePID() { PIDLeft(); PIDRight(); } void PID_Controller::PIDLeft() { float fSPL = 0.0; int SPL = 0; if(m_turnLeft) { fSPL = m_stripesR / m_fProportionRight; SPL = (int) fSPL; } else if(m_turnRight) { fSPL = m_stripesR * m_fProportionLeft; SPL = (int) fSPL; } else { SPL = m_stripesR; } m_controllerL.setProcessValue(m_stripesL); m_motorL = (m_controllerL.compute()); //PWM output * some speed proportion. May slow it down or speed it up.*/ m_controllerL.setSetPoint(SPL); } void PID_Controller::PIDRight() { float fSPR = 0.0; int SPR = 0; if(m_turnRight) //If you're turning right, the left wheel goes further, so use xProportionLeft { fSPR = m_stripesL / m_fProportionLeft; SPR = (int) fSPR; } else if(m_turnLeft) //If you're turning left, the right wheel goes further, so use xProportionRight { fSPR = m_stripesL * m_fProportionRight; SPR = (int) fSPR; } else { SPR = m_stripesL; } m_controllerR.setProcessValue(m_stripesR); //Set the process value (what it IS). m_motorR = (m_controllerR.compute()); //Calculate the PWM duty cycle m_controllerR.setSetPoint(SPR); //SPR = set point right. this sets the set point (what it SHOULD BE). } void PID_Controller::countL() { m_stripesL++; } void PID_Controller::countR() { m_stripesR++; } void PID_Controller::setUpControllers() { m_controllerL.setInputLimits(0.0, 200); m_controllerR.setInputLimits(0.0, 200); //Pwm output from 0.0 to 1.0 (PWM duty cycle %) m_controllerL.setOutputLimits(0.0, 1.0); m_controllerR.setOutputLimits(0.0, 1.0); //If there's a bias. FULL SPEED AHEAD. I don't know why this works but it does. m_controllerL.setBias(1.0); m_controllerR.setBias(1.0); //Set it to auto mode. m_controllerL.setMode(AUTO_MODE); m_controllerR.setMode(AUTO_MODE); } void PID_Controller::ConfigurePID(float p, float i, float d) { m_controllerL.setTunings(p, i, d); m_controllerR.setTunings(p, i, d); } #endif