Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages | Examples

dpptuExample.cpp

Shows how to control the Directed Perceptions Pan-Tilt Unit.

This program lets you use the keyboard to control the DPPTU. It uses the same acceleration and slew rates for the pan and tilt axes.

Commands: _________________

UP,DOWN -- tilt up/down by one positional increment LEFT,RIGHT -- pan left/right by one positional increment SPACE -- perform reset calibration I -- initialize PTU to default settings <,> -- increase/decrease the posIncrement by 1 degree +,- -- increase/decrease the speed by 1 degree/sec A -- awaits the completion of last issued positional command R -- change pan/tilt movements to relative or absolute movements Z -- move pan and tilt axes to zero M -- Enter or Exit monitor mode H -- Halt all motion S -- print current variable values ESC -- quit

#include "Aria.h"

// If defined, use this computer serial port. If not defined, use first robot
// aux. serial port.  Most robots have the DPPTU on COM2 if on Linux and COM4 on
// Windows, if not equipped with other accessories which might require those
// ports (e.g. GPS or Laser).
#define SERIAL_PORT ArUtil::COM4

/*
  This class is the core of this demo, it adds itself to the robot given
  as a user task, and contains key handler callbacks to control the PTU.
*/
class KeyPTU
{
public:
  // constructor
  KeyPTU(ArRobot *robot);
  ~KeyPTU(void);
  
  void up(void);
  void down(void);
  void left(void);
  void right(void);
  void space(void);
  void i(void);
  void plus(void);
  void minus(void);
  void greater(void);
  void less(void);
  void question(void);
  void status(void);
  void a(void);
  void z(void);
  void m(void);
  void h(void);
  void r(void);

  // the callback function
  void drive(void);

protected:
  int myPanValPTU;
  int myTiltValPTU;

  int myDesiredPanPos;
  int myDesiredTiltPos;
  int mySlew;
  int myPosIncrement;
  int mySlewIncrement;

  int posIncIncrement;

  bool myMonitor;
  bool myReset;
  bool myInit;
  bool myAbsolute;

  ArFunctorC<KeyPTU> myUpCB;
  ArFunctorC<KeyPTU> myDownCB;
  ArFunctorC<KeyPTU> myLeftCB;
  ArFunctorC<KeyPTU> myRightCB;
  ArFunctorC<KeyPTU> mySpaceCB;
  ArFunctorC<KeyPTU> myICB;
  ArFunctorC<KeyPTU> myPlusCB;
  ArFunctorC<KeyPTU> myMinusCB;
  ArFunctorC<KeyPTU> myGreaterCB;
  ArFunctorC<KeyPTU> myLessCB;
  ArFunctorC<KeyPTU> myQuestionCB;
  ArFunctorC<KeyPTU> mySCB;
  ArFunctorC<KeyPTU> myACB;
  ArFunctorC<KeyPTU> myZCB;
  ArFunctorC<KeyPTU> myMCB;
  ArFunctorC<KeyPTU> myHCB;
  ArFunctorC<KeyPTU> myRCB;


  // the PTU
  ArDPPTU myPTU;
  

  // whether the PTU has been inited or not
  bool myPTUInited;
  // pointer to the robot
  ArRobot *myRobot;
  // callback for the drive function
  ArFunctorC<KeyPTU> myDriveCB;

  ArSerialConnection *mySerialConnection;
};

