This is an example of using ARNL or SONARNL and ArNetworking to provide a server program that remote clients, such as MobileEyes, can connect to. MobileEyes sends requests to this program to go to goals, get the current map, set ARNL and other configuration parameters, and get the current state of the robot and sensors. This example server includes almost all features provided by ARNL (or SONARNL), including localization, path planning and navigation to a map goal or abritrary point, sharing information with other servers peer-to-peer or through a "central server", using IR and bumper sensors, stopping the robot if localization fails, global replanning if a path is not followable, use of special SICK laser reflector beacons, as well as various networking services for MobileEyes and other clients, such as diagnostic visualizations, access to configuration parameters, access to camera control and video images (if SAVServer is running), special debugging commands ("custom commands"), file uploading/downloading and gathering raw laser scans using Mapper3, and safe and unsafe teleoperation.
Note, guiServer will allow remote clients to make map scans and to put and get files from the ARNL examples directory, if you do not wish this to be possible modify the guiServer code (search for ArServerHandlerMapping for map making ArServerFileLister for file getting and putting).
You can also start up guiServer with an option for using user and password information to allow connection. To do this you should edit examples/guiServer.userInfo and change the '.' for passwords to the password you wish and then pass guiServer an additional '-userInfo guiServer.userInfo' argument.
/* MobileRobots Advanced Robotics Navigation and Localization (ARNL) Copyright (C) 2004, 2005, ActivMedia Robotics LLC. Copyright (C) 2006, 2007, MobileRobots Inc. All Rights Reserved MobileRobots Inc does not make any representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. The license for this software is distributed as LICENSE.txt in the top level directory. robots@mobilerobots.com MobileRobots 19 Columbia Drive Amherst, NH 03031 800-639-9481 */ #include "Aria.h" #include "ArNetworking.h" #include "ArSystemStatus.h" #include "Arnl.h" class ExampleGoalTasks { protected: ArPathPlanningTask *myPathPlanner; ArFunctor1C<ExampleGoalTasks, ArPose> myGoalDoneCB; ArFunctor1C<ExampleGoalTasks, ArPose> myGoalFailedCB; public: ExampleGoalTasks(ArPathPlanningTask* pathPlanner) : myPathPlanner(pathPlanner), myGoalDoneCB(this, &ExampleGoalTasks::reachedGoal), myGoalFailedCB(this, &ExampleGoalTasks::failedGoal) { pathPlanner->addGoalDoneCB(&myGoalDoneCB); pathPlanner->addGoalFailedCB(&myGoalFailedCB); } ~ExampleGoalTasks() { myPathPlanner->remGoalDoneCB(&myGoalDoneCB); myPathPlanner->remGoalFailedCB(&myGoalFailedCB); } void reachedGoal(ArPose pose) { ArLog::log(ArLog::Normal, "guiServer: reached the goal."); } void failedGoal(ArPose pose) { ArLog::log(ArLog::Normal, "guiServer: failed to reach the goal!"); } }; int main(int argc, char *argv[]) { // Initialize location of Aria, Arnl and their args. Aria::init(); Arnl::init(); // log to a file //ArLog::init(ArLog::File, ArLog::Normal, "log.txt", true, true); //ArLog::init(ArLog::File, ArLog::Verbose); // To get CPU usage and wireless information from Linux ArSystemStatus::runRefreshThread(); // The robot object ArRobot robot; // Our server ArServerBase server; // Parse the command line arguments. ArArgumentParser parser(&argc, argv); // Set up our simpleConnector ArSimpleConnector simpleConnector(&parser); // Set up our simpleOpener ArServerSimpleOpener simpleOpener(&parser); // Set up our client for the central server ArClientSwitchManager clientSwitch(&server, &parser); // Load default arguments for this computer (from /etc/Aria.args, environment // variables, and other places) parser.loadDefaultArguments(); // set up a gyro ArAnalogGyro gyro(&robot); // Parse arguments for the simple connector. if (!Aria::parseArgs() || !parser.checkHelpAndWarnUnparsed()) { ArLog::log(ArLog::Normal, "\nUsage: %s -map mapfilename\n", argv[0]); Aria::logOptions(); Aria::exit(1); } #ifndef SONARNL // The laser object ArSick sick(361, 181); // Add the laser to the robot robot.addRangeDevice(&sick); #endif // ifndef SONARNL // Sonar, must be added to the robot, used by teleoperation and wander to // detect obstacles ArSonarDevice sonarDev; // Add the sonar to the robot robot.addRangeDevice(&sonarDev); // Set up where we'll look for files char fileDir[1024]; ArUtil::addDirectories(fileDir, sizeof(fileDir), Aria::getDirectory(), "examples"); // Set up the map, this will look for files in the examples // directory (unless the file name starts with a /, \, or . // You can take out the 'fileDir' argument to look in the current directory // instead ArMap arMap(fileDir); // set it up to ignore empty file names (otherwise the parseFile // on the config will fail) arMap.setIgnoreEmptyFileName(true); #ifndef SONARNL // Initialize the localization (for the laser) ArLocalizationTask locTask(&robot, &sick, &arMap); // Make the path task (for the laser) ArPathPlanningTask pathTask(&robot, &sick, &sonarDev, &arMap); // Set up things so data can be logged (only do it with the laser // since it can overrun a 9600 serial connection which the sonar is // more likely to have) ArDataLogger dataLogger(&robot); dataLogger.addToConfig(Aria::getConfig()); #else // ifndef SONARNL // Initialize the localization (for SONARNL) ArSonarLocalizationTask locTask(&robot, &sonarDev, &arMap); // Make the path task (for SONARNL) ArPathPlanningTask pathTask(&robot, &sonarDev, &arMap); #endif // ifndef SONARNL // add our logging to the config ArLog::addToConfig(Aria::getConfig()); // Object with things to do if we reach or fail to reach a goal: ExampleGoalTasks goalTasks(&pathTask); // First open the server up if (!simpleOpener.open(&server, fileDir, 240)) { if (simpleOpener.wasUserFileBad()) ArLog::log(ArLog::Normal, "Bad user file"); else ArLog::log(ArLog::Normal, "Could not open server port"); exit(2); } // Connect the robot if (!simpleConnector.connectRobot(&robot)) { ArLog::log(ArLog::Normal, "Could not connect to robot... exiting"); Aria::exit(3); } // Set up a class that'll put the movement parameters into the config stuff ArRobotConfig robotConfig(&robot); robotConfig.addAnalogGyro(&gyro); robot.enableMotors(); robot.clearDirectMotion(); // if we are connected to a simulator, reset it to its start position robot.comInt(ArCommands::RESETSIMTOORIGIN, 1); #ifndef SONARNL // Set up the laser before handing it to the robot. simpleConnector.setupLaser(&sick); #endif // ifndef SONARNL // Start the robot thread. robot.runAsync(true); #ifndef SONARNL // Start the laser thread. sick.runAsync(); robot.com2Bytes(31, 11, 0); ArUtil::sleep(1000); robot.com2Bytes(31, 11, 1); // Connect the laser if (!sick.blockingConnect()) { ArLog::log(ArLog::Normal, "Couldn't connect to sick, exiting"); Aria::exit(4); } ArServerHandlerMultiRobot *handlerMultiRobot = NULL; ArMultiRobotRangeDevice *multiRobotRangeDevice = NULL; ArServerHandlerMultiRobotPeer *multiRobotPeer = NULL; ArMultiRobotPeerRangeDevice *multiRobotPeerRangeDevice = NULL; // if we're using the central server then we want to create the // multiRobot central classes if (clientSwitch.getCentralServerHostName() != NULL) { // Make the handler for multi robot information (this sends the // information to the central server) handlerMultiRobot = new ArServerHandlerMultiRobot(&server, &robot, &pathTask, &locTask, &arMap); // the range device that handles the multi robot information from // the central server multiRobotRangeDevice = new ArMultiRobotRangeDevice(&server); robot.addRangeDevice(multiRobotRangeDevice); pathTask.addRangeDevice(multiRobotRangeDevice, ArPathPlanningTask::BOTH); // Set the range device so that we can see the information its using // to avoid, you can comment these out in order to not see them multiRobotRangeDevice->setCurrentDrawingData( new ArDrawingData("polyDots", ArColor(125, 125, 0), 100, 73, 1000), true); multiRobotRangeDevice->setCumulativeDrawingData( new ArDrawingData("polyDots", ArColor(125, 0, 125), 100, 72, 1000), true); } // if we're not then we want to create the multirobot peer classes else { // set the path planning so it uses the explicit collision range for how far its planning pathTask.setUseCollisionRangeForPlanningFlag(true); // make our thing that gathers information from the other servers multiRobotPeerRangeDevice = new ArMultiRobotPeerRangeDevice(&arMap); // make our thing that sends information to the other servers multiRobotPeer = new ArServerHandlerMultiRobotPeer(&server, &robot, &pathTask, &locTask); // hook the two together so they both know what priority this robot is multiRobotPeer->setNewPrecedenceCallback( multiRobotPeerRangeDevice->getSetPrecedenceCallback()); // hook the two together so they both know what priority this // robot's fingerprint is multiRobotPeer->setNewFingerprintCallback( multiRobotPeerRangeDevice->getSetFingerprintCallback()); // hook the two together so that the range device can call on the // server handler to change its fingerprint multiRobotPeerRangeDevice->setChangeFingerprintCB( multiRobotPeer->getChangeFingerprintCB()); // then add the robot to the places it needs to be robot.addRangeDevice(multiRobotPeerRangeDevice); pathTask.addRangeDevice(multiRobotPeerRangeDevice, ArPathPlanningTask::BOTH); // Set the range device so that we can see the information its using // to avoid, you can comment these out in order to not see them multiRobotPeerRangeDevice->setCurrentDrawingData( new ArDrawingData("polyDots", ArColor(125, 125, 0), 100, 72, 1000), true); multiRobotPeerRangeDevice->setCumulativeDrawingData( new ArDrawingData("polyDots", ArColor(125, 0, 125), 100, 72, 1000), true); } #endif // ifndef SONARNL ArUtil::sleep(300); // Add additional range devices to the robot and path planning task. // IRs robot.lock(); ArIRs irs; robot.addRangeDevice(&irs); pathTask.addRangeDevice(&irs, ArPathPlanningTask::CURRENT); // Bumpers. ArBumpers bumpers; robot.addRangeDevice(&bumpers); pathTask.addRangeDevice(&bumpers, ArPathPlanningTask::CURRENT); // Forbidden regions. ArForbiddenRangeDevice forbidden(&arMap); robot.addRangeDevice(&forbidden); pathTask.addRangeDevice(&forbidden, ArPathPlanningTask::CURRENT); // Action to overide when localization is lost. ArActionLost actionLostPath(&locTask, &pathTask); pathTask.getPathPlanActionGroup()->addAction(&actionLostPath, 150); // Action to slow down robot when localization score drops but not lost. ArActionSlowDownWhenNotCertain actionSlowDown(&locTask); pathTask.getPathPlanActionGroup()->addAction(&actionSlowDown, 140); #ifndef SONARNL // This is the place to add a range device which will hold sensor data // and delete it appropriately to replan around blocked paths. ArGlobalReplanningRangeDevice replanDev(&pathTask); #endif // Create objects that add network services: // Drawing in the map display: ArServerInfoDrawings drawings(&server); drawings.addRobotsRangeDevices(&robot); #ifndef SONARNL drawings.addRangeDevice(&replanDev); #endif // SONARNL #ifndef SONARNL // add something to display the reflectors ArLaserReflectorDevice reflector(&sick, &robot); drawings.addRangeDevice(&reflector); #endif /* If you want to draw the destination put this code back in: ArServerDrawingDestination destination( &drawings, &pathTask, "destination", 500, 500, new ArDrawingData("polyDots", ArColor(0xff, 0xff, 0x0), 800, // size 49), // just below the robot */ /* If you want to see the local path planning area use this (You can enable this particular drawing from custom commands which is set up down below in ArServerInfoPath) ArDrawingData drawingDataP("polyLine", ArColor(200,200,200), 1, 75); ArFunctor2C<ArPathPlanningTask, ArServerClient *, ArNetPacket *> drawingFunctorP(pathTask, &ArPathPlanningTask::drawSearchRectangle); drawings.addDrawing(&drawingDataP, "Local Plan Area", &drawingFunctorP); */ /* If you want to see the points making up the local path in addition to the * main path use this. ArDrawingData drawingDataP2("polyDots", ArColor(0,128,0), 100, 70); ArFunctor2C<ArPathPlanningTask, ArServerClient *, ArNetPacket *> drawingFunctorP2(pathTask, &ArPathPlanningTask::drawPathPoints); drawings.addDrawing(&drawingDataP2, "Path Points", &drawingFunctorP2); */ /* If you want to see the points used by localization use this ArDrawingData drawingDataL("polyDots", ArColor(0,255,0), 100, 75); ArFunctor2C<ArLocalizationTask, ArServerClient *, ArNetPacket *> drawingFunctorL(locTask, &ArLocalizationTask::drawRangePoints); drawings.addDrawing(&drawingDataL, "Localization Points", &drawingFunctorL); */ #ifndef SONARNL /* If you want to see the reflector rays use this */ ArDrawingData drawingDataL1("polySegments", ArColor(200,200,200), 1, 75); ArFunctor2C<ArLocalizationTask, ArServerClient *, ArNetPacket *> drawingFunctorL2(locTask, &ArLocalizationTask::drawReflectorRays); drawings.addDrawing(&drawingDataL1, "Reflector Rays", &drawingFunctorL2); #endif // Misc. simple commands: ArServerHandlerCommands commands(&server); // Forward any video if either ACTS or SAV server are running. // You can find out more about SAV and ACTS on our website // http://robots.activmedia.com. ACTS is for color tracking and is // a seperate product. SAV just does software A/V transmitting and is // free to all our customers. Just run ACTS or SAV server before you // start this program and this class here will forward video from the // server to the client. ArHybridForwarderVideo videoForwarder(&server, "localhost", 7070); // make a camera to use in case we have video ArPTZ *camera = NULL; ArServerHandlerCamera *handlerCamera = NULL; ArCameraCollection *cameraCollection = NULL; // if we have video then set up a camera if (videoForwarder.isForwardingVideo()) { cameraCollection = new ArCameraCollection(); cameraCollection->addCamera("Cam1", "VCC4", "Camera", "VCC4"); videoForwarder.setCameraName("Cam1"); videoForwarder.addToCameraCollection(*cameraCollection); bool invertedCamera = false; camera = new ArVCC4(&robot, invertedCamera, ArVCC4::COMM_UNKNOWN, true, true); camera->init(); handlerCamera = new ArServerHandlerCamera("Cam1", &server, &robot, camera, cameraCollection); pathTask.addNewGoalCB( new ArFunctor1C<ArServerHandlerCamera, ArPose>( handlerCamera, &ArServerHandlerCamera::cameraModeLookAtGoalSetGoal)); pathTask.addGoalFinishedCB( new ArFunctorC<ArServerHandlerCamera>( handlerCamera, &ArServerHandlerCamera::cameraModeLookAtGoalClearGoal)); } // After all of the cameras / videos have been created and added to the collection, // then start the collection server. // if (cameraCollection != NULL) { new ArServerHandlerCameraCollection(&server, cameraCollection); } // These provide various kinds of information to the client: ArServerInfoRobot serverInfoRobot(&server, &robot); ArServerInfoSensor serverInfoSensor(&server, &robot); ArServerInfoPath serverInfoPath(&server, &robot, &pathTask); serverInfoPath.addSearchRectangleDrawing(&drawings); serverInfoPath.addControlCommands(&commands); // Provides localization info and allows the client to relocalize at a given // pose: ArServerInfoLocalization serverInfoLocalization(&server, &robot, &locTask); ArServerHandlerLocalization serverLocHandler(&server, &robot, &locTask); // Provide the map to the client (and related controls): // This uses both lines and points now, since everything except // sonar localization uses both (path planning with sonar still uses both) ArServerHandlerMap serverMap(&server, &arMap); // Add some simple (custom) commands for testing and debugging: ArServerSimpleComUC uCCommands(&commands, &robot); // Send any command to the microcontroller ArServerSimpleComMovementLogging loggingCommands(&commands, &robot); // configure logging ArServerSimpleComGyro gyroCommands(&commands, &robot, &gyro); // monitor the gyro ArServerSimpleComLogRobotConfig configCommands(&commands, &robot); // trigger logging of the robot config parameters ArServerSimpleServerCommands serverCommands(&commands, &server); // monitor networking behavior (track packets sent etc.) /* Set up the possible modes for remote control from a client such as * MobileEyes: */ // Mode To go to a goal or other specific point: ArServerModeGoto modeGoto(&server, &robot, &pathTask, &arMap, locTask.getHomePose()); // Add a simple (custom) command that allows you to give a list of // goals to tour, instead of all. Useful for testing and debugging. modeGoto.addTourGoalsInListSimpleCommand(&commands); // Mode To stop and remain stopped: ArServerModeStop modeStop(&server, &robot); // Unless we are using SONARNL, cause the sonar to turn off automatically // when the robot is stopped, and turn it back on when commands to move // are sent. (If using SONARNL to localize, then we cannot turn sonar // off since localization may get lost) #ifndef SONARNL ArSonarAutoDisabler sonarAutoDisabler(&robot); #endif // Teleoperation modes To drive by keyboard, joystick, etc: ArServerModeRatioDrive modeRatioDrive(&server, &robot); // New, improved mode ArServerModeDrive modeDrive(&server, &robot); // Older mode for compatability // Prevent normal teleoperation driving if localization is lost using // a high-priority action, which enables itself when the particular mode is // active. // (You have to enter unsafe drive mode to drive when lost.) ArActionLost actionLostRatioDrive(&locTask, &pathTask, &modeRatioDrive); modeRatioDrive.getActionGroup()->addAction(&actionLostRatioDrive, 110); ArActionLost actionLostDrive(&locTask, &pathTask, &modeDrive); modeDrive.getActionGroup()->addAction(&actionLostDrive, 110); // Drive mode's configuration and custom (simple) commands: modeRatioDrive.addToConfig(Aria::getConfig(), "Teleop settings"); modeDrive.addControlCommands(&commands); modeRatioDrive.addControlCommands(&commands); // Wander mode (also prevent wandering if lost): ArServerModeWander modeWander(&server, &robot); ArActionLost actionLostWander(&locTask, &pathTask, &modeWander); modeWander.getActionGroup()->addAction(&actionLostWander, 110); // This provides a small table of interesting information for the client // to display to the operator: ArServerInfoStrings stringInfo(&server); Aria::getInfoGroup()->addAddStringCallback(stringInfo.getAddStringFunctor()); // Display localization score, and laser communication statistic if // not SonArnl: #ifdef SONARNL Aria::getInfoGroup()->addStringDouble( "Localization Score", 8, new ArRetFunctorC<double, ArSonarLocalizationTask>( &locTask, &ArSonarLocalizationTask::getLocalizationScore), "%.03f"); Aria::getInfoGroup()->addStringInt( "Num Samples", 8, new ArRetFunctorC<int, ArSonarLocalizationTask>( &locTask, &ArSonarLocalizationTask::getCurrentNumSamples), "%4d"); Aria::getInfoGroup()->addStringDouble( "CPU", 8, new ArGlobalRetFunctor<double>(&ArSystemStatus::getCPUPercent), "%.03f"); #else Aria::getInfoGroup()->addStringDouble( "Localization Score", 8, new ArRetFunctorC<double, ArLocalizationTask>( &locTask, &ArLocalizationTask::getLocalizationScore), "%.03f"); Aria::getInfoGroup()->addStringInt( "Num Samples", 8, new ArRetFunctorC<int, ArLocalizationTask>( &locTask, &ArLocalizationTask::getCurrentNumSamples), "%4d"); Aria::getInfoGroup()->addStringDouble( "CPU", 8, new ArGlobalRetFunctor<double>(&ArSystemStatus::getCPUPercent), "%.03f"); Aria::getInfoGroup()->addStringInt( "Laser Packet Count", 10, new ArRetFunctorC<int, ArSick>(&sick, &ArSick::getSickPacCount)); #endif Aria::getInfoGroup()->addStringInt( "Motor Packet Count", 10, new ArConstRetFunctorC<int, ArRobot>(&robot, &ArRobot::getMotorPacCount)); // Setup the dock if there is a docking system on board. // (But SONARNL can't dock, you need a laser to find it.) #ifndef SONARNL ArServerModeDock *modeDock = NULL; modeDock = ArServerModeDock::createDock(&server, &robot, &locTask, &pathTask); if (modeDock != NULL) { modeDock->checkDock(); modeDock->addAsDefaultMode(); modeDock->addToConfig(Aria::getConfig()); modeDock->addControlCommands(&commands); } #endif // ifndef SONARNL // Make Stop mode the default (If current mode deactivates without entering // a new mode, then Stop Mode will be selected) modeStop.addAsDefaultMode(); /* Services that allow the client to initiate scanning with the laser to create maps in Mapper3 (So not possible with SONARNL): */ #ifndef SONARNL // this will allow you to create a map from this program instead of having to // use sickLogger (comment it out if you don't want it) ArServerHandlerMapping handlerMapping(&server, &robot, &sick, fileDir, "", true); // make localization stop while mapping handlerMapping.addMappingStartCallback( new ArFunctor1C<ArLocalizationTask, bool> (&locTask, &ArLocalizationTask::setIdleFlag, true)); // and then make it start again when we're doine handlerMapping.addMappingEndCallback( new ArFunctor1C<ArLocalizationTask, bool> (&locTask, &ArLocalizationTask::setIdleFlag, false)); // Make it so our "lost" actions don't stop us while mapping handlerMapping.addMappingStartCallback(actionLostPath.getDisableCB()); handlerMapping.addMappingStartCallback(actionLostDrive.getDisableCB()); handlerMapping.addMappingStartCallback(actionLostRatioDrive.getDisableCB()); handlerMapping.addMappingStartCallback(actionLostWander.getDisableCB()); // And then let them make us stop as usual when done mapping handlerMapping.addMappingEndCallback(actionLostPath.getEnableCB()); handlerMapping.addMappingEndCallback(actionLostDrive.getEnableCB()); handlerMapping.addMappingEndCallback(actionLostRatioDrive.getEnableCB()); handlerMapping.addMappingEndCallback(actionLostWander.getEnableCB()); // don't let forbidden lines show up as obstacles while mapping // (since localization is off) handlerMapping.addMappingStartCallback(forbidden.getDisableCB()); // let forbidden lines show up as obstacles again as usual after mapping handlerMapping.addMappingEndCallback(forbidden.getEnableCB()); #endif // ifndef SONARNL /* File transfer services: */ #ifdef WIN32 // these server file things don't work under windows yet ArLog::log(ArLog::Normal, "Note, file upload/download services are not implemented for Windows; not enabling them."); #else // This block will allow you to set up where you get and put files // to/from, just comment them out if you don't want this to happen // /* ArServerFileLister fileLister(&server, fileDir); ArServerFileToClient fileToClient(&server, fileDir); ArServerFileFromClient fileFromClient(&server, fileDir, "/tmp"); ArServerDeleteFileOnServer deleteFileOnServer(&server, fileDir); // */ #endif // Create the service that allows the client to monitor the communication // between the robot and the client. // ArServerHandlerCommMonitor handlerCommMonitor(&server); // Create service that allows client to change configuration parameters in ArConfig ArServerHandlerConfig handlerConfig(&server, Aria::getConfig(), Arnl::getTypicalDefaultParamFileName(), Aria::getDirectory()); // Read in parameter files. Aria::getConfig()->useArgumentParser(&parser); if (!Aria::getConfig()->parseFile(Arnl::getTypicalParamFileName())) { ArLog::log(ArLog::Normal, "Trouble loading configuration file, exiting"); Aria::exit(5); } // Warn about unknown params. if (!simpleOpener.checkAndLog() || !parser.checkHelpAndWarnUnparsed()) { ArLog::log(ArLog::Normal, "\nUsage: %s -map mapfilename\n", argv[0]); simpleConnector.logOptions(); simpleOpener.logOptions(); Aria::exit(6); } // Warn if there is no map #ifndef SONARNL if (arMap.getFileName() == NULL || strlen(arMap.getFileName()) <= 0) { ArLog::log(ArLog::Normal, ""); ArLog::log(ArLog::Normal, "### No map file is set up, you can make a map with the following procedure"); ArLog::log(ArLog::Normal, "\t 0) You can find this information in README.txt or docs/Mapping.txt"); ArLog::log(ArLog::Normal, "\t 1) Connect to this server with MobileEyes"); ArLog::log(ArLog::Normal, "\t 2) Go to Tools->Map Creation->Start Scan"); ArLog::log(ArLog::Normal, "\t 3) Give the map a name and hit okay"); ArLog::log(ArLog::Normal, "\t 4) Drive the robot around your space (see docs/Mapping.txt"); ArLog::log(ArLog::Normal, "\t 5) Go to Tools->Map Creation->Stop Scan"); ArLog::log(ArLog::Normal, "\t 6) Start up Mapper3"); ArLog::log(ArLog::Normal, "\t 7) Go to File->Open on Robot"); ArLog::log(ArLog::Normal, "\t 8) Select the .2d you created"); ArLog::log(ArLog::Normal, "\t 9) Create a .map"); ArLog::log(ArLog::Normal, "\t10) Go to File->Save on Robot"); ArLog::log(ArLog::Normal, "\t11) In MobileEyes, go to Tools->Robot Config"); ArLog::log(ArLog::Normal, "\t12) Choose the Files section"); ArLog::log(ArLog::Normal, "\t13) Enter the path and name of your new .map file for the value of the Map parameter."); ArLog::log(ArLog::Normal, "\t14) Press OK and your new map should become the map used"); ArLog::log(ArLog::Normal, ""); } #else // ifndef SONARNL if (arMap.getFileName() == NULL || strlen(arMap.getFileName()) <= 0) { ArLog::log(ArLog::Normal, ""); ArLog::log(ArLog::Normal, "### No map file is set up, you can make a map with the following procedure"); ArLog::log(ArLog::Normal, "\t 0) You can find this information in README.txt or docs/SonarMapping.txt"); ArLog::log(ArLog::Normal, "\t 1) Start up Mapper3Basic"); ArLog::log(ArLog::Normal, "\t 2) Go to File->New"); ArLog::log(ArLog::Normal, "\t 3) Draw a line map of your area (make sure it is to scale)"); ArLog::log(ArLog::Normal, "\t 4) Go to File->Save on Robot"); ArLog::log(ArLog::Normal, "\t 5) In MobileEyes, go to Tools->Robot Config"); ArLog::log(ArLog::Normal, "\t 6) Choose the Files section"); ArLog::log(ArLog::Normal, "\t 7) Enter the path and name of your new .map file for the value of the Map parameter."); ArLog::log(ArLog::Normal, "\t 8) Press OK and your new map should become the map used"); ArLog::log(ArLog::Normal, ""); } #endif // ifndef SONARNL // find out where we'll want to put files ArLog::log(ArLog::Normal, ""); ArLog::log(ArLog::Normal, "Directory for maps and file serving: %s", fileDir); ArLog::log(ArLog::Normal, "See the ARNL README.txt for more information"); ArLog::log(ArLog::Normal, ""); // If you want MobileSim to try and load up the same map as you are // using in guiServer then uncomment out the next line and this object // will send a command to MobileSim to do so, but make sure you start // MobileSim from the Arnl/examples directory or use the --cwd option, // so that the map names used by MobileSim match the map names used // by guiServer //ArSimMapSwitcher mapSwitcher(&robot, &arMap); /* If using a "central server" to manage multiple robots, * then set up how configuration is recieved from the central * server: */ // Set one of these two flags to what you want to do... note if you // separate all sections from the central config // then you'll have to manage your own map on each robot, // which'll mean you can't use central avoidance bool enableSeparateAllSections = false; bool enableSeparateAllSectionsButFiles = false; if (clientSwitch.getCentralServerHostName() != NULL && (enableSeparateAllSections || enableSeparateAllSectionsButFiles)) { std::list<ArConfigSection *> *sections; std::list<ArConfigSection *>::iterator sIt; ArConfigSection *section; sections = Aria::getConfig()->getSections(); for (sIt = sections->begin(); sIt != sections->end(); sIt++) { section = (*sIt); // if this section is already separated then just continue if (section->hasFlag("SEPARATE_SECTION")) continue; // otherwise make sure we should separate it, and if so, do it if (enableSeparateAllSections || (enableSeparateAllSectionsButFiles && strcasecmp(section->getName(), "Files") != 0)) { Aria::getConfig()->addSectionFlags(section->getName(), "SEPARATE_SECTION"); } } } // if our map file has a separate local section then make a special // command on the server to tell the central server if (Aria::getConfig()->findSection("Files") != NULL && Aria::getConfig()->findSection("Files")->hasFlag("SEPARATE_SECTION")) { server.addData( "centralServerDoNotPushMap", "Data to tell the central server not to push maps at this program", NULL, "none", "none", "Disallowed", "MAIN_SERVER_ONLY"); } /* Finally, get ready to run the robot: */ robot.unlock(); // Localize robot at home. locTask.localizeRobotAtHomeBlocking(); // Let the client switch manager spin off into its own thread clientSwitch.runAsync(); // Now let it spin off in its own thread server.runAsync(); // Add a key handler (mostly so that on windows you can exit by pressing // escape.) This key handler, however, prevents this program from // running in the background (e.g. as a system daemon or run from // the shell with "&") -- it will lock up trying to read the keys; // remove this if you wish to be able to run this program in the background. ArKeyHandler *keyHandler; if ((keyHandler = Aria::getKeyHandler()) == NULL) { keyHandler = new ArKeyHandler; Aria::setKeyHandler(keyHandler); robot.lock(); robot.attachKeyHandler(keyHandler); robot.unlock(); printf("To exit, press escape.\n"); } robot.waitForRunExit(); Aria::exit(0); }
1.4.0