I have read the FAQ on asking questions and done my own research to solve this problem but come up short. I now ask for your help. Please let me know if I break etiquette or have missed something obvious. We are using an Arduino Uno along with the following:
Hardware: Pololu 12V motor https://www.pololu.com/product/3218
Hardware: Pololu MC33926 Motor Shield https://www.pololu.com/product/2503
MotorShield Library: https://github.com/pololu/dual-mc33926-motor-shield
My target goal is to read the encoders on both of these motors simultaneously to determine RPM for each of them as quickly as I can in real time. That RPM will then be used to enact rudimentary feedback control in the future. We are encountering the following issue: each motor encoder can determine RPM fine when the other is commented out of the code. However, when used together, the outputs are erroneous.
When I run the code as is, I receive a strange error of one RPM integer count starting low and one starting high, which then proceeds to increase or decrease respectively. Serial monitor output:
Dual MC33926 Motor Shield
56
998
61
783
78
641
However, if I comment out either of the RPM loops (identical code except with either loop 1 or loop 2 commented away), the remaining encoder can successfully determine the RPM of the motor. Motor 1:
Dual MC33926 Motor Shield
56
56
56
56
56
Motor 2:
Dual MC33926 Motor Shield
54
54
54
54
Here is the code:
/*************************************************************
Motor Shield 2-Channel DC Motor Demo
by Randy Sarafan
For more information see:
https://www.instructables.com/id/Arduino-Motor-Shield-Tutorial/
*************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_LSM9DS1.h>
#include <Adafruit_Sensor.h> // not used in this demo but required!
#include <DualMC33926MotorShield.h>
DualMC33926MotorShield md;
void stopIfFault()
{
if (md.getFault())
{
Serial.println("fault");
while (1);
}
}
int inPin = 5; // pushbutton connected to digital pin 5
int inPin2 = 6; // pushbutton connected to digital pin 6
int val1 = 0; // variable to store the read value
int val2 = 0; // variable to store the read value
int val3 = 0; // variable to store the read value
int val4 = 0; // variable to store the read value
//Max K=400 mapped to 255
int k = 200;
int k1 = k;
int k2 = k;
float minute = 0;
int t1 = 0;
int t2 = 0;
int dt = 0;
int rpm = 0;
int count = 0;
int count2 = 0;
void setup() {
//Set up Motor Controller
Serial.begin(9600);
Serial.println("Dual MC33926 Motor Shield");
md.init();
pinMode(inPin, INPUT); // sets the digital pin 5 as input
pinMode(inPin2, INPUT); // sets the digital pin 6 as input
t1 = millis();
}
//Andrew: We can consider using the F() function to utilize flash instead of SRAM for string-only println messages.
//See here: https://www.arduino.cc/reference/en/language/variables/utilities/progmem/
void loop() {
//Motor A forward
md.setM1Speed(k1);
stopIfFault();
Serial.print(F("M1 current: "));
Serial.println(md.getM1CurrentMilliamps());
//Motor B backward
md.setM2Speed(-k2);
stopIfFault();
Serial.print(F("M2 current: "));
Serial.println(md.getM2CurrentMilliamps());
//Encoders
val1 = digitalRead(inPin); // read the input pin
val3 = digitalRead(inPin2); // read the input pin
Serial.println(val1);
Serial.println(val2);
//Calculates RPM (corrected indentation)
//Full count is 1800 for one geared revolution
//Loop1
if (val1 != val2) {
count = count + 1;
val2 = val1;
//Serial.print("Count: ");
//Serial.println(count);
if (count == 1800) {
t2 = millis();
dt = t2 - t1;
t1 = t2;
rpm = 60000 / dt;
count = 0;
Serial.print(F("Motor 1 RPM: "));
Serial.println(rpm);
}
}
//Loop2
if (val3 != val4) {
count2 = count2 + 1;
val4 = val3;
//Serial.print("Count2: "); Serial.println(count);
//Full count is 1800 for one geared revolution
if (count2 == 1800) {
t2 = millis();
dt = t2 - t1;
t1 = t2;
rpm = 60000 / dt;
count2 = 0;
Serial.print(F("Motor 2 RPM: ")); Serial.println(rpm);
}
}
}
To save time, I will note the following items that I have researched and explored as potential culprits and solutions:
- Baud. We have experimented with changing the baud rates without seeing difference.
- Printing Strings. This was my initial suspicion as I did research and found that printing strings could be an issue if included at high rates. I removed traditional strings from the code and replaced with F() outputs.
- Printing any statements other than RPM integer. You will note in my output code that there are only the RPM numbers listed as loop output statements. I attempted to isolate prints as the issue without success.
- Faulty Motor hardware. Both motors were ordered brand new. Both display the correct RPM in the serial monitor window when evaluated individually with one of the loops commented out. RPM for output shaft was confirmed visually by inspection of rotation for 30 seconds, multiple times. While each motor is slightly different physically, as expected, both conform closely to target RPM.
- External Library Shenanigans. I looked through the c++ code for the motor shield library and did not see anything which would cause me to believe it was the cause.
Potential Solutions:
- Interrupt Service Routines. I have read a little bit on ISR’s here but I am still uncertain how to structure and proceed with designing this into a dual encoder code.
- Separate Encoder wiring. It was only towards the end of troubleshooting yesterday that I realized my colleague had attempted to save pinspace by splicing both power and ground to the encoders. To be clear, there is one male pin going into the 5V pinspace on the shied which is spliced into two male pins which each connect to the encoder power (blue wire).
- Different Motor Shield. This was chosen specifically because it was designed to run dual Pololu motors. However, if there is another shield with easy layout/mapping to use with Arduino then our lab can probably buy it.
If there is any other helpful information which I can provide, please let me know.