Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages | Examples

ArAnalogGyro.cpp

00001 /*
00002 MobileRobots Advanced Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004, 2005 ActivMedia Robotics LLC
00004 Copyright (C) 2006, 2007 MobileRobots Inc.
00005 
00006      This program is free software; you can redistribute it and/or modify
00007      it under the terms of the GNU General Public License as published by
00008      the Free Software Foundation; either version 2 of the License, or
00009      (at your option) any later version.
00010 
00011      This program is distributed in the hope that it will be useful,
00012      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014      GNU General Public License for more details.
00015 
00016      You should have received a copy of the GNU General Public License
00017      along with this program; if not, write to the Free Software
00018      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 If you wish to redistribute ARIA under different terms, contact 
00021 MobileRobots for information about a commercial version of ARIA at 
00022 robots@mobilerobots.com or 
00023 MobileRobots Inc, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 */
00025 
00026 #include "ariaOSDef.h"
00027 #include "ArCommands.h"
00028 #include "ArExport.h"
00029 #include "ArAnalogGyro.h"
00030 #include "ArRobot.h"
00031 #include "ArRobotConfigPacketReader.h"
00032 
00035 AREXPORT ArAnalogGyro::ArAnalogGyro(ArRobot *robot) : 
00036   myHandleGyroPacketCB(this, &ArAnalogGyro::handleGyroPacket),
00037   myEncoderCorrectCB(this, &ArAnalogGyro::encoderCorrect),
00038   myStabilizingCB(this, &ArAnalogGyro::stabilizingCallback)
00039 {
00040   myRobot = robot;
00041   myHandleGyroPacketCB.setName("ArAnalogGyro");
00042   myRobot->addStabilizingCB(&myStabilizingCB);
00043   // this scaling factor now comes from the parameter file
00044   myScalingFactor = 0;
00045   myHeading = 0;
00046   myReadingThisCycle = false;
00047 
00048   myAverageTotal = 0;
00049   myAverageCount = 0;
00050   myLastAverageTaken.setSec(0);
00051   myLastAverageTaken.setMSec(0);
00052   myLastAverage = 0;
00053   // nominal values
00054   myGyroSigma = .01;
00055   myInertialVarianceModel = 0.001;
00056   myRotVarianceModel = .25; // deg2/deg
00057   myTransVarianceModel = 4.0; // deg2/meter
00058   myAccumulatedDelta = 0;
00059   myIsActive = true;
00060   myHaveGottenData = false;
00061   myLogAnomalies = false;
00062   myGyroType = GYRO_NONE;
00063   myHasGyroOnlyMode = false;
00064   myHasNoData = true;
00065   if (myRobot->isConnected())
00066     stabilizingCallback();
00067 }
00068 
00069 AREXPORT ArAnalogGyro::~ArAnalogGyro()
00070 {
00071   myRobot->comInt(ArCommands::GYRO, 0);
00072   myRobot->remPacketHandler(&myHandleGyroPacketCB);
00073   myRobot->remStabilizingCB(&myStabilizingCB);
00074   myRobot->setEncoderCorrectionCallback(NULL);
00075 }
00076 
00077 AREXPORT void ArAnalogGyro::stabilizingCallback(void)
00078 {
00079   if (myRobot->getOrigRobotConfig() != NULL &&
00080       myRobot->getOrigRobotConfig()->getHasGyro() == 1)
00081   {
00082     myGyroType = GYRO_ANALOG_COMPUTER;
00083     myHasGyroOnlyMode = false;
00084     myHasNoData = false;
00085     myHaveGottenData = false;
00086     // moved these two here from above
00087     myRobot->setEncoderCorrectionCallback(&myEncoderCorrectCB);
00088     myRobot->addPacketHandler(&myHandleGyroPacketCB);
00089 
00090     myScalingFactor = myRobot->getRobotParams()->getGyroScaler();  
00091     
00092     if (!myRobot->isConnected())
00093       ArLog::log(ArLog::Normal, "Stabilizing gyro");
00094     if (!myRobot->isConnected() && myRobot->getStabilizingTime() < 3000)
00095       myRobot->setStabilizingTime(3000);
00096     myRobot->comInt(ArCommands::GYRO, 1);
00097   }
00098   else if (myRobot->getOrigRobotConfig() != NULL &&
00099        myRobot->getOrigRobotConfig()->getGyroType() == 2)
00100   {
00101     myGyroType = GYRO_ANALOG_CONTROLLER;
00102     myHasGyroOnlyMode = true;
00103     myHasNoData = true;
00104     myHaveGottenData = true;
00105     if (!myRobot->isConnected())
00106       ArLog::log(ArLog::Normal, "Stabilizing microcontroller gyro");
00107     myRobot->setStabilizingTime(2000);
00108     myRobot->setOdometryDelay(25);
00109   }
00110 }
00111 
00112 AREXPORT bool ArAnalogGyro::handleGyroPacket(ArRobotPacket *packet)
00113 {
00114   int numReadings;
00115   int i;
00116   double reading;
00117   int temperature;
00118   double rate;
00119   ArTime now;
00120 
00121   if (packet->getID() != 0x98)
00122     return false;
00123 
00124   numReadings = packet->bufToByte();
00125   if (numReadings > 0)
00126     myHaveGottenData = true;
00127   //packet->log();
00128   //printf("%d readings %d bytes ", numReadings, packet->getLength() - packet->getReadLength());
00129   for (i = 0; i < numReadings; i++)
00130   {
00131     reading = packet->bufToByte2();
00132     temperature = packet->bufToUByte();
00133 
00134     // if we haven't moved, check our average, to see if we've moved,
00135     // we see if the average is within .5% of the average and
00136     // if the velocity is less then 1 mm / sec and 
00137     // if the rotational velocity is less then 1 deg / sec
00138     //printf("%d %g %g %g %g\n", myAverageCount, myAverageTotal / myAverageCount, reading, myRobot->getVel(), myRobot->getRotVel());
00139     if ((myAverageCount == 0 || fabs(myAverageTotal / myAverageCount - reading) < myAverageTotal / myAverageCount * .005) &&
00140     fabs(myRobot->getVel()) < 1 && 
00141     fabs(myRobot->getRotVel()) < 1)
00142     {
00143       if (myAverageStarted.mSecSince() > 1000 && myAverageCount > 25)
00144       {
00145     //printf("new average\n");
00146     myLastAverage = myAverageTotal / myAverageCount;
00147     myLastAverageTaken.setToNow();
00148     myAverageTotal = 0;
00149     myAverageCount = 0;
00150     myAverageStarted.setToNow();
00151       }
00152       myAverageTotal += reading;
00153       myAverageCount++;
00154     }
00155     else
00156     {
00157       myAverageTotal = 0;
00158       myAverageCount = 0;
00159       myAverageStarted.setToNow();
00160     }
00161     
00162     if (myLastAverage == 0)
00163       continue;
00164     reading -= myLastAverage;
00165     rate = ((reading * 5.0 / 1023)) * 300 / 2.5 * myScalingFactor;
00166     rate *= -1;
00167 
00168     myTemperature = temperature;
00169     //printf("reading %10f rate %10f diff %10f temp %d, ave %g\n", reading, rate, rate * .025, temperature, myLastAverage);
00170 
00171     // if we're not moving and the reading is small disregard it
00172     if ((fabs(myRobot->getVel()) < 2 && fabs(myRobot->getRotVel()) < 2) &&
00173     ArMath::fabs(reading) < 2)      
00174     {
00175       rate = 0;
00176     }
00177     myHeading += rate * .025;
00178     //printf("rate %6.3f, reading %6.3f heading %6.3f\n", rate, reading, myHeading);
00179 
00180     myHeading = ArMath::fixAngle(myHeading);
00181 
00182     if (myTimeLastPacket != time(NULL)) 
00183     {
00184       myTimeLastPacket = time(NULL);
00185       myPacCount = myPacCurrentCount;
00186       myPacCurrentCount = 0;
00187     }
00188     myPacCurrentCount++;
00189     myReadingThisCycle = true;
00190     //printf("(%3d %3d)", reading, temperature);
00191   }
00192   //printf("\n");
00193   return true;
00194 }
00195 
00196 AREXPORT double ArAnalogGyro::encoderCorrect(ArPoseWithTime deltaPose)
00197 {
00198   ArPose ret;
00199 
00200   // variables
00201   double inertialVariance;
00202   double encoderVariance;
00203 
00204   double robotDeltaTh;
00205   double inertialDeltaTh;
00206   double deltaTh;
00207 
00208   /*
00209   ArPose lastPose;
00210   double lastTh;
00211   ArPose thisPose;
00212   double thisTh;
00213   */
00214   ArPoseWithTime zero(0.0, 0.0, 0.0);
00215 
00216 
00217   // if we didn't get a reading this take what we got at face value
00218   if (!myReadingThisCycle)
00219   {
00220     //ArLog::log(ArLog::Verbose, "ArAnalogGyro: no inertial reading, using encoder");
00221     myAccumulatedDelta += deltaPose.getTh();
00222     //printf("adding %f\n", myAccumulatedDelta);
00223     return deltaPose.getTh();
00224   }
00225 
00226   // 6/20/05 MPL added this fix
00227   robotDeltaTh = ArMath::fixAngle(myAccumulatedDelta + deltaPose.getTh());
00228   //printf("using %f %f %f\n", robotDeltaTh, myAccumulatedDelta, deltaPose.getTh());
00229 
00230   inertialVariance = (myGyroSigma * myGyroSigma * 10);
00231   // was: deltaPose.getTime().mSecSince(myLastAsked)/10.0);
00232 
00233 
00234   //printf("@ %10f %10f %10f %10f\n", multiplier, ArMath::subAngle(thisTh, lastTh), thisTh, lastTh);
00235   inertialDeltaTh = ArMath::subAngle(myHeading, myLastHeading);
00236 
00237   inertialVariance += fabs(inertialDeltaTh) * myInertialVarianceModel;
00238   encoderVariance = (fabs(deltaPose.getTh()) * myRotVarianceModel +
00239              deltaPose.findDistanceTo(zero) * myTransVarianceModel);
00240   
00241   
00242   if (myLogAnomalies)
00243   {
00244     if (fabs(inertialDeltaTh) < 1 && fabs(robotDeltaTh) < 1)
00245     {
00246 
00247     }
00248     else if (fabs(robotDeltaTh) < 1 && fabs(inertialDeltaTh) > 2)
00249       ArLog::log(ArLog::Normal, "ArAnalogGyro::anomaly: Gyro (%.1f) moved but encoder (%.1f) didn't, using gyro", inertialDeltaTh, robotDeltaTh);
00250     else if ((inertialDeltaTh < -1 && robotDeltaTh > 1) ||
00251          (robotDeltaTh < -1 && inertialDeltaTh > 1))
00252       ArLog::log(ArLog::Normal, "ArAnalogGyro::anomaly: gyro (%.1f) moved opposite of robot (%.1f)", inertialDeltaTh, robotDeltaTh);
00253     else if (fabs(robotDeltaTh) < fabs(inertialDeltaTh * .66666))
00254       ArLog::log(ArLog::Normal, "ArAnalogGyro::anomaly: robot (%.1f) moved less than gyro (%.1f)", robotDeltaTh, inertialDeltaTh);
00255     else if (fabs(inertialDeltaTh) < fabs(robotDeltaTh * .66666))
00256       ArLog::log(ArLog::Normal, "ArAnalogGyro::anomaly: gyro (%.1f) moved less than robot (%.1f)", inertialDeltaTh, robotDeltaTh);
00257   }
00258 
00259 
00260   //don't divide by 0, or close to it
00261   if (fabs(inertialVariance + encoderVariance) < .00000001)
00262     deltaTh = 0;
00263   // if we get no encoder readings, but we get gyro readings, just
00264   // believe the gyro (this case is new 6/20/05 MPL)
00265   else if (fabs(robotDeltaTh) < 1 && fabs(inertialDeltaTh) > 2)
00266     deltaTh = ArMath::fixAngle(inertialDeltaTh);
00267   else
00268     deltaTh = ArMath::fixAngle(
00269         (robotDeltaTh * 
00270          (inertialVariance / (inertialVariance + encoderVariance))) +
00271         (inertialDeltaTh *
00272          (encoderVariance / (inertialVariance + encoderVariance))));
00273 
00274   // now we need to compensate for the readings we got when we didn't
00275   // have gyro readings
00276   deltaTh -= myAccumulatedDelta;
00277   myReadingThisCycle = false;
00278   myLastHeading = myHeading;
00279   //printf("%6.3f %6.3f %6.3f\n", deltaTh, inertialDeltaTh, robotDeltaTh);
00280 
00281   myAccumulatedDelta = 0;
00282   
00283   if (myIsActive)
00284     return deltaTh;
00285   else
00286     return deltaPose.getTh();
00287 }
00288 
00289 
00290 AREXPORT void ArAnalogGyro::activate(void)
00291 { 
00292   if (!myIsActive || myIsGyroOnlyActive)
00293     ArLog::log(ArLog::Normal, "Activating gyro"); 
00294   myIsActive = true; 
00295   myIsGyroOnlyActive = false;
00296   if (myGyroType == GYRO_ANALOG_CONTROLLER)
00297     myRobot->comInt(ArCommands::GYRO, 1);
00298 }
00299 
00300 AREXPORT void ArAnalogGyro::deactivate(void)
00301 { 
00302   if (myIsActive || myIsGyroOnlyActive)
00303     ArLog::log(ArLog::Normal, "Dectivating gyro"); 
00304   myIsActive = false; 
00305   myIsGyroOnlyActive = false;
00306   if (myGyroType == GYRO_ANALOG_CONTROLLER)
00307     myRobot->comInt(ArCommands::GYRO, 0);
00308 }
00309 
00310 AREXPORT void ArAnalogGyro::activateGyroOnly(void)
00311 { 
00312   if (!myHasGyroOnlyMode)
00313   {
00314     ArLog::log(ArLog::Normal, 
00315            "An attempt was made (and rejected) to set gyro only mode on a gyro that cannot do that mode"); 
00316     return;
00317   }
00318   if (!myIsActive || !myIsGyroOnlyActive)
00319     ArLog::log(ArLog::Normal, "Activating gyro only"); 
00320   myIsActive = false; 
00321   myIsGyroOnlyActive = true;
00322   if (myGyroType == GYRO_ANALOG_CONTROLLER)
00323     myRobot->comInt(ArCommands::GYRO, 2);
00324 }

Generated on Tue Feb 20 10:51:38 2007 for Aria by  doxygen 1.4.0