Control de motor paso a paso con un ESP32 PLC

Cómo controlar un motor paso a paso con un driver y las salidas PWM del ESP32 PLC
15 de junio de 2026 por
Control de motor paso a paso con un ESP32 PLC
Boot & Work Corp. S.L, Ricard Franch Argullol

En este artículo veremos cómo controlar un motor paso a paso usando un ESP32 PLC. Cubriremos los fundamentos de los motores paso a paso, sus características y cómo funcionan en combinación con un driver controlado por las salidas PWM de un ESP32 PLC. El motor y el driver utilizados son el 17HS16-2004S y el TB6600, respectivamente.

Cómo funcionan los motores paso a paso

Los motores paso a paso son dispositivos electromecánicos que convierten señales eléctricas en movimientos mecánicos precisos. A diferencia de los motores convencionales que giran de forma continua, los motores paso a paso se mueven en pasos discretos. Esto los hace ideales para aplicaciones que requieren un control preciso de posición, velocidad y par.

Los pasos discretos corresponden a un desplazamiento angular fijo conocido como ángulo de paso, determinado por el diseño del motor y medido en grados. Los motores paso a paso pueden tener diferentes ángulos de paso, como 1,8° (200 pasos por revolución) o 0,9° (400 pasos por revolución). El 17HS16-2004S usa 200 pasos por revolución.

Tres señales controlan un motor paso a paso: pulso, dirección y habilitación. La señal de pulso determina la frecuencia de paso, la señal de dirección establece el sentido de rotación (horario o antihorario) y la señal de habilitación activa o desactiva el motor. Controlar el tiempo y la secuencia de estas señales permite un posicionamiento y una rotación precisos.

Estas señales no pueden enviarse al motor directamente; se necesita un driver. El driver recibe señales de control de un controlador como un microcontrolador o un PLC y proporciona la potencia y corriente necesarias a las bobinas del motor. Los drivers de motores paso a paso ofrecen características como diferentes modos de control (paso completo, medio paso, micropaso), regulación de corriente y mecanismos de protección. El TB6600 usado en este ejemplo admite hasta 32 micropasos y puede suministrar hasta 4 A de corriente.

Especificaciones del motor NEMA 17 17HS16-2004S

El motor NEMA 17 17HS16-2004S tiene las siguientes especificaciones eléctricas:

Especificación eléctrica
Bipolar/Unipolar Bipolar
Par de retención 0,45 Nm
Inductancia 2,6 mH
Resistencia de fase 1,1 Ohm
Corriente nominal 2 A
Angulo de paso 1,8°

Configuración del driver de micropaso TB6600

El TB6600 admite múltiples modos según la configuración de micropaso y corriente:

  • Micropasos: 1, 2, 4, 8, 16, 32
  • Corriente (A): 0,5, 1,0, 1,5, 2,0, 2,5, 3,0, 3,5

Para seleccionar los micropasos y la corriente, el driver tiene 6 interruptores DIP. Una tabla en la carcasa del driver muestra la combinación correcta de on/off para cada modo.

Cableado del ESP32 PLC al driver TB6600

Las siguientes conexiones son necesarias para controlar el motor paso a paso desde el ESP32 PLC.

Conexiones del motor al TB6600

  • Azul --> A-
  • Rojo --> A+
  • Negro --> B-
  • Verde --> B+

Configuración de pines del ESP32 PLC

  • Q0.0 --> PUL+
  • Q0.1 --> DIR+
  • Q0.2 --> ENA+
  • GND --> PUL-, DIR-, ENA-

Las salidas del ESP32 PLC deben configurarse a 5 V: conecta QVdc a 5 V y COM(-) a GND. La misma fuente de alimentación de 12-24 V puede usarse tanto para el ESP32 PLC como para el TB6600.

Diagrama de cableado

Diagrama de cableado del motor paso a paso con ESP32 PLC

Sketches de Arduino para el ESP32 PLC

Para programar el ESP32 PLC necesitas el paquete Industrial Shields ESP32 instalado en el IDE de Arduino. Ambos sketches requieren la librería Adafruit PWM Servo Driver para generar las señales PWM.

Adafruit PWM Servo Driver Library

Las salidas PWM del ESP32 PLC admiten frecuencias entre 24 Hz y 1526 Hz, lo que limita las velocidades disponibles del motor según la configuración de micropaso.

Salidas PWM del ESP32 PLC

Movimiento a velocidad constante

Este sketch hace que el motor realice movimientos a velocidad constante.

Primero, define la configuración física: pines usados, pasos del motor y configuración de micropaso. En este ejemplo se usan Q0.0, Q0.1 y Q0.2 para las señales de paso, dirección y habilitación respectivamente, aunque puede usarse cualquier salida PWM del ESP32 PLC. La macro STEPS_REV calcula los pasos totales por revolución basados en los pasos del motor y la configuración de micropaso del driver, lo que es útil para los cálculos de velocidad.

La función move_to() recibe una distancia en revoluciones, positiva o negativa según la dirección deseada, y calcula el tiempo que el motor debe funcionar a la velocidad objetivo para recorrer esa distancia.

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

#define DEBUG 1

#define STEP_PIN Q0_0
#define DIR_PIN Q0_1
#define ENA_PIN Q0_2

#define STEPS 200
#define MICROSTEPS 2
#define STEPS_REV (STEPS * MICROSTEPS)

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);

float target_speed; // RPM

void setup_motor(void) {

pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(ENA_PIN, OUTPUT);

pwm.begin();
pwm.setPWMFreq(1500);
pwm.setPWM(STEP_PIN, 0, 2048);

digitalWrite(ENA_PIN, HIGH);

}

