Implementing Wheel Encoders to make turns

Hello, I am seeking some help/guidance with my Arduino code.

I am using an Arduino Uno to program a bot car, which will drive a specific path that I have drawn out. To do this, I am using the magnetic wheel encoders from SparkFun.

These are the links to the parts, if that is helpful at all.
RedBot kit (my bot car) → https://www.sparkfun.com/products/13166
Wheel Encoders → Wheel Encoder Kit - ROB-12629 - SparkFun Electronics

So far I have been able to create a code that will make the bot go straight. However what I need help with, is make my bot do 90 degree turns.
I think what I need to do is make separate functions using while loops, and then implement that into the void loop(). But I am stuck on how to go about it, or if there is another way to do this. If I can get some guidance I would greatly appreciate it!

#define CW  0
#define CCW 1

// Motor definitions to make life easier:
#define MOTOR_A 0
#define MOTOR_B 1

#include <RedBot.h>
RedBotMotors motors;

// Pin Assignments //
// Don't change these! These pins are statically defined by shield layout
const byte PWMA = 3;  // PWM control (speed) for motor A
const byte PWMB = 11; // PWM control (speed) for motor B
const byte DIRA = 12; // Direction control for motor A
const byte DIRB = 13; // Direction control for motor B

RedBotEncoder encoder = RedBotEncoder(A2, 10);  // initializes encoder on pins A2 and 10

int countsPerRev = 192;   // 4 pairs of N-S x 48:1 gearbox = 192 ticks per wheel rev

// variables used to store the left and right encoder counts.
int lCount;
int rCount;

void setup()
{
  Serial.begin(9600);
}

// driveArdumoto drives 'motor' in 'dir' direction at 'spd' speed

void driveArdumoto(byte motor, byte dir, byte spd)
{
  if (motor == MOTOR_A)
  {
    digitalWrite(DIRA, dir);
    analogWrite(PWMA, spd);
  }
  else if (motor == MOTOR_B)
  {
    digitalWrite(DIRB, dir);
    analogWrite(PWMB, spd);
  }  
}
void loop(void)
{
  
  driveArdumoto(MOTOR_A, CW, 200);  // Motor A at max speed.
  driveArdumoto(MOTOR_B, CW, 200);  // Motor B at max speed.
    if (lCount >= rCount+20)   
  {
    driveArdumoto(MOTOR_B, CW, 150);  // Motor A stop.
    
  }
    if (rCount >= lCount+10){
  driveArdumoto(MOTOR_A, 0, 0);  // Motor B stop.
}
 // delay(1500);  // Drive forward for a second
  // store the encoder counts to a variable.
  lCount = encoder.getTicks(LEFT);    // read the left motor encoder
  rCount = encoder.getTicks(RIGHT);   // read the right motor encoder

int leftCount =2*lCount;
int rightCount =2*rCount;

  // if either left or right motor are more than 5 revolutions, stop

}

I think what I need to do is make separate functions

Good idea. Separate functions for what?

using while loops

To wait for what to happen?

and then implement that into the void loop()

It's called "the loop() function". You wouldn't say "the int analogRead()" would you? "The void loop()" is just as grating.

But I am stuck on how to go about it,

I have not seen anything that looks like a requirement specification, so I am not surprised.

    if (lCount >= rCount+20)   
  {
    driveArdumoto(MOTOR_B, CW, 150);  // Motor A stop.
   
  }
    if (rCount >= lCount+10){
  driveArdumoto(MOTOR_A, 0, 0);  // Motor B stop.
}
 // delay(1500);  // Drive forward for a second
  // store the encoder counts to a variable.
  lCount = encoder.getTicks(LEFT);    // read the left motor encoder
  rCount = encoder.getTicks(RIGHT);   // read the right motor encoder

Use some values, then read the values. The cart is on the wrong end of your horse.

Good idea. Separate functions for what?

Separate functions for the left and right turns.

For example:

void leftTurn()
{

while( i > 200, i++)

}

void rightTurn()
{

}

It's called "the loop() function". You wouldn't say "the int analogRead()" would you? "The void loop()" is just as grating.

Thank you, I apologize for I'm new to forums, and the language is still a bit foreign to me. But I understand what you mean.

What can I do to fix my code and make turns? Please help me.

What can I do to fix my code and make turns?

The first thing you need to do is to define how many ticks of an encoder are needed to make a 90 degree (or a 45 degree or a 180 degree) turn. Keep in mind that that depends on the radius of the turn. Stopping one motor and turning just the other will make one radius turn. Keeping both turning the same way, at different speeds, will result in a different radius turn. Turning one motor one way and the other motor the other way will result in another radius for the turn.

In each case, the number of ticks of the encoder will be different.

So, you need to pick a type of turn that you are going to make, and experiment to determine how many more times one encoder ticks than the other. to make a 90 degree turn.

