Skip to Content

Tutorial de TB6560 Stepper Motor Driver con Arduino

Tutorial de TB6560 Stepper Motor Driver con Arduino

En este tutorial, aprenderás a controlar un motor paso a paso con el driver microstepping TB6560 y Arduino. Este driver es fácil de usar y puede controlar grandes motores paso a paso como un NEMA 23 de 3 A.

He incluido un diagrama de cableado y 2 códigos de ejemplo. En el primer ejemplo, le mostraré cómo puede utilizar este controlador de motor paso a paso sin una biblioteca de Arduino. En el segundo ejemplo, vamos a echar un vistazo a la biblioteca AccelStepper. Esta biblioteca es bastante fácil de usar y le permite añadir aceleración y desaceleración al movimiento del motor paso a paso.

Después de cada ejemplo, desgloso y explico cómo funciona el código, por lo que no deberías tener problemas para modificarlo y adaptarlo a tus necesidades.

Si quiere saber más sobre otros controladores de motores paso a paso, los artículos siguientes pueden resultarle útiles:

Suministros

Componentes de hardware

Controlador de motor paso a paso TB6560× 1Amazon
Motor paso a pasoMotor paso a paso NEMA 23× 1Amazon
Arduino Uno Rev 3Arduino Uno Rev3× 1Amazon
Alimentación (24 V)× 1Amazon
Cables de puente× 4Amazon
Cable USB tipo A/B× 1Amazon

Herramientas

PelacablesAmazon
Destornillador pequeñoAmazon
Alicates de presión autoajustables (recomendados)*.Amazon
Surtido de casquillos (recomendado)*Amazon

*Hackaday escribió un magnífico artículo sobre las ventajas de utilizar virolas de cable (también conocidas como manguitos finales).

Software

Arduino IDEArduino IDE

Makerguides.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to products on Amazon.com. As an Amazon Associate we earn from qualifying purchases.

Sobre el conductor

El driver de micropasos TB6560 está construido en torno al chip TB6560AHQ de Toshiba y puede utilizarse para accionar motores paso a paso bipolares de dos fases.

Con una corriente máxima de 3 A continuos, el controlador TB6560 puede utilizarse para controlar motores paso a paso bastante grandes, como un NEMA 23. Asegúrese de no conectar al controlador motores paso a paso con una corriente superior a 3 A.

El chip tiene varias funciones de seguridad incorporadas, como la protección contra la sobrecorriente, el apagado por baja tensión y el sobrecalentamiento. Sin embargo, no tiene protección contra la tensión inversa, así que asegúrate de conectar la fuente de alimentación correctamente. Puedes encontrar más especificaciones en la siguiente tabla.

Especificaciones del TB6560

Tensión de funcionamiento10 - 35 VDC, se recomienda 24 VDC
Corriente de salida máxima3 A por fase, 3,5 A de pico
Resolución de micropasoscompleto, 1/2, 1/8 y 1/16
ProtecciónDesconexión por baja tensión, protección contra sobrecalentamiento y sobrecorriente
Dimensiones75 x 50 x 35 mm
Distancia entre agujeros69 x 43 mm, ⌀ 3,5 mm
CosteComprobar el precio

Para más información, puede consultar la hoja de datos/manual que aparece a continuación:

Tenga en cuenta que el TB6560 es un controlador analógico. En los últimos años, los controladores digitales como el DM556 o el DM542 son mucho más asequibles. Los controladores digitales suelen ofrecer un rendimiento mucho mayor y un funcionamiento más silencioso. Pueden ser cableados y controlados de la misma manera que el TB6560, por lo que puede actualizar fácilmente su sistema más adelante.

He utilizado los controladores DM556 para mi router CNC de bricolaje y han funcionado muy bien durante varios años.

TB6560 vs TB6600

Al comprar un controlador de motor paso a paso TB6560, probablemente también se encontrará con el controlador TB6600, ligeramente más caro. Este driver puede ser controlado con el mismo código/cableado, pero hay algunas diferencias clave.

