Editing Optimizing SimpleMotion V2 performance

Jump to: navigation, search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.

This page supports semantic in-text annotations (e.g. "[[Is specified as::World Heritage Site]]") to build structured and queryable content provided by Semantic MediaWiki. For a comprehensive description on how to use annotations or the #ask parser function, please have a look at the getting started, in-text annotation, or inline queries help page.

Latest revision Your text
Line 5: Line 5:
 
*Command execution time of SMV2 slave device (servo drive). This is the delay how soon slave sends the return data after it has received the command from the SMV2 host. On [[Argon]] this is typically around 1-2 ms for a single command and 0.4 ms on each additional command in the queue (see later sections for info about queued commands).
 
*Command execution time of SMV2 slave device (servo drive). This is the delay how soon slave sends the return data after it has received the command from the SMV2 host. On [[Argon]] this is typically around 1-2 ms for a single command and 0.4 ms on each additional command in the queue (see later sections for info about queued commands).
 
*Baud rate of RS485 bus. By default this is 460800 bits per second which is not typically the bottle neck. It is possible to change baud rate by one SMV2 command if necessary (TODO: how).
 
*Baud rate of RS485 bus. By default this is 460800 bits per second which is not typically the bottle neck. It is possible to change baud rate by one SMV2 command if necessary (TODO: how).
*Usage of SM library commands. Using higher level commands usually produce more bus traffic and lower performance compared to lower level code.
 
 
 
==Improving performance==
 
==Improving performance==
 
===RS485 adapter latency===
 
===RS485 adapter latency===
Line 14: Line 12:
 
===Optimizing code===
 
===Optimizing code===
 
The easiest way to use SMV2 library is to use ''smSetParameter'' and ''smRead1Parameter'' commands. However these commands are not optimal as they set and read only one parameter at the time and all latencies are added to this single call.
 
The easiest way to use SMV2 library is to use ''smSetParameter'' and ''smRead1Parameter'' commands. However these commands are not optimal as they set and read only one parameter at the time and all latencies are added to this single call.
===Queued calls===
+
====Queued calls====
 
The more optimal way is to use '''queued''' SM commands. Queued command is a list of commands that are transferred to a slave in single data transfer, executed as a batch in the slave and finally all return data is returned as list. In this case bus latencies occur only once per multiple commands.
 
The more optimal way is to use '''queued''' SM commands. Queued command is a list of commands that are transferred to a slave in single data transfer, executed as a batch in the slave and finally all return data is returned as list. In this case bus latencies occur only once per multiple commands.
  
 
Instead of doing this...
 
Instead of doing this...
 
<syntaxhighlight lang="c">
 
<syntaxhighlight lang="c">
smSetParameter( busHandle, deviceAddress, paramAddr1, paramVal1 );
+
smSetParameter( handle, deviceAddress, paramId1, paramVal1 );
smSetParameter( busHandle, deviceAddress, paramAddr2, paramVal1 );
+
smSetParameter( handle, deviceAddress, paramId2, paramVal1 );
smSetParameter( busHandle, deviceAddress, paramAddr3, paramVal1 );
+
smSetParameter( handle, deviceAddress, paramId3, paramVal1 );
smSetParameter( busHandle, deviceAddress, paramAddr4, paramVal1 );
+
smSetParameter( handle, deviceAddress, paramId4, paramVal1 );
 
</syntaxhighlight>
 
</syntaxhighlight>
 
...one may do this:
 
...one may do this:
Line 28: Line 26:
 
smint32 nul;
 
smint32 nul;
 
//append commands to queue
 
//append commands to queue
smAppendSetParamCommandToQueue( busHandle, paramAddr1, paramVal1 );
+
smAppendSetParamCommandToQueue( handle, paramId1, paramVal1 );
smAppendSetParamCommandToQueue( busHandle, paramAddr2, paramVal2 );
+
smAppendSetParamCommandToQueue( handle, paramId2, paramVal2 );
smAppendSetParamCommandToQueue( busHandle, paramAddr3, paramVal3 );
+
smAppendSetParamCommandToQueue( handle, paramId3, paramVal3 );
smAppendSetParamCommandToQueue( busHandle, paramAddr4, paramVal4 );
+
smAppendSetParamCommandToQueue( handle, paramId4, paramVal4 );
  
 
//execute commands over SM bus
 