After that, it’s pretty simple to read the number of ticks when the turn is to start, and use those values as a baseline. Start the turn, and a while statement to count the ticks until the required delta number of ticks has happened. When that happens, stop turning.

So, you need to pick a type of turn that you are going to make, and experiment to determine how many more times one encoder ticks than the other. to make a 90 degree turn.

After that, it’s pretty simple to read the number of ticks when the turn is to start, and use those values as a baseline. Start the turn, and a while statement to count the ticks until the required delta number of ticks has happened. When that happens, stop turning.

Thank you for your guidance, I spend quite a bit more time researching and re writing my code.

I have been working on making a right turn.

One full revolution is 192 ticks.

It takes about 200 counts per revolutions to make a 90 degree turn.

This is a part of the code I am working on now:

void loop(void)
{
  
  driveFWD();
  delay(3000);

  stopArdumoto(MOTOR_A);
  stopArdumoto(MOTOR_B);
  delay(1000);

  turnRight();

  stopArdumoto(MOTOR_A);
  stopArdumoto(MOTOR_B);
  delay(1000);

 driveFWD();
 delay(3000);
  
}

void driveFWD()
{
    int leftCount =2*lCount;
    int rightCount =2*rCount;

    driveArdumoto(MOTOR_A, CW, 255);  // Motor A at max speed.
    driveArdumoto(MOTOR_B, CW, 255);  // Motor B at max speed.
    
    if (lCount >= rCount+20)   
  {
    driveArdumoto(MOTOR_A, CW, 150);  // Motor A stop.
    
  }
    if (rCount >= lCount+10){
      
    driveArdumoto(MOTOR_B, 0, 0);  // Motor B stop.
}

}

void turnRight()
{
  lCount = 0;
  rCount = 0;
    
  while ( rCount <= 200)
  {
    driveArdumoto(MOTOR_A, CW, 200);
    driveArdumoto(MOTOR_B, CCW, 200);
  }
  stopArdumoto(MOTOR_A);
  stopArdumoto(MOTOR_B);
  
}

Once the loop starts, the wheels will go forward for 3 seconds, stop for 1 second, then the right wheel begins to turn, but it doesn’t stop! What am I missing? I tried using delays in the loop, and in the rightTurn function. I am stuck.

I apologize if again I am making silly mistakes or using the wrong verbiage. But I am determined on making this work.

lCount = encoder.getTicks(LEFT);    // read the left motor encoder
  rCount = encoder.getTicks(RIGHT);   // read the right motor encoder

I think you want some of this in your functions which move the motors based on count.

I think you want some of this in your functions which move the motors based on count.

I put the code in my functions. Unfortunately it hasn’t solved the issue :frowning:

void driveFWD()
{ 
    driveArdumoto(MOTOR_A, CW, 255);  // Motor A at max speed.
    driveArdumoto(MOTOR_B, CW, 255);  // Motor B at max speed.
    
    if (lCount >= rCount+20)   
  {
    driveArdumoto(MOTOR_A, CW, 150);  // Motor A stop.
    
  }
    if (rCount >= lCount+10){
      
    driveArdumoto(MOTOR_B, 0, 0);  // Motor B stop.
}
  lCount = encoder.getTicks(LEFT);    // read the left motor encoder
  rCount = encoder.getTicks(RIGHT);   // read the right motor encoder

}

void turnRight()
{   
  while ( rCount <= 200)
  {
    driveArdumoto(MOTOR_A, CW, 200);
    driveArdumoto(MOTOR_B, CCW, 200);
  }

  lCount = encoder.getTicks(LEFT);    // read the left motor encoder
  rCount = encoder.getTicks(RIGHT);   // read the right motor encoder
}

You are posting snippets but I hope that lCount and rCount are declared as global variables.

In the right turn function, the count needs to be updated within the while loop.

void turnRight()
{   
  while ( rCount <= 200)
  {
    rCount = encoder.getTicks(RIGHT);   // read the right motor encoder
    driveArdumoto(MOTOR_A, CW, 200);
    driveArdumoto(MOTOR_B, CCW, 200);
  }

 // lCount = encoder.getTicks(LEFT);    // read the left motor encoder
 // rCount = encoder.getTicks(RIGHT);   // read the right motor encoder
}

In the forward function you did not follow up on Pauls advice

Use some values, then read the values. The cart is on the wrong end of your horse.

