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

vos/corelibs/tracking/trackerd.cc

Go to the documentation of this file.
00001 
00002 /* $Id: trackerd.cc,v 1.14 2003/04/24 00:21:13 reed Exp $
00003  *
00004     Copyright (C) 2002 Reed Hedges
00005 
00006     This software was written at the University of Massachusetts with
00007     support from NSF grant #EIA 9703217
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017     GNU General Public License for more details.
00018 
00019     You should have received a copy of the GNU General Public License
00020     along with this program; if not, write to the Free Software
00021     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 */
00023 
00024 /** @file trackerd.cc 
00025  * This is a simple tracker server: it listens on a socket for commands, reads
00026  * data from the a position or orientation tracker, and returns the data.
00027  * This allows multiple programs to use data from the same tracker.
00028  *
00029  * @author Reed Hedges, August 2002
00030  *
00031  * Currently supported position trackers are:
00032  *  GPSD (Remco Treffkorn's GPS daemon: <http://russnelson.com/gpsd/>)
00033  *
00034  * Currently supported orientaiton trackers are:
00035  *  Intersense IS300 on a serial port 
00036  *  (soon GPS compass and GPS derived)
00037  *
00038  * Commands are:
00039  *  om:0  Read orientation matrix from tracker #0. 
00040  *      Returns: om:0=T11,T12,T13;T21,T22,T23;T31,T32,T33
00041  *  oa:0  Read orientation angles from tracker #0.
00042  *      Returns: oa:0=YAW,PITCH,ROLL 
00043  *  p:0  Read position from tracker #0.
00044  *      Returns: p:0=X,Y,Z
00045  *
00046  *  All values are double-precision floating point numbers, as 
00047  *  output by printf("%.8f"). (use "%lf" with scanf)
00048  *
00049  *  Currently only one orientation tracker (o?:0) and one position
00050  *  tracker (p:0) are possible.
00051  *
00052  * @TODO  support multiple trackers
00053  * @TODO  add commands to set tracker calibrations (offsets and scale factors)
00054  * @TODO  read tracker info from config file
00055  * @BUG   no timeout if intersense does not respond (bug in
00056  * IntersenseOrientation)
00057  */
00058 
00059 
00060 #include <sys/types.h>
00061 #include <netdb.h>
00062 #include <unistd.h>
00063 #include <sys/time.h>
00064 #include <sys/socket.h>
00065 #include <netinet/in.h>
00066 #include <signal.h>
00067 #include <errno.h>
00068 #include <set>
00069 #include <iostream>
00070 #include "orientation.hh"
00071 #include "intersenseorientation.hh"
00072 #include "position.hh"
00073 #include "gpsd_position.hh"
00074 
00075 
00076 using namespace std;
00077 
00078 #ifdef __APPLE__
00079 typedef unsigned int socklen_t;
00080 #endif
00081 
00082 
00083 /** Default socket port */
00084 #define DEFAULT_PORT 2948
00085 
00086 
00087 /** Return current time as seconds since unix epoc */
00088 double currentTime() {
00089     static struct timeval tv;
00090     gettimeofday(&tv, NULL);
00091     return  ( tv.tv_sec + (tv.tv_usec / 1000000.0) );
00092 }
00093 
00094 /** Print summary of command-line options. */
00095 void usage() {
00096     cout << "usage: trackerd [-P PORT] [-o OTYPE] [-p PTYPE] [-od DEV] [-os SPEED] [-ph HOST] [-pp PORT]\n" <<
00097         "\t-P PORT\tuse PORT for socket port (default is " << DEFAULT_PORT << "\n" <<
00098         "\t-o TYPE\tuse TYPE for orientation device 0 (intersense, fake)\n" <<
00099         "\t-p TYPE\tuse TYPE for position device 0 (gpsd, fake)\n" <<
00100         "\t-od DEV\tuse DEV for orientation device name (Default /dev/isense)\n" <<
00101         "\t-os SPEED\tuse SPEED baud for orientation device. (Default 115200)\n" <<
00102         "\t-of FREQ\tminimum tracker read frequency in seconds (Default 0.04)\n" << 
00103         "\t-ph HOST\tuse HOST for for position server host\n" <<
00104         "\t-pp PORT\tuse PORT for position server port\n" <<
00105         "\t-pf FREQ\tmininum tracker read frequency in seconds (Default is 0.04)\n" <<
00106         endl;
00107 }
00108 
00109 /** Testing */
00110 //@{
00111 class FakeOrientation : public Orientation {
00112 public:
00113     virtual void getOrientationMatrix(double m[3][3]) {
00114         m[0][0] = m[0][1] = m[0][2] =
00115         m[1][0] = m[1][1] = m[1][2] = 
00116         m[2][0] = m[2][1] = m[2][2] = 42.0;
00117     }
00118 
00119     virtual void getEulerAngles(double* y, double* p, double* r) {
00120         *y = *p = *r = 23.0;
00121     }
00122 };
00123 
00124 class FakePosition : public Position {
00125 public:
00126     virtual void getPosition(double* x, double* y, double* z) {
00127         *x = *y = *z = 0;
00128     }
00129 };
00130 //@}
00131 
00132 
00133 
00134 /** Main */
00135 int main(int argc, char** argv) {
00136     int port = DEFAULT_PORT;
00137     char* ori_type = 0;
00138     char* ori_dev = "/dev/isense";
00139     int ori_devspeed = 115200;  // baud
00140     Orientation* ori = NULL;
00141     char* pos_host = "localhost";
00142     int pos_port = GPSD_DEFAULT_PORT;
00143     char* pos_type = 0;
00144     Position* pos = NULL;
00145     double ori_freq = 0.04;     // seconds
00146     double pos_freq = 0.04;     // seconds
00147     double last_ori_read = 0;   // sec
00148     double last_pos_read = 0;   // sec
00149 
00150 
00151     /* Check parameters */
00152 
00153     for(int i = 1; i < argc; i++) {
00154         if(!strcmp(argv[i], "-o")) {
00155             ori_type = strdup(argv[++i]);
00156         } else if(!strcmp(argv[i], "-od")) {
00157             ori_dev = strdup(argv[++i]);
00158         } else if(!strcmp(argv[i], "-os")) {
00159             ori_devspeed = atoi(argv[++i]);
00160         } else if (!strcmp(argv[i], "-P")) {
00161            port = atoi( argv[++i] ); 
00162         } else if (!strcmp(argv[i], "-p")) {
00163             pos_type = strdup(argv[++i]);
00164         } else if (!strcmp(argv[i], "-ph")) {
00165             pos_host = strdup(argv[++i]);
00166         } else if (!strcmp(argv[i], "-pp")) {
00167             pos_port = atoi(argv[++i]);
00168         } else if (!strcmp(argv[i], "-of")) {
00169             ori_freq = atof(argv[++i]);
00170         } else if (!strcmp(argv[i], "-pf")) {
00171             pos_freq = atof(argv[++i]);
00172         } else {
00173             usage();
00174             exit(0);
00175         }
00176     }
00177 
00178     cerr << "creating tracking interfaces... ori_type = " << string( ori_type?ori_type:"NULL" ) << "  pos_type = " << string( pos_type?pos_type:"NULL" ) << endl;
00179 
00180     /* Create tracker objects */
00181 
00182     try {
00183         if(ori_type == 0)
00184             ori = 0;
00185         else if(strcmp(ori_type, "fake")==0)
00186             ori = new FakeOrientation();
00187 #ifdef HAVE_INTERSENSE
00188         else if(strcmp(ori_type, "intersense") == 0)
00189             ori = new IntersenseOrientation(ori_dev, ori_devspeed);
00190 #endif
00191         else {
00192             cerr << "Unrecognized orientation tracker type. Use \"-o intersense\" or \"-o fake\".\n";
00193             exit(-1);
00194         }
00195     } catch(exception& e) {
00196         cerr << "trackerd: Error connecting to " << ori_type << " orientation tracker device " << ori_dev << " at " << ori_devspeed << " baud! " << e.what();
00197         exit(-2);
00198     }
00199 
00200 
00201     try {
00202         if(pos_type == 0)
00203             pos = 0;
00204         else if(strcmp(pos_type, "fake")==0)
00205             pos = new FakePosition();
00206         else if(strcmp(pos_type, "gpsd") == 0)
00207             pos = new GPSDPosition(pos_host, pos_port);
00208         else {
00209             cerr << "Unrecognized position tracker type.  Use \"-p gpsd\" or \"-p fake\".\n";
00210             exit(-1);
00211         }
00212     } catch(exception& e) {
00213         cerr << "trackerd: Error connecting to " << pos_type << " position tracker server at " << pos_host << " port " << pos_port << "! " << e.what();
00214         exit(-2);
00215     }
00216 
00217     /* Start server */
00218 
00219     cout << "trackerd: Opening tcp socket at port " << port << "...\n";
00220     int server_socket = socket(AF_INET, SOCK_STREAM,  getprotobyname("tcp")->p_proto);
00221 
00222     cerr << "socket is: " << server_socket << endl;
00223 
00224     if(server_socket < 0) {
00225         cerr << "trackerd: error creating socket: " << strerror(errno) << "\n";
00226         exit(-1);
00227     }
00228 
00229     int one = 1;
00230     if(setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) {
00231         cerr << "trackerd: setting socket options: " << strerror(errno) << endl ; exit(-1);
00232     }
00233     struct sockaddr_in addr;
00234     memset(&addr, 0, sizeof(addr));
00235     addr.sin_addr.s_addr = htonl(INADDR_ANY);
00236     addr.sin_port = htons(port);
00237     addr.sin_family = AF_INET;
00238     if(bind(server_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
00239         cerr << "trackerd: error binding address with port "  << port << ": " << strerror(errno) << endl;
00240         exit(-1);
00241     }
00242     if( listen(server_socket, 5) < 0) {
00243         cerr << "trackerd: error listening on socket: " << strerror(errno) << endl;
00244     } 
00245 
00246     cout << "trackerd: ok. running...\n";
00247 
00248     char buff[8];
00249     memset(buff, 0, sizeof(buff));
00250     char output[128];
00251     memset(output, 0, sizeof(output));
00252     double mat[3][3];
00253     double y, p, r, px, py, pz;
00254     int n;
00255     set<int> client_sockets;
00256     fd_set rfds;
00257     fd_set wfds;
00258     int max;
00259 
00260     // do an initial read and save time
00261     if(ori) {
00262         try {
00263             ori->getOrientationMatrix(mat);
00264             ori->getEulerAngles(&y, &p, &r);
00265             last_ori_read = currentTime();
00266         } catch(exception& e) {
00267             cerr << "trackerd: Warning: error reading initial values from orientation device.\n";
00268         }
00269     } 
00270     if(pos) {
00271         try {
00272             pos->getPosition(&px, &py, &pz);
00273             last_pos_read = currentTime();
00274         } catch(exception& e) {
00275             cerr << "trackerd: Warning: error reading initial values from position device.\n";
00276         }
00277     }
00278 
00279     while(1) {
00280 
00281         /* Check for activity on sockets */
00282         FD_ZERO(&rfds);
00283         FD_ZERO(&wfds);
00284         FD_SET(server_socket, &rfds);
00285         max = server_socket;
00286         for(set<int>::const_iterator i = client_sockets.begin();
00287                                     i != client_sockets.end(); i++) {
00288             FD_SET(*i, &rfds);
00289             FD_SET(*i, &wfds);
00290             if(*i > max) max = *i;
00291         }
00292         if(select(max+1, &rfds, &wfds, NULL, NULL)) {
00293 
00294             /* Accept new connections? */
00295             if( FD_ISSET(server_socket, &rfds) ) {
00296                 int s = accept(server_socket, NULL, 0);
00297                 if(s == -1) {
00298                     cerr << "trackerd: warning: error accepting client: " << strerror(errno) << "\n"; 
00299                     continue;
00300                 }
00301                 client_sockets.insert(s);
00302             }
00303 
00304             /* Check clients for data */
00305             for(set<int>::const_iterator i = client_sockets.begin();
00306                                     i != client_sockets.end(); i++) {
00307                 if( FD_ISSET(*i, &rfds) && FD_ISSET(*i, &wfds) ) {
00308                     int fd = *i;
00309 
00310                     memset(buff, 0, sizeof(buff));
00311                     n = read( fd, buff, sizeof(buff) - 1);
00312                     //XXX if there's more than 8 bytes on the socket, flush them?
00313                     if(n > 0) {
00314                         // remove last char if it's a newline
00315                         if( buff[n-1] == '\n' ) 
00316                             buff[n-1] = '\0';
00317                         // check input and construct output
00318                         if(!strcmp(buff, "om:0")) {
00319                             if(ori) {
00320                                 try {
00321                                     double now =  currentTime();
00322                                     if(now - last_ori_read > ori_freq) {
00323                                         ori->getOrientationMatrix(mat);
00324                                         last_ori_read = now;
00325                                     }
00326                                     snprintf(output, sizeof(output), "om:0=%.8f,%.8f,%.8f;%.8f,%.8f,%.8f;%.8f,%.8f,%.8f\n",
00327                                           mat[0][0], mat[0][1], mat[0][2],
00328                                           mat[1][0], mat[1][1], mat[1][2],
00329                                           mat[2][0], mat[2][1], mat[2][2]);
00330                                 } catch(exception& e) {
00331                                     snprintf(output, sizeof(output), "om:0=ERROR:Error reading device: %s\n", e.what());
00332                                 }
00333                             } else {
00334                                 snprintf(output, sizeof(output), "om:0=ERROR:No device\n");
00335                             }
00336                         } else if(!strcmp(buff, "oa:0")) {
00337                             if(ori) {
00338                                 try {
00339                                     double now =  currentTime();
00340                                     if(now - last_ori_read > ori_freq) {
00341                                         ori->getEulerAngles(&y, &p, &r);
00342                                         last_ori_read = now;
00343                                     }
00344                                     snprintf(output, sizeof(output), "oa:0=%.8f,%.8f,%.8f\n", y, p, r);
00345                                 } catch(exception& e) {
00346                                     snprintf(output, sizeof(output), "oa:0=ERROR:Error reading device: %s\n", e.what());
00347                                 }
00348                             } else {
00349                                 snprintf(output, sizeof(output), "oa:0=ERROR:No device\n");
00350                             }
00351                         } else if(!strcmp(buff, "p:0")) {
00352                             if(pos) {
00353                                 try {
00354                                     double now = currentTime();
00355                                     if(now - last_pos_read > pos_freq) {
00356                                         pos->getPosition(&px, &py, &pz);
00357                                         last_pos_read = now;
00358                                     }
00359                                     snprintf(output, sizeof(output), "p:0=%.8f,%.8f,%.8f\n", px, py, pz);
00360                                 } catch(exception& e) {
00361                                     snprintf(output, sizeof(output), "p:0=ERROR:Error reading device: %s\n", e.what());
00362                                 }
00363                             } else {
00364                                 snprintf(output, sizeof(output), "p:0=ERROR:No device\n");
00365                             }
00366                         } else {
00367                             snprintf(output, sizeof(output), "%s=ERROR:Unknown command\n", buff);
00368                         }
00369 
00370                         write(fd, output, strlen(output));
00371 
00372                     } else if(n == 0) {   // socket it closed?
00373             //            fprintf(stderr, "closing socket %d",  fd);
00374                         close(fd);
00375                         client_sockets.erase(fd);
00376                     } else {
00377                         fprintf(stderr, "trackerd: Error reading from fd %d.  closing socket.", fd);
00378                         close(fd);
00379                         client_sockets.erase(fd);
00380                     }// if read
00381                 } // if FD_SET
00382             } // for each client_socket
00383         } //if select
00384     } // while(1)
00385 } // main

Generated on Tue Aug 12 03:55:38 2003 for Interreality Project - VOS by doxygen 1.3.2