Simple PID example for LabVIEW

Dependencies:   mbed

Revision:
0:e3b759ab4b5c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QEI.cpp	Mon Aug 02 18:53:02 2010 +0000
@@ -0,0 +1,217 @@
+//****************************************************************************/
+//@section LICENSE
+//
+//Copyright (c) 2010 ARM Limited
+//
+//Permission is hereby granted, free of charge, to any person obtaining a copy
+//of this software and associated documentation files (the "Software"), to deal
+//in the Software without restriction, including without limitation the rights
+//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//copies of the Software, and to permit persons to whom the Software is
+//furnished to do so, subject to the following conditions:
+//
+//The above copyright notice and this permission notice shall be included in
+//all copies or substantial portions of the Software.
+//
+//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//THE SOFTWARE.
+//****************************************************************************/
+//@section DESCRIPTION
+//
+// Quadrature Encoder Interface.
+//
+// A quadrature encoder consists of two code tracks on a disc which are 90
+// degrees out of phase. It can be used to determine how far a wheel has
+// rotated, relative to a known starting position.
+//
+// Only one code track changes at a time leading to a more robust system than
+// a single track, because any jitter around any edge won't cause a state
+// change as the other track will remain constant.
+//
+// Encoders can be a homebrew affair, consisting of infrared emitters/receivers
+// and paper code tracks consisting of alternating black and white sections;
+// alternatively, complete disk and PCB emitter/receiver encoder systems can
+// be bought, but the interface, regardless of implementation is the same.
+//
+//               +-----+     +-----+     +-----+
+// Channel A     |  ^  |     |     |     |     |
+//            ---+  ^  +-----+     +-----+     +-----
+//               ^  ^
+//               ^  +-----+     +-----+     +-----+
+// Channel B     ^  |     |     |     |     |     |
+//            ------+     +-----+     +-----+     +-----
+//               ^  ^
+//               ^  ^
+//               90deg
+//
+// This interface uses X4 encoding which calculates the pulse count based on
+// reading the current state after each rising and falling edge of either
+// channel.
+//
+//               +-----+     +-----+     +-----+
+// Channel A     |     |     |     |     |     |
+//            ---+     +-----+     +-----+     +-----
+//               ^     ^     ^     ^     ^
+//               ^  +-----+  ^  +-----+  ^  +-----+
+// Channel B     ^  |  ^  |  ^  |  ^  |  ^  |     |
+//            ------+  ^  +-----+  ^  +-----+     +--
+//               ^  ^  ^  ^  ^  ^  ^  ^  ^  ^
+//               ^  ^  ^  ^  ^  ^  ^  ^  ^  ^
+// Pulse count 0 1  2  3  4  5  6  7  8  9  ...
+//
+// An optional index channel can be used which determines when a full
+// revolution has occured.
+//
+// If a 4 pules per revolution encoder was used, the following would be
+// observed.
+//
+//               +-----+     +-----+     +-----+
+// Channel A     |     |     |     |     |     |
+//            ---+     +-----+     +-----+     +-----
+//               ^     ^     ^     ^     ^
+//               ^  +-----+  ^  +-----+  ^  +-----+
+// Channel B     ^  |  ^  |  ^  |  ^  |  ^  |     |
+//            ------+  ^  +-----+  ^  +-----+     +--
+//               ^  ^  ^  ^  ^  ^  ^  ^  ^  ^
+//               ^  ^  ^  ^  ^  ^  ^  ^  ^  ^
+//               ^  ^  ^  +--+  ^  ^  +--+  ^
+//               ^  ^  ^  |  |  ^  ^  |  |  ^
+// Index      ------------+  +--------+  +-----------
+//               ^  ^  ^  ^  ^  ^  ^  ^  ^  ^
+// Pulse count 0 1  2  3  4  5  6  7  8  9  ...
+// Rev.  count 0          1           2
+//
+// Rotational position in degrees can be calculated by:
+//
+// (pulse count / X * N) * 360
+//
+// Where X is the encoding type [in our case X=4], and N is the number of
+// pulses per revolution.
+//
+// Linear position can be calculated by:
+//
+// (pulse count / X * N) * (1 / PPI)
+//
+// Where X is encoding type [in our case X=4], N is the number of pulses per
+// revolution, and PPI is pulses per inch, or the equivalent for any other
+// unit of displacement. PPI can be calculated by taking the circumference
+// of the wheel or encoder disk and dividing it by the number of pulses per
+// revolution.
+//****************************************************************************/
+
+//****************************************************************************/
+// Includes
+//****************************************************************************/
+#include "QEI.h"
+
+QEI::QEI(PinName channelA, PinName channelB, PinName index, int pulsesPerRev) {
+
+    channelA_ = new InterruptIn(channelA);
+    channelB_ = new InterruptIn(channelB);
+    index_    = new InterruptIn(index);
+
+    pulses_       = 0;
+    revolutions_  = 0;
+    pulsesPerRev_ = pulsesPerRev;
+
+    //Workout what the current state is.
+    int chanA = channelA_->read();
+    int chanB = channelB_->read();
+
+    //2-bit state.
+    currState_ = (chanA << 1) | (chanB);
+    prevState_ = currState_;
+
+    channelA_->rise(this, &QEI::encode);
+    channelA_->fall(this, &QEI::encode);
+    channelB_->rise(this, &QEI::encode);
+    channelB_->fall(this, &QEI::encode);
+    //Index is optional.
+    if (index !=  NC) {
+        index_->rise(this, &QEI::index);
+    }
+
+}
+
+void QEI::reset(void) {
+
+    pulses_      = 0;
+    revolutions_ = 0;
+
+}
+
+int QEI::getCurrentState(void) {
+
+    return currState_;
+
+}
+
+int QEI::getPulses(void) {
+
+    return pulses_;
+
+}
+
+// There are four possible states for a quadrature encoder which correspond to
+// 2-bit gray code.
+//
+// A state change is only valid if of only one bit has changed.
+// A state change is invalid if both bits have changed.
+//
+// Clockwise Rotation ->
+//
+//    00 01 11 10 00
+//
+// <- Counter Clockwise Rotation
+//
+// If we observe any valid state changes going from left to right, we have
+// moved one pulse clockwise [we will consider this "backward" or "negative"].
+//
+// If we observe any valid state changes going from right to left we have
+// moved one pulse counter clockwise [we will consider this "forward" or
+// "positive"].
+//
+// We might enter an invalid state for a number of reasons which are hard to
+// predict - if this is the case, it is generally safe to ignore it, update
+// the state and carry on, with the error correcting itself shortly after.
+void QEI::encode(void) {
+
+    int change = 0;
+    int chanA  = channelA_->read();
+    int chanB  = channelB_->read();
+
+    //2-bit state.
+    currState_ = (chanA << 1) | (chanB);
+
+    //Entered an invalid state, or no change.
+    if ((currState_ ^ prevState_) == INVALID || currState_ == prevState_) {
+        //Even if the state was invalid, it will eventually
+        //correct itself if we simply update the state.
+        prevState_ = currState_;
+    }
+    //Entered a valid state.
+    else {
+        //2 bit state. Right hand bit of prev XOR left hand bit of current
+        //gives 0 if clockwise rotation and 1 if counter clockwise rotation.
+        change = (prevState_ & PREV_MASK) ^ ((currState_ & CURR_MASK) >> 1);
+
+        if (change == 0) {
+            change = -1;
+        }
+
+        pulses_ -= change;
+        prevState_ = currState_;
+    }
+
+}
+
+void QEI::index(void) {
+
+    revolutions_++;
+
+}