Smooth Stepper Motor Control with ESP32
Controlling a stepper motor precisely is crucial in many applications, from 3D printers to CNC machines.
The ESP32, with its dual-core architecture, offers an excellent opportunity to handle real-time stepper motor control and other logic simultaneously without compromising performance.
In this article, we will explore how to achieve smooth stepper motor control by using FreeRTOS tasks and separate cores on the ESP32.
Why Use Separate Cores?
The ESP32 features two Xtensa LX6 microprocessor cores. By assigning the stepper motor control to one core and the other logic to the second core, we can ensure that the motor runs smoothly without being interrupted by other tasks.
This setup minimizes jitter and enhances the reliability of the stepper motor movements.
Hardware Setup
First, ensure you have the following components,
- ESP32 development board
- Stepper motor
- Stepper motor driver (e.g., A4988/ DRV8825/TB6600)
- Power supply
- Jumper Wires
Wiring
Software Implementation
Let’s break down the code to control the stepper motor using FreeRTOS tasks on the ESP32.
Complete Code
// Define pin numbers
#define stepPin 16
#define dirPin 17
#define enablePin 18
// Stepper settings
const int stepsPerRevolution = 1600;
const int gearRatio = 80;
const int stepsPerDegree = (stepsPerRevolution * gearRatio) / 360;
const float wheelRPM = 3;
const long stopDuration = 400;
bool stepperMoving = false;
long steps = 12800;
unsigned long lastStepperMoveTime = 0;
// FreeRTOS Task Handle
TaskHandle_t StepperTaskHandle = NULL;
void setup() {
Serial.begin(9600);
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enablePin, OUTPUT);
// Set direction and enable stepper motor
digitalWrite(dirPin, HIGH);
digitalWrite(enablePin, LOW); // LOW to enable
// Create a task for stepper control on core 0
xTaskCreatePinnedToCore(
stepperControl,
"StepperControlTask",
10000,
NULL,
1,
&StepperTaskHandle,
0
);
}
void loop() {
// Placeholder for your logic to set `stepperMoving` and `steps`
// For demonstration, we will just move the stepper every 10 seconds
if (millis() - lastStepperMoveTime > 10000) {
stepperMoving = true;
steps = 12800; // Example steps
lastStepperMoveTime = millis();
}
}
void moveStepper(long steps) {
digitalWrite(enablePin, LOW); // Enable stepper motor
for (long i = 0; i < steps; i++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(156); // Adjust delay as needed
digitalWrite(stepPin, LOW);
delayMicroseconds(156);
if (i % 1000 == 0) {
vTaskDelay(1); // Yield to other tasks
}
}
digitalWrite(enablePin, HIGH); // Disable stepper motor
}
void stepperControl(void * parameter) {
for (;;) {
if (stepperMoving) {
moveStepper(steps);
stepperMoving = false; // Stop the stepper after moving the required steps
} else {
vTaskDelay(1); // Yield to other tasks
}
}
}
Let’s discuss on the code now,
Define Pin Numbers and Stepper Settings
We start by defining the pin numbers and stepper motor settings.
#define stepPin 16
#define dirPin 17
#define enablePin 18
const int stepsPerRevolution = 1600;
const int gearRatio = 80;
const int stepsPerDegree = (stepsPerRevolution * gearRatio) / 360;
const float wheelRPM = 3;
const long stopDuration = 400;
bool stepperMoving = false;
long steps = 12800;
unsigned long lastStepperMoveTime = 0;
TaskHandle_t StepperTaskHandle = NULL;
Setup Function
In the ‘setup’ function, we initialize the serial communication and configure the GPIO pins. We also create a FreeRTOS task to handle stepper motor control on core 0.
void setup() {
Serial.begin(9600);
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enablePin, OUTPUT);
digitalWrite(dirPin, HIGH);
digitalWrite(enablePin, LOW);
xTaskCreatePinnedToCore(
stepperControl,
"StepperControlTask",
10000,
NULL,
1,
&StepperTaskHandle,
0
);
}
Main Loop
In the ‘loop’ function, we can place the logic to control when the stepper motor should move. For demonstration purposes, we will move the stepper motor every 10 seconds.
In this loop, you can add the logic for the other functionalities.
void loop() {
if (millis() - lastStepperMoveTime > 10000) {
stepperMoving = true;
steps = 12800;
lastStepperMoveTime = millis();
}
}
Move Stepper Function
The ‘moveStepper’ function handles the actual movement of the stepper motor. It ensures smooth operation by inserting delays. The delay will be responsible for the speed of the motor.
void moveStepper(long steps) {
digitalWrite(enablePin, LOW);
for (long i = 0; i < steps; i++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(156);
digitalWrite(stepPin, LOW);
delayMicroseconds(156);
if (i % 1000 == 0) {
vTaskDelay(1);
}
}
digitalWrite(enablePin, HIGH);
}
Step 5: Stepper Control Task
The ‘stepperControl’ function runs as a FreeRTOS task on core 0. It continuously checks if the stepper motor needs to move and calls the ‘moveStepper’ function accordingly.
void stepperControl(void * parameter) {
for (;;) {
if (stepperMoving) {
moveStepper(steps);
stepperMoving = false;
} else {
vTaskDelay(1);
}
}
}
Conclusion
By utilizing FreeRTOS tasks and the dual-core architecture of the ESP32, we can achieve smooth and reliable stepper motor control. This approach ensures that the motor movements are not interrupted by other tasks, leading to precise and accurate positioning.
With this setup, you can expand the functionality of your project by adding more complex logic and operations on the second core, making full use of the ESP32’s capabilities.
Feel free to customize the code to fit your specific application needs.
Contact us for any consultations or projects related to any Stepper.
Email: udara@protonest.co
Protonest for more details.
Protonest specializes in transforming IoT ideas into reality. We offer prototyping services from concept to completion. Our commitment ensures that your visionary IoT concepts become tangible, innovative, and advanced prototypes.
Our Website: https://www.protonest.co/
If you enjoyed this article and would like to show some support, consider buying me a coffee on Ko-Fi.
Your support not only helps me keep creating content like this but also fuels me! ☕️📚
Thank you for being an amazing reader!
Here’s my Ko-Fi link: https://ko-fi.com/udarakumarasena
Cheers!