Control project for the Lift-arm. Works with ROS Melodic
Dependencies: mbed Servo ros_lib_melodic ULN2003_StepperDriver Async_4pin_Stepper
src/encoder.cpp
- Committer:
- krogedal
- Date:
- 2021-05-31
- Revision:
- 4:9edb248c6431
- Parent:
- 3:4b6080e86761
File content as of revision 4:9edb248c6431:
#ifndef ENCODER_H #define ENCODER_H /* Karbot encoder class * * This class is based upon the QEI class by Aaron Berk and the encoder class * I wrote during ESP in 2nd year * * Written by Simon Krogedal * 27/05/21 * Team 9 4th Year project * * for NUCLEO-F401RE * */ #include "encoder.h" encoder::encoder( PinName chanA, PinName chanB, int CPR, bool c, double p, double ec ) : channelA_(chanA, PullUp), channelB_(chanB, PullUp), c_d(c), period(p), enc_const(ec) { pulses_ = 0; pulsesPerRev_ = CPR; tot_clicks = 0; click_rate = 0; temp_tot = 0; //Workout what the current state is. int channA = channelA_.read(); int channB = channelB_.read(); //2-bit state. currState_ = (channA << 1) | (channB); prevState_ = currState_; //X4 encoding uses interrupts on channel A, //and on channel B. channelA_.rise(callback(this, &encoder::encode)); channelA_.fall(callback(this, &encoder::encode)); channelB_.rise(callback(this, &encoder::encode)); channelB_.fall(callback(this, &encoder::encode)); } void encoder::reset(void) { pulses_ = 0; } int encoder::getCurrentState(void) { return currState_; } int encoder::getPulses(void) { return pulses_; } // +-------------+ // | X2 Encoding | // +-------------+ // // When observing states two patterns will appear: // // Counter clockwise rotation: // // 10 -> 01 -> 10 -> 01 -> ... // // Clockwise rotation: // // 11 -> 00 -> 11 -> 00 -> ... // // We consider counter clockwise rotation to be "forward" and // counter clockwise to be "backward". Therefore pulse count will increase // during counter clockwise rotation and decrease during clockwise rotation. // // +-------------+ // | X4 Encoding | // +-------------+ // // 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 encoder::encode(void) { int change = 0; int chanA = channelA_.read(); int chanB = channelB_.read(); //2-bit state. currState_ = (chanA << 1) | (chanB); //Entered a new valid state. if (((currState_ ^ prevState_) != INVALID) && (currState_ != prevState_)) { //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 encoder::sample_func(void) { int clicks = getPulses(); click_rate = ((double)clicks / period); reset(); //reset clicks tot_clicks += clicks; temp_tot += clicks; } double encoder::getClicks(void) { // test_sample(); if(c_d) return click_rate; else return -click_rate; } double encoder::getSpeed(void) { double s = click_rate * enc_const; //angular frequency = 2pi*CPS/CPR and v = omega*r if(c_d) return s; else return -s; } double encoder::getDistance(void) { //calculates total distance and returns it // test_sample(); double d = ((double)click_store * enc_const); if(c_d) return d; else return -d; } double encoder::tempDist(void) { //calculates total distance and returns it // test_sample(); double d = ((double)temp_tot * enc_const); if(c_d) return d; else return -d; } void encoder::distRst(void) { int temp; if(c_d) temp = tot_clicks; else temp = -tot_clicks; if(temp > click_store) click_store = temp; tot_clicks = 0; } void encoder::tempRst(void) {temp_tot = 0;} void encoder::start(void) {sampler.attach(callback(this, &encoder::sample_func), period);} #endif