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

ArSickLogger.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 <stdarg.h>
00027 
00028 #include "ArExport.h"
00029 #include "ariaOSDef.h"
00030 #include "ArSickLogger.h"
00031 #include "ArRobot.h"
00032 #include "ArSick.h"
00033 #include "ArJoyHandler.h"
00034 #include "ArRobotJoyHandler.h"
00035 #include "ariaInternal.h"
00036 
00057 AREXPORT ArSickLogger::ArSickLogger(ArRobot *robot, ArSick *sick, 
00058                     double distDiff, double degDiff, 
00059                     const char *fileName, bool addGoals,
00060                     ArJoyHandler *joyHandler,
00061                     const char *baseDirectory, 
00062                     bool useReflectorValues,
00063                     ArRobotJoyHandler *robotJoyHandler) :
00064   mySectors(18), 
00065   myTaskCB(this, &ArSickLogger::robotTask),
00066   myGoalKeyCB(this, &ArSickLogger::goalKeyCallback), 
00067   myLoopPacketHandlerCB(this, &ArSickLogger::loopPacketHandler)
00068 {
00069   ArKeyHandler *keyHandler;
00070   
00071   ArSick::Degrees degrees;
00072   ArSick::Increment increment;
00073   double deg, incr;
00074 
00075   myOldReadings = false;
00076   myNewReadings = true;
00077   myUseReflectorValues = useReflectorValues;
00078   myWrote = false;
00079   myRobot = robot;
00080   mySick = sick;
00081   if (baseDirectory != NULL && strlen(baseDirectory) > 0)
00082     myBaseDirectory = baseDirectory;
00083   else
00084     myBaseDirectory = "";
00085   std::string realFileName;
00086   if (fileName[0] == '/' || fileName[0] == '\\')
00087   {
00088     realFileName = fileName;
00089   }
00090   else
00091   {
00092     realFileName = myBaseDirectory;
00093     realFileName += fileName;
00094   }
00095   myFileName = realFileName;
00096   
00097   myFile = fopen(realFileName.c_str(), "w+");
00098   degrees = mySick->getDegrees();
00099   increment = mySick->getIncrement();
00100   if (degrees == ArSick::DEGREES180)
00101     deg = 180;
00102   else 
00103     deg = 100;
00104   if (increment == ArSick::INCREMENT_ONE)
00105     incr = 1;
00106   else
00107     incr = .5;
00108   if (myFile != NULL)
00109   {
00110     const ArRobotParams *params;
00111     params = robot->getRobotParams();
00112     fprintf(myFile, "LaserOdometryLog\n");
00113     fprintf(myFile, "#Created by ARIA's ArSickLogger\n");
00114     fprintf(myFile, "version: 2\n");
00115     fprintf(myFile, "sick1pose: %d %d %.2f\n", params->getLaserX(), 
00116         params->getLaserY(), params->getLaserTh());
00117     fprintf(myFile, "sick1conf: %d %d %d\n", 
00118         ArMath::roundInt(0.0 - deg / 2.0),
00119         ArMath::roundInt(deg / 2.0), ArMath::roundInt(deg / incr + 1.0));
00120   }
00121   else
00122     ArLog::log(ArLog::Terse, "ArSickLogger cannot write to file %s", 
00123            myFileName.c_str());
00124 
00125   myDistDiff = distDiff;
00126   myDegDiff = degDiff;
00127   myFirstTaken = false;
00128   myScanNumber = 0;
00129   myLastVel = 0;
00130   myStartTime.setToNow();
00131   myRobot->addUserTask("Sick Logger", 1, &myTaskCB);
00132 
00133   char uCFileName[15];
00134   strncpy(uCFileName, fileName, 14);
00135   uCFileName[14] = '\0';
00136   myRobot->comStr(94, uCFileName);
00137 
00138   myLoopPacketHandlerCB.setName("ArSickLogger");
00139   myRobot->addPacketHandler(&myLoopPacketHandlerCB);
00140 
00141   myAddGoals = addGoals;
00142   myJoyHandler = joyHandler;
00143   myRobotJoyHandler = robotJoyHandler;
00144   myTakeReadingExplicit = false;
00145   myAddGoalExplicit = false;
00146   myAddGoalKeyboard = false;
00147   myLastAddGoalKeyboard = false;
00148   myLastJoyButton = false;
00149   myLastRobotJoyButton = false;
00150   myFirstGoalTaken = false;
00151   myNumGoal = 1;
00152   myLastLoops = 0;
00153   // only add goals from the keyboard if there's already a keyboard handler
00154   if (myAddGoals && (keyHandler = Aria::getKeyHandler()) != NULL)
00155   {
00156     // now that we have a key handler, add our keys as callbacks, print out big
00157     // warning messages if they fail
00158     if (!keyHandler->addKeyHandler('g', &myGoalKeyCB))
00159       ArLog::log(ArLog::Terse, "The key handler already has a key for g, sick logger goal handling will not work correctly.");
00160     if (!keyHandler->addKeyHandler('G', &myGoalKeyCB))
00161       ArLog::log(ArLog::Terse, "The key handler already has a key for g, sick logger goal handling will not work correctly.");
00162   }
00163 }
00164 
00165 AREXPORT ArSickLogger::~ArSickLogger()
00166 {
00167   myRobot->remUserTask(&myTaskCB);
00168   myRobot->remPacketHandler(&myLoopPacketHandlerCB);
00169   myRobot->comStr(94, "");
00170   if (myFile != NULL)
00171   {
00172     fprintf(myFile, "# End of log\n");
00173     fclose(myFile);
00174   }
00175 }
00176   
00177 AREXPORT bool ArSickLogger::loopPacketHandler(ArRobotPacket *packet)
00178 {
00179   unsigned char loops;
00180   if (packet->getID() != 0x96)
00181     return false;
00182   loops = packet->bufToUByte();
00183   unsigned char bit;
00184   int num;
00185   if (loops != myLastLoops)
00186   {
00187     for (bit = 1, num = 1; num <= 8; bit *= 2, num++)
00188     {
00189       if ((loops & bit) && !(myLastLoops & bit))
00190       {
00191     addTagToLog("loop: start %d", num);
00192     ArLog::log(ArLog::Normal, "Starting loop %d", num);
00193       }
00194       else if (!(loops & bit) && (myLastLoops & bit))
00195       {
00196     addTagToLog("loop: end %d", num);
00197     ArLog::log(ArLog::Normal, "Ending loop %d", num);
00198       }
00199     }
00200   }
00201   myLastLoops = loops;
00202   return true;
00203 }
00204 
00213 AREXPORT void ArSickLogger::addTagToLogPlain(const char *str)
00214 {
00215   myTags.push_back(str);
00216 }
00217 
00226 AREXPORT void ArSickLogger::addTagToLog(const char *str, ...)
00227 {
00228   char buf[2048];
00229   va_list ptr;
00230   va_start(ptr, str);
00231   vsprintf(buf, str, ptr);
00232   addTagToLogPlain(buf);
00233   va_end(ptr);
00234 }
00235 
00236 
00245 AREXPORT void ArSickLogger::addInfoToLogPlain(const char *str)
00246 {
00247   myInfos.push_back(str);
00248 }
00249 
00257 AREXPORT void ArSickLogger::addInfoToLog(const char *str, ...)
00258 {
00259   char buf[2048];
00260   va_list ptr;
00261   va_start(ptr, str);
00262   vsprintf(buf, str, ptr);
00263   addInfoToLogPlain(buf);
00264   va_end(ptr);
00265 }
00266 
00267 void ArSickLogger::goalKeyCallback(void)
00268 {
00269   myAddGoalKeyboard = true;
00270 }
00271 
00272 void ArSickLogger::internalAddGoal(void)
00273 {
00274   bool joyButton;
00275   bool robotJoyButton;
00276 
00277   // this check is for if we're not adding goals return... but if
00278   // we're not adding goals and one was requested explicitly then add
00279   // that one
00280   if (!myAddGoals && !myAddGoalExplicit) 
00281     return;
00282   
00283   if (myJoyHandler != NULL)
00284     joyButton = (myJoyHandler->getButton(2) || 
00285            myJoyHandler->getButton(3) || 
00286            myJoyHandler->getButton(4));
00287   else
00288     joyButton = (myRobot->getFlags() & ArUtil::BIT9);
00289   
00290   if (myRobotJoyHandler != NULL)
00291     robotJoyButton = myRobotJoyHandler->getButton2();
00292   else
00293     robotJoyButton = false;
00294 
00295   // see if we want to add a goal... note that if the button is pushed
00296   // it must have been unpushed at one point to cause the goal to
00297   // trigger
00298   if (myRobot->isConnected() && 
00299       (myAddGoalExplicit ||
00300        (myAddGoalKeyboard && !myLastAddGoalKeyboard) ||
00301        (joyButton && !myLastJoyButton) ||
00302        (robotJoyButton && !myLastRobotJoyButton)))
00303   {
00304     myFirstGoalTaken = true;
00305     myAddGoalExplicit = false;
00306     myLastGoalTakenTime.setToNow();
00307     myLastGoalTakenPose = myRobot->getEncoderPose();
00308     // call addTagToLog not do it directly so we get additional info
00309     // needed
00310     addTagToLog("cairn: GoalWithHeading \"\" ICON_GOALWITHHEADING \"goal%d\"", myNumGoal);
00311     ArLog::log(ArLog::Normal, "Goal %d taken", myNumGoal);
00312     myNumGoal++;
00313   }
00314   myLastAddGoalKeyboard = myAddGoalKeyboard;
00315   myLastJoyButton = joyButton;
00316   myLastRobotJoyButton = robotJoyButton;
00317       
00318   // reset this here for if they held the key down a little, so it
00319   // gets reset and doesn't hit multiple goals
00320   myAddGoalKeyboard = false;
00321 }
00322 
00323 void ArSickLogger::internalWriteTags(void)
00324 {
00325   time_t msec;
00326 
00327   // now put the tags into the file
00328   while (myInfos.size() > 0)
00329   {
00330     if (myFile != NULL)
00331     {
00332       myWrote = true;
00333       fprintf(myFile, "%s\n", (*myInfos.begin()).c_str());
00334     }
00335     myInfos.pop_front();
00336   }
00337 
00338 
00339   // now put the tags into the file
00340   while (myTags.size() > 0)
00341   {
00342     if (myFile != NULL)
00343     {
00344       myWrote = true;
00345       msec = myStartTime.mSecSince();
00346       fprintf(myFile, "time: %ld.%ld\n", msec / 1000, msec % 1000);
00347       internalPrintPos(myRobot->getEncoderPose());
00348       fprintf(myFile, "%s\n", (*myTags.begin()).c_str());
00349     }
00350     myTags.pop_front();
00351   }
00352 }
00353 
00354 void ArSickLogger::internalTakeReading(void)
00355 {
00356   const std::list<ArSensorReading *> *readings;
00357   std::list<ArSensorReading *>::const_iterator it;
00358   std::list<ArSensorReading *>::const_reverse_iterator rit;
00359   ArPose poseTaken;
00360   time_t msec;
00361   ArSensorReading *reading;
00362   bool usingAdjustedReadings;
00363 
00364   // we take readings in any of the following cases if we haven't
00365   // taken one yet or if we've been explicitly told to take one or if
00366   // we've gone further than myDistDiff if we've turned more than
00367   // myDegDiff if we've switched sign on velocity and gone more than
00368   // 50 mm (so it doesn't oscilate and cause us to trigger)
00369 
00370   if (myRobot->isConnected() && (!myFirstTaken || myTakeReadingExplicit || 
00371       myLast.findDistanceTo(myRobot->getEncoderPose()) > myDistDiff ||
00372       fabs(ArMath::subAngle(myLast.getTh(), 
00373                 myRobot->getEncoderPose().getTh())) > myDegDiff ||
00374       ((myLastVel < 0 && myRobot->getVel() > 0 ||
00375     myLastVel > 0 && myRobot->getVel() < 0) && 
00376        myLast.findDistanceTo(myRobot->getEncoderPose()) > 50)))
00377   {
00378     myWrote = true;
00379     mySick->lockDevice();
00382     if ((readings = mySick->getAdjustedRawReadings()) != NULL)
00383     {
00384       usingAdjustedReadings = true;
00385     }
00386     else
00387     {
00388       usingAdjustedReadings = false;
00389       readings = mySick->getRawReadings();
00390     }
00391     if (readings == NULL || (it = readings->begin()) == readings->end() ||
00392     myFile == NULL)
00393     {
00394       mySick->unlockDevice();
00395       return;
00396     }
00397     myTakeReadingExplicit = false;
00398     myScanNumber++;
00399     if (usingAdjustedReadings)
00400       ArLog::log(ArLog::Normal, 
00401          "Taking adjusted readings from the %d laser values", 
00402          readings->size());
00403     else
00404       ArLog::log(ArLog::Normal, 
00405          "Taking readings from the %d laser values", 
00406          readings->size());
00407     myFirstTaken = true;
00408     myLast = myRobot->getEncoderPose();
00409     poseTaken = (*readings->begin())->getEncoderPoseTaken();
00410     myLastVel = myRobot->getVel();
00411     msec = myStartTime.mSecSince();
00412     fprintf(myFile, "scan1Id: %d\n", myScanNumber);
00413     fprintf(myFile, "time: %ld.%ld\n", msec / 1000, msec % 1000);
00414     /* ScanStudio isn't using these yet so don't print them
00415       fprintf(myFile, "velocities: %.2f %.2f\n", myRobot->getRotVel(),
00416       myRobot->getVel());*/
00417     internalPrintPos(poseTaken);
00418 
00419     if (myUseReflectorValues)
00420     {
00421       fprintf(myFile, "reflector1: ");
00422       
00423       if (!mySick->isLaserFlipped())
00424       {
00425     // make sure that the list is in increasing order
00426     for (it = readings->begin(); it != readings->end(); it++)
00427     {
00428       reading = (*it);
00429       if (!reading->getIgnoreThisReading())
00430         fprintf(myFile, "%d ", reading->getExtraInt());
00431       else
00432         fprintf(myFile, "0 ");
00433     }
00434       }
00435       else
00436       {
00437     for (rit = readings->rbegin(); rit != readings->rend(); rit++)
00438     {
00439       reading = (*rit);
00440       if (!reading->getIgnoreThisReading())
00441         fprintf(myFile, "%d ", reading->getExtraInt());
00442       else
00443         fprintf(myFile, "0 ");
00444     }
00445       }
00446       fprintf(myFile, "\n");
00447     }
00453     if (myOldReadings)
00454     {
00455       fprintf(myFile, "sick1: ");
00456       
00457       if (!mySick->isLaserFlipped())
00458       {
00459     // make sure that the list is in increasing order
00460     for (it = readings->begin(); it != readings->end(); it++)
00461     {
00462       reading = (*it);
00463       fprintf(myFile, "%d ", reading->getRange());
00464     }
00465       }
00466       else
00467       {
00468     for (rit = readings->rbegin(); rit != readings->rend(); rit++)
00469     {
00470       reading = (*rit);
00471       fprintf(myFile, "%d ", reading->getRange());
00472     }
00473       }
00474       fprintf(myFile, "\n");
00475     }
00476     if (myNewReadings)
00477     {
00478       fprintf(myFile, "scan1: ");
00479       
00480       if (!mySick->isLaserFlipped())
00481       {
00482     // make sure that the list is in increasing order
00483     for (it = readings->begin(); it != readings->end(); it++)
00484     {
00485       reading = (*it);
00486       if (!reading->getIgnoreThisReading())
00487         fprintf(myFile, "%.0f %.0f  ", 
00488             reading->getLocalX() - mySick->getSensorPositionX(), 
00489             reading->getLocalY() - mySick->getSensorPositionY());
00490       else
00491         fprintf(myFile, "0 0  ");
00492     }
00493       }
00494       else
00495       {
00496     for (rit = readings->rbegin(); rit != readings->rend(); rit++)
00497     {
00498       reading = (*rit);
00499       if (!reading->getIgnoreThisReading())
00500         fprintf(myFile, "%.0f %.0f  ", 
00501             reading->getLocalX() - mySick->getSensorPositionX(), 
00502             reading->getLocalY() - mySick->getSensorPositionY());
00503       else
00504         fprintf(myFile, "0 0  ");
00505     }
00506       }
00507       fprintf(myFile, "\n");
00508     }
00509     mySick->unlockDevice();
00510   }
00511 }
00512 
00513 void ArSickLogger::internalPrintPos(ArPose poseTaken)
00514 {
00515   if (myFile == NULL)
00516     return;
00517   ArPose encoderPose = myRobot->getEncoderPose();
00518   ArPose rawEncoderPose = myRobot->getRawEncoderPose();
00519   ArTransform normalToRaw(rawEncoderPose, encoderPose);
00520 
00521   ArPose rawPose;
00522   rawPose = normalToRaw.doInvTransform(poseTaken);
00523   fprintf(myFile, "#rawRobot: %.0f %.0f %.2f %.0f %.0f\n", 
00524       rawPose.getX(), 
00525       rawPose.getY(), 
00526       rawPose.getTh(), 
00527       myRobot->getVel(),
00528       myRobot->getRotVel());
00529   fprintf(myFile, "robot: %.0f %.0f %.2f %.0f %.0f\n", 
00530       poseTaken.getX(), 
00531       poseTaken.getY(), 
00532       poseTaken.getTh(), 
00533       myRobot->getVel(),
00534       myRobot->getRotVel());
00535 }
00536 
00537 AREXPORT void ArSickLogger::robotTask(void)
00538 {
00539 
00540   // call our function to check goals
00541   internalAddGoal();
00542   
00543   // call our function to dump tags
00544   internalWriteTags();
00545   
00546   // call our function to take a reading
00547   internalTakeReading();
00548 
00549   // now make sure the files all out to disk
00550   if (myWrote)
00551   {
00552     fflush(myFile);
00553 #ifndef WIN32
00554     fsync(fileno(myFile));
00555 #endif
00556   }
00557   myWrote = false;
00558 }
00559 
00560 
00561 
00562 

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