CanDriveHarmonica.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *   http://www.apache.org/licenses/LICENSE-2.0
00009 
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
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         // Parameter
00026         m_Param.iDivForRequestStatus = 10;
00027         m_Param.dCanTimeout = 6;
00028 
00029         // Variables
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; // 0x0001 for CoB3 steering drive homing input; 0x0400 for Scara
00083         int iTemp1, iTemp2;
00084 
00085         m_CanMsgLast = msg;
00086 
00087         //-----------------------
00088         // eval answers from PDO1 - transmitted on SYNC msg
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         // eval answers from binary interpreter
00110         if (msg.m_iID == m_ParamCanOpen.iTxPDO2)
00111         {
00112                 if( (msg.getAt(0) == 'P') && (msg.getAt(1) == 'X') ) // current pos
00113                 {
00114                 }
00115 
00116                 else if( (msg.getAt(0) == 'P') && (msg.getAt(1) == 'A') ) // position absolute
00117                 {
00118                 }
00119 
00120                 else if( (msg.getAt(0) == 'J') && (msg.getAt(1) == 'V') ) // current velocity
00121                 {
00122                 }
00123 
00124                 else if( (msg.getAt(0) == 'B') && (msg.getAt(1) == 'G') ) // begin motion
00125                 {
00126                 }
00127 
00128                 else if( (msg.getAt(0) == 'U') && (msg.getAt(1) == 'M') ) // user mode
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') ) // digital in == limit switches
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') ) // status
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') ) // motor failure
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                 // debug eval
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                         // status message (homing armed = 1 / disarmed = 0) is encoded in 5th byte
00200                         if(msg.getAt(4) == 0)
00201                         {
00202                                 // if 0 received: elmo disarmed homing after receiving the defined event
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         // eval answer from SDO
00227         if (msg.m_iID == m_ParamCanOpen.iTxSDO)
00228         {
00229                 m_WatchdogTime.SetNow();
00230 
00231                 if( (msg.getAt(0) >> 5) == 0) { //Received Upload SDO Segment (scs = 0)
00232                         //std::cout << "SDO Upload Segment received" << std::endl;
00233                         receivedSDODataSegment(msg);
00234 
00235                 } else if( (msg.getAt(0) & 0xE2) == 0x40) { //Received Initiate SDO Upload, that is not expedited -> start segmented upload (scs = 2 AND expedited flag = 0)
00236                         //std::cout << "SDO Initiate Segmented Upload received, Object ID: " << (msg.getAt(1) | (msg.getAt(2) << 8) ) << std::endl;
00237                         receivedSDOSegmentedInitiation(msg);
00238 
00239                 } else if( (msg.getAt(0) >> 5) == 4) { // Received an Abort SDO Transfer message, cs = 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         // Set Values for Modulo-Counting. Neccessary to preserve absolute position for homed motors (after encoder overflow)
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         // ---------- set position counter to zero
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         // ---------- set PDO mapping
00302         // Mapping of TPDO1:
00303         // - position
00304         // - velocity
00305 
00306         // stop all emissions of TPDO1
00307         sendSDODownload(0x1A00, 0, 0);
00308 
00309         // position 4 byte of TPDO1
00310         sendSDODownload(0x1A00, 1, 0x60640020);
00311 
00312         // velocity 4 byte of TPDO1
00313         sendSDODownload(0x1A00, 2, 0x60690020);
00314 
00315         // transmission type "synch"
00316         sendSDODownload(0x1800, 2, 1);
00317 
00318         // activate mapped objects
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         // motor off
00333         IntprtSetInt(8, 'M', 'O', 0, 0);
00334         usleep(20000);
00335         return bRet;
00336 }
00337 //-----------------------------------------------
00338 bool CanDriveHarmonica::start()
00339 {
00340         // motor on
00341         IntprtSetInt(8, 'M', 'O', 0, 1);
00342         usleep(20000);
00343 
00344         // ------------------- request status
00345         int iCnt;
00346         bool bRet = true;
00347         int iStatus;
00348         CanMsg Msg;
00349 
00350         //  clear the can buffer
00351         do
00352         {
00353                 bRet = m_pCanCtrl->receiveMsg(&Msg);
00354         }
00355         while(bRet == true);
00356 
00357         // send request
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         // ------------------- start watchdog timer
00386         m_WatchdogTime.SetNow();
00387         m_SendTime.SetNow();
00388 
00389         return bRet;
00390 }
00391 
00392 //-----------------------------------------------
00393 bool CanDriveHarmonica::reset()
00394 {
00395         // repeat initialization
00396 
00397         // start network
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         // init and start
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                 //save Watchdog state into member variable
00426                 m_bWatchdogActive = true;
00427                 // ------- init watchdog
00428                 // Harmonica checks PC hearbeat
00429                 // note: the COB-ID for a heartbeat message = 0x700 + Device ID
00430 
00431                 const int c_iHeartbeatTimeMS = 1000;
00432                 const int c_iNMTNodeID = 0x00;
00433 
00434                 // consumer (PC) heartbeat time
00435                 sendSDODownload(0x1016, 1, (c_iNMTNodeID << 16) | c_iHeartbeatTimeMS);
00436 
00437                 // error behavior after failure: 0=pre-operational, 1=no state change, 2=stopped"
00438                 sendSDODownload(0x1029, 1, 2);
00439 
00440                 // motor behavior after heartbeat failre: "quick stop"
00441                 sendSDODownload(0x6007, 0, 3);
00442 
00443                 // acivate emergency events: "heartbeat event"
00444                 // Object 0x2F21 = "Emergency Events" which cause an Emergency Message
00445                 // Bit 3 is responsible for Heartbeart-Failure.--> Hex 0x08
00446                 sendSDODownload(0x2F21, 0, 0x08);
00447                 usleep(20000);
00448 
00449         }
00450         else
00451         {
00452                 //save Watchdog state into member variable
00453                 m_bWatchdogActive = false;
00454 
00455                 //Motor action after Hearbeat-Error: No Action
00456                 sendSDODownload(0x6007, 0, 0);
00457 
00458                 //Error Behavior: No state change
00459                 sendSDODownload(0x1029, 1, 1);
00460 
00461                 // Deacivate emergency events: "heartbeat event"
00462                 // Object 0x2F21 = "Emergency Events" which cause an Emergency Message
00463                 // Bit 3 is responsible for Heartbeart-Failure.
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                 // 1. make sure that, if on elmo controller still a pending homing from a previous startup is running (in case of warm-start without switching of the whole robot), this old sequence is disabled
00497                 // disarm homing process
00498                 IntprtSetInt(8, 'H', 'M', 1, 0);
00499 
00500                 // always give can and controller some time to understand the command
00501                 usleep(20000);
00502 
00503                 /* THIS is needed for head_axis on cob3-2!
00504 
00505                 //set input logic to 'general purpose'
00506                 IntprtSetInt(8, 'I', 'L', 2, 7);
00507                 usleep(20000);
00508                 */
00509 
00510                 // 2. configure the homing sequence
00511                 // 2.a set the value to which the increment counter shall be reseted as soon as the homing event occurs
00512                 // value to load at homing event
00513                 IntprtSetInt(8, 'H', 'M', 2, c_iPosRef);
00514                 usleep(20000);
00515 
00516                 // 2.b choose the chanel/switch on which the controller listens for a change or defined logic level (the homing event) (high/low/falling/rising)
00517                 // home event
00518                 // iHomeEvent = 5 : event according to defined FLS switch (for scara arm)
00519                 // iHomeEvent = 9 : event according to definded DIN1 switch (for full steerable wheels COb3)
00520                 // iHomeEvent =11 : event according to ?? (for COb3 Head-Axis)
00521                 IntprtSetInt(8, 'H', 'M', 3, m_DriveParam.getHomingDigIn());
00522                 //IntprtSetInt(8, 'H', 'M', 3, 11); //cob3-2
00523                 usleep(20000);
00524 
00525 
00526                 // 2.c choose the action that the controller shall perform after the homing event occured
00527                 // HM[4] = 0 : after Event stop immediately
00528                 // HM[4] = 2 : Do nothing!
00529                 IntprtSetInt(8, 'H', 'M', 4, 2);
00530                 usleep(20000);
00531 
00532                 // 2.d choose the setting of the position counter (i.e. to the value defined in 2.a) after the homing event occured
00533                 // HM[5] = 0 : absolute setting of position counter: PX = HM[2]
00534                 IntprtSetInt(8, 'H', 'M', 5, 0);
00535                 usleep(20000);
00536 
00537                 // 3. let the motor turn some time to give him the possibility to escape the approximation sensor if accidently in home position already at the beginning of the sequence (done in CanCtrlPltf...)
00538 
00539         return true;
00540 }
00541 
00542 
00543 //-----------------------------------------------
00544 bool CanDriveHarmonica::execHoming() //not used by CanCtrlPltf, that has its own homing implementation
00545 {
00546 
00547         int iCnt;
00548         CanMsg Msg;
00549         bool bRet = true;
00550 
00551         int iNrDrive = m_DriveParam.getDriveIdent();
00552 
00553         // 4. arm the homing process -> as soon as the approximation sensor is reached and the homing event occurs the commands set in 2. take effect
00554         // arm homing process
00555         IntprtSetInt(8, 'H', 'M', 1, 1);
00556 
00557         // 5. clear the can buffer to get rid of all uneccessary and potentially disturbing commands still floating through the wires
00558         do
00559         {
00560                 // read from can
00561                 bRet = m_pCanCtrl->receiveMsg(&Msg);
00562         }
00563         while(bRet == true);
00564 
00565         // 6. now listen for status of homing, to synchronize program flow -> proceed only after homing was succesful (homing disarmed by elmo) or timeout occured
00566 
00567         // set timeout counter to zero
00568         iCnt = 0;
00569 
00570         do
00571         {
00572                 // 6.a ask for status of homing process (armed/disarmed)
00573                 // ask for first byte in Homing Configuration
00574                 IntprtSetInt(4, 'H', 'M', 1, 0);
00575 
00576                 // 6.b read message from can
00577                 m_pCanCtrl->receiveMsgRetry(&Msg, 10);
00578 
00579                 // 6.c see if received message is answer of request and if so what is the status
00580                 if( (Msg.getAt(0) == 'H') && (Msg.getAt(1) == 'M') )
00581                 {
00582                         // status message (homing armed = 1 / disarmed = 0) is encoded in 5th byte
00583                         if(Msg.getAt(4) == 0)
00584                         {
00585                                 // if 0 received: elmo disarmed homing after receiving the defined event
00586                                 std::cout << "Got Homing-Signal "  << std::endl;
00587                                 m_bLimSwRight = true;
00588                                 break;
00589                         }
00590                 }
00591 
00592                 // increase count for timeout
00593                 usleep(10000);
00594                 iCnt++;
00595 
00596         }
00597         while((m_bLimSwRight == false) && (iCnt<2000)); // wait some time
00598 
00599         // 7. see why finished (homed or timeout) and log out
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         //IntprtSetInt(8, 'I', 'L', 2, 9); //cob3-2                  |  -----------------------------------------------------------------------------------
00611         //usleep(20000);
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                         //new: set VELOCITY for PTP Motion
00636                         IntprtSetInt(8, 'S', 'P', 0, iVelEncIncrPeriod);
00637 
00638                         // Position Relativ ("PR") , because of positioning of driving wheel
00639                         // which is not initialized to zero on a specific position
00640                         // only when command is for homed steering wheel set absolute
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         // request pos and vel by TPDO1, triggered by SYNC msg
00658         // (to request pos by SDO usesendSDOUpload(0x6064, 0) )
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         // calc motor velocity from joint velocity
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         // request pos and vel by TPDO1, triggered by SYNC msg
00690         // (to request pos by SDO use sendSDOUpload(0x6064, 0) )
00691         // sync msg is: iID 0x80 with msg (0,0,0,0,0,0,0,0)
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         // send heartbeat to keep watchdog inactive
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         // request status
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         // request pos and vel by TPDO1, triggered by SYNC msg
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         // (to request pos by SDO use sendSDOUpload(0x6064, 0) )
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         // send command for requesting motor current:
00786         IntprtSetInt(4, 'I', 'Q', 0, 0);        // active current
00787         //IntprtSetInt(4, 'I', 'D', 0, 0);      // reactive current
00788 }
00789 
00790 //-----------------------------------------------
00791 bool CanDriveHarmonica::isError()
00792 {
00793         if (m_iMotorState != ST_MOTOR_FAILURE)
00794         {
00795                 // Check timeout of can communication
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                 // 1.) Switch to UnitMode = 5 (Single Loop Position Control) //
00824 
00825                 // switch off Motor to change Unit-Mode
00826                 IntprtSetInt(8, 'M', 'O', 0, 0);
00827                 usleep(20000);
00828                 // switch Unit-Mode
00829                 IntprtSetInt(8, 'U', 'M', 0, 5);
00830 
00831                 // set Target Radius to X Increments
00832                 IntprtSetInt(8, 'T', 'R', 1, 15);
00833                 // set Target Time to X ms
00834                 IntprtSetInt(8, 'T', 'R', 2, 100);
00835 
00836                 // set maximum Acceleration to X Incr/s^2
00837                 IntprtSetInt(8, 'A', 'C', 0, iMaxAcc);
00838                 // set maximum decceleration to X Incr/s^2
00839                 IntprtSetInt(8, 'D', 'C', 0, iMaxDcc);
00840                 usleep(100000);
00841 
00842 
00843         }
00844         else if (iType == MOTIONTYPE_TORQUECTRL)
00845         {
00846                 // Switch to TorqueControll-Mode
00847                 // switch off Motor to change Unit-Mode
00848                 IntprtSetInt(8, 'M', 'O', 0, 0);
00849                 usleep(50000);
00850                 // switch Unit-Mode 1: Torque Controlled
00851                 IntprtSetInt(8, 'U', 'M', 0, 1);
00852                 // disable external compensation input
00853                 // to avoid noise from that input pin
00854                 IntprtSetInt(8, 'R', 'M', 0, 0);
00855 
00856                 // debugging:
00857                 std::cout << "Motor"<<m_DriveParam.getDriveIdent()<<" Unit Mode switched to: TORQUE controlled" << std::endl;
00858                 usleep(100000);
00859         }
00860         else
00861         {
00862                 //Default Motion Type = VelocityControled
00863                 // switch off Motor to change Unit-Mode
00864                 IntprtSetInt(8, 'M', 'O', 0, 0);
00865                 // switch Unit-Mode
00866                 IntprtSetInt(8, 'U', 'M', 0, 2);
00867                 // set profiler Mode (only if Unit Mode = 2)
00868                 IntprtSetInt(8, 'P', 'M', 0, 1);
00869 
00870                 // set maximum Acceleration to X Incr/s^2
00871                 IntprtSetInt(8, 'A', 'C', 0, iMaxAcc);
00872                 // set maximum decceleration to X Incr/s^2
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;  // The two MSB must be 0. Cf. DSP 301 Implementation guide p. 39.
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         // for sending float values bit 6 has to be zero and bit 7 one (according to Elmo Implementation guide)
00917         cIndex[1] = (iIndex >> 8) & 0x3F;       // setting bit 6 to zero with mask 0b10111111->0xBF
00918         cIndex[1] = cIndex[1] | 0x80;           // setting bit 7 to one with mask 0b10000000 ->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 // SDO Communication Protocol, most functions are used for general SDO Segmented Transfer
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) { //only accept new SDO Segmented Upload if seg_Data is free
01034                 seg_Data.resetTransferData();
01035                 seg_Data.statusFlag = segData::SDO_SEG_COLLECTING;
01036 
01037                 //read out objectIDs
01038                 evalSDO(msg, &seg_Data.objectID, &seg_Data.objectSubID);
01039 
01040                 //data in byte 4 to 7 contain the number of bytes to be uploaded (if Size indicator flag is set)
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         //Read SDO Upload Protocol:
01058         //Byte 0: SSS T NNN C | SSS=Cmd-Specifier, T=ToggleBit, NNN=num of empty bytes, C=Finished
01059         //Byte 1 to 7: Data
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); //Send SDO Abort with error code Toggle-Bit not alternated
01064                 return 1;
01065         }
01066 
01067         if( (msg.getAt(0) & 0x01) == 0x00) { //Is finished-bit not set?
01068                 seg_Data.statusFlag = segData::SDO_SEG_COLLECTING;
01069         } else {
01070                 //std::cout << "SDO Segmented Transfer finished bit found!" << std::endl;
01071                 seg_Data.statusFlag = segData::SDO_SEG_PROCESSING;
01072         };
01073 
01074         numEmptyBytes = (msg.getAt(0) >> 1) & 0x07;
01075         //std::cout << "NUM empty bytes in SDO :" << numEmptyBytes << std::endl;
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; //first three bits must be css = 3 : 011 00000
01096         iConfirmSegment = iConfirmSegment | (toggleBit << 4); //fourth bit is toggle bit: 011T0000
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                 //abort processing?
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         // --------- Error status
01154         if( isBitSet(iStatus, 0) )
01155         {
01156                 // ------------ Error
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                         // Request detailed description of failure
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                 // General failure
01184                 if ( m_bOutputOfFailure == false )
01185                 {
01186                         std::cout << "Motor " << m_DriveParam.getDriveIdent() << " failure latched" << std::endl;
01187 
01188                         // Request detailed description of failure
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                 // ---------- No error
01200                 bNoError = true;
01201 
01202                 // Clear flag for failure output only if at least one
01203                 // status message without error has been received.
01204                 // Printing an error message on recovery is avoided.
01205                 m_bOutputOfFailure = false;
01206 
01207                 // --------- General status bits
01208                 // check if Bit 4 (-> Motor is ON) ist set
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                 // Current limit
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         // Change state
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         // convert commanded motor current into amperes
01291         float fMotCurr = m_DriveParam.getSign() * dTorqueNm / m_DriveParam.getCurrToTorque();
01292 
01293         // check for limitations
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         // send Command
01306         IntprtSetFloat(8, 'T', 'C', 0, fMotCurr);
01307 
01308         // request pos and vel by TPDO1, triggered by SYNC msg
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         // send heartbeat to keep watchdog inactive
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         // request status
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         // With motor sign:
01342         *dTorqueNm = m_DriveParam.getSign() * m_dMotorCurr * m_DriveParam.getCurrToTorque();
01343 
01344 }
01345 
01346 
01347 
01348 //----------------
01349 //----------------
01350 //Function, that proceeds (Elmo-) recorder readout
01351 
01352 //-----------------------------------------------
01353 int CanDriveHarmonica::setRecorder(int iFlag, int iParam, std::string sParam) {
01354 
01355         switch(iFlag) {
01356                 case 0: //Configure Elmo Recorder for new Record, param = iRecordingGap, which specifies every which time quantum (4*90usec) a new data point is recorded
01357                         if(iParam < 1) iParam = 1;
01358                         ElmoRec->isInitialized(true);
01359                         ElmoRec->configureElmoRecorder(iParam, m_DriveParam.getDriveIdent()); //int startImmediately is default = 1
01360                         return 0;
01361 
01362                 case 1: //Query upload of previous recorded data, data is being proceeded after complete upload, param = recorded ID, filename
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); //as subindex, give the recorded variable
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: //request status, still collecting data during ReadOut process?
01382                         if(seg_Data.statusFlag == segData::SDO_SEG_COLLECTING) {
01383                                 //std::cout << "Transmission of data is still in progress" << std::endl;
01384                                 return 2;
01385                         } else if(seg_Data.statusFlag == segData::SDO_SEG_PROCESSING) {
01386                                 //std::cout << "Transmission of data finished, data not proceeded yet" << std::endl;
01387                                 return 2;
01388                         } else if(seg_Data.statusFlag == segData::SDO_SEG_WAITING) {
01389                                 //std::cout << "Still waiting for transmission to begin" << std::endl;
01390                                 return 2;
01391                         } else { //finished transmission and finished proceeding
01392                                 return 0;
01393                         }
01394 
01395                         break;
01396 
01397                 case 99: //Abort ongoing SDO data Transmission and clear collected data
01398                         sendSDOAbort(0x2030, 0x00, 0x08000020); //send general error abort
01399                         seg_Data.resetTransferData(); 
01400                         return 0;
01401         }
01402 
01403         return 0;
01404 }


cob_canopen_motor
Author(s): Christian Connette
autogenerated on Sat Jun 8 2019 21:02:28