Help reading encoder while driving motor via H-Bridge

Hi, I am trying to use the below code to read an encoder value whilst driving a dc motor via an H-bridge. The loop of the code is about the process my robot must do, whilst reading the encoder and driving the motor.
The code is a combo of two separate codes (which work by themselves) for driving a motor and reading the encoder. When combined, I can’t get an encoder reading.
Any ideas/help as to why my encoder will work with its own code, but not when put into the main code?

ENCODER CODE:

#define encoder0PinA  2
#define encoder0PinB  3

volatile unsigned int encoder0Pos = 0;
unsigned int copy_encoder0Pos = 0;

unsigned long lastDisplayTime;
unsigned long displayInterval = 100; // One second serial updates

void setup() { 


  pinMode(encoder0PinA, INPUT); 
  pinMode(encoder0PinB, INPUT); 
 

  attachInterrupt(0, doEncoder, CHANGE);  // encoder pin on interrupt 0 - pin 2
  Serial.begin (9600);
  Serial.println("start");                // a personal quirk

} 

void loop(){

  if (millis() - lastDisplayTime >= displayInterval)
  {
    lastDisplayTime += displayInterval;
    noInterrupts();
    copy_encoder0Pos = encoder0Pos;
    interrupts();
    Serial.println (copy_encoder0Pos, DEC);
  }
}
  

void doEncoder() {
  /* If pinA and pinB are both high or both low, it is spinning
   * forward. If they're different, it's going backward.
   *
   * For more information on speeding up this process, see
   * [Reference/PortManipulation], specifically the PIND register.
   */
  if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {
    encoder0Pos++;
  } else {
    encoder0Pos--;
  }
}

Main code

//ENCODER DECLARATIONS
#define encoder0PinA  2
#define encoder0PinB  3

volatile unsigned int encoder0Pos = 0;
unsigned int copy_encoder0Pos = 0;

unsigned long lastDisplayTime;
unsigned long displayInterval = 100; // One second serial updates

volatile unsigned int encoderPosStart = 0;
volatile unsigned int encoderPosWall = 0;

//MOTOR DECLARATIONS
int enablePin = 11;
int in1Pin = 10;
int in2Pin = 9;
int switchPin = 7;

boolean buttonState;
boolean lastState;
boolean state = HIGH;

void setup() {
  
  //ENCODER SETUP
  pinMode(encoder0PinA, INPUT);
  pinMode(encoder0PinB, INPUT);
  
  //MOTOR SETUP
  pinMode(in1Pin, OUTPUT);
  pinMode(in2Pin, OUTPUT);
  pinMode(enablePin, OUTPUT);
  pinMode(switchPin, INPUT_PULLUP);

  attachInterrupt(0, doEncoder, CHANGE);  // encoder pin on interrupt 0 - pin 2
  Serial.begin (9600);
  Serial.println("start");
}

void loop() {

  //MAIN DRIVE

  encoderPosStart = encoder0Pos; //Read initial encoder position

  //Stage 1: To Wall & Reverse
  int speed = 140;

  while ( digitalRead(switchPin) == LOW) //OR HIGH?
 
  {
    //delay (10); //switch bounce NO DELAY!
    encoderPosWall = encoder0Pos; //Store encoder value when vehiclle hits wall
    boolean reverse = digitalRead(switchPin);
    setMotor(speed, reverse);
  

  //Stage 2: Stopping on first target
  if (encoderPosStart == encoder0Pos) {
    int speed = 0;
    delay (8000);

    {
      boolean reverse = HIGH;
      int speed = 140;
    setMotor(speed, reverse); //NOT SURE THIS SPEED SETTING WILL WORK!
    }

    //Stopping on second target
       if (encoder0Pos = encoderPosWall / 4) {
          int speed = 0;
          delay (8000);
          while (1);
    }
  }  
  }

    //ENCODER READING LOOP

  if (millis() - lastDisplayTime >= displayInterval)
  {
    lastDisplayTime += displayInterval;
    noInterrupts();
    copy_encoder0Pos = encoder0Pos;
    interrupts();
    Serial.println (copy_encoder0Pos, DEC);
  }
} 
  


  /*//MOTOR DRIVE LOOP
    {
    int speed = 70;
    int reading = digitalRead(switchPin);
    if ( reading == LOW && lastState == HIGH ) {
     delay (10);  // To solve the The problem switch bounce
    if (digitalRead(switchPin) == LOW) state = !state;
    }
    boolean reverse = state;
    lastState = reading;
    setMotor(speed, reverse);
    }*/


