New QEI library with position (angle) outputs

Fork of QEI_modified by Chun Feng Huang

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 //////////////////////////////
00127 #ifndef QEI_H
00128 #define QEI_H
00129 
00130 #include "mbed.h"
00131 
00132 
00133 #define PREV_MASK 0x1 // Mask for the previous state in determining direction of rotation. (0b01)
00134 #define CURR_MASK 0x2 // Mask for the current state in determining direction of rotation. (0b10)
00135 #define INVALID   0x3 // XORing two states where both bits have changed. (0b11)
00136 
00137 // QEI
00138 ////////////////////////
00139 class QEI {
00140 
00141 public:
00142 
00143     volatile int pulses_;
00144 
00145     int angularvelocity;
00146     int *countArray;
00147     uint8_t arrayPtr;
00148     int arraysize_;
00149     double sampletime_;
00150 
00151     typedef enum Encoding {
00152 
00153         X2_ENCODING,
00154         X4_ENCODING
00155 
00156     } Encoding;
00157 
00158     /**
00159      * Constructor.
00160      *
00161      * Reads the current values on channel A and channel B to determine the
00162      * initial state.
00163      *
00164      * Attaches the encode function to the rise/fall interrupt edges of
00165      * channels A and B to perform X4 encoding.
00166      *
00167      * Attaches the index function to the rise interrupt edge of channel index
00168      * (if it is used) to count revolutions.
00169      *
00170      * @param channelA mbed pin for channel A input.
00171      * @param channelB mbed pin for channel B input.
00172      * @param index    mbed pin for optional index channel input,
00173      *                 (pass NC if not needed).
00174      * @param pulsesPerRev Number of pulses in one revolution.
00175      * @param encoding The encoding to use. Uses X2 encoding by default. X2
00176      *                 encoding uses interrupts on the rising and falling edges
00177      *                 of only channel A where as X4 uses them on both
00178      *                 channels.
00179      */
00180     QEI(PinName channelA, PinName channelB, PinName index, int pulsesPerRev, int arraysize, double sampletime, Encoding encoding = X2_ENCODING);
00181 
00182     /**
00183      * Reset the encoder.
00184      *
00185      * Sets the pulses and revolutions count to zero.
00186      */
00187     void reset(void);
00188 
00189     /**
00190      * Read the state of the encoder.
00191      *
00192      * @return The current state of the encoder as a 2-bit number, where:
00193      *         bit 1 = The reading from channel B
00194      *         bit 2 = The reading from channel A
00195      */
00196     int getCurrentState(void);
00197 
00198     /**
00199      * Read the number of pulses recorded by the encoder.
00200      *
00201      * @return Number of pulses which have occured.
00202      */
00203     int getPulses(void);
00204 
00205     /**
00206      * Read the number of revolutions recorded by the encoder on the index channel.
00207      *
00208      * @return Number of revolutions which have occured on the index channel.
00209      */
00210     int getRevolutions(void);
00211 
00212     void Calculate(void);
00213 
00214     // Get results
00215     // Rotational speed
00216     double getAngularSpeed(void);
00217     double getAngularSpeed_deg_s(void);
00218     // Angle
00219     double getAngle(bool is_ranged); // rad, if is_ranged, return 0~2*PI
00220     double getAngle_deg(bool is_ranged); // deg, if is_ranged, return 0~360
00221 
00222 private:
00223 
00224     /**
00225      * Update the pulse count.
00226      *
00227      * Called on every rising/falling edge of channels A/B.
00228      *
00229      * Reads the state of the channels and determines whether a pulse forward
00230      * or backward has occured, updating the count appropriately.
00231      */
00232     void encode(void);
00233 
00234     /**
00235      * Called on every rising edge of channel index to update revolution
00236      * count by one.
00237      */
00238     void index(void);
00239 
00240     Encoding encoding_;
00241 
00242     InterruptIn channelA_;
00243     InterruptIn channelB_;
00244     InterruptIn index_;
00245 
00246     int          pulsesPerRev_;
00247     int          prevState_;
00248     int          currState_;
00249     
00250     // Unit transformation
00251     // Rotational speed
00252     double        count_2_rad_s;
00253     double        count_2_deg_s;
00254     // Angle
00255     double       count_2_rad;
00256     double       count_2_deg;
00257 
00258 //    volatile int pulses_;
00259     volatile int revolutions_;
00260 
00261 };
00262 
00263 #endif /* QEI_H */