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

Generated on Thu Apr 23 10:19:34 2009 for ARNL by  doxygen 1.5.1