erratic.cc

00001 // -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:1; -*-
00002 
00171 // This must be first per pthread reference
00172 #include <pthread.h>
00173 
00174 #include <fcntl.h>
00175 #include <stdio.h>
00176 #include <unistd.h>
00177 #include <math.h>
00178 #include <termios.h>
00179 #include <stdlib.h> // for abs()
00180 
00181 #include "erratic.h"
00182 
00183 #ifdef HAVE_CONFIG_H
00184 #include "config.h"
00185 #endif
00186 
00187 bool debug_mode = FALSE;
00188 
00189 
00190 
00193 // These get the driver in where it belongs, loading
00194 Driver* Erratic_Init(ConfigFile* cf, int section) 
00195 {
00196   return (Driver*)(new Erratic(cf,section));
00197 }
00198 
00199 void Erratic_Register(DriverTable* table) 
00200 {
00201   table->AddDriver("erratic", Erratic_Init);
00202 }
00203 
00204 #if 0
00205 extern "C" {
00206   int player_driver_init(DriverTable* table)
00207   {
00208     Erratic_Register(table);
00209     #define QUOTEME(x) #x
00210     //#define DATE "##VIDERE_DATE##\"
00211     printf("  Erratic robot driver %s, build date %s\n", ERRATIC_VERSION, ERRATIC_DATE);
00212     return 0;
00213   }
00214 }
00215 #endif
00216 
00217 // Constructor of the driver from configuration entry
00218 Erratic::Erratic(ConfigFile* cf, int section) 
00219   : Driver(cf,section,true,PLAYER_MSGQUEUE_DEFAULT_MAXLEN) 
00220 {
00221   // zero ids, so that we'll know later which interfaces were requested
00222   memset(&this->position_id, 0, sizeof(player_devaddr_t));
00223   memset(&this->power_id, 0, sizeof(player_devaddr_t));
00224   memset(&this->aio_id, 0, sizeof(player_devaddr_t));
00225   memset(&this->sonar_id, 0, sizeof(player_devaddr_t));
00226   memset(&this->ptz_id, 0, sizeof(player_devaddr_t));
00227   memset(&this->ptz2_id, 0, sizeof(player_devaddr_t));
00228 
00229   memset(&this->last_position_cmd, 0, sizeof(player_position2d_cmd_vel_t));
00230   memset(&this->last_car_cmd, 0, sizeof(player_position2d_cmd_car_t));
00231 
00232   this->position_subscriptions = 0;
00233   this->aio_ir_subscriptions = 0;
00234   this->sonar_subscriptions = 0;
00235   this->ptz_subscriptions = 0;
00236   this->ptz2_subscriptions = 0;
00237 
00238   // intialise members
00239   motor_packet = NULL;
00240   mcount = 0;
00241   memset(&this->erratic_data,0,sizeof(this->erratic_data));
00242 
00243   // Do we create a robot position interface?
00244   if(cf->ReadDeviceAddr(&(this->position_id), section, "provides", PLAYER_POSITION2D_CODE, -1, NULL) == 0) {
00245     if(this->AddInterface(this->position_id) != 0) {
00246       this->SetError(-1);
00247       return;
00248     }
00249   }
00250 
00251   // Do we create a power interface?
00252   if(cf->ReadDeviceAddr(&(this->power_id), section, "provides", PLAYER_POWER_CODE, -1, NULL) == 0) {
00253     if(this->AddInterface(this->power_id) != 0) {
00254       this->SetError(-1);
00255       return;
00256     }
00257   }
00258   
00259   // Do we create a aio interface?
00260   if(cf->ReadDeviceAddr(&(this->aio_id), section, "provides", PLAYER_AIO_CODE, -1, NULL) == 0) {
00261     if(this->AddInterface(this->aio_id) != 0) {
00262       this->SetError(-1);
00263       return;
00264     }
00265   }
00266 
00267   // Do we create an ir interface?
00268   if(cf->ReadDeviceAddr(&(this->ir_id), section, "provides", PLAYER_IR_CODE, -1, NULL) == 0) {
00269     if(this->AddInterface(this->ir_id) != 0) {
00270       this->SetError(-1);
00271       return;
00272     }
00273   }
00274 
00275   // Do we create a sonar interface?
00276   if(cf->ReadDeviceAddr(&(this->sonar_id), section, "provides", PLAYER_SONAR_CODE, -1, NULL) == 0) {
00277     if(this->AddInterface(this->sonar_id) != 0) {
00278       this->SetError(-1);
00279       return;
00280     }
00281   }
00282 
00283   // Do we create a tilt-only ptz interface?
00284         // Must have a key of "tilt", e.g., "tilt:::ptz:1"
00285         // This device must be listed after the default PTZ device
00286   if(cf->ReadDeviceAddr(&(this->ptz2_id), section, "provides", PLAYER_PTZ_CODE, -1, "tilt") == 0) {
00287     if(this->AddInterface(this->ptz2_id) != 0) {
00288       this->SetError(-1);
00289       return;
00290     }
00291   }
00292 
00293   // Do we create a standard ptz interface?
00294         // NOTE: this interface has no key, it picks up the default PTZ device
00295         // MUST BE LISTED FIRST of all PTZ devices
00296   if(cf->ReadDeviceAddr(&(this->ptz_id), section, "provides", PLAYER_PTZ_CODE, -1, NULL) == 0) {
00297     if(this->AddInterface(this->ptz_id) != 0) {
00298       this->SetError(-1);
00299       return;
00300     }
00301   }
00302 
00303   // build the table of robot parameters.
00304   initialize_robot_params();
00305 
00306   // Read config file options
00307   this->psos_serial_port = cf->ReadString(section,"port",DEFAULT_VIDERE_PORT);
00308   this->direct_wheel_vel_control = cf->ReadInt(section, "direct_wheel_vel_control", 0);
00309   this->motor_max_speed = (int)rint(1e3 * cf->ReadLength(section, "max_trans_vel", MOTOR_DEF_MAX_SPEED));
00310   this->motor_max_turnspeed = (int)rint(RTOD(cf->ReadAngle(section, "max_rot_vel", MOTOR_DEF_MAX_TURNSPEED)));
00311   this->motor_max_trans_accel = (short)rint(1.0e3 * cf->ReadLength(section, "trans_acc", 0));
00312   this->motor_max_trans_decel = (short)rint(1.0e3 * cf->ReadLength(section, "trans_decel", 0));
00313   this->motor_max_rot_accel = (short)rint(RTOD(cf->ReadAngle(section, "rot_acc", 0)));
00314   this->motor_max_rot_decel = (short)rint(RTOD(cf->ReadAngle(section, "rot_decel", 0)));
00315 
00316   this->pid_trans_p = cf->ReadInt(section, "pid_trans_p", -1);
00317   this->pid_trans_v = cf->ReadInt(section, "pid_trans_v", -1);
00318   this->pid_trans_i = cf->ReadInt(section, "pid_trans_i", -1);
00319   this->pid_rot_p = cf->ReadInt(section, "pid_rot_p", -1);
00320   this->pid_rot_v = cf->ReadInt(section, "pid_rot_v", -1);
00321   this->pid_rot_i = cf->ReadInt(section, "pid_rot_i", -1);
00322 
00323   this->motor_pwm_frequency = cf->ReadInt(section, "motor_pwm_frequency", -1);
00324   this->motor_pwm_max_on = (uint16_t)(cf->ReadFloat(section, "motor_pwm_max_on", -1) * 1000.0);
00325 
00326   this->use_vel_band = 0;//cf->ReadInt(section, "use_vel_band", 0);
00327 
00328   this->print_all_packets = 0;
00329   this->print_status_summary = 1;
00330 
00331   debug_mode = cf->ReadInt(section, "debug", 0);
00332   save_settings_in_robot = cf->ReadInt(section, "save_settings_in_robot", 0);
00333 
00334   this->read_fd = -1;
00335   this->write_fd = -1;
00336   
00337   // Data mutexes and semaphores
00338   pthread_mutex_init(&send_queue_mutex, 0);
00339   pthread_cond_init(&send_queue_cond, 0);
00340   pthread_mutex_init(&motor_packet_mutex, 0);
00341   
00342   if (Connect()) 
00343     {
00344       printf("Error connecting to Erratic robot\n");
00345       exit(1);
00346     }
00347 }
00348 
00349 // Called by player when the driver is asked to connect
00350 int Erratic::Setup() {
00351   // We don't care, we connect at startup anyway
00352   return 0;
00353 }
00354 
00355 // Establishes connection and starts threads
00356 int Erratic::Connect() 
00357 {
00358   printf("  Erratic connection initializing (%s)...",this->psos_serial_port); fflush(stdout);
00359 
00360   //Try opening both our file descriptors
00361   if ((this->read_fd = open(this->psos_serial_port, O_RDONLY, S_IRUSR | S_IWUSR)) < 0) {
00362     perror("Erratic::Setup():open():");
00363     return(1);
00364   };
00365   if ((this->write_fd = open(this->psos_serial_port, O_WRONLY, S_IRUSR | S_IWUSR)) < 0) {
00366     perror("Erratic::Setup():open():");
00367     close(this->read_fd); this->read_fd = -1;
00368     return(1);
00369   }
00370 
00371   // Populate term and set initial baud rate
00372   int bauds[] = {B38400, B115200};
00373   int numbauds = sizeof(bauds), currbaud = 0;
00374   struct termios read_term, write_term;
00375   {
00376     if(tcgetattr( this->read_fd, &read_term ) < 0 ) {
00377       perror("Erratic::Setup():tcgetattr():");
00378       close(this->read_fd); close(this->write_fd);
00379       this->read_fd = -1; this->write_fd = -1;
00380       return(1);
00381     } 
00382     
00383     cfmakeraw(&read_term);
00384     //cfsetspeed(&read_term, bauds[currbaud]);
00385     cfsetispeed(&read_term, bauds[currbaud]);
00386     cfsetospeed(&read_term, bauds[currbaud]);
00387       
00388     if(tcsetattr(this->read_fd, TCSAFLUSH, &read_term ) < 0) {
00389       perror("Erratic::Setup():tcsetattr(read channel):");
00390       close(this->read_fd); close(this->write_fd);
00391       this->read_fd = -1; this->write_fd = -1;
00392       return(1);
00393     }
00394   }
00395   
00396   
00397   // Empty buffers 
00398   if (tcflush(this->read_fd, TCIOFLUSH ) < 0) {
00399     perror("Erratic::Setup():tcflush():");
00400     close(this->read_fd); close(this->write_fd);
00401     this->read_fd = -1; this->write_fd = -1;
00402     return(1);
00403   }
00404   if (tcflush(this->write_fd, TCIOFLUSH ) < 0) {
00405     perror("Erratic::Setup():tcflush():");
00406     close(this->read_fd); close(this->write_fd);
00407     this->read_fd = -1; this->write_fd = -1;
00408     return(1);
00409   }
00410   
00411   // will send config packets until a response is gotten
00412   int num_sync_attempts = 10;
00413   int num_patience = 200;
00414   int failed = 0;
00415   enum { NO_SYNC, AFTER_FIRST_SYNC, AFTER_SECOND_SYNC, READY } communication_state = NO_SYNC;
00416   ErraticPacket received_packet;
00417   while(communication_state != READY && num_patience-- > 0) {
00418     // Send a configuration request
00419     if (num_patience % 5 == 0) {
00420       ErraticPacket packet;
00421       unsigned char command = (command_e)configuration;
00422       packet.Build(&command, 1);
00423       packet.Send(this->write_fd);
00424     }
00425 
00426     // Receive a reply to see if we got it yet
00427     uint8_t receive_error;
00428     if((receive_error = received_packet.Receive(this->read_fd))) {
00429       if (receive_error == (receive_result_e)failure)
00430         printf("Error receiving\n");
00431       // If we still have retries, just get another packet
00432       if((communication_state == NO_SYNC) && (num_sync_attempts >= 0)) {
00433         num_sync_attempts--;
00434         usleep(ROBOT_CYCLETIME);
00435         continue;
00436       }
00437       // Otherwise, try next speed or give up completely
00438       else {
00439       // Couldn't connect; try different speed.
00440         if(++currbaud < numbauds) {
00441         // Set speeds for the descriptors
00442           cfsetispeed(&read_term, bauds[currbaud]);
00443           cfsetospeed(&write_term, bauds[currbaud]);
00444           if( tcsetattr(this->read_fd, TCSAFLUSH, &read_term ) < 0 ) {
00445             perror("Erratic::Setup():tcsetattr():");
00446             close(this->read_fd); close(this->write_fd);
00447             this->read_fd = -1; this->write_fd = -1;
00448             return(1);
00449           }
00450           if( tcsetattr(this->write_fd, TCSAFLUSH, &write_term ) < 0 ) {
00451             perror("Erratic::Setup():tcsetattr():");
00452             close(this->read_fd); close(this->write_fd);
00453             this->read_fd = -1; this->write_fd = -1;
00454             return(1);
00455           }
00456 
00457           // Flush the descriptors
00458           if(tcflush(this->read_fd, TCIOFLUSH ) < 0 ) {
00459             perror("Erratic::Setup():tcflush():");
00460             close(this->read_fd); close(this->write_fd);
00461             this->read_fd = -1; this->write_fd = -1;
00462             return(1);
00463           }
00464           if(tcflush(this->write_fd, TCIOFLUSH ) < 0 ) {
00465             perror("Erratic::Setup():tcflush():");
00466             close(this->read_fd); close(this->write_fd);
00467             this->read_fd = -1; this->write_fd = -1;
00468             return(1);
00469           }
00470 
00471           // Give same slack to new speed
00472           num_sync_attempts = 10;
00473           continue;
00474         }
00475         // Tried all speeds, abort
00476         else failed = 1;
00477       }
00478     }
00479 
00480     // If we gave up
00481     if (failed) break;
00482 
00483     // If we successfully got a packet, check if it's the one we're waiting for
00484     if (received_packet.packet[3] == 0x20) communication_state = READY;
00485 
00486     usleep(ROBOT_CYCLETIME);
00487   }
00488 
00489   if(failed) {
00490     printf("  Couldn't synchronize with Erratic robot.\n");
00491     printf("  Most likely because the robot is not connected to %s\n", this->psos_serial_port);
00492     close(this->read_fd); close(this->write_fd);
00493     this->read_fd = -1; this->write_fd = -1;
00494     return(1);
00495   }
00496   else if (communication_state != READY) {
00497     printf("  Couldn't synchronize with Erratic robot.\n");
00498     printf("  We heard something though. Is the sending part of the cable dead?\n");
00499     close(this->read_fd); close(this->write_fd);
00500     this->read_fd = -1; this->write_fd = -1;
00501     return(1);
00502   }
00503 
00504   char name[20], type[20], subtype[20];
00505   sprintf(name, "%s", &received_packet.packet[5]);
00506   sprintf(type, "%s", &received_packet.packet[25]);
00507   sprintf(subtype, "%s", &received_packet.packet[45]);
00508 
00509   // Open the driver, and tickle it a bit
00510   {
00511     ErraticPacket packet;
00512 
00513     unsigned char command = (command_e)open_controller;
00514     packet.Build(&command, 1);
00515     packet.Send(this->write_fd);
00516     usleep(ROBOT_CYCLETIME);
00517 
00518     command = (command_e)pulse;
00519     packet.Build(&command, 1);
00520     packet.Send(this->write_fd);
00521     usleep(ROBOT_CYCLETIME);
00522   }
00523 
00524   printf(" done.\n  Connected to <%s>, an %s %s\n", name, type, subtype);
00525 
00526   // Set the robot type
00527         if (strcmp(subtype,"Rev H")==0)
00528                 param_idx = 2;
00529         else    if (strcmp(subtype,"Rev G")==0)
00530                 param_idx = 1;
00531         else    if (strcmp(subtype,"Rev E")==0)
00532                 param_idx = 0;
00533         else
00534                 param_idx = 0;
00535 
00536   // Create a packet and set initial odometry position (the ErraticMotorPacket is persistent)
00537   this->motor_packet = new ErraticMotorPacket(param_idx);
00538   this->motor_packet->x_offset = 0;
00539   this->motor_packet->y_offset = 0;
00540   this->motor_packet->angle_offset = 0;
00541 
00542   // If requested, set max accel/decel limits
00543   {
00544     ErraticPacket *accel_packet;
00545     unsigned char accel_command[4];
00546     if(this->motor_max_trans_accel != 0) {
00547       accel_packet = new ErraticPacket();
00548       accel_command[0] = (command_e)set_max_trans_acc;
00549       accel_command[1] = (argtype_e)argint;
00550       accel_command[2] = this->motor_max_trans_accel & 0x00FF;
00551       accel_command[3] = (this->motor_max_trans_accel & 0xFF00) >> 8;
00552       accel_packet->Build(accel_command, 4);
00553       this->Send(accel_packet);
00554     }
00555     if(this->motor_max_trans_decel != 0) {
00556       accel_packet = new ErraticPacket();
00557       accel_command[0] = (command_e)set_max_trans_acc;
00558       accel_command[1] = (argtype_e)argnint;
00559       accel_command[2] = abs(this->motor_max_trans_decel) & 0x00FF;
00560       accel_command[3] = (abs(this->motor_max_trans_decel) & 0xFF00) >> 8;
00561       accel_packet->Build(accel_command, 4);
00562       this->Send(accel_packet);
00563     } else if(this->motor_max_trans_accel != 0) {
00564         accel_packet = new ErraticPacket();
00565         accel_command[0] = (command_e)set_max_trans_acc;
00566         accel_command[1] = (argtype_e)argnint;
00567         accel_command[2] = this->motor_max_trans_accel & 0x00FF;
00568         accel_command[3] = (this->motor_max_trans_accel & 0xFF00) >> 8;
00569         accel_packet->Build(accel_command, 4);
00570         this->Send(accel_packet);
00571     }
00572     
00573     if(this->motor_max_rot_accel != 0) {
00574       accel_packet = new ErraticPacket();
00575       accel_command[0] = (command_e)set_max_rot_acc;
00576       accel_command[1] = (argtype_e)argint;
00577       accel_command[2] = this->motor_max_rot_accel & 0x00FF;
00578       accel_command[3] = (this->motor_max_rot_accel & 0xFF00) >> 8;
00579       accel_packet->Build(accel_command, 4);
00580       this->Send(accel_packet);
00581     }
00582     if(this->motor_max_rot_decel != 0) {
00583       accel_packet = new ErraticPacket();
00584       accel_command[0] = (command_e)set_max_rot_acc;
00585       accel_command[1] = (argtype_e)argnint;
00586       accel_command[2] = abs(this->motor_max_rot_decel) & 0x00FF;
00587       accel_command[3] = (abs(this->motor_max_rot_decel) & 0xFF00) >> 8;
00588       accel_packet->Build(accel_command, 4);
00589       this->Send(accel_packet);
00590     } else if(this->motor_max_rot_accel != 0) {
00591         accel_packet = new ErraticPacket();
00592         accel_command[0] = (command_e)set_max_rot_acc;
00593         accel_command[1] = (argtype_e)argnint;
00594         accel_command[2] = this->motor_max_rot_accel & 0x00FF;
00595         accel_command[3] = (this->motor_max_rot_accel & 0xFF00) >> 8;
00596         accel_packet->Build(accel_command, 4);
00597         this->Send(accel_packet);
00598     }
00599   }
00600   
00601   {
00602     ErraticPacket *packet;
00603     unsigned char payload[4];
00604 
00605     // If requested, download custom PID settings
00606     if(this->pid_trans_p >= 0) {
00607       packet = new ErraticPacket();
00608       payload[0] = (command_e)set_pid_trans_p;
00609       payload[1] = (argtype_e)argint;
00610       payload[2] = this->pid_trans_p & 0x00FF;
00611       payload[3] = (this->pid_trans_p & 0xFF00) >> 8;
00612       packet->Build(payload, 4);
00613       this->Send(packet);
00614     }
00615     if(this->pid_trans_v >= 0) {
00616       packet = new ErraticPacket();
00617       payload[0] = (command_e)set_pid_trans_v;
00618       payload[1] = (argtype_e)argint;
00619       payload[2] = this->pid_trans_v & 0x00FF;
00620       payload[3] = (this->pid_trans_v & 0xFF00) >> 8;
00621       packet->Build(payload, 4);
00622       this->Send(packet);
00623     }
00624     if(this->pid_trans_i >= 0) {
00625       packet = new ErraticPacket();
00626       payload[0] = (command_e)set_pid_trans_i;
00627       payload[1] = (argtype_e)argint;
00628       payload[2] = this->pid_trans_i & 0x00FF;
00629       payload[3] = (this->pid_trans_i & 0xFF00) >> 8;
00630       packet->Build(payload, 4);
00631       this->Send(packet);
00632     }
00633     if(this->pid_rot_p >= 0) {
00634       packet = new ErraticPacket();
00635       payload[0] = (command_e)set_pid_rot_p;
00636       payload[1] = (argtype_e)argint;
00637       payload[2] = this->pid_rot_p & 0x00FF;
00638       payload[3] = (this->pid_rot_p & 0xFF00) >> 8;
00639       packet->Build(payload, 4);
00640       this->Send(packet);
00641     }
00642     if(this->pid_rot_v >= 0) {
00643       packet = new ErraticPacket();
00644       payload[0] = (command_e)set_pid_rot_v;
00645       payload[1] = (argtype_e)argint;
00646       payload[2] = this->pid_rot_v & 0x00FF;
00647       payload[3] = (this->pid_rot_v & 0xFF00) >> 8;
00648       packet->Build(payload, 4);
00649       this->Send(packet);
00650     }
00651     if(this->pid_rot_i >= 0) {
00652       packet = new ErraticPacket();
00653       payload[0] = (command_e)set_pid_rot_i;
00654       payload[1] = (argtype_e)argint;
00655       payload[2] = this->pid_rot_i & 0x00FF;
00656       payload[3] = (this->pid_rot_i & 0xFF00) >> 8;
00657       packet->Build(payload, 4);
00658       this->Send(packet);
00659     }
00660 
00661     // If requested, set PWM parameters
00662     if (this->motor_pwm_frequency > 0) {
00663       packet = new ErraticPacket();
00664       payload[0] = (command_e)set_pwm_freq;
00665       payload[1] = (argtype_e)argint;
00666       payload[2] = this->motor_pwm_frequency & 0x00FF;
00667       payload[3] = (this->motor_pwm_frequency & 0xFF00) >> 8;
00668       packet->Build(payload, 4);
00669       this->Send(packet);
00670     }
00671     if (this->motor_pwm_max_on > 0) {
00672       packet = new ErraticPacket();
00673       payload[0] = (command_e)set_pwm_max_on;
00674       payload[1] = (argtype_e)argint;
00675       payload[2] = this->motor_pwm_max_on & 0x00FF;
00676       payload[3] = (this->motor_pwm_max_on & 0xFF00) >> 8;
00677       packet->Build(payload, 4);
00678       this->Send(packet);
00679     }
00680 
00681     // If requested, make robot save all settings
00682     if (save_settings_in_robot) {
00683       packet = new ErraticPacket();
00684       payload[0] = (command_e)save_config;
00685       payload[1] = 0;
00686       payload[2] = 0;
00687       payload[3] = 0;
00688       packet->Build(payload, 4);
00689       this->Send(packet);
00690     }
00691   }
00692   
00693   // TODO: figure out what the right behavior here is
00694 
00695   // zero position command buffer
00696     //player_position_cmd_t zero;
00697     //memset(&zero,0,sizeof(player_position_cmd_t));
00698     //this->PutCommand(this->position_id,(void*)&zero,
00699       //sizeof(player_position_cmd_t),NULL);
00700 
00701 
00702   /* now spawn reading thread */
00703   ((Erratic*)this)->StartThreads();
00704   return(0);
00705 }
00706 
00707 // Called by player when the driver is supposed to disconnect
00708 int Erratic::Shutdown() {
00709   // We don't care, we'll never disconnect
00710   // Oh, yes, you will!
00711   this->Disconnect();
00712   return 0;
00713 }
00714 
00715 // Is theoretically able to disconnect, but we don't do that
00716 int Erratic::Disconnect() {
00717   printf("Shutting Erratic driver down\n");
00718   
00719   this->StopThreads();
00720   
00721   // If we're connected, send some kill commands before killing connections
00722   if (this->write_fd > -1) {
00723     unsigned char command[20],buffer[20];
00724     ErraticPacket packet;
00725 
00726     memset(buffer,0,20);
00727   
00728     command[0] = (command_e)stop;
00729     packet.Build(command, 1);
00730     packet.Send(this->write_fd);
00731     usleep(ROBOT_CYCLETIME);
00732 
00733     command[0] = (command_e)close_controller;
00734     packet.Build(command, 1);
00735     packet.Send(this->write_fd);
00736     usleep(ROBOT_CYCLETIME);
00737   
00738     close(this->write_fd);
00739     this->write_fd = -1;
00740   }
00741   if (this->read_fd > -1) {
00742     close(this->read_fd);
00743     this->read_fd = -1;
00744   }
00745 
00746   if (this->motor_packet) {
00747     delete this->motor_packet;
00748     this->motor_packet = NULL;
00749   }
00750   
00751   printf("Erratic has been shut down");
00752 
00753   return(0);
00754 }
00755 
00756 // These call the supplied Driver::StartThread() method, but adds additional threads
00757 void Erratic::StartThreads() {
00758   StartThread();
00759   pthread_create(&send_thread, 0, &SendThreadDummy, this);
00760   pthread_create(&receive_thread, 0, &ReceiveThreadDummy, this);
00761 }
00762 void Erratic::StopThreads() {
00763   pthread_cancel(send_thread);
00764   pthread_cancel(receive_thread);
00765   //TODO destroy threads?
00766   //TODO tickle threads to cancel point
00767   StopThread();
00768   
00769   // Cleanup mutexes
00770   pthread_mutex_trylock(&send_queue_mutex);
00771   pthread_mutex_unlock(&send_queue_mutex);
00772   
00773   pthread_mutex_trylock(&motor_packet_mutex);
00774   pthread_mutex_unlock(&motor_packet_mutex);
00775 }
00776 
00777 // Subscription is overridden to add a subscription count of our own
00778 int Erratic::Subscribe(player_devaddr_t id) {
00779   int setupResult;                     
00780                                        
00781   // do the subscription               
00782   if((setupResult = Driver::Subscribe(id)) == 0)
00783   {
00784     // also increment the appropriate subscription counters
00785 
00786     if(Device::MatchDeviceAddress(id, this->position_id))
00787       this->position_subscriptions++;
00788     
00789     if(Device::MatchDeviceAddress(id, this->aio_id))
00790       this->aio_ir_subscriptions++;
00791 
00792     if(Device::MatchDeviceAddress(id, this->ir_id))
00793       this->aio_ir_subscriptions++;
00794 
00795     if(Device::MatchDeviceAddress(id, this->sonar_id))
00796       this->sonar_subscriptions++;
00797 
00798     if(Device::MatchDeviceAddress(id, this->ptz_id))
00799       this->ptz_subscriptions++;
00800 
00801     if(Device::MatchDeviceAddress(id, this->ptz2_id))
00802       this->ptz2_subscriptions++;
00803   }                                    
00804                                        
00805   return(setupResult);                 
00806 }                                      
00807 int Erratic::Unsubscribe(player_devaddr_t id) {
00808   int shutdownResult;
00809 
00810   // do the unsubscription
00811   if((shutdownResult = Driver::Unsubscribe(id)) == 0)
00812   {
00813     // also decrement the appropriate subscription counter
00814     if(Device::MatchDeviceAddress(id, this->position_id))
00815     {
00816       this->position_subscriptions--;
00817       assert(this->position_subscriptions >= 0);
00818     }
00819 
00820     if(Device::MatchDeviceAddress(id, this->aio_id))
00821       this->aio_ir_subscriptions--;
00822 
00823     if(Device::MatchDeviceAddress(id, this->ir_id))
00824       this->aio_ir_subscriptions--;
00825 
00826     if(Device::MatchDeviceAddress(id, this->sonar_id))
00827       this->sonar_subscriptions--;
00828 
00829     if(Device::MatchDeviceAddress(id, this->ptz_id))
00830       this->ptz_subscriptions--;
00831 
00832     if(Device::MatchDeviceAddress(id, this->ptz2_id))
00833       this->ptz2_subscriptions--;
00834 
00835   }
00836 
00837   return(shutdownResult);
00838 }
00839 
00840 
00841 
00842 
00845 // Listens to the robot
00846 void Erratic::ReceiveThread() 
00847 {
00848   for (;;) {
00849     pthread_testcancel();
00850 
00851 
00852     // Receive next packet from robot
00853     ErraticPacket packet;
00854     uint32_t waited = 0;
00855     uint8_t error_code;
00856     while ((error_code = packet.Receive(this->read_fd, 5000))) {
00857       waited += 5;
00858       printf("Lost serial communication with Erratic (%d) - no data received for %i seconds\n", error_code, waited);
00859     }
00860                 
00861     if (waited)
00862       printf("Connection re-established\n");
00863                 
00864                 
00865     if (print_all_packets) {
00866       printf("Got: ");
00867       packet.PrintHex();
00868     }
00869                 
00870     // Process the packet
00871     //Lock();
00872                 
00873     int count, maxcount;
00874     switch(packet.packet[3]) 
00875       {
00876       case (reply_e)motor:
00877       case (reply_e)motor+2:
00878       case (reply_e)motor+3:
00879         if (motor_packet->Parse(&packet.packet[3], packet.size-3)) {
00880           motor_packet->Fill(&erratic_data);
00881           PublishPosition2D();
00882           PublishPower();
00883         }
00884         break;
00885 
00886       case (reply_e)config:
00887         break;
00888 
00889       case (reply_e)ain:
00890         // This data goes in two places, analog input and ir rangers
00891         if(erratic_data.aio.voltages_count != (unsigned int)(packet.packet[4]+4))
00892         {
00893           erratic_data.aio.voltages_count = packet.packet[4]+4;
00894           if(erratic_data.aio.voltages)
00895             delete[] erratic_data.aio.voltages; 
00896           erratic_data.aio.voltages = new float[erratic_data.aio.voltages_count];
00897         }
00898         if(erratic_data.ir.voltages_count != 
00899            (unsigned int)RobotParams[this->param_idx]->NumIR)
00900         {
00901           erratic_data.ir.voltages_count = RobotParams[this->param_idx]->NumIR;
00902           if(erratic_data.ir.voltages)
00903             delete[] erratic_data.ir.voltages; 
00904           erratic_data.ir.voltages = new float[erratic_data.ir.voltages_count];
00905         }
00906         if(erratic_data.ir.ranges_count != 
00907            (unsigned int)RobotParams[this->param_idx]->NumIR)
00908         {
00909           erratic_data.ir.ranges_count = RobotParams[this->param_idx]->NumIR;
00910           if(erratic_data.ir.ranges)
00911             delete[] erratic_data.ir.ranges;
00912           erratic_data.ir.ranges = new float[erratic_data.ir.ranges_count];
00913         }
00914         unsigned int i_voltage;
00915         for (i_voltage = 0; i_voltage < erratic_data.aio.voltages_count ;i_voltage++) 
00916           {
00917             erratic_data.aio.voltages[i_voltage] = (packet.packet[5+i_voltage*2]
00918                                                     + 256*packet.packet[6+i_voltage*2]) * (1.0 / 1024.0) * CPU_VOLTAGE;
00919             erratic_data.ir.voltages[i_voltage] = (packet.packet[5+i_voltage*2]
00920                                                    + 256*packet.packet[6+i_voltage*2]) * (1.0 / 1024.0) * CPU_VOLTAGE;
00921             //                                          erratic_data.ir.ranges[i_voltage] = IRRangeFromVoltage(erratic_data.ir.voltages[i_voltage]);
00922           }
00923 
00924         // add digital inputs, four E port bits
00925         for (int i=0; i < 4; i++) 
00926           {
00927             erratic_data.aio.voltages[i_voltage+i] = 
00928               (packet.packet[5+i_voltage*2] & (0x1 << i+4)) ? 1.0 : 0.0;
00929             erratic_data.ir.voltages[i] = 
00930               (packet.packet[5+i_voltage*2] & (0x1 << i+4)) ? 1.0 : 0.0;
00931             erratic_data.ir.ranges[i] = 
00932               IRFloorRange(erratic_data.ir.voltages[i]);
00933           }
00934 
00935                                         
00936 
00937         PublishAIn();
00938         PublishIR();
00939         break;
00940 
00941       case (reply_e)sonar:
00942         // Sonar packet
00943         maxcount = RobotParams[this->param_idx]->NumSonars;
00944         count = packet.packet[4];
00945         if(erratic_data.sonar.ranges_count != (unsigned int)maxcount)
00946         {
00947           erratic_data.sonar.ranges_count = maxcount;
00948           if(erratic_data.sonar.ranges)
00949             delete[] erratic_data.sonar.ranges;
00950           erratic_data.sonar.ranges = new float[erratic_data.sonar.ranges_count];
00951         }
00952         for (int i = 0; i < count; i++) 
00953           {
00954             int ch = packet.packet[5+i*3]; // channel number
00955             if (ch >= maxcount)
00956               continue;         // bad channel number
00957             erratic_data.sonar.ranges[ch] = .001 * (double)(packet.packet[6+i*3]
00958                                                             + 256*packet.packet[7+i*3]);
00959 //                      printf("Sonar %d: %.2f\n", ch, erratic_data.sonar.ranges[ch]);
00960           }
00961 
00962         PublishSonar();
00963         break;
00964 
00965       case (reply_e)debug:
00966         if (debug_mode) {
00967           printf("Debug message: ");
00968           for (uint8_t i = 3; i < packet.size-2 ;i++)
00969             printf("%c", packet.packet[i]);
00970           printf("\n");
00971         }
00972         break;
00973 
00974       default:
00975         if (debug_mode) {
00976           printf("Unrecognized packet: ");
00977           packet.Print();
00978         }
00979       }
00980                 
00981     //Unlock();
00982   }
00983 }
00984 
00985 void* Erratic::ReceiveThreadDummy(void *driver) {
00986   ((Erratic*)driver)->ReceiveThread();
00987   return 0;
00988 }
00989 
00990 // Sends to the robot
00991 void Erratic::SendThread() {
00992   for (;;) {
00993     pthread_testcancel();
00994     
00995     // Get rights to the queue
00996     pthread_mutex_lock(&send_queue_mutex);
00997     
00998     // If there is nothing, we wait for signal
00999     if (!send_queue.size())
01000       pthread_cond_wait(&send_queue_cond, &send_queue_mutex);
01001 
01002     // Get first element and give the queue back
01003     ErraticPacket *packet = 0;
01004     if (send_queue.size()) {
01005       packet = send_queue.front();
01006       send_queue.pop();
01007     }
01008     pthread_mutex_unlock(&send_queue_mutex);
01009     
01010     // Send the packet and destroy it
01011     if (packet) {
01012       if (print_all_packets) {
01013         printf("Just about to send: ");
01014         packet->Print();
01015       }
01016       packet->Send(this->write_fd);
01017       // To not overload buffers on the robot, hold off a little bit
01018       //if (debug_mode)
01019       //  printf("Just sent it, I guess\n");
01020       // To not overload buffers on the robot, hold off a little bit
01021       usleep(15000);
01022     }
01023     delete(packet);
01024   }
01025 }
01026 void* Erratic::SendThreadDummy(void *driver) {
01027   ((Erratic*)driver)->SendThread();
01028   return 0;
01029 }
01030 
01031 // Queues for sending
01032 void Erratic::Send(ErraticPacket *packet) {
01033   pthread_mutex_lock(&send_queue_mutex); {
01034     send_queue.push(packet);
01035     pthread_cond_signal(&send_queue_cond);
01036   } pthread_mutex_unlock(&send_queue_mutex);
01037 }
01038 
01039 // Tells the robot to reset the odometry center
01040 // Just resets accumulation in this driver, not the controller
01041 void Erratic::ResetRawPositions() {
01042   ErraticPacket *pkt;
01043   unsigned char erraticcommand[4];
01044 
01045   //**************************
01046   //  printf("Reset raw odometry\n");
01047 
01048   if(this->motor_packet) {
01049     pkt = new ErraticPacket();
01050                 // don't reset raw values, else there will be a jump
01051                 //    this->motor_packet->rawxpos = 0;
01052                 //    this->motor_packet->rawypos = 0;
01053     this->motor_packet->xpos = 0;
01054     this->motor_packet->ypos = 0;
01055     this->motor_packet->x_offset = 0;
01056     this->motor_packet->y_offset = 0;
01057     this->motor_packet->angle_offset = 0;
01058     erraticcommand[0] = (command_e)reset_origo;
01059     erraticcommand[1] = (argtype_e)argint;
01060 
01061     //TODO this is removed as a hack
01062     //pkt->Build(erraticcommand, 2);
01063     //this->Send(pkt);
01064   }
01065 }
01066 
01067 // Enable or disable motors
01068 void Erratic::ToggleMotorPower(unsigned char val) {
01069   unsigned char command[4];
01070   ErraticPacket *packet = new ErraticPacket();
01071 
01072   command[0] = (command_e)enable_motors;
01073   command[1] = (argtype_e)argint;
01074   command[2] = val;
01075   command[3] = 0;
01076   packet->Build(command, 4);
01077   
01078   Send(packet);
01079 }
01080 
01081 // Enable or disable analog input reporting
01082 void Erratic::ToggleAIn(unsigned char val) 
01083 {
01084   unsigned char command[4];
01085   ErraticPacket *packet = new ErraticPacket();
01086 
01087   command[0] = (command_e)set_analog;
01088   command[1] = (argtype_e)argint;
01089   command[2] = val ? 1 : 0;
01090   command[3] = 0;
01091   packet->Build(command, 4);
01092   
01093   Send(packet);  
01094 }
01095 
01096 // Enable or disable sonar reporting
01097 void Erratic::ToggleSonar(unsigned char val) 
01098 {
01099   unsigned char command[4];
01100   ErraticPacket *packet = new ErraticPacket();
01101 
01102   command[0] = (command_e)set_sonar;
01103   command[1] = (argtype_e)argint;
01104   command[2] = val ? 1 : 0;
01105   command[3] = 0;
01106   packet->Build(command, 4);
01107   
01108   Send(packet);  
01109 }
01110 
01111 // This describes the IR hardware
01112 float Erratic::IRRangeFromVoltage(float voltage) 
01113 {
01114   // This is for the Sharp 2Y0A02, 150 cm ranger
01115   return -.2475 + .1756 * voltage + .7455 / voltage - .0446 * voltage * voltage;
01116 }
01117 
01118 float Erratic::IRFloorRange(float value) 
01119 {
01120   // floor range is 1 (floor present) or 0 (no floor)
01121   if (value >= 0.9)
01122     return 0.10;                // approximate location of floor from sensors
01123   else
01124     return 1.0;                  // far away
01125 }
01126 
01127 
01130 // Main entry point for the worker thread
01131 void Erratic::Main() {
01132   int last_position_subscrcount=0;
01133   int last_aio_ir_subscriptions=0;
01134   int last_sonar_subscriptions=0;
01135 
01136   for(;;)
01137   {
01138     pthread_testcancel();
01139 
01140     // Wait for some instructions
01141     //    Wait();
01142     usleep(10000);              // Wait() blocks too much, doesn't get subscriptions
01143 
01144     this->Lock();
01145 
01146     // we want to reset the odometry and enable the motors if the first
01147     // client just subscribed to the position device, and we want to stop
01148     // and disable the motors if the last client unsubscribed.
01149     if(!last_position_subscrcount && this->position_subscriptions)
01150     {
01151       this->ToggleMotorPower(0);
01152       this->ResetRawPositions();
01153     }
01154     else if(last_position_subscrcount && !(this->position_subscriptions))
01155     {
01156       // enable motor power
01157       this->ToggleMotorPower(1);
01158     }
01159     last_position_subscrcount = this->position_subscriptions;
01160 
01161 
01162     // We'll ask the robot to enable analog packets if we just got our
01163     // first subscriber
01164     if(!last_aio_ir_subscriptions && this->aio_ir_subscriptions)
01165       this->ToggleAIn(1);
01166     else if(last_aio_ir_subscriptions && !(this->aio_ir_subscriptions))
01167       this->ToggleAIn(0);
01168     last_aio_ir_subscriptions = this->aio_ir_subscriptions;
01169 
01170 
01171     // We'll ask the robot to enable sonar packets if we just got our
01172     // first subscriber
01173     if(!last_sonar_subscriptions && this->sonar_subscriptions)
01174       this->ToggleSonar(1);
01175     else if(last_sonar_subscriptions && !(this->sonar_subscriptions))
01176       this->ToggleSonar(0);
01177     last_sonar_subscriptions = this->sonar_subscriptions;
01178 
01179     this->Unlock();
01180 
01181     // handle pending messages
01182     //printf( "Will look for incoming messages\n" );
01183     if(!this->InQueue->Empty())
01184     {
01185       ProcessMessages();
01186     }
01187     else
01188     {
01189       // if no pending msg, resend the last position cmd.
01190       //TODO reenable?
01191       //this->HandlePositionCommand(this->last_position_cmd);
01192     }
01193     
01194     // Do some little nice printout
01195     if (print_status_summary) {
01196       
01197     }
01198   }
01199 }
01200 
01201 // Publishes the indicated interface data
01202 void Erratic::PublishPosition2D() {
01203   this->Publish(this->position_id,
01204     PLAYER_MSGTYPE_DATA,
01205     PLAYER_POSITION2D_DATA_STATE,
01206     (void*)&(this->erratic_data.position),
01207     sizeof(player_position2d_data_t),
01208     NULL);
01209 }
01210 void Erratic::PublishPower() {
01211   this->Publish(this->power_id,
01212     PLAYER_MSGTYPE_DATA,
01213     PLAYER_POWER_DATA_STATE,
01214     (void*)&(this->erratic_data.power),
01215     sizeof(player_power_data_t),
01216     NULL);
01217 }
01218 void Erratic::PublishAIn() {
01219   this->Publish(this->aio_id,
01220     PLAYER_MSGTYPE_DATA,
01221     PLAYER_AIO_DATA_STATE,
01222     (void*)&(this->erratic_data.aio),
01223     sizeof(player_aio_data_t),
01224     NULL);
01225 }
01226 void Erratic::PublishIR() {
01227   this->Publish(this->ir_id,
01228     PLAYER_MSGTYPE_DATA,
01229     PLAYER_IR_DATA_RANGES,
01230     (void*)&(this->erratic_data.ir),
01231     sizeof(player_ir_data_t),
01232     NULL);
01233 }
01234 void Erratic::PublishSonar() {
01235   this->Publish(this->sonar_id,
01236     PLAYER_MSGTYPE_DATA,
01237     PLAYER_SONAR_DATA_RANGES,
01238     (void*)&(this->erratic_data.sonar),
01239     sizeof(player_sonar_data_t),
01240     NULL);
01241 }
01242 void Erratic::PublishAllData() {
01243   this->PublishPosition2D();
01244   this->PublishPower();
01245   this->PublishAIn();
01246   this->PublishIR();
01247   this->PublishSonar();
01248 }
01249 
01250 // Gets called from ProcessMessages to handle one message
01251 int Erratic::ProcessMessage(QueuePointer &resp_queue, player_msghdr * hdr, void * data) {
01252   // Look for configuration requests
01253   if(hdr->type == PLAYER_MSGTYPE_REQ)
01254     return(this->HandleConfig(resp_queue,hdr,data));
01255   else if(hdr->type == PLAYER_MSGTYPE_CMD)
01256     return(this->HandleCommand(hdr,data));
01257   else
01258     return(-1);
01259 }
01260 
01261 // Handles one Player command with a configuration request
01262 int Erratic::HandleConfig(QueuePointer &resp_queue, player_msghdr * hdr, void * data) {
01263 
01264   // check for position config requests
01265   if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
01266                                PLAYER_POSITION2D_REQ_SET_ODOM,
01267                                this->position_id))
01268   {
01269     if(hdr->size != sizeof(player_position2d_set_odom_req_t))
01270     {
01271       PLAYER_WARN("Arg to odometry set requests wrong size; ignoring");
01272       return(-1);
01273     }
01274     player_position2d_set_odom_req_t* set_odom_req =
01275       (player_position2d_set_odom_req_t*)data;
01276 
01277     this->motor_packet->x_offset = ((int )rint(set_odom_req->pose.px*1e3))
01278                                     + this->motor_packet->xpos;
01279     this->motor_packet->y_offset = ((int)rint(set_odom_req->pose.py*1e3))
01280                                     + this->motor_packet->ypos;
01281     this->motor_packet->angle_offset = ((int)rint(RTOA(set_odom_req->pose.pa)))
01282                                      + this->motor_packet->angle;
01283 
01284     //**************************
01285                 //    printf("Reset odometry: %f %f %f\n", set_odom_req->pose.px, set_odom_req->pose.py, set_odom_req->pose.pa);
01286                 //    printf("Reset odometry: %d %d %d\n", motor_packet->x_offset, motor_packet->y_offset, motor_packet->angle_offset);
01287     
01288 
01289     this->Publish(this->position_id, resp_queue,
01290                   PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_SET_ODOM);
01291     return(0);
01292   }
01293   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
01294                                     PLAYER_POSITION2D_REQ_MOTOR_POWER,
01295                                     this->position_id)) {
01296     if(hdr->size != sizeof(player_position2d_power_config_t)) {
01297       PLAYER_WARN("Arg to motor state change request wrong size; ignoring");
01298       return(-1);
01299     }
01300     player_position2d_power_config_t* power_config =
01301       (player_position2d_power_config_t*)data;
01302     this->ToggleMotorPower(power_config->state);
01303 
01304     this->Publish(this->position_id, resp_queue,
01305                   PLAYER_MSGTYPE_RESP_ACK,
01306                   PLAYER_POSITION2D_REQ_MOTOR_POWER);
01307     return(0);
01308   } else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
01309                                       PLAYER_POSITION2D_REQ_RESET_ODOM,
01310                                       this->position_id)) {
01311     if(hdr->size != 0) {
01312       PLAYER_WARN("Arg to reset position request is wrong size; ignoring");
01313       return(-1);
01314     }
01315 
01316                 this->motor_packet->x_offset = this->motor_packet->xpos;
01317                 this->motor_packet->y_offset = this->motor_packet->ypos;;
01318                 this->motor_packet->angle_offset = this->motor_packet->angle;;
01319                 printf("Resetting odometry offsets: %d %d %d\n", motor_packet->xpos,
01320                                          motor_packet->ypos, motor_packet->angle);
01321 
01322     this->Publish(this->position_id, resp_queue,
01323       PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_RESET_ODOM);
01324     return(0);
01325   }
01326   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
01327                                     PLAYER_POSITION2D_REQ_GET_GEOM,
01328                                     this->position_id)) {
01329     /* Return the robot geometry. */
01330     if(hdr->size != 0) {
01331       PLAYER_WARN("Arg get robot geom is wrong size; ignoring");
01332       return(-1);
01333     }
01334     player_position2d_geom_t geom;
01335 
01336     geom.pose.px = -RobotParams[param_idx]->RobotAxleOffset / 1e3;
01337     geom.pose.py = 0.0;
01338     geom.pose.pyaw = 0.0;
01339 
01340     geom.size.sl = RobotParams[param_idx]->RobotLength / 1e3;
01341     geom.size.sw = RobotParams[param_idx]->RobotWidth / 1e3;
01342 
01343     this->Publish(this->position_id, resp_queue,
01344                   PLAYER_MSGTYPE_RESP_ACK,
01345                   PLAYER_POSITION2D_REQ_GET_GEOM,
01346                   (void*)&geom, sizeof(geom), NULL);
01347     return(0);
01348   }
01349   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
01350                                     PLAYER_POSITION2D_REQ_VELOCITY_MODE,
01351                                     this->position_id)) {
01352     /* velocity control mode:
01353      *   0 = direct wheel velocity control
01354      *   1 = separate translational and rotational control
01355      */
01356       if(hdr->size != sizeof(player_position2d_velocity_mode_config_t))
01357     {
01358       PLAYER_WARN("Arg to velocity control mode change request is wrong "
01359         "size; ignoring");
01360       return(-1);
01361     }
01362     player_position2d_velocity_mode_config_t* velmode_config =
01363       (player_position2d_velocity_mode_config_t*)data;
01364 
01365     if(velmode_config->value)
01366       direct_wheel_vel_control = false;
01367     else
01368       direct_wheel_vel_control = true;
01369 
01370     this->Publish(this->position_id, resp_queue,
01371                   PLAYER_MSGTYPE_RESP_ACK,
01372                   PLAYER_POSITION2D_REQ_VELOCITY_MODE);
01373     return(0);
01374   }
01375   
01376   // Request for getting IR locations
01377   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
01378                                     PLAYER_IR_REQ_POSE,
01379                                     this->ir_id)) {
01380     player_ir_pose_t pose;
01381     pose.poses_count = RobotParams[param_idx]->NumIR;
01382     for (uint16_t i = 0; i < pose.poses_count ;i++)
01383       pose.poses[i] = RobotParams[param_idx]->IRPose[i];
01384     
01385     this->Publish(this->ir_id, resp_queue,
01386                   PLAYER_MSGTYPE_RESP_ACK,
01387                   PLAYER_IR_REQ_POSE,
01388                   (void*)&pose, sizeof(pose), NULL);
01389     return(0);
01390   }
01391   // Request for getting sonar locations
01392   // two types of requests...
01393   else if (Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
01394                                     PLAYER_SONAR_DATA_GEOM,
01395                                     this->sonar_id)) 
01396     {
01397       player_sonar_geom_t pose;
01398       pose.poses_count = RobotParams[param_idx]->NumSonars;
01399       for (uint16_t i = 0; i < pose.poses_count ;i++)
01400         pose.poses[i] = RobotParams[param_idx]->sonar_pose[i];
01401     
01402       this->Publish(this->sonar_id, resp_queue,
01403                     PLAYER_MSGTYPE_RESP_ACK,
01404                     PLAYER_SONAR_DATA_GEOM,
01405                     (void*)&pose, sizeof(pose), NULL);
01406       return(0);
01407     }
01408 
01409   // Request for getting sonar locations
01410   // two types of requests...
01411   else if (Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
01412                                     PLAYER_SONAR_REQ_GET_GEOM,
01413                                     this->sonar_id)) 
01414     {
01415       player_sonar_geom_t pose;
01416       pose.poses_count = RobotParams[param_idx]->NumSonars;
01417       for (uint16_t i = 0; i < pose.poses_count ;i++)
01418         pose.poses[i] = RobotParams[param_idx]->sonar_pose[i];
01419     
01420       this->Publish(this->sonar_id, resp_queue,
01421                     PLAYER_MSGTYPE_RESP_ACK,
01422                     PLAYER_SONAR_REQ_GET_GEOM,
01423                     (void*)&pose, sizeof(pose), NULL);
01424       return(0);
01425     }
01426 
01427   else
01428     {
01429       PLAYER_WARN("unknown config request to erratic driver");
01430       return(-1);
01431     }
01432 }
01433 
01434 // Process car-like command, which sets an angular position target and
01435 // translational velocity target.
01436 // Erratic handles this natively
01437 //
01438 void 
01439 Erratic::HandleCarCommand(player_position2d_cmd_car_t cmd)
01440 {
01441   int speedDemand, angleDemand;
01442   unsigned short absspeedDemand, absangleDemand;
01443   unsigned char motorcommand[4];
01444   ErraticPacket *motorpacket;
01445 
01446   speedDemand = (int)rint(cmd.velocity * 1e3);  // convert to mm/s
01447   angleDemand = (int)rint(RTOD(cmd.angle)); // convert to deg heading
01448   angleDemand += (int)rint(ATOD(this->motor_packet->angle_offset));  // check for angle offset of odometry
01449         while (angleDemand > 360)        // normalize
01450     angleDemand -= 360;
01451   while (angleDemand < 0)
01452     angleDemand += 360;
01453 
01454   // do separate trans and rot vels
01455   motorcommand[0] = (command_e)trans_vel;
01456   if(speedDemand >= 0)
01457     motorcommand[1] = (argtype_e)argint;
01458   else
01459     motorcommand[1] = (argtype_e)argnint;
01460 
01461   absspeedDemand = (unsigned short)abs(speedDemand);
01462   if(absspeedDemand < this->motor_max_speed)
01463     {
01464       motorcommand[2] = absspeedDemand & 0x00FF;
01465       motorcommand[3] = (absspeedDemand & 0xFF00) >> 8;
01466     }
01467   else
01468     {
01469       motorcommand[2] = this->motor_max_speed & 0x00FF;
01470       motorcommand[3] = (this->motor_max_speed & 0xFF00) >> 8;
01471     }
01472     
01473     motorpacket = new ErraticPacket();
01474     motorpacket->Build(motorcommand, 4);
01475     Send(motorpacket);
01476 
01477 
01478   // do separate trans and rot vels
01479   motorcommand[0] = (command_e)rot_pos;
01480   if(angleDemand >= 0)
01481     motorcommand[1] = (argtype_e)argint;
01482   else
01483     motorcommand[1] = (argtype_e)argnint;
01484 
01485   absangleDemand = (unsigned short)abs(angleDemand);
01486   motorcommand[2] = absangleDemand & 0x00FF;
01487   motorcommand[3] = (absangleDemand & 0xFF00) >> 8;
01488     
01489   motorpacket = new ErraticPacket();
01490   motorpacket->Build(motorcommand, 4);
01491   Send(motorpacket);
01492 }
01493 
01494 
01495 // function to get the time in ms
01496 int getms()
01497 {
01498   struct timeval tv;
01499   gettimeofday(&tv,NULL);
01500   return tv.tv_sec*1000 + tv.tv_usec/1000;
01501 }
01502 
01503 
01504 // Handles one Player command detailing a velocity
01505 void Erratic::HandlePositionCommand(player_position2d_cmd_vel_t position_cmd) 
01506 {
01507   int speedDemand, turnRateDemand;
01508   double leftvel, rightvel;
01509   double rotational_term;
01510   unsigned short absspeedDemand, absturnRateDemand;
01511   unsigned char motorcommand[4];
01512   ErraticPacket *motorpacket;
01513 
01514   speedDemand = (int)rint(position_cmd.vel.px * 1e3);
01515   turnRateDemand = (int)rint(RTOD(position_cmd.vel.pa));
01516 
01517   //speedDemand = 0;
01518   //turnRateDemand = 768;
01519 
01520   // throttle back on commands
01521   int ms = getms();
01522   if (mcount == 0) mcount = ms-200;
01523   if (ms < mcount + 50)          // at least 100 ms have to elapse
01524     return;
01525   mcount = ms;
01526 
01527   //if (debug_mode)
01528   //  printf("Will VW, %i and %i\n", speedDemand, turnRateDemand);
01529 
01530   // TODO: interpret this command as 2 velocities
01531   if(this->direct_wheel_vel_control)
01532   {
01533     // convert xspeed and yawspeed into wheelspeeds
01534     rotational_term = (M_PI/180.0) * turnRateDemand /
01535       RobotParams[param_idx]->DiffConvFactor;
01536 
01537     //printf("rotational_term: %g\n", rotational_term);
01538 
01539     leftvel = (speedDemand - rotational_term);
01540     rightvel = (speedDemand + rotational_term);
01541 
01542     //printf("Speeds in ticks: %g %g\n", leftvel, rightvel);
01543 
01544     // Apply wheel speed bounds
01545     if(fabs(leftvel) > this->motor_max_speed)
01546     {
01547       if(leftvel > 0)
01548       {
01549         leftvel = this->motor_max_speed;
01550         rightvel *= this->motor_max_speed/leftvel;
01551       }
01552       else
01553       {
01554         leftvel = -this->motor_max_speed;
01555         rightvel *= -this->motor_max_speed/leftvel;
01556       }
01557     }
01558     if(fabs(rightvel) > this->motor_max_speed)
01559     {
01560       if(rightvel > 0)
01561       {
01562         rightvel = this->motor_max_speed;
01563         leftvel *= this->motor_max_speed/rightvel;
01564       }
01565       else
01566       {
01567         rightvel = -this->motor_max_speed;
01568         leftvel *= -this->motor_max_speed/rightvel;
01569       }
01570     }
01571 
01572     // Apply control band bounds
01573     if(this->use_vel_band)
01574     {
01575       // This band prevents the wheels from turning in opposite
01576       // directions
01577       //TODO WHY is this here??
01578       // It's disabled elsewhere now.
01579       if (leftvel * rightvel < 0)
01580       {
01581         if (leftvel + rightvel >= 0)
01582         {
01583           if (leftvel < 0)
01584             leftvel = 0;
01585           if (rightvel < 0)
01586             rightvel = 0;
01587         }
01588         else
01589         {
01590           if (leftvel > 0)
01591             leftvel = 0;
01592           if (rightvel > 0)
01593             rightvel = 0;
01594         }
01595       }
01596     }
01597 
01598     // Apply byte range bounds
01599     if (leftvel / RobotParams[param_idx]->Vel2Divisor > 126)
01600       leftvel = 126 * RobotParams[param_idx]->Vel2Divisor;
01601     if (leftvel / RobotParams[param_idx]->Vel2Divisor < -126)
01602       leftvel = -126 * RobotParams[param_idx]->Vel2Divisor;
01603     if (rightvel / RobotParams[param_idx]->Vel2Divisor > 126)
01604       rightvel = 126 * RobotParams[param_idx]->Vel2Divisor;
01605     if (rightvel / RobotParams[param_idx]->Vel2Divisor < -126)
01606       rightvel = -126 * RobotParams[param_idx]->Vel2Divisor;
01607 
01608     // send the speed command
01609     motorcommand[0] = (command_e)wheel_vel;
01610     motorcommand[1] = (argtype_e)argint;
01611     motorcommand[2] = (char)(rightvel /
01612       RobotParams[param_idx]->Vel2Divisor);
01613     motorcommand[3] = (char)(leftvel /
01614       RobotParams[param_idx]->Vel2Divisor);
01615 
01616     motorpacket = new ErraticPacket();
01617     motorpacket->Build(motorcommand, 4);
01618     Send(motorpacket);
01619   }
01620   else
01621   {
01622     // do separate trans and rot vels
01623     motorcommand[0] = (command_e)trans_vel;
01624     if(speedDemand >= 0)
01625       motorcommand[1] = (argtype_e)argint;
01626     else
01627       motorcommand[1] = (argtype_e)argnint;
01628 
01629     absspeedDemand = (unsigned short)abs(speedDemand);
01630     if(absspeedDemand < this->motor_max_speed)
01631     {
01632       motorcommand[2] = absspeedDemand & 0x00FF;
01633       motorcommand[3] = (absspeedDemand & 0xFF00) >> 8;
01634     }
01635     else
01636     {
01637       motorcommand[2] = this->motor_max_speed & 0x00FF;
01638       motorcommand[3] = (this->motor_max_speed & 0xFF00) >> 8;
01639     }
01640     
01641     motorpacket = new ErraticPacket();
01642     motorpacket->Build(motorcommand, 4);
01643     Send(motorpacket);
01644 
01645     motorcommand[0] = (command_e)rot_vel;
01646     if(turnRateDemand >= 0)
01647       motorcommand[1] = (argtype_e)argint;
01648     else
01649       motorcommand[1] = (argtype_e)argnint;
01650 
01651     absturnRateDemand = (unsigned short)abs(turnRateDemand);
01652     if(absturnRateDemand < this->motor_max_turnspeed)
01653     {
01654       motorcommand[2] = absturnRateDemand & 0x00FF;
01655       motorcommand[3] = (absturnRateDemand & 0xFF00) >> 8;
01656     }
01657     else
01658     {
01659       motorcommand[2] = this->motor_max_turnspeed & 0x00FF;
01660       motorcommand[3] = (this->motor_max_turnspeed & 0xFF00) >> 8;
01661     }
01662 
01663     motorpacket = new ErraticPacket();
01664     motorpacket->Build(motorcommand, 4);
01665     Send(motorpacket);
01666 
01667   }
01668 }
01669 
01670 //
01671 // Process PTZ command
01672 // Zoom is not used
01673 // For PTZ #0:
01674 //    Pan is on servo 1, tilt on servo 2
01675 // For PTZ #1:
01676 //    Tilt is on servo 0
01677 //
01678 // Commands are in degrees, positive and negative
01679 // Conversions are handled through the Erratic parameter structure,
01680 //   which has parameters for conversion of degrees to servo counts
01681 //   For now use fixed values
01682 // Currently no position or velocity feedback
01683 //
01684 
01685 #define SERVO_NEUTRAL 1650      // in servo counts
01686 #define SERVO_COUNTS_PER_DEGREE 6.5
01687 #define SERVO_MAX_COUNT 2300
01688 #define SERVO_MIN_COUNT 1100
01689 
01690 
01691 void 
01692 Erratic::HandlePtzCommand(player_ptz_cmd_t cmd, player_devaddr_t id)
01693 {
01694   int pan, tilt, servo=0;
01695   unsigned char payload[6];
01696   ErraticPacket *packet;
01697 
01698   // send pan command
01699   pan = (int)(RTOD(cmd.pan));
01700   pan = (int)((double)pan*SERVO_COUNTS_PER_DEGREE + SERVO_NEUTRAL);
01701   if (pan > SERVO_MAX_COUNT)
01702     pan = SERVO_MAX_COUNT;
01703   if (pan < SERVO_MIN_COUNT)
01704     pan = SERVO_MIN_COUNT;
01705 
01706         //      printf("Send command to servo %d: %d / %d\n", 0, (int)(RTOD(cmd.pan)), pan);
01707         if (Device::MatchDeviceAddress(id,this->ptz_id))                                // 1st pan/tilt unit
01708                 {
01709                         packet = new ErraticPacket();
01710                         payload[0] = (command_e)servo_pos;
01711                         payload[1] = (argtype_e)argstr; 
01712                         payload[2] = 3;                                         // 3 bytes in string
01713                         payload[3] = 2;                                         // servo #2
01714                         payload[4] = pan&0xff;
01715                         payload[5] = (pan&0xff00)>>8;
01716                         packet->Build(payload, 6);
01717                         this->Send(packet);
01718                 }
01719 
01720   // send tilt command
01721   tilt = (int)(RTOD(cmd.tilt));
01722   tilt = (int)((double)tilt*SERVO_COUNTS_PER_DEGREE + SERVO_NEUTRAL);
01723   if (tilt > SERVO_MAX_COUNT)
01724     tilt = SERVO_MAX_COUNT;
01725   if (tilt < SERVO_MIN_COUNT)
01726     tilt = SERVO_MIN_COUNT;
01727 
01728         // printf("Send command to servo %d: %d / %d\n", 1, (int)(RTOD(cmd.tilt)), tilt);
01729         if (Device::MatchDeviceAddress(id,this->ptz_id))
01730                 servo = 1;
01731         else if (Device::MatchDeviceAddress(id,this->ptz2_id))
01732                 servo = 0;
01733 
01734   packet = new ErraticPacket();
01735   payload[0] = (command_e)servo_pos;
01736   payload[1] = (argtype_e)argstr;
01737   payload[2] = 3;                                                               // 3 bytes in string
01738   payload[3] = servo;                                           // servo number
01739   payload[4] = tilt&0xff;
01740   payload[5] = (tilt&0xff00)>>8;
01741   packet->Build(payload, 6);
01742   this->Send(packet);
01743 }
01744 
01745 
01746 // Switchboard for robot commands, called from ProcessMessage
01747 // Note that these don't perform a response...
01748 int Erratic::HandleCommand(player_msghdr * hdr, void* data) 
01749 {
01750   if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, PLAYER_POSITION2D_CMD_VEL, this->position_id))
01751     {
01752       player_position2d_cmd_vel_t position_cmd = *(player_position2d_cmd_vel_t*)data;
01753       this->HandlePositionCommand(position_cmd);
01754     } 
01755   else if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, PLAYER_POSITION2D_CMD_CAR, this->position_id))
01756     {
01757       player_position2d_cmd_car_t position_cmd = *(player_position2d_cmd_car_t*)data;
01758       this->HandleCarCommand(position_cmd);
01759     } 
01760   else if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, PLAYER_POSITION2D_CMD_VEL_HEAD, this->position_id))
01761     {
01762       player_position2d_cmd_car_t position_cmd = *(player_position2d_cmd_car_t*)data;
01763       this->HandleCarCommand(position_cmd);
01764     } 
01765   else if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, PLAYER_PTZ_CMD_STATE, this->ptz_id))
01766     {
01767       player_ptz_cmd_t ptz_cmd = *(player_ptz_cmd_t*)data;
01768       this->HandlePtzCommand(ptz_cmd, this->ptz_id);
01769     }
01770   else if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, PLAYER_PTZ_CMD_STATE, this->ptz2_id))
01771     {
01772       player_ptz_cmd_t ptz_cmd = *(player_ptz_cmd_t*)data;
01773       this->HandlePtzCommand(ptz_cmd, this->ptz2_id);
01774     }
01775   else
01776     return(-1);
01777 
01778   return(0);
01779 }

Last updated 12 September 2005 21:38:45