//execute commands over SM bus
Line 40: Line 38:
 
before appending new commands. So each smAppendSetParamCommandToQueue will need  
 
before appending new commands. So each smAppendSetParamCommandToQueue will need  
 
one smGetQueuedSetParamReturnValue after smExecuteCommandQueue.*/
 
one smGetQueuedSetParamReturnValue after smExecuteCommandQueue.*/
smGetQueuedSetParamReturnValue(  busHandle, &nul );
+
smGetQueuedSetParamReturnValue(  handle, &nul );
smGetQueuedSetParamReturnValue(  busHandle, &nul );
+
smGetQueuedSetParamReturnValue(  handle, &nul );
smGetQueuedSetParamReturnValue(  busHandle, &nul );
+
smGetQueuedSetParamReturnValue(  handle, &nul );
smGetQueuedSetParamReturnValue(  busHandle, &nul );
+
smGetQueuedSetParamReturnValue(  handle, &nul );
 
+
//TODO add some SM error checking in appropriate places
+
 
</syntaxhighlight>
 
</syntaxhighlight>
  
In the above example, the ''smExecuteCommandQueue'' is the only line where RS485 is being used thus generating only one write-read latency instead. ''smAppendSetParamCommandToQueue'' and ''smGetQueuedSetParamReturnValue'' transfer data only inside SMV2 library buffers and are fast calls. The optimized code does only one bus transfer cycle instead of four.
+
In the above example, the ''smExecuteCommandQueue'' is the only line where RS485 is being used thus generating only one write-read latency. ''smAppendSetParamCommandToQueue'' and ''smGetQueuedSetParamReturnValue'' transfer data only inside SMV2 library buffers and are fast calls.
  
====Queued size limit====
+
=====Queued size limit=====
 
One SMV2 command or return data packet can hold up to 120 bytes of payload data. This means that one should not add too many commands to the queue to avoid exceeding the 120 byte limit in outbound or inbound direction.
 
One SMV2 command or return data packet can hold up to 120 bytes of payload data. This means that one should not add too many commands to the queue to avoid exceeding the 120 byte limit in outbound or inbound direction.
  
 
Single smAppendSetParamCommandToQueue commands consumes maximum of 6 bytes in outbound data and smGetQueuedSetParamReturnValue maximum of 4 bytes. So one can safely queue 20 set parameter commands in the one transfer.
 
Single smAppendSetParamCommandToQueue commands consumes maximum of 6 bytes in outbound data and smGetQueuedSetParamReturnValue maximum of 4 bytes. So one can safely queue 20 set parameter commands in the one transfer.
 
