ElmoRecorder.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 <math.h>
00019 #include <vector>
00020 #include <stdio.h>
00021 #include <sstream>
00022 #include <cob_canopen_motor/ElmoRecorder.h>
00023 #include <cob_canopen_motor/CanDriveHarmonica.h>
00024 
00025 ElmoRecorder::ElmoRecorder(CanDriveHarmonica * pParentHarmonicaDrive) {
00026         m_pHarmonicaDrive = pParentHarmonicaDrive;
00027 
00028         m_bIsInitialized = false;
00029         m_iReadoutRecorderTry = 0;
00030 }
00031 
00032 ElmoRecorder::~ElmoRecorder() {
00033 }
00034 
00035 bool ElmoRecorder::isInitialized(bool initNow) {
00036         if(initNow) m_bIsInitialized = true;
00037         return m_bIsInitialized;
00038 }
00039 
00040 int ElmoRecorder::configureElmoRecorder(int iRecordingGap, int driveID, int startImmediately){ //iRecordingGap = N indicates that a new sample should be taken once per N time quanta
00041         m_iDriveID = driveID;
00042 
00043         if(startImmediately >=2 ) startImmediately = 1;
00044 
00045         m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'R', 0, 0);     // Stop Recorder if it's active
00046         // Record Main speed (index 0, ID1)
00047         // Active Current (index 9, ID10)
00048         // Main Position (index 1, ID2)
00049         // Speed Command (index 15, ID16)
00050         // RC = 2^(Signal1Index) + 2^(Signal2Index) + ..; e.g.: 2^0 + 2^1 + 2^9 + 2^15 = 33283;
00051         m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'C', 0, 33283);
00052         // Set trigger type to immediate
00053         m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'P', 3, 0);
00054         // Set Recording Gap
00055         m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'G', 0, iRecordingGap);
00056         // Set Recording Length
00057         // RL = (4096 / Number of Signals)
00058         m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'L', 0, 1024);
00059 
00060         // Set Time Quantum, Default: RP=0 -> TS * 4; TS is 90us by default
00061         // m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'P', 0, 0);
00062         // ----> Total Recording Time = 90us * 4 * RG * RL
00063 
00064         m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'R', 0, startImmediately + 1); //2 launches immediately (8, 'R', 'R', 0, 1) launches at next BG
00065 
00066         m_fRecordingStepSec = 0.000090 * 4 * iRecordingGap;
00067 
00068         return 0;
00069 }
00070 
00071 int ElmoRecorder::readoutRecorderTry(int iObjSubIndex) {
00072         //Request the SR (status register) and begin all the read-out process with this action.
00073         //SDOData.statusFlag is segData::SDO_SEG_WAITING;
00074 
00075         m_iReadoutRecorderTry = 1;
00076         m_iCurrentObject = iObjSubIndex;
00077 
00078         m_pHarmonicaDrive->requestStatus();
00079 
00080         return 0;
00081 }
00082 
00083 int ElmoRecorder::readoutRecorderTryStatus(int iStatusReg, segData& SDOData) {
00084         if(m_iReadoutRecorderTry == 0) return 0; //only evaluate the SR, if we are really waiting for it (to save time and not to unintionally start a read-out)
00085 
00086         m_iReadoutRecorderTry = 0;
00087 
00088         //Bits 16-17 of status register contain recorder information
00089         int iRecorderStatus = (0x30000 & iStatusReg) >> 16;
00090 
00091         if(iRecorderStatus == 0) {
00092                 std::cout << "Recorder " << m_iDriveID << " inactive with no valid data to upload" << std::endl;
00093                 SDOData.statusFlag = segData::SDO_SEG_FREE;
00094         } else if(iRecorderStatus == 1) {
00095                 std::cout << "Recorder " << m_iDriveID << " waiting for a trigger event" << std::endl;
00096                 SDOData.statusFlag = segData::SDO_SEG_FREE;
00097         } else if(iRecorderStatus == 2) {
00098                 std::cout << "Recorder " << m_iDriveID << " finished, valid data ready for use" << std::endl;
00099                 readoutRecorder(m_iCurrentObject);
00100                 //already set to SDOData.statusFlag = segData::SDO_SEG_WAITING;
00101         } else if(iRecorderStatus == 3) {
00102                 std::cout << "Recorder " << m_iDriveID << " is still recording" << std::endl;
00103                 SDOData.statusFlag = segData::SDO_SEG_FREE;
00104         }
00105 
00106         return 0;
00107 }
00108 
00109 int ElmoRecorder::readoutRecorder(int iObjSubIndex){
00110         //initialize Upload of Recorded Data (object 0x2030)
00111         int iObjIndex = 0x2030;
00112 
00113         m_pHarmonicaDrive->sendSDOUpload(iObjIndex, iObjSubIndex);
00114         m_iCurrentObject = iObjSubIndex;
00115 
00116         return 0;
00117 }
00118 
00119 int ElmoRecorder::processData(segData& SDOData) {
00120         int iItemSize = 4;
00121         int iItemCount = 0;
00122         unsigned int iNumDataItems = 0;
00123         bool bCollectFloats = true;
00124         float fFloatingPointFactor = 0;
00125 
00126         std::vector<float> vfResData[2];
00127 
00128         //see SimplIQ CANopen DS 301 Implementation Guide, object 0x2030
00129 
00130         //HEADER
00131         //--------------------------------------
00132         //First 7 Bytes of the data sequence contain header information:
00133         //Byte 0: First four bits: 4 = Long Int data type, 1 = Half Float data type, 5 = Double Float
00134         //                      Next four bits: Recording frequency in 1 per n * TS => deltaT =  n * 90µsec
00135         //Byte 2, Byte 3: Number of recorded data points
00136         //Byte 3 to 6: Floating point factor for data to be multiplied with
00137         //
00138         //Byte 7 to Byte (7+ iNumdataItems * 4) contain data
00139 
00140         //B[0]: Time quantum and data type
00141         switch ((SDOData.data[0] >> 4) ) {
00142                 case 4:
00143                         bCollectFloats = false;
00144                         iItemSize = 4;
00145                         break;
00146                 case 5:
00147                         bCollectFloats = true;
00148                         iItemSize = 4;
00149                         break;
00150                 case 1:
00151                         bCollectFloats = true;
00152                         iItemSize = 2;
00153                         break;
00154                 default:
00155                         bCollectFloats = false;
00156                         iItemSize = 4;
00157                         break;
00158         }
00159         std::cout << ">>>>>ElmoRec: HEADER INFOS<<<<<\nData type is: " << (SDOData.data[0] >> 4) << std::endl;
00160 
00161         //std::cout << "fTimeQuantum from Header is " << fTimeQuantum << " m_fRecordingStepSec is " << m_fRecordingStepSec << std::endl;
00162 
00163 
00164         //B[1]..[2] //Number of recorded items
00165         iNumDataItems = (SDOData.data[2] << 8 | SDOData.data[1]);
00166         //std::cout << "Number of recorded data points: " << iNumDataItems << std::endl;
00167 
00168         //B[3] ... [6] //Floating point factor
00169         fFloatingPointFactor = convertBinaryToFloat( (SDOData.data[6] << 24) | (SDOData.data[5] << 16) | (SDOData.data[4] << 8) | (SDOData.data[3]) );
00170         std::cout << "Floating point factor for recorded values is: " << fFloatingPointFactor << std::endl;
00171 
00172 
00173         if( ((SDOData.numTotalBytes-7)/iItemSize) != iNumDataItems)
00174                 std::cout << "SDODataSize announced in SDO-Header" << ((SDOData.numTotalBytes-7)/iItemSize) << " differs from NumDataItems by ElmoData-Header" <<  iNumDataItems << std::endl;
00175         //END HEADER
00176         //--------------------------------------
00177 
00178         vfResData[0].assign(iNumDataItems, 0.0);
00179         vfResData[1].assign(iNumDataItems, 0.0);
00180         iItemCount = 0;
00181 
00182         //extract values from data stream, consider Little Endian conversion for every single object!
00183         for(unsigned int i=7;i<=SDOData.data.size() - iItemSize; i=i+iItemSize) {
00184                 if(bCollectFloats) {
00185                         if(iItemSize == 4)
00186                                 vfResData[1][iItemCount] = fFloatingPointFactor * convertBinaryToFloat( (SDOData.data[i] << 0) | (SDOData.data[i+1] << 8) | (SDOData.data[i+2] << 16) | (SDOData.data[i+3] << 24) );
00187 
00188                                 //DEBUG
00189                                 if(iItemCount == 120)
00190                                         std::cout << (unsigned int)( (SDOData.data[i] << 0) | (SDOData.data[i+1] << 8) | (SDOData.data[i+2] << 16) | (SDOData.data[i+3] << 24) ) << std::endl;
00191 
00192                         else vfResData[1][iItemCount] = fFloatingPointFactor * convertBinaryToHalfFloat( (SDOData.data[i] << 0) | (SDOData.data[i+1] << 8) | (SDOData.data[i+2] << 16) | (SDOData.data[i+3] << 24) );
00193                         iItemCount ++;
00194                 } else {
00195                         vfResData[1][iItemCount] = fFloatingPointFactor * (float)( (SDOData.data[i] << 0) | (SDOData.data[i+1] << 8) | (SDOData.data[i+2] << 16) | (SDOData.data[i+3] << 24) );
00196                         iItemCount ++;
00197                 }
00198 
00199                 vfResData[0][iItemCount] = m_fRecordingStepSec * iItemCount;
00200         }
00201 
00202         logToFile(m_sLogFilename, vfResData);
00203 
00204         SDOData.statusFlag = segData::SDO_SEG_FREE;
00205         return 0;
00206 }
00207 
00208 int ElmoRecorder::setLogFilename(std::string sLogFileprefix) {
00209         m_sLogFilename = sLogFileprefix;
00210         return 0;
00211 }
00212 
00213 
00214 
00215 float ElmoRecorder::convertBinaryToFloat(unsigned int iBinaryRepresentation) {
00216         //Converting binary-numbers to 32bit float values according to IEEE 754 see http://de.wikipedia.org/wiki/IEEE_754
00217         int iSign;
00218         int iExponent;
00219         unsigned int iMantissa;
00220         float iNumMantissa = 0.0f;
00221 
00222         if((iBinaryRepresentation & (1 << 31)) == 0) //first bit is sign bit: 0 = +, 1 = -
00223                 iSign = 1;
00224         else
00225                 iSign = -1;
00226 
00227         iExponent = ((iBinaryRepresentation >> 23) & 0xFF) - 127; //take away Bias(127) for positive and negative exponents
00228 
00229         iMantissa = (iBinaryRepresentation & 0x7FFFFF); //only keep mantissa part of binary number
00230 
00231         iNumMantissa = 1.0f;
00232 
00233         for(int i=1; i<=23; i++) { //calculate decimal places (convert binary mantissa to decimal number
00234                 if((iMantissa & (1 << (23-i))) > 0) {
00235                         iNumMantissa = iNumMantissa + pow(2,(-1)*i);
00236                 }
00237         }
00238 
00239         return iSign * pow(2,iExponent) * iNumMantissa;
00240 }
00241 
00242 float ElmoRecorder::convertBinaryToHalfFloat(unsigned int iBinaryRepresentation) {
00243         //Converting binary-numbers to 16bit float values according to IEEE 754 see http://de.wikipedia.org/wiki/IEEE_754
00244         int iSign;
00245         int iExponent;
00246         unsigned int iMantissa;
00247         float iNumMantissa = 0.0f;
00248 
00249         if((iBinaryRepresentation & (1 << 15)) == 0) //first bit is sign bit: 0 = +, 1 = -
00250                 iSign = 1;
00251         else
00252                 iSign = -1;
00253 
00254         iExponent = ((iBinaryRepresentation >> 10) & 0x1F) - 15; //take away Bias(15) for positive and negative exponents
00255 
00256         iMantissa = (iBinaryRepresentation & 0x3FF); //only keep mantissa part of binary number
00257 
00258         iNumMantissa = 1.0f;
00259 
00260         for(int i=1; i<=10; i++) { //calculate decimal places (convert binary mantissa to decimal number
00261                 if((iMantissa & (1 << (10-i))) > 0) {
00262                         iNumMantissa = iNumMantissa + pow(2,(-1)*i);
00263                 }
00264         }
00265 
00266         return iSign * pow(2,iExponent) * iNumMantissa;
00267 }
00268 
00269 // Function for writing Logfile
00270 int ElmoRecorder::logToFile(std::string filename, std::vector<float> vtValues[]) {
00271         std::stringstream outputFileName;
00272         outputFileName << filename << "mot_" << m_iDriveID << "_" << m_iCurrentObject << ".log";
00273 
00274         FILE* pFile;
00275         //open FileStream
00276         pFile = fopen(outputFileName.str().c_str(), "w");
00277 
00278         //Check if there was a problem
00279         if( pFile == NULL )
00280         {
00281                 std::cout << "Error while writing file: " << outputFileName.str() << " Maybe the selected folder does'nt exist." << std::endl;
00282         }
00283         else
00284         {
00285                 // write all data from vector to file
00286                 for (unsigned int i = 0; i < vtValues[0].size(); i++)
00287                         fprintf(pFile, "%e %e\n", vtValues[0][i], vtValues[1][i]);
00288                 fclose(pFile);
00289         }
00290 
00291         return true;
00292 }


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