Rotary Encoder not Triggering DC Motor Stop?

Hi All,

I am sure I am doing something wrong here but I don't know what it is...wondering if anyone of you could advise.

The Setup:

Arduino Uno
Pololu Dual TB9051FTG Motor Shield
Pololu 131:1 Metal Gearmotor 37Dx73L mm 12V with 64 CPR Encoder (Helical Pinion)

The Problem:

I want to be able to count ticks of the encoder on the DC motor and stop the motor when I reach a certain count. Currently, the test code I am working on does not work...but I cant see why it shouldn't work...

The Code:

#include "DualTB9051FTGMotorShield.h" //Include ther library for the motor driver
DualTB9051FTGMotorShield md; 
volatile unsigned int encoder = 0; 
const byte encoder1 = 2;
const byte encoder2 = 3;

void setup() {
  Serial.begin(115200);  //Initialize the serial connection
  md.init(); // Initialize the motor driver
  pinMode(encoder1, INPUT); //Set the pins the encoder is connected to as inputs
  pinMode(encoder2, INPUT); //Set the pins the encoder is connected to as inputs
  digitalWrite(encoder1,HIGH); // internal pull up resistor
  digitalWrite(encoder2,HIGH); // internal pull up resistor
  attachInterrupt(0,encoderISR,CHANGE); //
  md.flipM1(false); // Set motor driection
  md.enableDrivers(); // Enable the motor driver
}

void loop() {
  turnMotor();
}

void turnMotor(){
  int deltaSteps = 128;
  md.setM1Speed(400);
  if(encoder >= deltaSteps){
  md.setM1Speed(0);
  delay(10000);
  }
}

void encoderISR(){
    if (bitRead(PORTD, 2) == bitRead(PORTD, 3) ) {
         encoder += 1;
    }
    else encoder -= 1;
}

I have stripped away as much extraneous stuff as I could and tried to make sure the ISR function is streamlined but the code doesn't do anything when I upload it currently. When I test other programs with the same wiring and setup I can get the motor to turn...what am I missing?

Thanks!

What do you see on the serial monitor if you:

Serial.println(encoder);

?

When using a multibyte variable (in this case an int) in an ISR you must temporarily suspend interrupts when reading it to avoid the possibility that its value gets changed while you are reading it. Make a copy of the value and use the copy in the calculations in loop() - like this

noInterrupts()
  copyOfEncoder = encoder;
