00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <assert.h>
00019 #include <cob_canopen_motor/CanDriveHarmonica.h>
00020 #include <unistd.h>
00021
00022
00023 CanDriveHarmonica::CanDriveHarmonica()
00024 {
00025
00026 m_Param.iDivForRequestStatus = 10;
00027 m_Param.dCanTimeout = 6;
00028
00029
00030 m_pCanCtrl = NULL;
00031
00032 m_iStatusCtrl = 0;
00033 m_dPosGearMeasRad = 0;
00034 m_dAngleGearRadMem = 0;
00035 m_dVelGearMeasRadS = 0;
00036
00037 m_VelCalcTime.SetNow();
00038
00039 m_bLimSwLeft = false;
00040 m_bLimSwRight = false;
00041
00042 m_bLimitSwitchEnabled = false;
00043
00044 m_iCountRequestDiv = 0;
00045
00046 m_iMotorState = ST_PRE_INITIALIZED;
00047 m_bCurrentLimitOn = false;
00048
00049 m_iNumAttempsRecFail = 0;
00050
00051 m_SendTime.SetNow();
00052 m_StartTime.SetNow();
00053
00054 m_bOutputOfFailure = false;
00055
00056 m_bIsInitialized = false;
00057
00058
00059 ElmoRec = new ElmoRecorder(this);
00060
00061 }
00062
00063
00064 void CanDriveHarmonica::setCanOpenParam( int iTxPDO1, int iTxPDO2, int iRxPDO2, int iTxSDO, int iRxSDO )
00065 {
00066 m_ParamCanOpen.iTxPDO1 = iTxPDO1;
00067 m_ParamCanOpen.iTxPDO2 = iTxPDO2;
00068 m_ParamCanOpen.iRxPDO2 = iRxPDO2;
00069 m_ParamCanOpen.iTxSDO = iTxSDO;
00070 m_ParamCanOpen.iRxSDO = iRxSDO;
00071
00072 }
00073
00074
00075 bool CanDriveHarmonica::evalReceivedMsg(CanMsg& msg)
00076 {
00077 bool bRet = false;
00078 int iDigIn;
00079 int iFailure;
00080 int iPara;
00081
00082 int iHomeDigIn = 0x0001;
00083 int iTemp1, iTemp2;
00084
00085 m_CanMsgLast = msg;
00086
00087
00088
00089 if (msg.m_iID == m_ParamCanOpen.iTxPDO1)
00090 {
00091 iTemp1 = (msg.getAt(3) << 24) | (msg.getAt(2) << 16)
00092 | (msg.getAt(1) << 8) | (msg.getAt(0) );
00093
00094 m_dPosGearMeasRad = m_DriveParam.getSign() * m_DriveParam.
00095 PosMotIncrToPosGearRad(iTemp1);
00096
00097 iTemp2 = (msg.getAt(7) << 24) | (msg.getAt(6) << 16)
00098 | (msg.getAt(5) << 8) | (msg.getAt(4) );
00099
00100 m_dVelGearMeasRadS = m_DriveParam.getSign() * m_DriveParam.
00101 VelMotIncrPeriodToVelGearRadS(iTemp2);
00102
00103 m_WatchdogTime.SetNow();
00104
00105 bRet = true;
00106 }
00107
00108
00109
00110 if (msg.m_iID == m_ParamCanOpen.iTxPDO2)
00111 {
00112 if( (msg.getAt(0) == 'P') && (msg.getAt(1) == 'X') )
00113 {
00114 }
00115
00116 else if( (msg.getAt(0) == 'P') && (msg.getAt(1) == 'A') )
00117 {
00118 }
00119
00120 else if( (msg.getAt(0) == 'J') && (msg.getAt(1) == 'V') )
00121 {
00122 }
00123
00124 else if( (msg.getAt(0) == 'B') && (msg.getAt(1) == 'G') )
00125 {
00126 }
00127
00128 else if( (msg.getAt(0) == 'U') && (msg.getAt(1) == 'M') )
00129 {
00130 iDigIn = 0x1FFFFF & ( (msg.getAt(7) << 24) | (msg.getAt(6) << 16)
00131 | (msg.getAt(5) << 8) | (msg.getAt(4)) );
00132 }
00133
00134 else if( (msg.getAt(0) == 'I') && (msg.getAt(1) == 'P') )
00135 {
00136 iDigIn = 0x1FFFFF & ( (msg.getAt(7) << 24) | (msg.getAt(6) << 16)
00137 | (msg.getAt(5) << 8) | (msg.getAt(4)) );
00138 iDigIn = 0x1FFFFF & ( (msg.getAt(7) << 24) | (msg.getAt(6) << 16)
00139 | (msg.getAt(5) << 8) | (msg.getAt(4)) );
00140
00141 if( (iDigIn & iHomeDigIn) != 0x0000 )
00142 {
00143 m_bLimSwRight = true;
00144 }
00145 }
00146
00147 else if( (msg.getAt(0) == 'S') && (msg.getAt(1) == 'R') )
00148 {
00149 m_iStatusCtrl = (msg.getAt(7) << 24) | (msg.getAt(6) << 16)
00150 | (msg.getAt(5) << 8) | (msg.getAt(4) );
00151
00152 evalStatusRegister(m_iStatusCtrl);
00153 ElmoRec->readoutRecorderTryStatus(m_iStatusCtrl, seg_Data);
00154
00155 }
00156
00157 else if( (msg.getAt(0) == 'M') && (msg.getAt(1) == 'F') )
00158 {
00159 iFailure = (msg.getAt(7) << 24) | (msg.getAt(6) << 16)
00160 | (msg.getAt(5) << 8) | (msg.getAt(4) );
00161
00162 evalMotorFailure(iFailure);
00163 }
00164
00165
00166 else if( (msg.getAt(0) == 'U') && (msg.getAt(1) == 'M') )
00167 {
00168 iPara = (msg.getAt(7) << 24) | (msg.getAt(6) << 16)
00169 | (msg.getAt(5) << 8) | (msg.getAt(4) );
00170
00171 std::cout << "um " << iPara << std::endl;
00172 }
00173
00174 else if( (msg.getAt(0) == 'P') && (msg.getAt(1) == 'M') )
00175 {
00176 iPara = (msg.getAt(7) << 24) | (msg.getAt(6) << 16)
00177 | (msg.getAt(5) << 8) | (msg.getAt(4) );
00178
00179 std::cout << "pm " << iPara << std::endl;
00180 }
00181
00182 else if( (msg.getAt(0) == 'A') && (msg.getAt(1) == 'C') )
00183 {
00184 iPara = (msg.getAt(7) << 24) | (msg.getAt(6) << 16)
00185 | (msg.getAt(5) << 8) | (msg.getAt(4) );
00186
00187 std::cout << "ac " << iPara << std::endl;
00188 }
00189
00190 else if( (msg.getAt(0) == 'D') && (msg.getAt(1) == 'C') )
00191 {
00192 iPara = (msg.getAt(7) << 24) | (msg.getAt(6) << 16)
00193 | (msg.getAt(5) << 8) | (msg.getAt(4) );
00194
00195 std::cout << "dc " << iPara << std::endl;
00196 }
00197 else if( (msg.getAt(0) == 'H') && (msg.getAt(1) == 'M') )
00198 {
00199
00200 if(msg.getAt(4) == 0)
00201 {
00202
00203 m_bLimSwRight = true;
00204 }
00205 }
00206 else if( (msg.getAt(0) == 'I') && (msg.getAt(1) == 'Q') )
00207 {
00208 int iVal=0;
00209 iVal = (msg.getAt(7) << 24) | (msg.getAt(6) << 16)
00210 | (msg.getAt(5) << 8) | (msg.getAt(4) );
00211 float* pfVal;
00212 pfVal=(float*)&iVal;
00213 m_dMotorCurr = *pfVal;
00214 }
00215
00216 else
00217 {
00218 }
00219
00220 m_WatchdogTime.SetNow();
00221
00222 bRet = true;
00223 }
00224
00225
00226
00227 if (msg.m_iID == m_ParamCanOpen.iTxSDO)
00228 {
00229 m_WatchdogTime.SetNow();
00230
00231 if( (msg.getAt(0) >> 5) == 0) {
00232
00233 receivedSDODataSegment(msg);
00234
00235 } else if( (msg.getAt(0) & 0xE2) == 0x40) {
00236
00237 receivedSDOSegmentedInitiation(msg);
00238
00239 } else if( (msg.getAt(0) >> 5) == 4) {
00240 unsigned int iErrorNum = (msg.getAt(4) | msg.getAt(5) << 8 | msg.getAt(6) << 16 | msg.getAt(7) << 24);
00241 receivedSDOTransferAbort(iErrorNum);
00242 }
00243
00244 bRet = true;
00245 }
00246
00247 return bRet;
00248 }
00249
00250
00251 bool CanDriveHarmonica::init()
00252 {
00253 int iCnt, iPosCnt;
00254 bool bRet = true;
00255 CanMsg Msg;
00256
00257 m_iMotorState = ST_PRE_INITIALIZED;
00258
00259
00260
00261 int iIncrRevWheel = int( (double)m_DriveParam.getGearRatio() * (double)m_DriveParam.getBeltRatio()
00262 * (double)m_DriveParam.getEncIncrPerRevMot() * 3 );
00263 IntprtSetInt(8, 'M', 'O', 0, 0);
00264 usleep(20000);
00265 IntprtSetInt(8, 'X', 'M', 2, iIncrRevWheel * 5000);
00266 usleep(20000);
00267 IntprtSetInt(8, 'X', 'M', 1, -iIncrRevWheel * 5000);
00268 usleep(20000);
00269
00270
00271 setTypeMotion(MOTIONTYPE_VELCTRL);
00272
00273 IntprtSetInt(8, 'P', 'X', 0, 0);
00274
00275 iCnt = 0;
00276 while(true)
00277 {
00278 m_pCanCtrl->receiveMsg(&Msg);
00279
00280 if( (Msg.getAt(0) == 'P') && (Msg.getAt(1) == 'X') )
00281 {
00282 iPosCnt = (Msg.getAt(7) << 24) | (Msg.getAt(6) << 16)
00283 | (Msg.getAt(5) << 8) | (Msg.getAt(4) );
00284
00285 m_dPosGearMeasRad = m_DriveParam.getSign() * m_DriveParam.PosMotIncrToPosGearRad(iPosCnt);
00286 m_dAngleGearRadMem = m_dPosGearMeasRad;
00287 break;
00288 }
00289
00290 if ( iCnt > 300 )
00291 {
00292 std::cout << "CanDriveHarmonica: initial position not set" << std::endl;
00293 bRet = false;
00294 break;
00295 }
00296
00297 usleep(10000);
00298 iCnt++;
00299 }
00300
00301
00302
00303
00304
00305
00306
00307 sendSDODownload(0x1A00, 0, 0);
00308
00309
00310 sendSDODownload(0x1A00, 1, 0x60640020);
00311
00312
00313 sendSDODownload(0x1A00, 2, 0x60690020);
00314
00315
00316 sendSDODownload(0x1800, 2, 1);
00317
00318
00319 sendSDODownload(0x1A00, 0, 2);
00320
00321 m_bWatchdogActive = false;
00322
00323 if( bRet )
00324 m_bIsInitialized = true;
00325
00326 return bRet;
00327 }
00328
00329 bool CanDriveHarmonica::stop()
00330 {
00331 bool bRet = true;
00332
00333 IntprtSetInt(8, 'M', 'O', 0, 0);
00334 usleep(20000);
00335 return bRet;
00336 }
00337
00338 bool CanDriveHarmonica::start()
00339 {
00340
00341 IntprtSetInt(8, 'M', 'O', 0, 1);
00342 usleep(20000);
00343
00344
00345 int iCnt;
00346 bool bRet = true;
00347 int iStatus;
00348 CanMsg Msg;
00349
00350
00351 do
00352 {
00353 bRet = m_pCanCtrl->receiveMsg(&Msg);
00354 }
00355 while(bRet == true);
00356
00357
00358 IntprtSetInt(4, 'S', 'R', 0, 0);
00359
00360 iCnt = 0;
00361 while(true)
00362 {
00363 m_pCanCtrl->receiveMsg(&Msg);
00364
00365 if( (Msg.getAt(0) == 'S') && (Msg.getAt(1) == 'R') )
00366 {
00367 iStatus = (Msg.getAt(7) << 24) | (Msg.getAt(6) << 16)
00368 | (Msg.getAt(5) << 8) | (Msg.getAt(4) );
00369
00370 bRet = evalStatusRegister(iStatus);
00371 break;
00372 }
00373
00374 if ( iCnt > 300 )
00375 {
00376 std::cout << "CanDriveHarmonica::enableMotor(): No answer on status request" << std::endl;
00377 bRet = false;
00378 break;
00379 }
00380
00381 usleep(10000);
00382 iCnt++;
00383 }
00384
00385
00386 m_WatchdogTime.SetNow();
00387 m_SendTime.SetNow();
00388
00389 return bRet;
00390 }
00391
00392
00393 bool CanDriveHarmonica::reset()
00394 {
00395
00396
00397
00398 CanMsg msg;
00399 msg.m_iID = 0;
00400 msg.m_iLen = 2;
00401 msg.set(1,0,0,0,0,0,0,0);
00402 m_pCanCtrl->transmitMsg(msg);
00403
00404
00405 bool bRet = init();
00406 bRet |= start();
00407
00408 return bRet;
00409 }
00410
00411 bool CanDriveHarmonica::shutdown()
00412 {
00413 std::cout << "shutdown drive " << m_DriveParam.getDriveIdent() << std::endl;
00414
00415 IntprtSetInt(8, 'M', 'O', 0, 0);
00416
00417 return true;
00418 }
00419
00420
00421 bool CanDriveHarmonica::startWatchdog(bool bStarted)
00422 {
00423 if (bStarted == true)
00424 {
00425
00426 m_bWatchdogActive = true;
00427
00428
00429
00430
00431 const int c_iHeartbeatTimeMS = 1000;
00432 const int c_iNMTNodeID = 0x00;
00433
00434
00435 sendSDODownload(0x1016, 1, (c_iNMTNodeID << 16) | c_iHeartbeatTimeMS);
00436
00437
00438 sendSDODownload(0x1029, 1, 2);
00439
00440
00441 sendSDODownload(0x6007, 0, 3);
00442
00443
00444
00445
00446 sendSDODownload(0x2F21, 0, 0x08);
00447 usleep(20000);
00448
00449 }
00450 else
00451 {
00452
00453 m_bWatchdogActive = false;
00454
00455
00456 sendSDODownload(0x6007, 0, 0);
00457
00458
00459 sendSDODownload(0x1029, 1, 1);
00460
00461
00462
00463
00464 sendSDODownload(0x2F21, 0, 0x00);
00465 usleep(25000);
00466
00467
00468 }
00469
00470 return true;
00471 }
00472
00473
00474 bool CanDriveHarmonica::disableBrake(bool bDisabled)
00475 {
00476 return true;
00477 }
00478
00479
00480 double CanDriveHarmonica::getTimeToLastMsg()
00481 {
00482 m_CurrentTime.SetNow();
00483
00484 return m_CurrentTime - m_WatchdogTime;
00485 }
00486
00487 bool CanDriveHarmonica::getStatusLimitSwitch()
00488 {
00489 return m_bLimSwRight;
00490 }
00491
00492 bool CanDriveHarmonica::initHoming()
00493 {
00494 const int c_iPosRef = m_DriveParam.getEncOffset();
00495
00496
00497
00498 IntprtSetInt(8, 'H', 'M', 1, 0);
00499
00500
00501 usleep(20000);
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 IntprtSetInt(8, 'H', 'M', 2, c_iPosRef);
00514 usleep(20000);
00515
00516
00517
00518
00519
00520
00521 IntprtSetInt(8, 'H', 'M', 3, m_DriveParam.getHomingDigIn());
00522
00523 usleep(20000);
00524
00525
00526
00527
00528
00529 IntprtSetInt(8, 'H', 'M', 4, 2);
00530 usleep(20000);
00531
00532
00533
00534 IntprtSetInt(8, 'H', 'M', 5, 0);
00535 usleep(20000);
00536
00537
00538
00539 return true;
00540 }
00541
00542
00543
00544 bool CanDriveHarmonica::execHoming()
00545 {
00546
00547 int iCnt;
00548 CanMsg Msg;
00549 bool bRet = true;
00550
00551 int iNrDrive = m_DriveParam.getDriveIdent();
00552
00553
00554
00555 IntprtSetInt(8, 'H', 'M', 1, 1);
00556
00557
00558 do
00559 {
00560
00561 bRet = m_pCanCtrl->receiveMsg(&Msg);
00562 }
00563 while(bRet == true);
00564
00565
00566
00567
00568 iCnt = 0;
00569
00570 do
00571 {
00572
00573
00574 IntprtSetInt(4, 'H', 'M', 1, 0);
00575
00576
00577 m_pCanCtrl->receiveMsgRetry(&Msg, 10);
00578
00579
00580 if( (Msg.getAt(0) == 'H') && (Msg.getAt(1) == 'M') )
00581 {
00582
00583 if(Msg.getAt(4) == 0)
00584 {
00585
00586 std::cout << "Got Homing-Signal " << std::endl;
00587 m_bLimSwRight = true;
00588 break;
00589 }
00590 }
00591
00592
00593 usleep(10000);
00594 iCnt++;
00595
00596 }
00597 while((m_bLimSwRight == false) && (iCnt<2000));
00598
00599
00600 if(iCnt>=2000)
00601 {
00602 std::cout << "Homing failed - limit switch " << iNrDrive << " not reached" << std::endl;
00603 bRet = false;
00604 }
00605 else
00606 {
00607 std::cout << "Homing successful - limit switch " << iNrDrive << " ok" << std::endl;
00608 bRet = true;
00609 }
00610
00611
00612
00613 return bRet;
00614 }
00615
00616 void CanDriveHarmonica::setGearPosVelRadS(double dPosGearRad, double dVelGearRadS)
00617 {
00618 int iPosEncIncr;
00619 int iVelEncIncrPeriod;
00620
00621 m_DriveParam.PosVelRadToIncr(dPosGearRad, dVelGearRadS, &iPosEncIncr, &iVelEncIncrPeriod);
00622
00623 if(iVelEncIncrPeriod > m_DriveParam.getVelMax())
00624 {
00625 iVelEncIncrPeriod = (int)m_DriveParam.getVelMax();
00626 }
00627
00628 if(iVelEncIncrPeriod < -m_DriveParam.getVelMax())
00629 {
00630 iVelEncIncrPeriod = (int)-m_DriveParam.getVelMax();
00631 }
00632
00633 if(m_iTypeMotion == MOTIONTYPE_POSCTRL)
00634 {
00635
00636 IntprtSetInt(8, 'S', 'P', 0, iVelEncIncrPeriod);
00637
00638
00639
00640
00641 if (m_DriveParam.getIsSteer() == true)
00642 IntprtSetInt(8, 'P', 'A', 0, iPosEncIncr);
00643 else
00644 IntprtSetInt(8, 'P', 'R', 0, iPosEncIncr);
00645
00646 IntprtSetInt(4, 'B', 'G', 0, 0);
00647
00648 }
00649
00650 if(m_iTypeMotion == MOTIONTYPE_VELCTRL)
00651 {
00652 iVelEncIncrPeriod *= m_DriveParam.getSign();
00653 IntprtSetInt(8, 'J', 'V', 0, iVelEncIncrPeriod);
00654 IntprtSetInt(4, 'B', 'G', 0, 0);
00655 }
00656
00657
00658
00659 CanMsg msg;
00660 msg.m_iID = 0x80;
00661 msg.m_iLen = 0;
00662 msg.set(0,0,0,0,0,0,0,0);
00663 m_pCanCtrl->transmitMsg(msg);
00664 }
00665
00666
00667 void CanDriveHarmonica::setGearVelRadS(double dVelGearRadS)
00668 {
00669 int iVelEncIncrPeriod;
00670
00671
00672 iVelEncIncrPeriod = m_DriveParam.getSign() * m_DriveParam.VelGearRadSToVelMotIncrPeriod(dVelGearRadS);
00673
00674 if(iVelEncIncrPeriod > m_DriveParam.getVelMax())
00675 {
00676 std::cout << "SteerVelo asked for " << iVelEncIncrPeriod << " EncIncrements" << std::endl;
00677 iVelEncIncrPeriod = (int)m_DriveParam.getVelMax();
00678 }
00679
00680 if(iVelEncIncrPeriod < -m_DriveParam.getVelMax())
00681 {
00682 std::cout << "SteerVelo asked for " << iVelEncIncrPeriod << " EncIncrements" << std::endl;
00683 iVelEncIncrPeriod = -1 * (int)m_DriveParam.getVelMax();
00684 }
00685
00686 IntprtSetInt(8, 'J', 'V', 0, iVelEncIncrPeriod);
00687 IntprtSetInt(4, 'B', 'G', 0, 0);
00688
00689
00690
00691
00692 CanMsg msg;
00693 msg.m_iID = 0x80;
00694 msg.m_iLen = 0;
00695 msg.set(0,0,0,0,0,0,0,0);
00696 m_pCanCtrl->transmitMsg(msg);
00697
00698
00699 msg.m_iID = 0x700;
00700 msg.m_iLen = 5;
00701 msg.set(0x00,0,0,0,0,0,0,0);
00702 m_pCanCtrl->transmitMsg(msg);
00703
00704 m_CurrentTime.SetNow();
00705 double dt = m_CurrentTime - m_SendTime;
00706 if ((dt > 1.0) && m_bWatchdogActive)
00707 {
00708 std::cout << "Time between send velocity of motor " << m_DriveParam.getDriveIdent()
00709 << " is too large: " << dt << " s" << std::endl;
00710 }
00711 m_SendTime.SetNow();
00712
00713
00714
00715 m_iCountRequestDiv++;
00716 if (m_iCountRequestDiv > m_Param.iDivForRequestStatus)
00717 {
00718 requestStatus();
00719 m_iCountRequestDiv = 0;
00720 }
00721 }
00722
00723
00724 void CanDriveHarmonica::getGearPosRad(double* dGearPosRad)
00725 {
00726 *dGearPosRad = m_dPosGearMeasRad;
00727 }
00728
00729
00730 void CanDriveHarmonica::getGearPosVelRadS(double* pdAngleGearRad, double* pdVelGearRadS)
00731 {
00732 *pdAngleGearRad = m_dPosGearMeasRad;
00733 *pdVelGearRadS = m_dVelGearMeasRadS;
00734 }
00735
00736
00737 void CanDriveHarmonica::getGearDeltaPosVelRadS(double* pdAngleGearRad, double* pdVelGearRadS)
00738 {
00739 *pdAngleGearRad = m_dPosGearMeasRad - m_dAngleGearRadMem;
00740 *pdVelGearRadS = m_dVelGearMeasRadS;
00741 m_dAngleGearRadMem = m_dPosGearMeasRad;
00742 }
00743
00744
00745 void CanDriveHarmonica::getData(double* pdPosGearRad, double* pdVelGearRadS,
00746 int* piTorqueCtrl, int* piStatusCtrl)
00747 {
00748 *pdPosGearRad = m_dPosGearMeasRad;
00749 *pdVelGearRadS = m_dVelGearMeasRadS;
00750 *piTorqueCtrl = m_iTorqueCtrl;
00751 *piStatusCtrl = m_iStatusCtrl;
00752 }
00753
00754
00755 void CanDriveHarmonica::requestPosVel()
00756 {
00757
00758 CanMsg msg;
00759 msg.m_iID = 0x80;
00760 msg.m_iLen = 0;
00761 msg.set(0,0,0,0,0,0,0,0);
00762 m_pCanCtrl->transmitMsg(msg);
00763
00764 }
00765
00766
00767 void CanDriveHarmonica::sendHeartbeat()
00768 {
00769 CanMsg msg;
00770 msg.m_iID = 0x700;
00771 msg.m_iLen = 5;
00772 msg.set(0x00,0,0,0,0,0,0,0);
00773 m_pCanCtrl->transmitMsg(msg);
00774 }
00775
00776
00777 void CanDriveHarmonica::requestStatus()
00778 {
00779 IntprtSetInt(4, 'S', 'R', 0, 0);
00780 }
00781
00782
00783 void CanDriveHarmonica::requestMotorTorque()
00784 {
00785
00786 IntprtSetInt(4, 'I', 'Q', 0, 0);
00787
00788 }
00789
00790
00791 bool CanDriveHarmonica::isError()
00792 {
00793 if (m_iMotorState != ST_MOTOR_FAILURE)
00794 {
00795
00796 double dWatchTime = getTimeToLastMsg();
00797
00798 if (dWatchTime>m_Param.dCanTimeout)
00799 {
00800 if ( m_bOutputOfFailure == false)
00801 {
00802 std::cout << "Motor " << m_DriveParam.getDriveIdent() <<
00803 " has no can communication for " << dWatchTime << " s." << std::endl;
00804 }
00805
00806 m_iMotorState = ST_MOTOR_FAILURE;
00807 m_FailureStartTime.SetNow();
00808 }
00809
00810 }
00811
00812 return (m_iMotorState == ST_MOTOR_FAILURE);
00813 }
00814
00815 bool CanDriveHarmonica::setTypeMotion(int iType)
00816 {
00817 int iMaxAcc = int(m_DriveParam.getMaxAcc());
00818 int iMaxDcc = int(m_DriveParam.getMaxDec());
00819 CanMsg Msg;
00820
00821 if (iType == MOTIONTYPE_POSCTRL)
00822 {
00823
00824
00825
00826 IntprtSetInt(8, 'M', 'O', 0, 0);
00827 usleep(20000);
00828
00829 IntprtSetInt(8, 'U', 'M', 0, 5);
00830
00831
00832 IntprtSetInt(8, 'T', 'R', 1, 15);
00833
00834 IntprtSetInt(8, 'T', 'R', 2, 100);
00835
00836
00837 IntprtSetInt(8, 'A', 'C', 0, iMaxAcc);
00838
00839 IntprtSetInt(8, 'D', 'C', 0, iMaxDcc);
00840 usleep(100000);
00841
00842
00843 }
00844 else if (iType == MOTIONTYPE_TORQUECTRL)
00845 {
00846
00847
00848 IntprtSetInt(8, 'M', 'O', 0, 0);
00849 usleep(50000);
00850
00851 IntprtSetInt(8, 'U', 'M', 0, 1);
00852
00853
00854 IntprtSetInt(8, 'R', 'M', 0, 0);
00855
00856
00857 std::cout << "Motor"<<m_DriveParam.getDriveIdent()<<" Unit Mode switched to: TORQUE controlled" << std::endl;
00858 usleep(100000);
00859 }
00860 else
00861 {
00862
00863
00864 IntprtSetInt(8, 'M', 'O', 0, 0);
00865
00866 IntprtSetInt(8, 'U', 'M', 0, 2);
00867
00868 IntprtSetInt(8, 'P', 'M', 0, 1);
00869
00870
00871 IntprtSetInt(8, 'A', 'C', 0, iMaxAcc);
00872
00873 IntprtSetInt(8, 'D', 'C', 0, iMaxDcc);
00874 usleep(100000);
00875 }
00876
00877 m_iTypeMotion = iType;
00878 return true;
00879 }
00880
00881
00882
00883 void CanDriveHarmonica::IntprtSetInt(int iDataLen, char cCmdChar1, char cCmdChar2, int iIndex, int iData)
00884 {
00885 char cIndex[2];
00886 char cInt[4];
00887 CanMsg CMsgTr;
00888
00889 CMsgTr.m_iID = m_ParamCanOpen.iRxPDO2;
00890 CMsgTr.m_iLen = iDataLen;
00891
00892 cIndex[0] = iIndex;
00893 cIndex[1] = (iIndex >> 8) & 0x3F;
00894
00895 cInt[0] = iData;
00896 cInt[1] = iData >> 8;
00897 cInt[2] = iData >> 16;
00898 cInt[3] = iData >> 24;
00899
00900 CMsgTr.set(cCmdChar1, cCmdChar2, cIndex[0], cIndex[1], cInt[0], cInt[1], cInt[2], cInt[3]);
00901 m_pCanCtrl->transmitMsg(CMsgTr);
00902 }
00903
00904
00905 void CanDriveHarmonica::IntprtSetFloat(int iDataLen, char cCmdChar1, char cCmdChar2, int iIndex, float fData)
00906 {
00907 char cIndex[2];
00908 char cFloat[4];
00909 CanMsg CMsgTr;
00910 char* pTempFloat = NULL;
00911
00912 CMsgTr.m_iID = m_ParamCanOpen.iRxPDO2;
00913 CMsgTr.m_iLen = iDataLen;
00914
00915 cIndex[0] = iIndex;
00916
00917 cIndex[1] = (iIndex >> 8) & 0x3F;
00918 cIndex[1] = cIndex[1] | 0x80;
00919
00920 pTempFloat = (char*)&fData;
00921 for( int i=0; i<4; i++ )
00922 cFloat[i] = pTempFloat[i];
00923
00924 CMsgTr.set(cCmdChar1, cCmdChar2, cIndex[0], cIndex[1], cFloat[0], cFloat[1], cFloat[2], cFloat[3]);
00925 m_pCanCtrl->transmitMsg(CMsgTr);
00926 }
00927
00928
00929
00930
00931
00932
00933 void CanDriveHarmonica::sendSDOAbort(int iObjIndex, int iObjSubIndex, unsigned int iErrorCode)
00934 {
00935 CanMsg CMsgTr;
00936 const int ciAbortTransferReq = 0x04 << 5;
00937
00938 CMsgTr.m_iLen = 8;
00939 CMsgTr.m_iID = m_ParamCanOpen.iRxSDO;
00940
00941 unsigned char cMsg[8];
00942
00943 cMsg[0] = ciAbortTransferReq;
00944 cMsg[1] = iObjIndex;
00945 cMsg[2] = iObjIndex >> 8;
00946 cMsg[3] = iObjSubIndex;
00947 cMsg[4] = iErrorCode;
00948 cMsg[5] = iErrorCode >> 8;
00949 cMsg[6] = iErrorCode >> 16;
00950 cMsg[7] = iErrorCode >> 24;
00951
00952 CMsgTr.set(cMsg[0], cMsg[1], cMsg[2], cMsg[3], cMsg[4], cMsg[5], cMsg[6], cMsg[7]);
00953 m_pCanCtrl->transmitMsg(CMsgTr);
00954 }
00955
00956
00957 void CanDriveHarmonica::receivedSDOTransferAbort(unsigned int iErrorCode){
00958 std::cout << "SDO Abort Transfer received with error code: " << iErrorCode;
00959 seg_Data.statusFlag = segData::SDO_SEG_FREE;
00960 }
00961
00962
00963 void CanDriveHarmonica::sendSDOUpload(int iObjIndex, int iObjSubIndex)
00964 {
00965 CanMsg CMsgTr;
00966 const int ciInitUploadReq = 0x40;
00967
00968 CMsgTr.m_iLen = 8;
00969 CMsgTr.m_iID = m_ParamCanOpen.iRxSDO;
00970
00971 unsigned char cMsg[8];
00972
00973 cMsg[0] = ciInitUploadReq;
00974 cMsg[1] = iObjIndex;
00975 cMsg[2] = iObjIndex >> 8;
00976 cMsg[3] = iObjSubIndex;
00977 cMsg[4] = 0x00;
00978 cMsg[5] = 0x00;
00979 cMsg[6] = 0x00;
00980 cMsg[7] = 0x00;
00981
00982 CMsgTr.set(cMsg[0], cMsg[1], cMsg[2], cMsg[3], cMsg[4], cMsg[5], cMsg[6], cMsg[7]);
00983 m_pCanCtrl->transmitMsg(CMsgTr);
00984 }
00985
00986
00987 void CanDriveHarmonica::sendSDODownload(int iObjIndex, int iObjSubIndex, int iData)
00988 {
00989 CanMsg CMsgTr;
00990
00991 const int ciInitDownloadReq = 0x20;
00992 const int ciNrBytesNoData = 0x00;
00993 const int ciExpedited = 0x02;
00994 const int ciDataSizeInd = 0x01;
00995
00996 CMsgTr.m_iLen = 8;
00997 CMsgTr.m_iID = m_ParamCanOpen.iRxSDO;
00998
00999 unsigned char cMsg[8];
01000
01001 cMsg[0] = ciInitDownloadReq | (ciNrBytesNoData << 2) | ciExpedited | ciDataSizeInd;
01002 cMsg[1] = iObjIndex;
01003 cMsg[2] = iObjIndex >> 8;
01004 cMsg[3] = iObjSubIndex;
01005 cMsg[4] = iData;
01006 cMsg[5] = iData >> 8;
01007 cMsg[6] = iData >> 16;
01008 cMsg[7] = iData >> 24;
01009
01010 CMsgTr.set(cMsg[0], cMsg[1], cMsg[2], cMsg[3], cMsg[4], cMsg[5], cMsg[6], cMsg[7]);
01011 m_pCanCtrl->transmitMsg(CMsgTr);
01012 }
01013
01014
01015 void CanDriveHarmonica::evalSDO(CanMsg& CMsg, int* pIndex, int* pSubindex)
01016 {
01017 *pIndex = (CMsg.getAt(2) << 8) | CMsg.getAt(1);
01018 *pSubindex = CMsg.getAt(3);
01019 }
01020
01021
01022 int CanDriveHarmonica::getSDODataInt32(CanMsg& CMsg)
01023 {
01024 int iData = (CMsg.getAt(7) << 24) | (CMsg.getAt(6) << 16) |
01025 (CMsg.getAt(5) << 8) | CMsg.getAt(4);
01026
01027 return iData;
01028 }
01029
01030
01031 int CanDriveHarmonica::receivedSDOSegmentedInitiation(CanMsg& msg) {
01032
01033 if(seg_Data.statusFlag == segData::SDO_SEG_FREE || seg_Data.statusFlag == segData::SDO_SEG_WAITING) {
01034 seg_Data.resetTransferData();
01035 seg_Data.statusFlag = segData::SDO_SEG_COLLECTING;
01036
01037
01038 evalSDO(msg, &seg_Data.objectID, &seg_Data.objectSubID);
01039
01040
01041 if( (msg.getAt(0) & 0x01) == 1) {
01042 seg_Data.numTotalBytes = msg.getAt(7) << 24 | msg.getAt(6) << 16 | msg.getAt(5) << 8 | msg.getAt(4);
01043 } else seg_Data.numTotalBytes = 0;
01044
01045 sendSDOUploadSegmentConfirmation(seg_Data.toggleBit);
01046 }
01047
01048 return 0;
01049
01050 }
01051
01052
01053 int CanDriveHarmonica::receivedSDODataSegment(CanMsg& msg){
01054
01055 int numEmptyBytes = 0;
01056
01057
01058
01059
01060
01061 if( (msg.getAt(0) & 0x10) != (seg_Data.toggleBit << 4) ) {
01062 std::cout << "Toggle Bit error, send Abort SDO with \"Toggle bit not alternated\" error" << std::endl;
01063 sendSDOAbort(seg_Data.objectID, seg_Data.objectSubID, 0x05030000);
01064 return 1;
01065 }
01066
01067 if( (msg.getAt(0) & 0x01) == 0x00) {
01068 seg_Data.statusFlag = segData::SDO_SEG_COLLECTING;
01069 } else {
01070
01071 seg_Data.statusFlag = segData::SDO_SEG_PROCESSING;
01072 };
01073
01074 numEmptyBytes = (msg.getAt(0) >> 1) & 0x07;
01075
01076
01077 for(int i=1; i<=7-numEmptyBytes; i++) {
01078 seg_Data.data.push_back(msg.getAt(i));
01079 }
01080
01081 if(seg_Data.statusFlag == segData::SDO_SEG_PROCESSING) {
01082 finishedSDOSegmentedTransfer();
01083 } else {
01084 seg_Data.toggleBit = !seg_Data.toggleBit;
01085 sendSDOUploadSegmentConfirmation(seg_Data.toggleBit);
01086 }
01087
01088 return 0;
01089 }
01090
01091
01092 void CanDriveHarmonica::sendSDOUploadSegmentConfirmation(bool toggleBit) {
01093
01094 CanMsg CMsgTr;
01095 int iConfirmSegment = 0x60;
01096 iConfirmSegment = iConfirmSegment | (toggleBit << 4);
01097
01098 CMsgTr.m_iLen = 8;
01099 CMsgTr.m_iID = m_ParamCanOpen.iRxSDO;
01100
01101 unsigned char cMsg[8];
01102
01103 cMsg[0] = iConfirmSegment;
01104 cMsg[1] = 0x00;
01105 cMsg[2] = 0x00;
01106 cMsg[3] = 0x00;
01107 cMsg[4] = 0x00;
01108 cMsg[5] = 0x00;
01109 cMsg[6] = 0x00;
01110 cMsg[7] = 0x00;
01111
01112 CMsgTr.set(cMsg[0], cMsg[1], cMsg[2], cMsg[3], cMsg[4], cMsg[5], cMsg[6], cMsg[7]);
01113 m_pCanCtrl->transmitMsg(CMsgTr);
01114 }
01115
01116
01117 void CanDriveHarmonica::finishedSDOSegmentedTransfer() {
01118 seg_Data.statusFlag = segData::SDO_SEG_PROCESSING;
01119
01120 if( (seg_Data.data.size() != seg_Data.numTotalBytes) & (seg_Data.numTotalBytes != 0) ) {
01121 std::cout << "WARNING: SDO tranfer finished but number of collected bytes "
01122 << seg_Data.data.size() << " != expected number of bytes: " << seg_Data.numTotalBytes << std::endl;
01123
01124 }
01125
01126 if(seg_Data.objectID == 0x2030) {
01127 if(ElmoRec->processData(seg_Data) == 0) seg_Data.statusFlag = segData::SDO_SEG_FREE;
01128 }
01129 }
01130
01131
01132 double CanDriveHarmonica::estimVel(double dPos)
01133 {
01134 double dVel;
01135 double dt;
01136
01137 m_CurrentTime.SetNow();
01138
01139 dt = m_CurrentTime - m_VelCalcTime;
01140
01141 dVel = (dPos - m_dOldPos)/dt;
01142
01143 m_dOldPos = dPos;
01144 m_VelCalcTime.SetNow();
01145
01146 return dVel;
01147 }
01148
01149 bool CanDriveHarmonica::evalStatusRegister(int iStatus)
01150 {
01151 bool bNoError;
01152
01153
01154 if( isBitSet(iStatus, 0) )
01155 {
01156
01157 if ( m_bOutputOfFailure == false )
01158 {
01159 std::cout << "Error of drive: " << m_DriveParam.getDriveIdent() << std::endl;
01160
01161 if( (iStatus & 0x0000000E) == 2)
01162 std::cout << "- drive error under voltage" << std::endl;
01163
01164 if( (iStatus & 0x0000000E) == 4)
01165 std::cout << "- drive error over voltage" << std::endl;
01166
01167 if( (iStatus & 0x0000000E) == 10)
01168 std::cout << "- drive error short circuit" << std::endl;
01169
01170 if( (iStatus & 0x0000000E) == 12)
01171 std::cout << "- drive error overheating" << std::endl;
01172
01173
01174 IntprtSetInt(4, 'M', 'F', 0, 0);
01175 }
01176
01177 m_iNewMotorState = ST_MOTOR_FAILURE;
01178
01179 bNoError = false;
01180 }
01181 else if ( isBitSet(iStatus, 6) )
01182 {
01183
01184 if ( m_bOutputOfFailure == false )
01185 {
01186 std::cout << "Motor " << m_DriveParam.getDriveIdent() << " failure latched" << std::endl;
01187
01188
01189 IntprtSetInt(4, 'M', 'F', 0, 0);
01190
01191 m_FailureStartTime.SetNow();
01192 }
01193 m_iNewMotorState = ST_MOTOR_FAILURE;
01194
01195 bNoError = false;
01196 }
01197 else
01198 {
01199
01200 bNoError = true;
01201
01202
01203
01204
01205 m_bOutputOfFailure = false;
01206
01207
01208
01209 if( isBitSet(iStatus, 4) )
01210 {
01211 if (m_iMotorState != ST_OPERATION_ENABLED)
01212 {
01213 std::cout << "Motor " << m_DriveParam.getDriveIdent() << " operation enabled" << std::endl;
01214 m_FailureStartTime.SetNow();
01215 }
01216
01217 m_iNewMotorState = ST_OPERATION_ENABLED;
01218 }
01219 else
01220 {
01221 if (m_iMotorState != ST_OPERATION_DISABLED)
01222 {
01223 std::cout << "Motor " << m_DriveParam.getDriveIdent() << " operation disabled" << std::endl;
01224 }
01225
01226 m_iNewMotorState = ST_OPERATION_DISABLED;
01227 }
01228
01229
01230 if( isBitSet(iStatus, 13) )
01231 {
01232 if (m_bCurrentLimitOn == false)
01233 std::cout << "Motor " << m_DriveParam.getDriveIdent() << "current limit on" << std::endl;
01234
01235 m_bCurrentLimitOn = true;
01236 }
01237 else
01238 m_bCurrentLimitOn = false;
01239 }
01240
01241
01242 m_iMotorState = m_iNewMotorState;
01243
01244 if (m_iMotorState == ST_MOTOR_FAILURE)
01245 m_bOutputOfFailure = true;
01246
01247 return bNoError;
01248 }
01249
01250
01251 void CanDriveHarmonica::evalMotorFailure(int iFailure)
01252 {
01253
01254 std::cout << "Motor " << m_DriveParam.getDriveIdent() << " has a failure: " << iFailure << std::endl;
01255
01256 if( isBitSet(iFailure, 2) )
01257 {
01258 std::cout << "- feedback loss" << std::endl;
01259 }
01260
01261 if( isBitSet(iFailure, 3) )
01262 {
01263 std::cout << "- peak current excced" << std::endl;
01264 }
01265
01266 if( isBitSet(iFailure, 7) )
01267 {
01268 std::cout << "- speed track error" << std::endl;
01269 }
01270
01271 if( isBitSet(iFailure, 8) )
01272 {
01273 std::cout << "- position track error" << std::endl;
01274 }
01275
01276 if( isBitSet(iFailure, 17) )
01277 {
01278 std::cout << "- speed limit exceeded" << std::endl;
01279 }
01280
01281 if( isBitSet(iFailure, 21) )
01282 {
01283 std::cout << "- motor stuck" << std::endl;
01284 }
01285 }
01286
01287
01288 void CanDriveHarmonica::setMotorTorque(double dTorqueNm)
01289 {
01290
01291 float fMotCurr = m_DriveParam.getSign() * dTorqueNm / m_DriveParam.getCurrToTorque();
01292
01293
01294 if (fMotCurr > m_DriveParam.getCurrMax())
01295 {
01296 fMotCurr = m_DriveParam.getCurrMax();
01297 std::cout << "Torque command too high: " << fMotCurr << " Nm. Torque has been limitited." << std::endl;
01298 }
01299 if (fMotCurr < -m_DriveParam.getCurrMax())
01300 {
01301 fMotCurr = -m_DriveParam.getCurrMax();
01302 std::cout << "Torque command too high: " << fMotCurr << " Nm. Torque has been limitited." << std::endl;
01303 }
01304
01305
01306 IntprtSetFloat(8, 'T', 'C', 0, fMotCurr);
01307
01308
01309 CanMsg msg;
01310 msg.m_iID = 0x80;
01311 msg.m_iLen = 0;
01312 msg.set(0,0,0,0,0,0,0,0);
01313 m_pCanCtrl->transmitMsg(msg);
01314
01315
01316 sendHeartbeat();
01317
01318 m_CurrentTime.SetNow();
01319 double dt = m_CurrentTime - m_SendTime;
01320 if (dt > 1.0)
01321 {
01322 std::cout << "Time between send current/torque of motor " << m_DriveParam.getDriveIdent()
01323 << " is too large: " << dt << " s" << std::endl;
01324 }
01325 m_SendTime.SetNow();
01326
01327
01328
01329 m_iCountRequestDiv++;
01330 if (m_iCountRequestDiv > m_Param.iDivForRequestStatus)
01331 {
01332 requestStatus();
01333 m_iCountRequestDiv = 0;
01334 }
01335
01336 }
01337
01338
01339 void CanDriveHarmonica::getMotorTorque(double* dTorqueNm)
01340 {
01341
01342 *dTorqueNm = m_DriveParam.getSign() * m_dMotorCurr * m_DriveParam.getCurrToTorque();
01343
01344 }
01345
01346
01347
01348
01349
01350
01351
01352
01353 int CanDriveHarmonica::setRecorder(int iFlag, int iParam, std::string sParam) {
01354
01355 switch(iFlag) {
01356 case 0:
01357 if(iParam < 1) iParam = 1;
01358 ElmoRec->isInitialized(true);
01359 ElmoRec->configureElmoRecorder(iParam, m_DriveParam.getDriveIdent());
01360 return 0;
01361
01362 case 1:
01363 if(!ElmoRec->isInitialized(false)) return 1;
01364
01365 if(seg_Data.statusFlag == segData::SDO_SEG_FREE) {
01366 if( (iParam != 1) && (iParam != 2) && (iParam != 10) && (iParam != 16) ) {
01367 iParam = 1;
01368 std::cout << "Changed the Readout object to #1 as your selected object hasn't been recorded!" << std::endl;
01369 }
01370 ElmoRec->setLogFilename(sParam);
01371 seg_Data.statusFlag = segData::SDO_SEG_WAITING;
01372 ElmoRec->readoutRecorderTry(iParam);
01373 return 0;
01374 } else {
01375 std::cout << "Previous transmission not finished or colected data hasn't been proceeded yet" << std::endl;
01376 return 2;
01377 }
01378
01379 break;
01380
01381 case 2:
01382 if(seg_Data.statusFlag == segData::SDO_SEG_COLLECTING) {
01383
01384 return 2;
01385 } else if(seg_Data.statusFlag == segData::SDO_SEG_PROCESSING) {
01386
01387 return 2;
01388 } else if(seg_Data.statusFlag == segData::SDO_SEG_WAITING) {
01389
01390 return 2;
01391 } else {
01392 return 0;
01393 }
01394
01395 break;
01396
01397 case 99:
01398 sendSDOAbort(0x2030, 0x00, 0x08000020);
01399 seg_Data.resetTransferData();
01400 return 0;
01401 }
01402
01403 return 0;
01404 }