ElmoRecorder.cpp
Go to the documentation of this file.
00001 /****************************************************************
00002  *
00003  * Copyright (c) 2010
00004  *
00005  * Fraunhofer Institute for Manufacturing Engineering   
00006  * and Automation (IPA)
00007  *
00008  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00009  *
00010  * Project name: care-o-bot
00011  * ROS stack name: cob3_common
00012  * ROS package name: canopen_motor
00013  * Description:
00014  *                                                              
00015  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00016  *                      
00017  * Author: Philipp Köhler
00018  * Supervised by: Christian Connette, email:christian.connette@ipa.fhg.de
00019  *
00020  * Date of creation: Mar 2010
00021  * ToDo:
00022  *
00023  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00024  *
00025  * Redistribution and use in source and binary forms, with or without
00026  * modification, are permitted provided that the following conditions are met:
00027  *
00028  *       * Redistributions of source code must retain the above copyright
00029  *         notice, this list of conditions and the following disclaimer.
00030  *       * Redistributions in binary form must reproduce the above copyright
00031  *         notice, this list of conditions and the following disclaimer in the
00032  *         documentation and/or other materials provided with the distribution.
00033  *       * Neither the name of the Fraunhofer Institute for Manufacturing 
00034  *         Engineering and Automation (IPA) nor the names of its
00035  *         contributors may be used to endorse or promote products derived from
00036  *         this software without specific prior written permission.
00037  *
00038  * This program is free software: you can redistribute it and/or modify
00039  * it under the terms of the GNU Lesser General Public License LGPL as 
00040  * published by the Free Software Foundation, either version 3 of the 
00041  * License, or (at your option) any later version.
00042  * 
00043  * This program is distributed in the hope that it will be useful,
00044  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00045  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00046  * GNU Lesser General Public License LGPL for more details.
00047  * 
00048  * You should have received a copy of the GNU Lesser General Public 
00049  * License LGPL along with this program. 
00050  * If not, see <http://www.gnu.org/licenses/>.
00051  *
00052  ****************************************************************/
00053 
00054 #include <math.h>
00055 #include <vector>
00056 #include <stdio.h>
00057 #include <sstream>
00058 #include <cob_canopen_motor/ElmoRecorder.h>
00059 #include <cob_canopen_motor/CanDriveHarmonica.h>
00060 
00061 ElmoRecorder::ElmoRecorder(CanDriveHarmonica * pParentHarmonicaDrive) {
00062         m_pHarmonicaDrive = pParentHarmonicaDrive;
00063         
00064         m_bIsInitialized = false;
00065         m_iReadoutRecorderTry = 0;
00066 }
00067 
00068 ElmoRecorder::~ElmoRecorder() {
00069 }
00070 
00071 bool ElmoRecorder::isInitialized(bool initNow) {
00072         if(initNow) m_bIsInitialized = true;
00073         return m_bIsInitialized;
00074 }
00075 
00076 int ElmoRecorder::configureElmoRecorder(int iRecordingGap, int driveID, int startImmediately){ //iRecordingGap = N indicates that a new sample should be taken once per N time quanta
00077         m_iDriveID = driveID;
00078         
00079         if(startImmediately >=2 ) startImmediately = 1;
00080 
00081         m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'R', 0, 0);     // Stop Recorder if it's active 
00082         // Record Main speed (index 0, ID1) 
00083         // Active Current (index 9, ID10)
00084         // Main Position (index 1, ID2)
00085         // Speed Command (index 15, ID16)
00086         // RC = 2^(Signal1Index) + 2^(Signal2Index) + ..; e.g.: 2^0 + 2^1 + 2^9 + 2^15 = 33283;
00087         m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'C', 0, 33283);
00088         // Set trigger type to immediate
00089         m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'P', 3, 0);
00090         // Set Recording Gap
00091         m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'G', 0, iRecordingGap);
00092         // Set Recording Length
00093         // RL = (4096 / Number of Signals)
00094         m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'L', 0, 1024);
00095         
00096         // Set Time Quantum, Default: RP=0 -> TS * 4; TS is 90us by default
00097         // m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'P', 0, 0);
00098         // ----> Total Recording Time = 90us * 4 * RG * RL
00099 
00100         m_pHarmonicaDrive->IntprtSetInt(8, 'R', 'R', 0, startImmediately + 1); //2 launches immediately (8, 'R', 'R', 0, 1) launches at next BG
00101         
00102         m_fRecordingStepSec = 0.000090 * 4 * iRecordingGap;
00103         
00104         return 0;
00105 }
00106 
00107 int ElmoRecorder::readoutRecorderTry(int iObjSubIndex) {
00108         //Request the SR (status register) and begin all the read-out process with this action.
00109         //SDOData.statusFlag is segData::SDO_SEG_WAITING;
00110         
00111         m_iReadoutRecorderTry = 1;
00112         m_iCurrentObject = iObjSubIndex;
00113         
00114         m_pHarmonicaDrive->requestStatus();
00115         
00116         return 0;
00117 }
00118 
00119 int ElmoRecorder::readoutRecorderTryStatus(int iStatusReg, segData& SDOData) {
00120         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)
00121 
00122         m_iReadoutRecorderTry = 0;
00123         
00124         //Bits 16-17 of status register contain recorder information
00125         int iRecorderStatus = (0x30000 & iStatusReg) >> 16;
00126 
00127         if(iRecorderStatus == 0) {
00128                 std::cout << "Recorder " << m_iDriveID << " inactive with no valid data to upload" << std::endl;
00129                 SDOData.statusFlag = segData::SDO_SEG_FREE;
00130         } else if(iRecorderStatus == 1) {
00131                 std::cout << "Recorder " << m_iDriveID << " waiting for a trigger event" << std::endl;
00132                 SDOData.statusFlag = segData::SDO_SEG_FREE;
00133         } else if(iRecorderStatus == 2) {
00134                 std::cout << "Recorder " << m_iDriveID << " finished, valid data ready for use" << std::endl;
00135                 readoutRecorder(m_iCurrentObject);
00136                 //already set to SDOData.statusFlag = segData::SDO_SEG_WAITING;
00137         } else if(iRecorderStatus == 3) {
00138                 std::cout << "Recorder " << m_iDriveID << " is still recording" << std::endl;
00139                 SDOData.statusFlag = segData::SDO_SEG_FREE;
00140         }
00141         
00142         return 0;
00143 }
00144 
00145 int ElmoRecorder::readoutRecorder(int iObjSubIndex){
00146         //initialize Upload of Recorded Data (object 0x2030)
00147         int iObjIndex = 0x2030;
00148 
00149         m_pHarmonicaDrive->sendSDOUpload(iObjIndex, iObjSubIndex);
00150         m_iCurrentObject = iObjSubIndex;
00151         
00152         return 0;
00153 }
00154 
00155 int ElmoRecorder::processData(segData& SDOData) {
00156         int iItemSize = 4;
00157         int iItemCount = 0;
00158         unsigned int iNumDataItems = 0;
00159         bool bCollectFloats = true;
00160         float fFloatingPointFactor = 0;
00161         float fTimeQuantum = 1.0f;
00162         
00163         std::vector<float> vfResData[2];
00164         
00165         //see SimplIQ CANopen DS 301 Implementation Guide, object 0x2030
00166         
00167         //HEADER
00168         //--------------------------------------
00169         //First 7 Bytes of the data sequence contain header information:
00170         //Byte 0: First four bits: 4 = Long Int data type, 1 = Half Float data type, 5 = Double Float
00171         //                      Next four bits: Recording frequency in 1 per n * TS => deltaT =  n * 90µsec
00172         //Byte 2, Byte 3: Number of recorded data points
00173         //Byte 3 to 6: Floating point factor for data to be multiplied with
00174         //
00175         //Byte 7 to Byte (7+ iNumdataItems * 4) contain data
00176         
00177         //B[0]: Time quantum and data type
00178         switch ((SDOData.data[0] >> 4) ) {
00179                 case 4:
00180                         bCollectFloats = false;
00181                         iItemSize = 4;
00182                         break;
00183                 case 5:
00184                         bCollectFloats = true;
00185                         iItemSize = 4;
00186                         break;
00187                 case 1:
00188                         bCollectFloats = true;
00189                         iItemSize = 2;
00190                         break;
00191                 default:
00192                         bCollectFloats = false;
00193                         iItemSize = 4;
00194                         break;
00195         }
00196         std::cout << ">>>>>ElmoRec: HEADER INFOS<<<<<\nData type is: " << (SDOData.data[0] >> 4) << std::endl;
00197         
00198         fTimeQuantum = (SDOData.data[0] & 0x0F) * 0.000090; //Time quantum is specified in Bit 4 to 7
00199         //std::cout << "fTimeQuantum from Header is " << fTimeQuantum << " m_fRecordingStepSec is " << m_fRecordingStepSec << std::endl;
00200         
00201         
00202         //B[1]..[2] //Number of recorded items
00203         iNumDataItems = (SDOData.data[2] << 8 | SDOData.data[1]);
00204         //std::cout << "Number of recorded data points: " << iNumDataItems << std::endl;
00205 
00206         //B[3] ... [6] //Floating point factor
00207         fFloatingPointFactor = convertBinaryToFloat( (SDOData.data[6] << 24) | (SDOData.data[5] << 16) | (SDOData.data[4] << 8) | (SDOData.data[3]) );
00208         std::cout << "Floating point factor for recorded values is: " << fFloatingPointFactor << std::endl;
00209         
00210         
00211         if( ((SDOData.numTotalBytes-7)/iItemSize) != iNumDataItems) 
00212                 std::cout << "SDODataSize announced in SDO-Header" << ((SDOData.numTotalBytes-7)/iItemSize) << " differs from NumDataItems by ElmoData-Header" <<  iNumDataItems << std::endl;
00213         //END HEADER
00214         //--------------------------------------
00215 
00216         vfResData[0].assign(iNumDataItems, 0.0);
00217         vfResData[1].assign(iNumDataItems, 0.0);
00218         iItemCount = 0;
00219         
00220         //extract values from data stream, consider Little Endian conversion for every single object!
00221         for(unsigned int i=7;i<=SDOData.data.size() - iItemSize; i=i+iItemSize) {
00222                 if(bCollectFloats) {
00223                         if(iItemSize == 4)
00224                                 vfResData[1][iItemCount] = fFloatingPointFactor * convertBinaryToFloat( (SDOData.data[i] << 0) | (SDOData.data[i+1] << 8) | (SDOData.data[i+2] << 16) | (SDOData.data[i+3] << 24) );
00225                                 
00226                                 //DEBUG
00227                                 if(iItemCount == 120)
00228                                         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;
00229                                 
00230                         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) );
00231                         iItemCount ++;
00232                 } else {
00233                         vfResData[1][iItemCount] = fFloatingPointFactor * (float)( (SDOData.data[i] << 0) | (SDOData.data[i+1] << 8) | (SDOData.data[i+2] << 16) | (SDOData.data[i+3] << 24) );
00234                         iItemCount ++;
00235                 }
00236                 
00237                 vfResData[0][iItemCount] = m_fRecordingStepSec * iItemCount;
00238         }
00239         
00240         logToFile(m_sLogFilename, vfResData);
00241 
00242         SDOData.statusFlag = segData::SDO_SEG_FREE;
00243         return 0;
00244 }
00245 
00246 int ElmoRecorder::setLogFilename(std::string sLogFileprefix) {
00247         m_sLogFilename = sLogFileprefix;
00248         return 0;
00249 }
00250 
00251 
00252 
00253 float ElmoRecorder::convertBinaryToFloat(unsigned int iBinaryRepresentation) {
00254         //Converting binary-numbers to 32bit float values according to IEEE 754 see http://de.wikipedia.org/wiki/IEEE_754
00255         int iSign;
00256         int iExponent;
00257         unsigned int iMantissa;
00258         float iNumMantissa = 0.0f;
00259 
00260         if((iBinaryRepresentation & (1 << 31)) == 0) //first bit is sign bit: 0 = +, 1 = -
00261                 iSign = 1;
00262         else
00263                 iSign = -1;
00264 
00265         iExponent = ((iBinaryRepresentation >> 23) & 0xFF) - 127; //take away Bias(127) for positive and negative exponents
00266 
00267         iMantissa = (iBinaryRepresentation & 0x7FFFFF); //only keep mantissa part of binary number
00268 
00269         iNumMantissa = 1.0f;
00270         
00271         for(int i=1; i<=23; i++) { //calculate decimal places (convert binary mantissa to decimal number
00272                 if((iMantissa & (1 << (23-i))) > 0) {
00273                         iNumMantissa = iNumMantissa + pow(2,(-1)*i);
00274                 }
00275         }
00276 
00277         return iSign * pow(2,iExponent) * iNumMantissa;
00278 }
00279 
00280 float ElmoRecorder::convertBinaryToHalfFloat(unsigned int iBinaryRepresentation) {
00281         //Converting binary-numbers to 16bit float values according to IEEE 754 see http://de.wikipedia.org/wiki/IEEE_754
00282         int iSign;
00283         int iExponent;
00284         unsigned int iMantissa;
00285         float iNumMantissa = 0.0f;
00286 
00287         if((iBinaryRepresentation & (1 << 15)) == 0) //first bit is sign bit: 0 = +, 1 = -
00288                 iSign = 1;
00289         else
00290                 iSign = -1;
00291 
00292         iExponent = ((iBinaryRepresentation >> 10) & 0x1F) - 15; //take away Bias(15) for positive and negative exponents
00293 
00294         iMantissa = (iBinaryRepresentation & 0x3FF); //only keep mantissa part of binary number
00295 
00296         iNumMantissa = 1.0f;
00297         
00298         for(int i=1; i<=10; i++) { //calculate decimal places (convert binary mantissa to decimal number
00299                 if((iMantissa & (1 << (10-i))) > 0) {
00300                         iNumMantissa = iNumMantissa + pow(2,(-1)*i);
00301                 }
00302         }
00303 
00304         return iSign * pow(2,iExponent) * iNumMantissa;
00305 }
00306 
00307 // Function for writing Logfile
00308 int ElmoRecorder::logToFile(std::string filename, std::vector<float> vtValues[]) {
00309         std::stringstream outputFileName;
00310         outputFileName << filename << "mot_" << m_iDriveID << "_" << m_iCurrentObject << ".log";
00311 
00312         FILE* pFile;
00313         //open FileStream
00314         pFile = fopen(outputFileName.str().c_str(), "w");
00315         
00316         //Check if there was a problem
00317         if( pFile == NULL ) 
00318         {       
00319                 std::cout << "Error while writing file: " << outputFileName.str() << " Maybe the selected folder does'nt exist." << std::endl;
00320         } 
00321         else 
00322         {
00323                 // write all data from vector to file
00324                 for (unsigned int i = 0; i < vtValues[0].size(); i++)
00325                         fprintf(pFile, "%e %e\n", vtValues[0][i], vtValues[1][i]);
00326                 fclose(pFile);
00327         }
00328         
00329         return true;
00330 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends


cob_canopen_motor
Author(s): Christian Connette
autogenerated on Fri Mar 1 2013 17:46:48