void driveFWD()
{ 
     lCount = encoder.getTicks(LEFT);    // read the left motor encoder
     rCount = encoder.getTicks(RIGHT);   // read the right motor encoder
    
    driveArdumoto(MOTOR_A, CW, 255);  // Motor A at max speed.
    driveArdumoto(MOTOR_B, CW, 255);  // Motor B at max speed.
    
    if (lCount >= rCount+20)   
  {
    driveArdumoto(MOTOR_A, CW, 150);  // Motor A stop.
    
  }
    if (rCount >= lCount+10){
      
    driveArdumoto(MOTOR_B, 0, 0);  // Motor B stop.
}
  //lCount = encoder.getTicks(LEFT);    // read the left motor encoder
 // rCount = encoder.getTicks(RIGHT);   // read the right motor encoder

}

Here is my whole code:

#define CW  0
#define CCW 1

// Motor definitions to make life easier:
#define MOTOR_A 0
#define MOTOR_B 1

#include <RedBot.h>
RedBotMotors motors;

// Pin Assignments //
// Don't change these! These pins are statically defined by shield layout
const byte PWMA = 3;  // PWM control (speed) for motor A
const byte PWMB = 11; // PWM control (speed) for motor B
const byte DIRA = 12; // Direction control for motor A
const byte DIRB = 13; // Direction control for motor B

RedBotEncoder encoder = RedBotEncoder(A2, 10);  // initializes encoder on pins A2 and 10

int countsPerRev = 192;   // 4 pairs of N-S x 48:1 gearbox = 192 ticks per wheel rev

// variables used to store the left and right encoder counts.
int lCount;
int rCount;

float wheelDiam = 2.56;  // diam = 65mm / 25.4 mm/in
float wheelCirc = PI*wheelDiam;  // Redbot wheel circumference = pi*D


void setup()
{
  Serial.begin(9600);
}
// driveArdumoto drives 'motor' in 'dir' direction at 'spd' speed
void driveArdumoto(byte motor, byte dir, byte spd)
{
  if (motor == MOTOR_A)
  {
    digitalWrite(DIRA, dir);
    analogWrite(PWMA, spd);
  }
  else if (motor == MOTOR_B)
  {
    digitalWrite(DIRB, dir);
    analogWrite(PWMB, spd);
  }  
}
void loop(void)
{
  
  driveFWD();
  delay(3000);

  stopArdumoto(MOTOR_A);
  stopArdumoto(MOTOR_B);
  delay(1000);

  turnRight();

  stopArdumoto(MOTOR_A);
  stopArdumoto(MOTOR_B);
  delay(1000);

  driveFWD();
  delay(3000);
  
}

void driveFWD()
{ 
     lCount = encoder.getTicks(LEFT);    // read the left motor encoder
     rCount = encoder.getTicks(RIGHT);   // read the right motor encoder
    
    driveArdumoto(MOTOR_A, CW, 255);  // Motor A at max speed.
    driveArdumoto(MOTOR_B, CW, 255);  // Motor B at max speed.
    
    if (lCount >= rCount+20)   
  {
    driveArdumoto(MOTOR_A, CW, 150);  // Motor A stop.
    
  }
    if (rCount >= lCount+10){
      
    driveArdumoto(MOTOR_B, 0, 0);  // Motor B stop.
}

}

void turnRight()
{   
  while ( rCount <= 200)
  {
    rCount = encoder.getTicks(RIGHT);   // read the right motor encoder
    driveArdumoto(MOTOR_A, CW, 200);
    driveArdumoto(MOTOR_B, CCW, 200);
  }

}

void stopArdumoto(byte motor)
{
  driveArdumoto(motor, 0, 0);
}

I updated it with codes you suggested, but still it gets stuck turning the right wheel continuously after going forward for 3 seconds.

I’m not familiar with the RedBot library you are using. But I see a few things when I take a quick look.

First, you need to be resetting the counts at the start of the functions which rely on counts.
The syntax for how you declared the encoder object will be
encoder.clearEnc(LEFT,RIGHT,BOTH) It will take one of the three parameters depending what you want to reset.

There is an error in the driveFWD function in that you are not really turning off MotorA.

void driveFWD()
{ 
     lCount = encoder.getTicks(LEFT);    // read the left motor encoder
     rCount = encoder.getTicks(RIGHT);   // read the right motor encoder
    
    driveArdumoto(MOTOR_A, CW, 255);  // Motor A at max speed.
    driveArdumoto(MOTOR_B, CW, 255);  // Motor B at max speed.
    
    if (lCount >= rCount+20)   
  {
    //driveArdumoto(MOTOR_A, CW, 150); //??<<This does not stop the motor.
    driveArdumoto(MOTOR_A, 0, 0); // Motor A stop.
  
  }
    if (rCount >= lCount+10){
      
    driveArdumoto(MOTOR_B, 0, 0);  // Motor B stop.
}

}

In order to debug your code, it would be very helpful to have some serial printing for debugging. I’d like to verify that you are indeed entering the functions you think you are, and to get some printouts on the lCount and rCount values.

Question. When you use delay, do the motors stop turning?