interrupts();
if(copyOfEncoder >= deltaSteps){

Also you may want to set encoder back to 0 after you read it - while still with interrupts suspended

...R

Thanks @Robin2 !

That makes perfect sense. I implemented it as below but the motor still does not turn. It jerks a little once the code is uploaded but that is it...Which is so weird as I can test other code that turns the motor just fine...neither code seems able to stop the motor however.

#include "DualTB9051FTGMotorShield.h" //Include the library for the motor driver
DualTB9051FTGMotorShield md; 
volatile unsigned int encoder = 0;
volatile unsigned int copyOfEncoder =0;
const byte encoder1 = 2;
const byte encoder2 = 3;


void setup() {
  Serial.begin(115200);  //Initialize the serial connection
  pinMode(encoder1, INPUT); //Set the pins the encoder is connected to as inputs
  pinMode(encoder2, INPUT); //Set the pins the encoder is connected to as inputs
  digitalWrite(encoder1,HIGH); // internal pull up resistor
  digitalWrite(encoder2,HIGH); // internal pull up resistor
  attachInterrupt(0,encoderISR,CHANGE); //
  md.init(); // Initialize the motor driver
  md.flipM1(false); // Set motor driection
  md.enableDrivers(); // Enable the motor driver
}

void loop() {
  noInterrupts();
  copyOfEncoder = encoder;
  interrupts();
  turnMotor();
  Serial.println(encoder);
}

void turnMotor(){
  int deltaSteps = 128;
  md.setM1Speed(400);
  if(copyOfEncoder >= deltaSteps){
  md.setM1Speed(0);
  delay(10000);
  }
}

void encoderISR(){
    if (bitRead(PORTD, 2) == bitRead(PORTD, 3) ) {
         encoder += 1;
    }
    else encoder -= 1;
}

Any thoughts would be great! Thanks!

Hi @JCA34F !

The output from Serial.println(encoder); looks like:

291

112
113
115
117
118
120
122
123
125
127
7
88
90
91
92
93
94
96
97
98
99
101
102
104
105
107
109
110
112
113
115
117
118
120
122
123
125
127
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
2
2
2
2
2
2
3
3
3
3
3
3
4
4
4
4
5
5
5
5
6
6
6
7
7
7
7
8
8
8
9
9
9
10
10
11
11
12
12
13
13
14
15
15
16
16
17
18
18
19
20
20
21
22
22
23
24
25
25
26
27
28
28
29
30
31
32
33
33
34
35
36
37
38
39
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
69
70
71
72
73
74
75
76
78
79
80
81
82
83
85
86
87
88
89
91
92
93
94
95
97
98
99
100
102
104
105
107
108
110
112
113
115
117
118
120
122
123
125
127
291

The code in Reply #3 is not producing the output in Reply #4. Make sure to post the latest version of your program so we can keep up with you.

...R

Just updated it! I had stripped out the Serial.println(encoder); just to keep it tidy but its back in there now.

Serial.println(encoder);

This should be

Serial.println(copyOfEncoder);

I would rewrite turnMotor() thus:

const int deltaSteps = 128;

void turnMotor()
{
  if (encoder >= deltaSteps)
    md.setM1Speed(0);
  else
    md.setM1Speed(400);
}

Then it won't keep trying to turn it back on again, it simply sets the speed dependent on whether its
reached the target or not. Bring constants out to top level so they are easy to spot and can be shared in
multiple places in the code. Also this way you don't call delay().

So that all works fine now thanks! Updated code below:

#include "DualTB9051FTGMotorShield.h" //Include the library for the motor driver
DualTB9051FTGMotorShield md; 
volatile unsigned int encoder = 0;
volatile unsigned int copyOfEncoder =0;
const byte encoder1 = 2;
const byte encoder2 = 3;
const int deltaSteps = 8400;


void setup() {
  Serial.begin(115200);  //Initialize the serial connection
  pinMode(encoder1, INPUT); //Set the pins the encoder is connected to as inputs
  pinMode(encoder2, INPUT); //Set the pins the encoder is connected to as inputs
  digitalWrite(encoder1,HIGH); // internal pull up resistor
  digitalWrite(encoder2,HIGH); // internal pull up resistor
  attachInterrupt(0,encoderISR,CHANGE); //
  md.init(); // Initialize the motor driver
  md.flipM1(false); // Set motor driection
  md.enableDrivers(); // Enable the motor driver
}

void loop() {
  noInterrupts();
  copyOfEncoder = encoder;
  interrupts();
  turnMotor();
  Serial.println(copyOfEncoder);
}

void turnMotor(){
  
  
  if(copyOfEncoder >= deltaSteps){
    md.setM1Speed(0);
  }else{
    md.setM1Speed(400);
  }
}

void encoderISR(){
    if (bitRead(PORTD, 2) == bitRead(PORTD, 3) ) {
         encoder += 1;
    }
    else encoder -= 1;
}

I am trying to add in some SD card functionality now and its returning some intermittent failures...see code below:

#include "DualTB9051FTGMotorShield.h" //Include the library for the motor driver
DualTB9051FTGMotorShield md;
#include <SPI.h>
#include <SD.h>
File myFile;
volatile unsigned int encoder = 0;
volatile unsigned int copyOfEncoder =0;
const byte encoder1 = 2;
const byte encoder2 = 3;
const int deltaSteps = 8400;
char* fileName = "Combo.txt";

void setup() {
  Serial.begin(115200);  //Initialize the serial connection
  pinMode(encoder1, INPUT); //Set the pins the encoder is connected to as inputs
  pinMode(encoder2, INPUT); //Set the pins the encoder is connected to as inputs
  digitalWrite(encoder1,HIGH); // internal pull up resistor
  digitalWrite(encoder2,HIGH); // internal pull up resistor
  attachInterrupt(0,encoderISR,CHANGE); //
  md.init(); // Initialize the motor driver
  md.flipM1(false); // Set motor driection
  md.enableDrivers(); // Enable the motor driver
  while (!Serial) {
    ; // Wait for serial port to connect. Needed for native USB port only
  }
  Serial.print("Initializing SD card...");
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");
  myFile = SD.open(fileName, FILE_WRITE);
}

void loop() {
  noInterrupts();
  copyOfEncoder = encoder;
  interrupts();
  turnMotor();
  Serial.println(copyOfEncoder);
}

void turnMotor(){
  
  
  if(copyOfEncoder >= deltaSteps){
    md.setM1Speed(0);
  }else{
    md.setM1Speed(400);
  }
}

void encoderISR(){
    if (bitRead(PORTD, 2) == bitRead(PORTD, 3) ) {
         encoder += 1;
    }
    else encoder -= 1;
}

Can I use an SD card while using ISR without issue?

Thanks!