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-27
Revision:
1:7c355adbc977
Parent:
0:441289ea4e29
Child:
3:4b6080e86761

File content as of revision 1:7c355adbc977:

#ifndef ENCODER_H
#define ENCODER_H

/* Karbot encoder class
 * 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