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