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