Dynamixel.cpp
Go to the documentation of this file.
00001 // Dynamixel control code - C++ file
00002 // Copyright (c) 2008 Erik Schuitema, Eelko van Breda
00003 // Delft University of Technology
00004 // www.dbl.tudelft.nl
00005 
00006 #include <threemxl/platform/hardware/dynamixel/dynamixel/Dynamixel.h>
00007 #include <threemxl/platform/hardware/dynamixel/CDxlPacketHandler.h>
00008 
00009 #include <math.h>
00010 #include <sstream>
00011 #include <algorithm>
00012 #include <string.h>
00013 
00014 using namespace std;
00015 
00016 //***********************************************************//
00017 //*********************** CDynamixel ************************//
00018 //***********************************************************//
00019 
00020 
00021 CDynamixel::CDynamixel(): CDxlGeneric(), mLog("Dynamixel")
00022 {
00023         mLog.setLevel(llCrawl);
00024         //NOTE: Most of the initial values are set in the  setConfig() and init() methods!
00025         mID                                     = -1;
00026         mPosition                       = 0;
00027         mSpeed                          = 0;
00028         mLoad                           = 0;
00029         mVoltage                        = 0;
00030         mTemperature            = 45;   // Assume 45 degrees if not measured
00031         mRetlevel                       = 0;
00032         mNullAngle                      = DXL_MAX_RAD_ANGLE/2.0;        // Put the null angle in the middle of its range by default
00033 
00034         mDirection                      = 1.0;
00035         mCWAngleLimit           = 0;
00036         mCCWAngleLimit          = DXL_MAX_POSITION;
00037         mEndlessTurnMode        = false;
00038         // Fill the angle LookUp Table with initial data
00039         for (int i=0; i<DXL_NUM_POSITIONS; i++)
00040                 mAngleLUT[i] = (double)i*DXL_STEPS_TO_RAD;
00041 }
00042 
00043 CDynamixel::~CDynamixel()
00044 {
00045 }
00046 
00047 void CDynamixel::setConfig(CDxlConfig* config)
00048 {
00049         // Just copy the configuration
00050         mConfig = *config;
00051 
00052         // Set direction convention
00053         if (mConfig.mClockwiseIsPositive.isSet())
00054                 {setPositiveDirection(mConfig.mClockwiseIsPositive);}
00055         else
00056                 {setPositiveDirection(false);}
00057         //printf("Dynamixel with ID %d has direction %.1f\n", mConfig.mID, mDirection);
00058 
00059         // Set null angle
00060         if (mConfig.mNullAngle.isSet())
00061                 {setNullAngle(mConfig.mNullAngle);}
00062 
00063         //set initial configuration if not defined in the configuration
00064         if(!mConfig.mReturnDelay.isSet() ){setReturnDelayTime(INITIAL_RETURN_DELAY_TIME);}
00065         if(!mConfig.mAngleLowerLimit.isSet() ){setAngleLowerLimit(-DXL_MAX_RAD_ANGLE/2.0);}
00066         if(!mConfig.mAngleUpperLimit.isSet() ){setAngleUpperLimit(DXL_MAX_RAD_ANGLE/2.0);}
00067         if(!mConfig.mTempLimit.isSet() ){setTemperatureLimit(INITIAL_TEMPERATURE_LIMIT);}
00068         if(!mConfig.mLED.isSet() ){enableLED(false);}
00069         if(!mConfig.mTorqueLimit.isSet() ){setTorqueLimit(INITIAL_TORQUE_LIMIT);}
00070         if(!mConfig.mAlarmLED.isSet() ){setAlarmLEDMask(DXL_ERR_OVERHEATING | DXL_ERR_OVERLOAD);}
00071         if(!mConfig.mAlarmShutdown.isSet() ){setAlarmShutdownMask(DXL_ERR_OVERHEATING);}
00072         if(!mConfig.mPunch.isSet() ){setPunch(INITIAL_PUNCH);}
00073 
00074         // the following twin configuration parameters are set if one or both are missing in the config
00075         // in this way we always have a base value even if you have only one parameter in the config.
00076         if(!(mConfig.mVoltageLowerLimit.isSet() && mConfig.mVoltageUpperLimit.isSet()) )
00077                 {setVoltageLimits(INITIAL_VOLTAGE_LOWER_LIMIT, INITIAL_VOLTAGE_UPPER_LIMIT);}
00078         if(!(mConfig.mComplianceMargin.isSet() && mConfig.mComplianceSlope.isSet()) )
00079                 {setCompliance(INITIAL_COMPLIENCE_MARGIN,INITIAL_COMPLIENCE_SLOPE);}
00080 
00081         // Process calibration data
00082         if (config->mCalibType == dxlCtAuto)
00083         {
00084                 // Just copy the LUT
00085                 memcpy(mAngleLUT, config->mAngleLUT, DXL_NUM_POSITIONS*sizeof(mAngleLUT[0]));
00086         }
00087         else
00088         if (config->mCalibType == dxlCtManual)
00089         {
00090                 int calibIndex  = 1;    // Start at 1 because we interpolate between calibIndex and calibIndex-1
00091                 for (int lutIndex=0; lutIndex<DXL_NUM_POSITIONS; lutIndex++)
00092                 {
00093                         // Search for the first calibIndex point for which the calib data exceeds the lut index
00094                         while ((config->mCalibData[calibIndex] <= (double)lutIndex) && (calibIndex < DXLCONFIG_NUM_CALIBPOINTS-1))
00095                                 calibIndex++;
00096                         // Interpolate between calibIndex and calibIndex-1
00097                         double interpolfact = ((double)lutIndex - config->mCalibData[calibIndex-1])/(config->mCalibData[calibIndex] - config->mCalibData[calibIndex-1]);
00098                                 // calibIndex represents a value in degrees. Therefore, the number of degrees between calibIndex and (calibIndex-1) is just 1 :)
00099                         mAngleLUT[lutIndex] = ((double)(calibIndex-1) + interpolfact)*M_PI/180.0;
00100                         // DEBUG output
00101                         //printf("DXL ID %d; Angle LUT [%d] = %.3f deg\n", mConfig.mID, lutIndex, mAngleLUT[lutIndex]*180.0/M_PI);
00102                 }
00103         }
00104 }
00105 
00106 void CDynamixel::setSerialPort(LxSerial* serialPort)
00107 {
00108         mSerialPort = serialPort;
00109 }
00110 
00111 void CDynamixel::setPositiveDirection(bool clockwiseIsPositive)
00112 {
00113         if (clockwiseIsPositive)
00114                 mDirection = -1.0;
00115         else
00116                 mDirection = 1.0;
00117 }
00118 
00119 void CDynamixel::setNullAngle(double nullAngle)
00120 {
00121         mNullAngle = nullAngle;
00122 }
00123 
00124 double CDynamixel::dxlPosToInternalPos(WORD pos)
00125 {
00126         int lutPos = clip(pos, 0, DXL_MAX_POSITION);
00127         if (mDirection > 0)
00128                 return mAngleLUT[lutPos] - mNullAngle;
00129         else
00130                 return DXL_MAX_RAD_ANGLE - mAngleLUT[lutPos] - mNullAngle;
00131 }
00132 
00133 int CDynamixel::internalPosToDxlPos(double pos)
00134 {
00135         // First, take care of sign (mDirection) and null-angle conventions
00136         double transpos;
00137         if (mDirection > 0)
00138                 transpos = pos + mNullAngle;
00139         else
00140                 transpos = DXL_MAX_RAD_ANGLE - (pos + mNullAngle);
00141 
00142         // The plan: find the LUT index for which mAngleLUT has the closest match to 'pos'
00143         // Make a first estimate and start searching from there on
00144         int lutIndex = clip(round(transpos/DXL_STEPS_TO_RAD), 0, DXL_MAX_POSITION);
00145 
00146         if (mAngleLUT[lutIndex] > transpos)
00147         {
00148                 // we went too far -> go back
00149                 while (mAngleLUT[lutIndex] > transpos)
00150                 {
00151                         if (lutIndex > 0)
00152                                 lutIndex--;
00153                         else
00154                                 break;
00155                 }
00156                 // Now lutIndex >= 0 (guaranteed) and mAngleLUT[lutIndex] <= pos (under normal circumstances)
00157                 if ( fabs(transpos - mAngleLUT[lutIndex]) < fabs(mAngleLUT[lutIndex+1] - transpos) )
00158                         return lutIndex;
00159                 else
00160                         return lutIndex+1;
00161         }
00162         else // apparently, mAngleLUT[lutIndex] <= pos
00163         {
00164                 // we are not there yet -> go forth
00165                 while (mAngleLUT[lutIndex] <= transpos)
00166                 {
00167                         if (lutIndex < DXL_NUM_POSITIONS-1)
00168                                 lutIndex++;
00169                         else
00170                                 break;
00171                 }
00172                 // Now lutIndex <= DXL_NUM_POSITIONS-1 (guaranteed) and mAngleLUT[lutIndex] > pos (under normal circumstances)
00173                 if ( fabs(mAngleLUT[lutIndex] - transpos) < fabs(transpos - mAngleLUT[lutIndex-1]) )
00174                         return lutIndex;
00175                 else
00176                         return lutIndex-1;
00177         }
00178 }
00179 
00180 double CDynamixel::dxlSpeedToInternalSpeed(WORD speed)
00181 {
00182         if (speed & 0x400)      // Handle the sign bit
00183                 // Negative speed
00184                 return -mDirection*DXL_SPEED_TO_RAD_S*(double)(speed & 0x3FF);
00185         else
00186                 // Positive speed
00187                 return  mDirection*DXL_SPEED_TO_RAD_S*(double)(speed & 0x3FF);
00188 }
00189 
00190 int CDynamixel::internalSpeedToDxlSpeed(double speed)
00191 {
00192         return round(mDirection*speed/DXL_SPEED_TO_RAD_S);
00193 }
00194 
00195 double CDynamixel::dxlTorqueToInternalTorque(WORD torque)
00196 {
00197         if (torque & 0x400)     // Handle the sign bit
00198                 // Negative load or torque
00199                 return -mDirection*DXL_TORQUE_TO_RATIO*(double)(torque & 0x3FF);        // 10 bits accuracy
00200         else
00201                 // Positive load or torque
00202                 return  mDirection*DXL_TORQUE_TO_RATIO*(double)(torque & 0x3FF);        // 10 bits accuracy
00203 }
00204 
00205 WORD CDynamixel::internalTorqueToDxlTorque(double torqueRatio)
00206 {
00207         int rawTorque = round(mDirection*torqueRatio/DXL_TORQUE_TO_RATIO);
00208         // Clip to 1 here, not to 0. Because when switching to position control after torque control,
00209         // 'torque' set to 0, which is actually the goal speed register, means maximum speed instead of zero speed.
00210         if (rawTorque < 0)
00211                 rawTorque = clip(-rawTorque, 1, 1023) | 0x400;  // direction bit; negative torques will decrease position
00212         else
00213                 rawTorque = clip(rawTorque, 1, 1023);
00214 
00215         return (WORD)rawTorque;
00216 }
00217 
00218 double CDynamixel::presentAngleLowerLimit()
00219 {
00220         if (mDirection<0)
00221                 return dxlPosToInternalPos(mCCWAngleLimit);
00222         else
00223                 return dxlPosToInternalPos(mCWAngleLimit);
00224 }
00225 
00226 double CDynamixel::presentAngleUpperLimit()
00227 {
00228         if (mDirection<0)
00229                 return dxlPosToInternalPos(mCWAngleLimit);
00230         else
00231                 return dxlPosToInternalPos(mCCWAngleLimit);
00232 }
00233 
00234 int CDynamixel::init(bool sendConfigToMotor)
00235 {
00236         logCrawlLn(mLog,"INIT STARTED");
00237         if (mInitialized)
00238                 return DXL_ALREADY_INITIALIZED;
00239                 
00240         int initResult = initPacketHandler();
00241         if (initResult != DXL_SUCCESS)
00242         {
00243                 logDebugLn(mLog,"Error initializing packet handler!");
00244                 return initResult;
00245         }
00246 
00247         // Set internal ID to perform initial ping() and return level readout
00248         if (mConfig.mID.isSet())
00249         {
00250                 mID = mConfig.mID;
00251         }
00252         else
00253         {
00254                 logErrorLn(mLog,"No ID set for this dynamixel");
00255                 mInitialized = false;
00256                 return DXL_NOT_INITIALIZED;
00257         }
00258 
00259         // Is this dynamixel alive?
00260         int pingResult = ping();
00261         if (pingResult != DXL_SUCCESS)
00262         {
00263                 mInitialized = false;
00264                 logErrorLn(mLog,"dynamixel with ID " << mID << " failed ping test");
00265                 return pingResult;
00266         }
00267 
00268         // Check return level
00269         BYTE retlevel;
00270         int result = readData(P_RETURN_LEVEL, 1, &retlevel);
00271         if (result == DXL_SUCCESS)
00272         {
00273                 mRetlevel               = retlevel;
00274                 mInitialized    = true;
00275         }
00276         else
00277         {
00278                 if (result == DXL_PKT_RECV_TIMEOUT)             // possible that return level is 0 and dynamixel doesn't respond
00279                 {
00280                         mRetlevel               = 0;
00281                         mInitialized    = true;
00282                 }
00283                 else
00284                         // on all other errors do not initialize
00285                         mInitialized = false;
00286         }
00287 
00288         if (sendConfigToMotor)
00289                 // Configure the motor according to mConfig
00290                 mConfig.configureDynamixel(this);
00291 
00292         return result;
00293 }
00294 
00295 int CDynamixel::changeID(const int newID)
00296 {
00297         BYTE bNewID = newID;
00298         int result = writeData(P_ID, 1, &bNewID);
00299         if (result == DXL_PKT_RECV_ID_ERR)
00300         {
00301                 // This means the ID actually changed! Success!
00302                 mID = newID;
00303                 return DXL_SUCCESS;
00304         }
00305         else
00306         if (result == DXL_SUCCESS)
00307         {
00308                 // We should get a DXL_PKT_RECV_ID_ERR but hey.. DXL_SUCCESS is better than FAIL!
00309                 //printf(" (changeID returned DXL_SUCCESS instead of DXL_PKT_RECV_ID_ERR) \n");
00310                 mID = newID;
00311                 return DXL_SUCCESS;
00312         }
00313         else
00314                 return result;
00315 }
00316 
00317 int CDynamixel::enableLED(int state)
00318 {
00319         int result=DXL_SUCCESS;
00320 
00321         if (!mInitialized)
00322                 return DXL_NOT_INITIALIZED;
00323 
00324         BYTE ledStatus;
00325         switch(state)
00326         {
00327                 case DXL_ON:
00328                         ledStatus = 1;
00329                         result = writeData(P_LED, 1, &ledStatus);
00330                         break;
00331                 case DXL_OFF:
00332                         ledStatus = 0;
00333                         result = writeData(P_LED, 1, &ledStatus);
00334                         break;
00335                 case DXL_TOGGLE:
00336                         readData(P_LED, 1, &ledStatus);
00337                         ledStatus = !ledStatus;
00338                         result = writeData(P_LED, 1, &ledStatus);
00339                         break;
00340         }
00341         return result;
00342 }
00343 
00344 int CDynamixel::getState()
00345 {
00346         if (!mInitialized)
00347         {
00348                 return DXL_NOT_INITIALIZED;
00349         }
00350         BYTE data[8];
00351         memset(data, 0, 8*sizeof(BYTE));
00352 
00353         int result = readData(P_PRESENT_POSITION_L, 8, data);
00354         if (result != DXL_SUCCESS)
00355         {
00356                 return result;
00357         }
00358 
00359         mPosition               = dxlPosToInternalPos(*(WORD*)(data));
00360         mSpeed                  = dxlSpeedToInternalSpeed((*(WORD*)(data+2)));
00361         mLoad                   = dxlTorqueToInternalTorque((*(WORD*)(data+4)));        // 10 bits accuracy + sign bit
00362         mVoltage                = DXL_VOLTAGE_TO_VOLT*data[6];
00363         mTemperature    = data[7];      // No conversion needed
00364 
00365         return DXL_SUCCESS;
00366 }
00367 
00368 int CDynamixel::getPos()
00369 {
00370         if (!mInitialized)
00371                 return DXL_NOT_INITIALIZED;
00372 
00373         BYTE data[2];
00374         int result = readData(P_PRESENT_POSITION_L, 2, data);
00375         if (result != DXL_SUCCESS)
00376                 return result;
00377 
00378         mPosition = dxlPosToInternalPos(*(WORD*)(data));
00379         return DXL_SUCCESS;
00380 }
00381 
00382 int CDynamixel::getPosAndSpeed()
00383 {
00384         if (!mInitialized)
00385         {
00386                 return DXL_NOT_INITIALIZED;
00387         }
00388         BYTE data[4];
00389         memset(data, 0, 4*sizeof(BYTE));
00390 
00391         int result = readData(P_PRESENT_POSITION_L, 4, data);
00392         if (result != DXL_SUCCESS)
00393                 return result;
00394 
00395         mPosition       = dxlPosToInternalPos(*(WORD*)(data));
00396         mSpeed          = dxlSpeedToInternalSpeed((*(WORD*)(data+2)));
00397 
00398         return DXL_SUCCESS;
00399 }
00400 
00401 int CDynamixel::getTemp()
00402 {
00403         if (!mInitialized)
00404                 return DXL_NOT_INITIALIZED;
00405 
00406         BYTE data;
00407         int result = readData(P_PRESENT_TEMPERATURE, 1, &data);
00408         if (result != DXL_SUCCESS)
00409                 return result;
00410 
00411         mTemperature = data;    // No conversion needed
00412         return DXL_SUCCESS;
00413 }
00414 
00415 int CDynamixel::setPos(double pos, double absSpeed,bool shouldSyncWrite)
00416 {
00417         if (!mInitialized)
00418                 return DXL_NOT_INITIALIZED;
00419 
00420         WORD data[2];
00421         data[0] = clip(internalPosToDxlPos(pos), 0, DXL_MAX_POSITION);
00422         if (absSpeed < 0)       // Interpret negative speeds as maximum speed
00423                 data[1] = 0;    // speed = 0 means MAXIMUM speed.
00424         else
00425                 data[1] = clip(abs(internalSpeedToDxlSpeed(absSpeed)), 1, 1023);        // use abs() here, because internalSpeedToDxlSpeed() may return something negative.
00426         return writeData(P_GOAL_POSITION_L, 4, (BYTE*)data, shouldSyncWrite);
00427 }
00428 
00429 int CDynamixel::setSpeed(double speed,bool shouldSyncWrite)
00430 {
00431         if (!mInitialized)
00432                 return DXL_NOT_INITIALIZED;
00433 
00434         int dxlSpeed = internalSpeedToDxlSpeed(speed);
00435         WORD data[2];
00436         if (dxlSpeed > 0)
00437         {
00438                 data[0] = mCCWAngleLimit;
00439                 data[1] = clip(dxlSpeed, 1, 1023);
00440         }
00441         else
00442         {
00443                 data[0] = mCWAngleLimit;
00444                 data[1] = clip(-dxlSpeed, 1, 1023);
00445         }
00446 
00447         return writeData(P_GOAL_POSITION_L, 4, (BYTE*)data, shouldSyncWrite);
00448 }
00449 
00450 int CDynamixel::setRetlevel(const int returnlevel)
00451 {
00452         if (!mInitialized)
00453                 return DXL_NOT_INITIALIZED;
00454 
00455         BYTE bRetlevel = returnlevel;
00456         writeData(P_RETURN_LEVEL, 1, &bRetlevel);
00457         mRetlevel = returnlevel;
00458         return DXL_SUCCESS;
00459 }
00460 
00461 int CDynamixel::setBaudRateIndex(const BYTE baudRateIndex)
00462 {
00463         if (!mInitialized)
00464                 return DXL_NOT_INITIALIZED;
00465 
00466         BYTE bBaudRateIndex = baudRateIndex;
00467         return writeData(P_BAUD_RATE, 1, &bBaudRateIndex);
00468 }
00469 
00470 int CDynamixel::setBaudRate(const int baudRate)
00471 {
00472         if (!mInitialized)
00473                 return DXL_NOT_INITIALIZED;
00474 
00475         BYTE bBaudRateIndex = (int)2E6/baudRate - 1;
00476         return writeData(P_BAUD_RATE, 1, &bBaudRateIndex);
00477 }
00478 
00479 int CDynamixel::setReturnDelayTime(const int microsecondsReturnDelay)
00480 {
00481         if (!mInitialized)
00482                 return DXL_NOT_INITIALIZED;
00483 
00484         BYTE bReturnDelayIndex = microsecondsReturnDelay/2;
00485         return writeData(P_RETURN_DELAY_TIME, 1, &bReturnDelayIndex);
00486 }
00487 
00488 int CDynamixel::enableTorque(int state)
00489 {
00490         int result = DXL_SUCCESS;
00491         if (!mInitialized)
00492                 return DXL_NOT_INITIALIZED;
00493 
00494         BYTE torqueStatus;
00495         switch(state)
00496         {
00497                 case DXL_ON:
00498                         torqueStatus = 1;
00499                         result = writeData(P_TORQUE_ENABLE, 1, &torqueStatus);
00500                         break;
00501                 case DXL_OFF:
00502                         torqueStatus = 0;
00503                         result = writeData(P_TORQUE_ENABLE, 1, &torqueStatus);
00504                         break;
00505                 case DXL_TOGGLE:
00506                         readData(P_TORQUE_ENABLE, 1, &torqueStatus);
00507                         torqueStatus = !torqueStatus;
00508                         result = writeData(P_TORQUE_ENABLE, 1, &torqueStatus);
00509                         break;
00510         }
00511         return result;
00512 }
00513 
00514 int CDynamixel::setInitialTorqueLimit(double absMaxTorque)
00515 {
00516         if (!mInitialized)
00517                 return DXL_NOT_INITIALIZED;
00518 
00519         WORD data = clip(round(absMaxTorque/DXL_TORQUE_TO_RATIO), 1, 1023);     // Maximum torque of 0 would mean free run state!
00520         return writeData(P_MAX_TORQUE_L, 2, (BYTE*)&data);
00521 }
00522 
00523 int CDynamixel::setTorqueLimit(double absMaxTorque)
00524 {
00525         if (!mInitialized)
00526                 return DXL_NOT_INITIALIZED;
00527 
00528         WORD data = clip(round(absMaxTorque/DXL_TORQUE_TO_RATIO), 1, 1023);     // Maximum torque of 0 would mean free run state!
00529         return writeData(P_TORQUE_LIMIT_L, 2, (BYTE*)&data);
00530 }
00531 
00532 int CDynamixel::setAngleLowerLimit(double limit)
00533 {
00534         if (!mInitialized)
00535                 return DXL_NOT_INITIALIZED;
00536 
00537         WORD data = clip(internalPosToDxlPos(limit), 0, DXL_MAX_POSITION);
00538         BYTE dxlAddress;
00539         if (mDirection<0)
00540                 dxlAddress = P_CCW_ANGLE_LIMIT_L;
00541         else
00542                 dxlAddress = P_CW_ANGLE_LIMIT_L;
00543 
00544         return writeData(dxlAddress, 2, (BYTE*)&data);
00545 }
00546 
00547 int CDynamixel::setAngleUpperLimit(double limit)
00548 {
00549         if (!mInitialized)
00550                 return DXL_NOT_INITIALIZED;
00551 
00552         WORD data = clip(internalPosToDxlPos(limit), 0, DXL_MAX_POSITION);
00553         BYTE dxlAddress;
00554         if (mDirection<0)
00555                 dxlAddress = P_CW_ANGLE_LIMIT_L;
00556         else
00557                 dxlAddress = P_CCW_ANGLE_LIMIT_L;
00558 
00559         return writeData(dxlAddress, 2, (BYTE*)&data);
00560 }
00561 
00562 int CDynamixel::setTemperatureLimit(const int maxTemp)
00563 {
00564         if (!mInitialized)
00565                 return DXL_NOT_INITIALIZED;
00566 
00567         BYTE data = maxTemp;
00568         return writeData(P_LIMIT_TEMPERATURE, 1, &data);
00569 }
00570 
00571 int CDynamixel::setVoltageLimits(double minVoltage, double maxVoltage)
00572 {
00573         if (!mInitialized)
00574                 return DXL_NOT_INITIALIZED;
00575 
00576         BYTE data[2];
00577         data[0] = round(minVoltage/DXL_VOLTAGE_TO_VOLT);
00578         data[1] = round(maxVoltage/DXL_VOLTAGE_TO_VOLT);
00579         return writeData(P_DOWN_LIMIT_VOLTAGE, 2, data);
00580 }
00581 
00582 int CDynamixel::getAngleLimits()
00583 {
00584         if (!mInitialized)
00585                 return DXL_NOT_INITIALIZED;
00586         if (mEndlessTurnMode)
00587                 return -DXL_ERR_INSTRUCTION;
00588 
00589         WORD data[2];
00590         int result = readData(P_CW_ANGLE_LIMIT_L, 4, (BYTE*)data);
00591         if (result != DXL_SUCCESS)
00592                 return result;
00593 
00594         // The angle limits are NOT saved in SI units (see member field definitions).
00595         mCWAngleLimit   = data[0];
00596         mCCWAngleLimit  = data[1];
00597         return DXL_SUCCESS;
00598 }
00599 
00600 int CDynamixel::setAngleLimits(double lowerLimit, double upperLimit)
00601 {
00602         if (!mInitialized)
00603                 return DXL_NOT_INITIALIZED;
00604 
00605         if (upperLimit < lowerLimit)
00606                 return DXL_INVALID_PARAMETER;
00607 
00608         // The angle limits are NOT saved in SI units (see member field definitions).
00609         WORD data[2];
00610         if (mDirection<0)
00611         {
00612                 data[0] = mCWAngleLimit         = clip(internalPosToDxlPos(upperLimit), 0, DXL_MAX_POSITION);
00613                 data[1] = mCCWAngleLimit        = clip(internalPosToDxlPos(lowerLimit), 0, DXL_MAX_POSITION);
00614         }
00615         else
00616         {
00617                 data[0] = mCWAngleLimit         = clip(internalPosToDxlPos(lowerLimit), 0, DXL_MAX_POSITION);
00618                 data[1] = mCCWAngleLimit        = clip(internalPosToDxlPos(upperLimit), 0, DXL_MAX_POSITION);
00619         }
00620         return writeData(P_CW_ANGLE_LIMIT_L, 4, (BYTE*)data);
00621 }
00622 
00623 int CDynamixel::setEndlessTurnMode(bool enabled,bool shouldSyncWrite)
00624 {
00625         if (!mInitialized)
00626                 return DXL_NOT_INITIALIZED;
00627 
00628         WORD data[2];
00629         int result = DXL_SUCCESS;
00630         if (enabled)
00631         {
00632                 if (result != DXL_SUCCESS)
00633                         return result;
00634                 // The angle limits are set to 0 and the internal mCWAngleLimit and mCCWAngleLimit are not changed
00635                 // in order to be able to set the mode to false again
00636                 data[0] = 0;
00637                 data[1] = 0;
00638                 result = writeData(P_CW_ANGLE_LIMIT_L, 4, (BYTE*)data, shouldSyncWrite);
00639                 if (result == DXL_SUCCESS)
00640                         mEndlessTurnMode = true;
00641         }
00642         else
00643         {
00644                 data[0] = mCWAngleLimit;
00645                 data[1] = mCCWAngleLimit;
00646                 result = writeData(P_CW_ANGLE_LIMIT_L, 4, (BYTE*)data, shouldSyncWrite);
00647                 if (result == DXL_SUCCESS)
00648                         mEndlessTurnMode = false;
00649         }
00650         return result;
00651 }
00652 
00653 int CDynamixel::setEndlessTurnTorque(double torqueRatio,bool shouldSyncWrite)
00654 {
00655         if (!mInitialized)
00656                 return DXL_NOT_INITIALIZED;
00657         /*
00658         if (!mEndlessTurnMode)
00659                 return -DXL_ERR_INSTRUCTION;
00660          *
00661          * Commented out this safety check because sometimes,
00662          * you want to set the torque to zero first before changing to endless turn mode.
00663          */
00664 
00665         WORD data = internalTorqueToDxlTorque(torqueRatio);
00666         return writeData(P_GOAL_SPEED_L, 2, (BYTE*)&data, shouldSyncWrite);     // The endless turn torque must be written to the GOAL_SPEED field!
00667 }
00668 
00669 int CDynamixel::setOperatingMode(const BYTE mode)
00670 {
00671         if (!mInitialized)
00672                 return DXL_NOT_INITIALIZED;
00673 
00674         BYTE data = mode;
00675         return writeData(P_OPERATING_MODE, 1, &data);
00676 }
00677 
00678 int CDynamixel::setAlarmLEDMask(const BYTE mask)
00679 {
00680         if (!mInitialized)
00681                 return DXL_NOT_INITIALIZED;
00682 
00683         BYTE data = mask;
00684         return writeData(P_ALARM_LED, 1, &data);
00685 }
00686 
00687 int CDynamixel::setAlarmShutdownMask(const BYTE mask)
00688 {
00689         if (!mInitialized)
00690                 return DXL_NOT_INITIALIZED;
00691 
00692         BYTE data = mask;
00693         return writeData(P_ALARM_SHUTDOWN, 1, &data);
00694 }
00695 
00696 int CDynamixel::setCompliance(BYTE complianceMargin, BYTE complianceSlope)
00697 {
00698         if (!mInitialized)
00699                 return DXL_NOT_INITIALIZED;
00700 
00701         BYTE data[4];
00702         data[0] = complianceMargin;
00703         data[1] = complianceMargin;
00704         data[2] = complianceSlope;
00705         data[3] = complianceSlope;
00706         return writeData(P_CW_COMPLIANCE_MARGIN, 4, data);
00707 }
00708 
00709 int CDynamixel::setPunch(WORD punch)
00710 {
00711         if (!mInitialized)
00712                 return DXL_NOT_INITIALIZED;
00713 
00714         WORD data = punch;
00715         return writeData(P_PUNCH_L, 2, (BYTE*)&data);
00716 }
00717 
00718 int CDynamixel::printReport(FILE* fOut)
00719 {
00720         if (!mInitialized)
00721                 return DXL_NOT_INITIALIZED;
00722 
00723         BYTE data[50];
00724         memset(data, 0, 50*sizeof(BYTE));
00725 //      int result = readData(P_MODEL_NUMBER_L, 50, data);      // Read 50 bytes to read the complete control table
00726 //      if (result != DXL_SUCCESS)
00727 //      {
00728 //              return result;
00729 //      }
00730         for(int i=0; i<50 ; i++)
00731         {
00732                 mLogInfoLn("checking adress "<<i);
00733                 int result = readData(i, 1, &data[i]);  // Read each byte
00734                 if (result != DXL_SUCCESS)
00735                 {
00736                         return result;
00737                 }
00738         }
00739         // Model, version, return delay, return level, voltage, temperature
00740         fprintf(fOut, "Model=%d (v.%d), Ret.delay=%dus, Ret.level=%d, V=%.1f, T=%d°\n", (int)(*(unsigned short*)(data+P_MODEL_NUMBER_L)), (int)data[P_VERSION], 2*(int)data[P_RETURN_DELAY_TIME], data[P_RETURN_LEVEL], DXL_VOLTAGE_TO_VOLT*(double)data[P_PRESENT_VOLTAGE], data[P_PRESENT_TEMPERATURE]);
00741         // Torque on, LED on
00742         fprintf(fOut, "Pause time: %d, Torque: %s, LED: %s\n", (int)data[P_PAUSE_TIME], data[P_TORQUE_ENABLE]?"ON":"OFF", data[P_LED]?"ON":"OFF");
00743         // Angle limit, torque limit
00744         fprintf(fOut, "%.1f° <= angle <= %.1f°, torque <= %.0f%%\n", (300.0*(int)(*(unsigned short*)(data+P_CW_ANGLE_LIMIT_L)))/(double)DXL_MAX_POSITION, (300.0*((int)(*(unsigned short*)(data+P_CCW_ANGLE_LIMIT_L))))/(double)DXL_MAX_POSITION, 100.0*(int)(*(unsigned short*)(data+P_TORQUE_LIMIT_L))/1023.0);
00745         // Current Angle
00746         fprintf(fOut, "Current Angle %.1f°\n",(300.0*(int)(*(unsigned short*)(data+P_PRESENT_POSITION_L)))/1023.0);
00747         // Control parameters
00748         fprintf(fOut, "Control compliance: \\%d\\ -%d- |*%d*| -%d- \\%d\\\n", (int)data[P_CW_COMPLIANCE_SLOPE], (int)data[P_CW_COMPLIANCE_MARGIN], (int)(*(unsigned short*)(data+P_PUNCH_L)), (int)data[P_CCW_COMPLIANCE_MARGIN], (int)data[P_CCW_COMPLIANCE_SLOPE]  );
00749         return DXL_SUCCESS;
00750 }
00751 
00752 
00753 


threemxl
Author(s):
autogenerated on Fri Aug 28 2015 13:21:08