This document provides instructions on how to interface an incremental encoder with a B-Box RCP or a B-Board PRO and presents a simple and effective way to derive an angular velocity from the measured angle.

Technical resources

Incremental encoder

In drive applications, the knowledge of both the rotor angular position and angular speed is a central point to achieve oriented vector control and robust speed control. These two variables can either be measured (sensored) or estimated (sensorless).

In sensored applications, one possible way of measuring the rotor position is by using incremental encoders. They notably differ from absolute encoders in that the latter provides an absolute position, often coded in Gray code. Incremental encoders, on the contrary, provide only incremental position changes and an interface is needed to compute the rotor absolute position. This is the purpose of the decoder module available on the B-Box RCP and B-Board PRO.

The most common incremental encoders are quadrature encoders. They produce quadrature signals A and B, allowing to deduce the direction of rotation, depending on which signal is leading. Optionally, a reset signal Z is present to provide an absolute position (one pulse per turn). Finally, to offer more robustness against perturbations, some encoders provide also the complementary signals \A, \B and \Z.

References

[1] Encoder Products Company, “WP-2011: The Basics of How an Encoder Works“, White paper, March 2018
[2] Autonics, “Rotary encoders - Technical description”, Feb 2018

Decoder

The decoder modules present on the B-Box RCP and B-Board PRO are meant to decode the angle information from a quadrature incremental encoder, with or without Z signal and with or without complementary signals. They offer the following configuration parameters:

Parameter

Possible values

Remark

Input mode

Single-ended / Differential

If Differential, the complementary signals are also considered

Pulse per rotation (ppr)

Between 1 and 65536

Must correspond to the encoder specifications

Reset mode

Maximum value / Z input

If Maximum value, the decoder counter is reset when it reaches the ppr value. Otherwise, it’s reset on a rising edge of the Z signal.

Direction

Clockwise / Counterclockwise

If Clockwise and A is leading, the angle increases

Invert input signals

No / Yes

If Yes, all the inputs signals are inverted

The decoder driver is implemented in FPGA with the following logic:

There are a total of 4 decoder modules on each B-Box or B-Board. The encoder signals have to be connected to the GPI inputs of the device, using the following pins:

Conn. pin

GPI signal

DEC signal

A2

GPI 0

A0

A3

GPI 1

B0

A4

GPI 2

Z0

A5

GPI 3

A1 or \A0

A6

GPI 4

B1 or \B0

A7

GPI 5

Z1 or \Z0

Conn. pin

GPI signal

DEC signal

B2

GPI 8

A2

B3

GPI 9

B2

B4

GPI 10

Z2

B5

GPI 11

A3 or \A2

B6

GPI 12

B3 or \B2

B7

GPI 13

Z3 or \Z2

imperix provides a handy breakout board for the digital signal connectors, available here.

Computing angular speed

The angular speed can be derived from the angle information, directly inside the user application. The angular speed being the derivative of the angle, it can be computed as the variation of the measured angle between two consecutive samples:

\begin{array}{l}\displaystyle \omega_m(k) = \displaystyle\frac{\theta_m(k)-\theta_m(k-1)}{T_s}\end{array}

As the measured angle is in the range \begin{array}{l}\left[ 0; 2\pi\right]\end{array}, its value jumps from \begin{array}{l}2\pi\end{array} to \begin{array}{l}0\end{array}. These discontinuities can be compensated as follows:

\begin{array}{l}\omega_m(k) = \begin{cases} (\theta_m(k)-\theta_m(k-1)+2\pi)/T_s & \text{if } \theta_m(k)-\theta_m(k-1) < -\pi\\ (\theta_m(k)-\theta_m(k-1)-2\pi)/T_s & \text{if } \theta_m(k)-\theta_m(k-1) > \pi\\ (\theta_m(k)-\theta_m(k-1))/T_s & \text{otherwise} \end{cases}\right.\end{array}

Oftentimes, the speed value needs to be filtered to minimize the effect of the quantization error of the angle encoder. A simple filtering solution is by using an IIR filter, with the following transfer function:

\begin{array}{l}\displaystyle H(z) = \displaystyle\frac{\alpha}{1+(\alpha-1)z^{-1}}\end{array}

The \begin{array}{l}\alpha\end{array} parameter depends on the filter cutoff frequency \begin{array}{l}f_c = 1/(2\pi t_c)\end{array} and the sampling period \begin{array}{l}T_s\end{array}(i.e. execution rate of the filter):

\begin{array}{l}\displaystyle \alpha = \displaystyle\frac{T_s}{t_c+T_s} = \frac{2\pi f_c T_s}{1+2\pi f_c T_s}\end{array}

B-Box / B-Board implementation

The dedicated Simulink block is described in DEC - Angle decoder.

The decoder block (DEC) provides the measured angle. As such, the speed can also be derived as follows:

The following function accounts for discontinuities in the measured angle:

f(u) = u(1)+2*pi*((u(1)-u(2))<-pi)-2*pi*((u(1)-u(2)>pi))

PLECS

The dedicated PLECS blocks is described in DEC - Angle decoder.

Similarly to the Simulink implementation, the decoder block (DEC) can be used as follows:

The following function accounts for discontinuities in the measured angle:

f(u) = u(1)+2*pi*((u(1)-u(2))<-pi)-2*pi*((u(1)-u(2)>pi))

C/C++ code

The corresponding C/C++ routines are described in DEC - Angle decoder.

Implementation example

In UserInit: configuration of a differential decoder, with 4096 pulses per rotation and Z signal:

tUserSafe UserInit(void)
{
  // ...
  
  // Configuration of the decoder (angle measurement)
  Dec_ConfigureInputMode(DECODER_CHANNEL_0, DIFFERENTIAL);
  Dec_ConfigurePulsePerRotation(DECODER_CHANNEL_0, 4096);
  Dec_ConfigureResetMode(DECODER_CHANNEL_0, ZINPUT);
  
  // ...
}

In the main interrupt UserInterrupt: get the measured angle and compute the speed. An angle offset can be added to the measured angle to match the angle reference with the application.

tUserSafe UserInterrupt(void)
{
  // ...
  
  // Get angle from decoder module
  angle_meas = Dec_GetAngle(DECODER_CHANNEL_0) + angle_offset;
    
  // Speed measurement
  speed_meas_raw = ComputeSpeed(angle_meas, previous_angle);
  previous_angle = angle_meas;
  // Low-pass filter measured speed
  speed_meas = speed_meas - (alpha * (speed_meas - speed_meas_raw));
  
  // ...
}

float ComputeSpeed(float current_angle, float previous_angle)
{
  float corr = 0.0;
  if (current_angle - previous_angle < -PI)
    corr = 2*PI;
  else if (current_angle - previous_angle > PI)
    corr = -2*PI;
  
  return (current_angle - previous_angle + corr)/SAMPLING_PERIOD;
}
  • No labels