Main Page | Modules | Class Hierarchy | Class List | Class Members | Examples

guiServer.cpp

Deluxe example of almost all ARNL features

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);
}

Generated on Tue Feb 20 10:56:29 2007 for Arnl by  doxygen 1.4.0