reb.cc

00001 /*
00002  *  Player - One Hell of a Robot Server
00003  *  Copyright (C) 2000  
00004  *     Brian Gerkey, Kasper Stoy, Richard Vaughan, & Andrew Howard
00005  *
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  *
00021  */
00022 
00023 /* Copyright (C) 2002
00024  *   John Sweeney, UMASS, Amherst, Laboratory for Perceptual Robotics
00025  *
00026  * $Id: reb.cc 4126 2007-08-20 06:37:30Z thjc $
00027  *
00028  *   The REB device.  This controls the K-Team Kameleon 376SBC with
00029  * the Robotics Extension Board (REB).  (Technically the REB doesn't control
00030  * anything, it just provides the analog I/Os, H-bridges, etc but we
00031  * thought REB was a good acronym...)  The REB/Kameleon board has the motor
00032  * drivers and sensor I/O, and we communicate with it via a serial port.
00033  * So the overall architecture is similar to the p2osdevice, where this class
00034  * handles the data gathering tasks for the Position, IR and power devices.
00035  *
00036  * Note that we have actually made our own version of the SerCom program that
00037  * runs on the Kameleon.  Our version runs faster than K-Teams, so we
00038  * can reliably get new data at around 10 Hz.  (K-Team SerCom barfed for us
00039  * faster than about 2 Hz!)  Our SerCom, called LPRSerCom, also handles turning
00040  * the IRs on and off, so we don't have to worry about that in the player server.
00041  * If you would like a copy of LPRSerCom, then send me email: sweeney (at) cs.umass.edu
00042  *
00043  * Our robots use a StrongARM SA110 for the compute power, so we have
00044  * to minimize the use of floating point, since the ARM can only emulate
00045  * it.
00046  */
00047 
00148 #include <fcntl.h>
00149 #include <signal.h>
00150 #include <sys/stat.h>
00151 #include <sys/types.h>
00152 #include <stdio.h>
00153 #include <string.h>
00154 #include <termios.h>
00155 #include <unistd.h>
00156 #include <math.h>
00157 #include <stdlib.h>  /* for abs() */
00158 #include <netinet/in.h>
00159 #include <ctype.h>
00160 
00161 #include <reb.h>
00162 
00163 #include <error.h>
00164 #include <playertime.h>
00165 extern PlayerTime* GlobalTime;
00166 
00167 // so we can access the deviceTable and extract pointers to the sonar
00168 // and position objects
00169 #include <devicetable.h>
00170 extern int global_playerport; // used to get at devices
00171 
00172 // we need to debug different things at different times
00173 //#define DEBUG_POS
00174 //#define DEBUG_SERIAL
00175 #define DEBUG_CONFIG
00176 
00177 // useful macros
00178 #define DEG2RAD(x) (((double)(x))*0.01745329251994)
00179 #define RAD2DEG(x) (((double)(x))*57.29577951308232)
00180 
00181 //#define DEG2RAD_FIX(x) ((x) * 17453)
00182 //#define RAD2DEG_FIX(x) ((x) * 57295780)
00183 #define DEG2RAD_FIX(x) ((x) * 174)
00184 #define RAD2DEG_FIX(x) ((x) * 572958)
00185 
00186 /* initialize the driver.
00187  *
00188  * returns: pointer to new REBIR object
00189  */
00190 Driver*
00191 REB_Init(ConfigFile *cf, int section)
00192 {
00193   return (Driver *) new REB( cf, section);
00194 }
00195 
00196 /* register the Khepera IR driver in the drivertable
00197  *
00198  * returns: 
00199  */
00200 void
00201 REB_Register(DriverTable *table) 
00202 {
00203   table->AddDriver("reb", REB_Init);
00204 }
00205 
00206 REB::REB(ConfigFile *cf, int section)
00207         : Driver(cf,section)
00208 {
00209   // zero ids, so that we'll know later which interfaces were requested
00210   memset(&this->position_id, 0, sizeof(player_device_id_t));
00211   memset(&this->ir_id, 0, sizeof(player_device_id_t));
00212   memset(&this->power_id, 0, sizeof(player_device_id_t));
00213 
00214   last_trans_command=last_rot_command=0;
00215   leftvel=rightvel=0;
00216   leftpos=rightpos=0;
00217 
00218 
00219   this->position_subscriptions = 0;
00220   this->ir_subscriptions = 0;
00221 
00222   // Do we create a robot position interface?
00223   if(cf->ReadDeviceId(&(this->position_id), section, "provides", 
00224                       PLAYER_POSITION2D_CODE, -1, NULL) == 0)
00225   {
00226     if(this->AddInterface(this->position_id, PLAYER_ALL_MODE) != 0)
00227     {
00228       this->SetError(-1);    
00229       return;
00230     }
00231   }
00232 
00233   // Do we create an ir interface?
00234   if(cf->ReadDeviceId(&(this->ir_id), section, "provides", 
00235                       PLAYER_IR_CODE, -1, NULL) == 0)
00236   {
00237     if(this->AddInterface(this->ir_id, PLAYER_READ_MODE) != 0)
00238     {
00239       this->SetError(-1);    
00240       return;
00241     }
00242   }
00243 
00244   // Do we create a power interface?
00245   if(cf->ReadDeviceId(&(this->power_id), section, "provides", 
00246                       PLAYER_POWER_CODE, -1, NULL) == 0)
00247   {
00248     if(this->AddInterface(this->power_id, PLAYER_READ_MODE) != 0)
00249     {
00250       this->SetError(-1);    
00251       return;
00252     }
00253   }
00254 
00255   // build the table of robot parameters.
00256   initialize_reb_params();
00257 
00258   // Read config file options
00259   
00260   // also, install default parameter values.
00261   strncpy(reb_serial_port,REB_DEFAULT_SERIAL_PORT,sizeof(reb_serial_port));
00262   reb_fd = -1;
00263   param_index = 0;
00264 
00265   //set up the poll parameters... used for the comms
00266   // over the serial port to the Kam
00267   write_pfd.events = POLLOUT;
00268   read_pfd.events = POLLIN;
00269 
00270   // now we have to look up our parameters.  this should be given as an argument
00271   strncpy(reb_serial_port, cf->ReadString(section, "port", reb_serial_port),
00272           sizeof(reb_serial_port));
00273 
00274   char subclass[32] = "slow";
00275   strncpy(subclass, cf->ReadString(section, "subclass", subclass),
00276           strlen(subclass));
00277   if (!strcmp(subclass, "fast")) {
00278     param_index = 1;
00279   } else {
00280     param_index = 0;
00281   }
00282 
00283   // zero position counters
00284   last_lpos = 0;
00285   last_rpos = 0;
00286   last_x_f=0;
00287   last_y_f=0;
00288   last_theta = 0.0;
00289 }
00290 
00291 /* called the first time a client connects
00292  *
00293  * returns: 0 on success
00294  */
00295 int 
00296 REB::Setup()
00297 {
00298   struct termios oldtio;
00299   struct termios params;
00300 
00301   // open and initialize the serial port from the ARM -> REB  
00302   printf("REB: connection initializing (%s)...\n", this->reb_serial_port);
00303   fflush(stdout);
00304 
00305   if ((this->reb_fd = open(this->reb_serial_port, O_RDWR | O_NOCTTY)) == -1) {
00306     perror("REB::Setup():open()");
00307     return(1);
00308   }     
00309 
00310   // set the poll params
00311   write_pfd.fd = reb_fd;
00312   read_pfd.fd = reb_fd;
00313   
00314   memset(&params, 0, sizeof(params));  
00315   tcgetattr(this->reb_fd, &oldtio); /* save current serial port settings */
00316   params.c_cflag = REB_BAUDRATE | CS8 | CLOCAL | CREAD | CSTOPB;
00317   params.c_iflag = 0; 
00318   params.c_oflag = 0;
00319   params.c_lflag = ICANON; 
00320    
00321   params.c_cc[VMIN] = 0;
00322   params.c_cc[VTIME] = 0;
00323    
00324   tcflush(this->reb_fd, TCIFLUSH);
00325   tcsetattr(this->reb_fd, TCSANOW, &params);
00326 
00327   //  Restart();
00328 
00329   // so no IRs firing
00330   SetIRState(REB_IR_STOP);
00331 
00332   refresh_last_position = false;
00333   motors_enabled = false;
00334   velocity_mode = true;
00335   direct_velocity_control = false;
00336 
00337   desired_heading = 0;
00338 
00339   /*player_position_cmd_t cmd;
00340   memset(&cmd,0,sizeof(player_position_cmd_t));
00341   PutData(this->position_id,(void*)&cmd,
00342           sizeof(player_position_cmd_t),NULL);*/
00343 
00344   /* now spawn reading thread */
00345   StartThread();
00346   return(0);
00347 }
00348 
00349 
00350 int 
00351 REB::Shutdown()
00352 {
00353   printf("REB: SHUTDOWN\n");
00354 
00355   StopThread();
00356 
00357   SetSpeed(REB_MOTOR_LEFT, 0);
00358   SetSpeed(REB_MOTOR_RIGHT, 0);
00359 
00360   SetIRState(REB_IR_STOP);
00361 
00362   close(reb_fd);
00363   reb_fd = -1;
00364   return(0);
00365 }
00366 
00367 int 
00368 REB::Subscribe(player_device_id_t id)
00369 {
00370   int setupResult;
00371 
00372   // do the subscription
00373   if((setupResult = Driver::Subscribe(id)) == 0)
00374   {
00375     // also increment the appropriate subscription counter
00376     switch(id.code)
00377     {
00378       case PLAYER_POSITION2D_CODE:
00379         this->position_subscriptions++;
00380         break;
00381       case PLAYER_IR_CODE:
00382         this->ir_subscriptions++;
00383         break;
00384     }
00385   }
00386 
00387   return(setupResult);
00388 }
00389 
00390 int 
00391 REB::Unsubscribe(player_device_id_t id)
00392 {
00393   int shutdownResult;
00394 
00395   // do the unsubscription
00396   if((shutdownResult = Driver::Unsubscribe(id)) == 0)
00397   {
00398     // also decrement the appropriate subscription counter
00399     switch(id.code)
00400     {
00401       case PLAYER_POSITION2D_CODE:
00402         assert(--this->position_subscriptions >= 0);
00403         break;
00404       case PLAYER_IR_CODE:
00405         assert(--this->ir_subscriptions >= 0);
00406         break;
00407     }
00408   }
00409 
00410   return(shutdownResult);
00411 }
00412 
00413 
00414 void 
00415 REB::Main()
00416 {
00417   int last_ir_subscrcount=0;
00418   int last_position_subscrcount=0;
00419 
00420 
00421   pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
00422 
00423   while (1) {
00424     // we want to turn on the IR if someone just subscribed, and turn
00425     // them off if the last subscriber just unsubscribed.
00426     if(!last_ir_subscrcount && this->ir_subscriptions)
00427     {
00428       // then someone just subbed to IR
00429       SetIRState(REB_IR_START);
00430 
00431       // zero out ranges in IR data so proxy knows
00432       // to do regression
00433       player_ir_data_t ir_data;
00434       memset(&ir_data,0,sizeof(player_ir_data_t));
00435       PutMsg(this->ir_id,NULL, PLAYER_MSGTYPE_DATA, 0,(unsigned char*)&ir_data,
00436               sizeof(player_ir_data_t),NULL);
00437     } 
00438     else if(last_ir_subscrcount && !this->ir_subscriptions)
00439     {
00440       // then last person stopped sub from IR..
00441       SetIRState(REB_IR_STOP);
00442     }
00443     last_ir_subscrcount = this->ir_subscriptions;
00444     
00445     // we want to reset the odometry and enable the motors if the first 
00446     // client just subscribed to the position device, and we want to stop 
00447     // and disable the motors if the last client unsubscribed.
00448     if(!last_position_subscrcount && this->position_subscriptions)
00449     {
00450       printf("REB: first pos sub. turn off and reset\n");
00451       // then first sub for pos, so turn off motors and reset odom
00452       SetSpeed(REB_MOTOR_LEFT, 0);
00453       SetSpeed(REB_MOTOR_RIGHT, 0);
00454 
00455       SetOdometry(0,0,0);
00456 
00457       // set up speed and pos PID
00458       ConfigSpeedPID(0, 1000, 0, 10);
00459       ConfigSpeedPID(2, 1000, 0, 10);
00460       ConfigPosPID(0, 100, 0, 10);
00461       ConfigPosPID(2, 100, 0, 10);
00462 
00463       // have to convert spd from mm/s to pulse/10ms
00464       int spd = (int) rint(100.0 * 
00465                            PlayerUBotRobotParams[this->param_index].PulsesPerMMMS);
00466 
00467       // have to convert acc from mm/s^2 to pulses/256/(10ms^2)
00468       int acc = (int) rint(100.0 * 
00469                            PlayerUBotRobotParams[this->param_index].PulsesPerMMMS);
00470 
00471       if (acc > REB_MAX_ACC) {
00472         acc = REB_MAX_ACC;
00473       } else if (acc == 0) {
00474         acc = REB_MIN_ACC;
00475       }
00476       ConfigSpeedProfile(0, spd, acc);
00477       ConfigSpeedProfile(2, spd, acc);
00478 
00479     } 
00480     else if(last_position_subscrcount && !this->position_subscriptions)
00481     {
00482       // last sub just unsubbed
00483       printf("REB: last pos sub gone\n");
00484       SetSpeed(REB_MOTOR_LEFT, 0);
00485       SetSpeed(REB_MOTOR_RIGHT, 0);
00486 
00487       // overwrite existing motor commands to be zero
00488       player_position_cmd_t position_cmd;
00489       memset(&position_cmd,0,sizeof(position_cmd));
00490       /*PutCommand(this->position_id,
00491                  (unsigned char*)(&position_cmd), sizeof(position_cmd),NULL);*/
00492       ProcessCommand(&position_cmd);
00493     }
00494     last_position_subscrcount = this->position_subscriptions;
00495 
00496     // get configuration commands (ioctls)
00497     //ReadConfig();
00498     ProcessMessages();
00499  
00500     pthread_testcancel();
00501 
00502     // now lets get new data...
00503     UpdateData();
00504 
00505     pthread_testcancel();
00506     
00507   }
00508   pthread_exit(NULL);
00509 }
00510 
00511 int REB::ProcessCommand(player_position_cmd_t * poscmd)
00512 {
00513         player_position_cmd_t & cmd = * poscmd;
00514     if(this->position_subscriptions) 
00515     {
00516       bool newtrans = false, newrot = false, newheading=false;
00517       bool newposcommand=false;
00518       short trans_command, rot_command, heading_command;
00519 
00520       if ((trans_command = (short)ntohl(cmd.xspeed)) != 
00521           last_trans_command) {
00522         newtrans = true;
00523         last_trans_command = trans_command;
00524       }
00525 
00526       if ((rot_command = (short) ntohl(cmd.yawspeed)) != 
00527           last_rot_command) {
00528         newrot = true;
00529         last_rot_command = rot_command;
00530       }
00531 
00532       if ((heading_command = (short) ntohl(cmd.yaw)) != 
00533           this->desired_heading) {
00534         newheading = true;
00535         this->desired_heading = heading_command;
00536       }
00537     
00538       if (this->velocity_mode) {
00539         // then we are in velocity mode
00540         
00541         if (!this->direct_velocity_control) {
00542           // then we are doing my velocity based heading PD controller
00543           
00544           // calculate difference between desired and current
00545           int diff = this->desired_heading - this->current_heading;
00546           
00547           // this will make diff the shortest angle between command and current
00548           if (diff > 180) {
00549             diff += -360; 
00550           } else if (diff < -180) {
00551             diff += 360; 
00552           }
00553           
00554           int trans_long = (int) trans_command;
00555           int rot_long = (int) rot_command;
00556 
00557           // lets try to do this in fixed point
00558           // max angle error is 180, so get a ratio
00559           int err_ratio = diff*REB_FIXED_FACTOR / 180;
00560           //double err_ratio = (double) diff / 180.0;
00561 
00562           // choose trans speed inverse proportional to heading error
00563           trans_long = (REB_FIXED_FACTOR - ABS(err_ratio))*trans_long;
00564 
00565           // try doing squared error?
00566           //      trans_long = (REB_FIXED_FACTOR - err_ratio*err_ratio)*trans_long;
00567 
00568           // now divide by factor to get regular value
00569           trans_long /= REB_FIXED_FACTOR;
00570                   
00571           // now we have to make a rotational velocity proportional to
00572           // heading error with a damping term
00573           
00574           // there is a gain in here that maybe should be configurable
00575           rot_long = err_ratio*3*rot_long;
00576           rot_long /= REB_FIXED_FACTOR;
00577           //rot_command = (short) (err_ratio*2.0*(double)rot_command);
00578           
00579           // make sure we stay within given limits
00580 
00581           trans_command = (short)trans_long;
00582           rot_command = (short) rot_long;
00583 
00584 #ifdef DEBUG_POS
00585           printf("REB: PD: diff=%d err=%d des=%d curr=%d trans=%d rot=%d\n", 
00586                  diff, err_ratio, this->desired_heading, this->current_heading, 
00587                  trans_command, rot_command);
00588 #endif
00589           
00590           if (ABS(last_trans_command) - ABS(trans_command) < 0) {
00591             // then we have to clip the new desired trans to given
00592             // multiply by the sign just to take care of some crazy case
00593             trans_command = SGN(trans_command)* last_trans_command;
00594           }
00595           
00596           if (ABS(last_rot_command) - ABS(rot_command) < 0) {
00597             rot_command = SGN(rot_command)*last_rot_command;
00598           }
00599         }
00600         
00601         // so now we need to figure out left and right wheel velocities
00602         // to achieve the given trans and rot velocitties of the ubot
00603         long rot_term_fixed = rot_command * 
00604           PlayerUBotRobotParams[this->param_index].RobotAxleLength / 2;
00605 
00606         rot_term_fixed = DEG2RAD_FIX(rot_term_fixed);
00607 
00608         leftvel = trans_command*REB_FIXED_FACTOR - rot_term_fixed;
00609         rightvel = trans_command*REB_FIXED_FACTOR + rot_term_fixed;
00610         
00611 
00612         leftvel /= REB_FIXED_FACTOR;
00613         rightvel /= REB_FIXED_FACTOR;
00614 
00615         int max_trans = PlayerUBotRobotParams[this->param_index].MaxVelocity;
00616         
00617         if (ABS(leftvel) > max_trans) {
00618           if (leftvel > 0) {
00619             leftvel = max_trans;
00620             rightvel *= max_trans/leftvel;
00621           } else {
00622             leftvel = -max_trans;
00623             rightvel *= -max_trans/leftvel;
00624           }
00625           
00626           fprintf(stderr, "REB: left wheel velocity clipped\n");
00627         }
00628         
00629         if (ABS(rightvel) > max_trans) {
00630           if (rightvel > 0) {
00631             rightvel = max_trans;
00632             leftvel *= max_trans/rightvel;
00633           } else {
00634             rightvel = -max_trans;
00635             leftvel *= -max_trans/rightvel;
00636           }
00637 
00638           fprintf(stderr, "REB: right wheel velocity clipped\n");
00639         }
00640         
00641         // we have to convert from mm/s to pulse/10ms
00642         //      double left_velocity = (double) leftvel;
00643         //      double right_velocity = (double) rightvel;
00644 
00645         // add the RFF/2 for rounding
00646         long lvf = leftvel * PlayerUBotRobotParams[this->param_index].PulsesPerMMMSF + 
00647           (REB_FIXED_FACTOR/2);
00648         long rvf = -(rightvel * PlayerUBotRobotParams[this->param_index].PulsesPerMMMSF +
00649                      (REB_FIXED_FACTOR/2));
00650 
00651         lvf /= REB_FIXED_FACTOR;
00652         rvf /= REB_FIXED_FACTOR;
00653         //      printf("REB: POS: lvel=%d rvel=%d ", leftvel, rightvel);
00654         //      left_velocity *= PlayerUBotRobotParams[this->param_index].PulsesPerMMMS;
00655         //      right_velocity *= PlayerUBotRobotParams[this->param_index].PulsesPerMMMS;
00656         
00657         //      right_velocity = -right_velocity;
00658         
00659         //      leftvel = (int) rint(left_velocity);
00660         //      rightvel = (int) rint(right_velocity);
00661         leftvel = lvf;
00662         rightvel = rvf;
00663         //      printf("REB: POS: %g [%d] lv=%d [%d] rv=%d [%d]\n", PlayerUBotRobotParams[this->param_index].PulsesPerMMMS,
00664         //             PlayerUBotRobotParams[this->param_index].PulsesPerMMMSF,leftvel, lvf/REB_FIXED_FACTOR, rightvel, rvf/REB_FIXED_FACTOR);
00665 #ifdef DEBUG_POS
00666         printf("REB: [%sABLED] VEL %s: lv=%d rv=%d trans=%d rot=%d\n", 
00667                this->motors_enabled ? "EN" : "DIS",
00668                this->direct_velocity_control ?
00669                "DIRECT" : "PD", leftvel, rightvel, trans_command, rot_command);
00670 #endif
00671         
00672         // now we set the speed
00673         if (this->motors_enabled) {
00674           SetSpeed(REB_MOTOR_LEFT, leftvel);
00675           SetSpeed(REB_MOTOR_RIGHT, rightvel);
00676         } else {
00677           SetSpeed(REB_MOTOR_LEFT, 0);
00678           SetSpeed(REB_MOTOR_RIGHT, 0);
00679         }
00680       } else {
00681         // we are in position mode....
00682         // we only do a translation or a rotation
00683         double lp, rp;
00684 
00685         // set this to false so that we catch the first on_target
00686         //      this->pos_mode_odom_update = false;
00687 
00688         newposcommand = false;
00689         // this will skip translation if command is 0
00690         // or if no new command
00691         if (newtrans) {
00692           // then the command is a translation in mm
00693           lp = (double) trans_command;
00694           lp *= PlayerUBotRobotParams[this->param_index].PulsesPerMM;
00695           leftpos = (int)rint(lp);
00696 
00697           rp = (double) trans_command;
00698           rp *= PlayerUBotRobotParams[this->param_index].PulsesPerMM;
00699           rightpos = (int) rint(rp);
00700 
00701           newposcommand = true;
00702         } else if (newrot) {
00703           // then new rotation instead
00704           // this rot command is in degrees
00705           lp = -DEG2RAD((double)rot_command)*
00706             PlayerUBotRobotParams[this->param_index].RobotAxleLength/2.0 *
00707             PlayerUBotRobotParams[this->param_index].PulsesPerMM;
00708           rp = -lp;
00709           
00710           leftpos = (int) rint(lp);
00711           rightpos = (int) rint(rp);
00712 
00713           newposcommand = true;
00714         }
00715 
00716 #ifdef DEBUG_POS        
00717         printf("REB: [%sABLED] POSITION leftpos=%d rightpos=%d\n",
00718                this->motors_enabled ? "EN" : "DIS", leftpos, rightpos);
00719 #endif
00720 
00721         // now leftpos and rightpos are the right positions to reach
00722         // reset the counters first???? FIX  
00723         // we have to return the position command status now FIX
00724         if (this->motors_enabled && newposcommand) {
00725           printf("REB: SENDING POS COMMAND l=%d r=%d\n", leftpos, rightpos);
00726           // we need to reset counters to 0 for odometry to work
00727           SetPosCounter(REB_MOTOR_LEFT, 0);
00728           SetPosCounter(REB_MOTOR_RIGHT, 0);
00729           SetPos(REB_MOTOR_LEFT, leftpos);
00730           SetPos(REB_MOTOR_RIGHT, -rightpos);
00731         }
00732       }
00733     }
00734   return 0;    
00735 }
00736 
00737 // Process incoming messages from clients 
00738 int REB::ProcessMessage(ClientData * client, player_msghdr * hdr, uint8_t * data, uint8_t * resp_data, size_t * resp_len)
00739 {
00740   assert(hdr);
00741   assert(data);
00742   assert(resp_data);
00743   assert(resp_len);
00744   
00745   if (MatchMessage(hdr, PLAYER_MSGTYPE_CMD, 0, position_id))
00746   {
00747         assert(hdr->size == sizeof(player_position_cmd_t));
00748         ProcessCommand(reinterpret_cast<player_position_cmd_t *> (data));
00749         *resp_len = 0;
00750         return 0;
00751   }
00752 
00753   if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_IR_REQ_POWER, ir_id))
00754   {
00755         assert(hdr->size == sizeof(player_ir_power_req_t));
00756         player_ir_power_req_t * powreq = reinterpret_cast<player_ir_power_req_t *> (data);
00757         
00758     if (powreq->state) 
00759       SetIRState(REB_IR_START);
00760     else 
00761       SetIRState(REB_IR_STOP);
00762       
00763     *resp_len = 0;
00764     return PLAYER_MSGTYPE_RESP_ACK;
00765   }
00766   
00767   if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_IR_REQ_POSE, ir_id))
00768   {
00769         assert(*resp_len >= sizeof(player_ir_pose_t));
00770         player_ir_pose_t & irpose = *reinterpret_cast<player_ir_pose_t *> (resp_data);
00771 
00772     uint16_t numir = PlayerUBotRobotParams[param_index].NumberIRSensors;
00773     irpose.pose_count = htons(numir);
00774     for (int i =0; i < numir; i++) {
00775       int16_t *irp = PlayerUBotRobotParams[param_index].ir_pose[i];
00776       for (int j =0; j < 3; j++) {
00777         irpose.poses[i][j] = htons(irp[j]);
00778       }
00779     }
00780 
00781     *resp_len = sizeof(player_ir_pose_t);
00782     return PLAYER_MSGTYPE_RESP_ACK;
00783   }
00784   
00785   if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER2D_POSITION_REQ_GET_GEOM, position_id))
00786   {
00787 /*      assert(hdr->size == sizeof(player_position_geom_t));
00788         player_position_geom_t * req = reinterpret_cast<player_position_geom_t *> (data);*/
00789         assert(*resp_len >= sizeof(player_position_geom_t));
00790         player_position_geom_t & geom = *reinterpret_cast<player_position_geom_t *> (resp_data);
00791 
00792     geom.pose[0] = htons(0);
00793     geom.pose[1] = htons(0);
00794     geom.pose[2] = htons(0);
00795     geom.size[0] = geom.size[1] = 
00796                   htons( (short) (2 * PlayerUBotRobotParams[this->param_index].RobotRadius));
00797 
00798     *resp_len = sizeof(player_position_geom_t);
00799     return PLAYER_MSGTYPE_RESP_ACK;
00800   }
00801 
00802   if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_MOTOR_POWER, position_id))
00803   {
00804         assert(hdr->size == sizeof(player_position_power_config_t));
00805         player_position_power_config_t * mpowreq = reinterpret_cast<player_position_power_config_t *> (data);
00806 
00807     if (mpowreq->value) {
00808       this->motors_enabled = true;
00809     } else {
00810       this->motors_enabled = false;
00811     }
00812 
00813     *resp_len = 0;
00814     return PLAYER_MSGTYPE_RESP_ACK;
00815   }
00816 
00817           // select method of velocity control
00818           // 0 for direct velocity control (trans and rot applied directly)
00819           // 1 for builtin velocity based heading PD controller
00820   if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_VELOCITY_MODE, position_id))
00821   {
00822     assert(hdr->size == sizeof(player_position_velocitymode_config_t));
00823         player_position_velocitymode_config_t * velcont = reinterpret_cast<player_position_velocitymode_config_t *> (data);
00824 
00825     if (!velcont->value) {
00826       this->direct_velocity_control = true;
00827     } else {
00828       this->direct_velocity_control = false;
00829     }
00830 
00831     // also set up not to use position mode!
00832     this->velocity_mode = true;
00833     
00834     *resp_len = 0;
00835     return PLAYER_MSGTYPE_RESP_ACK;
00836   }
00837 
00838   if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_RESET_ODOM, position_id))
00839   {
00840     SetOdometry(0,0,0);
00841 
00842     *resp_len = 0;
00843     return PLAYER_MSGTYPE_RESP_ACK;
00844   }
00845   
00846   if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_POSITION_MODE, position_id))
00847   {
00848         assert(hdr->size == sizeof(player_position_position_mode_req_t));
00849         player_position_position_mode_req_t * posmode = reinterpret_cast<player_position_position_mode_req_t *> (data);
00850 
00851     if (posmode->state) {
00852       this->velocity_mode = false;
00853     } else {
00854       this->velocity_mode = true;
00855     }
00856 
00857     *resp_len = 0;
00858     return PLAYER_MSGTYPE_RESP_ACK;
00859   }
00860           
00861   if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_SET_ODOM, position_id))
00862   {
00863         assert(hdr->size == sizeof(player_position_set_odom_req_t));
00864         player_position_set_odom_req_t * req = reinterpret_cast<player_position_set_odom_req_t *> (data);
00865 
00866 #ifdef DEBUG_CONFIG
00867     int x,y;
00868     short theta;
00869     x = ntohl(req->x);
00870     y = ntohl(req->y);
00871     theta = ntohs(req->theta);
00872 
00873     printf("REB: SET_ODOM_REQ x=%d y=%d theta=%d\n", x, y, theta);
00874 #endif
00875     SetOdometry(req->x, req->y, req->theta);
00876 
00877     *resp_len = 0;
00878     return PLAYER_MSGTYPE_RESP_ACK;
00879   }
00880 
00881   if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_SPEED_PID, position_id))
00882   {
00883         assert(hdr->size == sizeof(player_position_speed_pid_req_t));
00884         player_position_speed_pid_req_t * pid = reinterpret_cast<player_position_speed_pid_req_t *> (data);
00885 
00886     int kp = ntohl(pid->kp);
00887     int ki = ntohl(pid->ki);
00888     int kd = ntohl(pid->kd);
00889 
00890 #ifdef DEBUG_CONFIG
00891     printf("REB: SPEED_PID_REQ kp=%d ki=%d kd=%d\n", kp, ki, kd);
00892 #endif
00893 
00894     ConfigSpeedPID(REB_MOTOR_LEFT, kp, ki, kd);
00895     ConfigSpeedPID(REB_MOTOR_RIGHT, kp, ki, kd);
00896 
00897     *resp_len = 0;
00898     return PLAYER_MSGTYPE_RESP_ACK;
00899   }
00900 
00901   if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_POSITION_PID, position_id))
00902   {
00903         assert(hdr->size == sizeof(player_position_position_pid_req_t));
00904         player_position_position_pid_req_t * pid = reinterpret_cast<player_position_position_pid_req_t *> (data);
00905 
00906     int kp = ntohl(pid->kp);
00907     int ki = ntohl(pid->ki);
00908     int kd = ntohl(pid->kd);
00909 
00910 #ifdef DEBUG_CONFIG
00911     printf("REB: POS_PID_REQ kp=%d ki=%d kd=%d\n", kp, ki, kd);
00912 #endif
00913 
00914     ConfigPosPID(REB_MOTOR_LEFT, kp, ki, kd);
00915     ConfigPosPID(REB_MOTOR_RIGHT, kp, ki, kd);
00916 
00917     *resp_len = 0;
00918     return PLAYER_MSGTYPE_RESP_ACK;
00919   }
00920 
00921   if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_SPEED_PROF, position_id))
00922   {
00923         assert(hdr->size == sizeof(player_position_speed_prof_req_t));
00924         player_position_speed_prof_req_t * prof = reinterpret_cast<player_position_speed_prof_req_t *> (data);
00925 
00926     int spd = ntohs(prof->speed);
00927     int acc = ntohs(prof->acc);
00928 
00929 #ifdef DEBUG_CONFIG     
00930     printf("REB: SPEED_PROF_REQ: spd=%d acc=%d  spdu=%g accu=%g\n", spd, acc,
00931            spd*PlayerUBotRobotParams[this->param_index].PulsesPerMMMS,
00932            acc*PlayerUBotRobotParams[this->param_index].PulsesPerMMMS);
00933 #endif
00934     // have to convert spd from mm/s to pulse/10ms
00935     spd = (int) rint((double)spd * 
00936                      PlayerUBotRobotParams[this->param_index].PulsesPerMMMS);
00937 
00938     // have to convert acc from mm/s^2 to pulses/256/(10ms^2)
00939     acc = (int) rint((double)acc * 
00940                      PlayerUBotRobotParams[this->param_index].PulsesPerMMMS);
00941     // now have to turn into pulse/256
00942     //  acc *= 256;
00943 
00944     if (acc > REB_MAX_ACC) {
00945       acc = REB_MAX_ACC;
00946     } else if (acc == 0) {
00947       acc = REB_MIN_ACC;
00948     }
00949 
00950 #ifdef DEBUG_CONFIG
00951     printf("REB: SPEED_PROF_REQ: SPD=%d  ACC=%d\n", spd, acc);
00952     ConfigSpeedProfile(REB_MOTOR_LEFT, spd, acc);
00953     ConfigSpeedProfile(REB_MOTOR_RIGHT, spd, acc);
00954 #endif
00955 
00956     *resp_len = 0;
00957     return PLAYER_MSGTYPE_RESP_ACK;
00958   }
00959 
00960   *resp_len = 0;
00961   return -1;
00962 }
00963 
00964 
00965 /* this will read a new config command and interpret it
00966  *
00967  * returns: 
00968  */
00969 /*void
00970 REB::ReadConfig()
00971 {
00972   int config_size;
00973   unsigned char config_buffer[REB_CONFIG_BUFFER_SIZE];
00974   void *client;
00975 
00976   // check for IR config requests
00977   if((config_size = GetConfig(this->ir_id, &client, 
00978                               (void*)config_buffer, 
00979                               sizeof(config_buffer),NULL))) 
00980   {
00981     // REB_IR IOCTLS /////////////////
00982       
00983 #ifdef DEBUG_CONFIG
00984     printf("REB: IR CONFIG\n");
00985 #endif
00986 
00987     // figure out which command
00988     switch(config_buffer[0]) 
00989     {
00990       case PLAYER_IR_REQ_POWER: 
00991         {
00992           // request to change IR state
00993           // 1 means turn on
00994           // 0 is off
00995           if (config_size != sizeof(player_ir_power_req_t)) 
00996           {
00997             fprintf(stderr, "REB: argument to IR power req wrong size (%d)\n", config_size);
00998             if(PutReply(this->ir_id, client, PLAYER_MSGTYPE_RESP_NACK, NULL))
00999               PLAYER_ERROR("REB: failed to reply");
01000             break;
01001           }
01002 
01003           player_ir_power_req_t *powreq = (player_ir_power_req_t *)config_buffer;       
01004 #ifdef DEBUG_CONFIG
01005           printf("REB: IR_POWER_REQ: %d\n", powreq->state);
01006 #endif
01007 
01008           if (powreq->state) {
01009             SetIRState(REB_IR_START);
01010           } else {
01011             SetIRState(REB_IR_STOP);
01012           }
01013 
01014           if(PutReply(this->ir_id, client, PLAYER_MSGTYPE_RESP_ACK, NULL))
01015             PLAYER_ERROR("REB: failed to reply");
01016         }
01017         break;
01018       
01019       case PLAYER_IR_REQ_POSE: 
01020         {
01021           // request the pose of the IR sensors in robot-centric coords
01022           if(config_size != sizeof(player_ir_pose_req_t)) 
01023           {
01024             fprintf(stderr, "REB: argument to IR pose req wrong size (%d)\n", config_size);
01025             if(PutReply(this->ir_id, client, PLAYER_MSGTYPE_RESP_NACK, NULL))
01026               PLAYER_ERROR("REB: failed to put reply");
01027             break;
01028           }
01029 
01030 #ifdef DEBUG_CONFIG
01031           printf("REB: IR_POSE_REQ\n");
01032 #endif
01033 
01034           player_ir_pose_t irpose;
01035           uint16_t numir = PlayerUBotRobotParams[param_index].NumberIRSensors;
01036           irpose.pose_count = htons(numir);
01037           for (int i =0; i < numir; i++) {
01038             int16_t *irp = PlayerUBotRobotParams[param_index].ir_pose[i];
01039             for (int j =0; j < 3; j++) {
01040               irpose.poses[i][j] = htons(irp[j]);
01041             }
01042           }
01043 
01044           if(PutReply(this->ir_id, client, PLAYER_MSGTYPE_RESP_ACK, 
01045                       &irpose, sizeof(irpose), NULL)) 
01046             PLAYER_ERROR("REB: failed to put reply");
01047         }
01048         break;
01049 
01050       default:
01051         fprintf(stderr, "REB: IR got unknown config\n");
01052         if(PutReply(this->ir_id, client, PLAYER_MSGTYPE_RESP_NACK, NULL))
01053           PLAYER_ERROR("REB: failed to put reply");
01054         break;
01055     }
01056     // END REB_IR IOCTLS //////////////
01057   }
01058 
01059   // check for position config requests
01060   if((config_size = GetConfig(this->position_id, &client, 
01061                               (void*)config_buffer, 
01062                               sizeof(config_buffer),NULL))) 
01063 
01064   {
01065       // POSITION IOCTLS ////////////////
01066 #ifdef DEBUG_CONFIG
01067     printf("REB: POSITION CONFIG\n");
01068 #endif
01069     switch (config_buffer[0]) 
01070     {
01071       case PLAYER_POSITION2D_REQ_GET_GEOM: 
01072         {
01073           // get geometry of robot
01074           if (config_size != sizeof(player_position_geom_t)) 
01075           {
01076             fprintf(stderr, "REB: get geom req is wrong size (%d)\n", config_size);
01077             if(PutReply(this->position_id, client, 
01078                         PLAYER_MSGTYPE_RESP_NACK, NULL))
01079               PLAYER_ERROR("REB: failed to put reply");
01080             break;
01081           }
01082 
01083 #ifdef DEBUG_CONFIG
01084           printf("REB: POSITION_GET_GEOM_REQ\n");
01085 #endif
01086 
01087           player_position_geom_t geom;
01088           geom.subtype = PLAYER_POSITION2D_REQ_GET_GEOM;
01089           geom.pose[0] = htons(0);
01090           geom.pose[1] = htons(0);
01091           geom.pose[2] = htons(0);
01092           geom.size[0] = geom.size[1] = 
01093                   htons( (short) (2 * PlayerUBotRobotParams[this->param_index].RobotRadius));
01094 
01095           if(PutReply(this->position_id, client, PLAYER_MSGTYPE_RESP_ACK, 
01096                       &geom, sizeof(geom), NULL)) 
01097             PLAYER_ERROR("REB: failed to put reply");
01098         }
01099         break;
01100 
01101       case PLAYER_POSITION2D_REQ_MOTOR_POWER: 
01102         {
01103           // change motor state
01104           // 1 for on 
01105           // 0 for off
01106 
01107           if (config_size != sizeof(player_position_power_config_t)) 
01108           {
01109             fprintf(stderr, "REB: pos motor power req got wrong size (%d)\n", config_size);
01110             if(PutReply(this->position_id, client, 
01111                         PLAYER_MSGTYPE_RESP_NACK, NULL))
01112               PLAYER_ERROR("REB: failed to put reply");
01113             break;
01114           }
01115 
01116           player_position_power_config_t *mpowreq = (player_position_power_config_t *)config_buffer;
01117 
01118 #ifdef DEBUG_CONFIG
01119           printf("REB: MOTOR_POWER_REQ %d\n", mpowreq->value);
01120 #endif
01121 
01122           if (mpowreq->value) {
01123             this->motors_enabled = true;
01124           } else {
01125             this->motors_enabled = false;
01126           }
01127 
01128           if(PutReply(this->position_id, client, PLAYER_MSGTYPE_RESP_ACK, NULL))
01129             PLAYER_ERROR("REB: failed to put reply");
01130 
01131           printf("REB: put MOTOR POWER REQ\n");
01132         }
01133         break;
01134 
01135       case PLAYER_POSITION2D_REQ_VELOCITY_MODE: 
01136         {
01137           // select method of velocity control
01138           // 0 for direct velocity control (trans and rot applied directly)
01139           // 1 for builtin velocity based heading PD controller
01140           if (config_size != sizeof(player_position_velocitymode_config_t)) 
01141           {
01142             fprintf(stderr, "REB: pos vel control req got wrong size (%d)\n", config_size);
01143             if(PutReply(this->position_id, client, 
01144                         PLAYER_MSGTYPE_RESP_NACK, NULL))
01145               PLAYER_ERROR("REB: failed to put reply");
01146             break;
01147           }
01148 
01149           player_position_velocitymode_config_t *velcont = 
01150                   (player_position_velocitymode_config_t *) config_buffer;
01151 
01152 #ifdef DEBUG_CONFIG
01153           printf("REB: VELOCITY_MODE_REQ %d\n", velcont->value);
01154 #endif
01155 
01156           if (!velcont->value) {
01157             this->direct_velocity_control = true;
01158           } else {
01159             this->direct_velocity_control = false;
01160           }
01161 
01162           // also set up not to use position mode!
01163           this->velocity_mode = true;
01164 
01165           if(PutReply(this->position_id, client, 
01166                       PLAYER_MSGTYPE_RESP_ACK, NULL))
01167             PLAYER_ERROR("REB: failed to put reply");
01168         }
01169         break;
01170 
01171       case PLAYER_POSITION2D_REQ_RESET_ODOM: 
01172         {
01173           // reset the odometry
01174           if (config_size != sizeof(player_position_resetodom_config_t)) 
01175           {
01176             fprintf(stderr, "REB: pos reset odom req got wrong size (%d)\n", config_size);
01177             if(PutReply(this->position_id, client, 
01178                         PLAYER_MSGTYPE_RESP_NACK, NULL))
01179               PLAYER_ERROR("REB: failed to put reply");
01180             break;
01181           }
01182 
01183 #ifdef DEBUG_CONFIG
01184           printf("REB: RESET_ODOM_REQ\n");
01185 #endif
01186 
01187           SetOdometry(0,0,0);
01188 
01189           if(PutReply(this->position_id, client, 
01190                       PLAYER_MSGTYPE_RESP_ACK, NULL))
01191             PLAYER_ERROR("REB: failed to put reply");
01192         }
01193         break;
01194       
01195       case PLAYER_POSITION2D_REQ_POSITION_MODE: 
01196         {
01197           // select velocity or position mode
01198           // 0 for velocity mode
01199           // 1 for position mode
01200           if (config_size != sizeof(player_position_position_mode_req_t)) 
01201           {
01202             fprintf(stderr, "REB: pos vel mode req got wrong size (%d)\n", config_size);
01203             if(PutReply(this->position_id, client, 
01204                         PLAYER_MSGTYPE_RESP_NACK, NULL))
01205               PLAYER_ERROR("REB: failed to put reply");
01206             break;
01207           }
01208 
01209           player_position_position_mode_req_t *posmode = 
01210                   (player_position_position_mode_req_t *)config_buffer;
01211 #ifdef DEBUG_CONFIG
01212           printf("REB: POSITION_MODE_REQ %d\n", posmode->state);
01213 #endif
01214 
01215           if (posmode->state) {
01216             this->velocity_mode = false;
01217           } else {
01218             this->velocity_mode = true;
01219           }
01220 
01221           if(PutReply(this->position_id, client, PLAYER_MSGTYPE_RESP_ACK, NULL))
01222             PLAYER_ERROR("REB: failed to put reply");
01223         }
01224         break;
01225 
01226       case PLAYER_POSITION2D_REQ_SET_ODOM: 
01227         {
01228           // set the odometry to a given position
01229           if (config_size != sizeof(player_position_set_odom_req_t)) 
01230           {
01231             fprintf(stderr, "REB: pos set odom req got wrong size (%d)\n",
01232                     config_size);
01233             if(PutReply(this->position_id, client, 
01234                         PLAYER_MSGTYPE_RESP_NACK, NULL))
01235               PLAYER_ERROR("REB: failed to put reply");
01236             break;
01237           }
01238 
01239           player_position_set_odom_req_t *req = 
01240                   (player_position_set_odom_req_t *)config_buffer;
01241 
01242 #ifdef DEBUG_CONFIG
01243           int x,y;
01244           short theta;
01245           x = ntohl(req->x);
01246           y = ntohl(req->y);
01247           theta = ntohs(req->theta);
01248 
01249           printf("REB: SET_ODOM_REQ x=%d y=%d theta=%d\n", x, y, theta);
01250 #endif
01251           SetOdometry(req->x, req->y, req->theta);
01252 
01253           if(PutReply(this->position_id, client, 
01254                       PLAYER_MSGTYPE_RESP_ACK, NULL))
01255             PLAYER_ERROR("REB: failed to put reply");
01256         }
01257         break;
01258 
01259       case PLAYER_POSITION2D_REQ_SPEED_PID: 
01260         {
01261           // set up the velocity PID on the REB
01262           // kp, ki, kd are used
01263           if (config_size != sizeof(player_position_speed_pid_req_t)) 
01264           {
01265             fprintf(stderr, "REB: pos speed PID req got wrong size (%d)\n", config_size);
01266             if(PutReply(this->position_id, client, 
01267                         PLAYER_MSGTYPE_RESP_NACK, NULL))
01268               PLAYER_ERROR("REB: failed to put reply");
01269             break;
01270           }
01271 
01272           player_position_speed_pid_req_t *pid = 
01273                   (player_position_speed_pid_req_t *)config_buffer;
01274           int kp = ntohl(pid->kp);
01275           int ki = ntohl(pid->ki);
01276           int kd = ntohl(pid->kd);
01277 
01278 #ifdef DEBUG_CONFIG
01279           printf("REB: SPEED_PID_REQ kp=%d ki=%d kd=%d\n", kp, ki, kd);
01280 #endif
01281 
01282           ConfigSpeedPID(REB_MOTOR_LEFT, kp, ki, kd);
01283           ConfigSpeedPID(REB_MOTOR_RIGHT, kp, ki, kd);
01284 
01285           if(PutReply(this->position_id, client, 
01286                       PLAYER_MSGTYPE_RESP_ACK, NULL))
01287             PLAYER_ERROR("REB: failed to put reply");
01288         }
01289         break;
01290       
01291       case PLAYER_POSITION2D_REQ_POSITION_PID: 
01292         {
01293           // set up the position PID on the REB
01294           // kp, ki, kd are used
01295           if(config_size != sizeof(player_position_position_pid_req_t)) 
01296           {
01297             fprintf(stderr, "REB: pos pos PID req got wrong size (%d)\n", config_size);
01298             if(PutReply(this->position_id, client, 
01299                         PLAYER_MSGTYPE_RESP_NACK, NULL))
01300               PLAYER_ERROR("REB: failed to put reply");
01301             break;
01302           }
01303 
01304           player_position_position_pid_req_t *pid = 
01305                   (player_position_position_pid_req_t *)config_buffer;
01306           int kp = ntohl(pid->kp);
01307           int ki = ntohl(pid->ki);
01308           int kd = ntohl(pid->kd);
01309 
01310 #ifdef DEBUG_CONFIG
01311           printf("REB: POS_PID_REQ kp=%d ki=%d kd=%d\n", kp, ki, kd);
01312 #endif
01313 
01314           ConfigPosPID(REB_MOTOR_LEFT, kp, ki, kd);
01315           ConfigPosPID(REB_MOTOR_RIGHT, kp, ki, kd);
01316 
01317           if(PutReply(this->position_id, client, 
01318                       PLAYER_MSGTYPE_RESP_ACK, NULL))
01319             PLAYER_ERROR("REB: failed to put reply");
01320         }
01321         break;
01322 
01323       case PLAYER_POSITION2D_REQ_SPEED_PROF: 
01324         {
01325           // set the speed profile for position mode 
01326           // speed is max speed
01327           // acc is max acceleration
01328           if (config_size != sizeof(player_position_speed_prof_req_t)) 
01329           {
01330             fprintf(stderr, "REB: pos speed prof req got wrong size (%d)\n", config_size);
01331             if(PutReply(this->position_id, client, 
01332                         PLAYER_MSGTYPE_RESP_NACK, NULL))
01333               PLAYER_ERROR("REB: failed to put reply");
01334             break;
01335           }
01336 
01337           player_position_speed_prof_req_t *prof = 
01338                   (player_position_speed_prof_req_t *)config_buffer;    
01339           int spd = ntohs(prof->speed);
01340           int acc = ntohs(prof->acc);
01341 
01342 #ifdef DEBUG_CONFIG     
01343           printf("REB: SPEED_PROF_REQ: spd=%d acc=%d  spdu=%g accu=%g\n", spd, acc,
01344                  spd*PlayerUBotRobotParams[this->param_index].PulsesPerMMMS,
01345                  acc*PlayerUBotRobotParams[this->param_index].PulsesPerMMMS);
01346 #endif
01347           // have to convert spd from mm/s to pulse/10ms
01348           spd = (int) rint((double)spd * 
01349                            PlayerUBotRobotParams[this->param_index].PulsesPerMMMS);
01350 
01351           // have to convert acc from mm/s^2 to pulses/256/(10ms^2)
01352           acc = (int) rint((double)acc * 
01353                            PlayerUBotRobotParams[this->param_index].PulsesPerMMMS);
01354           // now have to turn into pulse/256
01355           //    acc *= 256;
01356 
01357           if (acc > REB_MAX_ACC) {
01358             acc = REB_MAX_ACC;
01359           } else if (acc == 0) {
01360             acc = REB_MIN_ACC;
01361           }
01362 
01363 #ifdef DEBUG_CONFIG
01364           printf("REB: SPEED_PROF_REQ: SPD=%d  ACC=%d\n", spd, acc);
01365           ConfigSpeedProfile(REB_MOTOR_LEFT, spd, acc);
01366           ConfigSpeedProfile(REB_MOTOR_RIGHT, spd, acc);
01367 #endif
01368           if(PutReply(this->position_id, client, PLAYER_MSGTYPE_RESP_ACK, NULL))
01369             PLAYER_ERROR("REB: failed to put reply");
01370         }
01371         break;
01372       
01373       default:
01374         fprintf(stderr, "REB: got unknown position config command\n");
01375         if(PutReply(this->position_id, client, PLAYER_MSGTYPE_RESP_NACK, NULL))
01376           PLAYER_ERROR("REB: failed to put reply");
01377         break;
01378     }
01379     // END REB_POSITION IOCTLS ////////////
01380   }
01381 }
01382 */
01383 
01384 /* this will update the data that is sent to clients
01385  * just call separate functions to take care of it
01386  *
01387  * returns:
01388  */
01389 void
01390 REB::UpdateData()
01391 {
01392   player_position_data_t position_data;
01393   player_ir_data_t ir_data;
01394   player_power_data_t power_data;
01395 
01396   UpdateIRData(&ir_data);
01397   PutMsg(this->ir_id, NULL, PLAYER_MSGTYPE_DATA, 0,
01398           (void*)&ir_data,
01399           sizeof(player_ir_data_t),
01400           NULL);
01401 
01402   UpdatePowerData(&power_data);
01403   PutMsg(this->power_id, NULL, PLAYER_MSGTYPE_DATA, 0,
01404           (void*)&power_data,
01405           sizeof(player_power_data_t),
01406           NULL);
01407 
01408   UpdatePosData(&position_data);
01409   PutMsg(this->position_id, NULL, PLAYER_MSGTYPE_DATA, 0,
01410           (void*)&position_data,
01411           sizeof(player_position_data_t),
01412           NULL);
01413 }
01414 
01415 /* this will update the IR part of the client data
01416  * it entails reading the currently active IR sensors
01417  * and then changing their state to off and turning on
01418  * 2 new IRs.  
01419  * NOTE: assumes calling function already called Lock()
01420  *
01421  * returns:
01422  */
01423 void
01424 REB::UpdateIRData(player_ir_data_t * d)
01425 {
01426   // then we can take a reading
01427   uint16_t volts[PLAYER_IR_MAX_SAMPLES];
01428 
01429   ReadAllIR(volts);
01430   
01431   for (int i =0; i < PLAYER_IR_MAX_SAMPLES; i++) {
01432     // these are in units of 4 mV
01433     // now turn into mV units
01434     volts[i] *= 4;
01435     d->voltages[i] = htons(volts[i]);
01436   }
01437   
01438 }
01439 
01440 /* this will update the POWER data.. basically just the battery level for now
01441  * NOTE: assumes calling function already called Lock()
01442  * returns:
01443  */
01444 void
01445 REB::UpdatePowerData(player_power_data_t *d)
01446 {
01447   // read voltage 
01448   uint16_t volt = (uint16_t)ReadAD(REB_BATTERY_CHANNEL);
01449   
01450   // this is in units of 20mV.. change to mV
01451   volt *= 20;
01452   d->charge = htons(volt);
01453 }
01454   
01455 /* this will update the position data.  this entails odometry, etc
01456  * assumes caller already called Lock()
01457  * It is in the midst of being converted from floating to fixed point...
01458  * returns:
01459  */ 
01460 void
01461 REB::UpdatePosData(player_position_data_t *d)
01462 {
01463   // change to fixed point FIX
01464   double x=0, y=0, theta;
01465   long x_f, y_f;
01466   unsigned char target_status =0;
01467   int lreading=0, rreading=0;
01468   long mmpp_f = PlayerUBotRobotParams[this->param_index].MMPerPulsesF;
01469   //  static int last_lpos=0, last_rpos=0;
01470   int x_rem=0, y_rem=0;
01471 
01472   // check if we have to get a baseline time first
01473   if (this->refresh_last_position) {
01474     GlobalTime->GetTime(&(this->last_position));
01475     this->refresh_last_position = false;
01476   }
01477   
01478   // get the previous odometry values
01479   // we know this is from last time, cuz this function
01480   // is only place to change them
01481   //  theta = (double) ((int)ntohs(this->data->position.yaw));
01482 
01483   //covert theta to rad
01484   //  theta = DEG2RAD(theta);
01485   theta = last_theta;
01486 
01487   //  x_f = ntohl(this->data->position.xpos)*REB_FIXED_FACTOR ;
01488   //  y_f = ntohl(this->data->position.ypos)*REB_FIXED_FACTOR ;
01489   x_f = last_x_f;
01490   y_f = last_y_f;
01491 
01492   // get the time
01493   struct timeval curr;
01494   GlobalTime->GetTime(&curr);
01495 
01496   double v, theta_dot;
01497   long v_f=0;
01498 
01499   if (this->velocity_mode) {
01500     int lpos=0, rpos=0, lp, rp;
01501     //        lvel = ReadSpeed(REB_MOTOR_LEFT);
01502     lpos = ReadPos(REB_MOTOR_LEFT);
01503     // negate because motor's are facing opposite directions
01504     //        rvel = -ReadSpeed(REB_MOTOR_RIGHT); 
01505     rpos = -ReadPos(REB_MOTOR_RIGHT);
01506 
01507     lreading = lpos;
01508     rreading = rpos;
01509 
01510     // calc time in  sec
01511     long t_f = (curr.tv_sec - this->last_position.tv_sec)*100 +
01512       (curr.tv_usec - this->last_position.tv_usec)/10000;
01513 
01514     lp = lpos-last_lpos;
01515     rp = rpos-last_rpos;
01516     
01517     last_lpos = lpos;
01518     last_rpos = rpos;
01519 
01520     // this is pulse/10ms
01521     v_f = (rp+lp) * REB_FIXED_FACTOR / 2;
01522     v_f /= t_f;
01523 
01524     //    v_f = (rvel+lvel)/2;
01525     //    v_f *= REB_FIXED_FACTOR;
01526 
01527     // rad/pulse
01528     //    theta_dot = (rvel- lvel) /
01529     //    theta_dot = (( (double) rp / (double) t_f) - ( (double)lp / (double) t_f)) /
01530     //      (PlayerUBotRobotParams[this->param_index].RobotAxleLength *
01531     //       PlayerUBotRobotParams[this->param_index].PulsesPerMM);
01532     theta_dot = (rp - lp) / 
01533       (PlayerUBotRobotParams[param_index].RobotAxleLength *
01534        PlayerUBotRobotParams[param_index].PulsesPerMM * (double)t_f);
01535 
01536     theta += theta_dot * t_f;
01537 
01538     // convert from rad/10ms -> rad/s -> deg/s
01539     theta_dot *= 100.0;
01540     
01541     // this is pulse/10ms
01542     long x_dot_f = (long) (v_f * cos(theta));
01543     long y_dot_f = (long) (v_f * sin(theta));
01544 
01545     // change to deltas mm and add integrate over time
01546       
01547     //    x_f += (x_dot_f/REB_FIXED_FACTOR) * mmpp_f * t_f;
01548     //    y_f += (y_dot_f/REB_FIXED_FACTOR) * mmpp_f * t_f;
01549 
01550     int base = (mmpp_f * t_f);
01551     x_rem = base * (x_dot_f /100);
01552     assert(ABS(x_rem) <= 0x7FFFFFFF);
01553     x_rem /= 100;
01554 
01555     y_rem = base * (y_dot_f / 100);
01556     assert(ABS(y_rem) <= 0x7FFFFFFF);
01557     y_rem /= 100;
01558 
01559     x_f += x_rem;
01560     y_f += y_rem;
01561 
01562     last_x_f = x_f;
01563     last_y_f = y_f;
01564     last_theta = theta;
01565 
01566     //    printf("REB: x=%d y=%d t=%g lp=%d rp=%d t_f=%d vf=%d xd=%d yd=%d xr=%d yr=%d\n", x_f, y_f, last_theta, lp, rp, t_f, v_f,
01567     //     x_dot_f, y_dot_f, x_rem, y_rem);
01568 
01569     x_f /= REB_FIXED_FACTOR;
01570     y_f /= REB_FIXED_FACTOR;
01571   } else {
01572     // in position mode
01573     int rpos=0, lpos=0;
01574     uint8_t rtar;
01575     int mode, error;
01576     
01577     v = theta_dot= 0.0;
01578 
01579     // now we read the status of the motion controller
01580     // DONT ASK ME -- but calling ReadStatus on the LEFT
01581     // motor seems to cause the REB (the kameleon itself!)
01582     // to freeze some time after issuing a position mode
01583     // command -- happens for RIGHT motor too but
01584     // maybe not as much???
01585     //  ltar = ReadStatus(REB_MOTOR_LEFT, &mode, &error);
01586     
01587     rtar = ReadStatus(REB_MOTOR_RIGHT, &mode, &error);
01588 
01589     target_status = rtar;
01590     // check for on target so we know to update
01591     //    if (!d->position.stall && target_status) {
01592       // then this is a new one, so do an update
01593 
01594       lpos = ReadPos(REB_MOTOR_LEFT);
01595       rpos = -ReadPos(REB_MOTOR_RIGHT);
01596 
01597       lreading = lpos;
01598       rreading = rpos;
01599       double p;
01600 
01601       // take average pos
01602       p = (lpos + rpos) /2.0;
01603       
01604       // now convert to mm
01605       p *= PlayerUBotRobotParams[this->param_index].MMPerPulses;
01606       
01607       // this should be change in theta in rad
01608       theta_dot = (rpos - lpos) *
01609         PlayerUBotRobotParams[this->param_index].MMPerPulses / 
01610         PlayerUBotRobotParams[this->param_index].RobotAxleLength;
01611       
01612       // update our theta
01613       theta += theta_dot;
01614       
01615       // update x & y positions
01616       x += p * cos(theta);
01617       y += p * sin(theta);
01618 
01619       x_f = (long) rint(x);
01620       y_f = (long) rint(y);
01621 
01622   }
01623 
01624   this->current_heading = (int) rint(RAD2DEG(theta));
01625   
01626   // get int rounded angular velocity
01627   int rtd = (int) rint(RAD2DEG(theta_dot));
01628 
01629   // get int rounded trans velocity (in convert from pulses/10ms -> mm/s)
01630   
01631   // need to add the RFF/2 for rounding
01632   long rv  = (v_f/REB_FIXED_FACTOR) *100 * mmpp_f + (REB_FIXED_FACTOR/2);
01633   rv/= REB_FIXED_FACTOR;
01634 
01635   // normalize theta
01636   this->current_heading %= 360;
01637 
01638   // now make theta positive
01639   if (this->current_heading < 0) {
01640     this->current_heading += 360;
01641   }
01642 
01643 #ifdef DEBUG_POS
01644   printf("REB: l%s=%d r%s=%d x=%d y=%d theta=%d trans=%d rot=%d target=%02x\n",
01645          this->velocity_mode ? "vel" : "pos", lreading,
01646          this->velocity_mode ? "vel" : "pos", rreading, 
01647          x_f, y_f, this->current_heading,  rv, rtd, target_status);
01648 #endif
01649 
01650   // now write data
01651   d->xpos = htonl(x_f);
01652   d->ypos = htonl(y_f);
01653   d->yaw = htonl(this->current_heading);
01654   d->xspeed = htonl(rv);
01655   d->yawspeed = htonl( rtd);
01656   d->stall = target_status;
01657 
01658   // later we read the torques FIX
01659 
01660   // update last time
01661   this->last_position = curr;
01662 }
01663 
01664 /* this will set the odometry to a given position
01665  * ****NOTE: assumes that the arguments are in network byte order!*****
01666  *
01667  * returns: 
01668  */
01669 void
01670 REB::SetOdometry(int x, int y, short theta)
01671 {
01672 
01673   SetPosCounter(REB_MOTOR_LEFT, 0);
01674   SetPosCounter(REB_MOTOR_RIGHT, 0);
01675 
01676   last_lpos = 0;
01677   last_rpos = 0;
01678 
01679   last_x_f = ntohl(x)*REB_FIXED_FACTOR;
01680   last_y_f = ntohl(y)*REB_FIXED_FACTOR;
01681 
01682   last_theta = (double) DEG2RAD(ntohs(theta));
01683 
01684   player_position_data_t position_data;
01685   memset(&position_data,0,sizeof(player_position_data_t));
01686   PutMsg(this->position_id,NULL, PLAYER_MSGTYPE_DATA, 0,
01687           (void*)&position_data, sizeof(player_position_data_t), NULL);
01688 }
01689 
01690 /* this will write len bytes from buf out to the serial port reb_fd 
01691  *   
01692  *  returns: the number of bytes written, -1 on error
01693  */
01694 int
01695 REB::write_serial(char *buf, int len)
01696 {
01697   int num, t,i, pret;
01698   
01699 #ifdef DEBUG_SERIAL
01700   printf("WRITE: len=%d: ", len);
01701   for (i =0; i < len; i++) {
01702     if (isspace(buf[i])) {
01703       if (buf[i] == ' ') {
01704         printf("%c", ' ');
01705       } else {
01706         printf("'%02x'", buf[i]);
01707       }
01708     } else {
01709       printf("%c", buf[i]);
01710     }
01711   }
01712   printf("\n");
01713 #endif
01714   
01715   num = 0;
01716   while (num < len) {
01717 
01718     // wait for channel so we can write
01719     pret = poll(&write_pfd, 1, 1000);
01720     
01721     if (pret < 0) {
01722       fprintf(stderr, "REB: write_serial: poll returned error\n");
01723       perror("write_serial");
01724       exit(-1);
01725     } else if (pret == 0) {
01726       fprintf(stderr, "REB: write_serial: poll timed out!\n");
01727       return -1;
01728     }
01729 
01730     t = write(this->reb_fd, buf+num, len-num);
01731     if (t < 0) {
01732       switch(errno) {
01733       case EBADF:
01734         fprintf(stderr, "bad file descriptor!!\n");
01735         break;
01736       }
01737 
01738       fprintf(stderr, "error writing\n");
01739       for (i = 0; i < len; i++) {
01740         fprintf(stderr, "%c (%02x) ", isprint(buf[i]) ? buf[i] : ' ',
01741                buf[i]);
01742       }
01743       fprintf(stderr, "\n");
01744       return -1;
01745     }
01746     
01747 #ifdef _DEBUG
01748     printf("WRITES: wrote %d of %d\n", t, len);
01749 #endif
01750     
01751     num += t;
01752   }
01753   return len;
01754 }
01755 
01756 /* this will read upto len bytes from reb_fd or until it reads the
01757    flag string given by flag (length is flen)
01758 
01759    returns: number of bytes read
01760 */
01761 int
01762 REB::read_serial_until(char *buf, int len, char *flag, int flen)
01763 {
01764   int num=0,t, pret;
01765   
01766   int timeout;
01767 
01768   if (velocity_mode) {
01769     timeout = 500;
01770   } else {
01771     timeout = 1500;
01772   }
01773 #ifdef DEBUG_SERIAL
01774   printf("RSU before while flag len=%d len=%d\n", flen, len);
01775 #endif
01776   
01777   while (num < len-1) {
01778 
01779     // wait for channel to have data first...
01780     pret = poll(&read_pfd, 1, timeout);
01781     
01782     if (pret < 0) {
01783       perror("read_serial_until");
01784       exit(-1);
01785     } else if (pret == 0) {
01786       fprintf(stderr, "REB: read_serial_until timed out!\n");
01787       return -1;
01788     }
01789 
01790 
01791     // now we can read
01792     t = read(this->reb_fd, buf+num, 1);
01793 
01794 #ifdef DEBUG_SERIAL
01795     printf("RSU: %c (%02x)\n", isspace(buf[num]) ? ' ' : buf[num], buf[num]);
01796 #endif
01797     
01798     if (t < 0) {
01799       fprintf(stderr, "error!!!\n");
01800       switch(errno) {
01801       case EAGAIN:
01802         t = 0;
01803         break;
01804       case EINTR:
01805         return -1;
01806       default:
01807         return -1;
01808       }
01809     }
01810     
01811     num ++;
01812     buf[num] = '\0';
01813     if (num >= flen) {
01814       
01815       if (!strcmp(buf+num-flen, flag)) {
01816         return 0;
01817       }
01818     }
01819     
01820     if (num>= 2) {
01821       buf[num] = '\0';
01822       if (strcmp(buf+num-2, "\r\n") == 0) {
01823         num =0;
01824 #ifdef DEBUG_SERIAL
01825         printf("RSU: MATCHED CRLF\n");
01826 #endif
01827       }
01828     }
01829   }
01830   
01831   buf[num] = '\0';
01832   return num;
01833 }
01834 
01835 
01836 /* this will take the given buffer, which should have a command in it,
01837  * and write it to the serial port, then read a response back into the
01838  * buffer
01839  *
01840  * returns: number of bytes read
01841  */
01842 int
01843 REB::write_command(char *buf, int len, int maxsize)
01844 {
01845   static int total=0;
01846   int ret;
01847   char rbuf[256];
01848   int rcount=0;
01849   assert(maxsize < 256);
01850 
01851   while (1) {
01852     ret = read_serial_until(rbuf, 256, REB_COMMAND_PROMPT, strlen(REB_COMMAND_PROMPT));
01853 
01854     total += write_serial(buf, len);
01855 
01856     do {
01857       rcount=0;
01858       ret = read_serial_until(rbuf, maxsize, CRLF, strlen(CRLF));
01859       if (ret < 0) {
01860         Restart();
01861       }
01862     } while (rbuf[0] != tolower(buf[0]) && rcount++ < 2 );
01863 
01864     if (ret < 0) {
01865       Restart();
01866       continue;
01867     }
01868     
01869     total += ret;
01870     break;
01871   }
01872 
01873   memcpy(buf, rbuf, maxsize);
01874   return ret;
01875 }
01876 
01877 /* this sends the restart command to the Kam
01878  *
01879  * returns: 
01880  */
01881 void
01882 REB::Restart()
01883 {
01884   char buf;
01885   int ret=0,pret=0;
01886   
01887   struct pollfd pfd;
01888 
01889   pfd.fd = this->reb_fd;
01890   pfd.events = POLLIN;
01891 
01892   printf("REB: flushing read channel: ");
01893   fflush(stdout);
01894   do {
01895     pret = poll(&pfd, 1, 2000);
01896 
01897     if (pret) {
01898       ret = read(this->reb_fd, &buf, 1);
01899       if (ret) {
01900         if (isalnum(buf)) {
01901           printf("%c", buf);
01902         } else {
01903           printf("%02x", buf);
01904         }
01905       }
01906     } else {
01907       printf("timed out");
01908       break;
01909     }
01910   } while (ret);
01911   printf("\n");
01912   
01913 
01914   // restart the control software on the REB
01915   printf("REB: sending restart...");
01916 
01917   fflush(stdout);
01918   write_serial("\r", strlen("\r"));
01919 
01920   printf("done\n");
01921 }
01922 
01923 /* sets the state of the IR. REB_IR_START (true) turns
01924  * them on, REB_IR_STOP (False) turns em off
01925  *
01926  * returns: 
01927  */
01928 void
01929 REB::SetIRState(int action)
01930 {
01931   char buf[64];
01932  
01933   sprintf(buf, "Y,%c\r", action ? '1' : '0');
01934 
01935   write_command(buf, strlen(buf), sizeof(buf));
01936 }
01937 
01938 /* this will configure the AD channel given.
01939  *  0 == channel OFF
01940  *  1 == channel ON
01941  *  2 == toggle channel state
01942  */
01943 void
01944 REB::ConfigAD(int channel, int action)
01945 {
01946   char buf[64];
01947 
01948   sprintf(buf, "Q,%d,%c\r", channel, '0'+action);
01949 
01950   write_command(buf, strlen(buf), sizeof(buf));
01951 }
01952 
01953 /* this will read the given AD channel
01954  *
01955  * returns: the value of the AD channel
01956  */
01957 unsigned short
01958 REB::ReadAD(int channel) 
01959 {
01960   char buf[64];
01961 
01962   sprintf(buf, "I,%d\r", channel);
01963   write_command(buf, strlen(buf), sizeof(buf));
01964   
01965   return atoi(&buf[2]);
01966 }
01967 
01968 /* reads all the IR values at once.  stores them
01969  * in the uint16_t array given as arg ir
01970  *
01971  * returns: 
01972  */
01973 void
01974 REB::ReadAllIR(uint16_t *ir)
01975 {
01976   char buf[64];
01977   int ret;
01978 
01979   sprintf(buf, "W\r");
01980   ret = write_command(buf, strlen(buf), sizeof(buf));
01981     
01982   int p=0;
01983   for (int i =0; i < PLAYER_IR_MAX_SAMPLES; i++) {
01984     // find the first comma
01985     while (buf[p++] != ',') {
01986       if (p >= (int) strlen(buf)) {
01987         return;
01988       }
01989     }
01990     ir[i] = atoi(&buf[p]);
01991   }
01992 }
01993 
01994 /* this will set the desired speed for the given motor mn
01995  *
01996  * returns:
01997  */
01998 void
01999 REB::SetSpeed(int mn, int speed)
02000 {
02001   char buf[64];
02002   
02003   sprintf(buf, "D,%c,%d\r", '0'+mn, speed);
02004 
02005   write_command(buf, strlen(buf), sizeof(buf));
02006 }
02007 
02008 /* reads the current speed of motor mn
02009  *
02010  * returns: the speed of mn
02011  */
02012 int
02013 REB::ReadSpeed(int mn)
02014 {
02015   char buf[64];
02016   
02017   sprintf(buf, "E,%c\r", '0'+mn);
02018 
02019   write_command(buf, strlen(buf), sizeof(buf));
02020 
02021   return atoi(&buf[2]);
02022 }
02023 
02024 /* this sets the desired position motor mn should go to
02025  *
02026  * returns:
02027  */
02028 void
02029 REB::SetPos(int mn, int pos)
02030 {
02031   char buf[64];
02032   
02033   sprintf(buf,"C,%c,%d\r", '0'+mn,pos);
02034 
02035   write_command(buf, strlen(buf), sizeof(buf));
02036 }
02037 
02038 /* this sets the position counter of motor mn to the given value
02039  *
02040  * returns:
02041  */
02042 void
02043 REB::SetPosCounter(int mn, int pos)
02044 {
02045   char buf[64];
02046  
02047   sprintf(buf,"G,%c,%d\r", '0'+mn,pos);
02048   write_command(buf, strlen(buf), sizeof(buf));
02049 }
02050 
02051 /* this will read the current value of the position counter
02052  * for motor mn
02053  *
02054  * returns: the current position for mn
02055  */
02056 int
02057 REB::ReadPos(int mn)
02058 {
02059   char buf[64];
02060   
02061   sprintf(buf, "H,%c\r", '0'+mn);
02062   write_command(buf, strlen(buf), sizeof(buf));
02063   
02064   return atoi(&buf[2]);
02065 }
02066 
02067 /* this will configure the position PID for motor mn
02068  * using paramters Kp, Ki, and Kd
02069  *
02070  * returns:
02071  */
02072 void
02073 REB::ConfigPosPID(int mn, int kp, int ki, int kd)
02074 { 
02075   char buf[64];
02076 
02077   sprintf(buf, "F,%c,%d,%d,%d\r", '0'+mn, kp,ki,kd);
02078   write_command(buf, strlen(buf), sizeof(buf));
02079 }
02080 
02081 /* this will configure the speed PID for motor mn
02082  *
02083  * returns:
02084  */
02085 void
02086 REB::ConfigSpeedPID(int mn, int kp, int ki, int kd)
02087 {
02088   char buf[64];
02089   
02090   sprintf(buf, "A,%c,%d,%d,%d\r", '0'+mn, kp,ki,kd);
02091   
02092   write_command(buf, strlen(buf), sizeof(buf));
02093 }
02094 
02095 /* this will set the speed profile for motor mn
02096  * it takes the max velocity and acceleration
02097  *
02098  * returns:
02099  */
02100 void
02101 REB::ConfigSpeedProfile(int mn, int speed, int acc)
02102 {
02103   char buf[64];
02104   
02105   sprintf(buf, "J,%c,%d,%d\r", '0'+mn, speed,acc);
02106   write_command(buf, strlen(buf), sizeof(buf));
02107 }
02108 
02109 /* this will read the status of the motion controller.
02110  * mode is set to 1 if in position mode, 0 if velocity mode
02111  * error is set to the position/speed error
02112  *
02113  * returns: target status: 1 is on target, 0 is not on target
02114  */
02115 unsigned char
02116 REB::ReadStatus(int mn, int *mode, int *error)
02117 {
02118   char buf[64];
02119 
02120   sprintf(buf, "K,%c\r", '0'+mn);
02121   write_command(buf, strlen(buf), sizeof(buf));
02122 
02123   // buf now has the form "k,target,mode,error"
02124   int target;
02125 
02126   sscanf(buf, "k,%d,%d,%d", &target, mode, error);
02127 
02128   return (unsigned char)target;
02129 }

Last updated 12 September 2005 21:38:45