Let's Make Robots!

Doing "something" with my encoder inputs.

I have a Rover 5 with the Dagu red back spider and motor controller. I have connected 2 encoders (one on each side) to the motor controller / red back spider. I found the encoder library, and tested it. I now have 2 working encoders and can read the value of them with the example sketches of the encoder library. So far so good.

Now I wanted to make a sketch so that when my Rover detects an object it does a 90° turn. I'll use an ultrasonic sensor on a servo to decide between left and right. I already have the code for the ultrasonic sensor and servo. But the thing that I can't figure out is how to code a "void turnleft()" That function should make my robot turn 90°. With some testing I can easily find how many "pulses" from the encoder a 90° turn is. But how can I program this function? It must spin the motors for xxxx number of encoder pulses.

Another possible issue is also that the encoders have to count very fast so they sometimes jump by 2 at once.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Ro-Bot-X's picture

You can calculate how many pulses the robot needs to count until it turns 90 degrees. To do that, you need to know several measuremets of your robot.

First, you need to know how many encoder pulses are in a complete wheel rotation. That should be in the motor data sheet. For example, my motors have 282 pulses per rotation.

Second, you need to know the diameter of your wheel. For example, a regular servo wheel is 2 5/8" in diameter, that makes 66.67 mm. 

Now you can calculate the pulses per mm of travel, by dividing number of pulses per wheel rotation by the circumference of the wheel. The circumference of the wheel is the wheel diameter times PI (3.14), that makes 209.34. Doing the math you get 1.347 pulses per mm of travel.

Third, you need to know the distance between the wheels. To measure that, place the robot on a flat surface and measure the distance from the left wheel's contact point with the surface to the right wheel's contact point to the surface. Dividing that by 2 you get the turn radius, asuming the robot turns in place. For example, my robot has 120 mm between wheels, thus 60 mm turn radius.

Now you can calculate the number of pulses per turn degree. We need to calculate the turn circumference, by multiplying the turn diameter by PI, resulting 376.8 mm. To get the mm per turn degree we divide 360 degrees by the turn circumference and get 0.955 mm per turn degree. Multiplying that by pulses per mm of travel, we get 1.286 pulses per turn degree.

So, a 90 degree turn will take 90*1.286=115.74 pulses for my robot.

Because I used in my calculations maximum 3 floating digits, and only 2 floating digits for the constant PI, there will be a lot of accumulating error after a while. There are ways to minimise the errors by choosing a wheel diameter that will give a round integer number for pulses per mm of travel and the distance between the wheels to get a round integer number for mm per turn degree. Then all your calculations will be easier and a lot less errors will accumulate.

NilsB's picture

You could also try something like this: Go Ahead as long nothing is in your way. Turn left if something is in the way. Turn left. Keep turning until the 90° is reached. Then Go Ahead.

...

const int NOTHING_INSIGHT = 0;

const int ATTENTION_DISTANCE = 16; // This 16 must be changed to the distance you want the robot to turn.
const int NINETY_DEGREES = 90;

int currentDegrees = 0;
int lastPulse = 0;

void loop() {
  if(isAttention()){

    resetDegreeMeasurement();
    turnLeft();
  }
  if(isTurnFinished()){

    goAhead();
  }else{
    measureDegrees();

  }
  delay(25);  
}

void measureDegrees(){

  int pulse = readPulse();
  if(pulse == lastPulse){

    return;
  }
  lastPulse = pulse;
  currentDegrees++;  

}

int readPulse(){
  return encoder.read(); // This must be replaced with the library code you have.

}

boolean isTurnFinished(){ 
  return (currentDegrees == NINETY_DEGREES);

}

void turnLeft(){
  motorLeft.run(RELEASE);

  motorRight.run(FORWARD);  
}

void resetDegreeMeasurement(){

  currentDegrees = 0;
}

void goAhead(){

  motorLeft.run(FORWARD);
  motorRight.run(FORWARD);  

}

boolean isAttention(){
  int distance = ultrasonic.Ranging(CM); // This must be replaced with the library code you have.

  if(distance == NOTHING_INSIGHT){
    return false;

  }
  if(distance > ATTENTION_DISTANCE){
    return false;

  }
  return true;
}
Bajdi's picture

Thanks, I'll give that a try. Just made a sketch to sent the value from the encoders to the lcd on my "remote".

Chris the Carpenter's picture

It is going to be something like this:

# constant turnPulses=how many pulses it takes to go 90

int remCount;

remCount=currentEncoderCount;
Start your motors turning 

while (currentEncoderCount<(remCount+turnPulses)
{
    update currentEncoderCount;
 } 

Turn off motors

 

Now, that is the super-simple run-down of how to do it. In practice, you will probably want to add a "slow down" as you get close to the target number. You will also probably need to add an "overshoot" number to deal with any momentum of the wheels. This slow-down period and the overshoot numbers can even be themselves offset to reflect how fast the turn is being done.

Just to start out, I would base your turns (and your code) off of just one wheel. It will make code and testing a lot easier for you.