sip.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  * $Id: sip.cc 4356 2008-02-15 08:53:55Z thjc $
00025  *
00026  * part of the P2OS parser.  methods for filling and parsing server
00027  * information packets (SIPs)
00028  */
00029 #include <stdio.h>
00030 #include <limits.h>
00031 #include <math.h>  /* rint(3) */
00032 #include <sys/types.h>
00033 #include <stdlib.h> /* for abs() */
00034 #include <unistd.h>
00035 
00036 #include <libplayercore/error.h>
00037 
00038 #include "sip.h"
00039 
00040 // Variable with constant lifetime to store lift actuator data
00041 static player_actarray_actuator_t liftActuator;
00042 // Same thing for blobs
00043 static player_blobfinder_blob_t cmucamBlob;
00044 
00045 void SIP::FillStandard(player_p2os_data_t* data)
00046 {
00048   // odometry
00049 
00050   // initialize position to current offset
00051   data->position.pos.px = this->x_offset / 1e3;
00052   data->position.pos.py = this->y_offset / 1e3;
00053   // now transform current position by rotation if there is one
00054   // and add to offset
00055   if(this->angle_offset != 0)
00056   {
00057     double rot = DTOR(this->angle_offset);    // convert rotation to radians
00058     data->position.pos.px +=  ((this->xpos/1e3) * cos(rot) -
00059                                (this->ypos/1e3) * sin(rot));
00060     data->position.pos.py +=  ((this->xpos/1e3) * sin(rot) +
00061                                (this->ypos/1e3) * cos(rot));
00062     data->position.pos.pa = DTOR(this->angle_offset + angle);
00063   }
00064   else
00065   {
00066     data->position.pos.px += this->xpos / 1e3;
00067     data->position.pos.py += this->ypos / 1e3;
00068     data->position.pos.pa = DTOR(this->angle);
00069   }
00070   data->position.vel.px = (((this->lvel) + (this->rvel) ) / 2) / 1e3;
00071   data->position.vel.py = 0.0;
00072   data->position.vel.pa = ((double)(this->rvel - this->lvel) /
00073                            (2.0/PlayerRobotParams[param_idx].DiffConvFactor));
00074   data->position.stall = (unsigned char)(this->lwstall || this->rwstall);
00075 
00077   // compass
00078   memset(&(data->compass),0,sizeof(data->compass));
00079   data->compass.pos.pa = DTOR(this->compass);
00080 
00082   // sonar
00083   data->sonar.ranges_count = PlayerRobotParams[param_idx].SonarNum;
00084   data->sonar.ranges = new float[data->sonar.ranges_count];
00085   for(int i=0;i<MIN(PlayerRobotParams[param_idx].SonarNum,sonarreadings);i++)
00086     data->sonar.ranges[i] = this->sonars[i] / 1e3;
00087 
00089   // gripper
00090   unsigned char gripState = timer >> 8;
00091   if ((gripState & 0x01) && (gripState & 0x02) && !(gripState & 0x04))
00092     data->gripper.state = PLAYER_GRIPPER_STATE_ERROR;
00093   else
00094     data->gripper.state = (gripState & 0x01) ? PLAYER_GRIPPER_STATE_OPEN :
00095       ((gripState & 0x02) ? PLAYER_GRIPPER_STATE_CLOSED :
00096       ((gripState & 0x04) ? PLAYER_GRIPPER_STATE_MOVING : PLAYER_GRIPPER_STATE_ERROR));
00097   data->gripper.beams = (digin & 0x02) & (digin & 0x04);
00098   data->gripper.stored = 0;
00099 
00101   // lift
00102   data->lift.actuators_count = 1;
00103   data->lift.actuators = &liftActuator;
00104   data->lift.actuators[0].speed = 0;
00105   data->lift.actuators[0].acceleration = -1;
00106   data->lift.actuators[0].current = -1;
00107   if ((gripState & 0x10) && (gripState & 0x20) && !(gripState & 0x40))
00108   {
00109     // In this case, the lift is somewhere in between, so
00110     // must be at an intermediate carry position. Use last commanded position.
00111     data->lift.actuators[0].state = PLAYER_ACTARRAY_ACTSTATE_IDLE;
00112     data->lift.actuators[0].position = lastLiftPos;
00113   }
00114   else if (gripState & 0x10)  // Up
00115   {
00116     data->lift.actuators[0].state = PLAYER_ACTARRAY_ACTSTATE_IDLE;
00117     data->lift.actuators[0].position = 1.0f;
00118   }
00119   else if (gripState & 0x20)  // Down
00120   {
00121     data->lift.actuators[0].state = PLAYER_ACTARRAY_ACTSTATE_IDLE;
00122     data->lift.actuators[0].position = 0.0f;
00123   }
00124   else if (gripState & 0x40)  // Moving
00125   {
00126     data->lift.actuators[0].state = PLAYER_ACTARRAY_ACTSTATE_MOVING;
00127     // There is no way to know where it is for sure, so use last commanded position.
00128     data->lift.actuators[0].position = lastLiftPos;
00129   }
00130   else    // Assume stalled
00131   {
00132     data->lift.actuators[0].state = PLAYER_ACTARRAY_ACTSTATE_STALLED;
00133   }
00134 
00136   // bumper
00137   unsigned int bump_count = PlayerRobotParams[param_idx].NumFrontBumpers + PlayerRobotParams[param_idx].NumRearBumpers;
00138   if (data->bumper.bumpers_count != bump_count)
00139   {
00140     data->bumper.bumpers_count = bump_count;
00141     delete [] data->bumper.bumpers;
00142     data->bumper.bumpers = new uint8_t[bump_count];
00143   }
00144   int j = 0;
00145   for(int i=PlayerRobotParams[param_idx].NumFrontBumpers-1;i>=0;i--)
00146     data->bumper.bumpers[j++] =
00147       (unsigned char)((this->frontbumpers >> i) & 0x01);
00148   for(int i=PlayerRobotParams[param_idx].NumRearBumpers-1;i>=0;i--)
00149     data->bumper.bumpers[j++] =
00150       (unsigned char)((this->rearbumpers >> i) & 0x01);
00151 
00153   // power
00154   // set the bits that indicate which fields we're using
00155   data->power.valid = PLAYER_POWER_MASK_VOLTS | PLAYER_POWER_MASK_PERCENT;
00156   data->power.volts = this->battery / 1e1;
00157   data->power.percent = 1e2 * (data->power.volts / P2OS_NOMINAL_VOLTAGE);
00158 
00160   // digital I/O
00161   data->dio.count = (unsigned char)8;
00162   data->dio.bits = (unsigned int)this->digin;
00163 
00165   // analog I/O
00166   //TODO: should do this smarter, based on which analog input is selected
00167   data->aio.voltages_count = (unsigned char)1;
00168   if (!data->aio.voltages)
00169     data->aio.voltages = new float[1];
00170   data->aio.voltages[0] = (this->analog / 255.0) * 5.0;
00171 }
00172 
00173 void SIP::FillGyro(player_p2os_data_t* data)
00174 {
00176   // gyro
00177   memset(&(data->gyro),0,sizeof(data->gyro));
00178   data->gyro.pos.pa = DTOR(this->gyro_rate);
00179 }
00180 
00181 void SIP::FillSERAUX(player_p2os_data_t* data)
00182 {
00183   /* CMUcam blob tracking interface.  The CMUcam only supports one blob
00184   ** (and therefore one channel too), so everything else is zero.  All
00185   ** data is storde in the blobfinder packet in Network byte order.
00186   ** Note: In CMUcam terminology, X is horizontal and Y is vertical, with
00187   ** (0,0) being TOP-LEFT (from the camera's perspective).  Also,
00188   ** since CMUcam doesn't have range information, but does have a
00189   ** confidence value, I'm passing it back as range. */
00190   data->blobfinder.blobs = &cmucamBlob;
00191   memset(data->blobfinder.blobs,0,
00192          sizeof(player_blobfinder_blob_t));
00193   data->blobfinder.width = CMUCAM_IMAGE_WIDTH;
00194   data->blobfinder.height = CMUCAM_IMAGE_HEIGHT;
00195 
00196   if (blobarea > 1)     // With filtering, definition of track is 2 pixels
00197   {
00198     data->blobfinder.blobs_count = 1;
00199     if (!data->blobfinder.blobs)
00200         data->blobfinder.blobs = new player_blobfinder_blob_t[1];
00201     data->blobfinder.blobs[0].color = this->blobcolor;
00202     data->blobfinder.blobs[0].x = this->blobmx;
00203     data->blobfinder.blobs[0].y = this->blobmy;
00204     data->blobfinder.blobs[0].left = this->blobx1;
00205     data->blobfinder.blobs[0].right = this->blobx2;
00206     data->blobfinder.blobs[0].top = this->bloby1;
00207     data->blobfinder.blobs[0].bottom = this->bloby2;
00208     data->blobfinder.blobs[0].area = this->blobarea;
00209     data->blobfinder.blobs[0].range = this->blobconf;
00210   }
00211   else
00212     data->blobfinder.blobs_count = 0;
00213 }
00214 
00215 void SIP::FillArm(player_p2os_data_t* data)
00216 {
00218   // Fill in arm data
00219   data->actArray.actuators_count = armNumJoints;
00220   data->actArray.actuators = new player_actarray_actuator_t[armNumJoints];  // This will be cleaned up in P2OS::PutData
00221   memset (data->actArray.actuators, 0, sizeof (player_actarray_actuator_t) * armNumJoints);
00222   for (int ii = 0; ii < armNumJoints; ii++)
00223   {
00224     data->actArray.actuators[ii].position = armJointPosRads[ii];
00225     data->actArray.actuators[ii].speed = 0;
00226     data->actArray.actuators[ii].acceleration = -1;
00227     data->actArray.actuators[ii].current = -1;
00228     // State is complex. It can be idle, moving, or stalled (we don't have brakes so don't need to worry about the brake state).
00229     // Moving means have moving state from status packet
00230     // Idle means have not moving state from status packet and are at target position
00231     // Stalled means have not moving state from status packet and are not at target position
00232     if (armJointMoving[ii])
00233       data->actArray.actuators[ii].state = PLAYER_ACTARRAY_ACTSTATE_MOVING;
00234     else if (armJointPos[ii] == armJointTargetPos[ii])
00235       data->actArray.actuators[ii].state = PLAYER_ACTARRAY_ACTSTATE_IDLE;
00236     else
00237       data->actArray.actuators[ii].state = PLAYER_ACTARRAY_ACTSTATE_STALLED;
00238   }
00239 
00241   // Fill in arm gripper data
00242   memset (&(data->armGripper), 0, sizeof (player_gripper_data_t));
00243   if (armJointMoving[5])
00244     data->armGripper.state = PLAYER_GRIPPER_STATE_MOVING;
00245   else if (armJointPos[5] == armJointTargetPos[5])
00246     if (armJointPos[5] > 128)    // Position is between 0 and 255
00247       data->armGripper.state = PLAYER_GRIPPER_STATE_OPEN;
00248     else
00249       data->armGripper.state = PLAYER_GRIPPER_STATE_CLOSED;
00250   else
00251     data->armGripper.state = PLAYER_GRIPPER_STATE_ERROR;
00252   data->armGripper.beams = 0;
00253   data->armGripper.stored = 0;
00254 }
00255 
00256 int SIP::PositionChange( unsigned short from, unsigned short to )
00257 {
00258   int diff1, diff2;
00259 
00260   /* find difference in two directions and pick shortest */
00261   if ( to > from ) {
00262     diff1 = to - from;
00263     diff2 = - ( from + 4096 - to );
00264   }
00265   else {
00266     diff1 = to - from;
00267     diff2 = 4096 - from + to;
00268   }
00269 
00270   if ( abs(diff1) < abs(diff2) )
00271     return(diff1);
00272   else
00273     return(diff2);
00274 
00275 }
00276 
00277 void SIP::Print()
00278 {
00279   int i;
00280 
00281   printf("lwstall:%d rwstall:%d\n", lwstall, rwstall);
00282 
00283   printf("Front bumpers: ");
00284   for(int i=0;i<5;i++) {
00285     printf("%d", (frontbumpers >> i) & 0x01 );
00286   }
00287   puts("");
00288 
00289   printf("Rear bumpers: ");
00290   for(int i=0;i<5;i++) {
00291     printf("%d", (rearbumpers >> i) & 0x01 );
00292   }
00293   puts("");
00294 
00295   printf("status: 0x%x analog: %d ", status, analog);
00296   printf("digin: ");
00297   for(i=0;i<8;i++) {
00298     printf("%d", (digin >> 7-i ) & 0x01);
00299   }
00300   printf(" digout: ");
00301   for(i=0;i<8;i++) {
00302     printf("%d", (digout >> 7-i ) & 0x01);
00303   }
00304   puts("");
00305   printf("battery: %d compass: %d sonarreadings: %d\n", battery, compass, sonarreadings);
00306   printf("xpos: %d ypos:%d ptu:%hu timer:%hu\n", xpos, ypos, ptu, timer);
00307   printf("angle: %d lvel: %d rvel: %d control: %d\n", angle, lvel, rvel, control);
00308 
00309   PrintSonars();
00310   PrintArmInfo ();
00311   PrintArm ();
00312 }
00313 
00314 void SIP::PrintSonars()
00315 {
00316   printf("Sonars: ");
00317   for(int i = 0; i < 16; i++){
00318     printf("%hu ", sonars[i]);
00319   }
00320   puts("");
00321 }
00322 
00323 void SIP::PrintArm ()
00324 {
00325         printf ("Arm power is %s\tArm is %sconnected\n", (armPowerOn ? "on" : "off"), (armConnected ? "" : "not "));
00326         printf ("Arm joint status:\n");
00327         for (int ii = 0; ii < 6; ii++)
00328                 printf ("Joint %d   %s   %d\n", ii + 1, (armJointMoving[ii] ? "Moving " : "Stopped"), armJointPos[ii]);
00329 }
00330 
00331 void SIP::PrintArmInfo ()
00332 {
00333         printf ("Arm version:\t%s\n", armVersionString);
00334         printf ("Arm has %d joints:\n", armNumJoints);
00335         printf ("  |\tSpeed\tHome\tMin\tCentre\tMax\tTicks/90\n");
00336         for (int ii = 0; ii < armNumJoints; ii++)
00337                 printf ("%d |\t%d\t%d\t%d\t%d\t%d\t%d\n", ii, armJoints[ii].speed, armJoints[ii].home, armJoints[ii].min, armJoints[ii].centre, armJoints[ii].max, armJoints[ii].ticksPer90);
00338 }
00339 
00340 void SIP::ParseStandard( unsigned char *buffer )
00341 {
00342   int cnt = 0, change;
00343   unsigned short newxpos, newypos;
00344 
00345   status = buffer[cnt];
00346   cnt += sizeof(unsigned char);
00347   /*
00348    * Remember P2OS uses little endian:
00349    * for a 2 byte short (called integer on P2OS)
00350    * byte0 is low byte, byte1 is high byte
00351    * The following code is host-machine endian independant
00352    * Also we must or (|) bytes together instead of casting to a
00353    * short * since on ARM architectures short * must be even byte aligned!
00354    * You can get away with this on a i386 since shorts * can be
00355    * odd byte aligned. But on ARM, the last bit of the pointer will be ignored!
00356    * The or'ing will work on either arch.
00357    */
00358   newxpos = ((buffer[cnt] | (buffer[cnt+1] << 8))
00359              & 0xEFFF) % 4096; /* 15 ls-bits */
00360 
00361   if (xpos!=INT_MAX) {
00362     change = (int) rint(PositionChange( rawxpos, newxpos ) *
00363                         PlayerRobotParams[param_idx].DistConvFactor);
00364     if (abs(change)>100)
00365       PLAYER_WARN1("invalid odometry change [%d]; odometry values are tainted", change);
00366     else
00367       xpos += change;
00368   }
00369   else
00370     xpos = 0;
00371   rawxpos = newxpos;
00372   cnt += sizeof(short);
00373 
00374   newypos = ((buffer[cnt] | (buffer[cnt+1] << 8))
00375              & 0xEFFF) % 4096; /* 15 ls-bits */
00376 
00377   if (ypos!=INT_MAX) {
00378     change = (int) rint(PositionChange( rawypos, newypos ) *
00379                         PlayerRobotParams[param_idx].DistConvFactor);
00380     if (abs(change)>100)
00381       PLAYER_WARN1("invalid odometry change [%d]; odometry values are tainted", change);
00382     else
00383       ypos += change;
00384   }
00385   else
00386     ypos = 0;
00387   rawypos = newypos;
00388   cnt += sizeof(short);
00389 
00390   angle = (short)
00391     rint(((short)(buffer[cnt] | (buffer[cnt+1] << 8))) *
00392          PlayerRobotParams[param_idx].AngleConvFactor * 180.0/M_PI);
00393   cnt += sizeof(short);
00394 
00395   lvel = (short)
00396     rint(((short)(buffer[cnt] | (buffer[cnt+1] << 8))) *
00397          PlayerRobotParams[param_idx].VelConvFactor);
00398   cnt += sizeof(short);
00399 
00400   rvel = (short)
00401     rint(((short)(buffer[cnt] | (buffer[cnt+1] << 8))) *
00402          PlayerRobotParams[param_idx].VelConvFactor);
00403   cnt += sizeof(short);
00404 
00405   battery = buffer[cnt];
00406   cnt += sizeof(unsigned char);
00407 
00408   lwstall = buffer[cnt] & 0x01;
00409   rearbumpers = buffer[cnt] >> 1;
00410   cnt += sizeof(unsigned char);
00411 
00412   rwstall = buffer[cnt] & 0x01;
00413   frontbumpers = buffer[cnt] >> 1;
00414   cnt += sizeof(unsigned char);
00415 
00416   control = (short)
00417     rint(((short)(buffer[cnt] | (buffer[cnt+1] << 8))) *
00418          PlayerRobotParams[param_idx].AngleConvFactor);
00419   cnt += sizeof(short);
00420 
00421   ptu = (buffer[cnt] | (buffer[cnt+1] << 8));
00422   cnt += sizeof(short);
00423 
00424   //compass = buffer[cnt]*2;
00425   if(buffer[cnt] != 255 && buffer[cnt] != 0 && buffer[cnt] != 181)
00426     compass = (buffer[cnt]-1)*2;
00427   cnt += sizeof(unsigned char);
00428 
00429   unsigned char numSonars=buffer[cnt];
00430   cnt+=sizeof(unsigned char);  
00431   
00432   if(numSonars>0)
00433   {
00434     //find the largest sonar index supplied
00435     unsigned char maxSonars=sonarreadings;
00436     for(unsigned char i=0;i<numSonars;i++)
00437     {
00438       unsigned char sonarIndex=buffer[cnt+i*(sizeof(unsigned char)+sizeof(unsigned short))];
00439       if((sonarIndex+1)>maxSonars) maxSonars=sonarIndex+1;
00440     }
00441     
00442     //if necessary make more space in the array and preserve existing readings
00443     if(maxSonars>sonarreadings)
00444     {
00445       unsigned short *newSonars=new unsigned short[maxSonars];
00446       for(unsigned char i=0;i<sonarreadings;i++)
00447         newSonars[i]=sonars[i];
00448       if(sonars!=NULL) delete[] sonars;
00449       sonars=newSonars;
00450       sonarreadings=maxSonars;
00451     }
00452     
00453     //update the sonar readings array with the new readings
00454     for(unsigned char i=0;i<numSonars;i++)
00455     {
00456     sonars[buffer[cnt]]=   (unsigned short)
00457       rint((buffer[cnt+1] | (buffer[cnt+2] << 8)) *
00458            PlayerRobotParams[param_idx].RangeConvFactor);
00459       cnt+=sizeof(unsigned char)+sizeof(unsigned short);
00460   }
00461   }
00462 
00463   timer = (buffer[cnt] | (buffer[cnt+1] << 8));
00464   cnt += sizeof(short);
00465 
00466   analog = buffer[cnt];
00467   cnt += sizeof(unsigned char);
00468 
00469   digin = buffer[cnt];
00470   cnt += sizeof(unsigned char);
00471 
00472   digout = buffer[cnt];
00473   cnt += sizeof(unsigned char);
00474   // for debugging:
00475   //Print();
00476 }
00477 
00478 
00488 void SIP::ParseSERAUX( unsigned char *buffer )
00489 {
00490   unsigned char type = buffer[1];
00491   if (type != SERAUX && type != SERAUX2)
00492   {
00493     // Really should never get here...
00494     printf("ERROR: Attempt to parse non SERAUX packet as serial data.\n");
00495     return;
00496   }
00497 
00498   int len  = (int)buffer[0]-3;          // Get the string length
00499 
00500   /* First thing is to find the beginning of last full packet (if possible).
00501   ** If there are less than CMUCAM_MESSAGE_LEN*2-1 bytes (19), we're not
00502   ** guaranteed to have a full packet.  If less than CMUCAM_MESSAGE_LEN
00503   ** bytes, it is impossible to have a full packet.
00504   ** To find the beginning of the last full packet, search between bytes
00505   ** len-17 and len-8 (inclusive) for the start flag (255).
00506   */
00507   int ix;
00508   for (ix = (len>18 ? len-17 : 2); ix<=len-8; ix++)
00509     if (buffer[ix] == 255)
00510       break;            // Got it!
00511   if (len < 10 || ix > len-8) {
00512     printf("ERROR: Failed to get a full blob tracking packet.\n");
00513     return;
00514   }
00515 
00516   // There is a special 'S' message containing the tracking color info
00517   if (buffer[ix+1] == 'S')
00518   {
00519      // Color information (track color)
00520      printf("Tracking color (RGB):  %d %d %d\n"
00521             "       with variance:  %d %d %d\n",
00522               buffer[ix+2], buffer[ix+3], buffer[ix+4],
00523               buffer[ix+5], buffer[ix+6], buffer[ix+7]);
00524      blobcolor = buffer[ix+2]<<16 | buffer[ix+3]<<8 | buffer[ix+4];
00525      return;
00526   }
00527 
00528   // Tracking packets with centroid info are designated with a 'M'
00529   if (buffer[ix+1] == 'M')
00530   {
00531      // Now it's easy.  Just parse the packet.
00532      blobmx     = buffer[ix+2];
00533      blobmy     = buffer[ix+3];
00534      blobx1     = buffer[ix+4];
00535      bloby1     = buffer[ix+5];
00536      blobx2     = buffer[ix+6];
00537      bloby2     = buffer[ix+7];
00538      blobconf   = buffer[ix+9];
00539      // Xiaoquan Fu's calculation for blob area (max 11297).
00540      blobarea   = (bloby2 - bloby1 +1)*(blobx2 - blobx1 + 1)*blobconf/255;
00541      return;
00542   }
00543 
00544   printf("ERROR: Unknown blob tracker packet type: %c\n", buffer[ix+1]);
00545   return;
00546 }
00547 
00548 // Parse a set of gyro measurements.  The buffer is formatted thusly:
00549 //     length (2 bytes), type (1 byte), count (1 byte)
00550 // followed by <count> pairs of the form:
00551 //     rate (2 bytes), temp (1 byte)
00552 // <rate> falls in [0,1023]; less than 512 is CCW rotation and greater
00553 // than 512 is CW
00554 void
00555 SIP::ParseGyro(unsigned char* buffer)
00556 {
00557   // Get the message length (account for the type byte and the 2-byte
00558   // checksum)
00559   int len  = (int)buffer[0]-3;
00560 
00561   unsigned char type = buffer[1];
00562   if(type != GYROPAC)
00563   {
00564     // Really should never get here...
00565     PLAYER_ERROR("ERROR: Attempt to parse non GYRO packet as gyro data.\n");
00566     return;
00567   }
00568 
00569   if(len < 1)
00570   {
00571     PLAYER_WARN("Couldn't get gyro measurement count");
00572     return;
00573   }
00574 
00575   // get count
00576   int count = (int)buffer[2];
00577 
00578   // sanity check
00579   if((len-1) != (count*3))
00580   {
00581     PLAYER_WARN("Mismatch between gyro measurement count and packet length");
00582     return;
00583   }
00584 
00585   // Actually handle the rate values.  Any number of things could (and
00586   // probably should) be done here, like filtering, calibration, conversion
00587   // from the gyro's arbitrary units to something meaningful, etc.
00588   //
00589   // As a first cut, we'll just average all the rate measurements in this
00590   // set, and ignore the temperatures.
00591   float ratesum = 0;
00592   int bufferpos = 3;
00593   unsigned short rate;
00594   unsigned char temp;
00595   for(int i=0; i<count; i++)
00596   {
00597     rate = (unsigned short)(buffer[bufferpos++]);
00598     rate |= buffer[bufferpos++] << 8;
00599     temp = bufferpos++;
00600 
00601     ratesum += rate;
00602   }
00603 
00604   int32_t average_rate = (int32_t)rint(ratesum / (float)count);
00605 
00606   // store the result for sending
00607   gyro_rate = average_rate;
00608 }
00609 
00610 void SIP::ParseArm (unsigned char *buffer)
00611 {
00612         int length = (int) buffer[0] - 2;
00613 
00614         if (buffer[1] != ARMPAC)
00615         {
00616                 PLAYER_ERROR ("ERROR: Attempt to parse a non ARM packet as arm data.\n");
00617                 return;
00618         }
00619 
00620         if (length < 1 || length != 9)
00621         {
00622                 PLAYER_WARN ("ARMpac length incorrect size");
00623                 return;
00624         }
00625 
00626         unsigned char status = buffer[2];
00627         if (status & 0x01)
00628                 armPowerOn = true;              // Power is on
00629         else
00630                 armPowerOn = false;             // Power is off
00631 
00632         if (status & 0x02)
00633                 armConnected = true;    // Connection is established
00634         else
00635                 armConnected = false;   // Connection is not established
00636 
00637         unsigned char motionStatus = buffer[3];
00638         if (motionStatus & 0x01)
00639                 armJointMoving[0] = true;
00640         if (motionStatus & 0x02)
00641                 armJointMoving[1] = true;
00642         if (motionStatus & 0x04)
00643                 armJointMoving[2] = true;
00644         if (motionStatus & 0x08)
00645                 armJointMoving[3] = true;
00646         if (motionStatus & 0x10)
00647                 armJointMoving[4] = true;
00648         if (motionStatus & 0x20)
00649                 armJointMoving[5] = true;
00650 
00651         memcpy (armJointPos, &buffer[4], 6);
00652         memset (armJointPosRads, 0, 6 * sizeof (double));
00653 }
00654 
00655 void SIP::ParseArmInfo (unsigned char *buffer)
00656 {
00657         int length = (int) buffer[0] - 2;
00658         if (buffer[1] != ARMINFOPAC)
00659         {
00660                 PLAYER_ERROR ("ERROR: Attempt to parse a non ARMINFO packet as arm info.\n");
00661                 return;
00662         }
00663 
00664         if (length < 1)
00665         {
00666                 PLAYER_WARN ("ARMINFOpac length bad size");
00667                 return;
00668         }
00669 
00670         // Copy the version string
00671         if (armVersionString)
00672                 free (armVersionString);
00673         // strndup() isn't available everywhere (e.g., Darwin)
00674         //armVersionString = strndup ((char*) &buffer[2], length);              // Can't be any bigger than length
00675         armVersionString = (char*)calloc(length+1,sizeof(char));
00676         assert(armVersionString);
00677         strncpy(armVersionString,(char*)&buffer[2], length);
00678         int dataOffset = strlen (armVersionString) + 3;         // +1 for packet size byte, +1 for packet ID, +1 for null byte
00679 
00680         armNumJoints = buffer[dataOffset];
00681         if (armJoints)
00682                 delete[] armJoints;
00683         if (armNumJoints <= 0)
00684                 return;
00685         armJoints = new ArmJoint[armNumJoints];
00686         dataOffset += 1;
00687         for (int ii = 0; ii < armNumJoints; ii++)
00688         {
00689                 armJoints[ii].speed = buffer[dataOffset + (ii * 6)];
00690                 armJoints[ii].home = buffer[dataOffset + (ii * 6) + 1];
00691                 armJoints[ii].min = buffer[dataOffset + (ii * 6) + 2];
00692                 armJoints[ii].centre = buffer[dataOffset + (ii * 6) + 3];
00693                 armJoints[ii].max = buffer[dataOffset + (ii * 6) + 4];
00694                 armJoints[ii].ticksPer90 = buffer[dataOffset + (ii * 6) + 5];
00695         }
00696 }

Last updated 12 September 2005 21:38:45