void set_speed_rpm(float rpm) {

pwm.setPWMFreq((uint16_t)((rpm/60)*STEPS_REV));

#if DEBUG
Serial.print("set_speed_rmp: freq = ");
Serial.println((uint16_t)((rpm/60)*STEPS_REV));
#endif

}

void move_to(float dist) {

unsigned long init_time;
unsigned long expected_time;

expected_time = abs(dist)*1000*60./target_speed;

#if DEBUG
Serial.print("move_to: expected_time = ");
Serial.println(expected_time);
#endif

set_speed_rpm(target_speed);

digitalWrite(DIR_PIN, dist >= 0 ? HIGH : LOW);
digitalWrite(ENA_PIN, LOW);
init_time = millis();

while ((millis() - init_time) < expected_time);

digitalWrite(ENA_PIN, HIGH);

#if DEBUG
Serial.print("Time: ");
Serial.println(millis() - init_time);
#endif

}

void setup() {

Serial.begin(115200);
setup_motor();

}

void loop() {

target_speed = 50;
move_to(1.45);
delay(100);
move_to(-1.45);
delay(100);

}

Movimiento con aceleración

Este sketch mueve el motor aplicando aceleración y deceleración al inicio y al final de cada movimiento.

En lugar de calcular un tiempo de movimiento fijo, el programa recalcula la distancia recorrida a intervalos fijos de 30 ms. La función calculate_speed() devuelve la velocidad a la que debe girar el motor en cada momento, basada en los perfiles de aceleración y deceleración calculados al inicio por calculate_accel(). De este modo la velocidad se ajusta cada 30 ms. Según el valor de aceleración, el movimiento puede no ser perfectamente suave, ya que la velocidad puede variar significativamente en 30 ms debido al límite de frecuencia de actualización de los chips de expansión interna del ESP32 PLC.

Dentro del bucle principal, la distancia recorrida se actualiza cada 30 ms en función de la velocidad actual, lo que permite al programa rastrear la posición del motor y realizar movimientos de distancia fija.

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

#define DEBUG 1

#define STEP_PIN Q0_0
#define DIR_PIN Q0_1
#define ENA_PIN Q0_2

#define STEPS 200
#define MICROSTEPS 2
#define STEPS_REV (STEPS * MICROSTEPS)
#define MIN_SPEED 24 // steps/s

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);

float distance; // Revoluciones
float acceleration = 50000; // RPM^2
float target_speed; // RPM

void setup_motor(void) {

pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(ENA_PIN, OUTPUT);

pwm.begin();
pwm.setPWMFreq(1500);
pwm.setPWM(STEP_PIN, 0, 2048);

digitalWrite(ENA_PIN, HIGH);

}

void set_speed_rpm(float rpm) {

pwm.setPWMFreq((rpm/60)*STEPS_REV);

#if DEBUG
Serial.print("set_speed_rmp: freq = ");
Serial.println((rpm/60)*STEPS_REV);
#endif

}

float calculate_accel_dist(void) {

float acel_time = target_speed / acceleration;
float acel_dist = 0.5 * acceleration * pow(acel_time, 2);

if ( distance < (acel_dist * 2)) {
target_speed = sqrt( acceleration * distance );
acel_time = target_speed / acceleration ;
acel_dist = 0.5 * acceleration *pow(acel_time, 2);
}

return acel_dist;
}

float calculate_speed(float current_pos, float accel_dist) {

float speed = MIN_SPEED;
float accel_step = accel_dist * STEPS_REV;

if (current_pos <= accel_step) {
speed = sqrt(2 * (acceleration * STEPS_REV / 3600) * current_pos);
}
else if ((distance * STEPS_REV - current_pos ) <= (accel_step)) {
speed = sqrt(2 * (acceleration * STEPS_REV / 3600) * (distance * STEPS_REV - current_pos));
}
else {
speed = target_speed * STEPS_REV / 60;
}

if (speed < MIN_SPEED) speed = MIN_SPEED;

return speed;
}

void move_to(float dist) {

unsigned long init_time;
unsigned long current_time;

distance = abs(dist);

float accel_dist = calculate_accel_dist();
float time = 0;
float current_pos = 0;
float final_pos = distance * STEPS_REV;
float current_speed = 0;
float new_speed;
float time_delay = 30;

digitalWrite(DIR_PIN, dist >= 0 ? HIGH : LOW);
digitalWrite(ENA_PIN, LOW);
init_time = millis();

while (current_pos < final_pos) {
current_time = millis() - init_time;
new_speed = calculate_speed(current_pos, accel_dist);

if (new_speed != current_speed) {
set_speed_rpm(new_speed * 60 / STEPS_REV);
current_speed = new_speed;
}

delay(time_delay);
time += time_delay;
current_pos = current_pos + (current_speed * time_delay / 1000);
}

digitalWrite(ENA_PIN, HIGH);

}

void setup() {
Serial.begin(115200);
setup_motor();
}

void loop() {
target_speed = 100;
move_to(1);
delay(10);
move_to(-1);
delay(10);
}

Buscar en nuestro blog

Control de motor paso a paso con un ESP32 PLC
Boot & Work Corp. S.L, Ricard Franch Argullol 15 de junio de 2026
Compartir esta publicación
Etiquetas

¿Estás buscando tu Controlador Lógico Programable ideal?

Echa un vistazo a esta comparativa de producto de varios controladores industriales basados en Arduino.

Comparamos entradas, salidas, comunicaciones y otras especificaciones con las de los equipos de otras marcas destacadas.

Comparativa de PLCs