diff --git a/robots/primotion/garcia-pilot.cc b/robots/primotion/garcia-pilot.cc index caf437243a49317bc65cea4fbc424db03ca1c1cf..e45cba2d415b0cf6b7a3f944d374cbe43a797b5f 100644 --- a/robots/primotion/garcia-pilot.cc +++ b/robots/primotion/garcia-pilot.cc @@ -49,6 +49,14 @@ static const char *DEFAULT_LOG_PATH = "/tmp/garcia-pilot.log"; */ static const char *BATTERY_LOG_PATH = "/var/log/battery.log"; + +/** + * Default file to read in state data + */ +static const char *DEFAULT_SFILE = "sdata.txt"; + + + /** * Determines whether or not to continue in the main loop. * @@ -68,11 +76,11 @@ static void sigquit(int sig) static int quit_count = 3; if (quit_count == 0) { - static char *msg = "error: wedged, aborting...\n"; - - write(2, msg, strlen(msg)); + static char *msg = "error: wedged, aborting...\n"; + + write(2, msg, strlen(msg)); - abort(); + abort(); } looping = 0; @@ -87,9 +95,9 @@ static void sigquit(int sig) static void sigdebug(int sig) { if (debug == 3) - debug = 1; + debug = 1; else - debug = 3; + debug = 3; } /** @@ -119,96 +127,102 @@ static void sigpanic(int signum) static void usage(void) { fprintf(stderr, - "usage: garcia-pilot -hd [-l logfile] [-i pidfile] [-p port]\n" - " [-b battery-log]\n" - "Options:\n" - " -h\t\tPrint this message\n" - " -d\t\tTurn on debugging messages and do not daemonize\n" - " -l logfile\tSend log output to the given file\n" - " -i pidfile\tWrite the process ID to the given file\n" - " -p port\tListen on the given port for MTP messages\n" - " -b battery-log\tAppend battery log data to the given file\n" - " \t\t(Default: %s)\n", - BATTERY_LOG_PATH); + "usage: garcia-pilot -hd [-l logfile] [-i pidfile] [-p port]\n" + " [-b battery-log]\n" + "Options:\n" + " -h\t\tPrint this message\n" + " -d\t\tTurn on debugging messages and do not daemonize\n" + " -o\t\tOpen loop path demo\n" + " -l logfile\tSend log output to the given file\n" + " -i pidfile\tWrite the process ID to the given file\n" + " -p port\tListen on the given port for MTP messages\n" + " -b battery-log\tAppend battery log data to the given file\n" + " \t\t(Default: %s)\n", + BATTERY_LOG_PATH); } int main(int argc, char *argv[]) { - int c, port = PILOT_PORT, serv_sock, on_off = 1; + int c, port = PILOT_PORT, serv_sock, on_off = 1, ol_demo = 0; const char *logfile = NULL, *pidfile = NULL; const char *batteryfile = BATTERY_LOG_PATH; + const char *sfile = DEFAULT_SFILE; int retval = EXIT_SUCCESS; unsigned long now; FILE *batterylog; + FILE *sdata_in; aIOLib ioRef; aErr err; - while ((c = getopt(argc, argv, "hdp:l:i:b:")) != -1) { - switch (c) { - case 'h': - usage(); - exit(0); - break; - case 'd': - debug += 1; - break; - case 'l': - logfile = optarg; - break; - case 'i': - pidfile = optarg; - break; - case 'p': - if (sscanf(optarg, "%d", &port) != 1) { - fprintf(stderr, - "error: -p option is not a number: %s\n", - optarg); - usage(); - exit(1); - } - break; - case 'b': - batteryfile = optarg; - break; - } + while ((c = getopt(argc, argv, "hdop:l:i:b:")) != -1) { + switch (c) { + case 'h': + usage(); + exit(0); + break; + case 'd': + debug += 1; + break; + case 'o': + ol_demo = 1; + break; + case 'l': + logfile = optarg; + break; + case 'i': + pidfile = optarg; + break; + case 'p': + if (sscanf(optarg, "%d", &port) != 1) { + fprintf(stderr, + "error: -p option is not a number: %s\n", + optarg); + usage(); + exit(1); + } + break; + case 'b': + batteryfile = optarg; + break; + } } #if 0 if (getuid() != 0) { - fprintf(stderr, "error: must run as root!\n"); - exit(1); + fprintf(stderr, "error: must run as root!\n"); + exit(1); } #endif if (!debug) { - /* Become a daemon */ - daemon(1, 0); + /* Become a daemon */ + daemon(1, 0); } if (logfile) { - int logfd; - - if ((logfd = open(logfile, O_CREAT|O_WRONLY|O_APPEND, 0644)) != -1) { - dup2(logfd, 1); - dup2(logfd, 2); - if (logfd > 2) - close(logfd); - } + int logfd; + + if ((logfd = open(logfile, O_CREAT|O_WRONLY|O_APPEND, 0644)) != -1) { + dup2(logfd, 1); + dup2(logfd, 2); + if (logfd > 2) + close(logfd); + } } if (pidfile) { - FILE *fp; - - if ((fp = fopen(pidfile, "w")) != NULL) { - (void) fclose(fp); - } + FILE *fp; + + if ((fp = fopen(pidfile, "w")) != NULL) { + (void) fclose(fp); + } } if ((batterylog = fopen(batteryfile, "a")) == NULL) { - fprintf(stderr, - "error: cannot open battery log file - %s\n", - batteryfile); - exit(1); + fprintf(stderr, + "error: cannot open battery log file - %s\n", + batteryfile); + exit(1); } acpGarcia garcia; @@ -227,197 +241,303 @@ int main(int argc, char *argv[]) aIO_GetLibRef(&ioRef, &err); if (!wait_for_brainstem_link(ioRef, garcia)) { - fprintf(stderr, - "error: could not connect to robot %d\n", - garcia.getNamedValue("status")->getIntVal()); - exit(1); + fprintf(stderr, + "error: could not connect to robot %d\n", + garcia.getNamedValue("status")->getIntVal()); + exit(1); } else { - struct sockaddr_in saddr; - acpValue av; - - if (debug) { - fprintf(stderr, "debug: connected to brainstem\n"); - } - - /* Make sure the units used by the robot are what we expect. */ - av.set("radians"); - garcia.setNamedValue("angle-units-string", &av); - - av.set("meters"); - garcia.setNamedValue("distance-units-string", &av); - - /* turn off fall sensors */ - av.set(0); - garcia.setNamedValue("down-ranger-enable", &av); - - memset(&saddr, 0, sizeof(saddr)); + struct sockaddr_in saddr; + acpValue av; + + if (debug) { + fprintf(stderr, "debug: connected to brainstem\n"); + } + + /* Make sure the units used by the robot are what we expect. */ + av.set("radians"); + garcia.setNamedValue("angle-units-string", &av); + + av.set("meters"); + garcia.setNamedValue("distance-units-string", &av); + + /* turn off fall sensors */ + av.set(0); + garcia.setNamedValue("down-ranger-enable", &av); + + + + if (1 == ol_demo) { + /* open loop demonstration mode */ + + float e_in = 0.0f, alpha_in = 0.0f, theta_in = 0.0f; /* states */ + float C_u, C_omega; /* controller outputs */ + + /* controller parameters: */ + float K_gamma = 1.0f, K_h = 1.0f, K_k = 1.0f; + + float K_radius = 0.0889f; + float vleft, vright; + acpValue av_L; + acpValue av_R; + + acpObject *nullb; + + int lcount = 0; + + + + if ((sdata_in = fopen(sfile, "r")) == NULL) { + fprintf(stderr, + "FATAL: Error opening state input file: %s\n", + sfile); + exit(1); + } + + nullb = garcia.createNamedBehavior("null", NULL); + av.set(0.2f); + nullb->setNamedValue("acceleration", &av); + + garcia.queueBehavior(nullb); + + + /* read states (e,alpha,theta) in from file: */ + /* These states will come from the RMCD/EMCD in the future */ + while (3 == fscanf(sdata_in, "%f %f %f\n", &e_in, &alpha_in, &theta_in)) { + + lcount++; + + /* controller: */ + C_u = 0.8 * tanh(K_gamma * cos(alpha_in) * e_in); + + if (0 == alpha_in) { + C_omega = 0.0f; + } + else { + C_omega = K_k * alpha_in + K_gamma * ((cos(alpha_in)*sin(alpha_in)) / alpha_in) * (alpha_in + K_h * theta_in); + + if (C_omega > 26.25f) { + C_omega = 26.25f; + } + if (C_omega < -26.25f) { + C_omega = -26.25f; + } + } + /* end controller */ + + /* wheel velocity translator: */ + vleft = C_u - K_radius * C_omega; + vright = C_u + K_radius * C_omega; + /* end wheel velocity translator */ + + + av_L.set(vleft); + av_R.set(vright); + + garcia.setNamedValue("damped-speed-left", &av_L); + garcia.setNamedValue("damped-speed-right", &av_R); + + vleft = garcia.getNamedValue("damped-speed-left")->getFloatVal(); + vright = garcia.getNamedValue("damped-speed-right")->getFloatVal(); + + if (debug) { + fprintf(stderr, "L/R velocities: %f %f\n", vleft, vright); + } + + + /* wait 0.033 (1/30) seconds */ + garcia.handleCallbacks(33); + + } + if (debug) { + fprintf(stderr, "Done with file: read %d lines\n", lcount); + } + + /* abort the null primitive: */ + av.set(aGARCIA_ERRFLAG_ABORT); + garcia.setNamedValue("status", &av); + + + if (sdata_in != NULL) { + fclose(sdata_in); + sdata_in = NULL; + } + + + + } + else { + /* normal mode */ + + + memset(&saddr, 0, sizeof(saddr)); #if !defined(linux) - saddr.sin_len = sizeof(saddr); + saddr.sin_len = sizeof(saddr); #endif - saddr.sin_family = AF_INET; - saddr.sin_port = htons(port); - saddr.sin_addr.s_addr = INADDR_ANY; - - if ((serv_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - perror("socket"); - } - else if (setsockopt(serv_sock, - SOL_SOCKET, - SO_REUSEADDR, - &on_off, - sizeof(on_off)) == -1) { - perror("setsockopt"); - } - else if (bind(serv_sock, - (struct sockaddr *)&saddr, - sizeof(saddr)) == -1) { - perror("bind"); - } - else if (listen(serv_sock, 5) == -1) { - perror("listen"); - } - else { - int rmc_telemetry_timeout = 60; - pilotClient::list clients; - fd_set readfds, writefds; - - dashboard db(garcia, batterylog); - wheelManager wm(garcia); - pilotButtonCallback pbc(db, wm); - - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_SET(serv_sock, &readfds); - - wm.setDashboard(&db); - do { - fd_set rreadyfds = readfds, wreadyfds = writefds; - struct timeval tv_zero = { 0, 0 }; - int rc; - - /* Poll the file descriptors, don't block */ - rc = select(FD_SETSIZE, - &rreadyfds, - &wreadyfds, - NULL, - &tv_zero); - if (rc > 0) { - bool do_telem = db.wasTelemetryUpdated(); - pilotClient::iterator i, j; - struct mtp_packet tmp; - - if (FD_ISSET(serv_sock, &rreadyfds)) { - struct sockaddr_in peer_sin; - socklen_t slen; - int cfd; - - slen = sizeof(peer_sin); - if ((cfd = accept(serv_sock, - (struct sockaddr *)&peer_sin, - &slen)) == -1) { - perror("accept"); - } - else { - pilotClient *pc = new pilotClient(cfd, wm, db); - - if (debug) { - fprintf(stderr, - "debug: connect from %s:%d\n", - inet_ntoa(peer_sin.sin_addr), - ntohs(peer_sin.sin_port)); - } - - pc->setFD(&readfds); - pc->setFD(&writefds); - clients.push_back(pc); - } - } - - if (do_telem) { - mtp_init_packet(&tmp, - MA_Opcode, MTP_TELEMETRY, - MA_Role, MTP_ROLE_RMC, - MA_GarciaTelemetry, db.getTelemetry(), - MA_TAG_DONE); - - if (pilotClient::pc_rmc_client != NULL) { - rmc_telemetry_timeout -= 1; - if (rmc_telemetry_timeout <= 0) { - pilotClient *pc = pilotClient::pc_rmc_client; - - rmc_telemetry_timeout = 60; - if (mtp_send_packet(pc->getHandle(), &tmp) != - MTP_PP_SUCCESS) { - fprintf(stderr, - "error: cannot send telemetry to " - "rmcd\n"); - } - } - } - } - - for (i = clients.begin(); i != clients.end(); ) { - bool bad_client = false; - pilotClient *pc = *i; - - j = i++; - if (pc->isFDSet(&rreadyfds)) { - do { - struct mtp_packet mp; - - if ((mtp_receive_packet(pc->getHandle(), - &mp) != - MTP_PP_SUCCESS) || - !pc->handlePacket(&mp, clients)) { - bad_client = true; - } - - mtp_free_packet(&mp); - } while (pc && pc->getHandle()->mh_remaining); - } - - if (!bad_client && - (pc->getRole() == MTP_ROLE_EMULAB) && - pc->isFDSet(&wreadyfds)) { - if (do_telem && - mtp_send_packet(pc->getHandle(), &tmp) != - MTP_PP_SUCCESS) { - fprintf(stderr, - "error: cannot send telemetry to " - "client\n"); - - bad_client = true; - } - } - - if (bad_client) { - clients.erase(j); - - pc->clearFD(&readfds); - pc->clearFD(&writefds); - - delete pc; - pc = NULL; - } - } - } - - garcia.handleCallbacks(50); - aIO_GetMSTicks(ioRef, &now, NULL); - } while (looping && db.update(now)); - - garcia.flushQueuedBehaviors(); - - garcia.handleCallbacks(1000); - } + saddr.sin_family = AF_INET; + saddr.sin_port = htons(port); + saddr.sin_addr.s_addr = INADDR_ANY; + + if ((serv_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + perror("socket"); + } + else if (setsockopt(serv_sock, + SOL_SOCKET, + SO_REUSEADDR, + &on_off, + sizeof(on_off)) == -1) { + perror("setsockopt"); + } + else if (bind(serv_sock, + (struct sockaddr *)&saddr, + sizeof(saddr)) == -1) { + perror("bind"); + } + else if (listen(serv_sock, 5) == -1) { + perror("listen"); + } + else { + int rmc_telemetry_timeout = 60; + pilotClient::list clients; + fd_set readfds, writefds; + + dashboard db(garcia, batterylog); + wheelManager wm(garcia); + pilotButtonCallback pbc(db, wm); + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_SET(serv_sock, &readfds); + + wm.setDashboard(&db); + do { + fd_set rreadyfds = readfds, wreadyfds = writefds; + struct timeval tv_zero = { 0, 0 }; + int rc; + + /* Poll the file descriptors, don't block */ + rc = select(FD_SETSIZE, + &rreadyfds, + &wreadyfds, + NULL, + &tv_zero); + if (rc > 0) { + bool do_telem = db.wasTelemetryUpdated(); + pilotClient::iterator i, j; + struct mtp_packet tmp; + + if (FD_ISSET(serv_sock, &rreadyfds)) { + struct sockaddr_in peer_sin; + socklen_t slen; + int cfd; + + slen = sizeof(peer_sin); + if ((cfd = accept(serv_sock, + (struct sockaddr *)&peer_sin, + &slen)) == -1) { + perror("accept"); + } + else { + pilotClient *pc = new pilotClient(cfd, wm, db); + + if (debug) { + fprintf(stderr, + "debug: connect from %s:%d\n", + inet_ntoa(peer_sin.sin_addr), + ntohs(peer_sin.sin_port)); + } + + pc->setFD(&readfds); + pc->setFD(&writefds); + clients.push_back(pc); + } + } + + if (do_telem) { + mtp_init_packet(&tmp, + MA_Opcode, MTP_TELEMETRY, + MA_Role, MTP_ROLE_RMC, + MA_GarciaTelemetry, db.getTelemetry(), + MA_TAG_DONE); + + if (pilotClient::pc_rmc_client != NULL) { + rmc_telemetry_timeout -= 1; + if (rmc_telemetry_timeout <= 0) { + pilotClient *pc = pilotClient::pc_rmc_client; + + rmc_telemetry_timeout = 60; + if (mtp_send_packet(pc->getHandle(), &tmp) != + MTP_PP_SUCCESS) { + fprintf(stderr, + "error: cannot send telemetry to " + "rmcd\n"); + } + } + } + } + + for (i = clients.begin(); i != clients.end(); ) { + bool bad_client = false; + pilotClient *pc = *i; + + j = i++; + if (pc->isFDSet(&rreadyfds)) { + do { + struct mtp_packet mp; + + if ((mtp_receive_packet(pc->getHandle(), + &mp) != + MTP_PP_SUCCESS) || + !pc->handlePacket(&mp, clients)) { + bad_client = true; + } + + mtp_free_packet(&mp); + } while (pc && pc->getHandle()->mh_remaining); + } + + if (!bad_client && + (pc->getRole() == MTP_ROLE_EMULAB) && + pc->isFDSet(&wreadyfds)) { + if (do_telem && + mtp_send_packet(pc->getHandle(), &tmp) != + MTP_PP_SUCCESS) { + fprintf(stderr, + "error: cannot send telemetry to " + "client\n"); + + bad_client = true; + } + } + + if (bad_client) { + clients.erase(j); + + pc->clearFD(&readfds); + pc->clearFD(&writefds); + + delete pc; + pc = NULL; + } + } + } + + garcia.handleCallbacks(50); + aIO_GetMSTicks(ioRef, &now, NULL); + } while (looping && db.update(now)); + + garcia.flushQueuedBehaviors(); + + garcia.handleCallbacks(1000); + } + } } aIO_ReleaseLibRef(ioRef, &err); if (batterylog != NULL) { - fclose(batterylog); - batterylog = NULL; + fclose(batterylog); + batterylog = NULL; } return retval;