+
====Low level queued commands====
===Low level queued commands===
+
{{info|This is work in progress chapter, don't use}}
 
This section shall describe how to further optimize communication by using lower level queued commands instead of smAppendSetParamCommandToQueue and smGetQueuedSetParamReturnValue which do some dummy assumptions (such as all parameters are written as 30 bit values and every time parameter address is set even if it's not changed from the previous set parameter command). Also reading variables while writing one is possible without separate command which reduces the amount of SM commands needed.
 
This section shall describe how to further optimize communication by using lower level queued commands instead of smAppendSetParamCommandToQueue and smGetQueuedSetParamReturnValue which do some dummy assumptions (such as all parameters are written as 30 bit values and every time parameter address is set even if it's not changed from the previous set parameter command). Also reading variables while writing one is possible without separate command which reduces the amount of SM commands needed.
====Writing and reading multiple values at one cycle====
+
 
 
Following example will:
 
Following example will:
*Initialize read-out parameter size to 24 bits. All consequent commands will have return data length of 24 bits until changed next time.
+
*Initialize read-out parameter address so that all further SM commands will return the desired parameter as return value
*Use variable parameter bit lengths to reduce amount of data transferred. For example sending 24 bit commands is good for values such as torque command or parameter values and 32 bits for position commands when travel length is large.
+
*Use custom parameter lengths to reduce amount of data transferred
  
Initialization code where we specify readout variable length.
 
 
<syntaxhighlight lang="c">
 
<syntaxhighlight lang="c">
/*setting return data lenght to 24 bits (22 bits maximum returned integer value
+
TODOTODOTODOTODO
as 2 bits are used by SM protocol). 16 bit data will fit in return value without clipping. */
+
smSetParameter( busHandle, deviceAddress, SMP_RETURN_PARAM_LEN, SMPRET_24B);
+
 
</syntaxhighlight>
 
</syntaxhighlight>
  
This is our optimized code that goes into high frequency loop. It writes 3 different parameters and reads 3 parameters with single bus transfer.
 
 
<syntaxhighlight lang="c">
 
<syntaxhighlight lang="c">
    /* Variables:
+
//set address where values are written. Consumes 2 bytes of outbound payload
    -paramValue1-3 are the parameter values written to parameter numbers defined in paramAddr1-3
+
smAppendSMCommandToQueue( handle, SMPCMD_SETPARAMADDR, paramAddr1 );
    -readOutParamAddr1-3 will define the parameter numbers to read out into readout1-3
+
//write parameter value. SMPCMD_16B consumes 2 bytes of outbound payload
    */
+
smAppendSMCommandToQueue( handle, SMPCMD_16B, paramValue1);
 +
//set address where values are written
 +
smAppendSMCommandToQueue( handle, SMPCMD_SETPARAMADDR, paramAddr2 );
 +
//write parameter value. SMPCMD_24B consumes 3 bytes of outbound payload
 +
smAppendSMCommandToQueue( handle, SMPCMD_24B, paramValue2);
 +
//set address where values are written
 +
smAppendSMCommandToQueue( handle, SMPCMD_SETPARAMADDR, paramAddr3 );
 +
//write parameter value. SMPCMD_32B consumes 4 bytes of outbound payload
 +
smAppendSMCommandToQueue( handle, SMPCMD_32B, paramValue3);
  
    //VALUES DEFINED
+
//execute commands over SM bus
    int paramAddr1=SMP_DEBUGPARAM4;
+
smExecuteCommandQueue( handle, nodeAddress );
    int paramAddr2=SMP_DEBUGPARAM5;
+
    int paramAddr3=SMP_DEBUGPARAM6;
+
    int paramValue1=100;
+
    int paramValue2=200;
+
    int paramValue3=300;
+
    int readOutParamAddr1=SMP_ACTUAL_TORQUE;
+
    int readOutParamAddr2=SMP_ACTUAL_POSITION_FB;
+
    int readOutParamAddr3=SMP_BUS_SPEED;
+
    smint32 nul, readout1, readout2, readout3;
+
 
+
    //WRITING PARAMETERS
+
    //set an parameter number where next values are written. This line consumes 2 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_SETPARAMADDR, paramAddr1 );
+
 
+
    //write the parameter value to previously set parameter address. SMPCMD_24B consumes 3 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, paramValue1);
+
 
+
    //set an new parameter number where next values are written. This line consumes 2 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_SETPARAMADDR, paramAddr2 );
+
 
+
    //write the parameter value to previously set parameter address. SMPCMD_24B consumes 3 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, paramValue2);
+
 
+
    //set an new parameter number where next values are written. This line consumes 2 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_SETPARAMADDR, paramAddr3 );
+
 
+
    //write the parameter value to previously set parameter address. SMPCMD_32B consumes 4 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_32B, paramValue3);
+
 
+
    //READING PARAMETERS
+
    //set parameter parameter number which will be returned from each command executed after this
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_SETPARAMADDR, SMP_RETURN_PARAM_ADDR ); //consumes 2 bytes
+
    /*write new values to parameter SMP_RETURN_PARAM_ADDR. after execution these commands return the parameter values
+
    defined by readOutParamAddrN*/
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, readOutParamAddr1 ); //consumes 3 bytes
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, readOutParamAddr2 ); //consumes 3 bytes
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, readOutParamAddr3 ); //consumes 3 bytes
+
 
