Quadrature Encoder Interface for motion control with resistance to jitter and chatter on AB signals and motor vibrations

Dependents:   QEIx4_Example realtimeMM_V3 realtimeMM_V3

Quadrature Encoder Interface for Motion Control.

A class to decode pulses on a rotary encoder with AB signals (quadrature encoder). It uses all 4 edges of the AB signals to increase the counter resolution 4 times of cycles per rotation/revolution (CPR) (e.g. an encoder with 500 CPR get 2000 counts per rotation)

In opposite to most common QEI implementation this is resistant to jitter and chatter on AB signals and motor vibrations. When using interrupts (IRQ_NO_JAMMING-mode) only the needed edge and pin is activated to prevent jamming CPU time with unnecessary interrupts. Whes reaching the next position the edge that triggerd this position (state) is ignored to aboid oscillating up/down counts.

It can also be used in polling mode i.g. in idle routines if interrupts are not desired. At this mode be sure that the sampling frequency is heigher than the maximum rotation speed (expeced counts per second)

The internal state machine is based on a look up table (LUT) to minimize interrupt retention time and get all necessary flags at once.

Additional the rotation speed of the encoder can be measured. The algorithm is based on the measuring time between the edges to get a very precise speed at very slow rotation.

The library is designed to support closed loop speed- and motion-controller for also slow and smooth motions like movie camera motion control.

Quadrature Encoder Signals:

/media/uploads/jocis/qeix4.png

(+) Count UP; (-) Count DOWN

