RTC Website

section 4.4 companion and outline

This page contains companion resources and an outline for section 4.4 of the book An Introduction to Real-Time Computing for Mechanical Engineers, and it therefore lacks most of section 4.4’s contents. While some sections of the book are fully available on this site, many are not. Please consider purchasing a copy from the MIT Press.

Measuring motor position and velocity

An example encoder

Processing encoder signals

Programming the target computer encoder inputs

TX

The myRIO has four quadrature encoder inputs, one on each of the connectors A and B (), and two on connector C (). Each has an A channel (pin) and a B channel (pin). These are processed by the field-programmable gate array (FPGA) at up to \(100\) kHz. In this section, we will consider how to program the myRIO encoder inputs. There are three types of registers associated with each encoder input: a configuration register, a status register, and a counter value register.

Configuration and status registers

Each of the four encoder inputs has a \(1\)-byte configuration register that can be set programmatically. All register bits are 0 by default. Switching bit 4 to 1 (and then back to 0) will clear all overflow flags in the associated status register. Similarly, switching bit 3 to 1 (and then back to 0) will clear the error flag in the status register. Bit 2 is the signal mode; the default value 0 sets the encoder to “quadrature encoding” mode and setting it to 1 enables “step and direction” mode, which indicates that one channel will carry timing information about steps, and the other will carry direction information. We will use the quadrature mode. Setting bit 1 to 1 resets the corresponding encoder counter value register to 0, where it remains until configuration bit 1 is set back to 0, at which point counting will begin again. Finally, setting configuration bit 0 to 1 enables the corresponding encoder, and setting it back to 0 disables the encoder.

An encoder input can be configured with a MyRio_Encoder type variable; this type is defined in the myRIO C library’s Encoder.h header file. For instance, we can initialize a variable to configure encoder 0 on connector C with

MyRio_Encoder encC0;      // declare variable type
encC0.cnfg = ENCC_0CNFG;  // from MyRio1900.h
encC0.stat = ENCC_0STAT;  // from MyRio1900.h
encC0.cntr = ENCC_0CNTR;  // from MyRio1900.h

The configuration flags can be set using the Encoder_Configure() function from the myRIO C library’s Encoder.c source file and some bit masks. The Encoder.h header file defines the Encoder_StatusMask and the Encoder_ConfigureSettings types. The Encoder_Configure() function’s prototype is

void Encoder_Configure(MyRio_Encoder *channel,
                       Encoder_ConfigureMask mask,
                       Encoder_ConfigureSettings settings);

A configuration bit is selected with an Encoder_ConfigureMask like Encoder_Enable. The value to be assigned to the configuration bit is selected with an Encoder_ConfigureSettings like Encoder_Enabled. Multiple masks and settings can be combined with the bitwise or |. For instance, to continue the example here by configuring encoder 0 on connector C to be enabled and in quadrature mode, use the following code:

Encoder_Configure(&encC0,
                  Encoder_Enable | Encoder_SignalMode,
                  Encoder_Enabled | Encoder_QuadPhase);

Even if we plan on using a default configuration, it is best to explicitly set that configuration in any case.

The \(1\)-byte status register for each encoder includes several overflow flags, an error flag, and a direction bit that indicates the direction of the most recent change to the encoder counter value register. The Encoder_Status() function from the myRIO C library’s Encoder.c file reads the status register.

Counter value registers and their differences

Each encoder input has an associated unsigned 32-bit integer counter value register to keep track of the count. In quadrature mode, if channel A leads channel B, the count is incremented; if channel B leads, the count is decremented. The counter can be treated as unsigned or signed. As unsigned, once the count reaches its maximum of \(2^{32}-1\), it overflows back to \(0\); if it is decrementing, once it reaches its minimum of \(0\), it underflows back to \(2^{32}-1\). The signed count works similarly, with its maximum of \(2^{31}-1\) and minimum of \(-2^{31}\). When an overflow or underflow occurs, the corresponding bits in the status register are set.

With an initialized encoder variable like encC0, it is straightforward to get the current encoder count from the register with the Encoder_Counter() function from the myRIO C library’s Encoder.c:

Encoder_Counter(&encC0);   // returns current encoder count

This returns an unsigned specific-width integer uint32_t, but it can be assigned (and implicitly cast) to another integer type, such as the signed int (for our compiler, that is a 32-bit integer).

From the difference between the current encoder count \(c_i\) and a previous count \(c_{i-1}\), and the basic time interval (BTI)—the time that has elapsed between samples—we can estimate shaft position and velocity. How will overflow and underflow affect estimates of position and velocity? Assume that the current and previous counts are represented by signed integer variables of width equal to that of the counter. For our C compiler, the int data type is \(32\) bits. Further assume that the angular position of the encoder changes less than \(2^{32}/2{,}000\) revolutions (about \(2\) million!) during a single BTI. That is, \(| c_i - c_{i-1} | < 2^{32}\).

As a result of signed binary integer arithmetic (see subsection 1.4.8), when we compute the difference between two integer data types, the result is defined by the offset mod function: \[ \text{mod}(m,n,d)=m - n \left\lfloor \frac{ m-d}{n} \right\rfloor, \] where \(m\) is the value, \(n\) is the modulus, \(d\) is the offset, and \(\lfloor x \rfloor\) is the floor function (i.e., the greatest integer less than or equal to \(x\).) The result is mod-\(n\), and always in the range \([d,d+n-1]\). For int data, the difference \(\Delta c\) is mod \(2^{32}\), with offset \(d= -2^{31}\); that is, \[\begin{align} \Delta c &= \text{mod}(c_{i}-c_{i-1},2^{32},-2^{31}) \nonumber \\ &= c_{i}-c_{i-1} - 2^{32} \left\lfloor \frac{ c_{i}-c_{i-1}-(-2^{31})}{2^{32}} \right\rfloor. \label{eq:mod-diff} \end{align}\] Let’s examine what happens at overflow. Suppose that the previous counter value \(c_{i-1}\) was \(2^{31}-2\), and during the BTI, the encoder has moved forward by \(4\), such that the current reading \(c_{i}\) is \(-2^{31}+2\), and the numerical difference \(c_{i}-c_{i-1}\) is \(-4,294,967,292\). However, applying eq. ¿eq:mod-diff?, the 32-bit signed integer arithmetic gives the correct result: \(\text{mod}(-4294967292, 2^{32}, -2^{31})=4\).

Online resources for Section 4.4

No online resources.