+
    //execute commands over SM bus
+
    smExecuteCommandQueue( busHandle, deviceAddress );
+
 
+
    /*read value commands (one per each append command). Size of inbound payload depends on
+
    what was set to SMP_RETURN_PARAM_LEN at initialization */
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
 
+
 
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
 
+
    /*the next readouts reflect to the last three commands appended before smExecuteCommandQueue
+
    and here we get the readout values*/
+
 
+
    smGetQueuedSMCommandReturnValue( busHandle,&readout1 );
+
    smGetQueuedSMCommandReturnValue( busHandle,&readout2 );
+
    smGetQueuedSMCommandReturnValue( busHandle,&readout3 );
+
 
+
    //TODO add some SM error checking in appropriate places
+
</syntaxhighlight>
+
 
+
Below an alternative code that writes one variable (absolute setpoint) and read three variables (torque, position and velocity feedbacks). This code is present in live demo in [https://github.com/GraniteDevices/SMV2Commander SMV2Commander example].
+
<syntaxhighlight lang="c">
+
 
+
    //VALUES DEFINED
+
    int paramAddr1=SMP_ABSOLUTE_SETPOINT;
+
    int paramValue1=0;//your setpoint value
+
    int readOutParamAddr1=SMP_ACTUAL_TORQUE;
+
    int readOutParamAddr2=SMP_ACTUAL_POSITION_FB;
+
    int readOutParamAddr3=SMP_ACTUAL_VELOCITY_FB;
+
    smint32 nul, readout1, readout2, readout3;
+
 
+
    //WRITING PARAMETERS
+
    //set an parameter number where next values are written. This line consumes 2 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_SETPARAMADDR, paramAddr1 );
+
 
+
    //write the parameter value to previously set parameter address. SMPCMD_24B consumes 3 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, paramValue1);
+
 
+
    //READING PARAMETERS
+
    //set parameter parameter number which will be returned from each command executed after this
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_SETPARAMADDR, SMP_RETURN_PARAM_ADDR ); //consumes 2 bytes
+
    /*write new values to parameter SMP_RETURN_PARAM_ADDR. after execution these commands return the parameter values
+
    defined by readOutParamAddrN*/
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, readOutParamAddr1 ); //consumes 3 bytes
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, readOutParamAddr2 ); //consumes 3 bytes
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, readOutParamAddr3 ); //consumes 3 bytes
+
 
+
    //execute commands over SM bus
+
    smExecuteCommandQueue( busHandle, deviceAddress );
+
 
+
    /*read value commands (one per each append command). Size of inbound payload depends on
+
    what was set to SMP_RETURN_PARAM_LEN at initialization */
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
 
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
 
+
    /*the next readouts reflect to the last three commands appended before smExecuteCommandQueue
+
    and here we get the readout values*/
+
 
+
    smGetQueuedSMCommandReturnValue( busHandle,&readout1 );
+
    smGetQueuedSMCommandReturnValue( busHandle,&readout2 );
+
    smGetQueuedSMCommandReturnValue( busHandle,&readout3 );
+
 
+
    //TODO add some SM error checking in appropriate places
+
</syntaxhighlight>
+
====Writing multiple and reading single value at one cycle====
+
If we need to read only one variable, we don't need to change readout parameter address during cycle and further improve performance. In this case we set it at initialization and then all consequent commands will return the desired return value.
+
 
+
Initialization:
+
<syntaxhighlight lang="c">
+
    /* Variables:
+
    -readOutParamAddr1 will define the parameter number to be read out into readout1
+
    */
+
    smint32 nul, readOutParamAddr1=SMP_ACTUAL_POSITION_FB;
+
 
+
    /*setting return data lenght to 24 bits (22 bits maximum returned integer value
+
    as 2 bits are used by SM protocol). 16 bit data will fit in return value without clipping.
+
 
+
    Note: we do it the low level way in this case because SMPCMD_SETPARAMADD is
+
    not available on higher level SM functions*/