//ENCODER POSITION DETECTION INTERRUPT.
void doEncoder() {
  /* If pinA and pinB are both high or both low, it is spinning
     forward. If they're different, it's going backward.

     For more information on speeding up this process, see
     [Reference/PortManipulation], specifically the PIND register.
  */
  if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {
    encoder0Pos++;
  } else {
    encoder0Pos--;
  }
}

//MOTOR DRIVE INTERRUPT
void setMotor(int speed, boolean reverse)
{
  analogWrite(enablePin, speed);
  digitalWrite(in1Pin, ! reverse);
  digitalWrite(in2Pin, reverse);
}

LRC:
Any ideas/help as to why my encoder will work with its own code, but not when put into the main code?

You have not given us much to go on with "will work, won't work". You need to describe the symptoms in detail.

My wild guess is that your WHILE loop is the culprit. In general, never use a WHILE that takes more than a few microseconds to complete.

...R

Hi Robin,

Working meaning able to display the encoder value every second to the serial monitor, while driving the dc motor forward. For the main loop, I am looking for the dc motor to drive forward until the microswitch on the front of my robot (driven by the motor) is pressed. On this press I'm trying to do a few things at once:

  • Record the value of the encoder from the start position of the robo to this point
  • Reverse the motor to drive the robot back to its starting position.
  • Then stop the robot after it has reversed back the same encoder value as it went forward.

I hope this is enough to get across my point, I've been trying to figure it out for a while but am quite new to Arduino and coding so have been struggling along for a while.

Cheers,
LRC

LRC:
Working meaning able to display the encoder value every second to the serial monitor, while driving the dc motor forward.

That's what you want it to do. But what is it actually doing?

For the main loop, I am looking for the dc motor to drive forward until the microswitch on the front of my robot (driven by the motor) is pressed.

You have not responded to my comment about your use of WHILE?

...R

This code is silly

      boolean reverse = HIGH;
      int speed = 140;
    setMotor(speed, reverse); //NOT SURE THIS SPEED SETTING WILL WORK!

You can just do

    setMotor(140, HIGH); //NOT SURE THIS SPEED SETTING WILL WORK!

The code is littered with things like that.

And this:-

//Stage 2: Stopping on first target
  if (encoderPosStart == encoder0Pos) {
    int speed = 0;
    delay (8000);

Once you have reached a target you wait 8 seconds before turning the motors off!
Just creating a variable called speed is not going to do anything to your motor.

Every time you use int in front of a variable name you are creating a new variable, even if that name is already in use, you don't want to do that.

Thanks Mike,

I'll remove that and see the effect it has :slight_smile:

Robin2:
That's what you want it to do. But what is it actually doing?
You have not responded to my comment about your use of WHILE?

...R

What it is actually doing is driving the motors at 140 all the time, with no effect on them from the switch. The encoder reading on the serial monitor prints "start" and then nothing. When the encoder code is used alone and the encoder is stationary, it will print "start" followed by a 0 every second until the encoder rotates and the numbers go up (so that's what I'm aiming for).

My knowledge of WHILE is just that you can use it to do something while a condition is met. I was unaware that it should only be used on a situation that takes only a few microseconds to complete. In a previous iteration of the code, I used an IF instead of the while.

LRC:
My knowledge of WHILE is just that you can use it to do something while a condition is met. I was unaware that it should only be used on a situation that takes only a few microseconds to complete. In a previous iteration of the code, I used an IF instead of the while.

IF is usually preferable as it does not block other things in the way that a long-duration WHILE does. The loop() function can look after the repetition.

...R