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 }
1.4.7