wbr914.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 /*
00024  *
00025  *   The White Box Robotics Model 914 robot
00026  *
00027  */
00028 
00029 
00104 #ifdef HAVE_CONFIG_H
00105   #include "config.h"
00106 #endif
00107 
00108 #include <unistd.h>
00109 #include <inttypes.h>
00110 #include <stdio.h>
00111 #include <string.h>
00112 #include <math.h>
00113 #include <stdlib.h>  /* for abs() */
00114 
00115 #include <fcntl.h>
00116 #include <linux/serial.h>
00117 #include <signal.h>
00118 #include <sys/stat.h>
00119 #include <sys/types.h>
00120 #include <netinet/in.h>
00121 #include <termio.h>
00122 #include <termios.h>
00123 #include <sys/socket.h>
00124 #include <netinet/tcp.h>
00125 #include <netdb.h>
00126 
00127 #include "wbr914.h"
00128 
00129 #undef PLAYER_MSG0
00130 #define PLAYER_MSG0(a,b) LogMe(b)
00131 
00132 static void LogMe( const char* s )
00133 {
00134   FILE* fp = fopen( "plog", "a+" );
00135   fprintf( fp, s );
00136   fclose( fp );
00137 }
00138 
00139 
00140 
00141 Driver* wbr914_Init(ConfigFile* cf, int section)
00142 {
00143   return (Driver*)(new wbr914(cf,section));
00144 }
00145 
00146 void wbr914_Register(DriverTable* table)
00147 {
00148   table->AddDriver("wbr914", wbr914_Init);
00149 }
00150 
00151 wbr914::wbr914(ConfigFile* cf, int section)
00152   : Driver(cf,section,true,PLAYER_MSGQUEUE_DEFAULT_MAXLEN),
00153     _tioChanged( false ),
00154     _stopped( true ), _motorsEnabled( false ), _lastDigOut( 0 )
00155 {
00156   last_lpos = 0;
00157   last_rpos = 0;
00158 
00159   // Baud rate
00160   _baud = 416666;
00161 
00162   ErrorInit( 9 );
00163 
00164   // zero ids, so that we'll know later which interfaces were
00165   // requested
00166   memset(&this->position_id, 0, sizeof(player_devaddr_t));
00167   memset(&this->ir_id, 0, sizeof(player_devaddr_t));
00168 
00169   memset(&this->last_position_cmd, 0, sizeof(player_position2d_cmd_vel_t));
00170 
00171  this->position_subscriptions = 0;
00172   this->ir_subscriptions       = 0;
00173 
00174   // Do we create a robot position interface?
00175   if(cf->ReadDeviceAddr(&(this->position_id), section, "provides",
00176                         PLAYER_POSITION2D_CODE, -1, NULL) == 0)
00177   {
00178     if(this->AddInterface(this->position_id) != 0)
00179     {
00180       this->SetError(-1);
00181       return;
00182     }
00183   }
00184 
00185   // Do we create an ir interface?
00186   if(cf->ReadDeviceAddr(&(this->ir_id), section, "provides",
00187                       PLAYER_IR_CODE, -1, NULL) == 0)
00188   {
00189     if(this->AddInterface(this->ir_id) != 0)
00190     {
00191       this->SetError(-1);
00192       return;
00193     }
00194   }
00195 
00196   // Do we create an Analog I/O interface?
00197   if(cf->ReadDeviceAddr(&(this->aio_id), section, "provides",
00198                       PLAYER_AIO_CODE, -1, NULL) == 0)
00199   {
00200     if(this->AddInterface(this->aio_id) != 0)
00201     {
00202       this->SetError(-1);
00203       return;
00204     }
00205   }
00206 
00207   // Do we create a Digital I/O interface?
00208   if(cf->ReadDeviceAddr(&(this->dio_id), section, "provides",
00209                       PLAYER_DIO_CODE, -1, NULL) == 0)
00210   {
00211     if(this->AddInterface(this->dio_id) != 0)
00212     {
00213       this->SetError(-1);
00214       return;
00215     }
00216   }
00217 
00218 
00219   // Read config file options
00220   _serial_port = cf->ReadString(section,"port",DEFAULT_M3_PORT);
00221   _percentTorque = cf->ReadInt(section,"torque", DEFAULT_PERCENT_TORQUE );
00222   _debug = cf->ReadInt(section,"debug",0 );
00223   _fd = -1;
00224 
00225   // Constrain torque (power to motor phases) between 0 and 100.
00226   // Smaller numbers mean less torque, but less power used and less
00227   // heat generated. Not much use reducing the torque setting below
00228   // 20%.
00229   if ( _percentTorque > 100 )
00230   {
00231     _percentTorque = 100;
00232   }
00233   else if ( _percentTorque < 20 )
00234   {
00235     _percentTorque = 20;
00236   }
00237 
00238   // Set up the robot geometry
00239 
00240   memset(&_robot2d_geom, 0, sizeof(_robot2d_geom));
00241   // X location in meters
00242 //   _robot2d_geom.pose.px     = 0.0;
00243   // Y location in meters
00244 //   _robot2d_geom.pose.py     = 0.0;
00245   // yaw in rads
00246 //   _robot2d_geom.pose.pyaw     = 0.0;
00247 
00248   // Width in meters
00249   _robot2d_geom.size.sw     = 0.37;
00250   // Length in meters
00251   _robot2d_geom.size.sl     = 0.42;
00252   _robot2d_geom.size.sh     = 0.3;
00253 
00254   _robot3d_geom.pose             = _robot2d_geom.pose;
00255   _robot3d_geom.size             = _robot2d_geom.size;
00256 
00257 /*
00258   _robot3d_geom.size.sw     = _robot2d_geom.size.sw;
00259   _robot3d_geom.size.sl     = _robot2d_geom.size.sl;
00260   _robot3d_geom.size.sh     = 0.3;*/
00261 
00262   // Set up the IR array geometry
00263   _ir_geom.poses_count = NUM_IR_SENSORS;
00264   _ir_geom.poses = new player_pose3d_t[_ir_geom.poses_count];
00265 
00266   _ir_geom.poses[ 0 ].px = 0.030;
00267   _ir_geom.poses[ 0 ].py = -0.190;
00268   _ir_geom.poses[ 0 ].pyaw = DTOR( -90 );
00269 
00270   _ir_geom.poses[ 1 ].px = 0.190;
00271   _ir_geom.poses[ 1 ].py = -0.090;
00272   _ir_geom.poses[ 1 ].pyaw = DTOR( -30 );
00273 
00274   _ir_geom.poses[ 2 ].px = 0.210;
00275   _ir_geom.poses[ 2 ].py = 0.0;
00276   _ir_geom.poses[ 2 ].pyaw = DTOR( 0 );
00277 
00278   _ir_geom.poses[ 3 ].px = 0.190;
00279   _ir_geom.poses[ 3 ].py = 0.090;
00280   _ir_geom.poses[ 3 ].pyaw = DTOR( 30 );
00281 
00282   _ir_geom.poses[ 4 ].px = 0.030;
00283   _ir_geom.poses[ 4 ].py = 0.190;
00284   _ir_geom.poses[ 4 ].pyaw = DTOR( 90 );
00285 
00286   // These 3 sensor have a z value of 0.35m and a pitch of 30 degrees down
00287   // This type of pose is not currently handled by Player so do the best we
00288   // can with what we have.
00289   _ir_geom.poses[ 5 ].px = 0.200;
00290   _ir_geom.poses[ 5 ].py = -0.060;
00291   _ir_geom.poses[ 5 ].pyaw = DTOR( -60 );
00292 
00293   _ir_geom.poses[ 6 ].px = 0.210;
00294   _ir_geom.poses[ 6 ].py = 0.0;
00295   _ir_geom.poses[ 6 ].pyaw = DTOR( 0 );
00296 
00297   _ir_geom.poses[ 7 ].px = 0.200;
00298   _ir_geom.poses[ 7 ].py = 0.060;
00299   _ir_geom.poses[ 7 ].pyaw = DTOR( 60 );
00300   
00301   _data.ir.ranges_count = NUM_IR_SENSORS;
00302   _data.ir.voltages_count = _data.ir.ranges_count;
00303   _data.ir.ranges = new float [_data.ir.ranges_count];
00304   _data.ir.voltages = new float [_data.ir.voltages_count];
00305   
00306 }
00307 
00311 wbr914::~wbr914()
00312 {
00313   if ( _tioChanged )
00314     tcsetattr( this->_fd, TCSADRAIN, &_old_tio);
00315   Shutdown();
00316   delete [] _ir_geom.poses;
00317   delete [] _data.ir.ranges;
00318   delete [] _data.ir.voltages;
00319   
00320 }
00321 
00322 int wbr914::Setup()
00323 {
00324   struct termios term;
00325   int flags;
00326   //int ltics,rtics,lvel,rvel;
00327 
00328   printf( "Initializing White Box Robotics Controller on %s...\n", _serial_port);
00329   fflush(stdout);
00330 
00331   PLAYER_MSG0( 0, "Starting WBR driver\n" );
00332 
00333   // open it.  non-blocking at first, in case there's no robot
00334   if((this->_fd = open(_serial_port, O_RDWR | O_NOCTTY, S_IRUSR | S_IWUSR )) < 0 )
00335   {
00336     printf("open() failed: %s\n", strerror(errno));
00337     return(-1);
00338   }
00339 
00340   if(tcgetattr(this->_fd, &term) < 0 )
00341   {
00342     printf("tcgetattr() failed: %s\n", strerror(errno));
00343     close(this->_fd);
00344     this->_fd = -1;
00345     return(-1);
00346   }
00347 
00348   tcgetattr( this->_fd, &_old_tio);
00349 
00350   cfmakeraw( &term );
00351   cfsetispeed( &term, B38400 );
00352   cfsetospeed( &term, B38400 );
00353 
00354   // 2 stop bits
00355   term.c_cflag |= CSTOPB | CLOCAL | CREAD;
00356   term.c_iflag |= IGNPAR;
00357 
00358   // Set timeout to .1 sec
00359   term.c_cc[ VTIME ] = 1;
00360   term.c_cc[ VMIN ]  = 0;
00361 
00362   if(tcsetattr(this->_fd, TCSADRAIN, &term) < 0 )
00363   {
00364     printf("tcsetattr() failed: %s\n", strerror(errno));
00365     close(this->_fd);
00366     this->_fd = -1;
00367     return(-1);
00368   }
00369 
00370   _tioChanged = true;
00371 
00372   {
00373     struct serial_struct serial_info;
00374 
00375     if ( ioctl( _fd, TIOCGSERIAL, &serial_info ) < 0)
00376     {
00377       // get the serial info
00378       perror("config_serial_port: ioctl TIOCGSERIAL");
00379       return(-1);
00380     }
00381 
00382     // Custom baud rate of 416666 baud, the max the
00383     // motor controller will handle.
00384     // round off to get the closest divisor.
00385     serial_info.flags = ASYNC_SPD_CUST | ASYNC_LOW_LATENCY;
00386     serial_info.custom_divisor = (int)((float)24000000.0/(float)_baud + 0.5);
00387     if ( _debug )
00388       printf( "Custom divisor = %d\n", serial_info.custom_divisor );
00389 
00390     if ( ioctl( _fd, TIOCSSERIAL, &serial_info ) < 0)
00391     {
00392       perror("config_serial_port: ioctl TIOCSSERIAL");
00393       return(-1);
00394     }
00395   }
00396 
00397   _fd_blocking = false;
00398 
00399   if ( _debug )
00400     printf( "InitRobot\n" );
00401   fflush(stdout);
00402   if(InitRobot() < 0)
00403   {
00404     printf("failed to initialize robot\n");
00405     close(this->_fd);
00406     this->_fd = -1;
00407     return(-1);
00408   }
00409 
00410   /* ok, we got data, so now set NONBLOCK, and continue */
00411   if((flags = fcntl(this->_fd, F_GETFL)) < 0)
00412   {
00413     printf("fcntl() failed: %s\n", strerror(errno));
00414     close(this->_fd);
00415     this->_fd = -1;
00416     return(-1);
00417   }
00418 
00419   if(fcntl(this->_fd, F_SETFL, flags ^ O_NONBLOCK) < 0)
00420   {
00421     printf("fcntl() failed: %s\n", strerror(errno));
00422     close(this->_fd);
00423     this->_fd = -1;
00424     return(-1);
00425   }
00426   _fd_blocking = true;
00427 
00428   _usCycleTime = 154;
00429 
00430   unsigned char ret[4];
00431   if( sendCmd0( LEFT_MOTOR, GETSAMPLETIME, 4,ret ) < 0)
00432   {
00433     printf("failed to get cycle time\n");
00434     return -1;
00435   }
00436   _usCycleTime = BytesToInt16( &(ret[2]) );
00437 
00438   _velocityK = (GEAR_RATIO * MOTOR_TICKS_PER_REV * _usCycleTime * 65536)/(WHEEL_CIRC * 1000000);
00439 
00440   SetMicrosteps();
00441 
00442   // PWM sign magnitude mode
00443   if ( (sendCmd16( LEFT_MOTOR, SETOUTPUTMODE, 1, 2, ret ) < 0 ) ||
00444        (sendCmd16( RIGHT_MOTOR, SETOUTPUTMODE, 1, 2, ret ) < 0 ))
00445   {
00446     printf( "Error setting sign-magnitude mode\n" );
00447   }
00448   
00449   /*  This might be a good time to reset the odometry values */
00450   if ( _debug )
00451     printf( "ResetRawPositions\n" );
00452   fflush( stdout );
00453   ResetRawPositions();
00454 
00455   if ( _debug )
00456     printf( "SetAccelerationProfile\n" );
00457   SetAccelerationProfile();
00458   UpdateM3();
00459 
00460   /* now spawn reading thread */
00461   if ( _debug )
00462     printf( "Starting Thread...\n" );
00463   StartThread();
00464   return(0);
00465 }
00466 
00467 int wbr914::InitRobot()
00468 {
00469 
00470   // initialize the robot
00471   unsigned char buf[6];
00472   usleep( DELAY_US);
00473 
00474   if ( (sendCmd0( LEFT_MOTOR, RESET, 2, buf )<0 ) ||
00475        (sendCmd0( RIGHT_MOTOR, RESET, 2, buf )<0 ))
00476   {
00477     printf( "Error Resetting motors\n" );
00478   }
00479 
00480   if ( _debug )
00481     printf( "GetVersion\n" );
00482   if( (sendCmd0( LEFT_MOTOR, GETVERSION, 6, buf ) < 0)||
00483       (sendCmd0( RIGHT_MOTOR, GETVERSION, 6, buf )<0 ))
00484   {
00485     printf("Cannot get version\n");
00486     return -1;
00487   }
00488 
00489   _stopped = true;
00490   return(0);
00491 }
00492 
00493 
00494 int wbr914::Shutdown()
00495 {
00496   if( this->_fd == -1 )
00497     return(0);
00498 
00499   // Stop any more processing
00500   StopThread();
00501 
00502   // Stop the robot
00503   StopRobot();
00504 
00505   EnableMotors( false );
00506 
00507   // Close the connection to the M3
00508   int fd = _fd;
00509   this->_fd = -1;
00510   close( fd );
00511 
00512   puts( "914 has been shut down" );
00513 
00514   return(0);
00515 }
00516 
00517 int wbr914::Subscribe( player_devaddr_t id )
00518 {
00519   // do the subscription
00520   int rc = Driver::Subscribe(id);
00521 
00522   if( rc == 0)
00523   {
00524     // also increment the appropriate subscription counter
00525     if(Device::MatchDeviceAddress(id, this->position_id))
00526     {
00527       this->position_subscriptions++;
00528     }
00529     else if(Device::MatchDeviceAddress(id, this->ir_id))
00530     {
00531       this->ir_subscriptions++;
00532     }
00533     else if(Device::MatchDeviceAddress(id, this->aio_id))
00534     {
00535       this->aio_subscriptions++;
00536     }
00537     else if(Device::MatchDeviceAddress(id, this->dio_id))
00538     {
00539       this->dio_subscriptions++;
00540     }
00541   }
00542 
00543   return( rc );
00544 }
00545 
00546 int wbr914::Unsubscribe( player_devaddr_t id )
00547 {
00548   int shutdownResult = Driver::Unsubscribe(id);
00549 
00550   // do the unsubscription
00551   // and decrement the appropriate subscription counter
00552   if( shutdownResult == 0 )
00553   {
00554     if(Device::MatchDeviceAddress(id, this->position_id))
00555     {
00556       this->position_subscriptions--;
00557       assert(this->position_subscriptions >= 0);
00558     }
00559     else if(Device::MatchDeviceAddress(id, this->ir_id))
00560     {
00561       this->ir_subscriptions--;
00562       assert(this->ir_subscriptions >= 0);
00563     }
00564     else if(Device::MatchDeviceAddress(id, this->aio_id))
00565     {
00566       this->aio_subscriptions--;
00567       assert(this->aio_subscriptions >= 0);
00568     }
00569     else if(Device::MatchDeviceAddress(id, this->dio_id))
00570     {
00571       this->dio_subscriptions--;
00572       assert(this->dio_subscriptions >= 0);
00573     }
00574   }
00575 
00576   return(shutdownResult);
00577 }
00578 
00579 void wbr914::PublishData(void)
00580 {
00581   // TODO: something smarter about timestamping.
00582 
00583   if ( position_subscriptions )
00584   {
00585     // put odometry data
00586     this->Publish(this->position_id,
00587                   PLAYER_MSGTYPE_DATA,
00588                   PLAYER_POSITION2D_DATA_STATE,
00589                   (void*)&(this->_data.position),
00590                   sizeof(player_position2d_data_t),
00591                   NULL);
00592   }
00593 
00594   if ( ir_subscriptions )
00595   {
00596     // put ir data
00597     this->Publish(this->ir_id,
00598                   PLAYER_MSGTYPE_DATA,
00599                   PLAYER_IR_DATA_RANGES,
00600                   (void*)&(_data.ir),
00601                   sizeof(_data.ir),
00602                   NULL);
00603   }
00604 
00605   if ( aio_subscriptions )
00606   {
00607     // put Analog Input data
00608     this->Publish(this->aio_id,
00609                   PLAYER_MSGTYPE_DATA,
00610                   PLAYER_AIO_DATA_STATE,
00611                   (void*)&(_data.aio),
00612                   sizeof(_data.aio),
00613                   NULL);
00614   }
00615 
00616   if ( dio_subscriptions )
00617   {
00618     // put Digital Input data
00619     this->Publish(this->dio_id,
00620                   PLAYER_MSGTYPE_DATA,
00621                   PLAYER_DIO_DATA_VALUES,
00622                   (void*)&(_data.dio),
00623                   sizeof(_data.dio),
00624                   NULL);
00625   }
00626 }
00627 
00628 void wbr914::Main()
00629 {
00630   int last_position_subscrcount=0;
00631 
00632   if ( _debug )
00633     PLAYER_MSG0( 0, "Main\n" );
00634 
00635   for(;;)
00636   {
00637     pthread_testcancel();
00638 
00639     // we want to reset the odometry and enable the motors if the first
00640     // client just subscribed to the position device, and we want to stop
00641     // and disable the motors if the last client unsubscribed.
00642     if(!last_position_subscrcount && this->position_subscriptions)
00643     {
00644       this->EnableMotors( false );
00645       this->ResetRawPositions();
00646     }
00647     else if(last_position_subscrcount && !(this->position_subscriptions))
00648     {
00649       // enable motor power
00650       if ( _debug )
00651         PLAYER_MSG0( 0, "enabling motors\n" );
00652       this->EnableMotors( true );
00653     }
00654     last_position_subscrcount = this->position_subscriptions;
00655 
00656     this->Unlock();
00657 
00658     // handle pending messages
00659     if(!this->InQueue->Empty())
00660     {
00661       if ( _debug )
00662         PLAYER_MSG0( 0, "processing messages\n" );
00663       ProcessMessages();
00664     }
00665     else
00666     {
00667       // if no pending msg, resend the last position cmd.
00668       // TODO: check if this is initialized
00669       //      this->HandlePositionCommand( this->last_position_cmd );
00670     }
00671 
00672     if ( _debug )
00673       PLAYER_MSG0( 0, "GetAllData\n" );
00674 
00675     GetAllData();
00676 
00677     if ( _debug )
00678       PLAYER_MSG0( 0, "PublishData\n" );
00679 
00680     PublishData();
00681   }
00682 }
00683 
00684 int wbr914::ProcessMessage(QueuePointer &resp_queue,
00685                            player_msghdr * hdr,
00686                            void * data)
00687 {
00688   // Look for configuration requests
00689   if(hdr->type == PLAYER_MSGTYPE_REQ)
00690     return(this->HandleConfig(resp_queue,hdr,data));
00691   else if(hdr->type == PLAYER_MSGTYPE_CMD)
00692     return(this->HandleCommand(hdr,data));
00693 
00694 
00695   return(-1);
00696 }
00697 
00698 int wbr914::HandleConfig(QueuePointer &resp_queue,
00699                          player_msghdr * hdr,
00700                          void * data)
00701 {
00702   if ( _debug )
00703     printf( "HandleConfig\n" );
00704 
00705   // check for position config requests
00706   if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
00707                            PLAYER_POSITION2D_REQ_SET_ODOM,
00708                            this->position_id))
00709   {
00710     if(hdr->size != sizeof(player_position2d_set_odom_req_t))
00711     {
00712       PLAYER_WARN("Arg to odometry set requests wrong size; ignoring");
00713       return(-1);
00714     }
00715 
00716     SetOdometry( (player_position2d_set_odom_req_t*)data );
00717     Publish( position_id, resp_queue,
00718              PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_SET_ODOM);
00719     UpdateM3();
00720     return(0);
00721   }
00722   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
00723                                 PLAYER_POSITION2D_REQ_MOTOR_POWER,
00724                                 this->position_id))
00725   {
00726     /* motor state change request
00727      *   1 = enable motors
00728      *   0 = disable motors (default)
00729      */
00730     if(hdr->size != sizeof(player_position2d_power_config_t))
00731     {
00732       PLAYER_WARN("Arg to motor state change request wrong size; ignoring");
00733       return(-1);
00734     }
00735     player_position2d_power_config_t* power_config =
00736             (player_position2d_power_config_t*)data;
00737     this->EnableMotors( power_config->state == 1 );
00738 
00739     this->Publish(this->position_id, resp_queue,
00740                   PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_MOTOR_POWER);
00741     UpdateM3();
00742     return(0);
00743   }
00744   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
00745                                 PLAYER_POSITION2D_REQ_RESET_ODOM,
00746                                 this->position_id))
00747   {
00748     /* reset position to 0,0,0: no args */
00749     if(hdr->size != 0)
00750     {
00751       PLAYER_WARN("Arg to reset position request is wrong size; ignoring");
00752       return(-1);
00753     }
00754     ResetRawPositions();
00755 
00756     this->Publish(this->position_id, resp_queue,
00757                   PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_RESET_ODOM);
00758     UpdateM3();
00759     return(0);
00760   }
00761   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
00762                                 PLAYER_POSITION2D_REQ_GET_GEOM,
00763                                 this->position_id))
00764   {
00765     /* Return the robot geometry. */
00766     if(hdr->size != 0)
00767     {
00768       PLAYER_WARN("Arg get robot geom is wrong size; ignoring");
00769       return(-1);
00770     }
00771 
00772     Publish(this->position_id, resp_queue,
00773             PLAYER_MSGTYPE_RESP_ACK,
00774             PLAYER_POSITION2D_REQ_GET_GEOM,
00775             (void*)&_robot2d_geom, sizeof(_robot2d_geom), NULL);
00776     return(0);
00777   }
00778   else if(Message::MatchMessage(hdr,PLAYER_MSGTYPE_REQ,
00779                                 PLAYER_IR_REQ_POSE,
00780                                 ir_id))
00781   {
00782     /* Return the ir pose info */
00783     Publish( ir_id, resp_queue,
00784              PLAYER_MSGTYPE_RESP_ACK,
00785              hdr->subtype,
00786              (void*)&_ir_geom, sizeof( _ir_geom ), NULL);
00787     return(0);
00788   }
00789   else
00790   {
00791     PLAYER_WARN("unknown config request to wbr914 driver");
00792     return(-1);
00793   }
00794 }
00795 
00796 int wbr914::HandleCommand(player_msghdr * hdr, void* data)
00797 {
00798   if(Message::MatchMessage(hdr,
00799                            PLAYER_MSGTYPE_CMD,
00800                            PLAYER_POSITION2D_CMD_VEL,
00801                            this->position_id))
00802   {
00803     /*
00804     struct timeval now;
00805     gettimeofday( &now, NULL );
00806     double t = now.tv_sec + now.tv_usec/1e9;
00807     printf( "Vel cmd at %lf\n", t );
00808     */
00809     HandleVelocityCommand( (player_position2d_cmd_vel_t*)data );
00810     UpdateM3();
00811     return(0);
00812   }
00813   else if ( Message::MatchMessage(hdr,
00814                                   PLAYER_MSGTYPE_CMD,
00815                                   PLAYER_DIO_CMD_VALUES,
00816                                   this->dio_id))
00817   {
00818     HandleDigitalOutCommand( (player_dio_data_t*)data );
00819     return(0);
00820   }
00821 
00822 
00823   return(-1);
00824 }
00825 
00826 void wbr914::HandleVelocityCommand(player_position2d_cmd_vel_t* velcmd)
00827 {
00828   // need to calculate the left and right velocities
00829   float trans = velcmd->vel.px;
00830   float rot = velcmd->vel.pa * DEFAULT_AXLE_LENGTH/2.0;
00831   float l = trans - rot;
00832   float r = trans + rot;
00833 
00834   // Reduce the speed on each wheel to the max
00835   // speed to prevent the stepper motors from stalling
00836   // Scale the speed of the other wheel to keep the
00837   // turn of the same rate. Note the turn geometry
00838   // will be affected.
00839   if ( fabs( l ) > MOTOR_DEF_MAX_SPEED )
00840   {
00841     float dir = l/fabs(l);
00842     float scale = l/MOTOR_DEF_MAX_SPEED;
00843     l = dir*MOTOR_DEF_MAX_SPEED;
00844     r = r/fabs(scale);
00845   }
00846 
00847   if ( fabs( r ) > MOTOR_DEF_MAX_SPEED )
00848   {
00849     float dir = r/fabs(r);
00850     float scale = r/MOTOR_DEF_MAX_SPEED;
00851     r = dir*MOTOR_DEF_MAX_SPEED;
00852     l = l/fabs(scale);
00853   }
00854 
00855   int32_t leftvel = MPS2Vel( l );
00856   int32_t rightvel = MPS2Vel( r );
00857 
00858 
00859   //  printf( "VelCmd: px=%1.3f, pa=%1.3f, trvel=%d, rotvel=%d, rvel=%d, lvel=%d\n", velcmd->vel.px, velcmd->vel.pa, transvel, rotvel, leftvel, rightvel );
00860   SetContourMode( VelocityContouringProfile );
00861 
00862   // now we set the speed
00863   if ( this->_motorsEnabled )
00864   {
00865     SetVelocityInTicks( leftvel, rightvel );
00866   }
00867   else
00868   {
00869     SetVelocityInTicks( 0, 0 );
00870     printf( "Motors not enabled\n" );
00871   }
00872 }
00873 
00874 void wbr914::HandleDigitalOutCommand( player_dio_data_t* doutCmd )
00875 {
00876   SetDigitalData( doutCmd );
00877 }
00878 
00879 void wbr914::GetAllData( void )
00880 {
00881   // Don't bother reading them if nobody is subscribed to them
00882   if ( position_subscriptions )
00883   {
00884     GetPositionData( &_data.position );
00885   }
00886   
00887   if ( ir_subscriptions )
00888   {
00889     GetIRData( &_data.ir );
00890   }
00891 
00892   if ( aio_subscriptions )
00893   {
00894     GetAnalogData( &_data.aio );
00895   }
00896 
00897   if ( dio_subscriptions )
00898   {
00899     GetDigitalData( &_data.dio );
00900   }
00901 }
00902 
00903 void wbr914::GetPositionData( player_position2d_data_t* d )
00904 {
00905   // calculate position data
00906   int32_t left_pos = -57;
00907   int32_t right_pos = -57;
00908   const double TWOPI = 2.0*M_PI;
00909 
00910   GetPositionInTicks( &left_pos, &right_pos );
00911 
00912   int32_t change_left  = left_pos - last_lpos;
00913   int32_t change_right = right_pos - last_rpos;
00914 
00915   last_lpos = left_pos;
00916   last_rpos = right_pos;
00917 
00918   // Calculate translational and rotational change
00919   // translational change = avg of both changes
00920   // rotational change is half the diff between both changes
00921   double transchange = Ticks2Meters( (change_left + change_right)>>1 );
00922   double rotchange = Ticks2Meters( (change_left - change_right)>>1 );
00923 
00924   // Radius of the robotwheels
00925   double r = DEFAULT_AXLE_LENGTH/2.0;
00926 
00927   // calc total yaw, constraining from 0 to 2pi
00928   _yaw += rotchange/r;
00929   if ( _yaw < 0 )
00930     _yaw += TWOPI;
00931 
00932   if ( _yaw > TWOPI )
00933     _yaw -= TWOPI;
00934 
00935   // calc current x and y position
00936   _x += ( transchange * cos( _yaw )); 
00937   _y += ( transchange * sin( _yaw )); 
00938 
00939 
00940   // add code to read in the speed data
00941   int32_t left_vel, right_vel;
00942 
00943   GetVelocityInTicks( &left_vel, &right_vel );
00944 
00945   double lv = Vel2MPS( left_vel );
00946   double rv = Vel2MPS( right_vel );
00947   double trans_vel = (lv + rv)/2;
00948   double rot_vel = (lv - rv)/2;
00949   double rot_vel_rad = rot_vel/(r);
00950 
00951   d->pos.px = _x;
00952   d->pos.py = _y;
00953   d->pos.pa = _yaw;
00954   d->vel.px = trans_vel;
00955   d->vel.pa = rot_vel_rad;
00956 }
00957 
00958 /* this will update the IR part of the client data
00959  * returns:
00960  */
00961 void wbr914::GetIRData(player_ir_data_t * d)
00962 {
00963   // At 80cm Vmin=0.25V Vtyp=0.4V Vmax=0.55V
00964   // At 10cm delta increase in voltage Vmin=1.75V Vtyp=2.0V Vmax=2.25V
00965   // Therefore lets choose V=0.25V at 80cm and V=2.8V (2.25+0.55) at 10cm
00966   // Assume the formula for mm = 270 * (voltage)^-1.1 for 80cm to 10cm
00967   // Assume ADC input of 5.0V gives max value of 1023
00968 
00969   float adcLo = 0.0;
00970   float adcHi = 5.0;
00971   float vPerCount = (adcHi-adcLo)/1023.0;
00972   //  float v80 = 0.25;
00973   //  float deltaV = 2.25;
00974   //  float v10 = v80+deltaV;
00975   //  float mmPerVolt = (800.0-100.0)/(v80-v10); 
00976 
00977   for (uint32_t i=0; i < d->ranges_count; i++)
00978   {
00979     int16_t val = 0;
00980 
00981     GetAnalogSensor( i+8, &val );
00982     float voltage = (float)val*vPerCount;
00983     d->voltages[ i ] = voltage;
00984 
00985     // Range values are useless further out than 80-90 cm
00986     // with the Sharp sensors, so truncate them accordingly
00987     if ( val < 80 )
00988     {
00989       val = 80;
00990     }
00991 
00992     // Convert 10 bit value to a distance in meters
00993     float meters;
00994 
00995     // Formula for range conversion is different for long range
00996     // sensors than short range ones. Use appropriate formula.
00997     if ( i == 5 || i == 7 )
00998     {
00999       // Beak side firing sensors are longer range sensors
01000       // Sharp GP2Y0A02 sensors 20-150cm
01001       meters = ((16933.0/((float)val - 8.0)) - 13.0)/100.0;
01002     }
01003     else
01004     {
01005       // Sharp GP2Y0A21 sensors 10-80cm
01006       meters = ((6787.0/((float)val - 3.0)) - 4.0)/100.0;
01007     }
01008     d->ranges[ i ] = meters;
01009   }
01010 }
01011 
01012 /*
01013   Update the Analog input part of the client data
01014 
01015   We cannot reliably detect whether there is an I/O
01016   board attached to the M3 so blindly return the data.
01017  */
01018 void wbr914::GetAnalogData(player_aio_data_t * d)
01019 {
01020   // Read the 8 analog inputs on the second I/O board
01021   d->voltages_count = 8;
01022 
01023   float adcLo = 0.0;
01024   float adcHi = 5.0;
01025   float vPerCount = (adcHi-adcLo)/1023.0;
01026 
01027   for (uint32_t i=0; i < d->voltages_count; i++)
01028   {
01029     int16_t val = 0;
01030 
01031     GetAnalogSensor( i, &val );
01032     float voltage = (float)val*vPerCount;
01033     d->voltages[ i ] = voltage;
01034   }
01035 }
01036 
01037 /*
01038   Update the Digital input part of the client data
01039 
01040   We cannot reliably detect whether there is an I/O
01041   board attached to the M3 so blindly return the data.
01042  */
01043 void wbr914::GetDigitalData(player_dio_data_t * d)
01044 {
01045   // Read the 16 digital inputs
01046   uint16_t din;
01047 
01048   d->count = 16;
01049   GetDigitalIn( &din );
01050 
01051   // Byte flip the data to make the Input from the
01052   // optional I/O board show up in the upper byte.
01053   d->bits = (uint32_t)( (din>>8) | (din<<8));
01054 }
01055 
01056 /*
01057   Set the Digital outputs on the robot
01058 
01059   We cannot reliably detect whether there is an I/O
01060   board attached to the M3 so blindly set the data.
01061  */
01062 void wbr914::SetDigitalData( player_dio_data_t * d )
01063 {
01064   // We only have 16 bits of Dig out, so strip extra bits
01065   uint16_t data = d->bits & 0xFFFF;
01066 
01067   // Different number of digital bits being requested to
01068   // be set than we must actually set in the hardware.
01069   // Handle by using part of the last sent data.
01070   if ( d->count < 16 )
01071   {
01072     // Keep the last dig out bits that have not changed
01073     uint16_t mask = (0xffff << d->count);
01074     uint16_t oldPart = _lastDigOut & mask;
01075 
01076     // Invert the mask and keep the bits that are to change.
01077     mask = mask ^ 0xFFFF;
01078     data &= mask;
01079 
01080     // Build the output data
01081     data |= oldPart;
01082   }
01083 
01084   _lastDigOut = data;
01085 
01086   // Byte flip the data to make the Output to from the
01087   // optional I/O board show up in the upper byte.
01088   data = ( (data>>8) | (data<<8) );
01089 
01090   // Always set 16 bits of data
01091   SetDigitalOut( data );
01092 }
01093 
01094 //-------------------------------------------------------
01095 
01096 // TODO: Make the bogusRC temporally stable and threadsafe
01097 const char* wbr914::GetPMDErrorString( int rc )
01098 {
01099   static const char* errorStrings[] =
01100   {
01101     "Success",
01102     "Reset",
01103     "Invalid Instruction",
01104     "Invalid Axis",
01105     "Invalid Parameter",
01106     "Trace Running",
01107     "Flash",
01108     "Block Out of Bounds",
01109     "Trace buffer zero",
01110     "Bad checksum",
01111     "Not primary port",
01112     "Invalid negative value",
01113     "Invalid parameter change",
01114     "Limit event pending",
01115     "Invalid move into limit"
01116   };
01117   static char bogusRC[ 80 ];
01118 
01119   if ( rc < (int)sizeof( errorStrings ) )
01120   {
01121     return errorStrings[ rc ];
01122   }
01123 
01124   sprintf( bogusRC, "Unknown error %d", rc );
01125   return bogusRC;
01126 }
01127 
01128 int wbr914::ResetRawPositions()
01129 {
01130   if ( _debug )
01131     printf("Reset Odometry\n");
01132   int Values[2];
01133   Values[0] = 0;
01134   Values[1] = 0;
01135 
01136   if ( _debug )
01137     printf( "SetActualPositionInTicks\n" );
01138   SetActualPositionInTicks( 0, 0 );
01139   UpdateM3();
01140 
01141   last_lpos = 0;
01142   last_rpos = 0;
01143   /*
01144   player_position2d_data_t data;
01145   memset(&data,0,sizeof(player_position2d_data_t));
01146   Publish( position_id, PLAYER_MSGTYPE_DATA, PLAYER_POSITION2D_DATA_STATE, &data, sizeof(data),NULL);
01147   */
01148   _x   = 0;
01149   _y   = 0;
01150   _yaw = 0;
01151   return 0;
01152 }
01153 
01154 bool wbr914::RecvBytes( unsigned char*s, int len )
01155 {
01156   int nbytes;
01157   int bytesRead = 0;
01158 
01159   // max 10 retries
01160   for ( int i=0; i<10; i++ )
01161   {
01162     nbytes = read( _fd, s+bytesRead, len-bytesRead );
01163     if ( nbytes < 0 )
01164     {
01165       if ( errno != EAGAIN )
01166       {
01167         printf( "M3 Read error: %s\n", strerror( errno ));
01168         return false;
01169       }
01170       else
01171       {
01172         nbytes = 0;
01173       }
01174     }
01175 
01176     bytesRead += nbytes;
01177     if ( bytesRead == len )
01178     {
01179       return true;
01180     }
01181 
01182     // wait for the rest of the byte
01183     // calc time based on number of bytes left to read,
01184     // baud rate and num bits/byte
01185     int t = ( len-bytesRead )*11*1000/_baud;
01186     usleep( t*1000 );
01187   }
01188 
01189   printf( "Read timeout; Got %d bytes, expected %d\n",
01190           bytesRead, len );
01191 
01192   return false;
01193 }
01194 
01195 int wbr914::ReadBuf(unsigned char* s, size_t len)
01196 {
01197   // Get error code
01198   bool rc = RecvBytes( s, 1 );
01199   if ( !rc )
01200   {
01201     return -1;
01202   }
01203 
01204   // PMD 3410 error code in first byte
01205   if ( *s != 0 && *s != 1 )
01206   {
01207     const char* err = GetPMDErrorString( *s );
01208     printf( "Cmd error: %s\n", err );
01209     return( -(*s) );
01210   }
01211 
01212   // Read the rest of the response
01213   rc = RecvBytes( s+1, len-1 );
01214   if ( !rc )
01215   {
01216     return -1;
01217   }
01218 
01219   uint8_t chksum = 0;
01220 
01221   // Verify the checksum is correct
01222   for ( unsigned i=0; i<len; i++ )
01223   {
01224     chksum += *(s+i);
01225   }
01226   if ( chksum != 0 )
01227   {
01228     printf( "Read checksum error\n" );
01229     return -1;
01230   }
01231 
01232   return len;
01233 
01234 #ifdef FOO
01235 //      printf( "len=%d numread=%d\n", len, numread );
01236   while ( numread < (int)len )
01237   {
01238     if ( ( newread = read( this->_fd, s, len )) == -1 )
01239     {
01240       if( !_fd_blocking && errno == EAGAIN)
01241       {
01242         if ( readSlipped == false )
01243           printf( "read() slipped\n" );
01244         else
01245         {
01246           printf("read() failed: %s\n", strerror(errno));
01247           return(-1);
01248         }
01249 
01250         readSlipped = true;
01251 
01252         usleep( DELAY_US);
01253         continue;
01254       }
01255 
01256       printf("read() failed: %s\n", strerror(errno));
01257       return(-1);
01258     }
01259     else
01260     {
01261       numread += newread;
01262       if ( _fd_blocking )
01263       {
01264         break;
01265       }
01266     }
01267   }
01268 
01269 #ifdef DEBUG
01270   printf("read: %d of %d bytes - ", numread, len );
01271   ssize_t i;
01272   for( i=0; i<numread; i++)
01273   {
01274     printf( "0x%02x ", s[i] );
01275   }
01276   printf( "\n" );
01277 #endif
01278 
01279   uint8_t chksum = 0;
01280 
01281   // Verify the checksum is correct
01282   for ( i=0; i<numread; i++ )
01283   {
01284     chksum += s[i];
01285   }
01286   if ( chksum != 0 )
01287   {
01288     printf( "Read checksum error\n" );
01289   }
01290 
01291   // PMD 3410 error code in first byte
01292   if ( s[0] != 0 && s[0] != 1 )
01293   {
01294     const char* err = GetPMDErrorString( s[0] );
01295     printf( "Cmd error: %s\n", err );
01296     return( -s[0] );
01297   }
01298 
01299   return( numread );
01300 #endif
01301 }
01302 
01303 int wbr914::WriteBuf(unsigned char* s, size_t len)
01304 {
01305   size_t numwritten;
01306   int thisnumwritten;
01307   numwritten=0;
01308 
01309 #ifdef DEBUG
01310   printf("write: %d bytes - ", len );
01311   size_t i;
01312   for( i=0; i<len; i++)
01313   {
01314     printf( "0x%02x ", s[i] );
01315   }
01316   printf( "\n" );
01317 #endif
01318 
01319   for ( int i=0; i<10; i++ )
01320   {
01321     thisnumwritten = write( _fd, s+numwritten, len-numwritten);
01322     numwritten += thisnumwritten;
01323 
01324     if ( numwritten == len )
01325     {
01326       return numwritten;
01327     }
01328     else if ( thisnumwritten < 0 )
01329     {
01330       printf( "Write error; %s\n", strerror( errno ));
01331       return -1;
01332     }
01333   }
01334     
01335   printf( "Write timeout; wrote %ld bytes, tried to write %ld\n",
01336           numwritten, len );
01337 
01338   return numwritten;
01339 
01340 #ifdef FOO
01341   while(numwritten < len)
01342   {
01343     if((thisnumwritten = write(this->_fd,s+numwritten,len-numwritten)) < 0)
01344     {
01345       if(!this->_fd_blocking && errno == EAGAIN)
01346       {
01347         printf( "write() slipped\n" );
01348         usleep( DELAY_US);
01349         continue;
01350       }
01351       printf("write() failed: %s\n", strerror(errno));
01352       return(-1);
01353     }
01354     numwritten += thisnumwritten;
01355   }
01356 
01357 
01358 #endif
01359 
01360   return numwritten;
01361 }
01362 
01363 int wbr914::sendCmdCom( unsigned char address, unsigned char c, 
01364                         int cmd_num, unsigned char* arg, 
01365                         int ret_num, unsigned char * ret )
01366 {
01367   assert( cmd_num<=4 );
01368 
01369   unsigned char cmd[8];
01370   //bool retry = true;
01371   unsigned char savecs;
01372   
01373   cmd[0] = address;
01374   cmd[1] = 0;          // checksum. to be overwritten
01375   cmd[2] = 0x00;
01376   cmd[3] = c;
01377 
01378   // Add arguments to command
01379   int i;
01380   for ( i=0; i<cmd_num; i++ )
01381   {
01382     cmd[4+i] = arg[i];
01383   }
01384 
01385   // compute checksum. Ignore cmd[1] since it is the checksum location
01386   int chk = 0;
01387   for ( i=0; i<cmd_num+4; i++ )
01388   {
01389     chk += cmd[i];
01390   }
01391 
01392   // Set the checksum
01393   int cs = -chk;
01394   cmd[1] = (unsigned char) (cs & 0xff);
01395   savecs = cmd[1];
01396 
01397   int result;
01398 
01399   // Flush the receive buffer. It should be empty so lets make it be so.
01400   tcflush( _fd, TCIFLUSH );
01401 
01402   result = WriteBuf( cmd, 4+cmd_num );
01403 
01404   if( result != 4+cmd_num )
01405   {
01406     printf( "failed to send command %d\n", (int)c );
01407     return( -1 );
01408   }
01409 
01410 
01411   if( ret != NULL && ret_num > 0 )
01412   {
01413     //    if ( _fd_blocking == false )
01414       usleep( DELAY_US );
01415 
01416     int rc; 
01417     if( (rc = ReadBuf( ret, ret_num )) < 0 )
01418     {
01419       //      printf( "failed to read response\n" );
01420       result = -1;
01421     }
01422   }
01423 
01424 //      PLAYER_WARN1( "cmd: 0x%4x", *((int *) cmd) );
01425 //      PLAYER_WARN1( "cmd: 0x%4x", *((int *) &(cmd[4])) );
01426   return result;
01427 }
01428 
01429 int wbr914::sendCmd0( unsigned char address, unsigned char c, 
01430                       int ret_num, unsigned char * ret )
01431 {
01432   return sendCmdCom( address, c, 0, NULL, ret_num, ret );
01433 }
01434 
01435 int wbr914::sendCmd16( unsigned char address, unsigned char c, 
01436                        int16_t arg, int ret_num, unsigned char * ret )
01437 {
01438 
01439   unsigned char args[2];
01440   uint16_t a = htons( arg );
01441 
01442   args[1] = (a >> 8) & 0xFF;
01443   args[0] = (a >> 0) & 0xFF;
01444 
01445   return sendCmdCom( address, c, 2, args, ret_num, ret );
01446 }
01447 
01448 int wbr914::sendCmd32( unsigned char address, unsigned char c, 
01449                        int32_t arg, int ret_num, unsigned char * ret )
01450 {
01451   unsigned char args[4];
01452   uint32_t a = htonl( arg );
01453   args[3] = (a >> 24) & 0xFF;
01454   args[2] = (a >> 16) & 0xFF;
01455   args[1] = (a >> 8 ) & 0xFF;
01456   args[0] = (a >> 0 ) & 0xFF;
01457 
01458   return sendCmdCom( address, c, 4, args, ret_num, ret );
01459 }
01460 
01461 
01462 void wbr914::SetOdometry( player_position2d_set_odom_req_t* od )
01463 {
01464   unsigned char ret[2];
01465 
01466   _x = od->pose.px;
01467   _y = od->pose.py;
01468   _yaw = od->pose.pa;
01469 
01470   int32_t leftPos = Meters2Ticks( _x );
01471   int32_t rightPos = Meters2Ticks( _y );
01472 
01473   if ( (sendCmd32( LEFT_MOTOR, SETACTUALPOS, leftPos, 2, ret )<0)||
01474        (sendCmd32( LEFT_MOTOR, SETACTUALPOS, rightPos, 2, ret )<0 ))
01475   {
01476     printf( "Error setting actual position\n" );
01477   }
01478 }
01479 
01480 int wbr914::GetAnalogSensor(int s, short * val )
01481 {
01482   unsigned char ret[6];
01483 
01484   if ( sendCmd16( s / 8, READANALOG, s % 8, 4, ret )<0 )
01485   {
01486     printf( "Error reading Analog values\n" );
01487   }
01488 
01489   // Analog sensor values are 10 bit values that have been left shifted
01490   // 6 bits, so right-shift them back
01491   uint16_t v = ( (uint16_t)BytesToInt16(  &(ret[2]) ) >> 6) & 0x03ff;
01492 
01493   if ( _debug )
01494     printf( "sensor %d value: 0x%hx\n", s, v );
01495 
01496   *val = (uint16_t)v;
01497 
01498   return 0;
01499 }
01500 
01501 
01502 void wbr914::GetDigitalIn( uint16_t* d )
01503 {
01504   unsigned char ret[6];
01505 
01506   if ( sendCmd16( 0, READDIGITAL, 0, 4, ret )<0)
01507   {
01508     printf( "Error reading Digital input values\n" );
01509   }
01510 
01511   *d = (uint16_t)BytesToInt16(  &(ret[2]) );
01512 }
01513 
01514 void wbr914::SetDigitalOut( uint16_t d )
01515 {
01516   unsigned char ret[2];
01517 
01518   if ( sendCmd32( 0, WRITEDIGITAL, d, 2, ret ) < 0 )
01519   {
01520     printf( "Error setting Digital output values\n" );
01521   }
01522 }
01523 
01524 /*
01525   Robot commands
01526  */
01527 
01528 void wbr914::UpdateM3()
01529 {
01530   unsigned char ret[2];
01531 
01532   if ( (sendCmd0( LEFT_MOTOR,  UPDATE, 2, ret )<0 ) ||
01533        (sendCmd0( RIGHT_MOTOR, UPDATE, 2, ret )<0 ))
01534   {
01535     printf( "Error updating M3\n" );
01536   }
01537 }
01538 
01539 void wbr914::SetVelocity( uint8_t chan, float mps )
01540 {
01541   uint8_t ret[2];
01542   int flip = 1;
01543   if ( chan == LEFT_MOTOR )
01544   {
01545     flip = -1;
01546   }
01547   if ( sendCmd32( chan, SETVEL, MPS2Vel( mps )*flip, 2, ret )<0 )
01548   {
01549     printf( "Error setting velocity\n" );
01550   }
01551 }
01552 
01553 void wbr914::SetVelocity( float mpsL, float mpsR )
01554 {
01555   uint8_t ret[2];
01556 
01557   if ( (sendCmd32( LEFT_MOTOR,  SETVEL, -MPS2Vel( mpsL ), 2, ret )<0)||
01558        (sendCmd32( RIGHT_MOTOR, SETVEL, MPS2Vel( mpsR ), 2, ret )<0))
01559   {
01560     printf( "Error setting L/R velocity\n" );
01561   }
01562 }
01563 
01564 void wbr914::SetVelocityInTicks( int32_t left, int32_t right )
01565 {
01566   uint8_t ret[2];
01567   if ( (sendCmd32( LEFT_MOTOR,  SETVEL, -left, 2, ret )<0)||
01568        (sendCmd32( RIGHT_MOTOR, SETVEL, right, 2, ret )<0))
01569   {
01570     printf( "Error setting velocity in ticks\n" );
01571   }
01572 }
01573 
01574 void wbr914::Move( uint8_t chan, float meters )
01575 {
01576   uint8_t ret[6];
01577   int flip = 1;
01578 
01579   if ( chan == LEFT_MOTOR )
01580   {
01581     flip = -1;
01582   }
01583 
01584   if ( sendCmd0( chan, GETCMDPOS, 6, ret )< 0 )
01585   {
01586     printf( "Error getting actual position\n" );
01587   }
01588   int32_t loc = BytesToInt32( &ret[2] );
01589   loc += (flip*Meters2Ticks( meters ));
01590   if ( ( sendCmd32( chan, SETPOS, loc, 2, ret )<0))
01591   {
01592     printf( "Error setting actual position for Move\n" );
01593   }
01594 }
01595 
01596 void wbr914::Move( float metersL, float metersR )
01597 {
01598   Move( LEFT_MOTOR,   metersL );
01599   Move( RIGHT_MOTOR,  metersR );
01600 }
01601 
01602 void wbr914::SetPosition( uint8_t chan, float meters )
01603 {
01604   uint8_t ret[6];
01605   int flip = 1;
01606   if ( chan == LEFT_MOTOR )
01607   {
01608     flip = -1;
01609   }
01610 
01611   if ( sendCmd32( chan, SETPOS, flip*Meters2Ticks( meters ), 2, ret )<0)
01612   {
01613     printf( "Error issuing SetPosition\n" );
01614   }
01615 }
01616 
01617 void wbr914::SetPosition( float metersL, float metersR )
01618 {
01619   SetPosition( LEFT_MOTOR,   metersL );
01620   SetPosition( RIGHT_MOTOR,  metersR );
01621 }
01622 
01623 void wbr914::SetActualPositionInTicks( int32_t left, int32_t right )
01624 {
01625   uint8_t ret[6];
01626   if ( (sendCmd32( LEFT_MOTOR, SETACTUALPOS, -left, 2, ret )<0)||
01627        (sendCmd32( RIGHT_MOTOR, SETACTUALPOS, right, 2, ret )<0))
01628   {
01629     printf( "Error in SetActualPositionInTicks\n" );
01630   }
01631 }
01632 
01633 void wbr914::SetActualPosition( float metersL, float metersR )
01634 {
01635   uint8_t ret[6];
01636   if ( (sendCmd32( LEFT_MOTOR, SETACTUALPOS, -Meters2Ticks( metersL ), 2, ret )<0)||
01637        (sendCmd32( RIGHT_MOTOR, SETACTUALPOS, Meters2Ticks( metersL ), 2, ret )<0))
01638   {
01639     printf( "Error in L/R SetActualPosition\n" );
01640   }
01641 }
01642 
01643 void wbr914::GetPositionInTicks( int32_t* left, int32_t* right )
01644 {
01645   uint8_t ret[6];
01646   if ( sendCmd0( LEFT_MOTOR, GETCMDPOS, 6, ret )<0)
01647   {
01648     printf( "Error in Left GetPositionInTicks\n" );
01649   }
01650   *left = -BytesToInt32( &ret[2] );
01651   if ( sendCmd0( RIGHT_MOTOR, GETCMDPOS, 6, ret )<0 )
01652   {
01653     printf( "Error in Right GetPositionInTicks\n" );
01654   }
01655   *right = BytesToInt32( &ret[2] );
01656 }
01657 
01658 void wbr914::GetVelocityInTicks( int32_t* left, int32_t* right )
01659 {
01660   uint8_t ret[6];
01661   if ( sendCmd0( LEFT_MOTOR, GETCMDVEL, 6, ret )<0 )
01662   {
01663     printf( "Error in Left GetVelocityInTicks\n" );
01664   }
01665   *left = -BytesToInt32( &ret[2] );
01666   if ( sendCmd0( RIGHT_MOTOR, GETCMDVEL, 6, ret )<0 )
01667   {
01668     printf( "Error in Left GetVelocityInTicks\n" );
01669   }
01670   *right = BytesToInt32( &ret[2] );
01671 }
01672 
01673 void wbr914::SetAccelerationProfile()
01674 {
01675   uint8_t ret[2];
01676   //  int32_t accel = (int32_t)MOTOR_TICKS_PER_STEP*2;
01677 
01678   // Decelerate faster than accelerating.
01679   if ( (sendCmd32( LEFT_MOTOR,  SETACCEL, ACCELERATION_DEFAULT, 2, ret )<0)||
01680        (sendCmd32( RIGHT_MOTOR, SETACCEL, ACCELERATION_DEFAULT, 2, ret )<0))
01681   {
01682     printf( "Error setting Accelleration profile\n" );
01683   }
01684   if ((sendCmd32( LEFT_MOTOR,  SETDECEL, DECELERATION_DEFAULT, 2, ret )<0)||
01685       (sendCmd32( RIGHT_MOTOR, SETDECEL, DECELERATION_DEFAULT, 2, ret )<0))
01686   {
01687     printf( "Error setting Decelleration profile\n" );
01688   }
01689   SetContourMode( TrapezoidalProfile );
01690 }
01691 
01692 void wbr914::Stop( int StopMode ) {
01693         
01694   unsigned char ret[8];
01695   
01696   if ( _debug )
01697     printf( "Stop\n" );
01698 
01699   /* Start with motor 0*/
01700   _stopped = true;
01701   
01702   if( StopMode == FULL_STOP )
01703   {
01704     if (sendCmd16( LEFT_MOTOR, RESETEVENTSTATUS, 0x0000, 2, ret )<0 )
01705     {
01706       printf( "Error resetting event status\n" );
01707     }
01708     if ( sendCmd16( LEFT_MOTOR, SETSTOPMODE, AbruptStopMode, 2, ret )<0 )
01709     {
01710       printf( "Error setting stop mode\n" );
01711     }
01712     if ( sendCmd32( LEFT_MOTOR, SETVEL, 0, 2, ret )<0)
01713     {
01714       printf( "Error resetting motor velocity\n" );
01715     }
01716     if ( sendCmd32( LEFT_MOTOR, SETACCEL, 0, 2, ret )<0 )
01717     {
01718       printf( "Error resetting acceleration\n" );
01719     }
01720     if ( sendCmd32( LEFT_MOTOR, SETDECEL, 0, 2, ret )<0 )
01721     {
01722       printf( "Error resetting deceleration\n" );
01723     }
01724 
01725 
01726     if ( sendCmd16( RIGHT_MOTOR, RESETEVENTSTATUS, 0x0000, 2, ret )<0 )
01727     {
01728       printf( "Error resetting event status\n" );
01729     }
01730     if ( sendCmd16( RIGHT_MOTOR, SETSTOPMODE, AbruptStopMode, 2, ret )<0 )
01731     {
01732       printf( "Error setting stop mode\n" );
01733     }
01734     if ( sendCmd32( RIGHT_MOTOR, SETVEL, 0, 2, ret )<0 )
01735     {
01736       printf( "Error resetting motor velocity\n" );
01737     }
01738     if ( sendCmd32( RIGHT_MOTOR, SETACCEL, 0, 2, ret )<0 )
01739     {
01740       printf( "Error resetting acceleration\n" );
01741     }
01742     if ( sendCmd32( RIGHT_MOTOR, SETDECEL, 0, 2, ret )<0 )
01743     {
01744       printf( "Error resetting deceleration\n" );
01745     }
01746 
01747     SetContourMode( VelocityContouringProfile );
01748 
01749     EnableMotors( false );
01750     UpdateM3();
01751 
01752     if ((sendCmd0( LEFT_MOTOR, RESET, 2, ret )<0)||
01753         (sendCmd0( RIGHT_MOTOR, RESET, 2, ret )<0))
01754     {
01755       printf( "Error resetting motor\n" );
01756     }
01757 
01758   }
01759   else
01760   {
01761     if ( sendCmd16( LEFT_MOTOR, RESETEVENTSTATUS, 0x0700, 2, ret )<0 )
01762     {
01763       printf( "Error resetting event status\n" );
01764     }
01765     if ( sendCmd32( LEFT_MOTOR, SETVEL, 0, 2, ret )<0 )
01766     {
01767       printf( "Error resetting motor velocity\n" );
01768     }
01769 
01770     if ( sendCmd16( RIGHT_MOTOR, RESETEVENTSTATUS, 0x0700, 2, ret )<0 )
01771     {
01772       printf( "Error resetting event status\n" );
01773     }
01774     if ( sendCmd32( RIGHT_MOTOR, SETVEL, 0, 2, ret )<0)
01775     {
01776       printf( "Error resetting motor velocity\n" );
01777     }
01778 
01779     UpdateM3();
01780 
01781     if ((sendCmd0( LEFT_MOTOR, RESET, 2, ret )<0)||
01782         (sendCmd0( RIGHT_MOTOR, RESET, 2, ret )<0))
01783     {
01784       printf( "Error resetting motor\n" );
01785     }
01786   }
01787 }
01788 
01789 
01790 void wbr914::StopRobot()
01791 {
01792   Stop( FULL_STOP );
01793 }
01794 
01795 
01796 bool wbr914::EnableMotors( bool enable )
01797 {
01798   unsigned char ret[2];
01799   long torque = 0;
01800 
01801   if ( enable )
01802   {
01803     torque = _percentTorque*0x8000/100;
01804     if ( torque > 0x8000 )
01805       torque = 0x8000;
01806   }
01807 
01808   // Need to turn off motors to change the torque
01809   if ( ( sendCmd16( LEFT_MOTOR,  SETMOTORMODE, 0, 2, ret )<0)||
01810        ( sendCmd16( RIGHT_MOTOR, SETMOTORMODE, 0, 2, ret )<0))
01811   {
01812     printf( "Error resetting motor mode\n" );
01813   }
01814 
01815   if ((sendCmd16( LEFT_MOTOR, SETMOTORCMD, (short)torque, 2, ret )<0)||
01816       (sendCmd16( RIGHT_MOTOR, SETMOTORCMD, (short)torque, 2, ret )<0))
01817   {
01818     printf( "Error setting motor mode\n" );
01819   }
01820 
01821   // Update the torque setting
01822   UpdateM3();
01823 
01824   if ( enable )
01825   {
01826     if ((sendCmd16( LEFT_MOTOR,  SETMOTORMODE, 1, 2, ret )<0)||
01827         (sendCmd16( RIGHT_MOTOR, SETMOTORMODE, 1, 2, ret )<0))
01828     {
01829       printf( "Error setting motor mode\n" );
01830     }
01831   }
01832 
01833   _motorsEnabled = enable;
01834 
01835   return ( true );
01836 }
01837 
01838 void wbr914::SetContourMode( ProfileMode_t prof )
01839 {
01840   uint8_t ret[2];
01841 
01842   if ( (sendCmd16( LEFT_MOTOR, SETPROFILEMODE, prof, 2, ret)<0)||
01843        (sendCmd16( RIGHT_MOTOR, SETPROFILEMODE, prof, 2, ret)<0))
01844   {
01845     printf( "Error setting profile mode\n" );
01846   }
01847 }
01848 
01849 
01850 void wbr914::SetMicrosteps()
01851 {
01852   uint8_t ret[2];
01853 
01854   if ( (sendCmd16( LEFT_MOTOR, SETPHASECOUNTS, (short)MOTOR_TICKS_PER_STEP*4, 2, ret)<0)||
01855        (sendCmd16( RIGHT_MOTOR, SETPHASECOUNTS, (short)MOTOR_TICKS_PER_STEP*4, 2, ret)<0))
01856   {
01857     printf( "Error setting phase counts\n" );
01858   }
01859 }
01860 
01861 
01862 int32_t wbr914::Meters2Ticks( float meters )
01863 {
01864   return (int32_t)( (double)meters * GEAR_RATIO * MOTOR_TICKS_PER_REV / WHEEL_CIRC);
01865 }
01866 
01867 float wbr914::Ticks2Meters( int32_t ticks )
01868 {
01869   return (float)( WHEEL_CIRC*((double)ticks/GEAR_RATIO)/ MOTOR_TICKS_PER_REV );
01870 }
01871 
01872 int32_t wbr914::MPS2Vel( float mps )
01873 {
01874   return (int32_t)( (double)mps * _velocityK );
01875 
01876 }
01877 
01878 float wbr914::Vel2MPS( int32_t count )
01879 {
01880   return (float)( (double)count/_velocityK );
01881 
01882 }
01883 
01884 int32_t wbr914::BytesToInt32(unsigned char *ptr)
01885 {
01886   unsigned char char0,char1,char2,char3;
01887   int32_t data = 0;
01888 
01889   char0 = ptr[3];
01890   char1 = ptr[2];
01891   char2 = ptr[1];
01892   char3 = ptr[0];
01893 
01894   data |=  ((int)char0)        & 0x000000FF;
01895   data |= (((int)char1) << 8)  & 0x0000FF00;
01896   data |= (((int)char2) << 16) & 0x00FF0000;
01897   data |= (((int)char3) << 24) & 0xFF000000;
01898 
01899   //this could just be ntohl
01900 
01901   return data;
01902 }
01903 
01904 int16_t wbr914::BytesToInt16(unsigned char *ptr)
01905 {
01906   unsigned char char0,char1;
01907   int16_t data = 0;
01908 
01909   char0 = ptr[1];
01910   char1 = ptr[0];
01911 
01912   data |=  ((int)char0)        & 0x000000FF;
01913   data |= (((int)char1) << 8)  & 0x0000FF00;
01914 
01915   //this could just be ntohl
01916 
01917   return data;
01918 }

Last updated 12 September 2005 21:38:45