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

ArRobot.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 "ArExport.h"
00027 #include "ariaOSDef.h"
00028 #include <time.h>
00029 #include <ctype.h>
00030 
00031 #include "ArRobot.h"
00032 #include "ArLog.h"
00033 #include "ArDeviceConnection.h"
00034 #include "ArTcpConnection.h"
00035 #include "ArSerialConnection.h"
00036 #include "ArLogFileConnection.h"
00037 #include "ariaUtil.h"
00038 #include "ArSocket.h"
00039 #include "ArCommands.h"
00040 #include "ArRobotTypes.h"
00041 #include "ArSignalHandler.h"
00042 #include "ArPriorityResolver.h"
00043 #include "ArAction.h"
00044 #include "ArRangeDevice.h"
00045 #include "ArRobotConfigPacketReader.h"
00046 #include "ariaInternal.h"
00047 
00069 AREXPORT ArRobot::ArRobot(const char *name, bool obsolete, 
00070               bool doSigHandle, bool normalInit,
00071               bool addAriaExitCallback) :
00072   myMotorPacketCB(this, &ArRobot::processMotorPacket),
00073   myEncoderPacketCB(this, &ArRobot::processEncoderPacket),
00074   myIOPacketCB(this, &ArRobot::processIOPacket),
00075   myPacketHandlerCB(this, &ArRobot::packetHandler),
00076   myActionHandlerCB(this, &ArRobot::actionHandler),
00077   myStateReflectorCB(this, &ArRobot::stateReflector),
00078   myRobotLockerCB(this, &ArRobot::robotLocker),
00079   myRobotUnlockerCB(this, &ArRobot::robotUnlocker),
00080   myKeyHandlerExitCB(this, &ArRobot::keyHandlerExit),
00081   myGetCycleWarningTimeCB(this, &ArRobot::getCycleWarningTime),
00082   myGetNoTimeWarningThisCycleCB(this, &ArRobot::getNoTimeWarningThisCycle),
00083   myBatteryAverager(20),
00084   myRealBatteryAverager(20),
00085   myAriaExitCB(this, &ArRobot::ariaExitCallback)
00086 {
00087   setName(name);
00088   myAriaExitCB.setName("ArRobotExit");
00089   myNoTimeWarningThisCycle = false;
00090   myGlobalPose.setPose(0, 0, 0);
00091 
00092   myParams = new ArRobotGeneric("");
00093 
00094   myMotorPacketCB.setName("ArRobot::motorPacket");
00095   myEncoderPacketCB.setName("ArRobot::encoderPacket");
00096   myIOPacketCB.setName("ArRobot::IOPacket");
00097 
00098   myPtz = NULL;
00099   myKeyHandler = NULL;
00100   myKeyHandlerCB = NULL;
00101 
00102   myConn = NULL;
00103 
00104   myOwnTheResolver = false;
00105 
00106   myBlockingConnectRun = false;
00107   myAsyncConnectFlag = false;
00108 
00109   myLogMovementSent = false;
00110   myLogMovementReceived = false;
00111   myLogVelocitiesReceived = false;
00112   myLogActions = false;
00113   myLastVel = 0;
00114   myLastRotVel = 0;
00115   myLastHeading = 0;
00116   myLastCalculatedRotVel = 0;
00117 
00118   myPacketsSentTracking = false;
00119   myPacketsReceivedTracking = false;
00120   myPacketsReceivedTrackingCount = false;
00121   myPacketsReceivedTrackingStarted.setToNow();
00122 
00123   myCycleTime = 100;
00124   myCycleWarningTime = 250;
00125   myConnectionCycleMultiplier = 2;
00126   myTimeoutTime = 8000;
00127   myStabilizingTime = 0;
00128   myCounter = 1;
00129   myResolver = NULL;
00130   myNumSonar = 0;
00131 
00132   myRequestedIOPackets = false;
00133   myRequestedEncoderPackets = false;
00134   myEncoderCorrectionCB = NULL;
00135 
00136   myCycleChained = true;
00137 
00138   myMoveDoneDist = 40;
00139   myHeadingDoneDiff = 3;
00140 
00141   myOrigRobotConfig = NULL;
00142   reset();
00143   if (normalInit)
00144     init();
00145   
00146   mySyncLoop.setRobot(this);
00147 
00148   if (doSigHandle)
00149     Aria::addRobot(this);
00150   if (addAriaExitCallback)
00151   {
00152     Aria::addExitCallback(&myAriaExitCB, 0);
00153     myAddedAriaExitCB = true;
00154   }
00155   else
00156   {
00157     myAddedAriaExitCB = false;
00158   }
00159 
00160   myConnectWithNoParams = false;
00161 }
00162 
00163 
00164 
00165 AREXPORT ArRobot::~ArRobot()
00166 {
00167   ArResolver::ActionMap::iterator it;
00168 
00169   stopRunning();
00170   delete mySyncTaskRoot;
00171   ArUtil::deleteSetPairs(mySonars.begin(), mySonars.end());
00172   Aria::delRobot(this);
00173 
00174   if (myKeyHandlerCB != NULL)
00175     delete myKeyHandlerCB;
00176 
00177   for (it = myActions.begin(); it != myActions.end(); ++it)
00178   {
00179     (*it).second->setRobot(NULL);
00180   }
00181 }
00182 
00183 
00188 AREXPORT void ArRobot::init(void)
00189 {
00190   setUpPacketHandlers();
00191   setUpSyncList();
00192   myOwnTheResolver = true;
00193   myResolver = new ArPriorityResolver;
00194 }
00195 
00206 AREXPORT void ArRobot::run(bool stopRunIfNotConnected)
00207 {
00208   if (mySyncLoop.getRunning())
00209   {
00210     ArLog::log(ArLog::Terse, 
00211            "The robot is already running, cannot run it again.");
00212     return;
00213   }
00214   mySyncLoop.setRunning(true);
00215   mySyncLoop.stopRunIfNotConnected(stopRunIfNotConnected);
00216   mySyncLoop.runInThisThread();
00217 }
00218 
00224 AREXPORT bool ArRobot::isRunning(void) const
00225 {
00226   return mySyncLoop.getRunning();
00227 }
00228 
00238 AREXPORT void ArRobot::runAsync(bool stopRunIfNotConnected)
00239 {
00240   if (mySyncLoop.getRunning())
00241   {
00242     ArLog::log(ArLog::Terse, 
00243            "The robot is already running, cannot run it again.");
00244     return;
00245   }
00246   mySyncLoop.stopRunIfNotConnected(stopRunIfNotConnected);
00247   // Joinable, but do NOT lower priority. The robot thread is the most
00248   // important one around.
00249   mySyncLoop.create(true, false);
00250 }
00251 
00260 AREXPORT void ArRobot::stopRunning(bool doDisconnect)
00261 {
00262   if (myKeyHandler != NULL)
00263     myKeyHandler->restore();
00264   mySyncLoop.stopRunning();
00265   myBlockingConnectRun = false;
00266   if (doDisconnect && (isConnected() || myIsStabilizing))
00267   {
00268     waitForRunExit();
00269     disconnect();
00270   }
00271   wakeAllWaitingThreads();
00272 }
00273 
00274 AREXPORT void ArRobot::setUpSyncList(void)
00275 {
00276   mySyncTaskRoot = new ArSyncTask("SyncTasks");
00277   mySyncTaskRoot->setWarningTimeCB(&myGetCycleWarningTimeCB);
00278   mySyncTaskRoot->setNoTimeWarningCB(&myGetNoTimeWarningThisCycleCB);
00279   mySyncTaskRoot->addNewLeaf("Packet Handler", 85, &myPacketHandlerCB);
00280   mySyncTaskRoot->addNewLeaf("Robot Locker", 70, &myRobotLockerCB);
00281   mySyncTaskRoot->addNewBranch("Sensor Interp", 65);
00282   mySyncTaskRoot->addNewLeaf("Action Handler", 55, &myActionHandlerCB);
00283   mySyncTaskRoot->addNewLeaf("State Reflector", 45, &myStateReflectorCB);
00284   mySyncTaskRoot->addNewBranch("User Tasks", 25);
00285   mySyncTaskRoot->addNewLeaf("Robot Unlocker", 20, &myRobotUnlockerCB);
00286 }
00287 
00288 
00289 AREXPORT void ArRobot::setUpPacketHandlers(void)
00290 {
00291   addPacketHandler(&myMotorPacketCB, ArListPos::FIRST);
00292   addPacketHandler(&myEncoderPacketCB, ArListPos::LAST);
00293   addPacketHandler(&myIOPacketCB, ArListPos::LAST);
00294 }
00295 
00296 void ArRobot::reset(void)
00297 {
00298   resetOdometer();
00299   myInterpolation.reset();
00300   myEncoderInterpolation.reset();
00301   if (myOrigRobotConfig != NULL)
00302     delete myOrigRobotConfig;
00303   myOrigRobotConfig = new ArRobotConfigPacketReader(this, true);
00304   myFirstEncoderPose = true;
00305   //myEncoderPose.setPose(0, 0, 0);
00306   //myEncoderPoseTaken.setToNow();
00307   //myRawEncoderPose.setPose(0, 0, 0);
00308   //myGlobalPose.setPose(0, 0, 0);
00309   //myEncoderTransform.setTransform(myEncoderPose, myGlobalPose);
00310   myTransVelMax = 0;
00311   myTransAccel = 0;
00312   myTransDecel = 0;
00313   myRotVelMax = 0;
00314   myRotAccel = 0;
00315   myRotDecel = 0;
00316 
00317   myRobotLengthFront = 0;
00318   myRobotLengthRear = 0;
00319 
00320   myLeftVel = 0;
00321   myRightVel = 0;
00322   myBatteryVoltage = 13;
00323   myBatteryAverager.clear();
00324   myBatteryAverager.add(myBatteryVoltage);
00325   myStallValue = 0;
00326   myControl = 0;
00327   myFlags = 0;
00328   myFaultFlags = 0;
00329   myHasFaultFlags = 0;
00330   myCompass = 0;
00331   myAnalogPortSelected = 0;
00332   myAnalog = 0;
00333   myDigIn = 0;
00334   myDigOut = 0;
00335   myIOAnalogSize = 0;
00336   myIODigInSize = 0;
00337   myIODigOutSize = 0;
00338   myLastIOPacketReceivedTime.setSec(0);
00339   myLastIOPacketReceivedTime.setMSec(0);
00340   myVel = 0;
00341   myRotVel = 0;
00342   myChargeState = CHARGING_UNKNOWN;
00343   myLastX = 0;
00344   myLastY = 0;
00345   myLastTh = 0;
00346   mySentPulse = false;
00347   myIsConnected = false;
00348   myIsStabilizing = false;
00349 
00350   myTransVal = 0;
00351   myTransVal2 = 0;
00352   myTransType = TRANS_NONE;
00353   myLastTransVal = 0;
00354   myLastTransVal2 = 0;
00355   myLastTransType = TRANS_NONE;
00356   myLastTransSent.setToNow();
00357   myActionTransSet = false;
00358   myLastActionRotStopped = false;
00359   myLastActionRotHeading = false;
00360 
00361   myRotVal = 0;
00362   myLastRotVal = 0;
00363   myRotType = ROT_NONE;
00364   myLastRotType = ROT_NONE;
00365   myLastRotSent.setToNow();
00366   myActionRotSet = false;
00367 
00368   myLastPulseSent.setToNow();
00369 
00370   myDirectPrecedenceTime = 0;
00371   myStateReflectionRefreshTime = 500;
00372 
00373   myActionDesired.reset();
00374 
00375   myMotorPacCurrentCount = 0;
00376   myMotorPacCount = 0;
00377   myTimeLastMotorPacket = 0;
00378 
00379   mySonarPacCurrentCount = 0;
00380   mySonarPacCount = 0;
00381   myTimeLastSonarPacket = 0;
00382 
00383   myLeftEncoder = 0;
00384   myRightEncoder = 0;
00385 
00386   myWarnedAboutExtraSonar = false;
00387   myOdometryDelay = 0;
00388 }
00389 
00390 AREXPORT void ArRobot::setTransVelMax(double vel)
00391 {
00392   if (vel > myAbsoluteMaxTransVel)
00393   {
00394     ArLog::log(ArLog::Terse, "ArRobot: setTransVelMax of %g is over the absolute max of %g, capping it", vel, myAbsoluteMaxTransVel);
00395     vel = myAbsoluteMaxTransVel;
00396   }
00397   myTransVelMax = vel;
00398 }
00399 
00400 AREXPORT void ArRobot::setTransAccel(double acc)
00401 {
00402   if (acc > myAbsoluteMaxTransAccel)
00403   {
00404     ArLog::log(ArLog::Terse, "ArRobot: setTransAccel of %g is over the absolute max of %g, capping it", acc, myAbsoluteMaxTransAccel);
00405     acc = myAbsoluteMaxTransAccel;
00406   }
00407   myTransAccel = acc;
00408 }
00409 
00410 AREXPORT void ArRobot::setTransDecel(double decel)
00411 {
00412   if (fabs(decel) > myAbsoluteMaxTransDecel)
00413   {
00414     ArLog::log(ArLog::Terse, "ArRobot: setTransDecel of %g is over the absolute max of %g, capping it", decel, myAbsoluteMaxTransDecel);
00415     decel = myAbsoluteMaxTransDecel;
00416   }
00417   myTransDecel = ArMath::fabs(decel);
00418 }
00419 
00420 AREXPORT void ArRobot::setRotVelMax(double vel)
00421 {
00422   if (vel > myAbsoluteMaxRotVel)
00423   {
00424     ArLog::log(ArLog::Terse, "ArRobot: rotVelMax of %g is over the absolute max of %g, capping it", vel, myAbsoluteMaxRotVel);
00425     vel = myAbsoluteMaxRotVel;
00426   }
00427   myRotVelMax = vel;
00428 }
00429 
00430 AREXPORT void ArRobot::setRotAccel(double acc)
00431 {
00432   if (acc > myAbsoluteMaxRotAccel)
00433   {
00434     ArLog::log(ArLog::Terse, "ArRobot: setRotAccel of %g is over the absolute max of %g, capping it", acc, myAbsoluteMaxRotAccel);
00435     acc = myAbsoluteMaxRotAccel;
00436   }
00437   myRotAccel = acc;
00438 }
00439 
00440 AREXPORT void ArRobot::setRotDecel(double decel)
00441 {
00442   if (fabs(decel) > myAbsoluteMaxRotDecel)
00443   {
00444     ArLog::log(ArLog::Terse, "ArRobot: setRotDecel of %g is over the absolute max of %g, capping it", decel, myAbsoluteMaxRotDecel);
00445     decel = myAbsoluteMaxRotDecel;
00446   }
00447   myRotDecel = ArMath::fabs(decel);
00448 }
00449 
00450 AREXPORT double ArRobot::getTransVelMax(void) const
00451 {
00452   return myTransVelMax;
00453 }
00454 
00455 AREXPORT double ArRobot::getTransAccel(void) const
00456 {
00457   return myTransAccel;
00458 }
00459 
00460 AREXPORT double ArRobot::getTransDecel(void) const
00461 {
00462   return myTransDecel;
00463 }
00464 
00465 AREXPORT double ArRobot::getRotVelMax(void) const
00466 {
00467   return myRotVelMax;
00468 }
00469 
00470 AREXPORT double ArRobot::getRotAccel(void) const
00471 {
00472   return myRotAccel;
00473 }
00474 
00475 AREXPORT double ArRobot::getRotDecel(void) const
00476 {
00477   return myRotDecel;
00478 }
00479 
00488 AREXPORT void ArRobot::setDeviceConnection(ArDeviceConnection *connection)
00489 {
00490   myConn = connection;
00491   mySender.setDeviceConnection(myConn);
00492   myReceiver.setDeviceConnection(myConn);
00493 }
00494 
00503 AREXPORT ArDeviceConnection *ArRobot::getDeviceConnection(void) const
00504 {
00505   return myConn;
00506 }
00507 
00518 AREXPORT void ArRobot::setConnectionTimeoutTime(int mSecs)
00519 {
00520   if (mSecs > 0)
00521     myTimeoutTime = mSecs;
00522   else
00523     myTimeoutTime = 0;
00524 }
00525 
00532 AREXPORT int ArRobot::getConnectionTimeoutTime(void) const
00533 {
00534   return myTimeoutTime;
00535 }
00536 
00542 AREXPORT ArTime ArRobot::getLastPacketTime(void) const
00543 {
00544   return myLastPacketReceivedTime;
00545 }
00577 AREXPORT bool ArRobot::asyncConnect(void)
00578 {
00579   if (!mySyncLoop.getRunning() || isConnected())
00580     return false;
00581   
00582   myAsyncConnectFlag = true;
00583   myBlockingConnectRun = false;
00584   myAsyncConnectState = -1;
00585   return true;
00586 }
00587 
00618 AREXPORT bool ArRobot::blockingConnect(void)
00619 {
00620   int ret = 0;
00621 
00622   lock();
00623   if (myIsConnected)
00624     disconnect();
00625   myBlockingConnectRun = true;
00626   myAsyncConnectState = -1;
00627   while ((ret = asyncConnectHandler(true)) == 0 && myBlockingConnectRun)
00628     ArUtil::sleep(ArMath::roundInt(getCycleTime() * .80));
00629   unlock();
00630   if (ret == 1)
00631     return true;
00632   else
00633     return false;
00634 }
00635 
00651 AREXPORT int ArRobot::asyncConnectHandler(bool tryHarderToConnect)
00652 {
00653   int ret = 0;
00654   ArRobotPacket *packet;
00655   ArRobotPacket *tempPacket = NULL;
00656   char robotSubType[255];
00657   int i;
00658   int len;
00659   std::string str;
00660   ArTime endTime;
00661   int timeToWait;
00662   ArSerialConnection *serConn;
00663 
00664   endTime.setToNow();
00665   endTime.addMSec(getCycleTime()*myConnectionCycleMultiplier);
00666   
00667   myNoTimeWarningThisCycle = true;
00668 
00669   // if this is -1, then we're doing initialization stuff, then returning
00670   if (myAsyncConnectState == -1)
00671   {
00672     myAsyncConnectSentChangeBaud = false;
00673     myAsyncConnectNoPacketCount = 0;
00674     myAsyncConnectTimesTried = 0;
00675     reset();
00676     if (myConn == NULL)
00677     {
00678       ArLog::log(ArLog::Terse, "Cannot connect, no connection has been set.");
00679       failedConnect();
00680       return 2;
00681     }
00682     
00683     if (myConn->getStatus() != ArDeviceConnection::STATUS_OPEN) 
00684     {
00685       if (!myConn->openSimple())
00686       {
00687     /*str = myConn->getStatusMessage(myConn->getStatus());
00688       ArLog::log(ArLog::Terse, "Trying to connect to robot but connection not opened, it is %s", str.c_str());*/
00689         ArLog::log(ArLog::Terse, 
00690                    "Could not connect, because open on the device connection failed.");
00691         failedConnect();
00692         return 2;
00693       }
00694     }
00695 
00696     // check for log file connection: just return success
00697     if (dynamic_cast<ArLogFileConnection *>(myConn))
00698     {
00699       ArLogFileConnection *con = dynamic_cast<ArLogFileConnection *>(myConn);
00700       myRobotName = con->myName;
00701       myRobotType = con->myType;
00702       myRobotSubType = con->mySubtype;
00703       if (con->havePose)        // we know where to move
00704         moveTo(con->myPose);
00705       setCycleChained(false);   // don't process packets all at once
00706       madeConnection();
00707       finishedConnection();
00708       return 1;
00709     }
00710 
00711 
00712     if (dynamic_cast<ArSerialConnection *>(myConn))
00713     {
00714       myConn->write("WMS2\15", strlen("WMS2\15"));
00715     }
00716     // here we're flushing out all previously received packets
00717     while ( endTime.mSecTo() > 0 && myReceiver.receivePacket(0) != NULL);
00718 
00719     myAsyncConnectState = 0;
00720     return 0;
00721   }
00722 
00723   if (myAsyncConnectState >= 3)
00724   {
00725     bool handled;
00726     std::list<ArRetFunctor1<bool, ArRobotPacket *> *>::iterator it;
00727     while ((packet = myReceiver.receivePacket(0)) != NULL)
00728     {
00729       //printf("0x%x\n", packet->getID());
00730       for (handled = false, it = myPacketHandlerList.begin(); 
00731        it != myPacketHandlerList.end() && handled == false; 
00732        it++)
00733       {
00734     if ((*it) != NULL && (*it)->invokeR(packet)) 
00735       handled = true;
00736     else
00737       packet->resetRead();
00738       }
00739     }
00740   }
00741 
00742   if (myAsyncConnectState == 3)
00743   {
00744     //if (!myOrigRobotConfig->hasPacketBeenRequested())
00745     if (!myOrigRobotConfig->hasPacketArrived())
00746     {
00747       myOrigRobotConfig->requestPacket();
00748     }
00749     // if we've gotten our config packet or if we've timed out then
00750     // set our vel and acc/decel params and skip to the next part
00751     if (myOrigRobotConfig->hasPacketArrived() || 
00752     myAsyncStartedConnection.mSecSince() > 1000)
00753     {
00754       bool gotConfig;
00755       // if we have data from the robot use that
00756       if (myOrigRobotConfig->hasPacketArrived())
00757       {
00758     gotConfig = true;
00759     setAbsoluteMaxTransVel(myOrigRobotConfig->getTransVelTop());
00760     setAbsoluteMaxTransAccel(myOrigRobotConfig->getTransAccelTop());
00761     setAbsoluteMaxTransDecel(myOrigRobotConfig->getTransAccelTop());
00762     setAbsoluteMaxRotVel(myOrigRobotConfig->getRotVelTop());
00763     setAbsoluteMaxRotAccel(myOrigRobotConfig->getRotAccelTop());
00764     setAbsoluteMaxRotDecel(myOrigRobotConfig->getRotAccelTop());
00765     setTransVelMax(myOrigRobotConfig->getTransVelMax());
00766     setTransAccel(myOrigRobotConfig->getTransAccel());
00767     setTransDecel(myOrigRobotConfig->getTransDecel());
00768     setRotVelMax(myOrigRobotConfig->getRotVelMax());
00769     setRotAccel(myOrigRobotConfig->getRotAccel());
00770     setRotDecel(myOrigRobotConfig->getRotDecel());
00771       }
00772       // if our absolute maximums weren't set then set them
00773       else
00774       {
00775     gotConfig = false;
00776     setAbsoluteMaxTransVel(myParams->getAbsoluteMaxVelocity());
00777     setAbsoluteMaxTransAccel(1000);
00778     setAbsoluteMaxTransDecel(1000);
00779     setAbsoluteMaxRotVel(myParams->getAbsoluteMaxRotVelocity());
00780     setAbsoluteMaxRotAccel(100);
00781     setAbsoluteMaxRotDecel(100);
00782       }
00783       // okay we got in that data, now put over it any of the things
00784       // that we got from the robot parameter file... if we don't have
00785       // max vels from above or the parameters then use the absolutes
00786       // which we do have for everything
00787       if (ArMath::fabs(myParams->getTransVelMax()) > 1)
00788     setTransVelMax(myParams->getTransVelMax());
00789       else if (!gotConfig)
00790     setTransVelMax(myParams->getAbsoluteMaxVelocity());
00791       if (ArMath::fabs(myParams->getRotVelMax()) > 1)
00792     setRotVelMax(myParams->getRotVelMax());
00793       else if (!gotConfig)
00794     setRotVelMax(myParams->getAbsoluteMaxRotVelocity());
00795       if (ArMath::fabs(myParams->getTransAccel()) > 1)
00796     setTransAccel(myParams->getTransAccel());
00797       if (ArMath::fabs(myParams->getTransDecel()) > 1)
00798     setTransDecel(myParams->getTransDecel());
00799       if (ArMath::fabs(myParams->getRotAccel()) > 1)
00800     setRotAccel(myParams->getRotAccel());
00801       if (ArMath::fabs(myParams->getRotDecel()) > 1)
00802     setRotDecel(myParams->getRotDecel());
00803       myAsyncConnectState = 4;
00804     }
00805     else
00806       return 0;
00807   }
00808   // we want to see if we should switch baud
00809   if (myAsyncConnectState == 4)
00810   {
00811     serConn = dynamic_cast<ArSerialConnection *>(myConn);
00812     // if we didn't get a config packet or we can't change the baud or
00813     // we aren't using a serial port then don't switch the baud
00814     if (!myOrigRobotConfig->hasPacketArrived() || 
00815     !myOrigRobotConfig->getResetBaud() || 
00816     serConn == NULL ||
00817     myParams->getSwitchToBaudRate() == 0)
00818     {
00819       // if we're using a serial connection store our baud rate
00820       if (serConn != NULL)
00821     myAsyncConnectStartBaud = serConn->getBaud();
00822       myAsyncConnectState = 5;
00823     }
00824     // if we did get a packet and can change baud send the command
00825     else if (!myAsyncConnectSentChangeBaud)
00826     {
00827       // if we're using a serial connection store our baud rate
00828       if (serConn != NULL)
00829     myAsyncConnectStartBaud = serConn->getBaud();
00830 
00831       int baudNum = -1;
00832       
00833       // first suck up all the packets we have now
00834       while ((packet = myReceiver.receivePacket(0)) != NULL);
00835       if (myParams->getSwitchToBaudRate() == 9600)
00836     baudNum = 0;
00837       else if (myParams->getSwitchToBaudRate() == 19200)
00838     baudNum = 1;
00839       else if (myParams->getSwitchToBaudRate() == 38400)
00840     baudNum = 2;
00841       else if (myParams->getSwitchToBaudRate() == 57600)
00842     baudNum = 3;
00843       else if (myParams->getSwitchToBaudRate() == 115200)
00844     baudNum = 4;
00845       else
00846       {
00847     ArLog::log(ArLog::Normal, "Warning: SwitchToBaud is set to %d baud, ignoring.",
00848            myParams->getSwitchToBaudRate());
00849     ArLog::log(ArLog::Normal, "\tGood bauds are 9600 19200 38400 56800 116200.");
00850     myAsyncConnectState = 5;
00851     baudNum = -1;
00852     return 0;
00853       }
00854       if (baudNum != -1)
00855       {
00856     // now switch it over
00857     comInt(ArCommands::HOSTBAUD, baudNum);
00858     ArUtil::sleep(10);
00859     myAsyncConnectSentChangeBaud = true;
00860     myAsyncConnectStartedChangeBaud.setToNow();
00861     serConn->setBaud(myParams->getSwitchToBaudRate());
00862     //serConn->setBaud(19200);
00863     ArUtil::sleep(10);
00864     com(0);
00865     return 0;
00866       }
00867     }
00868     // if we did send the command then wait and see if we get any packets back
00869     else
00870     {
00871       packet = myReceiver.receivePacket(100);
00872       com(0);
00873       // if we got any packet we're good
00874       if (packet != NULL)
00875       {
00876     myAsyncConnectState = 5;
00877       }
00878       // if we didn't get it and its been 500 ms then fail
00879       else if (myAsyncConnectStartedChangeBaud.mSecSince() > 900)
00880       {
00881     ArLog::log(ArLog::Verbose, "Controller did not switch to baud, reset to %d baud.", myAsyncConnectStartBaud);
00882     serConn->setBaud(myAsyncConnectStartBaud);
00883     myAsyncConnectState = 5;
00884       }
00885       else
00886     return 0;
00887     }    
00888   }
00889 
00890   if (myAsyncConnectState == 5)
00891   {
00892     if (!myIsStabilizing)
00893       startStabilization();
00894     if (myStabilizingTime == 0 || 
00895     myStartedStabilizing.mSecSince() > myStabilizingTime)
00896     {
00897       finishedConnection();
00898       return 1;
00899     }
00900     else
00901       return 0;
00902   }
00903 
00904   // here we've gone beyond the initialization, so read set a time limit,
00905   // read in one packet, then if its a bad packet type, read in all the 
00906   // packets there are to read... if its a good packet, continue with sequence
00907   myAsyncConnectTimesTried++;
00908   ArLog::log(ArLog::Normal, "Syncing %d", myAsyncConnectState);
00909   mySender.com(myAsyncConnectState);
00910   //  packet = myReceiver.receivePacket(endTime.mSecTo());
00911   packet = myReceiver.receivePacket(1000);
00912   
00913   if (packet != NULL) 
00914   {
00915     ret = packet->getID();
00916     //printf("Got a packet %d\n", ret);
00917     
00918     if (ret == 50)
00919     {
00920       ArLog::log(ArLog::Normal, "Attempting to close previous connection.");
00921       comInt(ArCommands::CLOSE,1);
00922       while (endTime.mSecTo() > 0)
00923       {
00924     timeToWait = endTime.mSecTo();
00925     if (timeToWait < 0)
00926       timeToWait = 0;
00927     tempPacket = myReceiver.receivePacket(timeToWait);
00928     if (tempPacket != NULL)
00929       ArLog::log(ArLog::Verbose, "Got in another packet!");
00930     if (tempPacket != NULL && tempPacket->getID() == 50)
00931       comInt(ArCommands::CLOSE,1);
00932       }
00933       myAsyncConnectState = 0;
00934     } 
00935     else if (ret == 255)
00936     {
00937       ArLog::log(ArLog::Normal, "Attempting to correct syncCount");
00938       /*
00939       while (endTime.mSecTo() > 0)
00940       {
00941     timeToWait = endTime.mSecTo();
00942     if (timeToWait < 0)
00943       timeToWait = 0;
00944     tempPacket = myReceiver.receivePacket(timeToWait);
00945     if (tempPacket != NULL)
00946       ArLog::log(ArLog::Verbose, "Got in another packet!");
00947       }
00948       */
00949       while ((tempPacket = myReceiver.receivePacket(0)) != NULL);
00950 
00951       if (tempPacket != NULL && tempPacket->getID() == 0)
00952     myAsyncConnectState = 1;
00953       else
00954     myAsyncConnectState = 0;
00955       return 0;
00956     } 
00957     else if  (ret != myAsyncConnectState++)
00958     {
00959       myAsyncConnectState = 0;
00960     }
00961   }
00962   else 
00963   {
00964     ArLog::log(ArLog::Normal, "No packet.");
00965     myAsyncConnectNoPacketCount++;
00966     if ((myAsyncConnectNoPacketCount > 5
00967      && myAsyncConnectNoPacketCount >= myAsyncConnectTimesTried)
00968     || (myAsyncConnectNoPacketCount > 10))
00969     {
00970       ArLog::log(ArLog::Terse, "Could not connect, no robot responding.");
00971       failedConnect();
00972       return 2;
00973     }
00974 
00975       /* This code to connect the radio modems should never really be needed 
00976      so is being removed for now
00977      if (myAsyncConnectNoPacketCount >= 4)
00978      {
00979      
00980      if (tryHarderToConnect && dynamic_cast<ArSerialConnection *>(myConn))
00981      {
00982      ArLog::log(ArLog::Normal, 
00983      "Radio modem may not connected, trying to connect it.");
00984      ArUtil::sleep(1000);
00985      myConn->write("|||\15", strlen("!!!\15"));
00986      ArUtil::sleep(60);
00987      myConn->write("WMN\15", strlen("WMN\15"));
00988      ArUtil::sleep(60);
00989      myConn->write("WMS2\15", strlen("WMS2\15"));
00990      ArUtil::sleep(1000);
00991      } 
00992      else if (dynamic_cast<ArSerialConnection *>(myConn))
00993      {
00994      ArLog::log(ArLog::Normal,
00995      "Radio modem may not connected, trying to connect it.");
00996      myConn->write("WMS2\15", strlen("WMS2\15"));
00997      ArUtil::sleep(60);
00998      }
00999      }
01000       */
01001     
01002     // If we get no response first we dump close commands at the thing
01003     // in different bauds (if its a serial connection)
01004     if (myAsyncConnectNoPacketCount == 2 && 
01005     myAsyncConnectNoPacketCount >= myAsyncConnectTimesTried &&
01006     (serConn = dynamic_cast<ArSerialConnection *>(myConn)) != NULL)
01007     {
01008       int origBaud;
01009       ArLog::log(ArLog::Normal, "Trying to close possible old connection");
01010       origBaud = serConn->getBaud();
01011       serConn->setBaud(9600);
01012       comInt(ArCommands::CLOSE,1);
01013       ArUtil::sleep(3);
01014       serConn->setBaud(38400);
01015       comInt(ArCommands::CLOSE,1);
01016       ArUtil::sleep(3);
01017       serConn->setBaud(115200);
01018       comInt(ArCommands::CLOSE,1);
01019       ArUtil::sleep(3);
01020       serConn->setBaud(19200);
01021       comInt(ArCommands::CLOSE,1);
01022       ArUtil::sleep(3);
01023       serConn->setBaud(57600);
01024       comInt(ArCommands::CLOSE,1);
01025       ArUtil::sleep(3);
01026       serConn->setBaud(origBaud);
01027     }
01028 
01029     if (myAsyncConnectNoPacketCount > 3)
01030     {
01031       ArLog::log(ArLog::Normal,
01032          " Robot may be connected but not open, trying to dislodge.");
01033       mySender.comInt(ArCommands::OPEN,1);
01034     }
01035     
01036     myAsyncConnectState = 0;
01037   }
01038   // if we've connected and have a packet get the connection
01039   // information from it
01040   if (myAsyncConnectState == 3 && packet != NULL) 
01041   {
01042     char nameBuf[512];
01043     ArLog::log(ArLog::Terse, "Connected to robot.");
01044     packet->bufToStr(nameBuf, 512);
01045     myRobotName = nameBuf;
01046     ArLog::log(ArLog::Normal, "Name: %s", myRobotName.c_str());
01047     packet->bufToStr(nameBuf, 512);
01048     myRobotType = nameBuf;
01049     ArLog::log(ArLog::Normal, "Type: %s", myRobotType.c_str());
01050     packet->bufToStr(nameBuf, 512);
01051     myRobotSubType = nameBuf;
01052     strcpy(robotSubType, myRobotSubType.c_str());
01053     len = strlen(robotSubType);
01054     for (i = 0; i < len; i++)
01055       robotSubType[i] = tolower(robotSubType[i]);
01056     myRobotSubType = robotSubType;
01057     ArLog::log(ArLog::Normal, "Subtype: %s", myRobotSubType.c_str());
01058     ArUtil::sleep(getCycleTime());
01059     mySender.comInt(ArCommands::OPEN,1);
01060     if (!madeConnection())
01061     {
01062       mySender.comInt(ArCommands::CLOSE,1);
01063       failedConnect();
01064       return 2;
01065     }
01066 
01067     // now we return off so we can handle the rest of connecting, if
01068     // you're just using this for your own connections you can skip
01069     // this part because its really connected now
01070     myAsyncStartedConnection.setToNow();
01071     return asyncConnectHandler(tryHarderToConnect);
01072   }
01073   if (myAsyncConnectTimesTried > 50)
01074   {
01075     failedConnect();
01076     return 2;
01077   }
01078   return 0;
01079 }
01080 
01084 AREXPORT bool ArRobot::loadParamFile(const char *file)
01085 {
01086   if (myParams != NULL)
01087     delete myParams;
01088 
01089   myParams = new ArRobotGeneric("");
01090   if (!myParams->parseFile(file, false, true))
01091   {
01092     ArLog::log(ArLog::Normal, "ArRobot::loadParamFile: Could not find file '%s' to load.", file);
01093     return false;
01094   }
01095   processParamFile();
01096   ArLog::log(ArLog::Normal, "Loaded robot parameters from %s.", file);
01097   return true;
01098 }
01099 
01100 AREXPORT void ArRobot::processParamFile(void)
01101 {
01102   for (int i = 0; i < myParams->getNumSonar(); ++i)
01103   {
01104     //printf("sonar %d %d %d %d\n", i, myParams->getSonarX(i),
01105     //myParams->getSonarY(i), myParams->getSonarTh(i));
01106     if (mySonars.find(i) == mySonars.end())
01107     {
01108       mySonars[i] = new ArSensorReading(myParams->getSonarX(i),
01109                     myParams->getSonarY(i), 
01110                     myParams->getSonarTh(i));
01111       mySonars[i]->setIgnoreThisReading(true);
01112     }
01113     else
01114     {
01115       mySonars[i]->resetSensorPosition(myParams->getSonarX(i),
01116                       myParams->getSonarY(i), 
01117                       myParams->getSonarTh(i));
01118       mySonars[i]->setIgnoreThisReading(true);
01119     }
01120     if ((i + 1) > myNumSonar)
01121       myNumSonar = i + 1;
01122   }
01123   //myRobotType = myParams->getClassName();
01124   //myRobotSubType = myParams->getSubClassName();
01125   myAbsoluteMaxTransVel = myParams->getAbsoluteMaxVelocity();
01126   myAbsoluteMaxRotVel = myParams->getAbsoluteMaxRotVelocity();
01127 
01128   if (myParams->getRobotLengthFront() == 0)
01129     myRobotLengthFront = myParams->getRobotLength() / 2.0;
01130   else
01131     myRobotLengthFront = myParams->getRobotLengthFront();
01132 
01133   if (myParams->getRobotLengthRear() == 0)
01134     myRobotLengthRear = myParams->getRobotLength() / 2.0;
01135   else
01136     myRobotLengthRear = myParams->getRobotLengthRear();
01137 }
01138 
01139 
01140 AREXPORT bool ArRobot::madeConnection(void)
01141 {
01142   std::string subTypeParamName;
01143   std::string paramFileName;
01144   bool loadedSubTypeParam;
01145   bool loadedNameParam;
01146   bool hadDefault = true;
01147   
01148   if (myParams != NULL)
01149     delete myParams;
01150   
01151   // Find the robot parameters to load and get them into the structure we have
01152   if (ArUtil::strcmp(myRobotSubType, "p2dx") == 0)
01153     myParams = new ArRobotP2DX;
01154   else if (ArUtil::strcmp(myRobotSubType, "p2ce") == 0)
01155     myParams = new ArRobotP2CE;
01156   else if (ArUtil::strcmp(myRobotSubType, "p2de") == 0)
01157     myParams = new ArRobotP2DXe;
01158   else if (ArUtil::strcmp(myRobotSubType, "p2df") == 0)
01159     myParams = new ArRobotP2DF;
01160   else if (ArUtil::strcmp(myRobotSubType, "p2d8") == 0)
01161     myParams = new ArRobotP2D8;
01162   else if (ArUtil::strcmp(myRobotSubType, "amigo") == 0)
01163     myParams = new ArRobotAmigo;
01164   else if (ArUtil::strcmp(myRobotSubType, "amigo-sh") == 0)
01165     myParams = new ArRobotAmigoSh;
01166   else if (ArUtil::strcmp(myRobotSubType, "p2at") == 0)
01167     myParams = new ArRobotP2AT;
01168   else if (ArUtil::strcmp(myRobotSubType, "p2at8") == 0)
01169     myParams = new ArRobotP2AT8;
01170   else if (ArUtil::strcmp(myRobotSubType, "p2it") == 0)
01171     myParams = new ArRobotP2IT;
01172   else if (ArUtil::strcmp(myRobotSubType, "p2pb") == 0)
01173     myParams = new ArRobotP2PB;
01174   else if (ArUtil::strcmp(myRobotSubType, "p2pp") == 0)
01175     myParams = new ArRobotP2PP;
01176   else if (ArUtil::strcmp(myRobotSubType, "p3at") == 0)
01177     myParams = new ArRobotP3AT;
01178   else if (ArUtil::strcmp(myRobotSubType, "p3dx") == 0)
01179     myParams = new ArRobotP3DX;
01180   else if (ArUtil::strcmp(myRobotSubType, "perfpb") == 0)
01181     myParams = new ArRobotPerfPB;
01182   else if (ArUtil::strcmp(myRobotSubType, "pion1m") == 0)
01183     myParams = new ArRobotPion1M;
01184   else if (ArUtil::strcmp(myRobotSubType, "pion1x") == 0)
01185     myParams = new ArRobotPion1X;
01186   else if (ArUtil::strcmp(myRobotSubType, "psos1m") == 0)
01187     myParams = new ArRobotPsos1M;
01188   else if (ArUtil::strcmp(myRobotSubType, "psos43m") == 0)
01189     myParams = new ArRobotPsos43M;
01190   else if (ArUtil::strcmp(myRobotSubType, "psos1x") == 0)
01191     myParams = new ArRobotPsos1X;
01192   else if (ArUtil::strcmp(myRobotSubType, "pionat") == 0)
01193     myParams = new ArRobotPionAT;
01194   else if (ArUtil::strcmp(myRobotSubType, "mappr") == 0)
01195     myParams = new ArRobotMapper;
01196   else if (ArUtil::strcmp(myRobotSubType, "powerbot") == 0)
01197     myParams = new ArRobotPowerBot;
01198   else if (ArUtil::strcmp(myRobotSubType, "p2d8+") == 0)
01199     myParams = new ArRobotP2D8Plus;
01200   else if (ArUtil::strcmp(myRobotSubType, "p2at8+") == 0)
01201     myParams = new ArRobotP2AT8Plus;
01202   else if (ArUtil::strcmp(myRobotSubType, "perfpb+") == 0)
01203     myParams = new ArRobotPerfPBPlus;
01204   else if (ArUtil::strcmp(myRobotSubType, "p3dx-sh") == 0)
01205     myParams = new ArRobotP3DXSH;
01206   else if (ArUtil::strcmp(myRobotSubType, "p3at-sh") == 0)
01207     myParams = new ArRobotP3ATSH;
01208   else if (ArUtil::strcmp(myRobotSubType, "p3atiw-sh") == 0)
01209     myParams = new ArRobotP3ATIWSH;
01210   else if (ArUtil::strcmp(myRobotSubType, "patrolbot-sh") == 0)
01211     myParams = new ArRobotPatrolBotSH;
01212   else if (ArUtil::strcmp(myRobotSubType, "peoplebot-sh") == 0)
01213     myParams = new ArRobotPeopleBotSH;
01214   else if (ArUtil::strcmp(myRobotSubType, "powerbot-sh") == 0)
01215     myParams = new ArRobotPowerBotSH;
01216   else if (ArUtil::strcmp(myRobotSubType, "wheelchair-sh") == 0)
01217     myParams = new ArRobotWheelchairSH;
01218   else
01219   {
01220     hadDefault = false;
01221     myParams = new ArRobotGeneric(myRobotName.c_str());
01222   }
01223 
01224   // load up the param file for the subtype
01225   paramFileName = Aria::getDirectory();
01226   paramFileName += "params/";
01227   paramFileName += myRobotSubType;
01228   paramFileName += ".p";
01229   if ((loadedSubTypeParam = myParams->parseFile(paramFileName.c_str(), true, true)))
01230       ArLog::log(ArLog::Normal, 
01231          "Loaded robot parameters from %s.p", 
01232          myRobotSubType.c_str());
01233   /* If the above line was replaced with this one line
01234      paramFile->load(); 
01235      then the sonartest (and lots of other stuff probably) would break
01236   */
01237   // then the one for the particular name, if we can
01238   paramFileName = Aria::getDirectory();
01239   paramFileName += "params/";
01240   paramFileName += myRobotName;
01241   paramFileName += ".p";
01242   if ((loadedNameParam = myParams->parseFile(paramFileName.c_str(),
01243                          true, true)))
01244   {
01245     if (loadedSubTypeParam)
01246       ArLog::log(ArLog::Normal, 
01247  "Loaded robot parameters from %s.p on top of %s.p robot parameters", 
01248          myRobotName.c_str(), myRobotSubType.c_str());
01249     else
01250       ArLog::log(ArLog::Normal, "Loaded robot parameters from %s.p", 
01251          myRobotName.c_str());
01252   }
01253    
01254   if (!loadedSubTypeParam && !loadedNameParam)
01255   {
01256     if (hadDefault)
01257       ArLog::log(ArLog::Normal, "Using default parameters for a %s robot", 
01258          myRobotSubType.c_str());
01259     else
01260     {
01261       ArLog::log(ArLog::Terse, "Error: Have no parameters for this robot, bad configuration or out of date Aria");
01262       // in the default state (not connecting if we don't have params)
01263       // we will return false... if we can connect without params then
01264       // we'll keep going (this really shouldn't be used except by
01265       // downloaders and such)
01266       if (!myConnectWithNoParams)
01267     return false;
01268     }
01269   }
01270 
01271   processParamFile();
01272 
01273   if (myParams->getRequestIOPackets() || myRequestedIOPackets)
01274     comInt(ArCommands::IOREQUEST, 2);
01275 
01276   if(myParams->getRequestEncoderPackets() || myRequestedEncoderPackets)
01277     comInt(ArCommands::ENCODER, 2);
01278 
01279   return true;
01280 }
01281 
01287 AREXPORT void ArRobot::requestEncoderPackets(void)
01288 {
01289   comInt(ArCommands::ENCODER, 2);
01290   myRequestedEncoderPackets = true;
01291 }
01292 
01293 AREXPORT void ArRobot::requestIOPackets(void)
01294 {
01295   comInt(ArCommands::IOREQUEST, 2);
01296   myRequestedIOPackets = true;
01297 }
01298 
01299 AREXPORT void ArRobot::stopEncoderPackets(void)
01300 {
01301   comInt(ArCommands::ENCODER, 0);
01302   myRequestedEncoderPackets = false;
01303 }
01304 
01305 AREXPORT void ArRobot::stopIOPackets(void)
01306 {
01307   comInt(ArCommands::IOREQUEST, 0);
01308   myRequestedIOPackets = false;
01309 }
01310 
01311 AREXPORT void ArRobot::startStabilization(void)
01312 {
01313   std::list<ArFunctor *>::iterator it;
01314   myIsStabilizing = true;
01315   myStartedStabilizing.setToNow();
01316 
01317   for (it = myStabilizingCBList.begin(); 
01318        it != myStabilizingCBList.end(); 
01319        it++)
01320     (*it)->invoke();
01321 
01322 }
01323 
01324 AREXPORT void ArRobot::finishedConnection(void)
01325 {
01326   std::list<ArFunctor *>::iterator it;
01327 
01328   myIsStabilizing = false;
01329   myIsConnected = true;
01330   myAsyncConnectFlag = false;
01331   myBlockingConnectRun = false;
01332   resetOdometer();
01333   
01334   for (it = myConnectCBList.begin(); it != myConnectCBList.end(); it++)
01335     (*it)->invoke();
01336   myLastPacketReceivedTime.setToNow();
01337 
01338   wakeAllConnWaitingThreads();
01339 }
01340 
01341 AREXPORT void ArRobot::failedConnect(void)
01342 {
01343   std::list<ArFunctor *>::iterator it;  
01344   
01345   myAsyncConnectFlag = false;
01346   myBlockingConnectRun = false;
01347   ArLog::log(ArLog::Terse, "Failed to connect to robot.");
01348   myIsConnected = false;
01349   for (it = myFailedConnectCBList.begin(); 
01350        it != myFailedConnectCBList.end(); 
01351        it++)
01352     (*it)->invoke();
01353 
01354   if (myConn != NULL)
01355     myConn->close();
01356   wakeAllConnOrFailWaitingThreads();
01357 }
01358 
01368 AREXPORT bool ArRobot::disconnect(void)
01369 {
01370   std::list<ArFunctor *>::iterator it;  
01371   bool ret;
01372   ArSerialConnection *serConn;
01373 
01374   if (!myIsConnected && !myIsStabilizing)
01375     return true;
01376   
01377   ArLog::log(ArLog::Terse, "Disconnecting from robot.");
01378   myNoTimeWarningThisCycle = true;
01379   myIsConnected = false;
01380   myIsStabilizing = false;
01381   if (myIsConnected)
01382   {
01383     for (it = myDisconnectNormallyCBList.begin(); 
01384      it != myDisconnectNormallyCBList.end(); 
01385      it++)
01386       (*it)->invoke();
01387   }
01388   ret = mySender.comInt(ArCommands::CLOSE, 1);
01389   ArUtil::sleep(1000);
01390   if (ret == true)
01391   {
01392     if (myConn != NULL)
01393     {
01394       ret = myConn->close();
01395       if ((serConn = dynamic_cast<ArSerialConnection *>(myConn)) != NULL)
01396         serConn->setBaud(myAsyncConnectStartBaud);
01397     } 
01398     else
01399       ret = false;
01400   } 
01401   else if (myConn != NULL)
01402     myConn->close();
01403     
01404   return ret;
01405 }
01406 
01407 AREXPORT void ArRobot::dropConnection(void)
01408 {
01409   std::list<ArFunctor *>::iterator it;  
01410 
01411   if (!myIsConnected)
01412     return;
01413 
01414   ArLog::log(ArLog::Terse, "Lost connection to the robot because of error.");
01415   myIsConnected = false;
01416   for (it = myDisconnectOnErrorCBList.begin(); 
01417        it != myDisconnectOnErrorCBList.end(); 
01418        it++)
01419     (*it)->invoke();
01420 
01421   if (myConn != NULL)
01422     myConn->close();
01423   return;
01424 }
01425 
01426 AREXPORT void ArRobot::cancelConnection(void)
01427 {
01428   //std::list<ArFunctor *>::iterator it;  
01429 
01430   ArLog::log(ArLog::Verbose, "Cancelled connection to the robot because of command.");
01431   myIsConnected = false;
01432   myNoTimeWarningThisCycle = true;
01433   myIsStabilizing = false;
01434   return;
01435 }
01436 
01446 AREXPORT void ArRobot::stop(void)
01447 {
01448   comInt(ArCommands::VEL, 0);
01449   comInt(ArCommands::RVEL, 0);
01450   setVel(0);
01451   setRotVel(0);
01452   myLastActionTransVal = 0;
01453   myLastActionRotStopped = true;
01454   myLastActionRotHeading = false;
01455 }
01456 
01463 AREXPORT void ArRobot::setVel(double velocity)
01464 {
01465   myTransType = TRANS_VEL;
01466   myTransVal = velocity;
01467   myTransVal2 = 0;
01468   myTransSetTime.setToNow();
01469 }
01470 
01485 AREXPORT void ArRobot::setVel2(double leftVelocity, double rightVelocity)
01486 {
01487   myTransType = TRANS_VEL2;
01488   myTransVal = leftVelocity;
01489   myTransVal2 = rightVelocity;
01490   myRotType = ROT_IGNORE;
01491   myRotVal = 0;
01492   myTransSetTime.setToNow();
01493 }
01494 
01505 AREXPORT void ArRobot::move(double distance)
01506 {
01507   myTransType = TRANS_DIST_NEW;
01508   myTransDistStart = getPose();
01509   myTransVal = distance;
01510   myTransVal2 = 0;
01511   myTransSetTime.setToNow();
01512 }
01513 
01528 AREXPORT bool ArRobot::isMoveDone(double delta)
01529 {
01530   if (fabs(delta) < 0.001)
01531     delta = myMoveDoneDist;
01532   if (myTransType != TRANS_DIST && myTransType != TRANS_DIST_NEW)
01533     return true;        // no distance command operative
01534   if (myTransDistStart.findDistanceTo(getPose()) <
01535       fabs(myTransVal) - delta)
01536     return false;
01537   return true;
01538 }
01539 
01540 
01553 AREXPORT bool ArRobot::isHeadingDone(double delta) const
01554 {
01555   if (fabs(delta) < 0.001)
01556     delta = myHeadingDoneDiff;
01557   if (myRotType != ROT_HEADING)
01558     return true;        // no heading command operative
01559   if(fabs(ArMath::subAngle(getTh(), myRotVal)) > delta)
01560     return false;
01561   return true;
01562 }
01563 
01564 
01565 
01572 AREXPORT void ArRobot::setHeading(double heading)
01573 {
01574   myRotVal = heading;
01575   myRotType = ROT_HEADING;
01576   myRotSetTime.setToNow();
01577   if (myTransType == TRANS_VEL2)
01578   {
01579     myTransType = TRANS_IGNORE;
01580     myTransVal = 0;
01581     myTransVal2 = 0;
01582   }
01583 }
01584 
01591 AREXPORT void ArRobot::setRotVel(double velocity)
01592 {
01593   myRotVal = velocity;
01594   myRotType = ROT_VEL;
01595   myRotSetTime.setToNow();
01596   if (myTransType == TRANS_VEL2)
01597   {
01598     myTransType = TRANS_IGNORE;
01599     myTransVal = 0;
01600     myTransVal2 = 0;
01601   }
01602 }
01603 
01610 AREXPORT void ArRobot::setDeltaHeading(double deltaHeading)
01611 {
01612   myRotVal = ArMath::addAngle(getTh(), deltaHeading);
01613   myRotType = ROT_HEADING;
01614   myRotSetTime.setToNow();
01615   if (myTransType == TRANS_VEL2)
01616   {
01617     myTransType = TRANS_IGNORE;
01618     myTransVal = 0;
01619     myTransVal2 = 0;
01620   }
01621 }
01622 
01636 AREXPORT bool ArRobot::setAbsoluteMaxTransVel(double maxVel)
01637 {
01638   if (maxVel < 0)
01639     return false;
01640   myAbsoluteMaxTransVel = maxVel;
01641   if (getTransVelMax() > myAbsoluteMaxTransVel)
01642     setTransVelMax(myAbsoluteMaxTransVel);
01643   return true;
01644 }
01645 
01659 AREXPORT bool ArRobot::setAbsoluteMaxTransAccel(double maxAccel)
01660 {
01661   if (maxAccel < 0)
01662     return false;
01663   myAbsoluteMaxTransAccel = maxAccel;
01664   if (getTransAccel() > myAbsoluteMaxTransAccel)
01665     setTransAccel(myAbsoluteMaxTransAccel);
01666   return true;
01667 }
01668 
01682 AREXPORT bool ArRobot::setAbsoluteMaxTransDecel(double maxDecel)
01683 {
01684   if (maxDecel < 0)
01685     return false;
01686   myAbsoluteMaxTransDecel = maxDecel;
01687   if (getTransDecel() > myAbsoluteMaxTransDecel)
01688     setTransDecel(myAbsoluteMaxTransDecel);
01689   return true;
01690 }
01691 
01703 AREXPORT bool ArRobot::setAbsoluteMaxRotVel(double maxVel)
01704 {
01705   if (maxVel < 0)
01706     return false;
01707   myAbsoluteMaxRotVel = maxVel;
01708   if (getRotVelMax() > myAbsoluteMaxRotVel)
01709     setRotVelMax(myAbsoluteMaxRotVel);
01710   return true;
01711 }
01712 
01726 AREXPORT bool ArRobot::setAbsoluteMaxRotAccel(double maxAccel)
01727 {
01728   if (maxAccel < 0)
01729     return false;
01730   myAbsoluteMaxRotAccel = maxAccel;
01731   if (getRotAccel() > myAbsoluteMaxRotAccel)
01732     setRotAccel(myAbsoluteMaxRotAccel);
01733   return true;
01734 }
01735 
01749 AREXPORT bool ArRobot::setAbsoluteMaxRotDecel(double maxDecel)
01750 {
01751   if (maxDecel < 0)
01752     return false;
01753   myAbsoluteMaxRotDecel = maxDecel;
01754   if (getRotDecel() > myAbsoluteMaxRotDecel)
01755     setRotDecel(myAbsoluteMaxRotDecel);
01756   return true;
01757 }
01758 
01763 AREXPORT int ArRobot::getIOAnalog(int num) const
01764 {
01765   if (num <= getIOAnalogSize())
01766     return myIOAnalog[num];
01767   else
01768     return 0;
01769 }
01770 
01774 AREXPORT double ArRobot::getIOAnalogVoltage(int num) const
01775 {
01776   if (num <= getIOAnalogSize())
01777   {
01778     return (myIOAnalog[num] & 0xfff) * .0048828;
01779   }
01780   else
01781     return 0;
01782 }
01783 
01784 AREXPORT unsigned char ArRobot::getIODigIn(int num) const
01785 {
01786   if (num <= getIODigInSize())
01787     return myIODigIn[num];
01788   else
01789     return (unsigned char) 0;
01790 }
01791 
01792 AREXPORT unsigned char  ArRobot::getIODigOut(int num) const
01793 {
01794   if (num <= getIODigOutSize())
01795     return myIODigOut[num];
01796   else
01797     return (unsigned char) 0;
01798 }
01799 
01803 AREXPORT const ArRobotParams *ArRobot::getRobotParams(void) const
01804 {
01805   return myParams;
01806 }
01807 
01812 AREXPORT const ArRobotConfigPacketReader *ArRobot::getOrigRobotConfig(void) const
01813 {
01814   return myOrigRobotConfig;
01815 }
01816   
01833 AREXPORT void ArRobot::addPacketHandler(
01834     ArRetFunctor1<bool, ArRobotPacket *> *functor, 
01835     ArListPos::Pos position) 
01836 {
01837   if (position == ArListPos::FIRST)
01838     myPacketHandlerList.push_front(functor);
01839   else if (position == ArListPos::LAST)
01840     myPacketHandlerList.push_back(functor);
01841   else
01842     ArLog::log(ArLog::Terse, "ArRobot::addPacketHandler: Invalid position.");
01843 
01844 }
01845 
01850 AREXPORT void ArRobot::remPacketHandler(
01851     ArRetFunctor1<bool, ArRobotPacket *> *functor)
01852 {
01853   myPacketHandlerList.remove(functor);
01854 }
01855 
01866 AREXPORT void ArRobot::addConnectCB(ArFunctor *functor, 
01867                     ArListPos::Pos position)
01868 {
01869   if (position == ArListPos::FIRST)
01870     myConnectCBList.push_front(functor);
01871   else if (position == ArListPos::LAST)
01872     myConnectCBList.push_back(functor);
01873   else
01874     ArLog::log(ArLog::Terse, 
01875            "ArRobot::addConnectCallback: Invalid position.");
01876 }
01877 
01882 AREXPORT void ArRobot::remConnectCB(ArFunctor *functor)
01883 {
01884   myConnectCBList.remove(functor);
01885 }
01886 
01887 
01901 AREXPORT void ArRobot::addFailedConnectCB(ArFunctor *functor, 
01902                       ArListPos::Pos position)
01903 {
01904   if (position == ArListPos::FIRST)
01905     myFailedConnectCBList.push_front(functor);
01906   else if (position == ArListPos::LAST)
01907     myFailedConnectCBList.push_back(functor);
01908   else
01909     ArLog::log(ArLog::Terse, 
01910            "ArRobot::addFailedCallback: Invalid position.");
01911 }
01912 
01917 AREXPORT void ArRobot::remFailedConnectCB(ArFunctor *functor)
01918 {
01919   myFailedConnectCBList.remove(functor);
01920 }
01921 
01933 AREXPORT void ArRobot::addDisconnectNormallyCB(ArFunctor *functor, 
01934                            ArListPos::Pos position)
01935 {
01936   if (position == ArListPos::FIRST)
01937     myDisconnectNormallyCBList.push_front(functor);
01938   else if (position == ArListPos::LAST)
01939     myDisconnectNormallyCBList.push_back(functor);
01940   else
01941     ArLog::log(ArLog::Terse, 
01942            "ArRobot::addDisconnectNormallyCB: Invalid position.");
01943 }
01944 
01949 AREXPORT void ArRobot::remDisconnectNormallyCB(ArFunctor *functor)
01950 {
01951   myDisconnectNormallyCBList.remove(functor);
01952 }
01953 
01970 AREXPORT void ArRobot::addDisconnectOnErrorCB(ArFunctor *functor, 
01971                           ArListPos::Pos position)
01972 {
01973   if (position == ArListPos::FIRST)
01974     myDisconnectOnErrorCBList.push_front(functor);
01975   else if (position == ArListPos::LAST)
01976     myDisconnectOnErrorCBList.push_back(functor);
01977   else
01978     ArLog::log(ArLog::Terse, 
01979            "ArRobot::addDisconnectOnErrorCB: Invalid position");
01980 }
01981 
01986 AREXPORT void ArRobot::remDisconnectOnErrorCB(ArFunctor *functor)
01987 {
01988   myDisconnectOnErrorCBList.remove(functor);
01989 }
01990 
02002 AREXPORT void ArRobot::addRunExitCB(ArFunctor *functor,
02003                     ArListPos::Pos position)
02004 {
02005   if (position == ArListPos::FIRST)
02006     myRunExitCBList.push_front(functor);
02007   else if (position == ArListPos::LAST)
02008     myRunExitCBList.push_back(functor);
02009   else
02010     ArLog::log(ArLog::Terse, "ArRobot::addRunExitCB: Invalid position");
02011 }
02012 
02017 AREXPORT void ArRobot::remRunExitCB(ArFunctor *functor)
02018 {
02019   myRunExitCBList.remove(functor);
02020 }
02021 
02034 AREXPORT void ArRobot::addStabilizingCB(ArFunctor *functor, 
02035                        ArListPos::Pos position)
02036 {
02037   if (position == ArListPos::FIRST)
02038     myStabilizingCBList.push_front(functor);
02039   else if (position == ArListPos::LAST)
02040     myStabilizingCBList.push_back(functor);
02041   else
02042     ArLog::log(ArLog::Terse, 
02043            "ArRobot::addConnectCallback: Invalid position.");
02044 }
02045 
02050 AREXPORT void ArRobot::remStabilizingCB(ArFunctor *functor)
02051 {
02052   myStabilizingCBList.remove(functor);
02053 }
02054 
02055 
02056 AREXPORT std::list<ArFunctor *> * ArRobot::getRunExitListCopy()
02057 {
02058   return(new std::list<ArFunctor *>(myRunExitCBList));
02059 }
02060 
02076 AREXPORT ArRobot::WaitState ArRobot::waitForConnect(unsigned int msecs)
02077 {
02078   int ret;
02079 
02080   if (isConnected())
02081     return(WAIT_CONNECTED);
02082 
02083   if (msecs == 0)
02084     ret=myConnectCond.wait();
02085   else
02086     ret=myConnectCond.timedWait(msecs);
02087 
02088   if (ret == ArCondition::STATUS_WAIT_INTR)
02089     return(WAIT_INTR);
02090   else if (ret == ArCondition::STATUS_WAIT_TIMEDOUT)
02091     return(WAIT_TIMEDOUT);
02092   else if (ret == 0)
02093     return(WAIT_CONNECTED);
02094   else
02095     return(WAIT_FAIL);
02096 }
02097 
02107 AREXPORT ArRobot::WaitState
02108 ArRobot::waitForConnectOrConnFail(unsigned int msecs)
02109 {
02110   int ret;
02111 
02112   if (isConnected())
02113     return(WAIT_CONNECTED);
02114 
02115   if (msecs == 0)
02116     ret=myConnOrFailCond.wait();
02117   else
02118     ret=myConnOrFailCond.timedWait(msecs);
02119 
02120   if (ret == ArCondition::STATUS_WAIT_INTR)
02121     return(WAIT_INTR);
02122   else if (ret == ArCondition::STATUS_WAIT_TIMEDOUT)
02123     return(WAIT_TIMEDOUT);
02124   else if (ret == 0)
02125   {
02126     if (isConnected())
02127       return(WAIT_CONNECTED);
02128     else
02129       return(WAIT_FAILED_CONN);
02130   }
02131   else
02132     return(WAIT_FAIL);
02133 }
02134 
02143 AREXPORT ArRobot::WaitState ArRobot::waitForRunExit(unsigned int msecs)
02144 {
02145   int ret;
02146 
02147   if (!isRunning())
02148     return(WAIT_RUN_EXIT);
02149 
02150   if (msecs == 0)
02151     ret=myRunExitCond.wait();
02152   else
02153     ret=myRunExitCond.timedWait(msecs);
02154 
02155   if (ret == ArCondition::STATUS_WAIT_INTR)
02156     return(WAIT_INTR);
02157   else if (ret == ArCondition::STATUS_WAIT_TIMEDOUT)
02158     return(WAIT_TIMEDOUT);
02159   else if (ret == 0)
02160     return(WAIT_RUN_EXIT);
02161   else
02162     return(WAIT_FAIL);
02163 }
02164 
02172 AREXPORT void ArRobot::wakeAllWaitingThreads()
02173 {
02174   wakeAllConnWaitingThreads();
02175   wakeAllRunExitWaitingThreads();
02176 }
02177 
02183 AREXPORT void ArRobot::wakeAllConnWaitingThreads()
02184 {
02185   myConnectCond.broadcast();
02186   myConnOrFailCond.broadcast();
02187 }
02188 
02195 AREXPORT void ArRobot::wakeAllConnOrFailWaitingThreads()
02196 {
02197   myConnOrFailCond.broadcast();
02198 }
02199 
02205 AREXPORT void ArRobot::wakeAllRunExitWaitingThreads()
02206 {
02207   myRunExitCond.broadcast();
02208 }
02209 
02217 AREXPORT ArSyncTask *ArRobot::getSyncTaskRoot(void)
02218 {
02219   return mySyncTaskRoot;
02220 }
02221 
02238 AREXPORT bool ArRobot::addUserTask(const char *name, int position, 
02239                       ArFunctor *functor, 
02240                       ArTaskState::State *state)
02241 {
02242   ArSyncTask *proc;
02243   if (mySyncTaskRoot == NULL)
02244     return false;
02245 
02246   proc = mySyncTaskRoot->findNonRecursive("User Tasks");
02247   if (proc == NULL)
02248     return false;
02249   
02250   proc->addNewLeaf(name, position, functor, state);
02251   return true;  
02252 }
02253 
02258 AREXPORT void ArRobot::remUserTask(const char *name)
02259 {
02260   ArSyncTask *proc;
02261   ArSyncTask *userProc;
02262 
02263   if (mySyncTaskRoot == NULL)
02264     return;
02265 
02266   proc = mySyncTaskRoot->findNonRecursive("User Tasks");
02267   if (proc == NULL)
02268     return;
02269   
02270   userProc = proc->findNonRecursive(name);
02271   if (userProc == NULL)
02272     return;
02273 
02274   
02275   delete userProc;
02276 
02277 }
02278 
02283 AREXPORT void ArRobot::remUserTask(ArFunctor *functor)
02284 {
02285   ArSyncTask *proc;
02286   ArSyncTask *userProc;
02287 
02288   if (mySyncTaskRoot == NULL)
02289     return;
02290 
02291   proc = mySyncTaskRoot->findNonRecursive("User Tasks");
02292   if (proc == NULL)
02293     return;
02294   
02295   
02296   userProc = proc->findNonRecursive(functor);
02297   if (userProc == NULL)
02298     return;
02299 
02300   
02301   delete userProc;
02302 
02303 }
02304 
02316 AREXPORT bool ArRobot::addSensorInterpTask(const char *name, int position, 
02317                           ArFunctor *functor,
02318                           ArTaskState::State *state)
02319 {
02320   ArSyncTask *proc;
02321   if (mySyncTaskRoot == NULL)
02322     return false;
02323 
02324   proc = mySyncTaskRoot->findNonRecursive("Sensor Interp");
02325   if (proc == NULL)
02326     return false;
02327   
02328   proc->addNewLeaf(name, position, functor, state);
02329   return true;  
02330 }
02331 
02336 AREXPORT void ArRobot::remSensorInterpTask(const char *name)
02337 {
02338   ArSyncTask *proc;
02339   ArSyncTask *sensorInterpProc;
02340 
02341   if (mySyncTaskRoot == NULL)
02342     return;
02343 
02344   proc = mySyncTaskRoot->findNonRecursive("Sensor Interp");
02345   if (proc == NULL)
02346     return;
02347   
02348   sensorInterpProc = proc->findNonRecursive(name);
02349   if (sensorInterpProc == NULL)
02350     return;
02351 
02352   
02353   delete sensorInterpProc;
02354 
02355 }
02356 
02361 AREXPORT void ArRobot::remSensorInterpTask(ArFunctor *functor)
02362 {
02363   ArSyncTask *proc;
02364   ArSyncTask *sensorInterpProc;
02365 
02366   if (mySyncTaskRoot == NULL)
02367     return;
02368 
02369   proc = mySyncTaskRoot->findNonRecursive("Sensor Interp");
02370   if (proc == NULL)
02371     return;
02372   
02373   
02374   sensorInterpProc = proc->findNonRecursive(functor);
02375   if (sensorInterpProc == NULL)
02376     return;
02377 
02378   
02379   delete sensorInterpProc;
02380 
02381 }
02382 
02386 AREXPORT void ArRobot::logUserTasks(void) const
02387 {
02388   ArSyncTask *proc;
02389   if (mySyncTaskRoot == NULL)
02390     return;
02391 
02392   proc = mySyncTaskRoot->findNonRecursive("User Tasks");
02393   if (proc == NULL)
02394     return;
02395 
02396   proc->log();
02397 }
02398 
02402 AREXPORT void ArRobot::logAllTasks(void) const
02403 {
02404   if (mySyncTaskRoot != NULL)
02405     mySyncTaskRoot->log();
02406 }
02407 
02413 AREXPORT ArSyncTask *ArRobot::findUserTask(const char *name)
02414 {
02415   ArSyncTask *proc;
02416   if (mySyncTaskRoot == NULL)
02417     return NULL;
02418 
02419   proc = mySyncTaskRoot->findNonRecursive("User Tasks");
02420   if (proc == NULL)
02421     return NULL;
02422 
02423   return proc->find(name);
02424 }
02425 
02431 AREXPORT ArSyncTask *ArRobot::findUserTask(ArFunctor *functor)
02432 {
02433   ArSyncTask *proc;
02434   if (mySyncTaskRoot == NULL)
02435     return NULL;
02436 
02437   proc = mySyncTaskRoot->findNonRecursive("User Tasks");
02438   if (proc == NULL)
02439     return NULL;
02440 
02441   return proc->find(functor);
02442 }
02443 
02449 AREXPORT ArSyncTask *ArRobot::findTask(const char *name)
02450 {
02451   if (mySyncTaskRoot != NULL)
02452     return mySyncTaskRoot->find(name);
02453   else
02454     return NULL;
02455 
02456 }
02457 
02463 AREXPORT ArSyncTask *ArRobot::findTask(ArFunctor *functor)
02464 {
02465   if (mySyncTaskRoot != NULL)
02466     return mySyncTaskRoot->find(functor);
02467   else
02468     return NULL;
02469 
02470 }
02471 
02493 AREXPORT bool ArRobot::addAction(ArAction *action, int priority)
02494 {
02495   if (action == NULL)
02496   {
02497     ArLog::log(ArLog::Terse, 
02498       "ArRobot::addAction: an attempt was made to add a NULL action pointer");
02499     return false;
02500   }
02501   
02502   action->setRobot(this);
02503   myActions.insert(std::pair<int, ArAction *>(priority, action));
02504   return true;
02505 }
02506 
02517 AREXPORT bool ArRobot::remAction(const char *actionName)
02518 {
02519   ArResolver::ActionMap::iterator it;
02520   ArAction *act;
02521 
02522   for (it = myActions.begin(); it != myActions.end(); ++it)
02523   {
02524     act = (*it).second;
02525     if (strcmp(actionName, act->getName()) == 0)
02526       break;
02527   }
02528   if (it != myActions.end())
02529   {
02530     myActions.erase(it);
02531     return true;
02532   }
02533   return false;
02534 
02535 }
02536 
02547 AREXPORT bool ArRobot::remAction(ArAction *action)
02548 {
02549   ArResolver::ActionMap::iterator it;
02550   ArAction *act;
02551 
02552   for (it = myActions.begin(); it != myActions.end(); ++it)
02553   {
02554     act = (*it).second;
02555     if (act == action)
02556       break;
02557   }
02558   if (it != myActions.end())
02559   {
02560     myActions.erase(it);
02561     return true;
02562   }
02563   return false;
02564 
02565 }
02566 
02567 
02577 AREXPORT ArAction *ArRobot::findAction(const char *actionName)
02578 {
02579   ArResolver::ActionMap::reverse_iterator it;
02580   ArAction *act;
02581   
02582   for (it = myActions.rbegin(); it != myActions.rend(); ++it)
02583   {
02584     act = (*it).second;
02585     if (strcmp(actionName, act->getName()) == 0)
02586       return act;
02587   }
02588   return NULL;
02589 }
02590 
02601 AREXPORT ArResolver::ActionMap *ArRobot::getActionMap(void)
02602 {
02603   return &myActions;
02604 }
02605 
02606 AREXPORT void ArRobot::deactivateActions(void)
02607 {
02608   ArResolver::ActionMap *am;
02609   ArResolver::ActionMap::iterator amit;
02610   
02611   am = getActionMap();
02612   if (am == NULL)
02613   {
02614     ArLog::log(ArLog::Terse, 
02615             "ArRobot::deactivateActions: NULL action map... failed.");
02616     return;
02617   }
02618   for (amit = am->begin(); amit != am->end(); amit++)
02619     (*amit).second->deactivate();
02620   
02621 
02622 }
02623 
02624 
02625 AREXPORT void ArRobot::logActions(bool logDeactivated) const
02626 {
02627   ArResolver::ActionMap::const_reverse_iterator it;
02628   int lastPriority;
02629   bool first = true;
02630   const ArAction *action;
02631 
02632   if (logDeactivated)
02633     ArLog::log(ArLog::Terse, "The action list (%d total):", 
02634            myActions.size());
02635   else
02636     ArLog::log(ArLog::Terse, "The active action list:");
02637 
02638   for (it = myActions.rbegin(); it != myActions.rend(); ++it)
02639   {
02640     action = (*it).second;
02641     if ((logDeactivated || action->isActive()) &&
02642     (first || lastPriority != (*it).first))
02643     {
02644       ArLog::log(ArLog::Terse, "Priority %d:", (*it).first);
02645       first = false;
02646       lastPriority = (*it).first;
02647     }
02648     action->log(false);
02649   }
02650 }
02651 
02652 AREXPORT ArResolver *ArRobot::getResolver(void)
02653 {
02654   return myResolver;
02655 }
02656 
02657 AREXPORT void ArRobot::setResolver(ArResolver *resolver)
02658 {
02659   if (myOwnTheResolver)
02660   {
02661     delete myResolver;
02662     myResolver = NULL;
02663   }
02664 
02665   myResolver = resolver;
02666 }
02667 
02679 AREXPORT void ArRobot::stateReflector(void)
02680 {
02681   short transVal;
02682   short transVal2;
02683   short maxVel;
02684   short maxNegVel;
02685   double maxTransVel;
02686   double maxNegTransVel;
02687   double maxRotVel;
02688   double transAccel;
02689   double transDecel;
02690   short rotVal;
02691   double rotAccel;
02692   double rotDecel;
02693   bool rotStopped = false;
02694   bool rotHeading = false;
02695   double encTh;
02696   double rawTh;
02697 
02698 
02699   if (!myIsConnected)
02700     return;
02701 
02702   myTryingToMove = false;
02703 
02704   // if this is true actions can't go
02705   if ((myTransType != TRANS_NONE && myDirectPrecedenceTime == 0) ||
02706       (myTransType != TRANS_NONE && myDirectPrecedenceTime != 0 && 
02707        myTransSetTime.mSecSince() < myDirectPrecedenceTime))
02708   {
02709     myActionTransSet = false;
02710     transVal = ArMath::roundShort(myTransVal);
02711     transVal2 = 0;
02712 
02713     if (hasSettableVelMaxes() && 
02714     ArMath::fabs(myLastSentTransVelMax - myTransVelMax) >= 1)
02715     {
02716       comInt(ArCommands::SETV,
02717          ArMath::roundShort(myTransVelMax));
02718       myLastSentTransVelMax = myTransVelMax;
02719       if (myLogMovementSent)
02720     ArLog::log(ArLog::Normal, "Non-action trans max vel of %d", 
02721            ArMath::roundShort(myTransVelMax));
02722     }
02723 
02724     if (hasSettableAccsDecs() && ArMath::fabs(myTransAccel) > 1 && 
02725     ArMath::fabs(myLastSentTransAccel - myTransAccel) >= 1)
02726     {
02727       comInt(ArCommands::SETA,
02728          ArMath::roundShort(myTransAccel));
02729       myLastSentTransAccel = myTransAccel;
02730       if (myLogMovementSent)
02731     ArLog::log(ArLog::Normal, "Non-action trans accel of %d", 
02732            ArMath::roundShort(myTransAccel));
02733     }
02734 
02735     if (hasSettableAccsDecs() && ArMath::fabs(myTransDecel) > 1 &&
02736     ArMath::fabs(myLastSentTransDecel - myTransDecel) >= 1)
02737     {
02738       comInt(ArCommands::SETA,
02739          -ArMath::roundShort(myTransDecel));
02740       myLastSentTransDecel = myTransDecel;
02741       if (myLogMovementSent)
02742     ArLog::log(ArLog::Normal, "Non-action trans decel of %d", 
02743            -ArMath::roundShort(myTransDecel));
02744     }
02745 
02746     if (myTransType == TRANS_VEL)
02747     {
02748       maxVel = ArMath::roundShort(myTransVelMax);
02749       if (transVal > maxVel)
02750     transVal = maxVel;
02751       if (transVal < -maxVel)
02752     transVal = -maxVel;
02753       if (myLastTransVal != transVal || myLastTransType != myTransType ||
02754       (myLastTransSent.mSecSince() >= myStateReflectionRefreshTime))
02755       {
02756     comInt(ArCommands::VEL, ArMath::roundShort(transVal));
02757     myLastTransSent.setToNow();
02758     if (myLogMovementSent)
02759       ArLog::log(ArLog::Normal, "Non-action trans vel of %d", 
02760              ArMath::roundShort(transVal));
02761     //printf("Sent command vel!\n");
02762       }
02763       if (fabs((double)transVal) > (double).5)
02764     myTryingToMove = true;
02765     }
02766     else if (myTransType == TRANS_VEL2)
02767     {
02768       if (ArMath::roundShort(myTransVal/myParams->getVel2Divisor()) > 128)
02769     transVal = 128;
02770       else if (ArMath::roundShort(myTransVal/myParams->getVel2Divisor()) < -128)
02771     transVal = -128;
02772       else 
02773     transVal = ArMath::roundShort(myTransVal/myParams->getVel2Divisor());
02774       if (ArMath::roundShort(myTransVal2/myParams->getVel2Divisor()) > 128)
02775     transVal2 = 128;
02776       else if (ArMath::roundShort(myTransVal2/myParams->getVel2Divisor()) < -128)
02777     transVal2 = -128;
02778       else 
02779     transVal2 = ArMath::roundShort(myTransVal2/myParams->getVel2Divisor());
02780       if (myLastTransVal != transVal || myLastTransVal2 != transVal2 || 
02781       myLastTransType != myTransType ||
02782       (myLastTransSent.mSecSince() >= myStateReflectionRefreshTime))
02783       {
02784     com2Bytes(ArCommands::VEL2, transVal, transVal2);
02785     myLastTransSent.setToNow();
02786     if (myLogMovementSent)
02787       ArLog::log(ArLog::Normal, "Non-action vel2 of %d %d", 
02788              transVal, transVal2);
02789     //printf("Sent command vel2!\n");
02790       }
02791       if (fabs((double)transVal) > (double).5 || fabs((double)transVal2) > (double).5)
02792     myTryingToMove = true;
02793     }
02794     else if (myTransType == TRANS_DIST_NEW || myTransType == TRANS_DIST)
02795     {
02796       // if the robot doesn't have its own distance command
02797       if (!myParams->hasMoveCommand())
02798       {
02799     double distGone;
02800     double distToGo;
02801     double vel;
02802 
02803     myTransType = TRANS_DIST;
02804     distGone = myTransDistStart.findDistanceTo(getPose());
02805     distToGo = fabs(fabs(myTransVal) - distGone);
02806     if (distGone > fabs(myTransVal) || 
02807         (distToGo < 10 && fabs(getVel()) < 30))
02808     {
02809       comInt(ArCommands::VEL, 0);
02810       myTransType = TRANS_VEL;
02811       myTransVal = 0;
02812     }
02813     else
02814       myTryingToMove = true;
02815     vel = sqrt(distToGo * 200 * 2);
02816     if (vel > getTransVelMax())
02817       vel = getTransVelMax();
02818     if (myTransVal < 0)
02819       vel *= -1;
02820     comInt(ArCommands::VEL, ArMath::roundShort(vel));
02821     if (myLogMovementSent)
02822       ArLog::log(ArLog::Normal, "Non-action move-helper of %d", 
02823              ArMath::roundShort(vel));
02824       }
02825       else if (myParams->hasMoveCommand() && myTransType == TRANS_DIST_NEW) 
02826       {
02827     comInt(ArCommands::MOVE, transVal);
02828     myLastTransSent.setToNow();
02829     myTransType = TRANS_DIST;
02830     if (myLogMovementSent)
02831       ArLog::log(ArLog::Normal, "Non-action move of %d", 
02832              transVal);
02833     myTryingToMove = true;
02834       }
02835       else if (myTransType == TRANS_DIST && 
02836       (myLastTransSent.mSecSince() >= myStateReflectionRefreshTime))
02837       {
02838     com(0);
02839     myLastPulseSent.setToNow();
02840     myLastTransSent.setToNow();
02841     //printf("Sent pulse for dist!\n");
02842     if (myLogMovementSent)
02843       ArLog::log(ArLog::Normal, "Non-action pulse for dist");
02844       }
02845       //printf("Sent command move!\n");
02846     }
02847     else if (myTransType == TRANS_IGNORE)
02848     {
02849       //printf("No trans command sent\n");
02850     }
02851     else
02852       ArLog::log(ArLog::Terse, 
02853          "ArRobot::stateReflector: Invalid translational type %d.",
02854          myTransType);
02855     myLastTransVal = transVal;
02856     myLastTransVal2 = transVal2;
02857     myLastTransType = myTransType;
02858   }
02859   else // if actions can go
02860   {
02861     if (hasSettableVelMaxes() && 
02862     ArMath::fabs(myLastSentTransVelMax - myTransVelMax) >= 1)
02863     {
02864       comInt(ArCommands::SETV,
02865          ArMath::roundShort(myTransVelMax));
02866       myLastSentTransVelMax = myTransVelMax;
02867       if (myLogMovementSent)
02868     ArLog::log(ArLog::Normal, "Action-but-robot trans max vel of %d", 
02869            ArMath::roundShort(myTransVelMax));
02870     }
02871     
02872     // first we'll handle all of the accel decel things
02873     if (myActionDesired.getTransAccelStrength() >= 
02874     ArActionDesired::MIN_STRENGTH)
02875     {
02876       transAccel = ArMath::roundShort(myActionDesired.getTransAccel());
02877       if (hasSettableAccsDecs() && ArMath::fabs(transAccel) > 1 &&
02878       ArMath::fabs(myLastSentTransAccel - transAccel) >= 1)
02879       {
02880     comInt(ArCommands::SETA,
02881            ArMath::roundShort(transAccel));
02882     myLastSentTransAccel = transAccel;
02883     if (myLogMovementSent)
02884       ArLog::log(ArLog::Normal, "Action trans accel of %d", 
02885              ArMath::roundShort(transAccel));
02886       }
02887     }
02888     else if (hasSettableAccsDecs() && ArMath::fabs(myTransAccel) > 1 && 
02889     ArMath::fabs(myLastSentTransAccel - myTransAccel) >= 1)
02890     {
02891       comInt(ArCommands::SETA,
02892          ArMath::roundShort(myTransAccel));
02893       myLastSentTransAccel = myTransAccel;
02894       if (myLogMovementSent)
02895     ArLog::log(ArLog::Normal, "Action-but-robot trans accel of %d", 
02896            ArMath::roundShort(myTransAccel));
02897     }
02898 
02899     if (myActionDesired.getTransDecelStrength() >=
02900     ArActionDesired::MIN_STRENGTH)
02901     {
02902       transDecel = ArMath::roundShort(myActionDesired.getTransDecel());
02903       if (hasSettableAccsDecs() && ArMath::fabs(transDecel) > 1 &&
02904       ArMath::fabs(myLastSentTransDecel - transDecel) >= 1)
02905       {
02906     comInt(ArCommands::SETA,
02907            -ArMath::roundShort(transDecel));
02908     myLastSentTransDecel = transDecel;
02909     if (myLogMovementSent)
02910       ArLog::log(ArLog::Normal, "Action trans decel of %d", 
02911              -ArMath::roundShort(transDecel));
02912       }
02913     }
02914     else if (hasSettableAccsDecs() && ArMath::fabs(myTransDecel) > 1 &&
02915     ArMath::fabs(myLastSentTransDecel - myTransDecel) >= 1)
02916     {
02917       comInt(ArCommands::SETA,
02918          -ArMath::roundShort(myTransDecel));
02919       myLastSentTransDecel = myTransDecel;
02920       if (myLogMovementSent)
02921     ArLog::log(ArLog::Normal, "Action-but-robot trans decel of %d", 
02922            -ArMath::roundShort(myTransDecel));
02923     }
02924 
02925     if (myActionDesired.getMaxVelStrength() >= ArActionDesired::MIN_STRENGTH)
02926     {
02927       maxTransVel = myActionDesired.getMaxVel();
02928       if (maxTransVel > myTransVelMax)
02929     maxTransVel = myTransVelMax;
02930     }
02931     else
02932       maxTransVel = myTransVelMax;
02933 
02934     if (myActionDesired.getMaxNegVelStrength() >= 
02935     ArActionDesired::MIN_STRENGTH)
02936     {
02937       maxNegTransVel = -ArMath::fabs(myActionDesired.getMaxNegVel());
02938       if (maxNegTransVel < -myTransVelMax)
02939     maxNegTransVel = -myTransVelMax;
02940     }
02941     else
02942       maxNegTransVel = -myTransVelMax;
02943     
02944     if (myActionDesired.getVelStrength() >= ArActionDesired::MIN_STRENGTH)
02945     {
02946       transVal = ArMath::roundShort(myActionDesired.getVel());
02947       myActionTransSet = true;
02948     }
02949     else
02950     {
02951       transVal = myLastActionTransVal;
02952     }
02953 
02954     if (fabs((double)transVal) > (double).5)
02955       myTryingToMove = true;
02956 
02957     maxVel = ArMath::roundShort(maxTransVel);
02958     maxNegVel = ArMath::roundShort(maxNegTransVel);
02959     if (transVal > maxVel)
02960       transVal = maxVel;
02961     if (transVal < maxNegVel)
02962       transVal = maxNegVel;
02963 
02964     if (myActionTransSet && 
02965     (myLastTransSent.mSecSince() >= myStateReflectionRefreshTime ||
02966      transVal != myLastActionTransVal))              
02967     {
02968       comInt(ArCommands::VEL, ArMath::roundShort(transVal));
02969       myLastTransSent.setToNow();
02970       if (myLogMovementSent)
02971     ArLog::log(ArLog::Normal, "Action trans vel of %d", 
02972            ArMath::roundShort(transVal));      
02973     }
02974     myLastActionTransVal = transVal;
02975   }
02976 
02977   // if this is true actions can't go
02978   if ((myRotType != ROT_NONE && myDirectPrecedenceTime == 0) ||
02979       (myRotType != ROT_NONE && myDirectPrecedenceTime != 0 && 
02980        myRotSetTime.mSecSince() < myDirectPrecedenceTime))
02981   {
02982     if (hasSettableVelMaxes() && 
02983     ArMath::fabs(myLastSentRotVelMax - myRotVelMax) >= 1)
02984     {
02985       comInt(ArCommands::SETRV,
02986          ArMath::roundShort(myRotVelMax));
02987       myLastSentRotVelMax = myRotVelMax;
02988     }
02989     if (hasSettableAccsDecs() && ArMath::fabs(myRotAccel) > 1 &&
02990     ArMath::fabs(myLastSentRotAccel - myRotAccel) >= 1)
02991     {
02992       comInt(ArCommands::SETRA,
02993          ArMath::roundShort(myRotAccel));
02994       myLastSentRotAccel = myRotAccel;
02995       if (myLogMovementSent)
02996     ArLog::log(ArLog::Normal, "%25sNon-action rot accel of %d", "",
02997            ArMath::roundShort(myRotAccel));      
02998     }
02999     if (hasSettableAccsDecs() && ArMath::fabs(myRotDecel) > 1 &&
03000     ArMath::fabs(myLastSentRotDecel - myRotDecel) >= 1)
03001     {
03002       comInt(ArCommands::SETRA,
03003          -ArMath::roundShort(myRotDecel));
03004       myLastSentRotDecel = myRotDecel;
03005       if (myLogMovementSent)
03006     ArLog::log(ArLog::Normal, "%25sNon-action rot decel of %d", "",
03007            -ArMath::roundShort(myRotDecel));      
03008     }
03009 
03010     myActionRotSet = false;
03011     rotVal = ArMath::roundShort(myRotVal);
03012     if (myRotType == ROT_HEADING)
03013     {
03014       encTh = ArMath::subAngle(myRotVal, myEncoderTransform.getTh());
03015       rawTh = ArMath::addAngle(encTh, 
03016                    ArMath::subAngle(myRawEncoderPose.getTh(),
03017                         myEncoderPose.getTh()));
03018       rotVal = ArMath::roundShort(rawTh);
03019 
03020       // if we were using a different heading type, a different heading
03021       // our heading doesn't match what we want it to be, or its been a while
03022       // since we sent the heading, send it again
03023       if (myLastRotVal != rotVal || myLastRotType != myRotType ||
03024       fabs(ArMath::subAngle(rotVal, getTh())) > 1 ||
03025       (myLastRotSent.mSecSince() >= myStateReflectionRefreshTime))
03026       {
03027     comInt(ArCommands::HEAD, rotVal);
03028     myLastRotSent.setToNow();
03029     //printf("sent command, heading\n");
03030     if (myLogMovementSent)
03031       ArLog::log(ArLog::Normal, 
03032          "%25sNon-action rot heading of %d (encoder %d, raw %d)",
03033              "",
03034              ArMath::roundShort(myRotVal),
03035              ArMath::roundShort(encTh),
03036              ArMath::roundShort(rotVal));
03037       }
03038       if (fabs(ArMath::subAngle(rotVal, getTh())) > 1)
03039     myTryingToMove = true;
03040     }
03041     else if (myRotType == ROT_VEL)
03042     {
03043       if (myLastRotVal != rotVal || myLastRotType != myRotType ||
03044       (myLastRotSent.mSecSince() >= myStateReflectionRefreshTime))
03045       {
03046     comInt(ArCommands::RVEL, rotVal);
03047     myLastRotSent.setToNow();
03048     if (myLogMovementSent)
03049       ArLog::log(ArLog::Normal, "%25sNon-action rot vel of %d", "",
03050              rotVal);      
03051     //printf("sent command, rot vel\n");
03052     if (fabs((double)rotVal) > (double).5)
03053       myTryingToMove = true;
03054       }
03055     }
03056     else if (myRotType == ROT_IGNORE)
03057     {
03058       //printf("Not sending any command, rot is set to ignore");
03059     }
03060     else
03061       ArLog::log(ArLog::Terse, 
03062          "ArRobot::stateReflector: Invalid rotation type %d.",
03063          myRotType);
03064     myLastRotVal = rotVal;
03065     myLastRotType = myRotType;
03066   }
03067   else // if the action can fire
03068   {
03069     // first we'll handle all of the accel decel things
03070     if (myActionDesired.getMaxRotVelStrength() >=
03071     ArActionDesired::MIN_STRENGTH)
03072     {
03073       maxRotVel = myActionDesired.getMaxRotVel();
03074       if (maxRotVel > myAbsoluteMaxRotVel)
03075     maxRotVel = myAbsoluteMaxRotVel;
03076       maxRotVel = ArMath::roundShort(maxRotVel);
03077       if (ArMath::fabs(myLastSentRotVelMax - maxRotVel) >= 1)
03078       {
03079     myLastSentRotVelMax = maxRotVel;
03080     comInt(ArCommands::SETRV, 
03081            ArMath::roundShort(maxRotVel));
03082     if (myLogMovementSent)
03083       ArLog::log(ArLog::Normal, "%25sAction rot vel max of %d", "",
03084              ArMath::roundShort(maxRotVel));
03085       }
03086     }
03087     else if (hasSettableVelMaxes() && 
03088          ArMath::fabs(myLastSentRotVelMax - myRotVelMax) >= 1)
03089     {
03090       comInt(ArCommands::SETRV,
03091          ArMath::roundShort(myRotVelMax));
03092       myLastSentRotVelMax = myRotVelMax;
03093       if (myLogMovementSent)
03094     ArLog::log(ArLog::Normal, 
03095            "%25sAction-but-robot rot vel max of %d", 
03096            "",  ArMath::roundShort(myRotVelMax));      
03097     }
03098 
03099     if (myActionDesired.getRotAccelStrength() >= ArActionDesired::MIN_STRENGTH)
03100     {
03101       rotAccel = ArMath::roundShort(myActionDesired.getRotAccel());
03102       if (ArMath::fabs(myLastSentRotAccel - rotAccel) >= 1)
03103       {
03104     comInt(ArCommands::SETRA,
03105            ArMath::roundShort(rotAccel));
03106     myLastSentRotAccel = rotAccel;
03107     if (myLogMovementSent)
03108       ArLog::log(ArLog::Normal, "%25sAction rot accel of %d", "",
03109              ArMath::roundShort(rotAccel));
03110       }
03111     }
03112     else if (hasSettableAccsDecs() && ArMath::fabs(myRotAccel) > 1 &&
03113     ArMath::fabs(myLastSentRotAccel - myRotAccel) >= 1)
03114     {
03115       comInt(ArCommands::SETRA,
03116          ArMath::roundShort(myRotAccel));
03117       myLastSentRotAccel = myRotAccel;
03118       if (myLogMovementSent)
03119     ArLog::log(ArLog::Normal, "%25sAction-but-robot rot accel of %d", 
03120            "", ArMath::roundShort(myRotAccel));      
03121     }
03122 
03123     if (myActionDesired.getRotDecelStrength() >= ArActionDesired::MIN_STRENGTH)
03124     {
03125       rotDecel = ArMath::roundShort(myActionDesired.getRotDecel());
03126       if (ArMath::fabs(myLastSentRotDecel - rotDecel) >= 1)
03127       {
03128     comInt(ArCommands::SETRA,
03129            -ArMath::roundShort(rotDecel));
03130     myLastSentRotDecel = rotDecel;
03131     if (myLogMovementSent)
03132       ArLog::log(ArLog::Normal, "%25sAction rot decel of %d", "",
03133              -ArMath::roundShort(rotDecel));
03134       }
03135     }
03136     else if (hasSettableAccsDecs() && ArMath::fabs(myRotDecel) > 1 &&
03137     ArMath::fabs(myLastSentRotDecel - myRotDecel) >= 1)
03138     {
03139       comInt(ArCommands::SETRA,
03140          -ArMath::roundShort(myRotDecel));
03141       myLastSentRotDecel = myRotDecel;
03142       if (myLogMovementSent)
03143     ArLog::log(ArLog::Normal, "%25sAction-but-robot rot decel of %d", 
03144            "", -ArMath::roundShort(myRotDecel));      
03145     }
03146 
03147 
03148 
03149     if (myActionDesired.getDeltaHeadingStrength() >=
03150                                          ArActionDesired::MIN_STRENGTH)
03151     {
03152       if (ArMath::roundShort(myActionDesired.getDeltaHeading()) == 0)
03153       {
03154     rotStopped = true;
03155     rotVal = 0;
03156     rotHeading = false;
03157       }
03158       else
03159       {
03160     //printf("delta %.0f\n", myActionDesired.getDeltaHeading());
03161     //encTh = ArMath::subAngle(myRotVal, myEncoderTransform.getTh());
03162     encTh = ArMath::subAngle(
03163         ArMath::addAngle(myActionDesired.getDeltaHeading(), 
03164                  getTh()),
03165         myEncoderTransform.getTh());
03166     //printf("final th %.0f\n", th);
03167     rawTh = ArMath::addAngle(encTh, 
03168                  ArMath::subAngle(myRawEncoderPose.getTh(),
03169                           myEncoderPose.getTh()));
03170     rotVal = ArMath::roundShort(rawTh);
03171     rotStopped = false;
03172     rotHeading = true;
03173     myTryingToMove = true;
03174       }
03175       myActionRotSet = true;
03176     } 
03177     else if (myActionDesired.getRotVelStrength() >=
03178                                          ArActionDesired::MIN_STRENGTH)
03179     {
03180       if (ArMath::roundShort(myActionDesired.getRotVel()) == 0)
03181       {
03182     rotStopped = true;
03183     rotVal = 0;
03184     rotHeading = false;
03185       }
03186       else
03187       {
03188     rotStopped = false;
03189     rotVal = ArMath::roundShort(myActionDesired.getRotVel());
03190     rotHeading = false;
03191     myTryingToMove = true;
03192       }
03193       myActionRotSet = true;
03194     }
03195     else
03196     {
03197       rotStopped = myLastActionRotStopped;
03198       rotVal = myLastActionRotVal;
03199       rotHeading = myLastActionRotHeading;
03200     }
03201 
03202     if (myActionRotSet && 
03203     (myLastRotSent.mSecSince() > myStateReflectionRefreshTime ||
03204      rotStopped != myLastActionRotStopped || 
03205      rotVal != myLastActionRotVal || 
03206      rotHeading != myLastActionRotHeading))
03207     {
03208       if (rotStopped)
03209       {
03210     comInt(ArCommands::RVEL, 0);
03211     if (myLogMovementSent)
03212       ArLog::log(ArLog::Normal, 
03213              "%25sAction rot vel of 0 (rotStopped)",
03214              "");
03215       }
03216       else if (rotHeading)
03217       {
03218     comInt(ArCommands::HEAD, rotVal);
03219     if (myLogMovementSent)
03220       ArLog::log(ArLog::Normal, 
03221              "%25sAction rot heading of %d (encoder %d, raw %d)",
03222              "",
03223              ArMath::roundShort(ArMath::addAngle(
03224                  myActionDesired.getDeltaHeading(), 
03225                  getTh())),
03226              ArMath::roundShort(encTh),
03227              ArMath::roundShort(rotVal));
03228       }
03229       else
03230       {
03231     comInt(ArCommands::RVEL, rotVal);
03232     if (myLogMovementSent)
03233       ArLog::log(ArLog::Normal, "%25sAction rot vel of %d", "", 
03234              rotVal);
03235       }
03236       myLastRotSent.setToNow();
03237     }           
03238     
03239     myLastActionRotVal = rotVal;
03240     myLastActionRotStopped = rotStopped;
03241     myLastActionRotHeading = rotHeading;
03242   }
03243 
03244   if (myLastRotSent.mSecSince() > myStateReflectionRefreshTime &&
03245       myLastTransSent.mSecSince() > myStateReflectionRefreshTime &&
03246       myLastPulseSent.mSecSince() > myStateReflectionRefreshTime)
03247   {
03248     com(ArCommands::PULSE);
03249     myLastPulseSent.setToNow();
03250     if (myLogMovementSent)
03251       ArLog::log(ArLog::Normal, "Pulse"); 
03252 
03253   }
03254 }
03255 
03256 AREXPORT bool ArRobot::handlePacket(ArRobotPacket *packet)
03257 {
03258   std::list<ArRetFunctor1<bool, ArRobotPacket *> *>::iterator it;
03259   bool handled;
03260 
03261   lock();
03262   //printf("ms since last packet %ld this type 0x%x\n", myLastPacketReceivedTime.mSecSince(packet->getTimeReceived()), packet->getID());
03263   myLastPacketReceivedTime = packet->getTimeReceived();
03264   if (packet->getID() == 0xff) 
03265   {
03266     ArLog::log(ArLog::Terse, "Losing connection because robot was reset.");
03267     dropConnection();
03268     unlock();
03269     return false;
03270   }
03271 
03272   for (handled = false, it = myPacketHandlerList.begin(); 
03273        it != myPacketHandlerList.end() && handled == false; 
03274        it++)
03275   {
03276     if ((*it) != NULL && (*it)->invokeR(packet)) 
03277       handled = true;
03278     else
03279       packet->resetRead();
03280   }
03281   if (!handled)
03282     ArLog::log(ArLog::Normal, 
03283            "No packet handler wanted packet with ID: 0x%x", 
03284            packet->getID());
03285   unlock();
03286   return handled;
03287 }
03288 
03289 
03293 AREXPORT long int ArRobot::getLeftEncoder()
03294 {
03295   return myLeftEncoder;
03296 }
03297 
03301 AREXPORT long int ArRobot::getRightEncoder()
03302 {
03303   return myRightEncoder;
03304 }
03305 
03306 
03311 AREXPORT void ArRobot::robotLocker(void)
03312 {
03313   lock();
03314 }
03315 
03320 AREXPORT void ArRobot::robotUnlocker(void)
03321 {
03322   unlock();
03323 }
03324 
03331 AREXPORT void ArRobot::packetHandler(void)
03332 {
03333   ArRobotPacket *packet;
03334   int timeToWait;
03335   ArTime start;
03336   bool sipHandled = false;
03337 
03338   if (myAsyncConnectFlag)
03339   {
03340     lock();
03341     asyncConnectHandler(false);
03342     unlock();
03343     return;
03344   }
03345 
03346   if (!isConnected())
03347     return;
03348 
03349   start.setToNow();
03350   /*
03351     The basic idea is that if we're chained to the sip we run through
03352     and see if we have any packets available now (like if we got
03353     backed up), we only check this for half the cycle time
03354     though... if we know the cycle time of the robot (from config)
03355     then we go for half that, if we don't know the cycle time of the
03356     robot (from config) then we go for half of whatever our cycle time
03357     is set to
03358 
03359     if we don't have any packets waiting then we chill and wait for
03360     it, if we got one, just get on with it
03361   **/
03362   packet = NULL;
03363   // read all the packets that are available
03364   while ((packet = myReceiver.receivePacket(0)) != NULL)
03365   {
03366     if (myPacketsReceivedTracking)
03367     {
03368       ArLog::log(ArLog::Normal, 
03369          "Rcvd: prePacket (%ld) 0x%x at %ld (%ld)", 
03370          myPacketsReceivedTrackingCount, 
03371          packet->getID(), start.mSecSince(), 
03372          myPacketsReceivedTrackingStarted.mSecSince());
03373       myPacketsReceivedTrackingCount++;
03374     }
03375 
03376     handlePacket(packet);
03377     if ((packet->getID() & 0xf0) == 0x30)
03378       sipHandled = true;
03379     packet = NULL;
03380 
03381     // if we've taken too long here then break
03382     if ((getOrigRobotConfig()->hasPacketArrived() &&
03383      start.mSecSince() > getOrigRobotConfig()->getSipCycleTime() / 2) ||
03384     (!getOrigRobotConfig()->hasPacketArrived() &&
03385      (unsigned int) start.mSecSince() > myCycleTime / 2))
03386     {
03387       break;
03388     }
03389   }
03390 
03391   if (isCycleChained())
03392     timeToWait = getCycleTime() * 2 - start.mSecSince();
03393   
03394   // if we didn't get a sip and we're chained to the sip, wait for the sip
03395   while (isCycleChained() && !sipHandled && isRunning() && 
03396      (packet = myReceiver.receivePacket(timeToWait)) != NULL)
03397   {
03398     if (myPacketsReceivedTracking)
03399     {
03400       ArLog::log(ArLog::Normal, "Rcvd: Packet (%ld) 0x%x at %ld (%ld)", 
03401          myPacketsReceivedTrackingCount, 
03402          packet->getID(), start.mSecSince(), 
03403          myPacketsReceivedTrackingStarted.mSecSince());
03404       myPacketsReceivedTrackingCount++;
03405     }
03406 
03407     handlePacket(packet);
03408     if ((packet->getID() & 0xf0) == 0x30)
03409       break;
03410     timeToWait = getCycleTime() * 2 - start.mSecSince();
03411     if (timeToWait < 0)
03412       timeToWait = 0;
03413   }
03414 
03415   if (myTimeoutTime > 0 && 
03416       ((-myLastPacketReceivedTime.mSecTo()) > myTimeoutTime))
03417   {
03418     ArLog::log(ArLog::Terse, 
03419            "Losing connection because nothing received from robot in %d milliseconds.", 
03420            myTimeoutTime);
03421     dropConnection();
03422   }
03423 
03424   if (myPacketsReceivedTracking)
03425     ArLog::log(ArLog::Normal, "Rcvd: time taken %ld", start.mSecSince());
03426 
03427 }
03428 
03436 AREXPORT void ArRobot::actionHandler(void)
03437 {
03438   ArActionDesired *actDesired;
03439 
03440   if (myResolver == NULL || myActions.size() == 0 || !isConnected())
03441     return;
03442   
03443   actDesired = myResolver->resolve(&myActions, this, myLogActions);
03444   
03445   myActionDesired.reset();
03446 
03447   if (actDesired == NULL)
03448     return;
03449 
03450   myActionDesired.merge(actDesired);  
03451 
03452   if (myLogActions)
03453   {
03454     ArLog::log(ArLog::Normal, "Final resolved desired:");
03455     myActionDesired.log();
03456   }
03457 }
03458 
03467 AREXPORT void ArRobot::setCycleWarningTime(unsigned int ms)
03468 {
03469   myCycleWarningTime = ms;
03470   // we don't have to send it down because the functor gets it each cycle
03471 }
03472 
03481 AREXPORT unsigned int ArRobot::getCycleWarningTime(void) const
03482 {
03483   return myCycleWarningTime;
03484 }
03485 
03494 AREXPORT unsigned int ArRobot::getCycleWarningTime(void)
03495 {
03496   return myCycleWarningTime;
03497 }
03498 
03506 AREXPORT void ArRobot::setCycleTime(unsigned int ms)
03507 {
03508   myCycleTime = ms;
03509 }
03510 
03523 AREXPORT void ArRobot::setStabilizingTime(int mSecs)
03524 {
03525   if (mSecs > 0)
03526     myStabilizingTime = mSecs;
03527   else
03528     myStabilizingTime = 0;
03529 }
03530 
03536 AREXPORT int ArRobot::getStabilizingTime(void) const
03537 {
03538   return myStabilizingTime;
03539 }
03540 
03548 AREXPORT unsigned int ArRobot::getCycleTime(void) const
03549 {
03550   return myCycleTime;
03551 }
03552 
03553 
03554 
03563 AREXPORT void ArRobot::setConnectionCycleMultiplier(unsigned int multiplier)
03564 {
03565   myConnectionCycleMultiplier = multiplier;
03566 }
03567 
03575 AREXPORT unsigned int ArRobot::getConnectionCycleMultiplier(void) const
03576 {
03577   return myConnectionCycleMultiplier;
03578 }
03579 
03580 
03587 AREXPORT void ArRobot::loopOnce(void)
03588 {
03589   if (mySyncTaskRoot != NULL)
03590     mySyncTaskRoot->run();
03591   
03592   incCounter();
03593 }
03594 
03595 
03596 // DigIn IR logic is reverse.  0 means broken, 1 means not broken
03597 
03598 AREXPORT bool ArRobot::isLeftTableSensingIRTriggered(void) const
03599 {
03600   if (myParams->haveTableSensingIR())
03601   {
03602     if (myParams->haveNewTableSensingIR() && myIODigInSize > 3)
03603       return !(getIODigIn(3) & ArUtil::BIT1);
03604     else
03605       return !(getDigIn() & ArUtil::BIT0);
03606   }
03607   return 0;
03608 }
03609 
03610 AREXPORT bool ArRobot::isRightTableSensingIRTriggered(void) const
03611 {
03612   if (myParams->haveTableSensingIR())
03613   {
03614     if (myParams->haveNewTableSensingIR() && myIODigInSize > 3) 
03615       return !(getIODigIn(3) & ArUtil::BIT0);
03616     else
03617       return !(getDigIn() & ArUtil::BIT1);
03618   }
03619   return 0;
03620 }
03621 
03622 AREXPORT bool ArRobot::isLeftBreakBeamTriggered(void) const
03623 {
03624   if (myParams->haveTableSensingIR())
03625   {
03626     if (myParams->haveNewTableSensingIR() && myIODigInSize > 3) 
03627       return !(getIODigIn(3) & ArUtil::BIT2);
03628     else
03629       return !(getDigIn() & ArUtil::BIT3);
03630   }
03631   return 0;
03632 }
03633 
03634 AREXPORT bool ArRobot::isRightBreakBeamTriggered(void) const
03635 {
03636   if (myParams->haveTableSensingIR())
03637   {
03638     if (myParams->haveNewTableSensingIR() && myIODigInSize > 3) 
03639       return !(getIODigIn(3) & ArUtil::BIT3);
03640     else
03641       return !(getDigIn() & ArUtil::BIT2);
03642   }
03643   return 0;
03644 }
03645 
03646 AREXPORT int ArRobot::getMotorPacCount(void) const
03647 {
03648   if (myTimeLastMotorPacket == time(NULL))
03649     return myMotorPacCount;
03650   if (myTimeLastMotorPacket == time(NULL) - 1)
03651     return myMotorPacCurrentCount;
03652   return 0;
03653 }
03654 
03655 AREXPORT int ArRobot::getSonarPacCount(void) const
03656 {
03657   if (myTimeLastSonarPacket == time(NULL))
03658     return mySonarPacCount;
03659   if (myTimeLastSonarPacket == time(NULL) - 1)
03660     return mySonarPacCurrentCount;
03661   return 0;
03662 }
03663 
03664 
03665 AREXPORT bool ArRobot::processMotorPacket(ArRobotPacket *packet)
03666 {
03667   int x, y, th, qx, qy, qth; 
03668   double deltaX, deltaY, deltaTh;
03669 
03670   int numReadings;
03671   int sonarNum;
03672   int sonarRange;
03673 
03674   if (packet->getID() != 0x32 && packet->getID() != 0x33) 
03675     return false;
03676 
03677   // upkeep the counting variable
03678   if (myTimeLastMotorPacket != time(NULL)) 
03679   {
03680     myTimeLastMotorPacket = time(NULL);
03681     myMotorPacCount = myMotorPacCurrentCount;
03682     myMotorPacCurrentCount = 0;
03683   }
03684   myMotorPacCurrentCount++;
03685 
03686   x = (packet->bufToUByte2() & 0x7fff);
03687   y = (packet->bufToUByte2() & 0x7fff);
03688   th = packet->bufToByte2();
03689 
03690   if (myFirstEncoderPose)
03691   {
03692     qx = 0;
03693     qy = 0;
03694     qth = 0;
03695     myFirstEncoderPose = false;
03696     myRawEncoderPose.setPose(
03697         myParams->getDistConvFactor() * x,
03698         myParams->getDistConvFactor() * y, 
03699         ArMath::radToDeg(myParams->getAngleConvFactor() * (double)th));
03700     myEncoderPose = myRawEncoderPose;
03701     myEncoderTransform.setTransform(myEncoderPose, myGlobalPose);
03702   }
03703   else 
03704   {
03705     qx = x - myLastX;
03706     qy = y - myLastY;
03707     qth = th - myLastTh;
03708   }
03709 
03710 
03711   //ArLog::log(ArLog::Terse, "Damnit qx %d qy %d,  x %d y %d,  lastx %d lasty %d", qx, qy, x, y, myLastX, myLastY);  
03712   myLastX = x;
03713   myLastY = y;
03714   myLastTh = th;
03715 
03716   if (qx > 0x1000) 
03717     qx -= 0x8000;
03718   if (qx < -0x1000)
03719     qx += 0x8000;
03720 
03721   if (qy > 0x1000) 
03722     qy -= 0x8000;
03723   if (qy < -0x1000)
03724     qy += 0x8000;
03725   
03726   deltaX = myParams->getDistConvFactor() * (double)qx;
03727   deltaY = myParams->getDistConvFactor() * (double)qy;
03728   deltaTh = ArMath::radToDeg(myParams->getAngleConvFactor() * (double)qth);
03729   //encoderTh = ArMath::radToDeg(myParams->getAngleConvFactor() * (double)(th));
03730 
03731 
03732   // encoder stuff was here
03733 
03734 
03735 
03736   myLeftVel = myParams->getVelConvFactor() * packet->bufToByte2();
03737   myRightVel = myParams->getVelConvFactor() * packet->bufToByte2();
03738   myVel = (myLeftVel + myRightVel)/2.0;
03739 
03740   myBatteryVoltage = packet->bufToUByte() * .1;
03741   myBatteryAverager.add(myBatteryVoltage);
03742   myStallValue = packet->bufToByte2();
03743   
03744   //ArLog::log("x %.1f y %.1f th %.1f vel %.1f voltage %.1f", myX, myY, myTh, 
03745   //myVel, myBatteryVoltage);
03746 
03747   myControl = ArMath::fixAngle(ArMath::radToDeg(myParams->getAngleConvFactor() *
03748                   (packet->bufToByte2() - th)));
03749   myFlags = packet->bufToUByte2();
03750   myCompass = 2*packet->bufToUByte();
03751   
03752   for (numReadings = packet->bufToByte(); numReadings > 0; numReadings--)
03753   {
03754     sonarNum = packet->bufToByte();
03755     sonarRange = ArMath::roundInt(
03756         (double)packet->bufToUByte2() * myParams->getRangeConvFactor());
03757     processNewSonar(sonarNum, sonarRange, packet->getTimeReceived());
03758   }
03759   
03760   if (packet->getDataLength() - packet->getDataReadLength() > 0)
03761   {
03762     myAnalogPortSelected = packet->bufToUByte2();
03763     myAnalog = packet->bufToByte();
03764     myDigIn = packet->bufToByte();
03765     myDigOut = packet->bufToByte();
03766   }
03767 
03768   if (packet->getDataLength() - packet->getDataReadLength() > 0)
03769     myRealBatteryVoltage = packet->bufToUByte2() * .1;
03770   else
03771     myRealBatteryVoltage = myBatteryVoltage;
03772 
03773   myRealBatteryAverager.add(myRealBatteryVoltage);
03774 
03775   if (packet->getDataLength() - packet->getDataReadLength() > 0)
03776     myChargeState = (ChargeState) packet->bufToUByte();
03777   else
03778     myChargeState = CHARGING_UNKNOWN;
03779 
03780   if (packet->getDataLength() - packet->getDataReadLength() > 0)
03781     myRotVel = (double)packet->bufToByte2() / 10.0;
03782   else
03783     myRotVel = ArMath::radToDeg((myRightVel - myLeftVel) / 2.0 * 
03784                 myParams->getDiffConvFactor());
03785 
03786   if (packet->getDataLength() - packet->getDataReadLength() > 0)
03787   {
03788     myHasFaultFlags = true;
03789     myFaultFlags = packet->bufToUByte2();  
03790   }
03791   else
03792   {
03793     myHasFaultFlags = false;
03794     myFaultFlags = packet->bufToUByte2();  
03795   }
03796   /*
03797     Okay how this works is like so.  
03798 
03799     We keep around the raw encoder position, because we must use this
03800     to find differences between last position and this position.
03801     
03802     We find the difference in x and y positions (deltaX and deltaY)
03803     and keep these around for later use, but we also add these to our
03804     raw encoder readings for X and Y.  We also find the change in
03805     angle (deltaTh), which is used for inertial corrections, and added
03806     to the raw encoder heading to find which the current raw encoder
03807     heading.
03808 
03809 
03810     From here there are two paths:
03811 
03812     Path 1) Have a callback.  If we have a callback it means that we
03813     have an inertial nav device of some kind.  If this is the case,
03814     then we pass the callback the delta between last position and
03815     current position, along with the time of the current position,
03816     then the callback gives us back a new delta theta (deltaTh).  We
03817     then need to rotate the deltaX and deltaY into our corrected
03818     encoder space.  We do this by making a transform that takes the
03819     raw encoder heading and transforms it to what our new heading is
03820     (adding deltaTh to our current encoder th), and then applying that
03821     transform, taking the results as our new deltaX and deltaY.
03822 
03823     Path 2) We have no callback, we just use the heading that came
03824     back from the robot as our delta theta (deltaTh);
03825 
03826     From here the two paths unify again.  deltaX and deltaY are added
03827     to the encoder pose (this is the corrected encoder pose), and the
03828     encoder heading is set to the newTh.
03829 
03830     Note that this leaves a difference between rawEncoder heading and
03831     our heading, which is fine, BUT if you are sending heading
03832     commands to the robot you need to compenstate for the difference
03833     between these. 
03834     
03835     Note above that we return deltaTh instead of just heading so that
03836     we can turn inertial on and off without losing track of where
03837     we're at... since we're just adding in deltas from the heading it
03838     doesn't matter how we switch around the callback.
03839     
03840   **/
03841 
03842   myRawEncoderPose.setX(myRawEncoderPose.getX() + deltaX);
03843   myRawEncoderPose.setY(myRawEncoderPose.getY() + deltaY);
03844   myRawEncoderPose.setTh(myRawEncoderPose.getTh() + deltaTh);
03845 
03846   // check if there is a correction callback, if there is get the new
03847   // heading out of it instead of using the raw encoder heading
03848   if (myEncoderCorrectionCB != NULL)
03849   {
03850     ArPoseWithTime deltaPose(deltaX, deltaY, deltaTh,
03851                  packet->getTimeReceived());
03852     deltaTh = myEncoderCorrectionCB->invokeR(deltaPose);   
03853     ArTransform trans(ArPose(0, 0, myRawEncoderPose.getTh()),
03854               ArPose(0, 0,
03855                  ArMath::addAngle(myEncoderPose.getTh(), 
03856                           deltaTh)));
03857 
03858     ArPose rotatedDelta = trans.doTransform(ArPose(deltaX, deltaY, 0));
03859 
03860     deltaX = rotatedDelta.getX();
03861     deltaY = rotatedDelta.getY();
03862   }
03863 
03864   myEncoderPose.setTime(packet->getTimeReceived());
03865   myEncoderPose.setX(myEncoderPose.getX() + deltaX);
03866   myEncoderPose.setY(myEncoderPose.getY() + deltaY);
03867   myEncoderPose.setTh(ArMath::addAngle(myEncoderPose.getTh(), deltaTh));
03868 
03869   myGlobalPose = myEncoderTransform.doTransform(myEncoderPose);
03870 
03871   myOdometerDegrees += fabs(deltaTh);
03872   myOdometerDistance += sqrt(fabs(deltaX * deltaX + deltaY * deltaY));
03873 
03874   if (myLogMovementReceived)
03875     ArLog::log(ArLog::Normal, 
03876            "Global (%5.0f %5.0f %5.0f) Encoder (%5.0f %5.0f %5.0f) Raw (%5.0f %5.0f %5.0f) Rawest (%5d %5d %5d) Delta (%5.0f %5.0f %5.0f) Conv %5.2f",
03877            myGlobalPose.getX(), myGlobalPose.getY(),
03878            myGlobalPose.getTh(),
03879            myEncoderPose.getX(), myEncoderPose.getY(),
03880            myEncoderPose.getTh(),
03881            myRawEncoderPose.getX(), myRawEncoderPose.getY(), 
03882            myRawEncoderPose.getTh(), x, y, th, deltaX, deltaY, deltaTh,
03883            myParams->getDistConvFactor());        
03884 
03885   if (myLogVelocitiesReceived)
03886     ArLog::log(ArLog::Normal, 
03887            "     TransVel: %4.0f RotVel: %4.0f(%4.0f) Heading %4.0f TransAcc %4.0f RotAcc %4.0f(%4.0f)",
03888            myVel, myRotVel, myLastHeading - getTh(), getTh(), 
03889            myVel - myLastVel, myRotVel - myLastRotVel,
03890            myLastCalculatedRotVel - (myLastHeading - getTh()));
03891   myLastVel = myVel;
03892   myLastRotVel = myRotVel;
03893   myLastHeading = getTh();
03894   myLastCalculatedRotVel = myLastHeading - getTh();
03895 
03896   //ArLog::log(ArLog::Terse, "(%.0f %.0f) (%.0f %.0f)", deltaX, deltaY, myGlobalPose.getX(),         myGlobalPose.getY());
03897   
03898   myInterpolation.addReading(packet->getTimeReceived(), myGlobalPose);
03899   myEncoderInterpolation.addReading(packet->getTimeReceived(), myEncoderPose);
03900 
03901   return true;
03902 }
03903 
03904 AREXPORT void ArRobot::processNewSonar(char number, int range, 
03905                        ArTime timeReceived)
03906 {
03915   std::map<int, ArSensorReading *>::iterator it;
03916   ArSensorReading *sonar;
03917   ArTransform encoderTrans;
03918   ArPose encoderPose;
03919 
03920   if ((it = mySonars.find(number)) != mySonars.end())
03921   {
03922     sonar = (*it).second;
03923     sonar->newData(range, getPose(), getEncoderPose(), getToGlobalTransform(), 
03924            getCounter(), timeReceived); 
03925     if (myTimeLastSonarPacket != time(NULL)) 
03926     {
03927       myTimeLastSonarPacket = time(NULL);
03928       mySonarPacCount = mySonarPacCurrentCount;
03929       mySonarPacCurrentCount = 0;
03930     }
03931     mySonarPacCurrentCount++;
03932   }
03933   else if (!myWarnedAboutExtraSonar)
03934   {
03935     ArLog::log(ArLog::Normal, "Robot gave back extra sonar reading!  Either the parameter file for the robot or the firmware needs updating.");
03936     myWarnedAboutExtraSonar = true;
03937   }
03938 }
03939 
03940 
03941 
03942 AREXPORT bool ArRobot::processEncoderPacket(ArRobotPacket *packet)
03943 {
03944   if (packet->getID() != 0x90)
03945     return false;
03946   myLeftEncoder = packet->bufToByte4();
03947   myRightEncoder = packet->bufToByte4();
03948   return true;
03949 }
03950 
03951 AREXPORT bool ArRobot::processIOPacket(ArRobotPacket *packet)
03952 {
03953   int i, num;
03954 
03955   if (packet->getID() != 0xf0)
03956     return false;
03957 
03958   myLastIOPacketReceivedTime = packet->getTimeReceived();
03959 
03960   // number of DigIn bytes
03961   num = packet->bufToUByte();
03962   for (i = 0; i < num; ++i)
03963     myIODigIn[i] = packet->bufToUByte();
03964   myIODigInSize = num;
03965 
03966   // number of DigOut bytes
03967   num = packet->bufToUByte();
03968   for (i = 0; i < num; ++i)
03969     myIODigOut[i] = packet->bufToUByte();
03970   myIODigOutSize = num;
03971 
03972   // number of A/D bytes
03973   num = packet->bufToUByte();
03974   for (i = 0; i < num; ++i)
03975     myIOAnalog[i] = packet->bufToUByte2();
03976   myIOAnalogSize = num;
03977 
03978   return true;
03979 }
03980 
03990 AREXPORT int ArRobot::getSonarRange(int num) const
03991 {
03992   std::map<int, ArSensorReading *>::const_iterator it;
03993   
03994   if ((it = mySonars.find(num)) != mySonars.end())
03995     return (*it).second->getRange();
03996   else
03997     return -1;
03998 }
03999 
04010 AREXPORT bool ArRobot::isSonarNew(int num) const
04011 {
04012   std::map<int, ArSensorReading *>::const_iterator it;
04013   
04014   if ((it = mySonars.find(num)) != mySonars.end())
04015     return (*it).second->isNew(getCounter());
04016   else
04017     return false;
04018 }
04019 
04032 AREXPORT ArSensorReading *ArRobot::getSonarReading(int num) const
04033 {
04034   std::map<int, ArSensorReading *>::const_iterator it;
04035   
04036   if ((it = mySonars.find(num)) != mySonars.end())
04037     return (*it).second;
04038   else
04039     return NULL;
04040 }
04041 
04042 
04048 AREXPORT bool ArRobot::com(unsigned char command)
04049 {
04050   if (myPacketsSentTracking)
04051     ArLog::log(ArLog::Normal, "Sent: com(%d)", command);
04052   return mySender.com(command);
04053 }
04054 
04061 AREXPORT bool ArRobot::comInt(unsigned char command, short int argument)
04062 {
04063   if (myPacketsSentTracking)
04064     ArLog::log(ArLog::Normal, "Sent: comInt(%d, %d)", command, argument);
04065   return mySender.comInt(command, argument);
04066 }
04067 
04075 AREXPORT bool ArRobot::com2Bytes(unsigned char command, char high, char low)
04076 {
04077   if (myPacketsSentTracking)
04078     ArLog::log(ArLog::Normal, "Sent: com2Bytes(%d, %d, %d)", command, 
04079            high, low);
04080   return mySender.com2Bytes(command, high, low);
04081 }
04082 
04089 AREXPORT bool ArRobot::comStr(unsigned char command, const char *argument)
04090 {
04091   if (myPacketsSentTracking)
04092     ArLog::log(ArLog::Normal, "Sent: comStr(%d, '%s')", command, 
04093            argument);
04094   return mySender.comStr(command, argument);
04095 }
04096 
04106 AREXPORT bool ArRobot::comStrN(unsigned char command, const char *str, 
04107                    int size)
04108 {
04109   if (myPacketsSentTracking)
04110   {
04111     char strBuf[512];
04112     strncpy(strBuf, str, size);
04113     strBuf[size] = '\0';
04114     ArLog::log(ArLog::Normal, "Sent: comStrN(%d, '%s') (size %d)",
04115            command, strBuf, size);
04116   }
04117   return mySender.comStrN(command, str, size);
04118 }
04119 
04120 AREXPORT bool ArRobot::comDataN(unsigned char command, const char* data, int size)
04121 {
04122   if(myPacketsSentTracking)
04123   {
04124     ArLog::log(ArLog::Normal, "Sent: comDataN(%d, <data...>) (size %d)", command, size);
04125   }
04126   return mySender.comDataN(command, data, size);
04127 }
04128 
04129 
04130 AREXPORT int ArRobot::getClosestSonarRange(double startAngle, double endAngle) const
04131 {
04132   int num;
04133   num = getClosestSonarNumber(startAngle, endAngle);
04134   if (num == -1)
04135     return -1;
04136   else 
04137     return getSonarRange(num);
04138 }
04139 
04140 AREXPORT int ArRobot::getClosestSonarNumber(double startAngle, double endAngle) const
04141 {
04142   int i;
04143   ArSensorReading *sonar;
04144   int closestReading;
04145   int closestSonar;
04146   bool noReadings = true;
04147 
04148   for (i = 0; i < getNumSonar(); i++) 
04149   {
04150     sonar = getSonarReading(i);
04151     if (sonar == NULL)
04152     {
04153       ArLog::log(ArLog::Terse, "Have an empty sonar at number %d, there should be %d sonar.", i, getNumSonar());
04154       continue;
04155     }
04156     if (ArMath::angleBetween(sonar->getSensorTh(), startAngle, endAngle))
04157     {
04158       if (noReadings)
04159       {
04160     closestReading = sonar->getRange();
04161     closestSonar = i;
04162     noReadings = false;
04163       }
04164       else if (sonar->getRange() < closestReading)
04165       {
04166     closestReading = sonar->getRange();
04167     closestSonar = i;
04168       }
04169     }
04170   }
04171 
04172   if (noReadings)
04173     return -1;
04174   else
04175     return closestSonar;
04176 }
04177 
04178 AREXPORT void ArRobot::addRangeDevice(ArRangeDevice *device)
04179 {
04180   device->setRobot(this);
04181   myRangeDeviceList.push_front(device);
04182 }
04183 
04187 AREXPORT void ArRobot::remRangeDevice(const char *name)
04188 {
04189   std::list<ArRangeDevice *>::iterator it;
04190   for (it = myRangeDeviceList.begin(); it != myRangeDeviceList.end(); ++it)
04191   {
04192     if (strcmp(name, (*it)->getName()) == 0)
04193     {
04194       myRangeDeviceList.erase(it);
04195       return;
04196     }
04197   }
04198 }
04199 
04203 AREXPORT void ArRobot::remRangeDevice(ArRangeDevice *device)
04204 {
04205   std::list<ArRangeDevice *>::iterator it;
04206   for (it = myRangeDeviceList.begin(); it != myRangeDeviceList.end(); ++it)
04207   {
04208     if ((*it) == device)
04209     {
04210       myRangeDeviceList.erase(it);
04211       return;
04212     }
04213   }
04214 }
04215 
04220 AREXPORT ArRangeDevice *ArRobot::findRangeDevice(const char *name)
04221 {
04222   std::list<ArRangeDevice *>::iterator it;
04223   ArRangeDevice *device;
04224 
04225   for (it = myRangeDeviceList.begin(); it != myRangeDeviceList.end(); ++it)
04226   {
04227     device = (*it);
04228     if(strcmp(name, device->getName()) == 0)
04229     {
04230       return device;
04231     }
04232   }
04233   return NULL;
04234 }
04235 
04240 AREXPORT const ArRangeDevice *ArRobot::findRangeDevice(const char *name) const
04241 {
04242   std::list<ArRangeDevice *>::const_iterator it;
04243   ArRangeDevice *device;
04244 
04245   for (it = myRangeDeviceList.begin(); it != myRangeDeviceList.end(); ++it)
04246   {
04247     device = (*it);
04248     if(strcmp(name, device->getName()) == 0)
04249     {
04250       return device;
04251     }
04252   }
04253   return NULL;
04254 }
04255 
04262 AREXPORT std::list<ArRangeDevice *> *ArRobot::getRangeDeviceList(void)
04263 {
04264   return &myRangeDeviceList;
04265 }
04266 
04270 AREXPORT bool ArRobot::hasRangeDevice(ArRangeDevice *device) const
04271 {
04272   std::list<ArRangeDevice *>::const_iterator it;
04273   for (it = myRangeDeviceList.begin(); it != myRangeDeviceList.end(); ++it)
04274   {
04275     if ((*it) == device)
04276       return true;
04277   }
04278   return false;
04279 }
04280 
04295 AREXPORT double ArRobot::checkRangeDevicesCurrentPolar(
04296     double startAngle, double endAngle, double *angle, 
04297     const ArRangeDevice **rangeDevice,
04298     bool useLocationDependentDevices) const
04299 {
04300   double closest = 32000;
04301   double closeAngle, tempDist, tempAngle;
04302   std::list<ArRangeDevice *>::const_iterator it;
04303   ArRangeDevice *device;
04304   bool foundOne = false;
04305   const ArRangeDevice *closestRangeDevice = NULL;
04306 
04307   for (it = myRangeDeviceList.begin(); it != myRangeDeviceList.end(); ++it)
04308   {
04309     device = (*it);
04310     device->lockDevice();
04311     if (!useLocationDependentDevices && device->isLocationDependent())
04312     {
04313       device->unlockDevice();
04314       continue;
04315     }
04316     if (!foundOne || 
04317     (tempDist = device->currentReadingPolar(startAngle, endAngle,
04318                         &tempAngle)) < closest)
04319     {
04320       if (!foundOne)
04321       {
04322     closest = device->currentReadingPolar(startAngle, endAngle, 
04323                           &closeAngle);
04324     closestRangeDevice = device;
04325       }
04326       else
04327       {
04328     closest = tempDist;
04329     closeAngle = tempAngle;
04330     closestRangeDevice = device;
04331       }
04332       foundOne = true;
04333     }
04334     device->unlockDevice();
04335   }
04336   if (!foundOne)
04337     return -1;
04338   if (angle != NULL)
04339     *angle = closeAngle;
04340   if (rangeDevice != NULL)
04341     *rangeDevice = closestRangeDevice;
04342   return closest;
04343   
04344 }
04345 
04346 
04359 AREXPORT double ArRobot::checkRangeDevicesCumulativePolar(
04360     double startAngle, double endAngle, double *angle, 
04361     const ArRangeDevice **rangeDevice, 
04362     bool useLocationDependentDevices) const
04363 {
04364   double closest = 32000;
04365   double closeAngle, tempDist, tempAngle;
04366   std::list<ArRangeDevice *>::const_iterator it;
04367   ArRangeDevice *device;
04368   bool foundOne = false;
04369   const ArRangeDevice *closestRangeDevice = NULL;
04370 
04371   for (it = myRangeDeviceList.begin(); it != myRangeDeviceList.end(); ++it)
04372   {
04373     device = (*it);
04374     device->lockDevice();
04375     if (!useLocationDependentDevices && device->isLocationDependent())
04376     {
04377       device->unlockDevice();
04378       continue;
04379     }
04380     if (!foundOne || 
04381     (tempDist = device->cumulativeReadingPolar(startAngle, endAngle,
04382                          &tempAngle)) < closest)
04383     {
04384       if (!foundOne)
04385       {
04386     closest = device->cumulativeReadingPolar(startAngle, endAngle, 
04387                           &closeAngle);
04388     closestRangeDevice = device;
04389       }
04390       else
04391       {
04392     closest = tempDist;
04393     closeAngle = tempAngle;
04394     closestRangeDevice = device;
04395       }
04396       foundOne = true;
04397     }
04398     device->unlockDevice();
04399   }
04400   if (!foundOne)
04401     return -1;
04402   if (angle != NULL)
04403     *angle = closeAngle;
04404   if (rangeDevice != NULL)
04405     *rangeDevice = closestRangeDevice;
04406   return closest;
04407   
04408 }
04409 
04426 AREXPORT double ArRobot::checkRangeDevicesCurrentBox(
04427     double x1, double y1, double x2, double y2, ArPose *readingPos,
04428     const ArRangeDevice **rangeDevice, 
04429     bool useLocationDependentDevices) const
04430 {
04431 
04432   double closest = 32000;
04433   double tempDist;
04434   ArPose closestPos, tempPos;
04435   std::list<ArRangeDevice *>::const_iterator it;
04436   ArRangeDevice *device;
04437   bool foundOne = false;
04438   const ArRangeDevice *closestRangeDevice = NULL;
04439 
04440   for (it = myRangeDeviceList.begin(); it != myRangeDeviceList.end(); ++it)
04441   {
04442     device = (*it);
04443     device->lockDevice();
04444     if (!useLocationDependentDevices && device->isLocationDependent())
04445     {
04446       device->unlockDevice();
04447       continue;
04448     }
04449     if (!foundOne || 
04450     (tempDist = device->currentReadingBox(x1, y1, x2, y2, &tempPos)) < closest)
04451     {
04452       if (!foundOne)
04453       {
04454     closest = device->currentReadingBox(x1, y1, x2, y2, &closestPos);
04455     closestRangeDevice = device;
04456       }
04457       else
04458       {
04459     closest = tempDist;
04460     closestPos = tempPos;
04461     closestRangeDevice = device;
04462       }
04463       foundOne = true;
04464     }
04465     device->unlockDevice();
04466   }
04467   if (!foundOne)
04468     return -1;
04469   if (readingPos != NULL)
04470     *readingPos = closestPos;
04471   if (rangeDevice != NULL)
04472     *rangeDevice = closestRangeDevice;
04473   return closest;
04474 }
04475 
04492 AREXPORT double ArRobot::checkRangeDevicesCumulativeBox(
04493     double x1, double y1, double x2, double y2, ArPose *readingPos,
04494     const ArRangeDevice **rangeDevice, 
04495     bool useLocationDependentDevices) const
04496 {
04497 
04498   double closest = 32000;
04499   double tempDist;
04500   ArPose closestPos, tempPos;
04501   std::list<ArRangeDevice *>::const_iterator it;
04502   ArRangeDevice *device;
04503   bool foundOne = false;
04504   const ArRangeDevice *closestRangeDevice = NULL;
04505 
04506   for (it = myRangeDeviceList.begin(); it != myRangeDeviceList.end(); ++it)
04507   {
04508     device = (*it);
04509     device->lockDevice();
04510     if (!useLocationDependentDevices && device->isLocationDependent())
04511     {
04512       device->unlockDevice();
04513       continue;
04514     }
04515     if (!foundOne || 
04516     (tempDist = device->cumulativeReadingBox(x1, y1, x2, y2, &tempPos)) < closest)
04517     {
04518       if (!foundOne)
04519       {
04520     closest = device->cumulativeReadingBox(x1, y1, x2, y2, &closestPos);
04521     closestRangeDevice = device;
04522       }
04523       else
04524       {
04525     closest = tempDist;
04526     closestPos = tempPos;
04527     closestRangeDevice = device;
04528       }
04529       foundOne = true;
04530     }
04531     device->unlockDevice();
04532   }
04533   if (!foundOne)
04534     return -1;
04535   if (readingPos != NULL)
04536     *readingPos = closestPos;
04537   if (rangeDevice != NULL)
04538     *rangeDevice = closestRangeDevice;
04539   return closest;
04540 }
04541 
04554 AREXPORT void ArRobot::moveTo(ArPose pose, bool doCumulative)
04555 {
04556   std::list<ArRangeDevice *>::iterator it;
04557   ArSensorReading *son;
04558   int i;
04559 
04560   // we need to get this one now because changing the encoder
04561   // transform and global pose will change the local transform
04562   ArTransform localTransform;
04563   localTransform = getToLocalTransform();
04564 
04565   myEncoderTransform.setTransform(myEncoderPose, pose);
04566   myGlobalPose = myEncoderTransform.doTransform(myEncoderPose);
04567 
04568   for (it = myRangeDeviceList.begin(); it != myRangeDeviceList.end(); it++)
04569   {
04570     (*it)->lockDevice();
04571     (*it)->applyTransform(localTransform, doCumulative);
04572     (*it)->applyTransform(getToGlobalTransform(), doCumulative);
04573     (*it)->unlockDevice();
04574   }
04575 
04576   for (i = 0; i < getNumSonar(); i++)
04577   {
04578     son = getSonarReading(i);
04579     if (son != NULL)
04580     {
04581       son->applyTransform(localTransform);
04582       son->applyTransform(getToGlobalTransform());
04583     }
04584   }
04585 
04586   //ArLog::log(ArLog::Normal, "Robot moved to %.0f %.0f %.1f", getX(), getY(), getTh());
04587 }
04588 
04604 AREXPORT void ArRobot::moveTo(ArPose poseTo, ArPose poseFrom,
04605                   bool doCumulative)
04606 {
04607   std::list<ArRangeDevice *>::iterator it;
04608   ArSensorReading *son;
04609   int i;
04610 
04611   ArPose result = myEncoderTransform.doInvTransform(poseFrom);
04612 
04613   // we need to get this one now because changing the encoder
04614   // transform and global pose will change the local transform
04615   ArTransform localTransform;
04616   localTransform = getToLocalTransform();
04617 
04618   myEncoderTransform.setTransform(result, poseTo);
04619   myGlobalPose = myEncoderTransform.doTransform(myEncoderPose);
04620 
04621   for (it = myRangeDeviceList.begin(); it != myRangeDeviceList.end(); it++)
04622   {
04623     (*it)->lockDevice();
04624     (*it)->applyTransform(localTransform, doCumulative);
04625     (*it)->applyTransform(getToGlobalTransform(), doCumulative);
04626     (*it)->unlockDevice();
04627   }
04628 
04629   for (i = 0; i < getNumSonar(); i++)
04630   {
04631     son = getSonarReading(i);
04632     if (son != NULL)
04633     {
04634       son->applyTransform(localTransform);
04635       son->applyTransform(getToGlobalTransform());
04636     }
04637   }
04638 
04639   //ArLog::log(ArLog::Normal, "Robot moved to %.0f %.0f %.1f", getX(), getY(), getTh());
04640 }
04641 
04646 AREXPORT void ArRobot::setEncoderTransform(ArPose deadReconPos, 
04647                     ArPose globalPos)
04648 {
04649   myEncoderTransform.setTransform(deadReconPos, globalPos);
04650   myGlobalPose = myEncoderTransform.doTransform(myEncoderPose);
04651 }
04652 
04656 AREXPORT void ArRobot::setEncoderTransform(ArPose transformPos)
04657 {
04658   myEncoderTransform.setTransform(transformPos);
04659   myGlobalPose = myEncoderTransform.doTransform(myEncoderPose);
04660 }
04661 
04665 AREXPORT ArTransform ArRobot::getEncoderTransform(void) const
04666 {
04667   return myEncoderTransform;
04668 }
04669 
04673 AREXPORT void ArRobot::setDeadReconPose(ArPose pose)
04674 {
04675   myEncoderPose.setPose(pose);
04676   myEncoderTransform.setTransform(myEncoderPose, myGlobalPose);
04677   myGlobalPose = myEncoderTransform.doTransform(myEncoderPose);
04678 }
04679 
04680 
04685 AREXPORT ArTransform ArRobot::getToGlobalTransform(void) const
04686 {
04687   ArTransform trans;
04688   ArPose origin(0, 0, 0);
04689   ArPose pose = getPose();
04690 
04691   trans.setTransform(origin, pose);
04692   return trans;
04693 }
04694 
04699 AREXPORT ArTransform ArRobot::getToLocalTransform(void) const
04700 {
04701   ArTransform trans;
04702   ArPose origin(0, 0, 0);
04703   ArPose pose = getPose();
04704 
04705   trans.setTransform(pose, origin);
04706   return trans;
04707 }
04708 
04716 AREXPORT void ArRobot::applyTransform(ArTransform trans, bool doCumulative)
04717 {
04718   std::list<ArRangeDevice *>::iterator it;
04719   ArSensorReading *son;
04720   int i;
04721   
04722   for (it = myRangeDeviceList.begin(); it != myRangeDeviceList.end(); it++)
04723   {
04724       (*it)->lockDevice();
04725       (*it)->applyTransform(trans, doCumulative);
04726       (*it)->unlockDevice();
04727   }
04728 
04729   for (i = 0; i < getNumSonar(); i++)
04730   {
04731     son = getSonarReading(i);
04732     if (son != NULL)
04733       son->applyTransform(trans);
04734   }
04735 }
04736 
04737 AREXPORT const char *ArRobot::getName(void) const
04738 {
04739   return myName.c_str();
04740 }
04741 
04742 AREXPORT void ArRobot::setName(const char * name)
04743 {
04744     std::list<ArRobot *> *robotList;
04745     std::list<ArRobot *>::iterator it;
04746     int i;
04747     char buf[1024];
04748  
04749  if (name != NULL)
04750   {
04751     myName = name;
04752   }
04753   else
04754   {
04755 
04756     
04757 
04758     robotList = Aria::getRobotList();
04759     for (i = 1, it = robotList->begin(); it != robotList->end(); it++, i++)
04760     {
04761       if (this == (*it))
04762       {
04763         if (i == 1)
04764             myName = "robot";
04765         else
04766         {
04767             sprintf(buf, "robot%d", i);
04768             myName = buf;
04769         }
04770         return;
04771       }
04772     }
04773     sprintf(buf, "robot%d", robotList->size());
04774     myName = buf;
04775    }
04776 }
04777 
04788 AREXPORT void ArRobot::setEncoderCorrectionCallback(
04789     ArRetFunctor1<double, ArPoseWithTime> *functor)
04790 {
04791   myEncoderCorrectionCB = functor;
04792 }
04799 AREXPORT ArRetFunctor1<double, ArPoseWithTime> * 
04800 ArRobot::getEncoderCorrectionCallback(void) const
04801 {
04802   return myEncoderCorrectionCB;
04803 }
04804 
04815 AREXPORT void ArRobot::setDirectMotionPrecedenceTime(int mSec)
04816 {
04817   if (mSec < 0) 
04818     myDirectPrecedenceTime = 0;
04819   else
04820     myDirectPrecedenceTime = mSec;
04821 }
04822 
04832 AREXPORT unsigned int ArRobot::getDirectMotionPrecedenceTime(void) const
04833 {
04834   return myDirectPrecedenceTime;
04835 }
04836 
04837 
04844 AREXPORT void ArRobot::clearDirectMotion(void)
04845 {
04846   myTransType = TRANS_NONE;
04847   myLastTransType = TRANS_NONE;
04848   myRotType = ROT_NONE;
04849   myLastRotType = ROT_NONE;
04850   myLastActionTransVal = 0;
04851   myLastActionRotStopped = true;
04852   myLastActionRotHeading = false;
04853 }
04854 
04862 AREXPORT void ArRobot::stopStateReflection(void)
04863 {
04864   myTransType = TRANS_IGNORE;
04865   myLastTransType = TRANS_IGNORE;
04866   myRotType = ROT_IGNORE;
04867   myLastRotType = ROT_IGNORE;
04868 }
04869 
04874 AREXPORT bool ArRobot::isDirectMotion(void) const
04875 {
04876   if (myTransType ==  TRANS_NONE && myLastTransType == TRANS_NONE &&
04877       myRotType == ROT_NONE && myLastRotType == ROT_NONE)
04878     return false;
04879   else
04880     return true;
04881 }
04882 
04883 
04887 AREXPORT void ArRobot::enableMotors()
04888 {
04889   comInt(ArCommands::ENABLE, 1);
04890 }
04891 
04895 AREXPORT void ArRobot::disableMotors()
04896 {
04897   comInt(ArCommands::ENABLE, 0);
04898 }
04899 
04903 AREXPORT void ArRobot::enableSonar()
04904 {
04905   comInt(ArCommands::SONAR, 1);
04906 }
04907 
04911 AREXPORT void ArRobot::disableSonar()
04912 {
04913   comInt(ArCommands::SONAR, 0);
04914 }
04915 
04916 
04925 AREXPORT void ArRobot::setStateReflectionRefreshTime(int mSec)
04926 {
04927   if (mSec < 0)
04928     myStateReflectionRefreshTime = 0;
04929   else
04930     myStateReflectionRefreshTime = mSec;
04931 }
04932 
04940 AREXPORT int ArRobot::getStateReflectionRefreshTime(void) const
04941 {
04942   return myStateReflectionRefreshTime;
04943 }
04944 
04960 AREXPORT void ArRobot::attachKeyHandler(ArKeyHandler *keyHandler, 
04961                     bool exitOnEscape, 
04962                     bool useExitNotShutdown)
04963 {
04964   if (myKeyHandlerCB != NULL)
04965     delete myKeyHandlerCB;
04966   myKeyHandlerCB = new ArFunctorC<ArKeyHandler>(keyHandler, 
04967                         &ArKeyHandler::checkKeys);
04968   addSensorInterpTask("Key Handler", 50, myKeyHandlerCB);
04969 
04970   myKeyHandler = keyHandler;
04971   myKeyHandlerUseExitNotShutdown = useExitNotShutdown;
04972   if (exitOnEscape)
04973     keyHandler->addKeyHandler(ArKeyHandler::ESCAPE, &myKeyHandlerExitCB);
04974 }
04975 
04976 AREXPORT ArKeyHandler *ArRobot::getKeyHandler(void) const
04977 {
04978   return myKeyHandler;
04979 }
04980 
04981 AREXPORT void ArRobot::keyHandlerExit(void)
04982 {
04983   ArLog::log(ArLog::Terse, "Escape was pressed, program is exiting.");
04984   // if we're using exit not the keyhandler then call Aria::exit
04985   // instead of shutdown, this call never returns
04986   if (myKeyHandlerUseExitNotShutdown)
04987     Aria::exit();
04988   stopRunning();
04989   unlock();
04990   Aria::shutdown();
04991 }
04992 
04993 AREXPORT void ArRobot::setPacketsReceivedTracking(bool packetsReceivedTracking)
04994 {
04995   myPacketsReceivedTracking = packetsReceivedTracking;
04996   myPacketsReceivedTrackingCount = 0; 
04997   myPacketsReceivedTrackingStarted.setToNow(); 
04998 }
04999 
05000 AREXPORT void ArRobot::ariaExitCallback(void)
05001 {
05002   mySyncLoop.stopRunIfNotConnected(false);
05003   disconnect();
05004 }
05005 
05011 AREXPORT ArRobot::ChargeState ArRobot::getChargeState(void) const
05012 {
05013   return myChargeState;
05014 }
05015 
05016 AREXPORT void ArRobot::resetOdometer(void)
05017 {
05018   myOdometerDistance = 0;
05019   myOdometerDegrees = 0;
05020   myOdometerStart.setToNow();
05021 }

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