TB6560TB6600
Tensión de funcionamiento10 - 35 VDC, se recomienda 24 VDC9 - 42 VDC, se recomienda 36 VDC
Corriente de salida máxima3 A por fase, 3,5 A de pico3,5 A por fase, 4 A de pico
# Configuración actual148
Resolución de micropasoscompleto, 1/2, 1/8 y 1/16completo, 1/2, 1/4, 1/8, 1/16 y 1/32
Frecuencia del reloj15 kHz200 kHz
CosteComprobar el precioComprobar el precio

Así que las principales diferencias son el mayor voltaje máximo, mayor corriente máxima, y hasta 1/32 microstepping. Si quieres controlar motores paso a paso más grandes o necesitas una mayor resolución, te recomiendo que optes por el TB6600.

Cableado - Conexión del TB6560 al motor paso a paso y al Arduino

El siguiente diagrama de cableado muestra cómo se puede conectar el controlador de motor paso a paso TB6560 al Arduino y a un motor paso a paso.

TB6560-Controlador de motor paso a paso con Arduino-UNO-Diagrama de cableado-Distribución esquemática
Controlador de motor paso a paso TB6560 con Arduino UNO y diagrama de cableado del motor paso a paso

En este tutorial, conectaremos el controlador en una configuración de cátodo común. Esto significa que conectamos todos los lados negativos de las conexiones de la señal de control juntos a tierra.

Las conexiones también se indican en la tabla siguiente:

Conexiones TB6560

TB6560Conexión
VCC10 - 35 VDC
GNDTierra de la fuente de alimentación
ES-No conectado
ES+No conectado
CW-Arduino GND
CW+Pin 2 Arduino
CLK-Arduino GND
CLK+Pin 3 Arduino
A-, A+Bobina 1 motor paso a paso
B-, B+Bobina 2 motor paso a paso

Observe que hemos dejado los pines de habilitación (EN- y EN+) desconectados. Esto significa que el pin de habilitación está siempre BAJO y el driver está siempre habilitado.

¿Cómo determinar el cableado correcto del motor paso a paso?

Si no puedes encontrar la hoja de datos de tu motor paso a paso, puede ser difícil averiguar qué color de cable va donde. Yo uso el siguiente truco para determinar cómo conectar motores paso a paso bipolares de 4 cables:

Lo único que tienes que identificar son los dos pares de cables que se conectan a las dos bobinas del motor. Los cables de una bobina se conectan a A- y A+ y el otro a B- y B+, la polaridad no importa.

Para encontrar los dos cables de una bobina, haga lo siguiente con el motor desconectado:

  1. Intenta hacer girar el eje del motor paso a paso con la mano y fíjate en lo difícil que es girar.
  2. Ahora escoge un par de cables al azar del motor y toca los extremos desnudos entre sí.
  3. A continuación, mientras mantiene los extremos juntos, intente hacer girar el eje del motor paso a paso de nuevo.

Si siente mucha resistencia, ha encontrado un par de cables que está conectado a la misma bobina. El otro par de cables está conectado a la segunda bobina.

Si todavía puede girar el eje libremente, pruebe con otro par de cables. Ahora conecte las dos bobinas a las clavijas que se muestran en el diagrama de cableado anterior.

(Si todavía no está claro, por favor deja un comentario abajo, también se puede encontrar más información en la wiki de RepRap.org)

Ajustes del micropaso TB6560

Los motores paso a paso suelen tener un tamaño de paso de 1,8° o 200 pasos por revolución, esto se refiere a pasos completos. Un driver de micropasos como el TB6560 permite resoluciones más altas al permitir ubicaciones de pasos intermedios. Esto se consigue energizando las bobinas con niveles de corriente intermedios.

Por ejemplo, al conducir un motor en el modo de 1/2 paso, el motor de 200 pasos por revolución dará 400 micropasos por revolución.

Puede cambiar el ajuste de micropasos del TB6560 o el modo de excitación activando o desactivando los interruptores DIP del controlador. Consulte la tabla siguiente para obtener más detalles. Asegúrese de que el controlador no está conectado a la corriente cuando ajuste los interruptores DIP.

Mesa de micropasos