Committer:
jocis
Date:
Tue Sep 02 18:23:36 2014 +0000
Revision:
0:46b8d5680f66
Child:
1:ac6b7b1bf6c5
Added documentation

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jocis 0:46b8d5680f66 1 /*
jocis 0:46b8d5680f66 2 * @author Jochen Krapf
jocis 0:46b8d5680f66 3 *
jocis 0:46b8d5680f66 4 * @section LICENSE
jocis 0:46b8d5680f66 5 *
jocis 0:46b8d5680f66 6 * Copyright (c) 2012 Jochen Krapf, MIT License
jocis 0:46b8d5680f66 7 *
jocis 0:46b8d5680f66 8 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
jocis 0:46b8d5680f66 9 * and associated documentation files (the "Software"), to deal in the Software without restriction,
jocis 0:46b8d5680f66 10 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
jocis 0:46b8d5680f66 11 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
jocis 0:46b8d5680f66 12 * furnished to do so, subject to the following conditions:
jocis 0:46b8d5680f66 13 *
jocis 0:46b8d5680f66 14 * The above copyright notice and this permission notice shall be included in all copies or
jocis 0:46b8d5680f66 15 * substantial portions of the Software.
jocis 0:46b8d5680f66 16 *
jocis 0:46b8d5680f66 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
jocis 0:46b8d5680f66 18 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
jocis 0:46b8d5680f66 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
jocis 0:46b8d5680f66 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
jocis 0:46b8d5680f66 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
jocis 0:46b8d5680f66 22 *
jocis 0:46b8d5680f66 23 * @section DESCRIPTION
jocis 0:46b8d5680f66 24 * mbed QEI (quadrature encoder interface) library, for decoding AB signals from a rotary encoder
jocis 0:46b8d5680f66 25 *
jocis 0:46b8d5680f66 26 * Use cases:
jocis 0:46b8d5680f66 27 * - Rotary encoder in closed loop motor regulation
jocis 0:46b8d5680f66 28 * - Hand wheel
jocis 0:46b8d5680f66 29 * - Input device for motion control (MoCo)
jocis 0:46b8d5680f66 30 */
jocis 0:46b8d5680f66 31
jocis 0:46b8d5680f66 32 #include "mbed.h"
jocis 0:46b8d5680f66 33
jocis 0:46b8d5680f66 34
jocis 0:46b8d5680f66 35 /** Quadrature encoder interface. A class to decode pulses on a AB rotary encoder. It uses all 4 edges on AB signals to increase resolution 4 times.
jocis 0:46b8d5680f66 36 *
jocis 0:46b8d5680f66 37 * In opposite to commen QEI implementation this is resistent to jitter on AB signals and motor vibration. When using interrupts only the needed edge and pin is activated to prevent jamming CPU time with interrups.
jocis 0:46b8d5680f66 38 *
jocis 0:46b8d5680f66 39 * It can also be used in polling mode i.g. in idle routines.
jocis 0:46b8d5680f66 40 *
jocis 0:46b8d5680f66 41 * Example:
jocis 0:46b8d5680f66 42 *
jocis 0:46b8d5680f66 43 * @code
jocis 0:46b8d5680f66 44 #include "mbed.h"
jocis 0:46b8d5680f66 45 #include "QEIx4.h"
jocis 0:46b8d5680f66 46
jocis 0:46b8d5680f66 47 DigitalOut myled(LED1);
jocis 0:46b8d5680f66 48 Timer t;
jocis 0:46b8d5680f66 49
jocis 0:46b8d5680f66 50 // ports for nxp LPC 1768
jocis 0:46b8d5680f66 51 QEIx4 qei1(p30, p29, p28); // QEI with index signal for zeroing
jocis 0:46b8d5680f66 52 QEIx4 qei2(p27, p26, NC); // QEI only with AB signals
jocis 0:46b8d5680f66 53 QEIx4 qei3(p25, p24, NC, false); // QEI without interrups for polling mode
jocis 0:46b8d5680f66 54
jocis 0:46b8d5680f66 55 int main() {
jocis 0:46b8d5680f66 56 t.start();
jocis 0:46b8d5680f66 57
jocis 0:46b8d5680f66 58 qei1.SetZeroOnIndex(true); // Set the flag to zero counter on next index signal rises
jocis 0:46b8d5680f66 59
jocis 0:46b8d5680f66 60 while(1)
jocis 0:46b8d5680f66 61 {
jocis 0:46b8d5680f66 62 qei3.poll(); // poll manually without interrupt - sampling in this loop with about 2kHz
jocis 0:46b8d5680f66 63
jocis 0:46b8d5680f66 64 if ( t.read_ms() > 500 ) // every half second
jocis 0:46b8d5680f66 65 {
jocis 0:46b8d5680f66 66 t.reset();
jocis 0:46b8d5680f66 67 t.start();
jocis 0:46b8d5680f66 68 myled = !myled;
jocis 0:46b8d5680f66 69
jocis 0:46b8d5680f66 70 printf ( "\r\n%6d %6d %6d", (int)qei1, (int)qei2, (int)qei3 ); // print counter values
jocis 0:46b8d5680f66 71 }
jocis 0:46b8d5680f66 72
jocis 0:46b8d5680f66 73 wait_us(500); // for about 2kHz
jocis 0:46b8d5680f66 74 }
jocis 0:46b8d5680f66 75 }
jocis 0:46b8d5680f66 76 * @endcode
jocis 0:46b8d5680f66 77 */
jocis 0:46b8d5680f66 78 class QEIx4 {
jocis 0:46b8d5680f66 79 public:
jocis 0:46b8d5680f66 80
jocis 0:46b8d5680f66 81 /** constructor of QEIx4 object
jocis 0:46b8d5680f66 82 *
jocis 0:46b8d5680f66 83 * @param pinA Pin number of input/interrupt pin for encoder line A. All port pins are possible except p19 and p20
jocis 0:46b8d5680f66 84 * @param pinB Pin number of input/interrupt pin for encoder line B. All port pins are possible except p19 and p20
jocis 0:46b8d5680f66 85 * @param pinI Pin number of input pin for optional encoder index or reference switch.
jocis 0:46b8d5680f66 86 * @param bUseIRQ Flag to use interrups to detect changes on line A and B. If FALSE the function poll() has to be called frequently
jocis 0:46b8d5680f66 87 */
jocis 0:46b8d5680f66 88 QEIx4 ( PinName pinA, PinName pinB, PinName pinI=NC, bool bUseIRQ=true );
jocis 0:46b8d5680f66 89
jocis 0:46b8d5680f66 90 /** destructor of QEIx4 object
jocis 0:46b8d5680f66 91 */
jocis 0:46b8d5680f66 92 ~QEIx4();
jocis 0:46b8d5680f66 93
jocis 0:46b8d5680f66 94 /** Gets the actual counter value.
jocis 0:46b8d5680f66 95 *
jocis 0:46b8d5680f66 96 * @return Actual counter value
jocis 0:46b8d5680f66 97 */
jocis 0:46b8d5680f66 98 int read()
jocis 0:46b8d5680f66 99 { return _counter; }
jocis 0:46b8d5680f66 100
jocis 0:46b8d5680f66 101 /** Gets the actual counter value as int operator.
jocis 0:46b8d5680f66 102 *
jocis 0:46b8d5680f66 103 * @return Actual counter value as int operator
jocis 0:46b8d5680f66 104 */
jocis 0:46b8d5680f66 105 operator int () // int-Operator
jocis 0:46b8d5680f66 106 { return _counter; }
jocis 0:46b8d5680f66 107
jocis 0:46b8d5680f66 108 /** Sets the counter value at actual encoder position to given value.
jocis 0:46b8d5680f66 109 *
jocis 0:46b8d5680f66 110 * @param Counter value
jocis 0:46b8d5680f66 111 */
jocis 0:46b8d5680f66 112 void write ( int counter )
jocis 0:46b8d5680f66 113 { _counter = counter; }
jocis 0:46b8d5680f66 114
jocis 0:46b8d5680f66 115 /** Sets the counter value at actual encoder position to given value as assign operator.
jocis 0:46b8d5680f66 116 *
jocis 0:46b8d5680f66 117 * @param Counter value
jocis 0:46b8d5680f66 118 */
jocis 0:46b8d5680f66 119 int operator= ( int counter ) // Assign-Operator
jocis 0:46b8d5680f66 120 { write(counter); return counter; }
jocis 0:46b8d5680f66 121
jocis 0:46b8d5680f66 122 /** Polls the state machine manually and updates the counter value.
jocis 0:46b8d5680f66 123 */
jocis 0:46b8d5680f66 124 void poll ()
jocis 0:46b8d5680f66 125 { ProcessISR(); }
jocis 0:46b8d5680f66 126
jocis 0:46b8d5680f66 127 /** Gets the actual counter value as float value. A value of 1.0 is one rotation
jocis 0:46b8d5680f66 128 *
jocis 0:46b8d5680f66 129 * @return Actual encoder position as float
jocis 0:46b8d5680f66 130 */
jocis 0:46b8d5680f66 131 float GetPosition ()
jocis 0:46b8d5680f66 132 { return (float)_counter / (_cpr*4.0); }
jocis 0:46b8d5680f66 133
jocis 0:46b8d5680f66 134 /** Sets the number of cycles per rotation (CPR) for function GetPosition().
jocis 0:46b8d5680f66 135 *
jocis 0:46b8d5680f66 136 * @param Cycles per rotation for a full rotation
jocis 0:46b8d5680f66 137 */
jocis 0:46b8d5680f66 138 void SetCPR ( int cpr )
jocis 0:46b8d5680f66 139 { _cpr = cpr; }
jocis 0:46b8d5680f66 140
jocis 0:46b8d5680f66 141 /** Sets the flag for zeroing on next high on index pin while AB lines triggers next counting. The trigger forces the counter set to zero
jocis 0:46b8d5680f66 142 *
jocis 0:46b8d5680f66 143 * @param Flag for triggering. Is reset on next zeroing
jocis 0:46b8d5680f66 144 */
jocis 0:46b8d5680f66 145 void SetZeroOnIndex ( bool bZeroOnIndex )
jocis 0:46b8d5680f66 146 { _bZeroOnIndex = bZeroOnIndex; }
jocis 0:46b8d5680f66 147
jocis 0:46b8d5680f66 148
jocis 0:46b8d5680f66 149 /** Callback in derived classes to act on counter change
jocis 0:46b8d5680f66 150 */
jocis 0:46b8d5680f66 151 virtual void CounterChange ( void ) {};
jocis 0:46b8d5680f66 152
jocis 0:46b8d5680f66 153 /** Callback in derived classes to act on zeroing trigger
jocis 0:46b8d5680f66 154 */
jocis 0:46b8d5680f66 155 virtual void CounterZero ( void ) {};
jocis 0:46b8d5680f66 156
jocis 0:46b8d5680f66 157 protected:
jocis 0:46b8d5680f66 158 InterruptIn _pinA, _pinB;
jocis 0:46b8d5680f66 159 DigitalIn _pinI;
jocis 0:46b8d5680f66 160 int _counter;
jocis 0:46b8d5680f66 161 short _mode;
jocis 0:46b8d5680f66 162 int _cpr;
jocis 0:46b8d5680f66 163 bool _bUseIRQ;
jocis 0:46b8d5680f66 164 bool _bZeroOnIndex;
jocis 0:46b8d5680f66 165
jocis 0:46b8d5680f66 166 void ProcessISR ( void );
jocis 0:46b8d5680f66 167
jocis 0:46b8d5680f66 168 private:
jocis 0:46b8d5680f66 169 static short _modeLUT[16];
jocis 0:46b8d5680f66 170 };