The project I'm working on uses a drive shaft which is driven — only some of the time — by a 24v brushed DC motor. This shaft's positions is also recordered using a 600p/r optical encoder.
Now when the motor is not running, the encoder works seamlessly with perfect precision. However, when the motor is running, the encoder's value becomes corrupted by up to a 10 steps per revolution (this progressivley becomes worse with each revolution until eventually it's obvious that the value has become corrupted as some point).
My initial thoughts were that the motor was causing electrical noise / interference with encoder hence why the encoder only malfunctions during motor operation. I carried out the following practices to eliminate this:
- Not routing any high voltage wiring alongside or near the encoder wiring
- Grounding the one end of the shield wire that runs along the rest of the encoder wires
- Installing a 1uf ceramic capacitor across the terminals of the motor
With the fault still present, I disconnected the chain that links the motor to the shaft and ran the motor off a seperate power source (isolating it, so it's no longer being controlled by the microcontroller). Then I manually spun the shaft and montiored the encoder value to see if any interference was being created by the motor. The result: the encoder was working fine again.
This leads me to beleive that the root cause is not inteference being induced into the encoder wiring, otherwise the fault would have been present during the above test. And so it could be something to do with my code instead?
Board: ESP32
Motor: 24v Motor (rated at 18.5a but consumes about 8amps when under full load in my application)
Encoder
[Solid State Relays](http://www.photosensor.com.tw/Solid State Relay/Single Phase Solid State Relay (DC to DC SSR)/SSR-10DD.htm)
Voltage regulator
Motor driver
#define BLYNK_PRINT Serial
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
BlynkTimer timer;
char auth[] = "removed";
// WiFi credentials.
char ssid[] = "removed";
char pass[] = "removed";
// Optical Encoder
const int CLK = 22; // White
const int DT = 23; // Green
volatile unsigned int temp, counter = 500; // Encoder value starts at 500 instead of 0
// 24v motor
const int relayPin = 13; //SSR used to creat open circuit when motor is off
const int ledpin = 12;
const int DCdir = 14;
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 8;
// Connections to A4988
const int dirPin = 4; // Direction
const int stepPin = 2; // Step
const int enablePin = 15;
// Motor steps per rotation
int STEPS_PER_REV = 20720; // CHANGE TO for old stepper motor. This equals 1 turn 1036
boolean Trigger = false; // FOr when stepper is released / engaged as part of programme
boolean Trigger2 = false; // For when stepper is operated via phone
int conValue; // Used to keep track of stepper motor position
byte oldconValue;
void setup()
{
// Debug console
Serial.begin(115200);
Blynk.begin(auth, ssid, pass); // for if you want to specify server. See Blynk website for more info
// Setup a function to be called. In this case every 200milliseconds.
timer.setInterval(200L, myTimerEvent);
//Setting up input pins + interrupts for optical encoder
pinMode(CLK, INPUT_PULLUP);
pinMode(DT, INPUT_PULLUP);
attachInterrupt(DT, ai0, RISING);
attachInterrupt(CLK, ai1, RISING);
ledcSetup(ledChannel, freq, resolution);
ledcAttachPin(ledpin, ledChannel);
pinMode(stepPin,OUTPUT);
pinMode(dirPin,OUTPUT);
pinMode(enablePin,OUTPUT);
pinMode(relayPin, OUTPUT);
}
void loop()
{
Blynk.run();
timer.run(); //Initiates Blynk timer
noInterrupts();
int count_copy = counter; // Protects the varible from corruption by stopping interupts.
interrupts();
count_copy = constrain(count_copy, 0, 2000);
if( count_copy != temp ){
Serial.println(count_copy);
temp = count_copy;
}
if(count_copy > 1500){ // UPPER THRESHOLD (turn 24v motor on)
digitalWrite(relayPin, HIGH); // Enable motore control via solid state relay
digitalWrite(DCdir, LOW); // Set motor direction
ledcWrite(ledChannel, 155); // Motor on
if (Trigger == false){ // Release caliper. The if Trigger ensures this is only done once.
digitalWrite(enablePin, LOW);
for(int x = 0; x < (STEPS_PER_REV / 360 * conValue); x++) {
// Set motor direction counterclockwise
digitalWrite(dirPin,LOW);
digitalWrite(stepPin,HIGH);
delayMicroseconds(500);
digitalWrite(stepPin,LOW);
delayMicroseconds(500);
}
digitalWrite(enablePin, HIGH);
Trigger = true; // Set trigger to True
}
}
if(count_copy < 600 && Trigger == true){ // LOWER THRESHOLD (turn 24v motor off)
ledcWrite(ledChannel, 0); // Motor off
digitalWrite(relayPin, LOW); // Disable motor control
//Code for reapplying stepper motor.
digitalWrite(enablePin, LOW); // Enable stepper motor
for(int x = 0; x < (STEPS_PER_REV / 360 * conValue); x++) {
digitalWrite(dirPin,HIGH); // Set stepper motor direction counterclockwise
digitalWrite(stepPin,HIGH);
delayMicroseconds(500);
digitalWrite(stepPin,LOW);
delayMicroseconds(500);
}
digitalWrite(enablePin, HIGH); //Disable stepper motor
Trigger = false;
repCountOnce = true;
}
}
void ai0() {
if(digitalRead(CLK)==LOW) {
counter++;
}else{
counter--;
}
}
void ai1() {
if(digitalRead(DT)==LOW) {
counter--;
}else{
counter++;
}
}
void myTimerEvent()
{
// Send info to Blynk app. You can send any value at any time. But do not send more than 10 values per second.
Blynk.virtualWrite(V0, count_copy);
}