$search
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 }