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
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
; // declare variable type
MyRio_Encoder encC0.cnfg = ENCC_0CNFG; // from MyRio1900.h
encC0.stat = ENCC_0STAT; // from MyRio1900.h
encC0.cntr = ENCC_0CNTR; // from MyRio1900.h encC0
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:
(&encC0,
Encoder_Configure| Encoder_SignalMode,
Encoder_Enable | Encoder_QuadPhase); Encoder_Enabled
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:
(&encC0); // returns current encoder count Encoder_Counter
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.