Using SimpleMotion scope capture feature
This page is written in Finnish. Translation work in progress. If you need it now, please inquire at Granite Devices support.
Alustus, asetetaan skoopin parametrit[edit | edit source]
SMP_CAPTURE_BUF_LENGHT - montako samplea kaapataan 1-2048
SMP_CAPTURE_SAMPLERATE - näytteistystaajuus (tai sen jakaja). Taajuus on 20kHz/(arvo+1), eli 0=20kHz, 1=10kHz, 2=6.66kHz jne
SMP_CAPTURE_SOURCE - päälläolevat bitit tässä parametrissa määräävät mitä signaaleja bufferiin kaapataan, seuraavat on saavatilla kaikissa firmisversioissa (samat mitä granityssä valittavissa): #define CAPTURE_TORQUE_TARGET 1 #define CAPTURE_TORQUE_ACTUAL 2 #define CAPTURE_VELOCITY_TARGET 3 #define CAPTURE_VELOCITY_ACTUAL 4 #define CAPTURE_POSITION_TARGET 5 #define CAPTURE_POSITION_ACTUAL 6 #define CAPTURE_FOLLOW_ERROR 7 #define CAPTURE_OUTPUT_VOLTAGE 8 #define CAPTURE_BUS_VOLTAGE 9 #define CAPTURE_DEBUG1 19 #define CAPTURE_DEBUG2 20 Esim arvoksi tulee 68 (bitit 2 & 6) kanavilla CAPTURE_TORQUE_ACTUAL ja CAPTURE_POSITION_ACTUAL.
SMP_CAPTURE_TRIGGER - triggeri mikä käynnistää kaappauksen, vaihtoehdot (samat mitä granityssä valittavissa): #define TRIG_NONE 0 #define TRIG_INSTANT 1 #define TRIG_FAULT 2 #define TRIG_TARGETCHANGE 3 #define TRIG_TARGETCHANGE_POS 4 #define TRIG_EXTERNAL_INPUT 5
SMP_CAPTURE_BEFORE_TRIGGER_PERCENTS - tämä tuli vasta FW versiossa 1.6.0. asettaa kaappauksen aloituksen ennen triggausta. arvo prosentteina -1000000...100. Granityt 1.13.0 voi testailla tämän toimintaa.
Skoopin luku[edit | edit source]
Pollataan arvoa SMP_CAPTURE_STATE, arvot: 0 - idle (kaappaus valmis tai ei vielä aloitettukaan) 1 - odottaa triggeriä 2 - kaappaus käynnissä
Kun kaappaus valmis (käynyt arvoissa !=0 ja sitten 0), ladataan data talteen: asetetaan SMP_CAPTURE_BUFFER_GET_ADDR = 0 luetaan parametria SMP_CAPTURE_BUFFER_GET_VALUE yhtä monta kertaa kuin alustuksessa asetettu parametrin arvo SMP_CAPTURE_BUF_LENGHT on tämän luku palauttaa kaapatut samplet. jos asetettiin kaapattavaksi kanavat a, b ja c, niin luetut arvot tulevat järjestyksesä a0,b0,c0,a1,b1,c1,a2,b2,c2,a3,b3,c3.
Example[edit | edit source]
/* Thanks to Oskari Timperi for making part of the code */ #include <stdio.h> #include <unistd.h> //for usleep #include "simplemotion.h" smbus handle; int nodeAddress; bool setupScope() { SM_STATUS status = 0; status |= smSetParameter(handle, nodeAddress, SMP_CAPTURE_BUF_LENGHT, 2048); status |= smSetParameter(handle, nodeAddress, SMP_CAPTURE_BEFORE_TRIGGER_PERCENTS, 0); //note, requires on IONI FW 1.6.0 or later status |= smSetParameter(handle, nodeAddress, SMP_CAPTURE_SAMPLERATE, 7); //with IONI sample rate is 20000/(SMP_CAPTURE_SAMPLERATE+1) Hz, so here it is 2500 Hz status |= smSetParameter(handle, nodeAddress, SMP_CAPTURE_SOURCE, BV(CAPTURE_POSITION_ACTUAL)|BV(CAPTURE_BUS_VOLTAGE)); status |= smSetParameter(handle, nodeAddress, SMP_CAPTURE_TRIGGER, TRIG_INSTANT); status |= smSetParameter(handle, nodeAddress, SMP_CAPTURE_STATE, 1); //start capture if(status!=SM_OK) { //error return false; } return true; } //parameters: nsamples=number of samples to read 1-2048, samples=pointer to buffer with at least nsamples length bool downloadScope( int nsamples, int *samples ) { smint32 retval; int samplesread=0, storepos=0; SM_STATUS smStat=0; //setup for scope reading smStat|=smAppendSMCommandToQueue( handle, SMPCMD_SET_PARAM_ADDR, SMP_RETURN_PARAM_LEN ); smStat|=smAppendSMCommandToQueue( handle, SMPCMD_24B, SMPRET_32B );//read 32 bit (values capped to 30 bits) samples smStat|=smAppendSMCommandToQueue( handle, SMPCMD_SET_PARAM_ADDR, SMP_RETURN_PARAM_ADDR ); smStat|=smAppendSMCommandToQueue( handle, SMPCMD_24B, SMP_CAPTURE_BUFFER_GET_VALUE ); //read at get_value param smStat|=smAppendSMCommandToQueue( handle, SMPCMD_SET_PARAM_ADDR, SMP_CAPTURE_BUFFER_GET_ADDR ); //set store address to get_addr smStat|=smExecuteCommandQueue(handle,nodeAddress); smStat|=smGetQueuedSMCommandReturnValue( handle, &retval ); smStat|=smGetQueuedSMCommandReturnValue( handle, &retval ); smStat|=smGetQueuedSMCommandReturnValue( handle, &retval ); smStat|=smGetQueuedSMCommandReturnValue( handle, &retval ); smStat|=smGetQueuedSMCommandReturnValue( handle, &retval ); //loop to read samples while(samplesread<nsamples) { int i; int samplestofetch=nsamples-samplesread; if(samplestofetch>30)samplestofetch=30;//maximum per one SM cycle (4*30=120 bytes=max payload) //add read param commands to queue for(i=0;i<samplestofetch;i++) { smStat|=smAppendSMCommandToQueue( handle, SMPCMD_24B, samplesread ); samplesread++; } //transmit & redeive over SM bus smStat|=smExecuteCommandQueue(handle,nodeAddress); //read values from return data queue for(i=0;i<samplestofetch;i++) { smStat|=smGetQueuedSMCommandReturnValue( handle, &retval ); samples[storepos++]=retval; } } //read one dummy variable just to cause SMP_RETURN_PARAM_ADDR to change to non-SMP_CAPTURE_BUFFER_GET_VALUE so next time we read data, we get it all from beginning smStat |= smRead1Parameter(handle, nodeAddress, SMP_NULL, &retval ); if(smStat!=SM_OK) return false; return true; } SM_STATUS scopeWait() { smint32 state; //loop until SMP_CAPTURE_STATE is 0 (scope idle) while (true) { SM_STATUS status = smRead1Parameter(handle, nodeAddress, SMP_CAPTURE_STATE, &state); if (status != SM_OK) return status; fprintf(stderr, "scope state: %d\n", state); if (state == 0) { break; } usleep(100000); } return SM_OK; } int main( void ) { const char *portName="COM3"; //bus device name nodeAddress = 4; //SM device address int samples[2048]; fprintf(stderr, "opening bus %s\n", portName); handle = smOpenBus(portName); if (handle < 0) { fprintf(stderr, "could not open bus: %s\n", portName); return -4; } if(setupScope()==false) return -1; if(scopeWait()!=SM_OK) return -2; if(downloadScope( 2048, samples )==false) return -3; //sample list will be repeating list of samples defined to SMP_CAPTURE_SOURCE. //I.e if we capture 3 channels A, B and C, then samples will contain A0,B0,C0,A1,B1,C1,A2,B3,C3 etc for( int i=0; i<2048; i++) { fprintf(stderr, "samples[%d]=%d\n", i, samples[i]); } fprintf(stderr, "All done\n"); return 0; }
In no event the Product Information or parts hereof shall be regarded as guarantee of conditions or characteristics. The Product Information or any part thereof may also not be regarded as a warranty of any kind. No liability of any kind shall be assumed by Author with respect to Product Information or any use made by you thereof, nor shall Author indemnify you against or be liable for any third party claims with respect to such information or any use thereof.
As content of this Wiki may be edited by user community, Granite Devices Oy or it's affiliates do not take any responsibility of the contents of this Wiki. Use information at your own risk. However, Granite Devices staff attempts to review all changes made to this Wiki and keep information trustworthy.
Without written consent, Granite Devices' Products or Intellectual Property shall not be used in situations or installations where living beings, material property, or immaterial property could be harmed by the operation, features or failures of Product. Products may only be used in a way where hazards like moving parts, electric shock, laser radiation, or fire can't be realized even if the content of this Wiki would suggest otherwise.