I am using the motor encoder library found here on an arduino uno using this dc motor and this motor driver. Currently the motor turns but does not stop. I am following the basic example included in the github for the Encoder library, what am I missing?
/* Encoder Library - Basic Example
* http://www.pjrc.com/teensy/td_libs_Encoder.html
*
* This example code is in the public domain.
*/
#include <Encoder.h>
#include "DualTB9051FTGMotorShield.h"
DualTB9051FTGMotorShield md;
volatile long newPosition;
volatile long oldPosition;
boolean runOnce = true;
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
Encoder myEnc(3, 2);
// avoid using pins with LEDs attached
void setup() {
Serial.begin(115200);
Serial.println("Basic Encoder Test:");
md.init(); // Initialize the motor driver
md.enableDrivers();
}
void loop() {
newPosition = myEnc.read();
if (newPosition != oldPosition) {
oldPosition = newPosition;
Serial.println(newPosition);
}
if(runOnce){
turn(1500);
runOnce = false;
}
}
void turn(int number) {
if (newPosition <= number) {
md.setM1Speed(100);
} else md.setM1Speed(0);
}
The results of running the demo sketch for the driver board are as expected. The motor turns one direction ramping up to full speed and back to zero before changing direction and ramping to full speed and going back to zero. It outputs the current for the motor in the serial monitor like so:
I do not think my problem is a motor driver or motor problem (but I am open to suggestions!) as I have gotten the motor to run and stop without using a library. I believe the issue is in my code structure but I don’t know where. Any thoughts?
The challenge is the basic example code provided with the library doesn’t actually do anything. There is no functionality built into to preform any actions. I have added in what I think is the minimum amount of code to get it counting ticks for the dc motor I have and it does do that. The problem seems to be that the code never enters this else condition and I don’t know why:
OK, I figured out the problem with why the motor wasn't stopping:
if(runOnce){
turn(1500);
runOnce = false;
}
I needed to not include the runOnce code:
turn(1500);
It did reveal another issue though. I am telling the encoder to go to 1500 "clicks" and it does overrun a bunch (it stops at around 1575) but that is not the part I am worried about. If I examine the output in the serial monitor I can see that there actually only 1352 lines outputted and of those lines a great number of them are repeats:
/* Encoder Library - Basic Example
* http://www.pjrc.com/teensy/td_libs_Encoder.html
*
* This example code is in the public domain.
*/
#include <Encoder.h>
#include "DualTB9051FTGMotorShield.h"
DualTB9051FTGMotorShield md;
volatile int newPosition = 0;
volatile int oldPosition = 0;
boolean runOnce = true;
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
Encoder myEnc(3, 2);
// avoid using pins with LEDs attached
void setup() {
Serial.begin(115200);
Serial.println("Basic Encoder Test:");
md.init(); // Initialize the motor driver
md.enableDrivers();
}
void loop() {
newPosition = myEnc.read();
if (newPosition != oldPosition) {
oldPosition = newPosition;
Serial.println(newPosition);
}
turn(1500);
}
void turn(int number) {
if (newPosition <= number) {
md.setM1Speed(100);
} else{
md.setM1Speed(0);
}
}
Here is the output (truncated to meet the post character limit):
I am looking for the output to be accurate in terms of encoder count. I need to know the encoder is actually counting 1500 ticks (not including any over run) when I tell the motor to turn 1500 ticks. Right now if you look at the output it is double counting and being crazy inaccurate. I am sure there is a way I can clean this up but I don’t know what it is from looking at the github repo for the library. Any help would be appreciated.
I think the biggest issue is that if you may be using the wrong motor for the job. If you want exact movement, a stepper motor is the common choice. You tell it to move exactly x steps and it does so. A DC motor is not as exact. You may be able to make it better by moving the motor slower so it has more time to react to the encoder feedback.
You also don’t need to continuously set the speed of the motor, just turn it on at the start and then turn it off when finished
/* Encoder Library - Basic Example
http://www.pjrc.com/teensy/td_libs_Encoder.html
This example code is in the public domain.
*/
#include <Encoder.h>
#include "DualTB9051FTGMotorShield.h"
DualTB9051FTGMotorShield md;
unsigned long int newPosition = 0;
unsigned long int oldPosition = 0;
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
Encoder myEnc(3, 2);
// avoid using pins with LEDs attached
void setup() {
Serial.begin(115200);
Serial.println("Basic Encoder Test:");
md.init(); // Initialize the motor driver
md.enableDrivers();
}
void loop() {
const unsigned long number = 1500;
Serial.println("Moving");
md.setM1Speed(100);
while ( newPostion < number ) {
newPosition = myEnc.read();
if (newPosition != oldPosition) {
oldPosition = newPosition;
Serial.println(newPosition);
}
}
md.setM1Speed(0);
Serial.println("Done");
}
So with some minor tweeks to what you provided works accurately:
/* Encoder Library - Basic Example
http://www.pjrc.com/teensy/td_libs_Encoder.html
This example code is in the public domain.
*/
#include <Encoder.h>
#include "DualTB9051FTGMotorShield.h"
DualTB9051FTGMotorShield md;
unsigned long int newPosition = 0;
unsigned long int oldPosition = 0;
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
Encoder myEnc(3, 2);
// avoid using pins with LEDs attached
void setup() {
Serial.begin(115200);
Serial.println("Basic Encoder Test:");
md.init(); // Initialize the motor driver
md.enableDrivers();
}
void loop() {
const unsigned long number = 1500;
if ( newPosition < number ) {
md.setM1Speed(100);
newPosition = myEnc.read();
if (newPosition != oldPosition) {
oldPosition = newPosition;
Serial.println(newPosition);
}
}
md.setM1Speed(0);
}
There are a couple things here that I’d rather not do if possible but in all my testing I haven’t found a way for it to work. I’d rather not have the motor controls in the main loop and currently the one IF statement turns off the encoder count after “number” reaches its goal so it does not track any motor over run which I would like it to.
I am following your example...where you placed the motor controls in loop()...I did move the "md.setM1Speed(100);" line inside the if statement because if you don't do that the motor never turns off...
Sure it does. And then it prints "Done" on the Serial Monitor. Of course, loop() repeats so the entire process starts over again, but it most certainly does turn off. If you only want to do this once as a demonstration, you can always move all this code into setup() or add this at the end of loop
OK, so it looks like you answered your question of why it is being called over and over again. I am still looking for direction on my original questions:
There are a couple things here that I’d rather not do if possible but in all my testing I haven’t found a way for it to work. I’d rather not have the motor controls in the main loop and currently the one IF statement turns off the encoder count after “number” reaches its goal so it does not track any motor over run which I would like it to.
You are absolutely correct. I will be dealing with the overrun once I’m able to accurately count the encoder(without missing steps or duplicating counts) while operating the motor outside of the loop(). Any thoughts on how to accomplish that? All my attempts to control the motor in a separate function while using this library causes the encoder count to miss steps...(see original post). Blh64 was able to show a way to have it count accurately but only when everything is in loop() which isn’t practical unfortunately.
Having it inside loop() has nothing to do with it. I simply put it there to make it smaller and easier.
/* Encoder Library - Basic Example
http://www.pjrc.com/teensy/td_libs_Encoder.html
This example code is in the public domain.
*/
#include <Encoder.h>
#include "DualTB9051FTGMotorShield.h"
DualTB9051FTGMotorShield md;
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
Encoder myEnc(3, 2);
// avoid using pins with LEDs attached
void setup() {
Serial.begin(115200);
Serial.println("Basic Encoder Test:");
md.init(); // Initialize the motor driver
md.enableDrivers();
}
void loop() {
for ( int i = 50; i <= 400; i += 50) {
Turn( 1500, i);
delay(1000);
}
for ( int i = -50; i >= -400; i -= 50) {
Turn( 1500, i);
delay(1000);
}
}
void Turn(const unsigned long count, const int speed) {
myEnc.write(0);
Serial.println("Moving "); Serial.print(count); Serial.print(" steps at speed "); Serial.println(speed);
md.setM1Speed(speed);
while ( myEnc.read() < count) {
// keep looping until done
}
md.setM1Speed(0);
Serial.print("Done with final count of "); Serial.println(myEnc.read());
}
See what this code produces and it may show you how much overrun you are getting vs. speed
This was a great test case. I ran your code as you posted it and recieved the following output:
Basic Encoder Test:
Moving
1500 steps at speed 50
Done with final count of 1500
Moving
1500 steps at speed 100
Done with final count of 1500
Moving
1500 steps at speed 150
Done with final count of 1500
Moving
1500 steps at speed 200
Done with final count of 1501
Moving
1500 steps at speed 250
Done with final count of 1501
Moving
1500 steps at speed 300
Done with final count of 1502
Moving
1500 steps at speed 350
Done with final count of 1502
Moving
1500 steps at speed 400
Done with final count of -1
Moving
1500 steps at speed -50
Done with final count of -1
Moving
1500 steps at speed -100
Done with final count of -1
Moving
1500 steps at speed -150
Done with final count of -1
Moving
1500 steps at speed -200
Done with final count of -1
Moving
1500 steps at speed -250
Done with final count of -1
Moving
1500 steps at speed -300
Done with final count of -1
Moving
1500 steps at speed -350
Done with final count of -1
Moving
1500 steps at speed -400
Done with final count of -1
Moving
1500 steps at speed 50
Done with final count of 1500
Moving
1500 steps at speed 100
Done with final count of 1501
Moving
1500 steps at speed 150
Done with final count of 1500
Moving
1500 steps at speed 200
Done with final count of 1501
Moving
1500 steps at speed 250
Done with final count of 1501
Moving
1500 steps at speed 300
Done with final count of 1502
Moving
1500 steps at speed 350
Done with final count of 1503
Moving
1500 steps at speed 400
Done with final count of 1503
Moving
1500 steps at speed -50
Done with final count of -1
Moving
1500 steps at speed -100
Done with final count of -1
Moving
1500 steps at speed -150
Done with final count of -1
Moving
1500 steps at speed -200
Done with final count of -1
Moving
1500 steps at speed -250
Done with final count of -1
Moving
1500 steps at speed -300
Done with final count of -1
Moving
1500 steps at speed -350
Done with final count of -1
Moving
1500 steps at speed -400
Done with final count of -1
Moving
1500 steps at speed 50
Done with final count of 1500
Moving
1500 steps at speed 100
Done with final count of 1501
Moving
1500 steps at speed 150
Done with final count of 1500
Moving
1500 steps at speed 200
Done with final count of 1501
Moving
1500 steps at speed 250
Done with final count of 1501
Moving
1500 steps at speed 300
Done with final count of 1502
Moving
1500 steps at speed 350
It looks as if it is fairly accurate when looking at the outputted count but I notice that the motor turns drastically different amounts each time which makes me think the count is not actually accurate which is what I was observing before but maybe it is something else? When I try to output the count for every encoder tick, like in my first example, there is double counting and missing numbers.
Back to reply#8 - wrong motor for the job. If you need exact steps, use a stepper motor. Doing Serial.print() every time an encoder ticks takes a ton of time vs. the time to increment the encoder.