Dagu Rover 5 encoders - weird behaviour!

Hi everyone,

I'm a newbie on this forum and globally on robotics.

I started a few months ago the build of an autonomous car (https://medium.com/@MAC1project/episode-1-one-car-to-rule-them-all-94f705ea9737) from scratch using : 

  • Dagu Rover 5 - 2 motors - 2 encoders
  • Raspi 3
  • Explorer board RS017
  • Sensors: ultrasonic, sharp IR, neato lidar
  • ...

All my code is in NodeJS, yes yes, nodeJS :)...

I manage to drive manually the robot using my smartphone (either joystick or accelerometer).

I manage to start an autonomous mode V0 using ultrasonic sensor and IR sensor.

Comes the time to odometry, mapping and robot localization ==> ENCODER TIME

I have a strange behaviour :

  • If i manually turn the left wheels it increments BOTH left encoder ticks and a little bit the right encoder ticks. ==> How that possible?
  • If i manually turn the right wheels it increments ONLY right encoder ticks

Here under few lines of code :

 

//Encoder instanciation
    this.RightEncoder = new Encoder ("RIGHT ENCODER", constants.RIGHT_ENCODER_PINA, constants.RIGHT_ENCODER_PINB);
    this.LeftEncoder = new Encoder ("LEFT ENCODER", constants.LEFT_ENCODER_PINA, constants.LEFT_ENCODER_PINB);
function Encoder(name, pinA, pinB) {
    this.name = name;
    this.pinA = pinA
    this.pinB = pinB;
    this.nbTicks = 0;
    this.traveledDistance = 0; //distance in meter

    var encoder = this;

    rpio.open(pinA, rpio.INPUT);
    rpio.poll(pinA, function countTickPinA(pinA){
        encoder.nbTicks = encoder.nbTicks + 1; //CW
        //encoder.setTraveledDistance();
        }
    );

    rpio.open(pinB, rpio.INPUT);
    rpio.poll(pinB, function countTickPinB(pinB){
        encoder.nbTicks = encoder.nbTicks + 1; //CW
        //encoder.setTraveledDistance();
    } );
}
Any help would be much appreciated. Thanks a lot.

Rotary encoders

I beleive that the encoders on the Rover 5 are quadratue encoders. At a minimum you need to debounce the inputs and only increment the count on the transition from LOW to HIGH. You can get twice the resolution with the quadrature algorithm.

 

Hi ggallant, thanks for

Hi ggallant,

 

thanks for your reply. I first tried this algorithm (to instanciate per encoder)…with bad results.

 

Do you have a particular algorithm in mind ? (https://forum.arduino.cc/index.php?topic=93345.0 ?)

Thanks for your help, it is my very first time with all these mechanisms.

function Encoder(name, pinA, pinB) {
    this.name = name;
    this.pinA = pinA
    this.pinB = pinB;
    this.nbTicks = 0;
    this.traveledDistance = 0; //distance in meter

    var encoder = this;

    rpio.open(pinA, rpio.INPUT);
    rpio.poll(pinA, function countTickPinA(pinA){
        //Returns either 0 for LOW or 1 for HIGH
        var statePinA = rpio.read(pinA);
        var statePinB = rpio.read(encoder.pinB);
        
        // look for a low-to-high on channel A
        if (statePinA == 1){
            // check channel B to see which way encoder is turning
            if (statePinB == 0) {
                encoder.nbTicks = encoder.nbTicks + 1; //CW
            }
            else {
                encoder.nbTicks = encoder.nbTicks - 1; // CCW
            }
        }
        // must be a high-to-low edge on channel A
        else {
            // check channel B to see which way encoder is turning
            if (statePinB == 1) {
                encoder.nbTicks = encoder.nbTicks + 1; //CW
            }
            else {
                encoder.nbTicks = encoder.nbTicks - 1; //CCW
            }
        }
        //console.log(name, " ", encoder.nbTicks);
        encoder.setTraveledDistance();
        }
    );

    rpio.open(pinB, rpio.INPUT);
    rpio.poll(pinB, function countTickPinB(pinB){
        //Returns either 0 for LOW or 1 for HIGH
        var statePinA = rpio.read(encoder.pinA);
        var statePinB = rpio.read(pinB);

        // look for a low-to-high on channel B
        if (statePinB == 1){
            // check channel A to see which way encoder is turning
            if (statePinA == 1) {
                encoder.nbTicks = encoder.nbTicks + 1; //CW
            }
            else {
                encoder.nbTicks = encoder.nbTicks - 1; //CCW
            }
        }
        // Look for a high-to-low on channel B
        else {
            // check channel B to see which way encoder is turning
            if (statePinA == 0) {
                encoder.nbTicks = encoder.nbTicks + 1; //CW
            }
            else {
                encoder.nbTicks = encoder.nbTicks - 1; //CCW
            }
        }
        //console.log(name, " ", encoder.nbTicks);
        encoder.setTraveledDistance();
        } );
}

Encoders

Quadrature decoders are a low level, time sensitive, I/O operations. Probably best done with embedded hardware sush as found in the PIC16 series or at a  minimum with ISR coding. The number of transitions per second is dependent upon rotational speed and the number of slots per revolution. Some encoders are on the motor shaft, others on the geared down output. Using polled more I/O system libraries is probably not going to work very well. Too easy to miss a transition plus you will need to schedulte quite often which eats CPU resources.

I am quite lost reading the attached code.

What is the difference between gpio.read(encoder.pinA) and gpio.read(pinA)?

Where is the debounce?

Where is the edge detect?