Patrick Wensing / QEI_pmw

Dependents:   Bezier_Trajectory_Follower Dolphin 2_131TEST Jerby ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers QEI.cpp Source File

QEI.cpp

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  * Includes
00128  */
00129 #include "QEI.h"
00130 
00131 QEI::QEI(PinName channelA,
00132          PinName channelB,
00133          PinName index,
00134          int pulsesPerRev,
00135          Encoding encoding) : channelA_(channelA), channelB_(channelB),
00136         index_(index) {
00137 
00138     pulses_       = 0;
00139     revolutions_  = 0;
00140     pulsesPerRev_ = pulsesPerRev;
00141     encoding_     = encoding;
00142 
00143     //Workout what the current state is.
00144     int chanA = channelA_.read();
00145     int chanB = channelB_.read();
00146 
00147     //2-bit state.
00148     currState_ = (chanA << 1) | (chanB);
00149     prevState_ = currState_;
00150 
00151     //X2 encoding uses interrupts on only channel A.
00152     //X4 encoding uses interrupts on      channel A,
00153     //and on channel B.
00154     channelA_.rise(this, &QEI::encode);
00155     channelA_.fall(this, &QEI::encode);
00156 
00157     //If we're using X4 encoding, then attach interrupts to channel B too.
00158     if (encoding == X4_ENCODING) {
00159         channelB_.rise(this, &QEI::encode);
00160         channelB_.fall(this, &QEI::encode);
00161     }
00162     //Index is optional.
00163     if (index !=  NC) {
00164         index_.rise(this, &QEI::index);
00165     }
00166     
00167     timer.start();
00168     prevTime_ = 0;
00169     currTime_ = 0;
00170     prevDirection_ = 1;
00171     currDirection_ = 1;
00172 }
00173 
00174 void QEI::reset(void) {
00175 
00176     pulses_      = 0;
00177     revolutions_ = 0;
00178 
00179 }
00180 
00181 int QEI::getCurrentState(void) {
00182 
00183     return currState_;
00184 
00185 }
00186 
00187 int QEI::getPulses(void) {
00188 
00189     return pulses_;
00190 
00191 }
00192 
00193 int QEI::getRevolutions(void) {
00194 
00195     return revolutions_;
00196 
00197 }
00198 
00199 // +-------------+
00200 // | X2 Encoding |
00201 // +-------------+
00202 //
00203 // When observing states two patterns will appear:
00204 //
00205 // Counter clockwise rotation:
00206 //
00207 // 10 -> 01 -> 10 -> 01 -> ...
00208 //
00209 // Clockwise rotation:
00210 //
00211 // 11 -> 00 -> 11 -> 00 -> ...
00212 //
00213 // We consider counter clockwise rotation to be "forward" and
00214 // counter clockwise to be "backward". Therefore pulse count will increase
00215 // during counter clockwise rotation and decrease during clockwise rotation.
00216 //
00217 // +-------------+
00218 // | X4 Encoding |
00219 // +-------------+
00220 //
00221 // There are four possible states for a quadrature encoder which correspond to
00222 // 2-bit gray code.
00223 //
00224 // A state change is only valid if of only one bit has changed.
00225 // A state change is invalid if both bits have changed.
00226 //
00227 // Clockwise Rotation ->
00228 //
00229 //    00 01 11 10 00
00230 //
00231 // <- Counter Clockwise Rotation
00232 //
00233 // If we observe any valid state changes going from left to right, we have
00234 // moved one pulse clockwise [we will consider this "backward" or "negative"].
00235 //
00236 // If we observe any valid state changes going from right to left we have
00237 // moved one pulse counter clockwise [we will consider this "forward" or
00238 // "positive"].
00239 //
00240 // We might enter an invalid state for a number of reasons which are hard to
00241 // predict - if this is the case, it is generally safe to ignore it, update
00242 // the state and carry on, with the error correcting itself shortly after.
00243 void QEI::encode(void) {
00244 
00245     int change = 0;
00246     int chanA  = channelA_.read();
00247     int chanB  = channelB_.read();
00248 
00249     //2-bit state.
00250     currState_ = (chanA << 1) | (chanB);
00251 
00252     if (encoding_ == X2_ENCODING) {
00253 
00254         //11->00->11->00 is counter clockwise rotation or "forward".
00255         if ((prevState_ == 0x3 && currState_ == 0x0) ||
00256                 (prevState_ == 0x0 && currState_ == 0x3)) {
00257 
00258             pulses_++;
00259 
00260         }
00261         //10->01->10->01 is clockwise rotation or "backward".
00262         else if ((prevState_ == 0x2 && currState_ == 0x1) ||
00263                  (prevState_ == 0x1 && currState_ == 0x2)) {
00264 
00265             pulses_--;
00266 
00267         }
00268 
00269     } else if (encoding_ == X4_ENCODING) {
00270 
00271         //    00 01 11 10 00
00272         
00273         //Entered a new valid state.
00274         if (((currState_ ^ prevState_) != INVALID) && (currState_ != prevState_)) {
00275             //2 bit state. Right hand bit of prev XOR left hand bit of current
00276             //gives 0 if clockwise rotation and 1 if counter clockwise rotation.
00277             change = (prevState_ & PREV_MASK) ^ ((currState_ & CURR_MASK) >> 1);
00278 
00279             if (change == 0) {
00280                 change = -1;
00281             }
00282             
00283             prevTime_ = currTime_;
00284             currTime_ = timer.read_us();
00285             
00286             prevDirection_ = currDirection_;
00287             currDirection_ = change;
00288 
00289             pulses_ -= change;
00290         }
00291 
00292     }
00293 
00294     prevState_ = currState_;
00295 
00296 }
00297 
00298 float QEI::getVelocity()
00299 {
00300      int ct = currTime_;
00301      int pt = prevTime_;
00302      
00303      if(prevDirection_ != currDirection_ || pt == ct) {
00304         return 0;    
00305      }
00306      double dt = (currTime_ - prevTime_)/1000000.;
00307      return ( (float) -currDirection_/dt );    
00308 }
00309 
00310 void QEI::index(void) {
00311 
00312     revolutions_++;
00313 
00314 }