Alison Bartsch / Mbed 2 deprecated FreeFlyerROS

Dependencies:   mbed ros_lib_kinetic

Committer:
Knillinux
Date:
Tue Feb 14 05:12:54 2017 +0000
Revision:
0:dd126a1080d3
Child:
1:40bdbe1a93b7
test

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Knillinux 0:dd126a1080d3 1 /**
Knillinux 0:dd126a1080d3 2 * @author Aaron Berk
Knillinux 0:dd126a1080d3 3 *
Knillinux 0:dd126a1080d3 4 * @section LICENSE
Knillinux 0:dd126a1080d3 5 *
Knillinux 0:dd126a1080d3 6 * Copyright (c) 2010 ARM Limited
Knillinux 0:dd126a1080d3 7 *
Knillinux 0:dd126a1080d3 8 * Permission is hereby granted, free of charge, to any person obtaining a copy
Knillinux 0:dd126a1080d3 9 * of this software and associated documentation files (the "Software"), to deal
Knillinux 0:dd126a1080d3 10 * in the Software without restriction, including without limitation the rights
Knillinux 0:dd126a1080d3 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Knillinux 0:dd126a1080d3 12 * copies of the Software, and to permit persons to whom the Software is
Knillinux 0:dd126a1080d3 13 * furnished to do so, subject to the following conditions:
Knillinux 0:dd126a1080d3 14 *
Knillinux 0:dd126a1080d3 15 * The above copyright notice and this permission notice shall be included in
Knillinux 0:dd126a1080d3 16 * all copies or substantial portions of the Software.
Knillinux 0:dd126a1080d3 17 *
Knillinux 0:dd126a1080d3 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Knillinux 0:dd126a1080d3 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Knillinux 0:dd126a1080d3 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Knillinux 0:dd126a1080d3 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Knillinux 0:dd126a1080d3 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Knillinux 0:dd126a1080d3 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Knillinux 0:dd126a1080d3 24 * THE SOFTWARE.
Knillinux 0:dd126a1080d3 25 *
Knillinux 0:dd126a1080d3 26 * @section DESCRIPTION
Knillinux 0:dd126a1080d3 27 *
Knillinux 0:dd126a1080d3 28 * Quadrature Encoder Interface.
Knillinux 0:dd126a1080d3 29 *
Knillinux 0:dd126a1080d3 30 * A quadrature encoder consists of two code tracks on a disc which are 90
Knillinux 0:dd126a1080d3 31 * degrees out of phase. It can be used to determine how far a wheel has
Knillinux 0:dd126a1080d3 32 * rotated, relative to a known starting position.
Knillinux 0:dd126a1080d3 33 *
Knillinux 0:dd126a1080d3 34 * Only one code track changes at a time leading to a more robust system than
Knillinux 0:dd126a1080d3 35 * a single track, because any jitter around any edge won't cause a state
Knillinux 0:dd126a1080d3 36 * change as the other track will remain constant.
Knillinux 0:dd126a1080d3 37 *
Knillinux 0:dd126a1080d3 38 * Encoders can be a homebrew affair, consisting of infrared emitters/receivers
Knillinux 0:dd126a1080d3 39 * and paper code tracks consisting of alternating black and white sections;
Knillinux 0:dd126a1080d3 40 * alternatively, complete disk and PCB emitter/receiver encoder systems can
Knillinux 0:dd126a1080d3 41 * be bought, but the interface, regardless of implementation is the same.
Knillinux 0:dd126a1080d3 42 *
Knillinux 0:dd126a1080d3 43 * +-----+ +-----+ +-----+
Knillinux 0:dd126a1080d3 44 * Channel A | ^ | | | | |
Knillinux 0:dd126a1080d3 45 * ---+ ^ +-----+ +-----+ +-----
Knillinux 0:dd126a1080d3 46 * ^ ^
Knillinux 0:dd126a1080d3 47 * ^ +-----+ +-----+ +-----+
Knillinux 0:dd126a1080d3 48 * Channel B ^ | | | | | |
Knillinux 0:dd126a1080d3 49 * ------+ +-----+ +-----+ +-----
Knillinux 0:dd126a1080d3 50 * ^ ^
Knillinux 0:dd126a1080d3 51 * ^ ^
Knillinux 0:dd126a1080d3 52 * 90deg
Knillinux 0:dd126a1080d3 53 *
Knillinux 0:dd126a1080d3 54 * The interface uses X2 encoding by default which calculates the pulse count
Knillinux 0:dd126a1080d3 55 * based on reading the current state after each rising and falling edge of
Knillinux 0:dd126a1080d3 56 * channel A.
Knillinux 0:dd126a1080d3 57 *
Knillinux 0:dd126a1080d3 58 * +-----+ +-----+ +-----+
Knillinux 0:dd126a1080d3 59 * Channel A | | | | | |
Knillinux 0:dd126a1080d3 60 * ---+ +-----+ +-----+ +-----
Knillinux 0:dd126a1080d3 61 * ^ ^ ^ ^ ^
Knillinux 0:dd126a1080d3 62 * ^ +-----+ ^ +-----+ ^ +-----+
Knillinux 0:dd126a1080d3 63 * Channel B ^ | ^ | ^ | ^ | ^ | |
Knillinux 0:dd126a1080d3 64 * ------+ ^ +-----+ ^ +-----+ +--
Knillinux 0:dd126a1080d3 65 * ^ ^ ^ ^ ^
Knillinux 0:dd126a1080d3 66 * ^ ^ ^ ^ ^
Knillinux 0:dd126a1080d3 67 * Pulse count 0 1 2 3 4 5 ...
Knillinux 0:dd126a1080d3 68 *
Knillinux 0:dd126a1080d3 69 * This interface can also use X4 encoding which calculates the pulse count
Knillinux 0:dd126a1080d3 70 * based on reading the current state after each rising and falling edge of
Knillinux 0:dd126a1080d3 71 * either channel.
Knillinux 0:dd126a1080d3 72 *
Knillinux 0:dd126a1080d3 73 * +-----+ +-----+ +-----+
Knillinux 0:dd126a1080d3 74 * Channel A | | | | | |
Knillinux 0:dd126a1080d3 75 * ---+ +-----+ +-----+ +-----
Knillinux 0:dd126a1080d3 76 * ^ ^ ^ ^ ^
Knillinux 0:dd126a1080d3 77 * ^ +-----+ ^ +-----+ ^ +-----+
Knillinux 0:dd126a1080d3 78 * Channel B ^ | ^ | ^ | ^ | ^ | |
Knillinux 0:dd126a1080d3 79 * ------+ ^ +-----+ ^ +-----+ +--
Knillinux 0:dd126a1080d3 80 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
Knillinux 0:dd126a1080d3 81 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
Knillinux 0:dd126a1080d3 82 * Pulse count 0 1 2 3 4 5 6 7 8 9 ...
Knillinux 0:dd126a1080d3 83 *
Knillinux 0:dd126a1080d3 84 * It defaults
Knillinux 0:dd126a1080d3 85 *
Knillinux 0:dd126a1080d3 86 * An optional index channel can be used which determines when a full
Knillinux 0:dd126a1080d3 87 * revolution has occured.
Knillinux 0:dd126a1080d3 88 *
Knillinux 0:dd126a1080d3 89 * If a 4 pules per revolution encoder was used, with X4 encoding,
Knillinux 0:dd126a1080d3 90 * the following would be observed.
Knillinux 0:dd126a1080d3 91 *
Knillinux 0:dd126a1080d3 92 * +-----+ +-----+ +-----+
Knillinux 0:dd126a1080d3 93 * Channel A | | | | | |
Knillinux 0:dd126a1080d3 94 * ---+ +-----+ +-----+ +-----
Knillinux 0:dd126a1080d3 95 * ^ ^ ^ ^ ^
Knillinux 0:dd126a1080d3 96 * ^ +-----+ ^ +-----+ ^ +-----+
Knillinux 0:dd126a1080d3 97 * Channel B ^ | ^ | ^ | ^ | ^ | |
Knillinux 0:dd126a1080d3 98 * ------+ ^ +-----+ ^ +-----+ +--
Knillinux 0:dd126a1080d3 99 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
Knillinux 0:dd126a1080d3 100 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
Knillinux 0:dd126a1080d3 101 * ^ ^ ^ +--+ ^ ^ +--+ ^
Knillinux 0:dd126a1080d3 102 * ^ ^ ^ | | ^ ^ | | ^
Knillinux 0:dd126a1080d3 103 * Index ------------+ +--------+ +-----------
Knillinux 0:dd126a1080d3 104 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
Knillinux 0:dd126a1080d3 105 * Pulse count 0 1 2 3 4 5 6 7 8 9 ...
Knillinux 0:dd126a1080d3 106 * Rev. count 0 1 2
Knillinux 0:dd126a1080d3 107 *
Knillinux 0:dd126a1080d3 108 * Rotational position in degrees can be calculated by:
Knillinux 0:dd126a1080d3 109 *
Knillinux 0:dd126a1080d3 110 * (pulse count / X * N) * 360
Knillinux 0:dd126a1080d3 111 *
Knillinux 0:dd126a1080d3 112 * Where X is the encoding type [e.g. X4 encoding => X=4], and N is the number
Knillinux 0:dd126a1080d3 113 * of pulses per revolution.
Knillinux 0:dd126a1080d3 114 *
Knillinux 0:dd126a1080d3 115 * Linear position can be calculated by:
Knillinux 0:dd126a1080d3 116 *
Knillinux 0:dd126a1080d3 117 * (pulse count / X * N) * (1 / PPI)
Knillinux 0:dd126a1080d3 118 *
Knillinux 0:dd126a1080d3 119 * Where X is encoding type [e.g. X4 encoding => X=44], N is the number of
Knillinux 0:dd126a1080d3 120 * pulses per revolution, and PPI is pulses per inch, or the equivalent for
Knillinux 0:dd126a1080d3 121 * any other unit of displacement. PPI can be calculated by taking the
Knillinux 0:dd126a1080d3 122 * circumference of the wheel or encoder disk and dividing it by the number
Knillinux 0:dd126a1080d3 123 * of pulses per revolution.
Knillinux 0:dd126a1080d3 124 */
Knillinux 0:dd126a1080d3 125
Knillinux 0:dd126a1080d3 126 /**
Knillinux 0:dd126a1080d3 127 * Includes
Knillinux 0:dd126a1080d3 128 */
Knillinux 0:dd126a1080d3 129 #include "QEI.h"
Knillinux 0:dd126a1080d3 130
Knillinux 0:dd126a1080d3 131 QEI::QEI(PinName channelA,
Knillinux 0:dd126a1080d3 132 PinName channelB,
Knillinux 0:dd126a1080d3 133 PinName index,
Knillinux 0:dd126a1080d3 134 int pulsesPerRev,
Knillinux 0:dd126a1080d3 135 int pulsesPerSpeedMeas,
Knillinux 0:dd126a1080d3 136 Encoding encoding) : channelA_(channelA), channelB_(channelB),
Knillinux 0:dd126a1080d3 137 index_(index) {
Knillinux 0:dd126a1080d3 138
Knillinux 0:dd126a1080d3 139 pulses_ = 0;
Knillinux 0:dd126a1080d3 140 revolutions_ = 0;
Knillinux 0:dd126a1080d3 141 pulsesPerRev_ = pulsesPerRev;
Knillinux 0:dd126a1080d3 142 pulsesPerSpeedMeas_ = pulsesPerSpeedMeas;
Knillinux 0:dd126a1080d3 143 encoding_ = encoding;
Knillinux 0:dd126a1080d3 144
Knillinux 0:dd126a1080d3 145 //Workout what the current state is.
Knillinux 0:dd126a1080d3 146 int chanA = channelA_.read();
Knillinux 0:dd126a1080d3 147 int chanB = channelB_.read();
Knillinux 0:dd126a1080d3 148
Knillinux 0:dd126a1080d3 149 //2-bit state.
Knillinux 0:dd126a1080d3 150 currState_ = (chanA << 1) | (chanB);
Knillinux 0:dd126a1080d3 151 prevState_ = currState_;
Knillinux 0:dd126a1080d3 152
Knillinux 0:dd126a1080d3 153 timer.reset();
Knillinux 0:dd126a1080d3 154 timer.start();
Knillinux 0:dd126a1080d3 155
Knillinux 0:dd126a1080d3 156 //X2 encoding uses interrupts on only channel A.
Knillinux 0:dd126a1080d3 157 //X4 encoding uses interrupts on channel A,
Knillinux 0:dd126a1080d3 158 //and on channel B.
Knillinux 0:dd126a1080d3 159 channelA_.rise(this, &QEI::encode);
Knillinux 0:dd126a1080d3 160 channelA_.fall(this, &QEI::encode);
Knillinux 0:dd126a1080d3 161
Knillinux 0:dd126a1080d3 162 //If we're using X4 encoding, then attach interrupts to channel B too.
Knillinux 0:dd126a1080d3 163 if (encoding == X4_ENCODING) {
Knillinux 0:dd126a1080d3 164 channelB_.rise(this, &QEI::encode);
Knillinux 0:dd126a1080d3 165 channelB_.fall(this, &QEI::encode);
Knillinux 0:dd126a1080d3 166 }
Knillinux 0:dd126a1080d3 167 //Index is optional.
Knillinux 0:dd126a1080d3 168 if (index != NC) {
Knillinux 0:dd126a1080d3 169 index_.rise(this, &QEI::index);
Knillinux 0:dd126a1080d3 170 }
Knillinux 0:dd126a1080d3 171
Knillinux 0:dd126a1080d3 172 }
Knillinux 0:dd126a1080d3 173
Knillinux 0:dd126a1080d3 174 void QEI::reset(void) {
Knillinux 0:dd126a1080d3 175
Knillinux 0:dd126a1080d3 176 pulses_ = 0;
Knillinux 0:dd126a1080d3 177 revolutions_ = 0;
Knillinux 0:dd126a1080d3 178 timer.reset();
Knillinux 0:dd126a1080d3 179 timer.start();
Knillinux 0:dd126a1080d3 180 }
Knillinux 0:dd126a1080d3 181
Knillinux 0:dd126a1080d3 182 int QEI::getCurrentState(void) {
Knillinux 0:dd126a1080d3 183
Knillinux 0:dd126a1080d3 184 return currState_;
Knillinux 0:dd126a1080d3 185
Knillinux 0:dd126a1080d3 186 }
Knillinux 0:dd126a1080d3 187
Knillinux 0:dd126a1080d3 188 int QEI::getPulses(void) {
Knillinux 0:dd126a1080d3 189
Knillinux 0:dd126a1080d3 190 return pulses_;
Knillinux 0:dd126a1080d3 191
Knillinux 0:dd126a1080d3 192 }
Knillinux 0:dd126a1080d3 193
Knillinux 0:dd126a1080d3 194 float QEI::getSpeed(void) {
Knillinux 0:dd126a1080d3 195
Knillinux 0:dd126a1080d3 196 return speed_;
Knillinux 0:dd126a1080d3 197
Knillinux 0:dd126a1080d3 198 }
Knillinux 0:dd126a1080d3 199
Knillinux 0:dd126a1080d3 200 int QEI::getRevolutions(void) {
Knillinux 0:dd126a1080d3 201
Knillinux 0:dd126a1080d3 202 return revolutions_;
Knillinux 0:dd126a1080d3 203
Knillinux 0:dd126a1080d3 204 }
Knillinux 0:dd126a1080d3 205
Knillinux 0:dd126a1080d3 206 // +-------------+
Knillinux 0:dd126a1080d3 207 // | X2 Encoding |
Knillinux 0:dd126a1080d3 208 // +-------------+
Knillinux 0:dd126a1080d3 209 //
Knillinux 0:dd126a1080d3 210 // When observing states two patterns will appear:
Knillinux 0:dd126a1080d3 211 //
Knillinux 0:dd126a1080d3 212 // Counter clockwise rotation:
Knillinux 0:dd126a1080d3 213 //
Knillinux 0:dd126a1080d3 214 // 10 -> 01 -> 10 -> 01 -> ...
Knillinux 0:dd126a1080d3 215 //
Knillinux 0:dd126a1080d3 216 // Clockwise rotation:
Knillinux 0:dd126a1080d3 217 //
Knillinux 0:dd126a1080d3 218 // 11 -> 00 -> 11 -> 00 -> ...
Knillinux 0:dd126a1080d3 219 //
Knillinux 0:dd126a1080d3 220 // We consider counter clockwise rotation to be "forward" and
Knillinux 0:dd126a1080d3 221 // counter clockwise to be "backward". Therefore pulse count will increase
Knillinux 0:dd126a1080d3 222 // during counter clockwise rotation and decrease during clockwise rotation.
Knillinux 0:dd126a1080d3 223 //
Knillinux 0:dd126a1080d3 224 // +-------------+
Knillinux 0:dd126a1080d3 225 // | X4 Encoding |
Knillinux 0:dd126a1080d3 226 // +-------------+
Knillinux 0:dd126a1080d3 227 //
Knillinux 0:dd126a1080d3 228 // There are four possible states for a quadrature encoder which correspond to
Knillinux 0:dd126a1080d3 229 // 2-bit gray code.
Knillinux 0:dd126a1080d3 230 //
Knillinux 0:dd126a1080d3 231 // A state change is only valid if of only one bit has changed.
Knillinux 0:dd126a1080d3 232 // A state change is invalid if both bits have changed.
Knillinux 0:dd126a1080d3 233 //
Knillinux 0:dd126a1080d3 234 // Clockwise Rotation ->
Knillinux 0:dd126a1080d3 235 //
Knillinux 0:dd126a1080d3 236 // 00 01 11 10 00
Knillinux 0:dd126a1080d3 237 //
Knillinux 0:dd126a1080d3 238 // <- Counter Clockwise Rotation
Knillinux 0:dd126a1080d3 239 //
Knillinux 0:dd126a1080d3 240 // If we observe any valid state changes going from left to right, we have
Knillinux 0:dd126a1080d3 241 // moved one pulse clockwise [we will consider this "backward" or "negative"].
Knillinux 0:dd126a1080d3 242 //
Knillinux 0:dd126a1080d3 243 // If we observe any valid state changes going from right to left we have
Knillinux 0:dd126a1080d3 244 // moved one pulse counter clockwise [we will consider this "forward" or
Knillinux 0:dd126a1080d3 245 // "positive"].
Knillinux 0:dd126a1080d3 246 //
Knillinux 0:dd126a1080d3 247 // We might enter an invalid state for a number of reasons which are hard to
Knillinux 0:dd126a1080d3 248 // predict - if this is the case, it is generally safe to ignore it, update
Knillinux 0:dd126a1080d3 249 // the state and carry on, with the error correcting itself shortly after.
Knillinux 0:dd126a1080d3 250 void QEI::encode(void) {
Knillinux 0:dd126a1080d3 251
Knillinux 0:dd126a1080d3 252 int change = 0;
Knillinux 0:dd126a1080d3 253 int chanA = channelA_.read();
Knillinux 0:dd126a1080d3 254 int chanB = channelB_.read();
Knillinux 0:dd126a1080d3 255
Knillinux 0:dd126a1080d3 256 //2-bit state.
Knillinux 0:dd126a1080d3 257 currState_ = (chanA << 1) | (chanB);
Knillinux 0:dd126a1080d3 258
Knillinux 0:dd126a1080d3 259 if (encoding_ == X2_ENCODING) {
Knillinux 0:dd126a1080d3 260
Knillinux 0:dd126a1080d3 261 //11->00->11->00 is counter clockwise rotation or "forward".
Knillinux 0:dd126a1080d3 262 if ((prevState_ == 0x3 && currState_ == 0x0) ||
Knillinux 0:dd126a1080d3 263 (prevState_ == 0x0 && currState_ == 0x3)) {
Knillinux 0:dd126a1080d3 264
Knillinux 0:dd126a1080d3 265 pulses_++;
Knillinux 0:dd126a1080d3 266
Knillinux 0:dd126a1080d3 267 }
Knillinux 0:dd126a1080d3 268 //10->01->10->01 is clockwise rotation or "backward".
Knillinux 0:dd126a1080d3 269 else if ((prevState_ == 0x2 && currState_ == 0x1) ||
Knillinux 0:dd126a1080d3 270 (prevState_ == 0x1 && currState_ == 0x2)) {
Knillinux 0:dd126a1080d3 271
Knillinux 0:dd126a1080d3 272 pulses_--;
Knillinux 0:dd126a1080d3 273
Knillinux 0:dd126a1080d3 274 }
Knillinux 0:dd126a1080d3 275
Knillinux 0:dd126a1080d3 276 } else if (encoding_ == X4_ENCODING) {
Knillinux 0:dd126a1080d3 277
Knillinux 0:dd126a1080d3 278 //Entered a new valid state.
Knillinux 0:dd126a1080d3 279 if (((currState_ ^ prevState_) != INVALID) && (currState_ != prevState_)) {
Knillinux 0:dd126a1080d3 280 //2 bit state. Right hand bit of prev XOR left hand bit of current
Knillinux 0:dd126a1080d3 281 //gives 0 if clockwise rotation and 1 if counter clockwise rotation.
Knillinux 0:dd126a1080d3 282 change = (prevState_ & PREV_MASK) ^ ((currState_ & CURR_MASK) >> 1);
Knillinux 0:dd126a1080d3 283
Knillinux 0:dd126a1080d3 284 if (change == 0) {
Knillinux 0:dd126a1080d3 285 change = -1;
Knillinux 0:dd126a1080d3 286 }
Knillinux 0:dd126a1080d3 287
Knillinux 0:dd126a1080d3 288 pulses_ -= change;
Knillinux 0:dd126a1080d3 289 }
Knillinux 0:dd126a1080d3 290
Knillinux 0:dd126a1080d3 291 }
Knillinux 0:dd126a1080d3 292
Knillinux 0:dd126a1080d3 293 if (pulses_ >= pulsesPerSpeedMeas_) {
Knillinux 0:dd126a1080d3 294 speed_ = (float)pulses_/timer.read();
Knillinux 0:dd126a1080d3 295 pulses_ = 0;
Knillinux 0:dd126a1080d3 296 timer.reset();
Knillinux 0:dd126a1080d3 297 }
Knillinux 0:dd126a1080d3 298
Knillinux 0:dd126a1080d3 299 prevState_ = currState_;
Knillinux 0:dd126a1080d3 300
Knillinux 0:dd126a1080d3 301 }
Knillinux 0:dd126a1080d3 302
Knillinux 0:dd126a1080d3 303 void QEI::index(void) {
Knillinux 0:dd126a1080d3 304
Knillinux 0:dd126a1080d3 305 revolutions_++;
Knillinux 0:dd126a1080d3 306
Knillinux 0:dd126a1080d3 307 }