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
QEIx4.h
00001 /* 00002 * @author Jochen Krapf 00003 * parts by Andy Kirkham 00004 * 00005 * @section LICENSE 00006 * 00007 * Copyright (c) 2014 Jochen Krapf, MIT License 00008 * 00009 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00010 * and associated documentation files (the "Software"), to deal in the Software without restriction, 00011 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 00012 * sublicense, and/or sell 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 all copies or 00016 * substantial portions of the Software. 00017 * 00018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00019 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00020 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00021 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00022 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00023 * 00024 * @section DESCRIPTION 00025 * mbed QEI (quadrature encoder interface) library, for decoding AB signals from a rotary encoder 00026 * 00027 * Use cases: 00028 * - Rotary encoder in closed loop motor regulation 00029 * - Hand wheel 00030 * - Input device for motion control (MoCo) 00031 */ 00032 00033 #include "mbed.h" 00034 #include "FPointer_vi.h" 00035 00036 /** Quadrature Encoder Interface for Motion Control. 00037 * 00038 * A class to decode pulses on a rotary encoder with AB signals (quadrature encoder). 00039 * 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) 00040 * 00041 * In opposite to most common QEI implementation this is resistant to jitter and chatter on AB signals and motor vibrations. 00042 * When using interrupts (IRQ_NO_JAMMING-mode) only the needed edge and pin is activated to prevent jamming CPU time with unnecessary interrupts. 00043 * Whes reaching the next position the edge that triggerd this position (state) is ignored to aboid oscillating up/down counts. 00044 * 00045 * It can also be used in polling mode i.g. in idle routines if interrupts are not desired. 00046 * At this mode be sure that the sampling frequency is heigher than the maximum rotation speed (expeced counts per second) 00047 * 00048 * The internal state machine is based on a look up table (LUT) to minimize interrupt retention time and get all necessary flags at once. 00049 * 00050 * 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. 00051 * 00052 * The library is designed to support closed loop speed- and motion-controller for also slow and smooth motions like movie camera motion control. 00053 * 00054 * Example: 00055 * 00056 * @code 00057 #include "mbed.h" 00058 #include "QEIx4.h" 00059 00060 DigitalOut LEDalive(LED1); 00061 DigitalOut LEDzero(LED2); 00062 DigitalOut LEDup(LED4); 00063 DigitalOut LEDdown(LED3); 00064 00065 Timer t; // timer for polling 00066 00067 // ports for nxp LPC 1768 00068 QEIx4 qei1(p30, p29, p28, (QEIx4::EMODE)(QEIx4::IRQ | QEIx4::SPEED)); // QEI with index signal for zeroing 00069 QEIx4 qei2(p21, p22, NC, QEIx4::IRQ_NO_JAMMING); // QEI with AB signals only 00070 QEIx4 qei3(p25, p24, NC, QEIx4::POLLING); // QEI without interrups in polling mode 00071 00072 // The callback functions 00073 void myCounterChangeCallback(int value) 00074 { 00075 static int valueLast=-1; 00076 00077 if ( value > valueLast ) { 00078 LEDup = !LEDup; 00079 LEDdown = 0; 00080 } else { 00081 LEDdown = !LEDdown; 00082 LEDup = 0; 00083 } 00084 valueLast = value; 00085 } 00086 00087 void myIndexTriggerCallback(int value) 00088 { 00089 qei1 = 0; // reset counter 00090 LEDzero = 1; 00091 } 00092 00093 int main() 00094 { 00095 t.start(); 00096 00097 qei1.setIndexTrigger(true); // set the flag to zero counter on next index signal rises 00098 qei1.setSpeedFactor(1.0f); // factor to scale from Hz (edges pe second = 4 * CPS) to user units (1.0=Hz, 1/(4*CPR)=rps, 1/(60*4*CPR)=rpm, 360/(4*CPR)=°/s, ...) 00099 qei3.attachIndexTrigger(myIndexTriggerCallback); 00100 00101 qei3.attachCounterChange(myCounterChangeCallback); 00102 00103 while(1) { 00104 qei3.poll(); // poll manually without interrupt - sampling in this loop with about 2kHz 00105 00106 if ( t.read_ms() > 250 ) { // every quater second (4 Hz) 00107 t.reset(); 00108 t.start(); 00109 LEDalive = !LEDalive; 00110 00111 printf ( "\r\n%6d %6d %6d %10.3f", (int)qei1, (int)qei2, (int)qei3, (float)qei1.getSpeed() ); // print counter values 00112 } 00113 00114 wait_us(20); // for about 50kHz polling 00115 } 00116 } 00117 * @endcode 00118 */ 00119 class QEIx4 00120 { 00121 public: 00122 00123 typedef enum EMODE { 00124 POLLING = 0, 00125 IRQ = 1, 00126 IRQ_NO_JAMMING = 2, 00127 SPEED = 4, 00128 } EMODE; 00129 00130 /** constructor of QEIx4 object 00131 * 00132 * @param pinA Pin number of input/interrupt pin for encoder line A. All port pins are possible except p19 and p20 00133 * @param pinB Pin number of input/interrupt pin for encoder line B. All port pins are possible except p19 and p20 00134 * @param pinI Pin number of input pin for optional encoder index or reference switch. 00135 * @param eMode Flag to use interrups to detect changes on line A and B. For none interrupt use mode POLLING and call the function poll() frequently. For optional speed calculation the mode SPEED can be ored 00136 */ 00137 QEIx4 ( PinName pinA, PinName pinB, PinName pinI=NC, EMODE eMode=IRQ ); 00138 00139 /** destructor of QEIx4 object 00140 */ 00141 ~QEIx4(); 00142 00143 /** Gets the actual counter value. 00144 * 00145 * @return Actual counter value 00146 */ 00147 int read() { 00148 return _counter; 00149 } 00150 00151 /** Gets the actual counter value as int operator. 00152 * 00153 * @return Actual counter value as int operator 00154 */ 00155 operator int () { // int-Operator 00156 return _counter; 00157 } 00158 00159 /** Sets the counter value at actual encoder position to given value. 00160 * 00161 * @param Counter value 00162 */ 00163 void write ( int counter ) { 00164 _counter = counter; 00165 } 00166 00167 /** Sets the counter value at actual encoder position to given value as assign operator. 00168 * 00169 * @param Counter value 00170 */ 00171 int operator= ( int counter ) { // Assign-Operator 00172 write(counter); 00173 return counter; 00174 } 00175 00176 /** Polls the state machine manually and updates the counter value. 00177 */ 00178 void poll () { 00179 ProcessISR(); 00180 } 00181 00182 /** Sets the flag for zeroing on next high on index pin while AB lines triggers next counting. The trigger calls tha callback function in which the counter can be set to zero or the actual counter can be latched in for later offset calculation 00183 * 00184 * @param Flag for triggering. Set to 1 for call the attached callback. It is reseted after this call 00185 */ 00186 void setIndexTrigger ( bool bIndexTrigger ) { 00187 _bIndexTrigger = bIndexTrigger; 00188 } 00189 00190 /** attach - Overloaded attachment function. 00191 * 00192 * Attach a C type function pointer as the callback. 00193 * 00194 * Note, the callback function prototype must be:- 00195 * @code 00196 * void myCallbackFunction(int); 00197 * @endcode 00198 * @param A C function pointer to call. 00199 */ 00200 void attachCounterChange(void (*function)(int) = 0) { 00201 fPointerCounterChange.attach (function); 00202 } 00203 00204 /** attachCounterChange - Overloaded attachment function. 00205 * 00206 * Attach a C++ type object/method pointer as the callback. 00207 * 00208 * Note, the callback method prototype must be:- 00209 * @code 00210 * public: 00211 * static void myCallbackFunction(int); 00212 * @endcode 00213 * @param A C++ object pointer. 00214 * @param A C++ method within the object to call. 00215 */ 00216 template<class T> 00217 void attachCounterChange(T* item, void (T::*method)(int)) { 00218 fPointerCounterChange.attach( item, method); 00219 } 00220 00221 /** attachDirectionChange - Overloaded attachment function. 00222 * 00223 * Attach a C type function pointer as the callback. 00224 * 00225 * Note, the callback function prototype must be:- 00226 * @code 00227 * void myCallbackFunction(int); 00228 * @endcode 00229 * @param A C function pointer to call. 00230 */ 00231 void attachDirectionChange(void (*function)(int) = 0) { 00232 fPointerDirectionChange.attach (function); 00233 } 00234 00235 /** attachDirectionChange - Overloaded attachment function. 00236 * 00237 * Attach a C++ type object/method pointer as the callback. 00238 * 00239 * Note, the callback method prototype must be:- 00240 * @code 00241 * public: 00242 * static void myCallbackFunction(int); 00243 * @endcode 00244 * @param A C++ object pointer. 00245 * @param A C++ method within the object to call. 00246 */ 00247 template<class T> 00248 void attachDirectionChange(T* item, void (T::*method)(int)) { 00249 fPointerDirectionChange.attach( item, method); 00250 } 00251 00252 /** attachIndexTrigger - Overloaded attachment function. 00253 * 00254 * Attach a C type function pointer as the callback. 00255 * 00256 * Note, the callback function prototype must be:- 00257 * @code 00258 * void myCallbackFunction(int); 00259 * @endcode 00260 * @param A C function pointer to call. 00261 */ 00262 void attachIndexTrigger(void (*function)(int) = 0) { 00263 fPointerIndexTrigger.attach (function); 00264 } 00265 00266 /** attachIndexTrigger - Overloaded attachment function. 00267 * 00268 * Attach a C++ type object/method pointer as the callback. 00269 * 00270 * Note, the callback method prototype must be:- 00271 * @code 00272 * public: 00273 * static void myCallbackFunction(int); 00274 * @endcode 00275 * @param A C++ object pointer. 00276 * @param A C++ method within the object to call. 00277 */ 00278 template<class T> 00279 void attachIndexTrigger(T* item, void (T::*method)(int)) { 00280 fPointerIndexTrigger.attach( item, method); 00281 } 00282 00283 /** Sets the factor for the getter-functions to convert in another unit (1.0=Hz, 1/(4*CPR)=rps, 1/(60*4*CPR)=rpm, 360/(4*CPR)=°/s, ...) 00284 * 00285 * @param fSpeedFactor - factor to scale from Hz (edges per second = 4 * CPS) to user units 00286 */ 00287 void setSpeedFactor(float fSpeedFactor) { 00288 _fSpeedFactor = fSpeedFactor; 00289 } 00290 00291 /** Gets the actual speed as float value. The value is scales by the facor set by setPositionFactor() 00292 * 00293 * @return Actual encoder speed as float 00294 */ 00295 float getSpeed(); 00296 00297 /** Sets the factor for the getter-functions to convert in another unit (e.g. CPR (cycles per rotation) * 4.0 to get 1.0 for a full rotation) 00298 * 00299 * @param fPositionFactor Factor to scale from counts to user unit 00300 */ 00301 void setPositionFactor ( float fPositionFactor ) { 00302 _fPositionFactor = fPositionFactor; 00303 } 00304 00305 /** Gets the actual counter value as float value. The value is scales by the facor set by setSpeedFactor() 00306 * 00307 * @return Actual encoder position as float 00308 */ 00309 float getPosition () { 00310 return (float)_counter * _fPositionFactor; 00311 } 00312 00313 00314 protected: 00315 InterruptIn _pinA, _pinB; 00316 DigitalIn _pinI; 00317 FPointer_vi fPointerCounterChange; 00318 FPointer_vi fPointerDirectionChange; 00319 FPointer_vi fPointerIndexTrigger; 00320 00321 int _counter; 00322 short _state; 00323 short _eMode; 00324 bool _bIndexTrigger; 00325 00326 Timer _SpeedTimer; 00327 00328 unsigned int _nSpeedLastTimer; 00329 unsigned int _nSpeedTimeoutMax; 00330 unsigned int _nSpeedTimeoutCount; 00331 int _nSpeedAvrTimeSum; 00332 int _nSpeedAvrTimeCount; 00333 float _fLastSpeed; 00334 00335 void ProcessISR ( void ); 00336 void callback_timeout(); 00337 00338 float _fPositionFactor; 00339 float _fSpeedFactor; 00340 00341 private: 00342 static short _modeLUT[32]; 00343 };
Generated on Fri Jul 15 2022 02:24:32 by 1.7.2