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