/*
  Constructor, sets the robot pointer, and some initial values, also note the
  use of constructor chaining on myPTU and myDriveCB.
*/
KeyPTU::KeyPTU(ArRobot *robot) :
  myUpCB(this, &KeyPTU::up),
  myDownCB(this, &KeyPTU::down),
  myLeftCB(this, &KeyPTU::left),
  myRightCB(this, &KeyPTU::right),
  mySpaceCB(this, &KeyPTU::space),
  myICB(this, &KeyPTU::i),
  myPlusCB(this, &KeyPTU::plus),
  myMinusCB(this, &KeyPTU::minus),
  myGreaterCB(this, &KeyPTU::greater),
  myLessCB(this, &KeyPTU::less),
  myQuestionCB(this, &KeyPTU::question),
  mySCB(this, &KeyPTU::status),
  myACB(this, &KeyPTU::a),
  myZCB(this, &KeyPTU::z),
  myMCB(this, &KeyPTU::m),
  myHCB(this, &KeyPTU::h),
  myRCB(this, &KeyPTU::r),
  myPTU(robot),
  myDriveCB(this, &KeyPTU::drive),
  mySerialConnection(NULL)
{
#ifdef SERIAL_PORT
  mySerialConnection = new ArSerialConnection;
  ArLog::log(ArLog::Normal, "dpptuExample: connecting to DPPTU over computer serial port %s.", SERIAL_PORT);
  if(mySerialConnection->open(SERIAL_PORT) != 0)
  {
    ArLog::log(ArLog::Terse, "dpptuExample: Error: Could not open computer serial port %s for DPPTU!", SERIAL_PORT);
    Aria::exit(5);
  }
  myPTU.setDeviceConnection(mySerialConnection);
#endif

  // set the robot pointer and add the KeyPTU as user task
  ArKeyHandler *keyHandler;
  myRobot = robot;
  myRobot->addSensorInterpTask("KeyPTU", 50, &myDriveCB);

  if ((keyHandler = Aria::getKeyHandler()) == NULL)
  {
    keyHandler = new ArKeyHandler;
    Aria::setKeyHandler(keyHandler);
    myRobot->attachKeyHandler(keyHandler);
  }

  if (!keyHandler->addKeyHandler(ArKeyHandler::UP, &myUpCB))
    ArLog::log(ArLog::Terse, "The key handler already has a key for up, keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler(ArKeyHandler::DOWN, &myDownCB))
    ArLog::log(ArLog::Terse, "The key handler already has a key for down, keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler(ArKeyHandler::LEFT, &myLeftCB))
    ArLog::log(ArLog::Terse,  
"The key handler already has a key for left, keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler(ArKeyHandler::RIGHT, &myRightCB))
    ArLog::log(ArLog::Terse,  
"The key handler already has a key for right, keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler(ArKeyHandler::SPACE, &mySpaceCB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for space, keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler('i', &myICB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for 'i', keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler('+', &myPlusCB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for '+', keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler('-', &myMinusCB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for '-', keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler('>', &myGreaterCB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for '>', keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler('<', &myLessCB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for '<', keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler('?', &myQuestionCB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for '?', keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler('s', &mySCB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for 'S', keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler('a', &myACB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for 'A', keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler('z', &myZCB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for 'Z', keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler('m', &myMCB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for 'M', keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler('h', &myHCB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for 'H', keydrive will not work correctly.");
  if (!keyHandler->addKeyHandler('r', &myRCB))
    ArLog::log(ArLog::Terse,
"The key handler already has a key for 'R', keydrive will not work correctly.");

  // initialize some variables
  myReset = false;
  myInit = true;
  myDesiredPanPos = 0;
  myDesiredTiltPos = 0;
  myPosIncrement = 1;
  mySlewIncrement = 1;
  myPTUInited = false;
  posIncIncrement = 1;
  myMonitor = false;

}

KeyPTU::~KeyPTU() 
{
  if(mySerialConnection)
  {
    myPTU.setDeviceConnection(NULL);
    delete mySerialConnection;
  }
}



void KeyPTU::left(void)
{
  myDesiredPanPos += myPosIncrement;

  if (myDesiredPanPos > myPTU.getMaxPosPan())
    myDesiredPanPos = myPTU.getMaxPosPan();
}

void KeyPTU::right(void)
{
  myDesiredPanPos -= myPosIncrement;

  if (myDesiredPanPos < myPTU.getMaxNegPan())
    myDesiredPanPos = myPTU.getMaxNegPan();
}

void KeyPTU::up(void)
{
  myDesiredTiltPos += myPosIncrement;
 
  if (myDesiredTiltPos > myPTU.getMaxPosTilt())
    myDesiredTiltPos = myPTU.getMaxPosTilt();
}

void KeyPTU::down(void)
{
  myDesiredTiltPos -= myPosIncrement;

  if (myDesiredTiltPos < myPTU.getMaxNegTilt())
    myDesiredTiltPos = myPTU.getMaxNegTilt();
}

void KeyPTU::space(void)
{
  myReset = true;
}

void KeyPTU::i(void)
{
  myInit = true;
}

void KeyPTU::plus(void)
{
  mySlew += mySlewIncrement;

  if (mySlew > myPTU.getMaxPanSlew())
    mySlew = myPTU.getMaxPanSlew();

  status();
}

void KeyPTU::minus(void)
{
  mySlew -= mySlewIncrement;

  if (mySlew < myPTU.getMinPanSlew())
    mySlew = myPTU.getMinPanSlew();

  status();
}

void KeyPTU::greater(void)
{
  myPosIncrement += posIncIncrement;
  
  if (myPosIncrement > myPTU.getMaxPosPan())
    myPosIncrement = myPTU.getMaxPosPan();

  status();
}

void KeyPTU::less(void)
{
  myPosIncrement -= posIncIncrement;

  if (myPosIncrement < 0)
    myPosIncrement = 0;

  status();
}

void KeyPTU::a(void)
{
  myPTU.awaitExec();   
  ArLog::log(ArLog::Normal, "AwaitExecution command sent");
}

void KeyPTU::z(void)
{
  myPTU.pan(0);
  myPTU.awaitExec();
  myPTU.tilt(0);
  myPTU.awaitExec();
  myDesiredPanPos = 0;
  myDesiredTiltPos = 0;
  status();
}

void KeyPTU::question(void)
{
  ArLog::log(ArLog::Normal, "\r\nCommands:\r\n_________________\r\n");
  ArLog::log(ArLog::Normal, "UP,DOWN    -- tilt up/down by one positional increment");
  ArLog::log(ArLog::Normal, "LEFT,RIGHT -- pan left/right by one positional increment");
  ArLog::log(ArLog::Normal, "SPACE      -- perform reset calibration");
  ArLog::log(ArLog::Normal, "I          -- initialize PTU to default settings");
  ArLog::log(ArLog::Normal, "<,>        -- increase/decrease the posIncrement by 1 degree");
  ArLog::log(ArLog::Normal, "+,-        -- increase/decrease the speed by 1 degree/sec");
  ArLog::log(ArLog::Normal, "A          -- awaits the completion of last issued positional command");
  ArLog::log(ArLog::Normal, "R          -- change pan/tilt movements to relative or absolute movements");
  ArLog::log(ArLog::Normal, "Z          -- move pan and tilt axes to zero");
  ArLog::log(ArLog::Normal, "M          -- Enter or Exit monitor mode");
  ArLog::log(ArLog::Normal, "H          -- Halt all motion");
  ArLog::log(ArLog::Normal, "S          -- print current variable values");
  ArLog::log(ArLog::Normal, "ESC        -- exit program");
  ArLog::log(ArLog::Normal, "\r\n");
}

void KeyPTU::status(void)
{
  ArLog::log(ArLog::Normal, "\r\nStatus:\r\n_________________\r\n");
  ArLog::log(ArLog::Normal, "Pan Position       = %.1f deg", myPTU.getPan());
  ArLog::log(ArLog::Normal, "Tilt Position      = %.1f deg", myPTU.getTilt());
  ArLog::log(ArLog::Normal, "Pan Slew Rate      = %d deg/sec", myPTU.getPanSlew());
  ArLog::log(ArLog::Normal, "Tilt Slew Rate     = %d deg/sec", myPTU.getTiltSlew());
  ArLog::log(ArLog::Normal, "Position Increment = %d deg", myPosIncrement);
  if (myAbsolute)
    ArLog::log(ArLog::Normal, "Positional-movements using absolute commands");
  else
    ArLog::log(ArLog::Normal, "Positional-movements using relative commands");
  ArLog::log(ArLog::Normal, "\r\n");
}

void KeyPTU::m(void)
{
  if (!myMonitor)
  {
    ArLog::log(ArLog::Normal, "Entering Monitor mode - hit 'M' to disable");
    myMonitor = true;
    myPTU.initMon(-60,60,30,-30);
  }
  else
  {
    myPTU.blank();  //Blank packet exits monitor mode
    myMonitor = false;
  }
}

void KeyPTU::h(void)
{
  myPTU.haltAll();
}

void KeyPTU::r(void)
{
  if (!myAbsolute)
  {
    myAbsolute = true;
  }
  else
  {
    myAbsolute = false;
  }
  status();
}


// the important function
void KeyPTU::drive(void)
{

  // if the PTU isn't initialized, initialize it here... it has to be 
  // done here instead of above because it needs to be done when the 
  // robot is connected
  if (!myPTUInited && myRobot->isConnected())
  {
    myPTU.init();
    myPTU.resetCalib();
    myPTU.awaitExec();
    myPTU.regStatPower();
    myPTU.regMotPower();
    mySlew = myPTU.getPanSlew(); //uses only pan slew rate
    myPTU.awaitExec();
    myPTUInited = true;
    myInit = false;
    myAbsolute = true;
  }

  if (myInit == true)
  {
    myPTU.init();
    myInit = false;
    myDesiredPanPos = myPTU.getPan();
    myDesiredTiltPos = myPTU.getTilt();
    mySlew = myPTU.getPanSlew(); //uses only pan slew rate
    myReset = false;
  }

  if (myReset == true)
  {
    myPTU.resetCalib();
    myPTU.awaitExec();
    myDesiredPanPos = myPTU.getPan();
    myDesiredTiltPos = myPTU.getTilt();
    myReset = false;
  }
  else
  {

    if (myDesiredPanPos != myPTU.getPan())
    {
      if (myAbsolute)
        myPTU.pan(myDesiredPanPos);
      else
        myPTU.panRel(myDesiredPanPos - myPTU.getPan());
    }

    if (myDesiredTiltPos != myPTU.getTilt())
    {
      if (myAbsolute)
        myPTU.tilt(myDesiredTiltPos);
      else
        myPTU.tiltRel(myDesiredTiltPos - myPTU.getTilt());
    }

    if (mySlew != myPTU.getPanSlew())
    {
      myPTU.panSlew(mySlew);
      myPTU.tiltSlew(mySlew);
    }

  }

}

int main(int argc, char **argv) 
{ 
  Aria::init();

  // command-line arguments and robots connection
  ArArgumentParser argParser(&argc, argv);
  argParser.loadDefaultArguments();
  ArSimpleConnector con(&argParser);

  // the robot, but turn state reflection off (so we have no mobility control in
  // this program)
  ArRobot robot(NULL, false);

  // an object for keyboard control, class defined above, this also adds itself as a user task
  KeyPTU ptu(&robot);

  // parse command-line arguments (i.e. connection options for simple connector)
  if(!Aria::parseArgs())
  {
    Aria::logOptions();
    return 1;
  }

  // connect to the robot
  if (!con.connectRobot(&robot))
  {
    ArLog::log(ArLog::Terse, "Error connecting to robot!");
    Aria::shutdown();
    return 1;
  }


  // turn off the sonar
  robot.comInt(ArCommands::SONAR, 0);

  printf("Press '?' for available commands\r\n");

  // run, if we lose connection to the robot, exit
  robot.run(true);
  
  Aria::shutdown();
  return 0;
}


Generated on Thu Jan 7 10:34:38 2010 for Aria by  doxygen 1.4.2