00001 /*! @file ArmControl/ArmPlanner.C planning how to grab objects */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Chin-Kai Chang <chinkaic@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/ArmControl/ArmPlanner.C $ 00035 // $Id: ArmPlanner.C 11001 2009-03-08 06:28:55Z mundhenk $ 00036 // 00037 //#define USE_LWPR 00038 #include "ArmControl/ArmPlanner.H" 00039 00040 00041 ArmPlanner::ArmPlanner( OptionManager& mgr, 00042 const std::string& descrName, 00043 const std::string& tagName, 00044 nub::soft_ref<ArmController> realController, 00045 nub::soft_ref<ArmController> controller, 00046 nub::soft_ref<ArmSim> armSim): 00047 ModelComponent(mgr, descrName, tagName), 00048 numWarnings(0), 00049 itsRealArmController(realController), 00050 itsArmController(controller), 00051 itsArmSim(armSim), 00052 itsImage(512,256, ZEROS) 00053 { 00054 addSubComponent(itsArmController); 00055 addSubComponent(itsArmSim); 00056 00057 #ifdef USE_LWPR 00058 lwpr_read_xml(&ik_model, "ik_model.xml", &numWarnings); 00059 #endif 00060 } 00061 00062 00063 #ifdef USE_LWPR 00064 ArmController::JointPos ArmPlanner::getIK(LWPR_Model& ik_model, const double* desiredPos) 00065 { 00066 double joints[5]; 00067 lwpr_predict(&ik_model, desiredPos, 0.001, joints, NULL, NULL); 00068 00069 ArmController::JointPos jointPos; 00070 00071 jointPos.base = (int)joints[0]; 00072 jointPos.sholder = (int)joints[1]; 00073 jointPos.elbow = (int)joints[2]; 00074 jointPos.wrist1 = (int)joints[3]; 00075 jointPos.wrist2 = (int)joints[4]; 00076 // jointPos.gripper = 0; 00077 00078 LDEBUG("Mapping %0.2f %0.2f %0.2f => %i %i %i %i %i", 00079 desiredPos[0], desiredPos[1], desiredPos[2], 00080 jointPos.base, jointPos.sholder, jointPos.elbow, 00081 jointPos.wrist1, jointPos.wrist2); 00082 return jointPos; 00083 } 00084 #endif 00085 void ArmPlanner::getFK(double *endPos) 00086 { 00087 double jointsAng[5],armLoc[3]; 00088 itsArmSim->getArmLoc(armLoc); 00089 ArmController::JointPos jointPos = itsArmController->getJointPos(); 00090 jointsAng[0] = itsArmSim->encoder2ang(jointPos.base,RobotArm::BASE); 00091 jointsAng[1] = itsArmSim->encoder2ang(jointPos.sholder,RobotArm::SHOLDER); 00092 jointsAng[2] = itsArmSim->encoder2ang(jointPos.elbow,RobotArm::ELBOW); 00093 jointsAng[3] = itsArmSim->encoder2ang(jointPos.wrist1,RobotArm::WRIST1); 00094 jointsAng[4] = itsArmSim->encoder2ang(jointPos.wrist2,RobotArm::WRIST2); 00095 //Have not done yet 00096 } 00097 ArmController::JointPos ArmPlanner::getIK2(const double* desiredPos) 00098 { 00099 double joints[5],armLoc[3]; 00100 itsArmSim->getArmLoc(armLoc); 00101 ArmController::JointPos jointPos = itsArmController->getJointPos(); 00102 //joints[0] = atan2(desiredPos[1]-armLoc[1],desiredPos[0]-armLoc[0]); 00103 joints[0] = atan2(desiredPos[1]-armLoc[1],desiredPos[0]-armLoc[0]); 00104 /* 00105 | 00106 | /\ 00107 |<W> / \ 00108 |---/ | 00109 |^ 00110 |BaseH+bodyH 00111 |v 00112 +-----------o----- 00113 |<----r ----> 00114 */ 00115 // itsArmParam.base[0] = 0.230/2; //radius 00116 // itsArmParam.base[1] = 0.210; //length 00117 // 00118 // itsArmParam.body[0] = 0.200; //x 00119 // itsArmParam.body[1] = 0.200; //y 00120 // itsArmParam.body[2] = 0.174; //z 00121 // itsArmParam.upperarm[0] = 0.065; //x 00122 // itsArmParam.upperarm[1] = 0.15; //y 00123 // itsArmParam.upperarm[2] = 0.220; //z 00124 // 00125 // itsArmParam.forearm[0] = 0.06; //x 00126 // itsArmParam.forearm[1] = 0.13; //y 00127 // itsArmParam.forearm[2] = 0.220; //z 00128 00129 double r = getDistance2D(armLoc,desiredPos); 00130 double x = r - 0.03;//upperarm to body offset 00131 double y = -1*(0.210+0.174) + desiredPos[2]; // + 0.11;//base length + body height 00132 double l1 = 0.220 ;//upperarm 00133 double l2 = 0.220 + 0.145;// - 0.06;//forearm + wrist 00134 00135 double c2 = (sq(x)+sq(y)-sq(l1)-sq(l2)) / (2*l1*l2); 00136 if(c2 < 1 && c2 > -1){ 00137 jointPos.base = itsArmSim->ang2encoder(joints[0],RobotArm::BASE); //set the base 00138 double s2 = -1* sqrt(1-sq(c2)); 00139 00140 double th2 = atan2(-1*s2,c2); 00141 jointPos.elbow = itsArmSim->ang2encoder(th2-M_PI/2,RobotArm::ELBOW); 00142 00143 double k1 = l1+l2*c2; 00144 double k2 = l2*s2; 00145 double th1 = atan2(y,x) - atan2(k2,k1); 00146 //th1 = M_PI; 00147 jointPos.sholder = itsArmSim->ang2encoder(-1*th1+M_PI/2,RobotArm::SHOLDER); 00148 double th3 = M_PI/2 - th1 - th2; 00149 jointPos.wrist2 = itsArmSim->ang2encoder(th3,RobotArm::WRIST2); 00150 jointPos.wrist2 = 0;//itsArmSim->ang2encoder(th3,RobotArm::WRIST2); 00151 jointPos.wrist1 = 0; 00152 00153 LINFO("th1 %f,th2 %f , th3 %f, r %f ,x %f,y %f, c2 %f ,s2 %f",th1,th2,th3, r,x,y,c2,s2); 00154 // jointPos.gripper = 0; 00155 jointPos.reachable = true; 00156 }else{ 00157 00158 LINFO("Unreachable point x %f y %f z %f",desiredPos[0],desiredPos[1],desiredPos[2]); 00159 jointPos.reachable = false; 00160 } 00161 LDEBUG("Mapping %0.2f %0.2f %0.2f => %i %i %i %i %i", 00162 desiredPos[0], desiredPos[1], desiredPos[2], 00163 jointPos.base, jointPos.sholder, jointPos.elbow, 00164 jointPos.wrist1, jointPos.wrist2); 00165 return jointPos; 00166 } 00167 00168 #ifdef USE_LWPR 00169 void ArmPlanner::trainArm(LWPR_Model& ik_model, const double* armPos, const ArmController::JointPos& jointPos) 00170 { 00171 00172 double joints[5]; 00173 double pJoints[5]; 00174 LDEBUG("Training => %0.2f,%0.2f,%0.2f => %i %i %i %i %i", 00175 armPos[0], armPos[1], armPos[2], 00176 jointPos.base, jointPos.sholder, jointPos.elbow, 00177 jointPos.wrist1, jointPos.wrist2); 00178 00179 joints[0] = jointPos.base; 00180 joints[1] = jointPos.sholder; 00181 joints[2] = jointPos.elbow; 00182 joints[3] = jointPos.wrist1; 00183 joints[4] = jointPos.wrist2; 00184 00185 lwpr_update(&ik_model, armPos, joints, pJoints, NULL); 00186 00187 } 00188 #endif 00189 ArmController::JointPos ArmPlanner::calcGradient(const double* desiredPos) 00190 { 00191 00192 ArmController::JointPos jointPos = itsArmController->getJointPos(); 00193 ArmController::JointPos tmpJointPos = jointPos; 00194 00195 double dist1, dist2; 00196 double baseGrad, sholderGrad, elbowGrad; 00197 double err = getDistance(itsArmSim->getEndPos(), desiredPos); 00198 00199 //get the base gradient 00200 tmpJointPos.base = jointPos.base + 100; 00201 itsArmController->setJointPos(tmpJointPos); 00202 dist1 = getDistance(itsArmSim->getEndPos(), desiredPos); 00203 00204 tmpJointPos.base = jointPos.base - 100; 00205 itsArmController->setJointPos(tmpJointPos); 00206 dist2 = getDistance(itsArmSim->getEndPos(), desiredPos); 00207 baseGrad = dist1 - dist2; 00208 tmpJointPos.base = jointPos.base; 00209 00210 //get the base gradient 00211 tmpJointPos.sholder = jointPos.sholder + 100; 00212 itsArmController->setJointPos(tmpJointPos); 00213 dist1 = getDistance(itsArmSim->getEndPos(), desiredPos); 00214 tmpJointPos.sholder = jointPos.sholder - 100; 00215 itsArmController->setJointPos(tmpJointPos); 00216 dist2 = getDistance(itsArmSim->getEndPos(), desiredPos); 00217 sholderGrad = dist1 - dist2; 00218 tmpJointPos.sholder = jointPos.sholder; 00219 00220 //get the elbow gradient 00221 tmpJointPos.elbow = jointPos.elbow + 100; 00222 itsArmController->setJointPos(tmpJointPos); 00223 dist1 = getDistance(itsArmSim->getEndPos(), desiredPos); 00224 tmpJointPos.elbow = jointPos.elbow - 100; 00225 itsArmController->setJointPos(tmpJointPos); 00226 dist2 = getDistance(itsArmSim->getEndPos(), desiredPos); 00227 elbowGrad = dist1 - dist2; 00228 tmpJointPos.elbow = jointPos.elbow; 00229 00230 int moveThresh = (int)(err*100000); 00231 jointPos.base -= (int)(randomUpToIncluding(moveThresh)*baseGrad); 00232 jointPos.sholder -= (int)(randomUpToIncluding(moveThresh)*sholderGrad); 00233 jointPos.elbow -= (int)(randomUpToIncluding(moveThresh)*elbowGrad); 00234 00235 return jointPos; 00236 } 00237 00238 00239 bool ArmPlanner::gibbsSampling(double *desire,double errThres) 00240 { 00241 double current_distance = getDistance(itsArmSim->getEndPos(),desire); 00242 double prev_distance = current_distance; 00243 errThres = errThres * errThres; 00244 int moveThres = 200; 00245 if(current_distance < 0.02) 00246 moveThres /= 2;//half 50 00247 if(current_distance < 0.01) 00248 moveThres /= 2;//half 25 00249 if(current_distance < errThres){//close than 5mm 00250 return true; 00251 } 00252 do{ 00253 int motor = randomUpToIncluding(2);//get 0,1,2 motor 00254 int move = randomUpToIncluding(moveThres*2)-moveThres;//default get -100~100 move 00255 00256 LINFO("Move motor %d with %d dist %f",motor,move,current_distance); 00257 prev_distance = current_distance; 00258 moveMotor(motor,move); 00259 current_distance = getDistance(itsArmSim->getEndPos(),desire); 00260 LINFO("Motor moved %d with %d dist %f",motor,move,current_distance); 00261 00262 //After random move 00263 if(current_distance > prev_distance)//if getting far 00264 { 00265 // 00266 moveMotor(motor,-move); 00267 } 00268 }while(current_distance > prev_distance); 00269 00270 //Get joint pos from armSim and sync with real arm 00271 ArmController::JointPos jointPos = itsArmController->getJointPos(); 00272 itsRealArmController->setJointPos(sim2real(jointPos),false); 00273 return false; 00274 } 00275 00276 void ArmPlanner::moveMotor(int motor,int move) 00277 { 00278 switch(motor) 00279 { 00280 case 0: 00281 itsArmController->setBasePos(move, true); 00282 break; 00283 case 1: 00284 itsArmController->setSholderPos(move, true); 00285 break; 00286 case 2: 00287 itsArmController->setElbowPos(move, true); 00288 break; 00289 default: 00290 break; 00291 } 00292 while(!itsArmController->isFinishMove()) 00293 { 00294 itsArmSim->simLoop(); 00295 usleep(1000); 00296 } 00297 } 00298 bool ArmPlanner::gibbsControl(double *desire,double d) 00299 { 00300 double *current = itsArmSim->getEndPos(); 00301 double distance = getDistance(itsArmSim->getEndPos(),desire); 00302 //double errThres = 0.005; 00303 double errThresForSampling = d; 00304 double v[3],nextPoint[3]; 00305 if(getDistance(itsArmSim->getEndPos(),desire) < 0.01){ 00306 LINFO("Move by gibbs only"); 00307 errThresForSampling = d; 00308 return gradient(desire,errThresForSampling); 00309 }else{ 00310 for(int i=0;i<3;i++) 00311 { 00312 v[i] = desire[i] - current[i];//line vec 00313 v[i] = v[i]/distance;//vhat 00314 nextPoint[i] = current[i]+(distance/2)*v[i]; 00315 } 00316 while(!gradient(nextPoint,errThresForSampling)); 00317 LINFO("Move to next point %f %f %f %f",nextPoint[0],nextPoint[1],nextPoint[2],getDistance(itsArmSim->getEndPos(),nextPoint)); 00318 00319 } 00320 00321 return false; 00322 00323 } 00324 00325 bool ArmPlanner::gradient(double *desire,double errThres) 00326 { 00327 int gradient_base = itsArmSim->getGradientEncoder(RobotArm::BASE,desire); 00328 int gradient_sholder= itsArmSim->getGradientEncoder(RobotArm::SHOLDER,desire); 00329 int gradient_elbow = itsArmSim->getGradientEncoder(RobotArm::ELBOW,desire); 00330 gradient_base =(int)((double)gradient_base*(-483/63)); 00331 gradient_sholder=(int)((double)gradient_sholder*(-2606/354)); 00332 gradient_elbow =(int)((double)gradient_elbow*(-46/399)); 00333 errThres = errThres * errThres; 00334 LINFO("Gradient: %d %d %d dist %f",gradient_base,gradient_sholder,gradient_elbow, 00335 getDistance(itsArmSim->getEndPos(),desire)); 00336 if(getDistance(itsArmSim->getEndPos(),desire) > errThres){ 00337 // moveMotor(0,gradient_base/10); 00338 // moveMotor(1,gradient_sholder/10); 00339 // moveMotor(2,gradient_elbow/10); 00340 00341 }else{ 00342 return true; 00343 } 00344 return false; 00345 } 00346 00347 bool ArmPlanner::moveRel(double x,double y,double z,double errThres) 00348 { 00349 00350 double err; 00351 double* current = itsArmSim->getEndPos(); 00352 double desire[3]; 00353 int numTries = 0; 00354 00355 desire[0] = current[0] + x; 00356 desire[1] = current[1] + y; 00357 desire[2] = current[2] + z; 00358 LINFO("Current %f,%f,%f De: %f,%f,%f", 00359 current[0], current[1], current[2], 00360 desire[0], desire[1], desire[2]); 00361 getchar(); 00362 00363 //Predict the joint angle required for this position 00364 ArmController::JointPos jointPos = getIK2(desire); 00365 LINFO("Got Joint POs"); 00366 if(!jointPos.reachable){ 00367 LINFO("Can't reach point"); 00368 return false;//can't not reach those point 00369 } 00370 //move the arm 00371 CtrlPolicy xCP; 00372 CtrlPolicy yCP; 00373 CtrlPolicy zCP; 00374 xCP.setGoalPos(desire[0]); 00375 yCP.setGoalPos(desire[1]); 00376 zCP.setGoalPos(desire[2]); 00377 00378 00379 xCP.setCurrentPos(current[0]); 00380 yCP.setCurrentPos(current[1]); 00381 zCP.setCurrentPos(current[2]); 00382 LINFO("Moving"); 00383 err = getDistance(itsArmSim->getEndPos(), desire); 00384 int numTriesThres = 10000; 00385 while(err > errThres && numTries < numTriesThres) 00386 { 00387 00388 numTries++; 00389 double cp[3]; 00390 current = itsArmSim->getEndPos(); 00391 cp[0] = xCP.getPos(current[0]); 00392 cp[1] = yCP.getPos(current[1]); 00393 cp[2] = zCP.getPos(current[2]); 00394 //Showing the moving path, it may slow down the computer 00395 //itsArmSim->addDrawObject(ArmSim::SPHERE, cp); 00396 //LINFO("cpx %f y %f z %f",cp[0],cp[1],cp[2]); 00397 jointPos = getIK2(cp); 00398 updateDataImg(); 00399 if(jointPos.reachable){ 00400 itsArmController->setJointPos(jointPos,true); 00401 //itsRealArmController->setJointPos(sim2real(jointPos),false); 00402 } else { 00403 LINFO("Can't reach point"); 00404 } 00405 //LINFO("numTries %d",numTries); 00406 err = getDistance(itsArmSim->getEndPos(), desire); 00407 } 00408 if(numTries <= numTriesThres) 00409 { 00410 jointPos = getIK2(desire); 00411 itsArmController->setJointPos(jointPos); 00412 //If arm doesn't fellow the cp , than don't wait arm finish 00413 //itsRealArmController->setJointPos(sim2real(jointPos),false); 00414 } 00415 else{ 00416 LINFO("Can't reach point"); 00417 00418 } 00419 //gibbsSampling(desire,errThres); 00420 //Check the final error 00421 err = getDistance(itsArmSim->getEndPos(), desire); 00422 00423 LINFO("Moving Done,err %f errThres %f",err,errThres); 00424 return (err < errThres); 00425 00426 } 00427 bool ArmPlanner::move(double *desire,double errThres) 00428 { 00429 double err; 00430 int numTries = 0; 00431 //Predict the joint angle required for this position 00432 ArmController::JointPos jointPos = getIK2(desire); 00433 LINFO("Got Joint POs"); 00434 if(!jointPos.reachable){ 00435 LINFO("Can't reach point"); 00436 return false;//can't not reach those point 00437 } 00438 //move the arm 00439 CtrlPolicy xCP; 00440 CtrlPolicy yCP; 00441 CtrlPolicy zCP; 00442 xCP.setGoalPos(desire[0]); 00443 yCP.setGoalPos(desire[1]); 00444 zCP.setGoalPos(desire[2]); 00445 00446 00447 double* current = itsArmSim->getEndPos(); 00448 xCP.setCurrentPos(current[0]); 00449 yCP.setCurrentPos(current[1]); 00450 zCP.setCurrentPos(current[2]); 00451 LINFO("Moving"); 00452 err = getDistance(itsArmSim->getEndPos(), desire); 00453 int numTriesThres = 10000; 00454 while(err > errThres && numTries < numTriesThres) 00455 { 00456 00457 numTries++; 00458 double cp[3]; 00459 current = itsArmSim->getEndPos(); 00460 cp[0] = xCP.getPos(current[0]); 00461 cp[1] = yCP.getPos(current[1]); 00462 cp[2] = zCP.getPos(current[2]); 00463 //Showing the moving path, it may slow down the computer 00464 //itsArmSim->addDrawObject(ArmSim::SPHERE, cp); 00465 //LINFO("cpx %f y %f z %f",cp[0],cp[1],cp[2]); 00466 jointPos = getIK2(cp); 00467 updateDataImg(); 00468 if(jointPos.reachable){ 00469 itsArmController->setJointPos(jointPos,true); 00470 itsRealArmController->setJointPos(sim2real(jointPos),false); 00471 } else { 00472 LINFO("Can't reach point"); 00473 } 00474 //LINFO("numTries %d",numTries); 00475 err = getDistance(itsArmSim->getEndPos(), desire); 00476 } 00477 if(numTries <= numTriesThres) 00478 { 00479 jointPos = getIK2(desire); 00480 itsArmController->setJointPos(jointPos); 00481 //If arm doesn't fellow the cp , than don't wait arm finish 00482 itsRealArmController->setJointPos(sim2real(jointPos),false); 00483 } 00484 else{ 00485 LINFO("Can't reach point"); 00486 00487 } 00488 //gibbsSampling(desire,errThres); 00489 //Check the final error 00490 err = getDistance(itsArmSim->getEndPos(), desire); 00491 00492 LINFO("Moving Done,err %f errThres %f",err,errThres); 00493 return (err < errThres); 00494 } 00495 void ArmPlanner::minJerk(double *desire,double *nextPoint,double time) 00496 { 00497 double *currentPos = itsArmSim->getEndPos(); 00498 double distance = getDistance(currentPos,desire); 00499 double d = distance * 100;//Using distance to calc total time 00500 // double t = 1; 00501 for(int i = 0 ; i < 3 ; i++) 00502 { 00503 double td = time/d; 00504 nextPoint[i] = currentPos[i]+(desire[i] - currentPos[i]) 00505 *(10*pow(td,3) - 15*pow(td,4) + 6*pow(td,5)); 00506 00507 } 00508 00509 } 00510 //#ifdef CPDISPLAY 00511 void ArmPlanner::updateDataImg() 00512 { 00513 static int x = 0; 00514 //const double* endpos = itsArmSim->getEndPos(); 00515 if (x < itsImage.getWidth()) 00516 { 00517 if (!x) 00518 itsImage.clear(); 00519 00520 //int xpos= (int)(-1.0*((float)endpos[0]*100.0F)*256.0F); 00521 //LINFO("xpos %i endpos[0] %f",xpos, endpos[0]); 00522 //drawCircle(img,Point2D<int>(x,basePos), 2, PixRGB<byte>(255,0,0)); 00523 itsImage.setVal(x,0, PixRGB<byte>(255,0,0)); 00524 //itsImage.setVal(x,x/2, PixRGB<byte>(255,0,0)); 00525 00526 x++; // = (x+1)%img.getWidth(); 00527 } 00528 00529 } 00530 //#endif 00531 ArmController::JointPos ArmPlanner::sim2real(ArmController::JointPos armSimJointPos ) 00532 { 00533 00534 ArmController::JointPos scorbotJointPos; 00535 00536 scorbotJointPos.base = armSimJointPos.base ; 00537 scorbotJointPos.sholder = armSimJointPos.sholder; 00538 scorbotJointPos.elbow = armSimJointPos.elbow ; 00539 scorbotJointPos.wrist1 = armSimJointPos.wrist1 ; 00540 scorbotJointPos.wrist2 = armSimJointPos.wrist2 ; 00541 scorbotJointPos.reachable= armSimJointPos.reachable ; 00542 00543 //scorbotJointPos.gripper = 1; 00544 scorbotJointPos.elbow += scorbotJointPos.sholder; 00545 00546 scorbotJointPos.wrist1 += (int)((0.2496*(float)scorbotJointPos.elbow )-39.746) ;//+ pitch + (roll + offset) ; 00547 scorbotJointPos.wrist2 -= (int)((0.2496*(float)scorbotJointPos.elbow )-39.746) ;//- pitch + (roll + offset); 00548 scorbotJointPos.elbow *=-1; 00549 //LINFO("sim2real :%d %d %d ",scorbotJointPos.base,scorbotJointPos.sholder,scorbotJointPos.elbow); 00550 return scorbotJointPos; 00551 }