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

Revision:
2:c0b87b11b9cd
Parent:
1:ac6b7b1bf6c5
--- a/QEIx4.cpp	Tue Sep 30 12:34:07 2014 +0000
+++ b/QEIx4.cpp	Wed Oct 01 10:23:21 2014 +0000
@@ -70,19 +70,26 @@
 
 QEIx4::QEIx4 ( PinName pinA, PinName pinB, PinName pinI, EMODE eMode ) : _pinA(pinA), _pinB(pinB), _pinI(pinI)
 {
-    _eMode = eMode;
-    _bZeroOnIndex = false;
-    _fPositionFactor = 1.0;
-
-    // synchronize state machine
-    _counter = 0;
-    _state = 0;
-
+    // prepare input pins
     _pinA.mode(PullUp);
     _pinB.mode(PullUp);
     if(pinI!=NC)
         _pinI.mode(PullUp);
 
+    _eMode = eMode;
+    _bIndexTrigger = false;
+    _fPositionFactor = 1.0;
+    _fSpeedFactor = 1.0;
+    _counter = 0;
+    _state = 0;
+    _nSpeedLastTimer = 0;
+    _nSpeedAvrTimeSum = 0;
+    _nSpeedAvrTimeCount = -1;
+    _fLastSpeed = 0;
+    _nSpeedTimeoutMax = 10;
+    _nSpeedTimeoutCount = 0;
+
+    // synchronize state machine
     if ( _eMode & IRQ ) {
         _pinA.fall ( this, &QEIx4::ProcessISR );
         _pinA.rise ( this, &QEIx4::ProcessISR );
@@ -96,20 +103,11 @@
     ProcessISR ();
     _counter = 0;
 
+    // prepare for speed measurement
     if ( _eMode & SPEED ) {
         _SpeedTimer.reset();
         _SpeedTimer.start();
     }
-
-    _nSpeedLastTimer = 0;
-    _nSpeedAvrTimeSum = 0;
-    _nSpeedAvrTimeCount = -1;
-    _fSpeedFactor = 1.0f;
-    _fLastSpeed = 0;
-
-    _nSpeedTimeoutMax = 10;
-    _nSpeedTimeoutCount = 0;
-
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -157,6 +155,7 @@
 
 void QEIx4::ProcessISR ( void )
 {
+    int nLoopCounter=10;
     int pinA, pinB;
 
     do {
@@ -181,14 +180,8 @@
                 _counter--;
                 bCounterChange = true;
             }
-            if ( _bZeroOnIndex && _pinI != NC && _pinI == 1 ) {   // is index pin triggered?
-                _counter = 0;
-                _bZeroOnIndex = false;
-                CounterZero ();
-                bCounterChange = true;
-            }
 
-            if ( _eMode & IRQ_NO_JAMMING ) {   // need reconfiguration od interrupt edges?
+            if ( _eMode & IRQ_NO_JAMMING ) {   // need reconfiguration of interrupt edges?
                 switch ( _state & QEIx4_STATE ) {
                     case QEIx4_S0:
                         _pinB.rise ( NULL );
@@ -234,19 +227,21 @@
                 }
             }
 
+            if ( _bIndexTrigger && bCounterChange && _pinI != NC && _pinI == 1 ) {   // is index pin triggered?
+                _bIndexTrigger = false;
+                fPointerIndexTrigger.call(_counter);
+            }
+
             if ( bCounterChange ) {   // has counter changed?
-                CounterChange ();
                 fPointerCounterChange.call(_counter);
                 if ( _state & QEIx4_DIR )
                     fPointerDirectionChange.call(_counter);
             }
 
         }
-    } while ( pinA != _pinA || pinB != _pinB); // loop till stable input pins
+    } while (nLoopCounter-->0 && ( pinA != _pinA || pinB != _pinB)); // loop till stable input pins
 }
 
-//////////////////////////////////////////////////////////////////////////////////
-
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////