S3S4Resolución de micropasos
OFFOFFPaso completo
ENOFF1/2 paso
ENEN1/8 paso
OFFENPaso 1/16

En general, un ajuste de micropasos más pequeño dará lugar a un funcionamiento más suave y silencioso. Sin embargo, limitará la velocidad máxima que puede alcanzar al controlar el controlador del motor paso a paso con un Arduino.

Configuración actual del TB6560

Usted puede ajustar la corriente que va al motor cuando está funcionando mediante el ajuste de los interruptores dip SW1, SW2, SW3 y S1 en o fuera. Recomiendo empezar con un nivel de corriente de 1 A. Si tu motor pierde pasos o se cala, siempre puedes aumentar el nivel de corriente más adelante.

Tabla actual

(A)SW1SW2SW3S1
0.3OFFOFFENEN
0.5OFFOFFENOFF
0.8OFFENOFFEN
1OFFENOFFOFF
1.1OFFENENEN
1.2ENOFFOFFEN
1.4OFFENENOFF
1.5ENOFFENEN
1.6ENOFFOFFOFF
1.9ENENOFFEN
2ENOFFENOFF
2.2ENENENEN
2.6ENENOFFOFF
39ENENENOFF

La corriente de parada es la que se utiliza para mantener el eje del motor en una posición de parada. Usted querrá ajustar este valor lo más bajo posible, para minimizar el calentamiento innecesario del motor. Aumente este valor si su motor no puede mantener su posición.

Detener la tabla actual

Detener la corrienteS2
20 %EN
50 %OFF

El ajuste del decaimiento tiene que ver con la forma en que el chip del controlador maneja el EMF posterior del motor. La hoja de datos del TB6560 de Toshiba ofrece algunas explicaciones y diagramas sobre este ajuste. Yo suelo dejar el modo de decaimiento en el 0%. Puedes jugar con este ajuste para ver qué resultados da tu configuración.

Como referencia, el controlador TB6600 tiene un ajuste de decaimiento fijo del 40%.

Mesa de ajuste de la decadencia

S5S6
0 % NormalOFFOFF
25 %ENOFF
50 %OFFEN
100 % Modo rápidoENEN

En el resto de este tutorial, utilizaré el driver en modo microstepping 1/8 con una corriente de funcionamiento de 1 A, una corriente de parada del 20 % y un ajuste de decaimiento del 0 %.

Código de ejemplo del TB6560 Arduino

Ahora que has cableado el controlador y has ajustado los interruptores DIP, es el momento de conectar el Arduino al ordenador y cargar algo de código. Puedes subir el siguiente código de ejemplo a tu Arduino usando el IDE de Arduino. Para este ejemplo específico, no es necesario instalar ninguna biblioteca.

Este esquema controla tanto la velocidad, el número de revoluciones y el sentido de giro del motor paso a paso.

Puede copiar el código haciendo clic en el botón de la esquina superior derecha del campo de código.

/* Example sketch to control a stepper motor with TB6560 stepper motor driver and Arduino without a library. More info: https://www.makerguides.com */

// Define stepper motor connections and steps per revolution:
#define dirPin 2
#define stepPin 3
#define stepsPerRevolution 1600

