arnlServer.cpp

example of almost all ARNL features

00001 
00031 #include "Aria.h"
00032 #include "ArNetworking.h"
00033 #include "Arnl.h"
00034 
00035 #include "ArLocalizationTask.h"
00036 #include "ArDocking.h"
00037 
00038 void logOptions(const char *progname)
00039 {
00040   ArLog::log(ArLog::Normal, "Usage: %s [options]\n", progname);
00041   ArLog::log(ArLog::Normal, "[options] are any program options listed below, or any ARNL configuration");
00042   ArLog::log(ArLog::Normal, "parameters as -name <value>, see params/arnl.p for list.");
00043   ArLog::log(ArLog::Normal, "For example, -map <map file>.");
00044   Aria::logOptions();
00045 }
00046 
00047 bool gyroErrored = false;
00048 const char* getGyroStatusString(ArRobot* robot)
00049 {
00050   if(!robot || !robot->getOrigRobotConfig() || robot->getOrigRobotConfig()->getGyroType() < 2) return "N/A";
00051   if(robot->getFaultFlags() & ArUtil::BIT4)
00052   {
00053     gyroErrored = true;
00054     return "ERROR/OFF";
00055   }
00056   if(gyroErrored)
00057   {
00058     return "OK but error before";
00059   }
00060   return "OK";
00061 }
00062 
00063 int main(int argc, char **argv)
00064 {
00065   // Initialize Aria and Arnl global information
00066   Aria::init();
00067   Arnl::init();
00068 
00069 
00070   // The robot object
00071   ArRobot robot;
00072 
00073   // Parse the command line arguments.
00074   ArArgumentParser parser(&argc, argv);
00075 
00076   // Set up our simpleConnector, to connect to the robot and laser
00077   //ArSimpleConnector simpleConnector(&parser);
00078   ArRobotConnector robotConnector(&parser, &robot);
00079 
00080   // Connect to the robot
00081   if (!robotConnector.connectRobot())
00082   {
00083     ArLog::log(ArLog::Normal, "Error: Could not connect to robot... exiting");
00084     Aria::exit(3);
00085   }
00086 
00087 
00088 
00089   // Set up where we'll look for files. Arnl::init() set Aria's default
00090   // directory to Arnl's default directory; addDirectories() appends this
00091   // "examples" directory.
00092   char fileDir[1024];
00093   ArUtil::addDirectories(fileDir, sizeof(fileDir), Aria::getDirectory(), 
00094              "examples");
00095   ArLog::log(ArLog::Normal, "Installation directory is: %s\nMaps directory is: %s\n", Aria::getDirectory(), fileDir);
00096   
00097   
00098   // To direct log messages to a file, or to change the log level, use these  calls:
00099   //ArLog::init(ArLog::File, ArLog::Normal, "log.txt", true, true);
00100   //ArLog::init(ArLog::File, ArLog::Verbose);
00101  
00102   // Add a section to the configuration to change ArLog parameters
00103   ArLog::addToConfig(Aria::getConfig());
00104 
00105   // set up a gyro (if the robot is older and its firmware does not
00106   // automatically incorporate gyro corrections, then this object will do it)
00107   ArAnalogGyro gyro(&robot);
00108 
00109   // Our networking server
00110   ArServerBase server;
00111 
00112 
00113   // Set up our simpleOpener, used to set up the networking server
00114   ArServerSimpleOpener simpleOpener(&parser);
00115 
00116   // the laser connector
00117   ArLaserConnector laserConnector(&parser, &robot, &robotConnector);
00118 
00119   // Tell the laser connector to always connect the first laser since
00120   // this program always requires a laser.
00121   parser.addDefaultArgument("-connectLaser");
00122   
00123   // Load default arguments for this computer (from /etc/Aria.args, environment
00124   // variables, and other places)
00125   parser.loadDefaultArguments();
00126 
00127   // Parse arguments 
00128   if (!Aria::parseArgs() || !parser.checkHelpAndWarnUnparsed())
00129   {
00130     logOptions(argv[0]);
00131     Aria::exit(1);
00132   }
00133   
00134 
00135   // This causes Aria::exit(9) to be called if the robot unexpectedly
00136   // disconnects
00137   ArGlobalFunctor1<int> shutdownFunctor(&Aria::exit, 9);
00138   robot.addDisconnectOnErrorCB(&shutdownFunctor);
00139 
00140 
00141   // Create an ArSonarDevice object (ArRangeDevice subclass) and 
00142   // connect it to the robot.
00143   ArSonarDevice sonarDev;
00144   robot.addRangeDevice(&sonarDev);
00145 
00146 
00147 
00148   // This object will allow robot's movement parameters to be changed through
00149   // a Robot Configuration section in the ArConfig global configuration facility.
00150   ArRobotConfig robotConfig(&robot);
00151 
00152   // Include gyro configuration options in the robot configuration section.
00153   robotConfig.addAnalogGyro(&gyro);
00154 
00155   // Start the robot thread.
00156   robot.runAsync(true);
00157   
00158 
00159   // connect the laser(s) if it was requested, this adds them to the
00160   // robot too, and starts them running in their own threads
00161   if (!laserConnector.connectLasers())
00162   {
00163     ArLog::log(ArLog::Normal, "Could not connect to all lasers... exiting\n");
00164     Aria::exit(2);
00165   }
00166 
00167   // find the laser we should use for localization and/or mapping,
00168   // which will be the first laser
00169   robot.lock();
00170   ArLaser *firstLaser = robot.findLaser(1);
00171   if (firstLaser == NULL || !firstLaser->isConnected())
00172   {
00173     ArLog::log(ArLog::Normal, "Did not have laser 1 or it is not connected, cannot start localization and/or mapping... exiting");
00174     Aria::exit(2);
00175   }
00176   robot.unlock();
00177 
00178 
00179     /* Create and set up map object */
00180   
00181   // Set up the map object, this will look for files in the examples
00182   // directory (unless the file name starts with a /, \, or .
00183   // You can take out the 'fileDir' argument to look in the program's current directory
00184   // instead.
00185   // When a configuration file is loaded into ArConfig later, if it specifies a
00186   // map file, then that file will be loaded as the map.
00187   ArMap map(fileDir);
00188   // set it up to ignore empty file names (otherwise if a configuration omits
00189   // the map file, the whole configuration change will fail)
00190   map.setIgnoreEmptyFileName(true);
00191   // ignore the case, so that if someone is using MobileEyes or
00192   // MobilePlanner from Windows and changes the case on a map name,
00193   // it will still work.
00194   map.setIgnoreCase(true);
00195 
00196     
00197     /* Create localization and path planning threads */
00198 
00199 
00200   ArPathPlanningTask pathTask(&robot, &sonarDev, &map);
00201 
00202   ArLog::log(ArLog::Normal, "Creating laser localization task");
00203   // Laser Monte-Carlo Localization
00204   ArLocalizationTask locTask(&robot, firstLaser, &map);
00205 
00206 
00207 
00208   // Set some options on each laser that the laser connector 
00209   // connected to.
00210   std::map<int, ArLaser *>::iterator laserIt;
00211   for (laserIt = robot.getLaserMap()->begin();
00212        laserIt != robot.getLaserMap()->end();
00213        laserIt++)
00214   {
00215     int laserNum = (*laserIt).first;
00216     ArLaser *laser = (*laserIt).second;
00217 
00218     // Skip lasers that aren't connected
00219     if(!laser->isConnected())
00220       continue;
00221 
00222     // add the disconnectOnError CB to shut things down if the laser
00223     // connection is lost
00224     laser->addDisconnectOnErrorCB(&shutdownFunctor);
00225     // set the number of cumulative readings the laser will take
00226     laser->setCumulativeBufferSize(200);
00227     // add the lasers to the path planning task
00228     pathTask.addRangeDevice(laser, ArPathPlanningTask::BOTH);
00229     // set the cumulative clean offset (so that they don't all fire at once)
00230     laser->setCumulativeCleanOffset(laserNum * 100);
00231     // reset the cumulative clean time (to make the new offset take effect)
00232     laser->resetLastCumulativeCleanTime();
00233 
00234     // Add the packet count to the Aria info strings (It will be included in
00235     // MobileEyes custom details so you can monitor whether the laser data is
00236     // being received correctly)
00237     std::string laserPacketCountName;
00238     laserPacketCountName = laser->getName();
00239     laserPacketCountName += " Packet Count";
00240     Aria::getInfoGroup()->addStringInt(
00241         laserPacketCountName.c_str(), 10, 
00242         new ArRetFunctorC<int, ArLaser>(laser, 
00243                      &ArLaser::getReadingCount));
00244   }
00245 
00246 
00247   // Used for optional multirobot features (see below) (TODO move to multirobot
00248   // example?)
00249   ArClientSwitchManager clientSwitch(&server, &parser);
00250 
00251 
00252 
00253 
00254     /* Start the server */
00255 
00256   // Open the networking server
00257   if (!simpleOpener.open(&server, fileDir, 240))
00258   {
00259     ArLog::log(ArLog::Normal, "Error: Could not open server.");
00260     exit(2);
00261   }
00262 
00263 
00264 
00265     /* Create various services that provide network access to clients (such as
00266      * MobileEyes), as well as add various additional features to ARNL */
00267 
00268 
00269   // ARNL can optionally get information about the positions of other robots from a
00270   // "central server" (see central server example program), if command
00271   // line options specifying the address of the central server was given.
00272   // If there is no central server, then the address of each other robot
00273   // can instead be given in the configuration, and the multirobot systems
00274   // will connect to each robot (or "peer") individually.
00275 
00276         // TODO move this to multirobot example?
00277   ArServerHandlerMultiRobot *handlerMultiRobot = NULL;
00278   ArMultiRobotRangeDevice *multiRobotRangeDevice = NULL;
00279   ArServerHandlerMultiRobotPeer *multiRobotPeer = NULL;
00280   ArMultiRobotPeerRangeDevice *multiRobotPeerRangeDevice = NULL;
00281 
00282 
00283   bool usingCentralServer = false;
00284   if(clientSwitch.getCentralServerHostName() != NULL)
00285     usingCentralServer = true;
00286 
00287   // if we're using the central server then we want to create the
00288   // multiRobot central classes
00289   if (usingCentralServer)
00290   {
00291     // Make the handler for multi robot information (this sends the
00292     // information to the central server)
00293     handlerMultiRobot = new ArServerHandlerMultiRobot(&server, &robot, 
00294                               &pathTask,
00295                               &locTask, &map);
00296     
00297     // Normally each robot, and the central server, must all have
00298     // the same map name for the central server to share robot
00299     // information.  (i.e. they are operating in the same space).
00300     // This changes the map name that ArServerHandlerMutliRobot 
00301     // reports to the central server, in case you want this individual
00302     // robot to load a different map file name, but still report 
00303     // the common map file to the central server.
00304     //handlerMultiRobot->overrideMapName("central.map");
00305 
00306     // the range device that gets the multi robot information from
00307     // the central server and presents it as virtual range readings
00308     // to ARNL
00309     multiRobotRangeDevice = new ArMultiRobotRangeDevice(&server);
00310     
00311     robot.addRangeDevice(multiRobotRangeDevice);
00312     pathTask.addRangeDevice(multiRobotRangeDevice, 
00313                 ArPathPlanningTask::BOTH);
00314     
00315     // Set up options for drawing multirobot information in MobileEyes.
00316     multiRobotRangeDevice->setCurrentDrawingData(
00317         new ArDrawingData("polyDots", ArColor(125, 125, 0),
00318                   100, 73, 1000), true);
00319     multiRobotRangeDevice->setCumulativeDrawingData(
00320         new ArDrawingData("polyDots", ArColor(125, 0, 125),
00321                   100, 72, 1000), true);
00322 
00323     // This sets up the localization to use the known poses of other robots
00324     // for its localization in cases where numerous robots crowd out the map.
00325     locTask.setMultiRobotCallback(multiRobotRangeDevice->getOtherRobotsCB());
00326   }
00327   // if we're not using a central server then create the multirobot peer classes
00328   else
00329   {
00330     // set the path planning so it uses the explicit collision range for how far its planning
00331     pathTask.setUseCollisionRangeForPlanningFlag(true);
00332     // make our thing that gathers information from the other servers
00333     multiRobotPeerRangeDevice = new ArMultiRobotPeerRangeDevice(&map);
00334     // make our thing that sends information to the other servers
00335     multiRobotPeer = new ArServerHandlerMultiRobotPeer(&server, &robot, 
00336                              &pathTask, &locTask);
00337     // hook the two together so they both know what priority this robot is
00338     multiRobotPeer->setNewPrecedenceCallback(
00339         multiRobotPeerRangeDevice->getSetPrecedenceCallback());
00340     // hook the two together so they both know what priority this
00341     // robot's fingerprint is
00342     multiRobotPeer->setNewFingerprintCallback(
00343         multiRobotPeerRangeDevice->getSetFingerprintCallback());
00344     // hook the two together so that the range device can call on the
00345     // server handler to change its fingerprint
00346     multiRobotPeerRangeDevice->setChangeFingerprintCB(
00347         multiRobotPeer->getChangeFingerprintCB());
00348     // then add the robot to the places it needs to be
00349     robot.addRangeDevice(multiRobotPeerRangeDevice);
00350     pathTask.addRangeDevice(multiRobotPeerRangeDevice, 
00351                 ArPathPlanningTask::BOTH);
00352 
00353     // Set the range device so that we can see the information its using
00354     // to avoid, you can comment these out in order to not see them
00355     multiRobotPeerRangeDevice->setCurrentDrawingData(
00356         new ArDrawingData("polyDots", ArColor(125, 125, 0),
00357                   100, 72, 1000), true);
00358     multiRobotPeerRangeDevice->setCumulativeDrawingData(
00359         new ArDrawingData("polyDots", ArColor(125, 0, 125),
00360                   100, 72, 1000), true);
00361     // This sets up the localization to use the known poses of other robots
00362     // for its localization in cases where numerous robots crowd out the map.
00363     locTask.setMultiRobotCallback(
00364         multiRobotPeerRangeDevice->getOtherRobotsCB());
00365   }
00366 
00367 
00368 
00369 
00370   /* Add additional range devices to the robot and path planning task (so it
00371      avoids obstacles detected by these devices) */
00372   
00373   // Add IR range device to robot and path planning task (so it avoids obstacles
00374   // detected by this device)
00375   robot.lock();
00376   ArIRs irs;
00377   robot.addRangeDevice(&irs);
00378   pathTask.addRangeDevice(&irs, ArPathPlanningTask::CURRENT);
00379 
00380   // Add bumpers range device to robot and path planning task (so it avoids obstacles
00381   // detected by this device)
00382   ArBumpers bumpers;
00383   robot.addRangeDevice(&bumpers);
00384   pathTask.addRangeDevice(&bumpers, ArPathPlanningTask::CURRENT);
00385 
00386   // Add range device which uses forbidden regions given in the map to give virtual
00387   // range device readings to ARNL.  (so it avoids obstacles
00388   // detected by this device)
00389   ArForbiddenRangeDevice forbidden(&map);
00390   robot.addRangeDevice(&forbidden);
00391   pathTask.addRangeDevice(&forbidden, ArPathPlanningTask::CURRENT);
00392 
00393   robot.unlock();
00394 
00395 
00396   // Action to slow down robot when localization score drops but not lost.
00397   ArActionSlowDownWhenNotCertain actionSlowDown(&locTask);
00398   pathTask.getPathPlanActionGroup()->addAction(&actionSlowDown, 140);
00399 
00400   // Action to stop the robot when localization is "lost" (score too low)
00401   ArActionLost actionLostPath(&locTask, &pathTask);
00402   pathTask.getPathPlanActionGroup()->addAction(&actionLostPath, 150);
00403 
00404   // Arnl uses this object when it must replan its path because its
00405   // path is completely blocked.  It will use an older history of sensor
00406   // readings to replan this new path.  This should not be used with SONARNL
00407   // since sonar readings are not accurate enough and may prevent the robot
00408   // from planning through space that is actually clear.
00409   ArGlobalReplanningRangeDevice replanDev(&pathTask);
00410 
00411   
00412   // Service to provide drawings of data in the map display :
00413   ArServerInfoDrawings drawings(&server);
00414   drawings.addRobotsRangeDevices(&robot);
00415   drawings.addRangeDevice(&replanDev);
00416 
00417   /* Draw a box around the local path planning area use this 
00418     (You can enable this particular drawing from custom commands 
00419     which is set up down below in ArServerInfoPath) */
00420   ArDrawingData drawingDataP("polyLine", ArColor(200,200,200), 1, 75);
00421   ArFunctor2C<ArPathPlanningTask, ArServerClient *, ArNetPacket *> 
00422     drawingFunctorP(&pathTask, &ArPathPlanningTask::drawSearchRectangle);
00423   drawings.addDrawing(&drawingDataP, "Local Plan Area", &drawingFunctorP); 
00424 
00425   /* Show the sample points used by MCL */
00426   ArDrawingData drawingDataL("polyDots", ArColor(0,255,0), 100, 75);
00427   ArFunctor2C<ArLocalizationTask, ArServerClient *, ArNetPacket *> 
00428     drawingFunctorL(&locTask, &ArLocalizationTask::drawRangePoints);
00429   drawings.addDrawing(&drawingDataL, "Localization Points", &drawingFunctorL);
00430 
00431 
00432   // "Custom" commands. You can add your own custom commands here, they will
00433   // be available in MobileEyes' custom commands (enable in the toolbar or
00434   // access through Robot Tools)
00435   ArServerHandlerCommands commands(&server);
00436 
00437 
00438   // These provide various kinds of information to the client:
00439   ArServerInfoRobot serverInfoRobot(&server, &robot);
00440   ArServerInfoSensor serverInfoSensor(&server, &robot);
00441   ArServerInfoPath serverInfoPath(&server, &robot, &pathTask);
00442   serverInfoPath.addSearchRectangleDrawing(&drawings);
00443   serverInfoPath.addControlCommands(&commands);
00444 
00445   // Provides localization info and allows the client (MobileEyes) to relocalize at a given
00446   // pose:
00447   ArServerInfoLocalization serverInfoLocalization(&server, &robot, &locTask);
00448   ArServerHandlerLocalization serverLocHandler(&server, &robot, &locTask);
00449 
00450   // If you're using MobileSim, ArServerHandlerLocalization sends it a command
00451   // to move the robot's true pose if you manually do a localization through 
00452   // MobileEyes.  To disable that behavior, use this constructor call instead:
00453   // ArServerHandlerLocalization serverLocHandler(&server, &robot, true, false);
00454   // The fifth argument determines whether to send the command to MobileSim.
00455 
00456   // Provide the map to the client (and related controls):
00457   ArServerHandlerMap serverMap(&server, &map);
00458 
00459   // These objects add some simple (custom) commands to 'commands' for testing and debugging:
00460   ArServerSimpleComUC uCCommands(&commands, &robot);                   // Send any command to the microcontroller
00461   ArServerSimpleComMovementLogging loggingCommands(&commands, &robot); // configure logging
00462   ArServerSimpleComLogRobotConfig configCommands(&commands, &robot);   // trigger logging of the robot config parameters
00463 //  ArServerSimpleServerCommands serverCommands(&commands, &server);     // monitor networking behavior (track packets sent etc.)
00464 
00465 
00466   // service that allows the client to monitor the communication link status
00467   // between the robot and the client.
00468   //
00469   ArServerHandlerCommMonitor handlerCommMonitor(&server);
00470 
00471 
00472 
00473   // service that allows client to change configuration parameters in ArConfig 
00474   ArServerHandlerConfig handlerConfig(&server, Aria::getConfig(),
00475                       Arnl::getTypicalDefaultParamFileName(),
00476                       Aria::getDirectory());
00477 
00478 
00479 
00480   /* Set up the possible modes for remote control from a client such as
00481    * MobileEyes:
00482    */
00483 
00484   // Mode To go to a goal or other specific point:
00485   ArServerModeGoto modeGoto(&server, &robot, &pathTask, &map,
00486                 locTask.getRobotHome(),
00487                 locTask.getRobotHomeCallback());
00488 
00489 
00490   // Mode To stop and remain stopped:
00491   ArServerModeStop modeStop(&server, &robot);
00492 
00493   // Cause the sonar to turn off automatically
00494   // when the robot is stopped, and turn it back on when commands to move
00495   // are sent. (Note, if using SONARNL to localize, then don't do this
00496   // since localization may get lost)
00497   ArSonarAutoDisabler sonarAutoDisabler(&robot);
00498 
00499   // Teleoperation modes To drive by keyboard, joystick, etc:
00500   ArServerModeRatioDrive modeRatioDrive(&server, &robot);  
00501 //  ArServerModeDrive modeDrive(&server, &robot);            // Older mode for compatability
00502 
00503 
00504 
00505   // Prevent normal teleoperation driving if localization is lost using
00506   // a high-priority action, which enables itself when the particular mode is
00507   // active.
00508   // (You have to enter unsafe drive mode to drive when lost.)
00509   ArActionLost actionLostRatioDrive(&locTask, &pathTask, &modeRatioDrive);
00510   modeRatioDrive.getActionGroup()->addAction(&actionLostRatioDrive, 110);
00511 
00512   // Add drive mode section to the configuration, and also some custom (simple) commands:
00513   modeRatioDrive.addToConfig(Aria::getConfig(), "Teleop settings");
00514   modeRatioDrive.addControlCommands(&commands);
00515 
00516   // Wander mode (also prevent wandering if lost):
00517   ArServerModeWander modeWander(&server, &robot);
00518   ArActionLost actionLostWander(&locTask, &pathTask, &modeWander);
00519   modeWander.getActionGroup()->addAction(&actionLostWander, 110);
00520 
00521 
00522   // This provides a small table of interesting information for the client
00523   // to display to the operator. You can add your own callbacks to show any
00524   // data you want.
00525   ArServerInfoStrings stringInfo(&server);
00526   Aria::getInfoGroup()->addAddStringCallback(stringInfo.getAddStringFunctor());
00527   
00528   // Provide a set of informational data (turn on in MobileEyes with
00529   // View->Custom Details)
00530 
00531   Aria::getInfoGroup()->addStringInt(
00532       "Motor Packet Count", 10, 
00533       new ArConstRetFunctorC<int, ArRobot>(&robot, 
00534                            &ArRobot::getMotorPacCount));
00535 
00536   Aria::getInfoGroup()->addStringDouble(
00537       "Laser Localization Score", 8, 
00538       new ArRetFunctorC<double, ArLocalizationTask>(
00539           &locTask, &ArLocalizationTask::getLocalizationScore),
00540       "%.03f");
00541   Aria::getInfoGroup()->addStringInt(
00542       "Laser Loc Num Samples", 8, 
00543       new ArRetFunctorC<int, ArLocalizationTask>(
00544           &locTask, &ArLocalizationTask::getCurrentNumSamples),
00545       "%4d");
00546 
00547 
00548   // Display gyro status if gyro is enabled and is being handled by the firmware (gyro types 2, 3, or 4).
00549   // (If the firmware detects an error communicating with the gyro or IMU it
00550   // returns a flag, and stops using it.)
00551   // (This gyro type parameter, and fault flag, are only in ARCOS, not Seekur firmware)
00552   if(robot.getOrigRobotConfig() && robot.getOrigRobotConfig()->getGyroType() > 1)
00553   {
00554     Aria::getInfoGroup()->addStringString(
00555           "Gyro/IMU Status", 10,
00556           new ArGlobalRetFunctor1<const char*, ArRobot*>(&getGyroStatusString, &robot)
00557       );
00558   }
00559 
00560 
00561   // Setup the dock if there is a docking system on board.
00562   ArServerModeDock *modeDock = NULL;
00563   modeDock = ArServerModeDock::createDock(&server, &robot, &locTask, 
00564                       &pathTask);
00565   if (modeDock != NULL)
00566   {
00567     modeDock->checkDock();
00568     modeDock->addAsDefaultMode();
00569     modeDock->addToConfig(Aria::getConfig());
00570     modeDock->addControlCommands(&commands);
00571   }
00572 
00573 
00574 
00575   // Make Stop mode the default (If current mode deactivates without entering
00576   // a new mode, then Stop Mode will be selected)
00577   modeStop.addAsDefaultMode();
00578     // TODO move up near where stop mode is created?
00579 
00580 
00581 
00582 
00583 
00584   /* Services that allow the client to initiate scanning with the laser to
00585      create maps in Mapper3 (So not possible with SONARNL): */
00586 
00587   ArServerHandlerMapping handlerMapping(&server, &robot, firstLaser, 
00588                     fileDir, "", true);
00589 
00590   // make laser localization stop while mapping
00591   handlerMapping.addMappingStartCallback(
00592       new ArFunctor1C<ArLocalizationTask, bool>
00593       (&locTask, &ArLocalizationTask::setIdleFlag, true));
00594 
00595   // and then make it start again when we're doine
00596   handlerMapping.addMappingEndCallback(
00597       new ArFunctor1C<ArLocalizationTask, bool>
00598       (&locTask, &ArLocalizationTask::setIdleFlag, false));
00599 
00600 
00601   // Make it so our "lost" actions don't stop us while mapping
00602   handlerMapping.addMappingStartCallback(actionLostPath.getDisableCB());
00603   handlerMapping.addMappingStartCallback(actionLostRatioDrive.getDisableCB());
00604   handlerMapping.addMappingStartCallback(actionLostWander.getDisableCB());
00605 
00606   // And then let them make us stop as usual when done mapping
00607   handlerMapping.addMappingEndCallback(actionLostPath.getEnableCB());
00608   handlerMapping.addMappingEndCallback(actionLostRatioDrive.getEnableCB());
00609   handlerMapping.addMappingEndCallback(actionLostWander.getEnableCB());
00610 
00611   // don't let forbidden lines show up as obstacles while mapping
00612   // (they'll just interfere with driving while mapping, and localization is off anyway)
00613   handlerMapping.addMappingStartCallback(forbidden.getDisableCB());
00614 
00615   // let forbidden lines show up as obstacles again as usual after mapping
00616   handlerMapping.addMappingEndCallback(forbidden.getEnableCB());
00617 
00618 
00619   /*
00620   // If we are on a simulator, move the robot back to its starting position,
00621   // and reset its odometry.
00622   // This will allow localizeRobotAtHomeBlocking() below will (probably) work (it
00623   // tries current odometry (which will be 0,0,0) and all the map
00624   // home points.
00625   // (Ignored by a real robot)
00626   //robot.com(ArCommands::SIM_RESET);
00627   */
00628 
00629 
00630   // create a pose storage class, this will let the program keep track
00631   // of where the robot is between runs...  after we try and restore
00632   // from this file it will start saving the robot's pose into the
00633   // file
00634   ArPoseStorage poseStorage(&robot);
00639   if (poseStorage.restorePose("robotPose"))
00640     serverLocHandler.setSimPose(robot.getPose());
00641   else
00642     robot.com(ArCommands::SIM_RESET);
00643 
00644 
00645 
00646   /* File transfer services: */
00647   
00648 #ifdef WIN32
00649   // Not implemented for Windows yet.
00650   ArLog::log(ArLog::Normal, "Note, file upload/download services are not implemented for Windows; not enabling them.");
00651 #else
00652   // This block will allow you to set up where you get and put files
00653   // to/from, just comment them out if you don't want this to happen
00654   // /*
00655   ArServerFileLister fileLister(&server, fileDir);
00656   ArServerFileToClient fileToClient(&server, fileDir);
00657   ArServerFileFromClient fileFromClient(&server, fileDir, "/tmp");
00658   ArServerDeleteFileOnServer deleteFileOnServer(&server, fileDir);
00659   // */
00660 #endif
00661 
00662     /* Video image streaming, and camera controls (Requires SAVserver or ACTS) */
00663 
00664   // Forward any video if either ACTS or SAV server are running.
00665   // You can find out more about SAV and ACTS on our website
00666   // http://robots.activmedia.com. ACTS is for color tracking and is
00667   // a seperate product. SAV just does software A/V transmitting and is
00668   // free to all our customers. Just run ACTS or SAV server before you
00669   // start this program and this class here will forward video from the
00670   // server to the client.
00671   ArHybridForwarderVideo videoForwarder(&server, "localhost", 7070);
00672   
00673   // make a camera to use in case we have video. the camera collection collects
00674   // multiple ptz cameras 
00675   ArPTZ *camera = NULL;
00676   ArServerHandlerCamera *handlerCamera = NULL;
00677   ArCameraCollection *cameraCollection = NULL;
00678 
00679   // if we have video then set up a camera 
00680   if (videoForwarder.isForwardingVideo())
00681   {
00682 
00683     cameraCollection = new ArCameraCollection();
00684     cameraCollection->addCamera("Cam1", "VCC4", "Camera", "VCC4");
00685 
00686     videoForwarder.setCameraName("Cam1");
00687     videoForwarder.addToCameraCollection(*cameraCollection);
00688 
00689     bool invertedCamera = false;
00690     camera = new ArVCC4(&robot, invertedCamera, 
00691                               ArVCC4::COMM_UNKNOWN, true, true);
00692     camera->init();
00693 
00694     handlerCamera = new ArServerHandlerCamera("Cam1", 
00695                                                    &server, 
00696                                                          &robot,
00697                                                          camera, 
00698                                                          cameraCollection);
00699 
00700     pathTask.addGoalFinishedCB(
00701         new ArFunctorC<ArServerHandlerCamera>(
00702             handlerCamera, 
00703             &ArServerHandlerCamera::cameraModeLookAtGoalClearGoal));
00704   }
00705 
00706   // After all of the cameras / videos have been created and added to the collection,
00707   // then start the collection server.
00708   //
00709   if (cameraCollection != NULL) {
00710     new ArServerHandlerCameraCollection(&server, cameraCollection);
00711   }
00712 
00713 
00714 
00715 
00716     /* Load configuration values, map, and begin! */
00717 
00718   
00719   // When parsing the configuration file, also look at the program's command line options 
00720   // from the command-line argument parser as well as the configuration file.
00721   // (So you can use any argument on the command line, namely -map.) 
00722   Aria::getConfig()->useArgumentParser(&parser);
00723 
00724   // Read in parameter files.
00725   ArLog::log(ArLog::Normal, "Loading config file %s into ArConfig...", Arnl::getTypicalParamFileName());
00726   if (!Aria::getConfig()->parseFile(Arnl::getTypicalParamFileName()))
00727   {
00728     ArLog::log(ArLog::Normal, "Trouble loading configuration file, exiting");
00729     Aria::exit(5);
00730   }
00731 
00732   // Warn about unknown params.
00733   if (!simpleOpener.checkAndLog() || !parser.checkHelpAndWarnUnparsed())
00734   {
00735     logOptions(argv[0]);
00736     Aria::exit(6);
00737   }
00738 
00739   // Warn if there is no map
00740   if (map.getFileName() == NULL || strlen(map.getFileName()) <= 0)
00741   {
00742     ArLog::log(ArLog::Normal, "");
00743     ArLog::log(ArLog::Normal, "### No map file is set up, you can make a map with the following procedure");
00744     ArLog::log(ArLog::Normal, "   0) You can find this information in README.txt or docs/Mapping.txt");
00745     ArLog::log(ArLog::Normal, "   1) Connect to this server with MobileEyes");
00746     ArLog::log(ArLog::Normal, "   2) Go to Tools->Map Creation->Start Scan");
00747     ArLog::log(ArLog::Normal, "   3) Give the map a name and hit okay");
00748     ArLog::log(ArLog::Normal, "   4) Drive the robot around your space (see docs/Mapping.txt");
00749     ArLog::log(ArLog::Normal, "   5) Go to Tools->Map Creation->Stop Scan");
00750     ArLog::log(ArLog::Normal, "   6) Start up Mapper3");
00751     ArLog::log(ArLog::Normal, "   7) Go to File->Open on Robot");
00752     ArLog::log(ArLog::Normal, "   8) Select the .2d you created");
00753     ArLog::log(ArLog::Normal, "   9) Create a .map");
00754     ArLog::log(ArLog::Normal, "  10) Go to File->Save on Robot");
00755     ArLog::log(ArLog::Normal, "  11) In MobileEyes, go to Tools->Robot Config");
00756     ArLog::log(ArLog::Normal, "  12) Choose the Files section");
00757     ArLog::log(ArLog::Normal, "  13) Enter the path and name of your new .map file for the value of the Map parameter.");
00758     ArLog::log(ArLog::Normal, "  14) Press OK and your new map should become the map used");
00759     ArLog::log(ArLog::Normal, "");    
00760   }
00761 
00762   // Print a log message notifying user of the directory for map files
00763   ArLog::log(ArLog::Normal, "");
00764   ArLog::log(ArLog::Normal, 
00765          "Directory for maps and file serving: %s", fileDir);
00766   
00767   ArLog::log(ArLog::Normal, "See the ARNL README.txt for more information");
00768   ArLog::log(ArLog::Normal, "");
00769 
00770   // Do an initial localization of the robot. It tries all the home points
00771   // in the map, as well as the robot's current odometric position, as possible
00772   // places the robot is likely to be at startup.   If successful, it will
00773   // also save the position it found to be the best localized position as the
00774   // "Home" position, which can be obtained from the localization task (and is
00775   // used by the "Go to home" network request).
00776   locTask.localizeRobotAtHomeBlocking();
00777   
00778   // Let the client switch manager (for multirobot) spin off into its own thread
00779   // TODO move to multirobot example?
00780   clientSwitch.runAsync();
00781 
00782   // Start the networking server's thread
00783   server.runAsync();
00784 
00785 
00786   // Add a key handler so that you can exit by pressing
00787   // escape. Note that this key handler, however, prevents this program from
00788   // running in the background (e.g. as a system daemon or run from 
00789   // the shell with "&") -- it will lock up trying to read the keys; 
00790   // remove this if you wish to be able to run this program in the background.
00791   ArKeyHandler *keyHandler;
00792   if ((keyHandler = Aria::getKeyHandler()) == NULL)
00793   {
00794     keyHandler = new ArKeyHandler;
00795     Aria::setKeyHandler(keyHandler);
00796     robot.lock();
00797     robot.attachKeyHandler(keyHandler);
00798     robot.unlock();
00799     puts("Server running. To exit, press escape.");
00800   }
00801 
00802   // Enable the motors and wait until the robot exits (disconnection, etc.) or this program is
00803   // canceled.
00804   robot.enableMotors();
00805   robot.waitForRunExit();
00806   Aria::exit(0);
00807 }
00808 

Generated on Mon Apr 13 17:02:28 2009 for ARNL by  doxygen 1.4.7