+
 
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_SETPARAMADDR, SMP_RETURN_PARAM_LEN ); //2b
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, SMPRET_24B );//3b
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_SETPARAMADDR, SMP_RETURN_PARAM_ADDR );//2b
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, readOutParamAddr2 );//3b
+
 
+
    //execute commands over SM bus
+
    smExecuteCommandQueue( busHandle, deviceAddress );
+
 
+
    //must get all inserted commands from buffer
+
    smGetQueuedSMCommandReturnValue( busHandle, &nul );
+
    smGetQueuedSMCommandReturnValue( busHandle, &nul );
+
    smGetQueuedSMCommandReturnValue( busHandle, &nul );
+
    smGetQueuedSMCommandReturnValue( busHandle, &nul );
+
 
+
    //TODO add some SM error checking in appropriate places
+
</syntaxhighlight>
+
 
+
Frequently called function with writing 3 variables and reading one in one bus transfer:
+
<syntaxhighlight lang="c">
+
    /* Variables:
+
    -paramValue1-3 are the parameter values written to parameter numbers defined in paramAddr1-3
+
    -readOutParamAddr1-3 will define the parameter numbers to read out into readout1-3
+
    */
+
    int paramAddr1=SMP_DEBUGPARAM4;
+
    int paramAddr2=SMP_DEBUGPARAM5;
+
    int paramAddr3=SMP_DEBUGPARAM6;
+
    int paramValue1=100;
+
    int paramValue2=200;
+
    int paramValue3=300;
+
    smint32 nul, readout1;
+
 
+
    //WRITING PARAMETERS
+
    //set an parameter number where next values are written. This line consumes 2 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_SETPARAMADDR, paramAddr1 );
+
 
+
    //write the parameter value to previously set parameter address. SMPCMD_24B consumes 3 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, paramValue1);
+
 
+
    //set an new parameter number where next values are written. This line consumes 2 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_SETPARAMADDR, paramAddr2 );
+
 
+
    //write the parameter value to previously set parameter address. SMPCMD_24B consumes 3 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_24B, paramValue2);
+
 
+
    //set an new parameter number where next values are written. This line consumes 2 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_SETPARAMADDR, paramAddr3 );
+
 
+
    //write the parameter value to previously set parameter address. SMPCMD_32B consumes 4 bytes of outbound payload
+
    smAppendSMCommandToQueue( busHandle, SMPCMD_32B, paramValue3);
+
 
+
    //notice that we don't need to change readout parameter addresses here as it we have only one variable to read out
+
 
+
    //execute commands over SM bus
+
    smExecuteCommandQueue( busHandle, deviceAddress );
+
 
+
    /*read value commands (one per each append command before execute). Size of inbound payload depends on
+
    what was set to SMP_RETURN_PARAM_LEN at initialization. In this case 3 bytes per return value (total 6x3). */
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
    smGetQueuedSMCommandReturnValue( busHandle,&nul );
+
    smGetQueuedSMCommandReturnValue( busHandle,&readout1 ); //we could get the readout1 from any of the above lines as well
+
  
    //TODO add some SM error checking in appropriate places
+
//read value commands (one per each append command). Size of inbound payload depends on how large TODOTODO
 +
smGetQueuedSMCommandReturnValue( handle,&ret );
 +
smGetQueuedSMCommandReturnValue( handle,&ret );
 +
smGetQueuedSMCommandReturnValue( handle,&ret );
 +
smGetQueuedSMCommandReturnValue( handle,&ret );
 +
smGetQueuedSMCommandReturnValue( handle,&ret );
 +
smGetQueuedSMCommandReturnValue( handle,&ret );
 
</syntaxhighlight>
 
</syntaxhighlight>
==See also==
 
*[[Changing SimpleMotion baud rate]]
 
[[Category:Development]]
 
[[Category:SimpleMotion]]
 

Please note that all contributions to Granite Devices Knowledge Wiki may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see Granite Devices Knowledge Wiki:Copyrights for details). Do not submit copyrighted work without permission!

Select categories:

To edit this page, please answer the question that appears below (more info):

Cancel | Editing help (opens in new window)