void setup() {
  // Declare pins as output:
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

void loop() {
  // Set the spinning direction clockwise:
  digitalWrite(dirPin, HIGH);

  // Spin the stepper motor 1 revolution slowly:
  for (int i = 0; i < stepsPerRevolution; i++) {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(2000);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(2000);
  }

  delay(1000);

  // Set the spinning direction counterclockwise:
  digitalWrite(dirPin, LOW);

  // Spin the stepper motor 1 revolution quickly:
  for (int i = 0; i < stepsPerRevolution; i++) {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(1000);
  }

  delay(1000);

  // Set the spinning direction clockwise:
  digitalWrite(dirPin, HIGH);

  // Spin the stepper motor 5 revolutions fast:
  for (int i = 0; i < 5 * stepsPerRevolution; i++) {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
  }

  delay(1000);

  // Set the spinning direction counterclockwise:
  digitalWrite(dirPin, LOW);

  // Spin the stepper motor 5 revolutions fast:
  for (int i = 0; i < 5 * stepsPerRevolution; i++) {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
  }

  delay(1000);
}

Cómo funciona el código:

El sketch comienza definiendo los pines de paso (CLK-) y dirección (CW-). Los conecté a los pines 3 y 2 de Arduino.

La declaración #define se utiliza para dar un nombre a un valor constante. El compilador sustituirá cualquier referencia a esta constante por el valor definido cuando se compile el programa. Por lo tanto, en todos los casos en los que se menciona dirPinel compilador lo sustituirá por el valor 2 al compilar el programa.

También he definido un stepsPerRevolution constante. Como he configurado el driver en modo microstepping 1/8, lo he ajustado a 1600 pasos por revolución. Cambia este valor si tu configuración es diferente.

// Define stepper motor connections and steps per revolution:
#define dirPin 2
#define stepPin 3
#define stepsPerRevolution 1600

En el setup() del código, todos los pines de control del motor se declaran como OUTPUT digital con la función pinMode().

void setup() {
  // Declare pins as output:
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

En el loop() del código, dejamos que el motor gire una revolución lentamente en la dirección CW y una revolución rápidamente en la dirección CCW. Luego dejamos que el motor gire 5 revoluciones en cada dirección con una velocidad alta. Entonces, ¿cómo se controla la velocidad, la dirección de giro y el número de revoluciones?

  // Set the spinning direction clockwise:
  digitalWrite(dirPin, HIGH);

  // Spin the stepper motor 1 revolution slowly:
  for(int i = 0; i < stepsPerRevolution; i++)
  {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(2000);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(2000);
  }

Controla la dirección de giro:

Para controlar el sentido de giro del motor paso a paso ponemos el pin DIR (dirección) en HIGH o LOW. Para ello, utilizamos la función digitalWrite(). Dependiendo de cómo hayas conectado el motor paso a paso, al poner el pin DIR en alto el motor girará en sentido de la marcha o en sentido contrario.

Controla el número de pasos o revoluciones:

En este ejemplo, los bucles for controlan el número de pasos que dará el motor paso a paso. El código dentro del bucle for resulta en 1 (micro)paso del motor paso a paso. Como el código en el bucle se ejecuta 1600 veces (stepsPerRevolution), esto resulta en 1 revolución. En los dos últimos bucles, el código dentro del bucle for se ejecuta 8000 veces, lo que resulta en 8000 (micro)pasos o 5 revoluciones.

Tenga en cuenta que puede cambiar el segundo término del bucle for por el número de pasos que desee. for(int i = 0; i < 800; i++) resultaría en 800 pasos o media revolución.

Velocidad de control:

La velocidad del motor paso a paso viene determinada por la frecuencia de los pulsos que enviamos al pin STEP. Cuanto mayor sea la frecuencia, más rápido funcionará el motor. Puedes controlar la frecuencia de los pulsos cambiando delayMicroseconds() en el código. Cuanto más corto sea el retardo, mayor será la frecuencia y más rápido funcionará el motor.

Instalación de la biblioteca AccelStepper

La librería AccelStepper escrita por Mike McCauley es una librería impresionante para usar en tu proyecto. Una de las ventajas es que soporta la aceleración y la desaceleración, pero tiene un montón de otras funciones agradables también.

Puede descargar la última versión de esta biblioteca aquí o hacer clic en el botón de abajo.

Puedes instalar la librería yendo a Sketch > Incluir librería > Añadir librería .ZIP ... en el IDE de Arduino.

Otra opción es ir a Herramientas > Administrar Bibliotecas... o teclear Ctrl + Shift + I en Windows. El Administrador de Bibliotecas se abrirá y actualizará la lista de bibliotecas instaladas.

Installing an Arduino library via Library Manager
Library Manger

Puedes buscar 'accelstepper' y buscar la biblioteca de Mike McCauley. Seleccione la última versión y luego haga clic en Instalar.

Install AccelStepper Library
Install AccelStepper Library

Código de ejemplo de AccelStepper

Con el siguiente sketch puedes añadir aceleración y desaceleración a los movimientos del motor paso a paso, sin ninguna codificación complicada. En el siguiente ejemplo, el motor irá y vendrá con una velocidad de 1000 pasos por segundo y una aceleración de 500 pasos por segundo al cuadrado.

Tenga en cuenta que todavía estoy utilizando el controlador en el modo 1/8 microstepping. Si estás usando una configuración diferente, juega con los ajustes de velocidad y aceleración.

/* Example sketch to control a stepper motor with TB6560 stepper motor driver, AccelStepper library and Arduino: acceleration and deceleration. More info: https://www.makerguides.com */

// Include the AccelStepper library:
#include "AccelStepper.h"

// Define stepper motor connections and motor interface type. Motor interface type must be set to 1 when using a driver:
#define dirPin 2
#define stepPin 3
#define motorInterfaceType 1

// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

void setup() {
  // Set the maximum speed and acceleration:
  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(500);
}

void loop() {
  // Set the target position:
  stepper.moveTo(8000);
  // Run to target position with set speed and acceleration/deceleration:
  stepper.runToPosition();

  delay(1000);

  // Move back to zero:
  stepper.moveTo(0);
  stepper.runToPosition();

  delay(1000);
}

Explicación del código:

El primer paso es incluir la biblioteca con #include <AccelStepper.h>.

// Include the AccelStepper library:
#include "AccelStepper.h"

El siguiente paso es definir las conexiones del TB6560 a Arduino y el tipo de interfaz del motor. El tipo de interfaz del motor debe establecerse en 1 cuando se utiliza un controlador de paso y dirección. Puedes encontrar los otros tipos de interfaz aquí.

// Define stepper motor connections and motor interface type. Motor interface type must be set to 1 when using a driver:
#define dirPin 2
#define stepPin 3
#define motorInterfaceType 1

A continuación, hay que crear una nueva instancia de la clase AccelStepper con el tipo de interfaz del motor y las conexiones adecuadas.

En este caso he llamado al motor paso a paso 'stepper', pero también puedes utilizar otros nombres, como 'z_motor' o 'liftmotor', etc. AccelStepper liftmotor = AccelStepper(motorInterfaceType, stepPin, dirPin);. El nombre que le des al motor paso a paso se utilizará más tarde para establecer la velocidad, la posición y la aceleración de ese motor en particular. Puedes crear múltiples instancias de la clase AccelStepper con diferentes nombres y pines. Esto le permite controlar fácilmente 2 o más motores paso a paso al mismo tiempo.

// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

En la función setup(), además de la velocidad máxima, necesitamos definir la aceleración/desaceleración. Para ello utilizamos la función setMaxSpeed() y setAcceleration().

void setup() {
  // Set the maximum speed and acceleration:
  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(500);
}

En la sección de bucle del código, dejamos que el motor gire un número predefinido de pasos. La función stepper.moveTo() se utiliza para fijar la posición del objetivo (en pasos). La función stepper.runToPostion() mueve el motor (con aceleración/deceleración) a la posición objetivo y se bloquea hasta que esté en la posición objetivo. Debido a que esta función es de bloqueo, no deberías usarla cuando necesites controlar otras cosas al mismo tiempo.

  // Set the target position:
  stepper.moveTo(8000);
  // Run to target position with set speed and acceleration/deceleration:
  stepper.runToPosition();

Si quieres ver más ejemplos de la librería AccelStepper, echa un vistazo a mi tutorial sobre el controlador del motor paso a paso A4988:

Conclusión

En este artículo te he mostrado cómo controlar un motor paso a paso con el driver de motor paso a paso TB6560 y Arduino. Espero que lo hayas encontrado útil e informativo. Si lo has hecho, ¡compártelo con un amigo al que también le guste la electrónica y hacer cosas!

Me encantaría saber qué proyectos planeas construir (o ya has construido) con este controlador. Si tienes alguna pregunta, sugerencia, o si crees que faltan cosas en este tutorial, por favor deja un comentario abajo.

Tenga en cuenta que los comentarios son retenidos por la moderación para evitar el spam.

Rajiv B

Jueves 25 de febrero de 2021

Hola, ¿Cómo detener el motor paso a paso mientras su rotación en el medio? ¿Alguna señal de FRENO ALTO/BAJO en algún pin que pueda controlar? Muy buen post, BTW. Rajiv.

Rajiv B

Sábado 6 de marzo de 2021

Ok ... he descubierto esto ... el EN + no está conectado, en realidad su Activo LOW, por lo que su habilitado para siempre por mantenerlo desconectado.

Necesitamos controlar la señal EN+ para que se detenga entre la rotación en sentido horario/ rotación en sentido contrario a las agujas del reloj. He conectado EN+ al pin 8 y EN- a GND en el Arduino Uno. En la parte de Init, lo convertimos en un pin de salida digital y lo ponemos en LOW, para que esté habilitado. Ahora, en el medio de tirar de él ALTO durante algún tiempo y podemos ver el paso NEMA17 se detiene, por ese 'tiempo', y después de eso reanuda su movimiento.

Creo que es un buen ejercicio que se deja al espectador para que lo intente, por parte del Autor.

Abajo está mi código:

#define dirPin 5 #define stepPin 2 #define enPin 8 #define stepsPerRevolution 3200 int cntr =0;

void setup() { // Declare pins as output: pinMode(stepPin, OUTPUT); pinMode(dirPin, OUTPUT); pinMode(enPin, OUTPUT); digitalWrite(enPin, LOW); delay(5000); } void loop() { cntr =0; // Set the spinning direction clockwise: digitalWrite(dirPin, HIGH); // Spin the stepper motor 1 revolution slowly: for (int i = 0; i < stepsPerRevolution; i++) { // These four lines result in 1 step: digitalWrite(stepPin, HIGH); delayMicroseconds(500); digitalWrite(stepPin, LOW); delayMicroseconds(500); cntr +=1; digitalWrite(enPin, LOW); if (cntr == 1599) { digitalWrite(enPin, HIGH); delay(2000); digitalWrite(enPin, LOW); } } cntr =0; delay(5000); // Set the spinning direction counterclockwise: digitalWrite(dirPin, LOW); // Spin the stepper motor 1 revolution quickly: for (int i = 0; i < stepsPerRevolution; i++) { // These four lines result in 1 step: digitalWrite(stepPin, HIGH); delayMicroseconds(500); digitalWrite(stepPin, LOW); delayMicroseconds(500); cntr +=1; if (cntr == 1599) { digitalWrite(enPin, HIGH); delay(2000); digitalWrite(enPin, LOW); } } delay(5000); }

John

Martes 23 de febrero de 2021

Muy claro y preciso, una buena introducción a los steppers y su funcionamiento. El montaje del tb6560 fue sencillo con tu guía gracias por el trabajo y las ideas claras.

mejor Juan

Ray

Jueves 18 de febrero de 2021

¡Hola! Estoy tratando de hacer un diagrama de fritzing pero no puedo encontrar un .fzpz para el controlador de motor TB6560. ¿Dónde lo has encontrado? ¿Lo has hecho tú mismo?

Gracias de antemano.

Benne de Bakker

Martes 2 de marzo de 2021

Hola Ray, Sí, lo hice yo mismo, también puedes simplemente cargar una imagen en Fritzing y usarla como parte si sólo quieres dibujar un esquema de cableado. Benne

Eduardo Saman

Sábado 2 de enero de 2021

Muy buena explicación, acabo de descubrir un sitio excelente, gracias.

Doug

Thursday 11th of June 2020

Thanks for posting these instructions. I have a 4 axis CNC and the 4th axis/driver was not working. I was able to quickly hook up an Arduino Pro Mini and test it with your sketch and show it worked. BTW, you don't need to bind the grounds between 24V input and the Arduino inputs. The opto-isolators work off the 5V input and the active-Low signal of the Step/Direction/Enable lines.

My problem ended up being the CNC put out 5.3V and my 3.3V ESP32 was not going high enough to turn off the Opto-isolators. A quick hack was to put a diode inline with the 5.3V making it 4.6V and that was enough for the 3.3V signal to turn off the opto-isolators. But I wouldn't have known to keep looking without your post to prove the driver was functioning. Thank you.