ptzCameraClientExample.cpp

Example client showing how to control a Pan/Tilt/Zoom camera remotely.

To use, first run SAVserver. Then run serverDemo, or guiServer from ARNL or guiServerSonar from SONARNL on the robot's onboard computer. Or run your own server program that includes ArServerHandlerCamera. Then from another host, run ptzCameraClientExample with the -host argument. For example, if the hostname of the robot's onboard computer is "robot", run: ptzCameraClientExample -host robot

This program connects to the server, gets a list of cameras if neccesary, and for each camera on the robot, it receives and prints out one information packet, then a continuous stream of data packets, and then sends requests to cycle through each of its pan and tilt limits.

00001 #include "Aria.h"
00002 #include "ArNetworking.h"
00003 #include <math.h>
00004 
00005 
00026 class ArNetCameraRequest : public ArNetPacket
00027 {
00028   ArClientBase *myClient;
00029   std::string myAbsReqName;
00030 public:
00031   ArNetCameraRequest(ArClientBase *client, const char *cameraName = "") : myClient(client), myAbsReqName(std::string("setCameraAbs")+cameraName)
00032   {}
00033   void setCameraName(const char *name) {
00034     myAbsReqName = std::string("setCameraAbs") + name;
00035   }
00036   bool requestPanTiltZoomAbs(double pan, double tilt, double zoom);
00037   bool requestPanTiltAbs(double pan, double tilt);
00038 };
00039 
00040 
00044 class ArClientHandlerCamera {
00045 public:
00046   std::string name;
00047   std::string type;
00048   std::string displayName;
00049   std::string displayType;
00050   double minPan, maxPan, minTilt, maxTilt, minZoom, maxZoom;
00051   bool haveZoom;
00052   double pan, tilt, zoom;
00053 
00054   void handleCameraInfoReply(ArNetPacket *packet);
00055   void handleCameraDataReply(ArNetPacket *packet);
00056 
00057   ArClientBase *myClient;
00058   ArNetCameraRequest request;
00059   ArMutex myMutex;
00060 
00061   ArFunctor1C<ArClientHandlerCamera, ArNetPacket*> myCameraInfoReplyFunc;
00062   ArFunctor1C<ArClientHandlerCamera, ArNetPacket*> myCameraDataReplyFunc;
00063 
00064   ArClientHandlerCamera(ArClientBase *client, const char *cameraName) : 
00065     name(cameraName), myClient(client), request(client, cameraName) ,
00066     myCameraInfoReplyFunc(this, &ArClientHandlerCamera::handleCameraInfoReply),
00067     myCameraDataReplyFunc(this, &ArClientHandlerCamera::handleCameraDataReply)
00068   {
00069     myClient->addHandler((std::string("getCameraInfo")+name).c_str(), &myCameraInfoReplyFunc);
00070     myClient->addHandler((std::string("getCameraData")+name).c_str(), &myCameraDataReplyFunc);
00071   }
00072 
00073   void requestUpdates(int dataRequestFreq) {
00074     myClient->request((std::string("getCameraInfo")+name).c_str(), -1);
00075     myClient->request((std::string("getCameraData")+name).c_str(), 100);
00076   }
00077 
00078   void lock() { myMutex.lock(); }
00079   void unlock() { myMutex.unlock(); }
00080 };
00081 
00082 
00084 class PtzCameraExample
00085 {
00086   ArClientBase *myClient;
00087 
00088   std::set<ArClientHandlerCamera*> myCameras;
00089   ArMutex mutex;
00090 
00091   ArFunctor1C<PtzCameraExample, ArNetPacket*> myCameraListReplyFunc;
00092 
00093   void handleCameraListReply(ArNetPacket *packet);
00094 
00095 
00096 public:
00097   PtzCameraExample(ArClientBase *client) : 
00098     myClient(client), 
00099     myCameraListReplyFunc(this, &PtzCameraExample::handleCameraListReply)
00100   {
00101   }
00102 
00103   bool init();
00104   void run();
00105 };
00106 
00107 
00108 
00109 int main(int argc, char **argv)
00110 {
00111   Aria::init();
00112   ArClientBase client;
00113 
00114   ArArgumentParser parser(&argc, argv);
00115   ArClientSimpleConnector clientConnector(&parser);
00116   parser.loadDefaultArguments();
00117   if (!Aria::parseArgs() || !parser.checkHelpAndWarnUnparsed())
00118   {    
00119     Aria::logOptions();
00120     return 1;
00121   }
00122 
00123   if (!clientConnector.connectClient(&client))
00124   {
00125     if(client.wasRejected())
00126       ArLog::log(ArLog::Terse, "Error, server '%s' rejected connection. Exiting.", client.getHost());
00127     else
00128       ArLog::log(ArLog::Terse, "Error, could not connect to server '%s'. Exiting.", client.getHost());
00129     return 2;
00130   }
00131 
00132   client.setRobotName(client.getHost());  // include server hostname in log messages
00133 
00134   client.runAsync();
00135 
00136   PtzCameraExample example(&client);
00137   if(!example.init())
00138     return 1;
00139 
00140   example.run();
00141 
00142 
00143   Aria::shutdown();
00144   return 0;
00145 }
00146 
00147 
00148 bool PtzCameraExample::init()
00149 {
00150   // If the server has the "getCameraList" request, then it's using
00151   // ArServerHandlerCameraCollection, and migth have multiple PTZs/cameras each with
00152   // its own set of requests. So send a "getCameraList" request, and when its
00153   // reply is received, the handler will send "getCameraInfo" requests for each.
00154   // If the server does not have "getCameraList", it only has one PTZ camera, just
00155   // send "getCameraInfo". The handler for that will send various control
00156   // commands.
00157   // If the server does not have "getCameraInfo", then it doesn't provide any
00158   // access to PTZ cameras.
00159   if(myClient->dataExists("getCameraList"))
00160   {
00161     ArLog::log(ArLog::Normal, "Server may have multiple cameras. Requesting list.");
00162     myClient->addHandler("getCameraList", &myCameraListReplyFunc);
00163     myClient->requestOnce("getCameraList");
00164   }
00165   else if(myClient->dataExists("getCameraInfo"))
00166   {
00167     ArLog::log(ArLog::Normal, "Server does not support multiple cameras. Requesting info for its camera.");
00168     ArClientHandlerCamera *camClient = new ArClientHandlerCamera(myClient, "");
00169     camClient->requestUpdates(100);
00170     mutex.lock();
00171     myCameras.insert(camClient);
00172     mutex.unlock();
00173   }
00174   else
00175   {
00176     ArLog::log(ArLog::Terse, "Error, server does not have any camera control requests. (Was the server run with video features enabled or video forwarding active?)");
00177     return false;
00178   }
00179   return true;
00180 }
00181 
00182 void PtzCameraExample::handleCameraListReply(ArNetPacket *pkt)
00183 {
00184   ArTypes::Byte2 numCams = pkt->bufToByte2();
00185   ArLog::log(ArLog::Normal, "%d cameras in list.", numCams);
00186   char camName[128];
00187   char camType[128];
00188   char displayName[128];
00189   char displayType[128];
00190   char cmdDesc[128];
00191   char cmdName[128];
00192   ArTypes::Byte4 cmdFreq;
00193   int dataReqFreq = 100;
00194   for(ArTypes::Byte2 i = 0; i < numCams; ++i)
00195   {
00196     memset(camName, 0, 128);
00197     memset(camType, 0, 128);
00198     memset(displayName, 0, 128);
00199     memset(displayType, 0, 128);
00200     pkt->bufToStr(camName, 128); // name
00201 
00202     ArClientHandlerCamera *cam = new ArClientHandlerCamera(myClient, camName);
00203 
00204     pkt->bufToStr(camType, 128); // type
00205     cam->type = camType;
00206     pkt->bufToStr(displayName, 128); // description
00207     cam->displayName = displayName;
00208     pkt->bufToStr(displayType, 128); // description
00209     cam->displayType = displayType;
00210     ArTypes::Byte2 numCmds = pkt->bufToByte2();
00211     ArLog::log(ArLog::Normal, "%d commands for camera \'%s\' (%s) / \'%s\' (%s)", numCmds, camName, camType, displayName, displayType);
00212     for(ArTypes::Byte2 c = 0; c < numCmds; ++c)
00213     {
00214       memset(cmdDesc, 0, 128);
00215       memset(cmdName, 0, 128);
00216       char cmdDesc[128];
00217       char cmdName[128];
00218       pkt->bufToStr(cmdDesc, 128); // description
00219       pkt->bufToStr(cmdName, 128); // request name
00220       cmdFreq = pkt->bufToByte4(); // recommended request frequency
00221       ArLog::log(ArLog::Normal, "Camera %s has %s command named %s with recommended request frequency %d.", camName, cmdDesc, cmdName, cmdFreq);
00222 
00223       if(strcmp(cmdDesc, "getCameraData") == 0)
00224         dataReqFreq = cmdFreq;
00225     }
00226     ArTypes::Byte2 numParams = pkt->bufToByte2();
00227     ArLog::log(ArLog::Normal, "Camera %s has %d parameters.", camName, numParams);
00228     for(ArTypes::Byte2 p = 0; p < numParams; ++p)
00229     {
00230       ArClientArg carg;
00231       ArConfigArg arg;
00232       if(!carg.bufToArgValue(pkt, arg))
00233         ArLog::log(ArLog::Normal, "Hmm, error getting ArClientArg for camera %s's parameter #%d.", camName, p);
00234     }
00235 
00236     cam->requestUpdates(dataReqFreq);
00237     mutex.lock();
00238     myCameras.insert(cam);
00239     mutex.unlock();
00240   }
00241 }
00242 
00243 void ArClientHandlerCamera::handleCameraInfoReply(ArNetPacket *pkt)
00244 {
00245   lock();
00246   minPan = pkt->bufToByte2() / 1000.0;
00247   maxPan = pkt->bufToByte2() / 1000.0;
00248   minTilt = pkt->bufToByte2() / 1000.0;
00249   maxTilt = pkt->bufToByte2() / 1000.0;
00250   minZoom = pkt->bufToByte2() / 1000.0;
00251   maxZoom = pkt->bufToByte2() / 1000.0;
00252   haveZoom = pkt->bufToByte();
00253   ArLog::log(ArLog::Normal, "Got getCameraInfo reply with pan range (%f, %f), tilt range (%f, %f), zoom range (%f, %f), zoom valid %d.", minPan, maxPan, minTilt, maxTilt, minZoom, maxZoom, haveZoom);
00254   unlock();
00255 }
00256 
00257 void ArClientHandlerCamera::handleCameraDataReply(ArNetPacket *pkt)
00258 {
00259   lock();
00260   pan = pkt->bufToByte2() / 1000.0;
00261   tilt = pkt->bufToByte2() / 1000.0;
00262   zoom = pkt->bufToByte2() /1000.0;
00263   ArLog::log(ArLog::Normal, "Got camera data from camera %s with current pan=%f, tilt=%f, zoom=%f.", name.c_str(), pan, tilt, zoom);
00264   unlock();
00265 }
00266 
00267 bool ArNetCameraRequest::requestPanTiltAbs(double pan, double tilt)
00268 {
00269   empty();
00270   byte2ToBuf((ArTypes::Byte2)(pan * 1000.0));
00271   byte2ToBuf((ArTypes::Byte2)(tilt * 1000.0));
00272   finalizePacket();
00273   return myClient->requestOnce(myAbsReqName.c_str(), this);
00274 }
00275 
00276 bool ArNetCameraRequest::requestPanTiltZoomAbs(double pan, double tilt, double zoom)
00277 {
00278   empty();
00279   byte2ToBuf((ArTypes::Byte2)(pan * 1000.0));
00280   byte2ToBuf((ArTypes::Byte2)(tilt * 1000.0));
00281   byte2ToBuf((ArTypes::Byte2)(zoom * 1000.0));
00282   finalizePacket();
00283   return myClient->requestOnce(myAbsReqName.c_str(), this);
00284 }
00285 
00286 
00287 void PtzCameraExample::run()
00288 {
00289   enum { MinPan, MaxPan, Center1, MinTilt, MaxTilt, Center2} stage;
00290   stage = MinPan;
00291   while(myClient->isConnected()) 
00292   {
00293     mutex.lock();
00294     for(std::set<ArClientHandlerCamera*>::const_iterator i = myCameras.begin(); i != myCameras.end(); ++i)
00295     {
00296       ArClientHandlerCamera* c = (*i);
00297       c->lock();
00298       switch(stage)
00299       {
00300         case MinPan:
00301           c->request.requestPanTiltAbs(c->minPan, 0);
00302           stage = MaxPan;
00303           break;
00304         case MaxPan:
00305           c->request.requestPanTiltAbs(c->maxPan, 0);
00306           stage = Center1;
00307           break;
00308         case Center1:
00309           c->request.requestPanTiltAbs(0, 0);
00310           stage = MinTilt;
00311           break;
00312         case MinTilt:
00313           c->request.requestPanTiltAbs(0, c->minTilt);
00314           stage = MaxTilt;
00315           break;
00316         case MaxTilt:
00317           c->request.requestPanTiltAbs(0, c->maxTilt);
00318           stage = Center2;
00319           break;
00320         case Center2:
00321           c->request.requestPanTiltAbs(0, 0);
00322           stage = MinPan;
00323       }
00324       c->unlock();
00325     }
00326     mutex.unlock();
00327     ArUtil::sleep(3000);
00328   }
00329 }

Generated on Fri Jul 31 12:37:28 2009 for ArNetworking by  doxygen 1.4.7