01 · Punto de partida
Qué vamos a construir
El montaje es un plotter de dos ejes: un motor NEMA 17 mueve el eje X y otro el eje Y, cada uno con su driver A4988 en 1/16 de paso y una correa dentada GT2 con polea de 20 dientes (40 mm de avance por vuelta). Con 3200 micropasos por vuelta, resulta 3200 / 40 = 80 micropasos por milímetro, es decir 0,0125 mm de resolución nominal. Un servo (tema 32) levanta o baja la pluma. Dos finales de carrera marcan el origen de cada eje.
Los requisitos, de más simple a más exigente:
- Mover un eje una distancia dada, sin perder pasos (rampas).
- Encontrar el origen al encender (homing) y no pasarse de los límites.
- Mover los dos ejes para que la pluma siga una línea recta (movimiento coordinado).
- Sincronizar la pluma con los movimientos, sin que el dibujo salga con trazos de más.
Es el mismo problema que resuelven una impresora 3D o una CNC, con la diferencia de la escala. Y, como en los talleres anteriores, el resultado es un módulo: irA(x, y), plumaArriba(), plumaAbajo() y origen(), que el resto del programa usa sin saber cómo funciona.
02 · Paso 1
Arquitectura y tiempos
| Tarea | Dónde | Ritmo |
|---|---|---|
| Emitir los pulsos STEP | Lazo rápido o interrupción de un timer | Hasta unos 2400 Hz por eje (30 mm/s) |
| Calcular el siguiente intervalo (perfil) | Junto a cada paso | Un cálculo corto por paso |
| Leer los finales de carrera | Lazo (y homing) | Cada vuelta del lazo |
| Lista de trazos y máquina de estados de la pluma | Lazo principal | Sin bloqueos (tema 41) |
La regla de oro es no bloquear el lazo: cada paso es un evento «si ya venció el intervalo, emití el pulso». Si el lazo hace otras tareas lentas (por ejemplo, Serial.print largos o un delay), los pasos se retrasan y el movimiento sale entrecortado. A 2400 Hz hay un paso cada 417 µs; en un AVR, el lazo debe volver cada pocos cientos de microsegundos. Si las velocidades son más altas, se pasa a un timer con interrupción. Otro aspecto: la librería Servo de Arduino usa un timer, que puede interferir con otras librerías de pulsos; conviene verificar la compatibilidad o usar un servo controlado por un PCA9685.
03 · Paso 2
Cableado y montaje
- Drivers: cada A4988 con STEP y DIR a pines del microcontrolador, EN (activo en bajo) compartido, MS1-MS3 en alto para 1/16, SLEEP y RESET unidos. VMOT a 12 o 24 V con un capacitor de 100 µF por driver, lo más cerca posible.
- Vref: regulado para la corriente del motor (tema 33), con disipador en cada driver.
- Finales de carrera: un contacto por eje con
INPUT_PULLUP, cableado como normalmente cerrado hacia masa (cuando se acciona, se abre). Así, un cable cortado se lee igual que un tope accionado y el sistema se detiene en lugar de seguir ciegamente (tema 6). - Servo: alimentado desde una fuente de 5 V propia (no desde el regulador de la placa), con masa común y un capacitor de 470 µF; la señal en un pin con PWM de hardware o con la librería
Servo. - Masa común entre drivers, servo y microcontrolador, y cables de motor trenzados y separados de los de los finales de carrera.
Y, como siempre con drivers de paso a paso: nunca conectar ni desconectar los motores con la alimentación encendida.
04 · Paso 3
El perfil de velocidad
Mover un eje una distancia D con velocidad máxima v y aceleración a tiene dos formas posibles:
- Trapezoidal, si
D ≥ v² / a: acelera, viaja a velocidad constante y frena. Tiempo:2v/a + (D − v²/a) / v. - Triangular, si no alcanza a llegar a v: acelera la mitad del recorrido y frena la otra mitad. Velocidad pico:
√(a·D); tiempo:2√(D/a).
Con v = 30 mm/s y a = 300 mm/s² (en micropasos: 2400 por segundo y 24 000 por segundo al cuadrado), la aceleración dura 0,1 s y recorre 1,5 mm. Un trazo de 100 mm es trapezoidal y dura 3,43 s; uno de 10 mm, 0,43 s; uno de 2 mm es triangular, llega a 24,5 mm/s y dura 0,16 s. Sin rampa, la única velocidad segura sería la de arranque (unos 300 Hz, 3,75 mm/s): 100 mm tardarían 26,7 s, casi ocho veces más.
Una forma elegante de implementarlo sin planificar tiempos: calcular la velocidad en función de los pasos hechos i y los pasos que faltan, como si cada extremo fuera una rampa:
El primer término es el límite de velocidad, el segundo la velocidad alcanzable acelerando desde cero, y el tercero la máxima desde la que todavía se puede frenar a tiempo. Los tres juntos dan el trapecio, o el triángulo cuando el recorrido es corto, sin tratar los casos por separado. Para i = 0, la velocidad inicial es √(2a) = 219 micropasos/s con a = 24 000, por debajo de la frecuencia de arranque.
const float V_MAX = 2400.0; // micropasos/s (30 mm/s)
const float A_MAX = 24000.0; // micropasos/s² (300 mm/s²)
// velocidad (µpasos/s) para el paso i de un movimiento de n pasos
float velocidadEnPaso(uint32_t i, uint32_t n) {
float vAcel = sqrt(2.0 * A_MAX * (i + 1)); // acelerando desde parado
float vFren = sqrt(2.0 * A_MAX * (n - i)); // máxima desde la que aún se puede frenar
return min(V_MAX, min(vAcel, vFren));
}
uint32_t intervaloUs(float v) { return (uint32_t)(1000000.0 / v); }
05 · Paso 4
Homing
Los pasos se cuentan desde donde el programa cree que está, y al encender no tiene idea. El homing define el origen con un final de carrera. Un método robusto en dos pasadas:
- Levantar la pluma (para no rayar ni chocar).
- Pasada rápida: mover el eje hacia el final de carrera a velocidad moderada (por ejemplo 15 mm/s) hasta que se accione. Se frena de golpe: es un movimiento de velocidad baja, sin rampa larga.
- Retroceso: alejarse 1 mm del final de carrera (más que el sobreimpulso de la pasada rápida).
- Pasada lenta: acercarse a 2,5 mm/s hasta accionarlo de nuevo.
- Definir el cero:
posicion = 0en ese instante (o con un desplazamiento fijo medido).
La razón de la segunda pasada es el retardo de detección: entre que el contacto cambia y el programa lo nota pasa hasta un período del lazo, y durante ese tiempo el eje avanza v × período más allá del punto de conmutación. Con 15 mm/s y el lazo leyendo cada 5 ms, el error es de 0,075 mm; con 20 ms, 0,3 mm. A 2,5 mm/s, los mismos retardos dan 0,0125 y 0,05 mm: seis veces menos. La repetibilidad del cero la fija la pasada lenta (y el propio contacto: histéresis y desgaste).
bool topeAccionado(uint8_t pin) { return digitalRead(pin) == HIGH; } // NC con pull-up: abierto = accionado
void homing(Eje &e) {
plumaArriba();
moverHastaTope(e, -1, 1200); // rápida: 1200 µpasos/s = 15 mm/s
moverRelativo(e, +80, 800); // retrocede 1 mm
moverHastaTope(e, -1, 200); // lenta: 200 µpasos/s = 2,5 mm/s
e.pos = 0; // origen
e.homeado = true;
}
void moverHastaTope(Eje &e, int8_t sentido, uint16_t vel) {
uint32_t intervalo = 1000000UL / vel;
uint32_t limite = 20000; // máximo de pasos buscando el tope (límite de seguridad)
while (!topeAccionado(e.pinTope) && limite--) {
darPaso(e, sentido);
delayMicroseconds(intervalo); // el homing ocurre al arrancar y puede ser bloqueante
}
if (limite == 0) fallaHoming(e); // nunca encontró el tope: cable, tope o motor
}
Dos protecciones: el límite de pasos durante la búsqueda (si el tope no se acciona nunca, el eje avanzaría para siempre) y los límites de software tras el homing (no aceptar posiciones fuera de 0..ANCHO). Hasta que haya homing, el módulo debe rechazar movimientos absolutos.
06 · Paso 5
Movimiento coordinado
Si se ordena irA(60, 30) y cada eje se mueve por su cuenta, el eje Y (30 mm) llega antes que el X (60 mm) y la pluma dibuja una diagonal seguida de un tramo horizontal, no una recta. Con los parámetros del ejemplo (30 mm/s, 300 mm/s²), Y llega a los 1,10 s y X a los 2,10 s, y en el trayecto la pluma se aparta hasta 13 mm de la recta ideal.
Para dibujar una recta, los dos ejes deben llegar al mismo tiempo y avanzar en proporción. El algoritmo de Bresenham lo resuelve con enteros: el eje con mayor recorrido (el dominante) da un paso en cada ciclo; el otro da un paso solo cuando la acumulación del error lo requiere. Así la desviación respecto de la recta ideal nunca supera medio micropaso (0,006 mm). La velocidad y la aceleración se aplican al eje dominante, escaladas por la proporción del trazo:
Para el trazo de 60 × 30 mm, L = 67,08 mm; con el avance de 30 mm/s, X va a 26,8 mm/s y Y a 13,4 mm/s. El trazo dura 2,34 s, un 11 % más que el movimiento independiente del eje X (2,10 s), lo que es el precio de la recta correcta.
struct Linea {
int32_t dx, dy; // magnitudes (siempre positivas), en µpasos
int8_t sx, sy; // sentidos
int32_t n; // pasos del eje dominante
int32_t i, err; // paso actual y acumulador de Bresenham
bool xDominante;
uint32_t proximoUs;
bool activa;
};
Linea linea;
void iniciarLinea(int32_t destX, int32_t destY) {
int32_t ddx = destX - ejeX.pos, ddy = destY - ejeY.pos;
linea.dx = abs(ddx); linea.dy = abs(ddy);
linea.sx = ddx >= 0 ? 1 : -1; linea.sy = ddy >= 0 ? 1 : -1;
linea.xDominante = linea.dx >= linea.dy;
linea.n = linea.xDominante ? linea.dx : linea.dy;
linea.i = 0; linea.err = 0;
linea.proximoUs = micros();
linea.activa = linea.n > 0;
}
void avanzarLinea() { // se llama sin parar desde el loop
if (!linea.activa || (int32_t)(micros() - linea.proximoUs) < 0) return;
int32_t menor = linea.xDominante ? linea.dy : linea.dx;
if (linea.xDominante) darPaso(ejeX, linea.sx); else darPaso(ejeY, linea.sy);
linea.err += menor; // Bresenham: el eje menor da un paso cuando se acumula un paso completo
if (2 * linea.err >= linea.n) {
linea.err -= linea.n;
if (linea.xDominante) darPaso(ejeY, linea.sy); else darPaso(ejeX, linea.sx);
}
linea.i++;
float v = velocidadEnPaso(linea.i - 1, linea.n) * escalaDominante; // escalada por n / L
linea.proximoUs += intervaloUs(v);
if (linea.i >= linea.n) linea.activa = false;
}
07 · Paso 6
La pluma con el servo
Subir y bajar la pluma es un movimiento de un servo entre dos ángulos calibrados (por ejemplo, 70° arriba y 105° abajo). El servo no informa cuándo llegó, así que el programa debe esperar el tiempo que tarda: un servo común recorre 60° en unos 0,1 s, de modo que 35° llevan unos 60 ms; con el margen de la inercia de la pluma y de la banda muerta, se espera 150 a 250 ms. La espera se hace sin bloquear: una pequeña máquina de estados.
- Antes de mover con la pluma baja: asegurar que bajó (esperar). De lo contrario, el comienzo del trazo se pierde.
- Antes de desplazarse en vacío: subir la pluma y esperar, para no rayar.
- Al terminar o ante una falla: subir la pluma (estado seguro).
Un detalle práctico: el servo puede temblar cuando los motores paso a paso consumen sus picos de corriente (ruido en la alimentación), y los pulsos de STEP a alta frecuencia pueden perturbar la señal del servo. Una fuente aparte, capacitores y masa común bien hecha lo resuelven. Y se puede ahorrar energía y ruido con detach() cuando la pluma no necesita sostenerse (aunque, al volver a conectar, el servo vuelve a su posición con un tirón).
08 · Paso 7
El programa completo
La lógica de más alto nivel es una lista de trazos y una máquina de estados que ejecuta cada uno en secuencia: levantar la pluma, ir al inicio, bajarla, dibujar, levantarla.
struct Trazo { int16_t x0, y0, x1, y1; }; // en décimas de milímetro
const Trazo CUADRADO[] = { {100,100,500,100}, {500,100,500,500}, {500,500,100,500}, {100,500,100,100} };
const uint8_t N_TRAZOS = sizeof(CUADRADO) / sizeof(Trazo);
enum Estado { INICIO, SUBIENDO, YENDO, BAJANDO, DIBUJANDO, FIN };
Estado estado = INICIO;
uint8_t actual = 0;
uint32_t tEstado = 0;
int32_t aMicropasos(int16_t decimas) { return (int32_t)decimas * 8; } // 80 µpasos/mm = 8 por décima
void loop() {
avanzarLinea(); // prioridad: los pasos no se pueden retrasar
switch (estado) {
case INICIO:
plumaArriba(); tEstado = millis(); estado = SUBIENDO; break;
case SUBIENDO:
if (millis() - tEstado >= 200) {
iniciarLinea(aMicropasos(CUADRADO[actual].x0), aMicropasos(CUADRADO[actual].y0)); estado = YENDO;
} break;
case YENDO:
if (!linea.activa) { plumaAbajo(); tEstado = millis(); estado = BAJANDO; } break;
case BAJANDO:
if (millis() - tEstado >= 200) {
iniciarLinea(aMicropasos(CUADRADO[actual].x1), aMicropasos(CUADRADO[actual].y1)); estado = DIBUJANDO;
} break;
case DIBUJANDO:
if (!linea.activa) { plumaArriba(); tEstado = millis(); actual++; estado = (actual < N_TRAZOS) ? SUBIENDO : FIN; } break;
case FIN: break;
}
}
09 · Paso 8
Verificar
- Calibración de escala. Mové 100 mm y medí con regla: ajustá micropasos/mm (poleas, correa, diámetro) hasta que coincida.
- Repetibilidad del homing. Hacé homing diez veces, mandá a una posición fija y medí con calibre: la dispersión debe ser de pocas centésimas de milímetro.
- Cierre del dibujo. Trazá un cuadrado de 40 mm y repetilo veinte veces sobre el mismo lugar: si las líneas no coinciden, se pierden pasos.
- Prueba de retorno. Tras un recorrido largo y variado, volver al origen: el eje debe llegar al final de carrera con la cuenta en cero. Si la cuenta da distinta, hubo pérdida de pasos.
- Aceleración y velocidad. Subí la velocidad y la aceleración hasta que se pierdan pasos (se oye un zumbido o hay saltos) y trabajá con el 60 a 70 % de ese valor.
- Rectas y diagonales. Dibujá diagonales de distintas pendientes y comprobá que sean rectas y lleguen al punto.
- Pluma. Verificá que no quedan puntos de más al inicio y al final de los trazos, ni rayas en los desplazamientos.
10 · Paso 9
Fallas y robustez
| Falla | Síntoma | Defensa |
|---|---|---|
| Pérdida de pasos | El dibujo se corre; no cierra | Rampas, menos velocidad, más corriente, prueba de retorno |
| Final de carrera defectuoso | Homing que choca o nunca termina | Cableado normalmente cerrado, límite de pasos en la búsqueda |
| Rebote o ruido en el final de carrera | Cero distinto en cada homing | Dos pasadas, filtro RC o antirrebote (tema 6) |
| Fuera de límites | El carro choca contra el extremo | Límites de software, rechazo de movimientos sin homing |
| Resonancia | Zumbido o vibración a ciertas velocidades | Cambiar velocidad o microstepping, evitar velocidad crítica |
| Servo tembloroso | Pluma que vibra | Fuente propia, capacitor, masa común, cables separados |
| Driver caliente | Se apaga por temperatura | Reducir corriente, disipador, deshabilitar en reposo |
| Corte de energía | Posición perdida | Repetir el homing al arrancar |
El modo de falla distintivo del lazo abierto es el silencioso: el sistema hace lo que el programa cree y se aparta de la realidad sin avisar. Las defensas son estructurales: referenciar a menudo (volver al origen entre trabajos), mantener margen de par y de velocidad, y, si el trabajo lo exige, agregar un sensor (un encoder en el eje) que verifique.
11 · Analogía con programación
Planificar movimientos, coordinar ejes y estimar el homing
Calculemos los tres elementos del taller: el perfil de distintos trazos, la diferencia entre mover dos ejes de forma independiente o coordinada (con Bresenham) y el error de cero del homing según la velocidad y el retardo de detección.
Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.
import math
UP_MM = 80 # micropasos por milímetro (1/16, correa GT2 de 40 mm por vuelta)
V_MAX, A_MAX = 30.0, 300.0 # mm/s y mm/s²
def perfil(distancia, v_max=V_MAX, a=A_MAX):
d_acel = v_max ** 2 / (2 * a)
if distancia >= 2 * d_acel:
return "trapezoidal", v_max, 2 * v_max / a + (distancia - 2 * d_acel) / v_max
v_pico = math.sqrt(a * distancia)
return "triangular", v_pico, 2 * v_pico / a
print("trazo micropasos perfil v pico tiempo sin rampa (300 Hz)")
for d in (2, 10, 100):
forma, v, t = perfil(d)
print(f"{d:4d} mm {d * UP_MM:10d} {forma:11s} {v:5.1f} mm/s {t:6.3f} s {d * UP_MM / 300:7.1f} s")
print(f"Frecuencia de STEP a {V_MAX:.0f} mm/s: {V_MAX * UP_MM:.0f} Hz; arranque con a = {A_MAX * UP_MM:.0f} µp/s²: {math.sqrt(2 * A_MAX * UP_MM):.0f} µp/s")
# ---- Posición en el tiempo de un eje con perfil de velocidad ----
def posicion(distancia, t, v_max=V_MAX, a=A_MAX):
d_acel = v_max ** 2 / (2 * a)
if distancia >= 2 * d_acel:
ta, tc = v_max / a, (distancia - 2 * d_acel) / v_max
total = 2 * ta + tc
if t >= total: return distancia
if t < ta: return 0.5 * a * t * t
if t < ta + tc: return d_acel + v_max * (t - ta)
return distancia - 0.5 * a * (total - t) ** 2
v_pico = math.sqrt(a * distancia)
ta = v_pico / a
if t >= 2 * ta: return distancia
if t < ta: return 0.5 * a * t * t
return distancia - 0.5 * a * (2 * ta - t) ** 2
# ---- Trazo de 60 x 30 mm: ejes independientes frente a movimiento coordinado ----
dx, dy = 60.0, 30.0
longitud = math.hypot(dx, dy)
t_indep = max(perfil(dx)[2], perfil(dy)[2])
desvio = max(abs(posicion(dx, k / 1000) * dy - posicion(dy, k / 1000) * dx) / longitud for k in range(round(t_indep * 1000) + 1))
t_coord = perfil(longitud)[2]
print()
print(f"Independientes: {t_indep:.3f} s y la pluma se aparta hasta {desvio:.1f} mm de la recta")
print(f"Coordinado: longitud {longitud:.2f} mm, {t_coord:.3f} s; X a {V_MAX * dx / longitud:.1f} mm/s, Y a {V_MAX * dy / longitud:.1f} mm/s")
# ---- Bresenham con enteros ----
def bresenham(dx_i, dy_i):
y, err, peor = 0, 2 * dy_i - dx_i, 0.0
for x in range(1, dx_i + 1):
if err > 0:
y += 1
err += 2 * (dy_i - dx_i)
else:
err += 2 * dy_i
peor = max(peor, abs(y - dy_i * x / dx_i))
return y, peor
for pasos_x, pasos_y in ((4800, 2400), (4800, 2000), (3999, 1234)):
y_final, peor = bresenham(pasos_x, pasos_y)
print(f"Bresenham {pasos_x} x {pasos_y}: termina en y = {y_final}; desviación máxima {peor:.3f} micropasos ({peor / UP_MM:.4f} mm)")
# ---- Error de cero del homing: v × retardo de detección ----
print()
print("lazo lee cada pasada rápida (15 mm/s) pasada lenta (2,5 mm/s)")
for ms in (1, 5, 20):
print(f"{ms:8d} ms {15 * ms / 1000:14.4f} mm {2.5 * ms / 1000:20.4f} mm")
retardo = 0.005
t_homing = 100 / 15 + (1 + 15 * retardo) / 15 + 1 / 2.5
print(f"Homing desde 100 mm con lazo de 5 ms: {t_homing:.2f} s en total")
Resultado: con 80 micropasos/mm, un trazo de 2 mm (160 micropasos) es triangular, llega a 24,5 mm/s y dura 0,163 s; uno de 10 mm (800), trapezoidal, 0,433 s; y uno de 100 mm (8000), 3,433 s frente a 26,7 s sin rampa. A 30 mm/s la frecuencia de STEP es 2400 Hz y la velocidad inicial es 219 micropasos/s. El trazo de 60 × 30 mm con ejes independientes tarda 2,100 s y la pluma se aparta hasta 13,1 mm de la recta; coordinado, tarda 2,336 s (X a 26,8 mm/s, Y a 13,4 mm/s). Bresenham termina siempre en el punto exacto, con una desviación máxima de 0,5 micropasos (0,006 mm). El error de cero del homing con el lazo leyendo cada 5 ms es de 0,075 mm con una sola pasada rápida y de 0,0125 mm con la lenta; con 20 ms, 0,3 y 0,05 mm. Un homing desde 100 mm con lazo de 5 ms dura 7,14 s.
12 · Exploración interactiva
El banco de pruebas del posicionador
El primer instrumento dibuja el perfil de velocidad de un eje y verifica si el motor lo soporta. El segundo calcula el tiempo y el error del homing. El tercero compara el movimiento independiente con el coordinado de dos ejes, con el dibujo de las trayectorias. Los límites del motor son los del modelo ilustrativo del tema 33.
Instrumento 1: el perfil de velocidad
Instrumento 2: homing
Instrumento 3: movimiento coordinado
Recorrido guiado
- Con 100 mm, 30 mm/s y 300 mm/s²: perfil trapezoidal, 3,43 s, 2400 Hz de STEP (dentro de los 2653 Hz del motor a 24 V). Bajá la distancia a 2 mm: el perfil se vuelve triangular y la velocidad pico no llega a 30.
- Subí la velocidad a 50 mm/s: 4000 Hz, por encima del límite: el motor perdería pasos. Pasá a 12 V: el límite baja a 1327 Hz y hasta los 30 mm/s (2400 Hz) lo superan. La tensión es lo que da velocidad.
- Subí la aceleración a 1500 mm/s²: la rampa dura 20 ms y la velocidad inicial √(2a) supera los ~300 Hz a los que el motor puede arrancar sin rampa: el aviso indica riesgo de pérdida de pasos por aceleración.
- En el homing, con 15 mm/s y lectura cada 5 ms: sobreimpulso de 0,075 mm; con dos pasadas el error del cero baja a 0,0125 mm. Desmarcá las dos pasadas: el error es el de la rápida.
- Pasá a lectura cada 100 ms con 15 mm/s: 1,5 mm de sobreimpulso, más que el retroceso de 1 mm, y el eje queda apretando el tope. Un lazo lento requiere una velocidad de búsqueda menor.
- En el movimiento coordinado, 60 × 30 mm independientes: la trayectoria se curva y se aparta ~13 mm de la recta. Pasá a «Coordinado»: la trayectoria es la recta y el tiempo sube de 2,10 a 2,34 s.
- Probá Δx = Δy = 50 mm: coordinado, ambos ejes a 21,2 mm/s (la velocidad sobre la diagonal es 30 mm/s). Con ejes independientes y Δx = Δy, la trayectoria sale recta, porque llegan juntos.
Desafío: la letra «A»
Para dibujar una «A» de 40 mm de alto hacen falta tres trazos: dos diagonales y una horizontal. ¿Cuántas veces sube y baja la pluma, y cuánto tiempo se pierde en ello? Tres trazos independientes, cada uno con la pluma levantada para ir al inicio y bajada para dibujar: 6 movimientos del servo. Con 200 ms de espera cada uno, 1,2 s solo en la pluma, comparable con el tiempo de dibujo. Optimizaciones: ordenar los trazos para minimizar los desplazamientos en vacío, unir trazos contiguos sin levantar la pluma, y reducir la espera al mínimo que el servo necesita (medilo).
13 · Método de trabajo
Lo aprendido, para cualquier posicionador de lazo abierto
- Calculá la escala (micropasos por unidad) y la frecuencia de STEP a la velocidad máxima.
- Usá siempre un perfil de velocidad con aceleración limitada; calculalo con la fórmula de los pasos hechos y por hacer.
- Hacé homing en dos pasadas, con límite de pasos y finales de carrera normalmente cerrados.
- Coordiná los ejes con Bresenham y aplicá la velocidad al eje dominante.
- Sincronizá los actuadores auxiliares (servo, bomba, láser) con esperas calculadas y máquinas de estados.
- Definí límites de software y rechazá movimientos sin homing.
- Probá con ensayos de retorno y de cierre para detectar pérdida de pasos.
- Trabajá con margen: el 60 a 70 % de la velocidad y la aceleración en que empiezan los fallos.
Si el dibujo no cierra, se perdieron pasos (velocidad, aceleración o corriente); si el origen cambia, el homing o el final de carrera; si las diagonales salen curvas, falta coordinación; si la pluma deja manchas, la espera del servo es corta.
14 · Comprensión
Confusiones frecuentes
«Cada eje puede moverse por su cuenta y llegan igual»
Llegan en tiempos distintos, y la trayectoria deja de ser una recta. Para una recta hay que coordinar ambos ejes.
«Si el programa cuenta bien los pasos, la posición es exacta»
La cuenta del programa no sabe si el motor perdió pasos. La posición real puede diferir sin aviso.
«El homing con una pasada rápida es suficiente»
El sobreimpulso por el retardo de detección da un error proporcional a la velocidad; una segunda pasada lenta lo reduce mucho.
«La aceleración solo importa para movimientos largos»
En los cortos, el perfil es triangular y la velocidad pico depende de la aceleración: mandar mucha aceleración con distancias chicas igual pierde pasos.
«El servo ya llegó cuando se ejecutó write()»
write() solo fija la orden; el servo tarda decenas de milisegundos en moverse y no informa cuándo llegó.
«Un final de carrera normalmente abierto es lo mismo que uno normalmente cerrado»
Con el cerrado, un cable cortado se lee como tope accionado y el sistema se detiene; con el abierto, el cable cortado pasa inadvertido y el eje choca.
15 · Práctica guiada
Predecí antes de comprobar
1. Escala
Un eje con motor de 200 pasos, 1/8 de paso y una polea de 16 dientes con correa de paso 2 mm. ¿Cuántos micropasos por milímetro?
Ver solución
Avance por vuelta = 16 × 2 = 32 mm; micropasos por vuelta = 200 × 8 = 1600; 50 micropasos/mm (0,02 mm cada uno).
2. Perfil
Con v = 40 mm/s y a = 400 mm/s², ¿cuánto dura la aceleración y qué distancia recorre? ¿Un trazo de 3 mm es trapezoidal o triangular?
Ver solución
t = 40 / 400 = 0,1 s; distancia = 40² / (2 × 400) = 2 mm. Un trazo de 3 mm es menor que 2 × 2 = 4 mm: triangular, con velocidad pico √(400 × 3) = 34,6 mm/s.
3. Frecuencia
A 25 mm/s con 50 micropasos/mm, ¿qué frecuencia de STEP hay? ¿La soporta un motor que llega a 1300 Hz?
Ver solución
25 × 50 = 1250 Hz: está dentro del límite, pero con poco margen (4 %). Conviene bajar a unos 20 mm/s.
4. Homing
El lazo lee el final de carrera cada 10 ms. ¿Qué sobreimpulso produce una pasada a 12 mm/s y una a 2 mm/s?
Ver solución
12 × 0,010 = 0,12 mm; 2 × 0,010 = 0,02 mm.
5. Coordinación
Un trazo de 80 × 60 mm con avance de 40 mm/s. ¿Qué longitud tiene y a qué velocidad va cada eje?
Ver solución
L = √(80² + 60²) = 100 mm; X: 40 × 80/100 = 32 mm/s; Y: 40 × 60/100 = 24 mm/s.
6. Diagnóstico
Un cuadrado de 40 mm se dibuja bien una vez, pero al repetirlo 20 veces las líneas se corren hacia un lado. ¿Qué pasó y qué cambiás?
Ver solución
Pérdida de pasos acumulada en un eje (aceleración o velocidad excesivas, corriente baja o trayecto con roce). Se reduce la aceleración y la velocidad, se sube la corriente del driver, se revisa la correa y se agrega un homing periódico.
16 · Síntesis
Ideas para recordar
- Un posicionador de paso a paso funciona en lazo abierto: la posición es la cuenta de pasos, y no hay aviso si se pierden.
- El perfil de velocidad es trapezoidal (o triangular en trazos cortos); v(i) = mín(vmáx, √(2a(i+1)), √(2a(n−i))) lo da sin casos especiales.
- El homing define el cero con un final de carrera normalmente cerrado, en dos pasadas (rápida y lenta), con límite de pasos.
- El error del cero del homing es velocidad × retardo de detección; la pasada lenta lo reduce.
- El movimiento coordinado con Bresenham hace que los dos ejes lleguen juntos y la trayectoria sea una recta, con una desviación máxima de medio micropaso.
- Con ejes independientes, la trayectoria se curva: 13 mm de desvío en el ejemplo de 60 × 30 mm.
- Los actuadores auxiliares (el servo de la pluma) se sincronizan con esperas calculadas en una máquina de estados no bloqueante.
- Se verifica con pruebas de retorno y de cierre; se trabaja con margen de velocidad y aceleración, y se hace homing de nuevo al encender.
¿Listo para el bloque 8?
Antes de avanzar, calculá el tiempo de un trazo de 50 mm con v = 25 mm/s y a = 250 mm/s², explicá por qué un homing necesita dos pasadas y decí qué pasa si dos ejes se mueven de forma independiente en un trazo en diagonal. Si podés justificar las tres respuestas, ya sabés posicionar con motores paso a paso.
En el próximo tema empieza el bloque de salidas visuales y sonoras con los LEDs: corriente, brillo y color.