Quadrature encoder interface library.

Dependents:   SimpleRover PIDRover IMURover PID_VelocityExample ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers QEI.h Source File

QEI.h

00001 /**
00002  * @author Aaron Berk
00003  *
00004  * @section LICENSE
00005  *
00006  * Copyright (c) 2010 ARM Limited
00007  *
00008  * Permission is hereby granted, free of charge, to any person obtaining a copy
00009  * of this software and associated documentation files (the "Software"), to deal
00010  * in the Software without restriction, including without limitation the rights
00011  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00012  * copies of the Software, and to permit persons to whom the Software is
00013  * furnished to do so, subject to the following conditions:
00014  *
00015  * The above copyright notice and this permission notice shall be included in
00016  * all copies or substantial portions of the Software.
00017  *
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00019  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00020  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00021  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00022  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00023  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00024  * THE SOFTWARE.
00025  *
00026  * @section DESCRIPTION
00027  *
00028  * Quadrature Encoder Interface.
00029  *
00030  * A quadrature encoder consists of two code tracks on a disc which are 90
00031  * degrees out of phase. It can be used to determine how far a wheel has
00032  * rotated, relative to a known starting position.
00033  *
00034  * Only one code track changes at a time leading to a more robust system than
00035  * a single track, because any jitter around any edge won't cause a state
00036  * change as the other track will remain constant.
00037  *
00038  * Encoders can be a homebrew affair, consisting of infrared emitters/receivers
00039  * and paper code tracks consisting of alternating black and white sections;
00040  * alternatively, complete disk and PCB emitter/receiver encoder systems can
00041  * be bought, but the interface, regardless of implementation is the same.
00042  *
00043  *               +-----+     +-----+     +-----+
00044  * Channel A     |  ^  |     |     |     |     |
00045  *            ---+  ^  +-----+     +-----+     +-----
00046  *               ^  ^
00047  *               ^  +-----+     +-----+     +-----+
00048  * Channel B     ^  |     |     |     |     |     |
00049  *            ------+     +-----+     +-----+     +-----
00050  *               ^  ^
00051  *               ^  ^
00052  *               90deg
00053  *
00054  * The interface uses X2 encoding by default which calculates the pulse count
00055  * based on reading the current state after each rising and falling edge of
00056  * channel A.
00057  *
00058  *               +-----+     +-----+     +-----+
00059  * Channel A     |     |     |     |     |     |
00060  *            ---+     +-----+     +-----+     +-----
00061  *               ^     ^     ^     ^     ^
00062  *               ^  +-----+  ^  +-----+  ^  +-----+
00063  * Channel B     ^  |  ^  |  ^  |  ^  |  ^  |     |
00064  *            ------+  ^  +-----+  ^  +-----+     +--
00065  *               ^     ^     ^     ^     ^
00066  *               ^     ^     ^     ^     ^
00067  * Pulse count 0 1     2     3     4     5  ...
00068  *
00069  * This interface can also use X4 encoding which calculates the pulse count
00070  * based on reading the current state after each rising and falling edge of
00071  * either channel.
00072  *
00073  *               +-----+     +-----+     +-----+
00074  * Channel A     |     |     |     |     |     |
00075  *            ---+     +-----+     +-----+     +-----
00076  *               ^     ^     ^     ^     ^
00077  *               ^  +-----+  ^  +-----+  ^  +-----+
00078  * Channel B     ^  |  ^  |  ^  |  ^  |  ^  |     |
00079  *            ------+  ^  +-----+  ^  +-----+     +--
00080  *               ^  ^  ^  ^  ^  ^  ^  ^  ^  ^
00081  *               ^  ^  ^  ^  ^  ^  ^  ^  ^  ^
00082  * Pulse count 0 1  2  3  4  5  6  7  8  9  ...
00083  *
00084  * It defaults
00085  *
00086  * An optional index channel can be used which determines when a full
00087  * revolution has occured.
00088  *
00089  * If a 4 pules per revolution encoder was used, with X4 encoding,
00090  * the following would be observed.
00091  *
00092  *               +-----+     +-----+     +-----+
00093  * Channel A     |     |     |     |     |     |
00094  *            ---+     +-----+     +-----+     +-----
00095  *               ^     ^     ^     ^     ^
00096  *               ^  +-----+  ^  +-----+  ^  +-----+
00097  * Channel B     ^  |  ^  |  ^  |  ^  |  ^  |     |
00098  *            ------+  ^  +-----+  ^  +-----+     +--
00099  *               ^  ^  ^  ^  ^  ^  ^  ^  ^  ^
00100  *               ^  ^  ^  ^  ^  ^  ^  ^  ^  ^
00101  *               ^  ^  ^  +--+  ^  ^  +--+  ^
00102  *               ^  ^  ^  |  |  ^  ^  |  |  ^
00103  * Index      ------------+  +--------+  +-----------
00104  *               ^  ^  ^  ^  ^  ^  ^  ^  ^  ^
00105  * Pulse count 0 1  2  3  4  5  6  7  8  9  ...
00106  * Rev.  count 0          1           2
00107  *
00108  * Rotational position in degrees can be calculated by:
00109  *
00110  * (pulse count / X * N) * 360
00111  *
00112  * Where X is the encoding type [e.g. X4 encoding => X=4], and N is the number
00113  * of pulses per revolution.
00114  *
00115  * Linear position can be calculated by:
00116  *
00117  * (pulse count / X * N) * (1 / PPI)
00118  *
00119  * Where X is encoding type [e.g. X4 encoding => X=44], N is the number of
00120  * pulses per revolution, and PPI is pulses per inch, or the equivalent for
00121  * any other unit of displacement. PPI can be calculated by taking the
00122  * circumference of the wheel or encoder disk and dividing it by the number
00123  * of pulses per revolution.
00124  */
00125 
00126 #ifndef QEI_H
00127 #define QEI_H
00128 
00129 /**
00130  * Includes
00131  */
00132 #include "mbed.h"
00133 
00134 /**
00135  * Defines
00136  */
00137 #define PREV_MASK 0x1 //Mask for the previous state in determining direction
00138 //of rotation.
00139 #define CURR_MASK 0x2 //Mask for the current state in determining direction
00140 //of rotation.
00141 #define INVALID   0x3 //XORing two states where both bits have changed.
00142 
00143 /**
00144  * Quadrature Encoder Interface.
00145  */
00146 class QEI {
00147 
00148 public:
00149 
00150     typedef enum Encoding {
00151 
00152         X2_ENCODING,
00153         X4_ENCODING
00154 
00155     } Encoding;
00156 
00157     /**
00158      * Constructor.
00159      *
00160      * Reads the current values on channel A and channel B to determine the
00161      * initial state.
00162      *
00163      * Attaches the encode function to the rise/fall interrupt edges of
00164      * channels A and B to perform X4 encoding.
00165      *
00166      * Attaches the index function to the rise interrupt edge of channel index
00167      * (if it is used) to count revolutions.
00168      *
00169      * @param channelA mbed pin for channel A input.
00170      * @param channelB mbed pin for channel B input.
00171      * @param index    mbed pin for optional index channel input,
00172      *                 (pass NC if not needed).
00173      * @param pulsesPerRev Number of pulses in one revolution.
00174      * @param encoding The encoding to use. Uses X2 encoding by default. X2
00175      *                 encoding uses interrupts on the rising and falling edges
00176      *                 of only channel A where as X4 uses them on both
00177      *                 channels.
00178      */
00179     QEI(PinName channelA, PinName channelB, PinName index, int pulsesPerRev, Encoding encoding = X2_ENCODING);
00180 
00181     /**
00182      * Reset the encoder.
00183      *
00184      * Sets the pulses and revolutions count to zero.
00185      */
00186     void reset(void);
00187 
00188     /**
00189      * Read the state of the encoder.
00190      *
00191      * @return The current state of the encoder as a 2-bit number, where:
00192      *         bit 1 = The reading from channel B
00193      *         bit 2 = The reading from channel A
00194      */
00195     int getCurrentState(void);
00196 
00197     /**
00198      * Read the number of pulses recorded by the encoder.
00199      *
00200      * @return Number of pulses which have occured.
00201      */
00202     int getPulses(void);
00203 
00204     /**
00205      * Read the number of revolutions recorded by the encoder on the index channel.
00206      *
00207      * @return Number of revolutions which have occured on the index channel.
00208      */
00209     int getRevolutions(void);
00210 
00211 private:
00212 
00213     /**
00214      * Update the pulse count.
00215      *
00216      * Called on every rising/falling edge of channels A/B.
00217      *
00218      * Reads the state of the channels and determines whether a pulse forward
00219      * or backward has occured, updating the count appropriately.
00220      */
00221     void encode(void);
00222 
00223     /**
00224      * Called on every rising edge of channel index to update revolution
00225      * count by one.
00226      */
00227     void index(void);
00228 
00229     Encoding encoding_;
00230 
00231     InterruptIn channelA_;
00232     InterruptIn channelB_;
00233     InterruptIn index_;
00234 
00235     int          pulsesPerRev_;
00236     int          prevState_;
00237     int          currState_;
00238 
00239     volatile int pulses_;
00240     volatile int revolutions_;
00241 
00242 };
00243 
00244 #endif /* QEI_H */