Hi Everyone,
I am new to Arduino and am looking to read correctly the input from a optical incremental encoder that comes attached to the motor. I use this closed loop stepper motor for reading the integrated encoder from it.
The encoder has 4 outputs EA+, EA-, EB+ and EB-. I am making use of the EA+ and EB+ outputs as read on multiple output forums for reading the output.
Below is the code I am trying to run where I define the home position(using an end stop) of the slider attached on a ball screw which is connected to the above mentioned motor. Then I make it move 2200 steps and then back to the 0 position. I continue this infinitely just for testing. However I don't get an equivalent number from the encoder suggesting 2200 steps have been moved. The encoder resolution is 4000 Counts per Revolution and the motor is rated at 200 steps per revolution (no micro stepping being used). So theoretically this means 1 motor step is equal to 20 encoder counts. However, I am not getting the right output numbers. Your help in this regard will be highly appreciated.
#include <digitalWriteFast.h>
// Pin Definitions
#define dirPin 9 // Direction pin for the DM542
#define pulsePin 6 // Pulse pin for the DM542
#define limitSwitchPin 5 // Limit switch pin
#define ENCODER_A_PIN 2 // EA+
#define ENCODER_B_PIN 3 // EB+
//#define LeftEncoderIsReversed
volatile float count = 0;
float grades=0; /*variable to store converted value*/
// Motor and screw parameters
const float screwPitch = 5.0; // Ball screw pitch in mm/revolution
const int stepsPerRevolution = 200; // Motor steps per revolution
const int microstepping = 1; // Microstepping factor (e.g., 8x, 16x)
const int stepsPerMM = (stepsPerRevolution * microstepping) / screwPitch;
// Variables for position tracking
long currentPosition = -1; // Current position in steps (-1 indicates uncalibrated)
long targetPosition = 0; // Target position in steps
//volatile long EncoderCurrentPosition = 0; // Current position from encoder feedback
// Define constants based on encoder and motor specs
#define ENCODER_PPR 1000 // Counts per revolution (from encoder datasheet)
// Calculate derived constants
#define ENCODER_COUNTS_PER_REV (ENCODER_PPR * 4) // Quadrature decoding
#define STEPS_PER_REV (stepsPerRevolution * microstepping)
#define ENCODER_COUNTS_PER_STEP (ENCODER_COUNTS_PER_REV / STEPS_PER_REV)
// Loop count
int counter = 1;
// Motor control parameters
unsigned int stepDelay = 500; // Microseconds between pulses (adjust for speed)
const unsigned long holdTime = 15000; // Time to hold at target position in ms (15 seconds)
const unsigned long HomeHoldTime = 7000; // Time to hold at home position in ms (7 seconds)
void setup() {
// Set pin modes
pinMode(pulsePin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(limitSwitchPin, INPUT_PULLUP); // Enable internal pull-up for limit switch
// Encoder pins
pinMode(ENCODER_A_PIN, INPUT);
pinMode(ENCODER_A_PIN, INPUT);
// encoder pin on interrupt 3 (pin 20)
attachInterrupt(digitalPinToInterrupt(ENCODER_A_PIN), doA, CHANGE);
// encoder pin on interrupt 2 (pin 21)
attachInterrupt(digitalPinToInterrupt(ENCODER_B_PIN), doB, CHANGE);
// Initialize outputs
digitalWrite(pulsePin, LOW);
digitalWrite(dirPin, LOW);
// Debugging
Serial.begin(9600);
Serial.println("Stepper Motor with Calibration and Position Control Initialized.");
// Perform calibration
calibrateToHome();
delay(HomeHoldTime);
}
void loop() {
// Test run: Move to 100 mm (10 cm), hold, and return to home
static bool taskCompleted = false;
if (!taskCompleted) {
moveToTargetPosition(55); // Move to 55 mm which is 2200 motor steps as the pitch of the ball screw is 5 mm
//currentPosition += ENCODER_COUNTS_PER_STEP;
// Confirm the final position
Serial.print("Current Encoder Position: ");
Serial.println(count/20.0);
delay(holdTime); // Wait at the target position
moveToTargetPosition(0); // Return to home
//currentPosition -= ENCODER_COUNTS_PER_STEP;
// Confirm the final position
Serial.print("Current Encoder Position: ");
Serial.println(count/20.0);
delay(HomeHoldTime); // Wait at Home position
//taskCompleted = true; // Ensure it doesn't repeat indefinitely
Serial.println("Task " + String(counter) + " completed");
counter = counter + 1;
}
}
// Function to calibrate to the home position (limit switch)
void calibrateToHome() {
Serial.println("Calibrating to home position...");
// Move towards the limit switch until it is pressed
digitalWrite(dirPin, LOW); // Set direction towards home
while (digitalRead(limitSwitchPin) == HIGH) {
// Generate step pulses
digitalWrite(pulsePin, HIGH);
delayMicroseconds(stepDelay);
digitalWrite(pulsePin, LOW);
delayMicroseconds(stepDelay);
}
// Stop motor and set current position to 0
currentPosition = 0;
count = 0;
//EncoderCurrentPosition = 0;
//_LeftEncoderTicks = 0;
Serial.println("Home position reached. Position set to 0 both Arduino and Encoder.");
}
// Function to move to a specific target position in mm
void moveToTargetPosition(float positionInMM) {
// Convert the target position to steps
targetPosition = positionInMM * stepsPerMM;
// Determine direction
digitalWrite(dirPin, targetPosition > currentPosition ? HIGH : LOW);
// Calculate the number of steps to move
long stepsToMove = abs(targetPosition - currentPosition);
// Generate pulses to move the motor
for (long i = 0; i < stepsToMove; i++) {
digitalWrite(pulsePin, HIGH);
delayMicroseconds(stepDelay);
digitalWrite(pulsePin, LOW);
delayMicroseconds(stepDelay);
}
// Update the current position
currentPosition = targetPosition;
Serial.print("Moved to position (steps from Arduino): ");
Serial.println(currentPosition);
}
// Interrupt service routine for encoder A signal
void doA(){
// look for a low-to-high on channel A
if (digitalRead(ENCODER_A_PIN) == HIGH) {
// check channel B to see which way encoder is turning
if (digitalRead(ENCODER_B_PIN) == LOW) {
count = count + 1; // CW
}
else {
count = count - 1; // CCW
}
}
else // must be a high-to-low edge on channel A
{
// check channel B to see which way encoder is turning
if (digitalRead(ENCODER_B_PIN) == HIGH) {
count = count + 1; // CW
}
else {
count = count - 1; // CCW
}
}
}
void doB(){
// look for a low-to-high on channel B
if (digitalRead(ENCODER_B_PIN) == HIGH) {
// check channel A to see which way encoder is turning
if (digitalRead(ENCODER_A_PIN) == HIGH) {
count = count + 1; // CW
}
else {
count = count - 1; // CCW
}
}
// Look for a high-to-low on channel B
else {
// check channel B to see which way encoder is turning
if (digitalRead(ENCODER_A_PIN) == LOW) {
count = count + 1; // CW
}
else {
count = count - 1; // CCW
}
}
}
The output I get is as follows:
Calibrating to home position...
Stepper Motor with Calibration and Position Control Initialized.
Calibrating to home position...
Home position reached. Position set to 0 both Arduino and Encoder.
Moved to position (steps from Arduino): 2200
Current Encoder Position: -1126.25
Moved to position (steps from Arduino): 0
Current Encoder Position: -4004.35
Task 1 completed
Moved to position (steps from Arduino): 2200
Current Encoder Position: -5374.00
Moved to position (steps from Arduino): 0
Current Encoder Position: -8360.30
Task 2 completed
Moved to position (steps from Arduino): 2200
Current Encoder Position: -9593.75
These number don't make sense to me even if we consider the absolute value.