er.cc

00001 /*
00002 *  Player - One Hell of a Robot Server
00003 *  Copyright (C) 2000-2003
00004 *
00005 *               David Feil-Seifer
00006 *
00007 *
00008 *  This program is free software; you can redistribute it and/or modify
00009 *  it under the terms of the GNU General Public License as published by
00010 *  the Free Software Foundation; either version 2 of the License, or
00011 *  (at your option) any later version.
00012 *
00013 *  This program is distributed in the hope that it will be useful,
00014 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 *  GNU General Public License for more details.
00017 *
00018 *  You should have received a copy of the GNU General Public License
00019 *  along with this program; if not, write to the Free Software
00020 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 *
00022 */
00023 
00024 /*
00025 *
00026 * Driver for the "ER" robots, made by Evolution Robotics.
00027 *
00028 * Some of this code is borrowed and/or adapted from the player
00029 * module of trogdor; thanks to the author of that module.
00030 */
00031 
00100 #if HAVE_CONFIG_H
00101 #include <config.h>
00102 #endif
00103 
00104 #include "er.h"
00105 #include <errno.h>
00106 #include <fcntl.h>
00107 #include <termios.h>
00108 #include <stdlib.h>
00109 #include <unistd.h>
00110 #include <netinet/in.h>  /* for struct sockaddr_in, htons(3) */
00111 #include <math.h>
00112 #include <string.h>
00113 #include <sys/ioctl.h>
00114 #include <sys/time.h>
00115 
00116 #define DEG2RAD_CONV(x) ((x)*(M_PI/180))
00117 #include <libplayercore/playercore.h>
00118 
00119 static float lastlvel, lastrvel;
00120 
00121 static void StopRobot(void* erdev);
00122 
00123 // initialization function
00124 Driver* ER_Init( ConfigFile* cf, int section)
00125 {
00126   return((Driver*)(new ER(cf, section)));
00127 }
00128 
00129 
00130 // a driver registration function
00131 void
00132     ER_Register(DriverTable* table)
00133 {
00134   table->AddDriver("er1", ER_Init);
00135 }
00136 
00137 ER::ER(ConfigFile* cf, int section)
00138   : Driver(cf, section)
00139 {
00140     // zero ids, so that we'll know later which interfaces were requested
00141   memset(&this->position_id, 0, sizeof(position_id));
00142   this->position_subscriptions = 0;
00143 
00144   printf( "discovering drivers\n" );
00145 
00146     // Do we create a position interface?
00147   if(cf->ReadDeviceAddr(&(this->position_id), section, "provides",
00148     PLAYER_POSITION2D_CODE, -1, NULL) == 0)
00149   {
00150     if(this->AddInterface(this->position_id) != 0)
00151     {
00152       this->SetError(-1);
00153       return;
00154     }
00155   }
00156 
00157     //::initialize_robot_params();
00158 
00159   _fd = -1;
00160   _tc_num = new int[3];
00161   _tc_num[0] = 2;
00162   _tc_num[1] = 0;
00163   _tc_num[2] = 185;
00164   this->_serial_port = cf->ReadString(section, "port", ER_DEFAULT_PORT);
00165 
00166     //read in axle radius
00167   _axle_length = cf->ReadFloat( section, "axle", ER_DEFAULT_AXLE_LENGTH );
00168 
00169     //read in left motor and right motor direction
00170   int dir = cf->ReadInt(section,"motor_dir", 1);
00171   _motor_0_dir = dir * ER_DEFAULT_MOTOR_0_DIR;
00172   _motor_1_dir = dir * ER_DEFAULT_MOTOR_1_DIR;
00173 
00174   _debug = (1 == cf->ReadInt( section, "debug", 0 ));
00175 
00176   _powered = false; // don't send out constant msgs.
00177   _resting = false; // send out *one* 0,0 msg.
00178 }
00179 
00180 
00182       // bus fcns
00184 int
00185     ER::ReadBuf(unsigned char* s, size_t len)
00186 {
00187   int thisnumread;
00188   int errorprinted = 0;
00189   size_t numread = 0;
00190 
00191   for (int i = 0; i < 50; i++) {
00192     usleep (100);
00193     thisnumread = read (this->_fd, s + numread, len - numread);
00194     if (thisnumread > 0) {
00195       numread += thisnumread;
00196       errorprinted = 0;
00197     } else if (thisnumread < 0 && !errorprinted) {
00198       perror ("read");
00199       errorprinted = 1;
00200     } else if (numread != 0) {
00201             // didn't read as many as we hoped. oh well...
00202       return numread;
00203     }
00204         // wait until we read *something*, at least
00205   }
00206 
00207   return 0;
00208 }
00209 
00210 int
00211     ER::WriteBuf(unsigned char* s, size_t len)
00212 {
00213   size_t numwritten;
00214   int thisnumwritten;
00215   numwritten=0;
00216   while(numwritten < len)
00217   {
00218     if((thisnumwritten = write(this->_fd,s+numwritten,len-numwritten)) < 0)
00219     {
00220       if(!this->_fd_blocking && errno == EAGAIN)
00221       {
00222         usleep(ER_DELAY_US);
00223         continue;
00224       }
00225       printf("write() failed: %s\n", strerror(errno));
00226       return(-1);
00227     }
00228     numwritten += thisnumwritten;
00229   }
00230 
00231   ioctl( this->_fd, TIOCMSET, _tc_num );
00232   if( _tc_num[0] == 2 ) { _tc_num[0] = 0; }
00233   else { _tc_num[0] = 2; }
00234 
00235   return numwritten;
00236 }
00237 
00238 int
00239     ER::checksum_ok (unsigned char *buf, int len)
00240 {
00241   unsigned char csum = 0;
00242   for (int i = 0; i < len; i++) {
00243     csum += buf[i];
00244   }
00245   return (csum == 0);
00246 }
00247 
00248 int
00249     ER::send_command( unsigned char address, unsigned char c, int ret_num, unsigned char * ret )
00250 {
00251   unsigned char cmd[4];
00252 
00253   cmd[0] = address;
00254   cmd[2] = 0x00;
00255   cmd[3] = c;
00256 
00257     //compute checksum
00258   int chk = 0x100;
00259   chk -= cmd[0];
00260   chk -= cmd[2];
00261   chk -= cmd[3];
00262 
00263   cmd[1] = (unsigned char) chk;
00264 
00265   if (WriteBuf (cmd, 4) != 4) return -1;
00266   if (ReadBuf (ret, ret_num) <= 0) return -1;
00267 
00268     //  PLAYER_WARN1( "cmd: 0x%4x", *((int *) cmd) );
00269 
00270   return 4;
00271 }
00272 
00273 
00274 
00275 int
00276     ER::send_command_2_arg( unsigned char address, unsigned char c, int arg, int ret_num, unsigned char * ret )
00277 {
00278   unsigned char cmd[6];
00279 
00280   cmd[0] = address;
00281   cmd[2] = 0x00;
00282   cmd[3] = c;
00283 
00284   int a = htons( arg );
00285 
00286   cmd[5] = (a >> 8) & 0xFF;
00287   cmd[4] = (a >> 0) & 0xFF;
00288 
00289     //compute checksum
00290   int chk = 0x100;
00291   chk -= cmd[0];
00292   chk -= cmd[2];
00293   chk -= cmd[3];
00294   chk -= cmd[4];
00295   chk -= cmd[5];
00296 
00297   cmd[1] = (unsigned char) chk;
00298 
00299   if (WriteBuf (cmd, 6) != 6) return -1;
00300   if (ReadBuf (ret, ret_num) <= 0) return -1;
00301 
00302     //  PLAYER_WARN1( "cmd: 0x%4x", *((int *) cmd) );
00303     //  PLAYER_WARN1( "cmd: 0x%4x", *((int *) &(cmd[4])) );
00304   return 6;
00305 }
00306 
00307 int
00308     ER::send_command_4_arg( unsigned char address, unsigned char c, int arg, int ret_num, unsigned char * ret )
00309 {
00310   unsigned char cmd[8];
00311 
00312   cmd[0] = address;
00313   cmd[2] = 0x00;
00314   cmd[3] = c;
00315 
00316   int a = htonl( arg );
00317   cmd[7] = (a >> 24) & 0xFF;
00318   cmd[6] = (a >> 16) & 0xFF;
00319   cmd[5] = (a >> 8 ) & 0xFF;
00320   cmd[4] = (a >> 0 ) & 0xFF;
00321 
00322     //compute checksum
00323   int chk = 0x100;
00324   chk -= cmd[0];
00325   chk -= cmd[2];
00326   chk -= cmd[3];
00327   chk -= cmd[4];
00328   chk -= cmd[5];
00329   chk -= cmd[6];
00330   chk -= cmd[7];
00331 
00332   cmd[1] = (unsigned char) chk;
00333 
00334   if (WriteBuf (cmd, 8) != 8) return -1;
00335   if (ReadBuf (ret, ret_num) <= 0) return -1;
00336 
00337     //  PLAYER_WARN1( "cmd: 0x%4x", *((int *) cmd) );
00338     //  PLAYER_WARN1( "cmd: 0x%4x", *((int *) &(cmd[4])) );
00339 
00340   return 8;
00341 }
00342 
00344 // robot initializations
00346 
00347 int
00348     ER::InitRobot()
00349 {
00350     // initialize the robot
00351   unsigned char buf[6];
00352   usleep(ER_DELAY_US);
00353   if(send_command( MOTOR_0, GETVERSION, 6, buf ) < 0)
00354   {
00355     return -1;
00356   }
00357 
00358   if (!checksum_ok (buf, 6)) {
00359     printf ("invalid checksum\n");
00360     errno = ENXIO;
00361     return -1;
00362   }
00363 
00364   if(send_command( MOTOR_1, GETVERSION, 6, buf ) < 0)
00365   {
00366     return -1;
00367   }
00368 
00369   _tc_num[2] = 25;
00370   _stopped = true;
00371   return(0);
00372 }
00373 
00374 int
00375     ER::InitOdom()
00376 {
00377   unsigned char ret[8];
00378 
00379     //try leaving the getVersion out
00380   send_command( MOTOR_0, RESET, 2, ret );
00381   send_command_2_arg( MOTOR_0, SETMOTORCMD, 0, 2, ret );
00382   send_command_2_arg( MOTOR_0, SETLIMITSWITCHMODE, 0, 2, ret );
00383   send_command_2_arg( MOTOR_0, SETPROFILEMODE, 0x0001, 2, ret );
00384   send_command_4_arg( MOTOR_0, SETVEL, 0, 2, ret );
00385   send_command_4_arg( MOTOR_0, SETACCEL, 0, 2, ret );
00386   send_command_4_arg( MOTOR_0, SETDECEL, 0, 2, ret );
00387 
00388     //same for motor 1
00389   send_command( MOTOR_1, RESET, 2, ret );
00390   send_command_2_arg( MOTOR_1, SETMOTORCMD, 0, 2, ret );
00391   send_command_2_arg( MOTOR_1, SETLIMITSWITCHMODE, 0, 2, ret );
00392   send_command_2_arg( MOTOR_1, SETPROFILEMODE, 0x0001, 2, ret );
00393   send_command_4_arg( MOTOR_1, SETVEL, 0, 2, ret );
00394   send_command_4_arg( MOTOR_1, SETACCEL, 0, 2, ret );
00395   send_command_4_arg( MOTOR_1, SETDECEL, 0, 2, ret );
00396 
00397     //update values
00398   send_command( MOTOR_0, UPDATE, 2, ret );
00399   send_command( MOTOR_1, UPDATE, 2, ret );
00400 
00401   _last_ltics = 0;
00402   _last_rtics = 0;
00403 
00404   return 0;
00405 }
00406 
00407 int
00408     ER::Setup()
00409 {
00410   struct termios term;
00411   int flags;
00412     //int ltics,rtics,lvel,rvel;
00413 
00414   this->_px = this->_py = this->_pa = 0.0;
00415   this->_odom_initialized = false;
00416 
00417   printf("Evolution Robotics evolution_rcm connection initializing (%s)...\n", _serial_port);
00418   fflush(stdout);
00419 
00420     // open it.  non-blocking at first, in case there's no robot
00421   if((this->_fd = open(_serial_port, O_RDWR | O_NONBLOCK, S_IRUSR | S_IWUSR )) < 0 )
00422   {
00423     printf("open() failed: %s\n", strerror(errno));
00424     return(-1);
00425   }
00426 
00427   if(tcgetattr(this->_fd, &term) < 0 )
00428   {
00429     printf("tcgetattr() failed: %s\n", strerror(errno));
00430     close(this->_fd);
00431     this->_fd = -1;
00432     return(-1);
00433   }
00434 
00435   cfmakeraw( &term );
00436   term.c_cc[VTIME] = 20;
00437   term.c_cc[VMIN] = 0;
00438   cfsetispeed(&term, B230400);
00439   cfsetospeed(&term, B230400);
00440   if(tcsetattr(this->_fd, TCSADRAIN, &term) < 0 )
00441   {
00442     printf("tcsetattr() failed: %s\n", strerror(errno));
00443     close(this->_fd);
00444     this->_fd = -1;
00445     return(-1);
00446   }
00447 
00448   _fd_blocking = false;
00449   if(InitRobot() < 0)
00450   {
00451     printf("failed to initialize robot\n");
00452     close(this->_fd);
00453     this->_fd = -1;
00454     return(-1);
00455   }
00456 
00457   /* ok, we got data, so now set NONBLOCK, and continue */
00458   if((flags = fcntl(this->_fd, F_GETFL)) < 0)
00459   {
00460     printf("fcntl() failed: %s\n", strerror(errno));
00461     close(this->_fd);
00462     this->_fd = -1;
00463     return(-1);
00464   }
00465 
00466   flags &= ~O_NONBLOCK;
00467   if(fcntl(this->_fd, F_SETFL, flags) < 0)
00468   {
00469     printf("fcntl() failed: %s\n", strerror(errno));
00470     close(this->_fd);
00471     this->_fd = -1;
00472     return(-1);
00473   }
00474   _fd_blocking = true;
00475 
00476   /*  This might be a good time to reset the odometry values */
00477   if( InitOdom() < 0 ) {
00478     printf("InitOdom failed\n" );
00479     close(this->_fd);
00480     this->_fd = -1;
00481     return -1;
00482   }
00483 
00484     // start the thread to talk with the robot
00485   this->StartThread();
00486 
00487   return(0);
00488 }
00489 
00490 void InvokeMain (void *arg)
00491 {
00492   ER *er = (ER *)arg;
00493   er->Main();
00494 }
00495 
00496 int
00497     ER::Shutdown()
00498 {
00499   if(this->_fd == -1)
00500     return(0);
00501 
00502   StopThread();
00503 
00504     // the robot is stopped by the thread cleanup function StopRobot(), which
00505     // is called as a result of the above StopThread()
00506 
00507   if(SetVelocity(0,0) < 0)
00508     printf("failed to stop robot while shutting down\n");
00509 
00510 
00511   usleep(ER_DELAY_US);
00512 
00513   if(close(this->_fd))
00514     printf("close() failed:%s\n",strerror(errno));
00515   this->_fd = -1;
00516   if( _debug )
00517     printf("ER has been shutdown\n\n");
00518 
00519   return(0);
00520 }
00521 
00522 void
00523     ER::Stop( int StopMode )
00524 {
00525   unsigned char ret[8];
00526 
00527   printf( "Stop\n" );
00528   /* Start with motor 0*/
00529   _stopped = true;
00530   if( StopMode == FULL_STOP )
00531   {
00532     /* motor 0 */
00533     send_command_2_arg( MOTOR_0, RESETEVENTSTATUS, 0x0000, 2, ret );
00534     send_command_2_arg( MOTOR_0, SETMOTORCMD, 0x0000, 2, ret );
00535     send_command_2_arg( MOTOR_0, SETPROFILEMODE, 0x0001, 2, ret );
00536     send_command_2_arg( MOTOR_0, SETSTOPMODE, 0x0001, 2, ret );
00537     send_command_4_arg( MOTOR_0, SETVEL, 0, 2, ret );
00538     send_command_4_arg( MOTOR_0, SETACCEL, 0, 2, ret );
00539     send_command_4_arg( MOTOR_0, SETDECEL, 0, 2, ret );
00540     send_command( MOTOR_0, UPDATE, 2, ret );
00541     send_command( MOTOR_0, RESET, 2, ret );
00542 
00543     /* motor 1 */
00544     send_command_2_arg( MOTOR_1, RESETEVENTSTATUS, 0x0000, 2, ret );
00545     send_command_2_arg( MOTOR_1, SETMOTORCMD, 0x0000, 2, ret );
00546     send_command_2_arg( MOTOR_1, SETPROFILEMODE, 0x0001, 2, ret );
00547     send_command_2_arg( MOTOR_1, SETSTOPMODE, 0x0001, 2, ret );
00548     send_command_4_arg( MOTOR_1, SETVEL, 0, 2, ret );
00549     send_command_4_arg( MOTOR_1, SETACCEL, 0, 2, ret );
00550     send_command_4_arg( MOTOR_1, SETDECEL, 0, 2, ret );
00551     send_command( MOTOR_1, UPDATE, 2, ret );
00552     send_command( MOTOR_1, RESET, 2, ret );
00553   } else {
00554     /* motor 0 */
00555     send_command_2_arg( MOTOR_0, RESETEVENTSTATUS, 0x0700, 2, ret );
00556     send_command_4_arg( MOTOR_0, SETVEL, 0, 2, ret );
00557     send_command( MOTOR_0, UPDATE, 2, ret );
00558     send_command( MOTOR_0, RESET, 2, ret );
00559 
00560     /* motor 1 */
00561     send_command_2_arg( MOTOR_1, RESETEVENTSTATUS, 0x0700, 2, ret );
00562     send_command_4_arg( MOTOR_1, SETVEL, 0, 2, ret );
00563     send_command( MOTOR_1, UPDATE, 2, ret );
00564     send_command( MOTOR_1, RESET, 2, ret );
00565   }
00566 }
00567 
00569 // periodic fcns
00571 
00572 //============================
00573 // function GetOdom
00574 //   - Retrieves tick counts for both wheels
00575 //============================
00576 int ER::GetOdom(int *ltics, int *rtics)
00577 {
00578     // Variable declaration
00579   unsigned char ret[6];
00580 
00581     // Determine number of ticks for motor 0 (left)
00582   send_command( MOTOR_0, GETCMDPOS, 6, ret );
00583   *ltics = _motor_0_dir * BytesToInt32(&(ret[2]));
00584 
00585     // Determine number of ticks for motor 1 (right)
00586   send_command( MOTOR_1, GETCMDPOS, 6, ret );
00587   *rtics = _motor_1_dir * BytesToInt32(&(ret[2]));
00588 
00589     // Output debug (motor tick count) data?
00590   if (_debug)
00591   {
00592     printf("lticks: %d, %2x %2x %2x %2x %2x %2x\n",
00593           *ltics, ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]);
00594     printf("rticks: %d, %2x %2x %2x %2x %2x %2x\n",
00595           *rtics, ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]);
00596   }
00597 
00598     // Read motor 0 again since first response seems to be crap
00599     //   - adding a delay (~75000usec) between reads doesn't help
00600     //   - alternating reads (L,R,R,L or R,L,L,R) causes problems
00601     //   - don't really need to read the other motor, but for completeness
00602 
00603     // Determine number of ticks for motor 0 (left)
00604   send_command( MOTOR_0, GETCMDPOS, 6, ret );
00605   *ltics = _motor_0_dir * BytesToInt32(&(ret[2]));
00606 
00607     // Determine number of ticks for motor 1 (right)
00608   send_command( MOTOR_1, GETCMDPOS, 6, ret );
00609   *rtics = _motor_1_dir * BytesToInt32(&(ret[2]));
00610 
00611     // Output debug (motor tick count) data?
00612   if (_debug)
00613   {
00614     printf("lticks: %d, %2x %2x %2x %2x %2x %2x\n",
00615           *ltics, ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]);
00616     printf("rticks: %d, %2x %2x %2x %2x %2x %2x\n",
00617           *rtics, ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]);
00618   }
00619 
00620     // Output debug (motor tick count) data?
00621   if( _debug )
00622   {
00623     printf("ltics: %d rtics: %d\n", *ltics, *rtics);
00624   }
00625 
00626   return(0);
00627 }
00628 
00629 int
00630     ER::GetBatteryVoltage(int* voltage)
00631 {
00632   unsigned char ret[4];
00633 
00634   send_command_2_arg( MOTOR_1, READANALOG, 0x0001, 6, ret );
00635 
00636   if( _debug )
00637     printf( "voltage?: %f\n", (float) BytesToFloat(&(ret[2])) );
00638 
00639     //yeah and do something with this voltage???
00640 
00641   return(0);
00642 }
00643 
00644 int
00645     ER::GetRangeSensor(int s, float * val )
00646 {
00647   unsigned char ret[6];
00648 
00649   send_command_2_arg( s / 8, READANALOG, s % 8, 6, ret );
00650 
00651   /* this is definately wrong, need to fix this */
00652   float range = (float) BytesToFloat( &(ret[2]) );
00653 
00654   if( _debug )
00655     printf( "sensor value?: %d\n", s );
00656 
00657   val = &range;
00658 
00659   return 0;
00660 }
00661 
00662 
00663 //============================
00664 //
00665 //============================
00666 int
00667     ER::SetVelocity(double lvel, double rvel)
00668 {
00669   lastlvel = lvel;
00670   lastrvel = rvel;
00671 
00672   if (_debug)
00673     printf("Setting velocity to %f %f\n",lvel,rvel);
00674 
00675   if (lvel != 0 || rvel != 0) {
00676     this->_powered = true;
00677   }
00678   this->_resting = false;
00679 
00680   /* fixed the no-stop bug via hack (ES,6/30) */
00681   static bool stopped = false;
00682   if ( (lvel == 0) && (rvel == 0) )
00683   {
00684         // asked to stop moving... are we already stopped?
00685     if (stopped)
00686     {
00687             // already stopped, do not listen to this velocity zero command
00688       return 0;
00689     }
00690         // haven't stopped, we will this time
00691     stopped = true;
00692   } else {
00693         // not stopping
00694     stopped = false;
00695   }
00696   /* hack off */
00697 
00698     // resume normal function!
00699 
00700   unsigned char ret[8];
00701   if( _debug )
00702     printf( "lvel: %f rvel: %f\n", lvel, rvel );
00703 
00704     // Motor 0
00705 
00706   send_command( MOTOR_0, GETEVENTSTATUS, 4, ret );
00707 
00708   if( _stopped )
00709   {
00710     send_command_2_arg( MOTOR_0, RESETEVENTSTATUS, 0x0300, 2, ret );
00711     send_command_2_arg( MOTOR_0, SETMOTORCMD, 0x6590, 2, ret );
00712     send_command_2_arg( MOTOR_0, SETPROFILEMODE, 0x0001, 2, ret );
00713   } else {
00714     send_command_2_arg( MOTOR_0, RESETEVENTSTATUS, 0x0700, 2, ret );
00715   }
00716 
00717   SpeedCommand( MOTOR_0, lvel, _motor_0_dir );
00718 
00719   send_command_4_arg( MOTOR_0, SETACCEL, 0x0000007E, 2, ret );
00720 
00721     // Motor 1
00722 
00723   send_command( MOTOR_1, GETEVENTSTATUS, 4, ret );
00724 
00725   if( _stopped )
00726   {
00727     send_command_2_arg( MOTOR_1, RESETEVENTSTATUS, 0x0300, 2, ret );
00728     send_command_2_arg( MOTOR_1, SETMOTORCMD, 0x6590, 2, ret );
00729     send_command_2_arg( MOTOR_1, SETPROFILEMODE, 0x0001, 2, ret );
00730   } else {
00731     send_command_2_arg( MOTOR_1, RESETEVENTSTATUS, 0x0700, 2, ret );
00732   }
00733 
00734   SpeedCommand( MOTOR_1, rvel, _motor_1_dir );
00735   send_command_4_arg( MOTOR_1, SETACCEL, 0x0000007E, 2, ret );
00736 
00737     // and UPDATE both
00738   send_command( MOTOR_0, UPDATE, 2, ret );
00739   send_command( MOTOR_1, UPDATE, 2, ret );
00740 
00741   _stopped = false;
00742   return 0;
00743 }
00744 
00745 
00746 void
00747     ER::Main()
00748 {
00749   player_position2d_data_t data;
00750   int rtics, ltics;
00751   pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
00752 
00753     // push a pthread cleanup function that stops the robot
00754   pthread_cleanup_push(StopRobot,this);
00755 
00756   for(;;)
00757   {
00758     pthread_testcancel();
00759     ProcessMessages();
00760 
00761     /* get the odometry values */
00762     GetOdom (&ltics, &rtics);
00763     UpdateOdom (ltics, rtics);
00764 
00765         // Current position (odometry)
00766     data.pos.px = this->_px;
00767     data.pos.py = this->_py;
00768     data.pos.pa = this->_pa;
00769 
00770         // Current velocity
00771     data.vel.px = (lastlvel + lastrvel) / 2.0;
00772     data.vel.py = 0;
00773     data.vel.pa = (lastrvel - lastlvel) / _axle_length;
00774 
00775     data.stall = _stopped;
00776 
00777     if (this->_powered || !this->_resting) {
00778       Publish(position_id, PLAYER_MSGTYPE_DATA, PLAYER_POSITION2D_DATA_STATE, &data, sizeof(data), NULL);
00779       if (!this->_powered) this->_resting = true;
00780     }
00781 
00782     usleep (50000);
00783 
00784   } /* for */
00785   pthread_cleanup_pop(1);
00786 }
00787 
00789 // Process an incoming message
00790 int ER::ProcessMessage(QueuePointer & resp_queue,
00791                       player_msghdr * hdr,
00792                       void * data)
00793 {
00794   assert(hdr);
00795   assert(data);
00796 
00797   if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_GET_GEOM, position_id))
00798   {
00799     player_position2d_geom_t geom;
00800 
00801         //TODO : get values from somewhere.
00802     geom.pose.px = -0.1;//htons((short) (-100));
00803     geom.pose.py = 0;//htons((short) (0));
00804     geom.pose.pyaw = 0;//htons((short) (0));
00805     geom.size.sw = 0.25;//htons((short) (250));
00806     geom.size.sl = 0.425;//htons((short) (425));
00807     Publish(position_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_GET_GEOM, &geom, sizeof(geom),NULL);
00808 
00809     return 0;
00810   }
00811 
00812   if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_MOTOR_POWER, position_id))
00813   {
00814     player_position2d_power_config_t * powercfg = reinterpret_cast<player_position2d_power_config_t *> (data);
00815 
00816     printf("got motor power req: %d\n", powercfg->state);
00817     if(ChangeMotorState(powercfg->state) < 0)
00818       Publish(position_id, resp_queue, PLAYER_MSGTYPE_RESP_NACK, PLAYER_POSITION2D_REQ_MOTOR_POWER);
00819     else
00820       Publish(position_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_MOTOR_POWER);
00821     return 0;
00822   }
00823 
00824   if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_SET_ODOM, position_id))
00825   {
00826     player_position2d_set_odom_req_t * odom = (player_position2d_set_odom_req_t *)data;
00827     this->_px = odom->pose.px;
00828     this->_py = odom->pose.py;
00829     this->_pa = odom->pose.pa;
00830     while (this->_pa > M_PI) this->_pa -= M_PI;
00831     while (this->_pa < -M_PI) this->_pa += M_PI;
00832     this->_resting = false;
00833     Publish (position_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_SET_ODOM);
00834     return 0;
00835   }
00836 
00837   if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_RESET_ODOM, position_id))
00838   {
00839     this->_px = 0.0;
00840     this->_py = 0.0;
00841     this->_pa = 0.0;
00842     this->_resting = false;
00843     Publish (position_id, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_RESET_ODOM);
00844     return 0;
00845   }
00846 
00847   if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, PLAYER_POSITION2D_CMD_VEL, position_id) ||
00848       Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, PLAYER_POSITION2D_CMD_CAR, position_id))
00849   {
00850     double velocity, angle;
00851     if (hdr->subtype == PLAYER_POSITION2D_CMD_VEL) {
00852       player_position2d_cmd_vel_t *position_cmd = (player_position2d_cmd_vel_t *)data;
00853       velocity = position_cmd->vel.px;
00854       angle = position_cmd->vel.pa;
00855     } else {
00856       player_position2d_cmd_car_t *carlike_cmd = (player_position2d_cmd_car_t *)data;
00857       velocity = carlike_cmd->velocity;
00858       angle = carlike_cmd->angle;
00859     }
00860 
00861     double rotational_term;
00862     double command_rvel, command_lvel;
00863     double final_lvel = 0, final_rvel = 0;
00864     double last_final_lvel = 0, last_final_rvel = 0;
00865 
00866         // convert (tv,rv) to (lv,rv) and send to robot
00867     rotational_term = angle * _axle_length / 2.0;
00868     command_rvel = velocity + rotational_term;
00869     command_lvel = velocity - rotational_term;
00870 
00871         // sanity check on per-wheel speeds
00872     if (fabs (command_lvel) > ER_MAX_WHEELSPEED) {
00873       command_rvel = command_rvel * ER_MAX_WHEELSPEED / fabs (command_lvel);
00874       command_lvel = command_lvel * ER_MAX_WHEELSPEED / fabs (command_lvel);
00875     }
00876     if (fabs (command_rvel) > ER_MAX_WHEELSPEED) {
00877       command_lvel = command_lvel * ER_MAX_WHEELSPEED / fabs (command_rvel);
00878       command_rvel = command_rvel * ER_MAX_WHEELSPEED / fabs (command_rvel);
00879     }
00880 
00881     final_lvel = command_lvel;
00882     final_rvel = command_rvel;
00883 
00884     if( _debug )
00885       printf( "final_lvel: %f, final_rvel: %f\n", final_lvel, final_rvel );
00886 
00887     if ((final_lvel != last_final_lvel) || (final_rvel != last_final_rvel)) {
00888       if (final_lvel * last_final_lvel < 0 || final_rvel * last_final_rvel < 0) {
00889                 //                              PLAYER_WARN( "Changing motor direction, soft stop\n" );
00890         SetVelocity(0,0);
00891       }
00892       if (SetVelocity (final_lvel, final_rvel) < 0) {
00893         printf ("failed to set velocity\n");
00894         pthread_exit (NULL);
00895       }
00896       if (velocity == 0 && angle == 0)
00897       {
00898         if (_debug) printf ("STOP\n");
00899         Stop (STOP);
00900       }
00901 
00902       last_final_lvel = final_lvel;
00903       last_final_rvel = final_rvel;
00904       MotorSpeed();
00905     }
00906 
00907         // do a hack to stop the vehicle if the speeds are zero (ES, 6/30)
00908     if( (velocity == 0) && (angle == 0) )
00909     {
00910             //                  printf( "implicit stop\n" );
00911       SetVelocity(0,0);
00912     }
00913 
00914     return 0;
00915   }
00916 
00917   return -1;
00918 }
00919 
00920 
00921 
00923 // util fcns
00925 
00926 void
00927     ER::MotorSpeed()
00928 {
00929   unsigned char ret[8];
00930 
00931   send_command( MOTOR_0, GETEVENTSTATUS, 4, ret );
00932   send_command_2_arg( MOTOR_0, RESETEVENTSTATUS, 0x0700, 2, ret );
00933   send_command_4_arg( MOTOR_0, SETACCEL, 0x0000007A, 2, ret );
00934   send_command( MOTOR_1, GETEVENTSTATUS, 4, ret );
00935   send_command_2_arg( MOTOR_1, RESETEVENTSTATUS, 0x0700, 2, ret );
00936   send_command_4_arg( MOTOR_1, SETACCEL, 0x0000007A, 2, ret );
00937 
00938   send_command( MOTOR_0, UPDATE, 2, ret );
00939   send_command( MOTOR_1, UPDATE, 2, ret );
00940 }
00941 
00942 void
00943     ER::SpeedCommand( unsigned char address, double speed, int dir ) {
00944 
00945   unsigned char ret[2];
00946 
00947   int whole = dir * (int) (speed / ER_M_PER_TICK);
00948 
00949   send_command_4_arg( address, SETVEL, whole, 2, ret );
00950 
00951     //  printf( "speed: %f checksum: 0x%02x value: 0x%08x\n", speed, cmd[1], whole );
00952     }
00953 
00954     int
00955         ER::BytesToInt32(unsigned char *ptr)
00956     {
00957       unsigned char char0,char1,char2,char3;
00958       int data = 0;
00959 
00960       char0 = ptr[3];
00961       char1 = ptr[2];
00962       char2 = ptr[1];
00963       char3 = ptr[0];
00964 
00965       data |=  ((int)char0)        & 0x000000FF;
00966       data |= (((int)char1) << 8)  & 0x0000FF00;
00967       data |= (((int)char2) << 16) & 0x00FF0000;
00968       data |= (((int)char3) << 24) & 0xFF000000;
00969 
00970     //this could just be ntohl
00971 
00972       return data;
00973     }
00974 
00975     float
00976         ER::BytesToFloat(unsigned char *ptr)
00977     {
00978       float res;
00979       int intermediate = BytesToInt32 (ptr);
00980       memcpy(&res,&intermediate,sizeof(res));
00981       return res;
00982     }
00983 
00984     int
00985         ER::ComputeTickDiff(int from, int to)
00986     {
00987       int diff1, diff2;
00988 
00989     // find difference in two directions and pick shortest
00990       if(to > from)
00991       {
00992         diff1 = to - from;
00993         diff2 = (-ER_MAX_TICKS - from) + (to - ER_MAX_TICKS);
00994       }
00995       else
00996       {
00997         diff1 = to - from;
00998         diff2 = (from - ER_MAX_TICKS) + (-ER_MAX_TICKS - to);
00999       }
01000 
01001       if(abs(diff1) < abs(diff2))
01002         return(diff1);
01003       else
01004         return(diff2);
01005 
01006       return 0;
01007     }
01008 
01009     void
01010         ER::UpdateOdom(int ltics, int rtics)
01011     {
01012       int ltics_delta, rtics_delta;
01013       double l_delta, r_delta, a_delta, d_delta;
01014       int max_tics;
01015       static struct timeval lasttime;
01016       struct timeval currtime;
01017       double timediff;
01018 
01019       if(!this->_odom_initialized)
01020       {
01021         this->_last_ltics = ltics;
01022         this->_last_rtics = rtics;
01023         gettimeofday(&lasttime,NULL);
01024         this->_odom_initialized = true;
01025         return;
01026       }
01027 
01028     //  ltics_delta = ComputeTickDiff(this->_last_ltics,ltics);
01029     //  rtics_delta = ComputeTickDiff(this->_last_rtics,rtics);
01030       ltics_delta = ltics - this->_last_ltics;
01031       rtics_delta = rtics - this->_last_rtics;
01032 
01033       gettimeofday(&currtime,NULL);
01034       timediff = (currtime.tv_sec + currtime.tv_usec/1e6) - (lasttime.tv_sec + lasttime.tv_usec/1e6);
01035       max_tics = (int)rint(ER_MAX_WHEELSPEED / ER_M_PER_TICK / timediff);
01036       lasttime = currtime;
01037 
01038       if( _debug ) {
01039         printf("ltics: %d\trtics: %d\n", ltics,rtics);
01040         printf("ldelt: %d\trdelt: %d\n", ltics_delta, rtics_delta);
01041       }
01042 
01043       l_delta = ltics_delta * ER_M_PER_TICK;
01044       r_delta = rtics_delta * ER_M_PER_TICK;
01045 
01046       a_delta = (r_delta - l_delta) / _axle_length;
01047       d_delta = (l_delta + r_delta) / 2.0;
01048 
01049       this->_px += d_delta * cos(this->_pa + (a_delta / 2));
01050       this->_py += d_delta * sin(this->_pa + (a_delta / 2));
01051       this->_pa += a_delta;
01052       while (this->_pa > M_PI) this->_pa -= 2*M_PI;
01053       while (this->_pa < -M_PI) this->_pa += 2*M_PI;
01054 
01055       if( _debug ) {
01056         printf("er: pose: %f,%f,%f\n", this->_px,this->_py,this->_pa);
01057       }
01058       this->_last_ltics = ltics;
01059       this->_last_rtics = rtics;
01060     }
01061 
01062 
01063     int
01064         ER::ChangeMotorState(int state)
01065     {
01066       if (!state) {
01067         SetVelocity (0, 0);
01068         this->_powered = false;
01069       } else {
01070         this->_powered = true;
01071       }
01072       return 0;
01073     }
01074 
01075     static void
01076         StopRobot(void* erdev)
01077     {
01078       ER* er = (ER*)erdev;
01079 
01080       er->Stop (FULL_STOP);
01081     }
01082 

Last updated 12 September 2005 21:38:45