00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <iostream>
00023 #include <iomanip>
00024 #include <cstring>
00025 #include <cstdlib>
00026 #include <cstdio>
00027 #include <cstdarg>
00028 #include <unistd.h>
00029 #include <netdb.h>
00030 #include <limits.h>
00031 #include <sys/time.h>
00032 #include <sys/types.h>
00033 #include <sys/socket.h>
00034 #include <sys/un.h>
00035 #include <arpa/inet.h>
00036 #include <netinet/tcp.h>
00037 #include <pthread.h>
00038 #include <signal.h>
00039 #include "config.h"
00040 #include "images.h"
00041 #include <Platform.h>
00042 #define USARSIM
00043 #include <Primitives.h>
00044 #include <OPENR/ODataFormats.h>
00045
00046 #define CHECK_SYSCALL(val, msg) if ((val) < 0) { perror(msg); exit(4); }
00047
00048 using namespace std;
00049
00050 enum team_type {
00051 NO_TEAM,
00052 TEAM_BLUE,
00053 TEAM_RED
00054 };
00055
00056 static team_type team = DEFAULT_USARSIM_ROBOT_TEAM;
00057 static const char *usarsim_host = DEFAULT_USARSIM_HOST;
00058 static short usarsim_port = DEFAULT_USARSIM_PORT;
00059 static short usarsim_imgserver_port = DEFAULT_USARSIM_IMGSERVER_PORT;
00060 static const char *usarsim_robot = DEFAULT_USARSIM_ROBOT;
00061 static const char *usarsim_location = DEFAULT_USARSIM_LOCATION;
00062 static const char *usarsim_ball_location = DEFAULT_USARSIM_BALL_LOCATION;
00063 static bool display_fps = DEFAULT_DISPLAY_IMAGE_FPS;
00064
00065 static int usarsim_socket;
00066 static int usarsim_ball_socket;
00067 static FILE *usarsim_imgserver_socket;
00068 static int actuators_socket;
00069 static FILE *sensors_socket;
00070
00071 static double joint_values[num_of_primitives] = {INT_MIN};
00072
00073
00075 static const char* team_str(void)
00076 {
00077 switch (team) {
00078 case NO_TEAM: return "NO_TEAM";
00079 case TEAM_BLUE: return "BLUE";
00080 case TEAM_RED: return "RED";
00081 }
00082
00083 return NULL;
00084 }
00085
00086
00088 static bool connect_to_usarsim(int *sock, int port = usarsim_port, bool read_init_msg = true)
00089 {
00090 char buffer[BUFFER_SIZE];
00091 struct sockaddr_in addr;
00092 struct hostent *h = gethostbyname(usarsim_host);
00093
00094 if (!h) {
00095 cerr << "Could not resolve the USARSim host: '" << usarsim_host << "'" << endl;
00096 return false;
00097 }
00098
00099 memset(&addr, 0, sizeof(struct sockaddr_in));
00100 memcpy(&addr.sin_addr, h->h_addr, h->h_length);
00101 addr.sin_family = AF_INET;
00102 addr.sin_port = htons(port);
00103
00104 *sock = socket(AF_INET, SOCK_STREAM, 0);
00105 if (*sock < 0) {
00106 perror("couldn't create a new socket");
00107 return false;
00108 }
00109
00110 if (connect(*sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
00111 perror("error connecting to USARSim server");
00112 close(*sock);
00113 return false;
00114 }
00115
00116
00117 if (read_init_msg) {
00118 ssize_t ret = read(*sock, buffer, sizeof(buffer));
00119 if (ret <= 0) {
00120 cerr << "error reading the initial message from the USARSim server" << endl;
00121 close(*sock);
00122 return false;
00123 }
00124
00125 fwrite(buffer, ret, 1, stdout);
00126 }
00127
00128 #if defined(TCP_NODELAY) && defined(IPPROTO_TCP)
00129
00130 const int opt = 1;
00131 if (setsockopt(*sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
00132 perror("could not set TCP_NODELAY");
00133 }
00134 #endif
00135
00136 return true;
00137 }
00138
00139
00141 static int connect_to_opensdk_sensor(const char *MSdir, const char *socket_name)
00142 {
00143 char filename[PATH_MAX];
00144 snprintf(filename, sizeof(filename), "%s/%s", MSdir, socket_name);
00145
00146 struct sockaddr_un addr;
00147 addr.sun_family = AF_UNIX;
00148 strcpy(addr.sun_path, filename);
00149
00150 int s = socket(AF_UNIX, SOCK_STREAM, 0);
00151
00152 for (int i=0; i < 1000; ++i) {
00153 if (connect(s, (const sockaddr*)&addr, sizeof(addr)) < 0) {
00154 opensdk_yield();
00155 continue;
00156 }
00157 goto ok;
00158 }
00159
00160 perror("Couldn't connect to the openSDK sensor server socket");
00161
00162 ok:
00163 return s;
00164 }
00165
00166
00168 static int connect_to_opensdk_actuator(const char *MSdir)
00169 {
00170 char filename[PATH_MAX];
00171 snprintf(filename, sizeof(filename), "%s/" ACTUATORS_SERVER_SOCKET, MSdir);
00172
00173 struct sockaddr_un addr;
00174 socklen_t sizeof_addr = sizeof(addr);
00175 addr.sun_family = AF_UNIX;
00176 strcpy(addr.sun_path, filename);
00177
00178 int s = socket(AF_UNIX, SOCK_STREAM, 0);
00179 int sock;
00180
00181 unlink(filename);
00182 CHECK_SYSCALL(bind(s, (const struct sockaddr*)&addr, sizeof(addr)), "bind() failed")
00183 CHECK_SYSCALL(listen(s, 1), "listen() failed")
00184 CHECK_SYSCALL(sock = accept(s, (struct sockaddr*)&addr, &sizeof_addr), "accept() failed")
00185
00186 close(s);
00187 return sock;
00188 }
00189
00190
00192 static void send_usarsim(int sock, const char *format, ...) PRINTF_FORMAT;
00193 static void send_usarsim(int sock, const char *format, ...)
00194 {
00195 va_list ap;
00196 char buffer[BUFFER_SIZE];
00197 int bufsize;
00198
00199 va_start(ap, format);
00200 bufsize = vsprintf(buffer, format, ap);
00201 va_end(ap);
00202
00203 if (DEBUG_USARSIM_PROTOCOL) {
00204 cout << "[->USARSim] " << buffer;
00205 }
00206
00207 if (write(sock, buffer, bufsize) < 0) {
00208 perror("error writing to the USARSim socket");
00209 exit(0x31);
00210 }
00211 }
00212
00213
00215 static void* read_usarsim_messages(void*)
00216 {
00217 char buffer[BUFFER_SIZE];
00218 FILE *fp = fdopen(usarsim_socket, "r");
00219
00220 while (true) {
00221 if (!fgets(buffer, sizeof(buffer), fp)) {
00222 cerr << "error reading from USARSim socket" << endl;
00223 exit(0xdd);
00224 }
00225
00226 if (!strncmp(buffer, "STA ", sizeof("STA ")-1)) {
00227
00228
00229 continue;
00230 }
00231
00232 if (DEBUG_USARSIM_PROTOCOL) {
00233 buffer[strlen(buffer)-1] = '\0';
00234 cout << "[<-USARSim] " << buffer << endl;
00235 }
00236
00237 if (!strncmp(buffer, "SEN ", sizeof("SEN ")-1)) {
00238
00239 char *msg = buffer + sizeof("SEN ")-1;
00240
00241 if (!strncmp("{Type IR} ", msg, sizeof("{Type IR} ")-1)) {
00242 msg += sizeof("{Type IR} ")-1;
00243 double IRN, IRF, EDG;
00244 if (sscanf(msg, "{Name IRN Range %lf} {Name IRF Range %lf} {Name EDG Range %lf}", &IRN, &IRF, &EDG) != 3) {
00245 goto sensors_error;
00246 }
00247
00248 fprintf(sensors_socket, "IRN:%lf\nIRF:%lf\nEDG:%lf\n", IRN, IRF, EDG);
00249 fflush(sensors_socket);
00250
00251 } else if (!strncmp("{Type Accel} ", msg, sizeof("{Type Accel} ")-1)) {
00252 msg += sizeof("{Type Accel} ")-1;
00253 double ax, ay, az;
00254 if (sscanf(msg, "{Name ACC} {Acceleration %lf,%lf,%lf}", &ax, &ay, &az) != 3) {
00255 goto sensors_error;
00256 }
00257
00258 fprintf(sensors_socket, "AX:%lf\nAY:%lf\nAZ:%lf\n", ax, ay, az);
00259 fflush(sensors_socket);
00260
00261 } else if (!strncmp("{Type Helper}", msg, sizeof("{Type Helper}")-1)) {
00262 continue;
00263
00264 } else {
00265 sensors_error:
00266 cerr << "bogus sensor readings message received from USARSim: '" << msg << "'" << endl;
00267 }
00268
00269 } else {
00270 cerr << "bogus message received: '" << buffer << "'" << endl;
00271 }
00272 }
00273
00274 return NULL;
00275 }
00276
00277
00279 static void* read_usarsim_images(void *MSdir)
00280 {
00281
00282 int img_socket = connect_to_opensdk_sensor((const char*)MSdir, IMAGE_SERVER_SOCKET);
00283 FILE *opensdk_socket = fdopen(img_socket, "w");
00284 if (!opensdk_socket) {
00285 exit(0x08);
00286 }
00287
00288 if (connect_to_usarsim(&img_socket, usarsim_imgserver_port, false)) {
00289 usarsim_imgserver_socket = fdopen(img_socket, "r+");
00290 if (!usarsim_imgserver_socket) {
00291 exit(0x43);
00292 }
00293
00294 } else {
00295 cout << "Not connected to USARSim image server" << endl;
00296 return NULL;
00297 }
00298
00299
00300 unsigned char buffer[IMG_SIZE], newimg[IMG_SIZE];
00301
00302 byte *Y = newimg;
00303 byte *Cb = newimg+(IMG_SIZE*2/3);
00304 byte *Cr = newimg+IMG_SIZE/3;
00305
00306 struct timeval last_tv = {0};
00307 unsigned int num_of_images = 0;
00308
00309 while (true) {
00310 if (fread(buffer, 1, 1, usarsim_imgserver_socket) != 1) {
00311 cerr << "error reading image type from USARSim" << endl;
00312 return NULL;
00313 }
00314
00315 if (*buffer != 0) {
00316 cerr << "Invalid image type received: " << (char)(*buffer + '0') << endl;
00317 return NULL;
00318 }
00319
00320 uint32_t size;
00321 uint16_t width, height;
00322
00323
00324 if (!fread(&size, 4, 1, usarsim_imgserver_socket) || !fread(&width, 2, 1, usarsim_imgserver_socket) || !fread(&height, 2, 1, usarsim_imgserver_socket)) {
00325 cerr << "error reading image info from USARSim" << endl;
00326 }
00327
00328 size = ntohl(size);
00329 width = ntohs(width);
00330 height = ntohs(height);
00331
00332 if (width != IMG_WIDTH || height != IMG_HEIGHT) {
00333 cerr << "the image received doesn't match the required dimensions (" << IMG_WIDTH << 'x' << IMG_HEIGHT <<
00334 "). received: " << width << 'x' << height << endl;
00335 return NULL;
00336 }
00337
00338 if (size-4 != IMG_SIZE) {
00339 cerr << "the image received doesn't match the required size (" << IMG_SIZE << "). received: " << size << endl;
00340 return NULL;
00341 }
00342
00343 if (!fread(buffer, IMG_SIZE, 1, usarsim_imgserver_socket)) {
00344 cerr << "error reading data from USARSim image server" << endl;
00345 return NULL;
00346 }
00347
00348
00349 if (display_fps) {
00350 struct timeval tv;
00351 gettimeofday(&tv, NULL);
00352
00353 ++num_of_images;
00354
00355 if (tv.tv_sec != last_tv.tv_sec) {
00356 float seconds = (tv.tv_sec + tv.tv_usec / 1000000.0) - (last_tv.tv_sec + last_tv.tv_usec / 1000000.0);
00357 float fps = num_of_images / seconds;
00358 cout << "\r" << fixed << setprecision(2) << fps << " fps" << flush;
00359 num_of_images = 0;
00360 last_tv = tv;
00361 }
00362 }
00363
00364
00365 RGB_to_YCbCr(buffer, IMG_WIDTH, IMG_HEIGHT, Y, Cb, Cr);
00366
00367 if (!fwrite(newimg, IMG_SIZE, 1, opensdk_socket)) {
00368 cerr << "error writing to openSDK image socket" << endl;
00369 return NULL;
00370 }
00371
00372 shrink_frame(IMG_WIDTH, IMG_HEIGHT, 2, Y, Cb, Cr, buffer, buffer+(IMG_SIZE/4*2/3), buffer+(IMG_SIZE/4/3));
00373
00374 if (!fwrite(buffer, IMG_SIZE/4, 1, opensdk_socket)) {
00375 cerr << "error writing to openSDK image socket" << endl;
00376 return NULL;
00377 }
00378
00379 shrink_frame(IMG_WIDTH, IMG_HEIGHT, 4, Y, Cb, Cr, buffer, buffer+(IMG_SIZE/16*2/3), buffer+(IMG_SIZE/16/3));
00380
00381 if (!fwrite(buffer, IMG_SIZE/16, 1, opensdk_socket)) {
00382 cerr << "error writing to openSDK image socket" << endl;
00383 return NULL;
00384 }
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 fwrite("OK", 2, 1, usarsim_imgserver_socket);
00395 }
00396
00397 return NULL;
00398 }
00399
00400
00402 static void read_opensdk_messages(void)
00403 {
00404 char buffer[BUFFER_SIZE];
00405 FILE *fp = fdopen(actuators_socket, "r");
00406
00407 while (true) {
00408 if (!fgets(buffer, sizeof(buffer), fp)) {
00409 cerr << "error reading from openSDK socket" << endl;
00410 exit(0x23);
00411 }
00412
00413 char *str = buffer;
00414 long primitiveId = strtol(str, &str, 10);
00415 double *table = &joint_values[primitiveId];
00416
00417 do {
00418 double val = strtod(str, &str);
00419 *table = val;
00420 } while (*str != '\n' && *str);
00421 }
00422 }
00423
00424
00425 static void sigalrm_handler(int)
00426 {
00427 char buffer[BUFFER_SIZE], *str = buffer + sizeof("MULTIDRIVE")-1;
00428 char buffer_opensdk[BUFFER_SIZE], *str_opensdk = buffer_opensdk;
00429 *str = '\0';
00430
00431 for (unsigned int i=0; i < num_of_primitives; ++i) {
00432 double val = joint_values[i];
00433 if (val != INT_MIN) {
00434 if (usarsim_primitives[i]) {
00435 str += sprintf(str, " {%s %lf}", usarsim_primitives[i], val);
00436 str_opensdk += sprintf(str_opensdk, "J%d:%lf\n", i, val);
00437 }
00438 joint_values[i] = INT_MIN;
00439 }
00440 }
00441
00442 if (*(buffer + sizeof("MULTIDRIVE")-1)) {
00443 memcpy(buffer, "MULTIDRIVE", sizeof("MULTIDRIVE")-1);
00444 sprintf(str, "\r\n");
00445 send_usarsim(usarsim_socket, buffer);
00446 fwrite(buffer_opensdk, strlen(buffer_opensdk), 1, sensors_socket);
00447 fflush(sensors_socket);
00448 }
00449 }
00450
00451
00452 int main(int argc, char *argv[])
00453 {
00454 const char *MSdir = NULL;
00455
00456 while (--argc) {
00457 const char *arg = *++argv;
00458
00459 if (!strncmp(arg, "--team=", sizeof("--team=")-1)) {
00460 arg += sizeof("--team=")-1;
00461
00462 if (!strcasecmp(arg, "blue")) {
00463 team = TEAM_BLUE;
00464 } else if (!strcasecmp(arg, "red")) {
00465 team = TEAM_RED;
00466 } else if (!strcasecmp(arg, "no_team")) {
00467 team = NO_TEAM;
00468 } else {
00469 cerr << "Warning: team '" << arg << "' not supported!" << endl;
00470 }
00471
00472 } else if (!strncmp(arg, "--usarsim-host=", sizeof("--usarsim-host=")-1)) {
00473 usarsim_host = arg + sizeof("--usarsim-host=")-1;
00474
00475 } else if (!strncmp(arg, "--usarsim-port=", sizeof("--usarsim-port=")-1)) {
00476 usarsim_port = atoi(arg + sizeof("--usarsim-port=")-1);
00477
00478 } else if (!strncmp(arg, "--usarsim-robot=", sizeof("--usarsim-robot=")-1)) {
00479 usarsim_robot = arg + sizeof("--usarsim-robot=")-1;
00480
00481 } else if (!strncmp(arg, "--usarsim-location=", sizeof("--usarsim-location=")-1)) {
00482 usarsim_location = arg + sizeof("--usarsim-location=")-1;
00483
00484 } else if (!strncmp(arg, "--usarsim-ball=", sizeof("--usarsim-ball=")-1)) {
00485 usarsim_ball_location = arg + sizeof("--usarsim-ball=")-1;
00486
00487 } else if (!strncmp(arg, "--display-fps=", sizeof("--display-fps=")-1)) {
00488 display_fps = !strncmp(arg + sizeof("--display-fps=")-1, "yes", sizeof("yes")-1);
00489
00490 } else if (!strcmp(arg, "--help") || !strcmp(arg, "-h")) {
00491 cout << "./USARSimServer [options] <MS dir>" << endl << endl
00492 << "Available options:" << endl
00493 << "--team=TEAM\t\t\tTeam of the robot (either BLUE, RED or NO_TEAM). defaults to '" << team_str() << "'" << endl
00494 << "--usarsim-host=HOST\t\tHost of the USARSim server. defaults to '" << DEFAULT_USARSIM_HOST << "'" << endl
00495 << "--usarsim-port=PORT\t\tPort of the USARSim server. defaults to " << DEFAULT_USARSIM_PORT << endl
00496 << "--usarsim-robot=MODEL\t\tUSARSim Robot Model. defaults to '" << DEFAULT_USARSIM_ROBOT << "'" << endl
00497 << "--usarsim-location=X,Y,Z\tCoordinates of the start position. defaults to '" << DEFAULT_USARSIM_LOCATION << "'" << endl
00498 << "--usarsim-ball=[no|location]\tIf and where to place the ball. defaults to '" << DEFAULT_USARSIM_BALL_LOCATION << "'" << endl
00499 << "--display-fps=[no|yes]\t\tDisplay image FPS received from the image server. defaults to '" << (DEFAULT_DISPLAY_IMAGE_FPS ? "yes" : "no") << "'" << endl
00500 << endl;
00501 return 0;
00502
00503 } else if (argc == 1) {
00504 MSdir = arg;
00505
00506 } else {
00507 cerr << "option not recognised: '" << arg << "'" << endl;
00508 }
00509 }
00510
00511
00512 if (!MSdir) {
00513 cerr << "MS directory not set. exiting.." << endl;
00514 return 0x02;
00515 }
00516
00517 cout << "OpenSDK USARSim connector loading..." << endl;
00518
00519 actuators_socket = connect_to_opensdk_actuator(MSdir);
00520 int sensors_fd = connect_to_opensdk_sensor(MSdir, SENSORS_SERVER_SOCKET);
00521
00522 if (!connect_to_usarsim(&usarsim_socket)) {
00523 return 0x01;
00524 }
00525
00526 sensors_socket = fdopen(sensors_fd, "w");
00527 if (!sensors_socket) {
00528 return 0x04;
00529 }
00530
00531
00532 if (strcasecmp(usarsim_ball_location, "no")) {
00533 if (!connect_to_usarsim(&usarsim_ball_socket)) {
00534 return 0x02;
00535 }
00536
00537 send_usarsim(usarsim_ball_socket, "INIT {ClassName USARBot.SoccerBall} {Name Ball} {Location %s}\r\n", usarsim_ball_location);
00538 }
00539
00540 {
00541 char skin[64];
00542 if (team == NO_TEAM) {
00543 *skin = '\0';
00544 } else {
00545 sprintf(skin, "{Skin %s} ", team_str());
00546 }
00547
00548
00549 send_usarsim(usarsim_socket, "INIT {ClassName USARBot.%s} %s{Location %s}\r\n", usarsim_robot, skin, usarsim_location);
00550 }
00551
00552
00553 pthread_t thread;
00554 pthread_create(&thread, NULL, read_usarsim_messages, NULL);
00555
00556 {
00557 struct itimerval timer = {
00558 {0, 10}, {0, 10}
00559 };
00560 signal(SIGALRM, sigalrm_handler);
00561
00562 if (setitimer(ITIMER_REAL, &timer, NULL) < 0) {
00563 perror("setitimer() failed");
00564 return 0x41;
00565 }
00566 }
00567
00568 pthread_create(&thread, NULL, read_usarsim_images, (void*)MSdir);
00569
00570
00571
00572 read_opensdk_messages();
00573
00574 return 0;
00575 }