Objetivo y caso de uso
Qué construirás: Un sistema de control de motor paso a paso utilizando Arduino Due, TMC2209 y AS5600 para lograr un posicionamiento preciso en bucle cerrado.
Para qué sirve
- Control de motores paso a paso en aplicaciones robóticas para movimientos precisos.
- Automatización de procesos industriales donde se requiere un posicionamiento exacto.
- Desarrollo de impresoras 3D que necesitan un control de posición de alta precisión.
- Uso en sistemas de control de cámaras para seguimiento automático.
Resultado esperado
- Latencia de respuesta del sistema inferior a 10 ms en el control del motor.
- Precisión de posicionamiento de ±0.1 grados en el motor paso a paso.
- Capacidad de manejar hasta 1000 pulsos por segundo sin pérdida de pasos.
- Consumo de energía optimizado, manteniendo el driver TMC2209 en modo standby cuando no está en uso.
Público objetivo: Ingenieros y desarrolladores de sistemas embebidos; Nivel: Avanzado
Arquitectura/flujo: Arduino Due controla el TMC2209, que a su vez gestiona el motor paso a paso, mientras que el AS5600 proporciona la retroalimentación de posición y el HM-10 BLE permite la comunicación inalámbrica.
Nivel: Avanzado
Prerrequisitos
Sistema operativo y versiones probadas
- Linux:
- Ubuntu 22.04.4 LTS (x86_64)
- Windows:
- Windows 11 Pro 23H2 (x64)
- macOS:
- macOS 14 Sonoma (Apple Silicon o Intel)
Nota: Las instrucciones de compilación y flasheo se muestran para Linux y Windows; en macOS son equivalentes a Linux con Homebrew/Paths ajustados.
Toolchain exacta
- Arduino CLI 0.35.3
- Núcleo de placas (core) Arduino SAM (para Arduino Due): arduino:sam 1.6.12
- Librerías Arduino:
- TMCStepper 0.7.3
- DueTimer 1.7.2
- Compilador ARM (incluido en el core arduino:sam)
- Software auxiliar (opcional para validación):
- Python 3.10.x con screen/minicom (Linux) o PuTTY (Windows) para consola serie
- App BLE en smartphone (nRF Connect, LightBlue u otra consola BLE)
Materiales
- Dispositivo exacto del proyecto:
- Arduino Due + TMC2209 stepper drivers + AS5600 encoders + HM-10 BLE
- Componentes específicos:
- 1x Arduino Due (SAM3X8E, 3.3 V)
- 1x Driver TMC2209 en módulo (ej. BigTreeTech TMC2209 v3.x) con R_SENSE ≈ 0.110 Ω
- 1x Motor paso a paso NEMA17 (200 pasos/rev) adecuado para TMC2209
- 1x Sensor magnético AS5600 (I2C, 12-bit), con imán diametral emparejado
- 1x Módulo BLE HM-10 (breakout con regulador y nivel lógico 3.3 V)
- Fuente de alimentación para motor: 12–24 V DC (capacidad según motor; típico 24 V/3 A)
- Alimentación para lógica: la propia del Arduino Due vía USB; compartir GND con la fuente de 24 V
- Resistencias 1 kΩ (2 unidades) para UART de TMC2209 (half-duplex en PDN_UART)
- Resistencias de pull-up I2C (opcional si tu módulo AS5600 ya las incluye): 4.7 kΩ a 3.3 V
- Cables Dupont, protoboard (si aplica), y fijación mecánica del imán AS5600 al eje del motor
Notas:
– El Arduino Due opera a 3.3 V lógicos. Evita conectar señales de 5 V a sus pines.
– HM-10: usa un módulo que funcione de forma fiable a 3.3 V lógicos. Muchos breakouts aceptan 3.3–6 V en VCC y manejan logic-level a 3.3 V.
Preparación y conexión
Principios de la conexión
- El TMC2209 se usará:
- En modo STEP/DIR para el movimiento
- Con comunicación UART para configuración (half-duplex en PDN_UART)
- El AS5600 proporciona la posición angular absoluta por I2C (0x36). Implementaremos multiturno por software.
- El HM-10 BLE crea una consola serie inalámbrica para enviar comandos de destino de posición y parámetros PID desde el móvil.
- El Arduino Due:
- Serial (USB) para log y depuración
- Serial1 (pines 18/19) para HM-10
- Serial2 (pines 16/17) para UART del TMC2209
- I2C (SDA: 20, SCL: 21) para AS5600
- Pines digitales para STEP/DIR/EN del TMC2209
Tabla de mapeo de pines y alimentación
| Módulo/Señal | Arduino Due pin/puerto | Módulo externo | Notas |
|---|---|---|---|
| STEP (TMC2209) | D2 | STEP del TMC2209 | Pulsos de paso (activo flanco) |
| DIR (TMC2209) | D3 | DIR del TMC2209 | Sentido de giro |
| EN (TMC2209) | D4 | EN del TMC2209 | Activo en LOW para habilitar el driver |
| UART TX (TMC2209) | TX2 (D16) | PDN_UART del TMC2209 (via 1k) | Half-duplex: ver esquema de resistencias abajo |
| UART RX (TMC2209) | RX2 (D17) | PDN_UART del TMC2209 (via 1k) | Half-duplex: mismo nodo PDN_UART |
| Motor coils | — | A1 A2 B1 B2 | Conecta según datasheet del motor |
| VM (Driver) | — | +12–24 V | Alimentación potencia motor |
| GND (Driver) | GND | GND común | GND común con Arduino Due |
| AS5600 VCC | 3.3 V | VCC del AS5600 | 3.3 V recomendado |
| AS5600 GND | GND | GND del AS5600 | — |
| AS5600 SDA | SDA (D20) | SDA del AS5600 | I2C 0x36; pull-ups a 3.3 V si el módulo no las tiene |
| AS5600 SCL | SCL (D21) | SCL del AS5600 | — |
| HM-10 VCC | 3.3 V | VCC del HM-10 | Usar módulo compatible 3.3 V |
| HM-10 GND | GND | GND del HM-10 | — |
| HM-10 TXD | RX1 (D19) | TXD del HM-10 | 9600 8N1 por defecto |
| HM-10 RXD | TX1 (D18) | RXD del HM-10 | — |
| USB (log) | Programming Port USB | — | Para subir firmware y ver logs serie (Serial) |
Conexión UART TMC2209 (half-duplex):
– Conecta PDN_UART del TMC2209 a:
– Arduino Due TX2 a través de una resistencia de 1 kΩ
– Arduino Due RX2 a través de otra resistencia de 1 kΩ
– Si el módulo expone pin PDN/CFG, úsalo para UART. Consulta la hoja del módulo específico (algunos traen jumpers para activar UART).
Ajustes TMC2209:
– Microstepping objetivo: 1/16 microsteps (interpolación a 256 interna activa)
– Corriente RMS inicial: 800 mA (ajusta a tu motor térmicamente seguro)
– Modo stealthChop habilitado para suavidad a baja velocidad
Mecánica del AS5600:
– Monta el imán diametral en el eje del motor, centrado y a ~1–3 mm del chip según datasheet. Una desalineación reduce linealidad.
Código completo (Arduino Due, C++)
A continuación, un sketch integral que:
– Configura TMC2209 por UART
– Lee el AS5600 por I2C y genera conteo multiturno
– Implementa un control de posición en bucle cerrado con PID
– Genera STEP/DIR con limitación de velocidad y aceleración
– Expone una interfaz BLE (HM-10) para comandos GOTO, ZERO, KP/KI/KD, STATUS
– Emite logs por USB (Serial)
Bloques clave:
– ISR de control a 1 kHz
– ISR de generación de pasos a 40 kHz (tick 25 µs)
– Conversión ángulo AS5600 -> pasos (con multiturno)
– Parser de comandos BLE
// Proyecto: closed-loop-stepper-positioning con Arduino Due + TMC2209 + AS5600 + HM-10
// Toolchain: Arduino CLI 0.35.3, core arduino:sam 1.6.12
// Librerías: TMCStepper 0.7.3, DueTimer 1.7.2
#include <Arduino.h>
#include <Wire.h>
#include <TMCStepper.h>
#include <DueTimer.h>
// --------------------------- Configuración de pines ---------------------------
#define STEP_PIN 2
#define DIR_PIN 3
#define EN_PIN 4
// UART para TMC2209
HardwareSerial& TMC_UART = Serial2; // TX2(D16), RX2(D17)
// UART para HM-10 BLE
HardwareSerial& BLE = Serial1; // TX1(D18), RX1(D19)
// I2C AS5600
#define AS5600_ADDR 0x36
#define AS5600_RAW_ANGLE_H 0x0C
#define AS5600_RAW_ANGLE_L 0x0D
// ---------------------- Configuración eléctrica TMC2209 ----------------------
#define R_SENSE 0.110f
#define DRIVER_ADDRESS 0b00 // Ajustar si usas múltiples drivers
TMC2209Stepper driver(&TMC_UART, R_SENSE, DRIVER_ADDRESS);
// Microstepping
const uint16_t MICROSTEPS = 16; // 1/16
const uint16_t FULL_STEPS_PER_REV = 200; // motor 1.8°
const uint32_t STEPS_PER_REV = FULL_STEPS_PER_REV * MICROSTEPS; // 3200
// -------------------- Control, cinemática y límites -------------------------
volatile int32_t target_pos_steps = 0; // Objetivo en micro-pasos
volatile float cmd_vel_steps_s = 0.0f; // Velocidad comandada por el controlador [steps/s]
volatile float max_vel_steps_s = 12000.0f; // Límite velocidad
volatile float max_acc_steps_s2 = 40000.0f; // Límite aceleración
// PID de posición (error = target - measured)
volatile float Kp = 2.0f;
volatile float Ki = 0.0f;
volatile float Kd = 0.02f;
volatile float integ = 0.0f;
volatile float prev_err = 0.0f;
// Medición encoder multiturno
volatile uint16_t last_raw_angle = 0;
volatile int32_t turns = 0; // conteo de vueltas (multiturno)
volatile int32_t zero_offset_counts = 0; // puesta a cero
const float steps_per_encoder_count = (float)STEPS_PER_REV / 4096.0f;
// Estado de paso
volatile float phase_accum = 0.0f; // acumulador de fase para emitir pasos
volatile bool step_high = false; // estado del pulso STEP
volatile int8_t motion_dir = 1; // +1 fwd, -1 rev
// Telemetría
volatile int32_t measured_pos_steps = 0; // posición medida [steps]
volatile int32_t commanded_pos_steps = 0; // posición comandada (integración de pasos emitidos)
// Buffers BLE
char ble_buf[96];
size_t ble_idx = 0;
// Timers
// controlTimer: 1 kHz, stepTimer: 40 kHz (25 us)
DueTimer controlTimer = DueTimer(3);
DueTimer stepTimer = DueTimer(4);
// ---------------------- Utilidades de I2C para AS5600 -----------------------
uint16_t readAS5600RawAngle() {
Wire.beginTransmission(AS5600_ADDR);
Wire.write(AS5600_RAW_ANGLE_H);
if (Wire.endTransmission(false) != 0) {
return last_raw_angle; // si falla, devuelve último valor
}
Wire.requestFrom(AS5600_ADDR, 2u);
if (Wire.available() < 2) {
return last_raw_angle;
}
uint8_t high = Wire.read();
uint8_t low = Wire.read();
uint16_t angle = ((high & 0x0F) << 8) | low; // 12 bits: [11:8] en high[3:0], [7:0] en low
return angle;
}
// ---------------------- Inicialización del TMC2209 --------------------------
void initTMC2209() {
pinMode(EN_PIN, OUTPUT);
digitalWrite(EN_PIN, HIGH); // deshabilitado inicialmente (EN activo en LOW)
TMC_UART.begin(115200);
delay(50);
driver.begin(); // Carga parámetros por defecto
driver.toff(5); // driver enable (sgnificant >0)
driver.rms_current(800); // mA RMS (ajusta según motor)
driver.microsteps(MICROSTEPS);
driver.pdn_disable(true); // PDN/UART como UART, no power-down
driver.I_scale_analog(false);
driver.en_spreadCycle(false); // usar stealthChop
driver.pwm_autoscale(true); // calibración automática
driver.TCOOLTHRS(0xFFFFF); // umbral alto para stealthChop
driver.semin(5); driver.semax(2); driver.sedn(0b01); // CoolStep básico
digitalWrite(EN_PIN, LOW); // habilitar driver
}
// ----------------------- ISR del control (1 kHz) -----------------------------
void controlISR() {
// 1) Leer encoder y construir multiturno
uint16_t angle = readAS5600RawAngle();
int16_t delta = (int16_t)angle - (int16_t)last_raw_angle;
// Detectar cruces (wrap) en ±2048 (la mitad de 4096)
if (delta > 2048) {
turns -= 1; // pasó por 0 hacia atrás
} else if (delta < -2048) {
turns += 1; // pasó por 0 hacia delante
}
last_raw_angle = angle;
int32_t multi_counts = turns * 4096 + (int32_t)angle - zero_offset_counts;
int32_t pos_steps = (int32_t)lroundf(multi_counts * steps_per_encoder_count);
measured_pos_steps = pos_steps;
// 2) Calcular error de posición
int32_t err = target_pos_steps - measured_pos_steps;
// 3) PID
const float dt = 0.001f; // 1 ms
float f_err = (float)err;
float deriv = (f_err - prev_err) / dt;
integ += f_err * dt;
// anti wind-up sencillo: clamp integral
const float integ_limit = max_vel_steps_s * 0.5f;
if (integ > integ_limit) integ = integ_limit;
if (integ < -integ_limit) integ = -integ_limit;
float vel_cmd = Kp * f_err + Ki * integ + Kd * deriv;
// 4) Acel/vel limitación (rampa)
// Limitar aceleración incremental por periodo de control
float dv_max = max_acc_steps_s2 * dt;
float dv = vel_cmd - cmd_vel_steps_s;
if (dv > dv_max) dv = dv_max;
if (dv < -dv_max) dv = -dv_max;
cmd_vel_steps_s += dv;
// Limitar velocidad máxima
if (cmd_vel_steps_s > max_vel_steps_s) cmd_vel_steps_s = max_vel_steps_s;
if (cmd_vel_steps_s < -max_vel_steps_s) cmd_vel_steps_s = -max_vel_steps_s;
// Configurar dirección deseada (se usa en generador de pasos)
motion_dir = (cmd_vel_steps_s >= 0.0f) ? +1 : -1;
}
// ------------------- ISR del generador de pasos (25 us) ----------------------
void stepISR() {
static bool need_low_after_high = false;
if (need_low_after_high) {
digitalWrite(STEP_PIN, LOW);
need_low_after_high = false;
// Actualiza posición comandada tras el flanco de bajada
commanded_pos_steps += motion_dir;
return;
}
// Incrementa el acumulador con |vel|*dt (dt = 25e-6 s)
float inc = fabsf(cmd_vel_steps_s) * 0.000025f; // steps per tick
phase_accum += inc;
if (phase_accum >= 1.0f) {
// Preparar pulso: fijar DIR primero
digitalWrite(DIR_PIN, (motion_dir > 0) ? HIGH : LOW);
// Emitir flanco de subida STEP
digitalWrite(STEP_PIN, HIGH);
need_low_after_high = true;
phase_accum -= 1.0f;
}
}
// ------------------------- Parser de comandos BLE ----------------------------
// Comandos:
// - GOTO <steps>
// - ZERO
// - KP <val>, KI <val>, KD <val>
// - VMAX <steps_s>, AMAX <steps_s2>
// - STATUS
void handleCommand(const char* line) {
if (strncmp(line, "GOTO", 4) == 0) {
long val = atol(line + 4);
noInterrupts();
target_pos_steps = (int32_t)val;
interrupts();
BLE.println(F("OK GOTO"));
} else if (strncmp(line, "ZERO", 4) == 0) {
noInterrupts();
zero_offset_counts = turns * 4096 + (int32_t)last_raw_angle;
target_pos_steps = 0;
commanded_pos_steps = 0;
interrupts();
BLE.println(F("OK ZERO"));
} else if (strncmp(line, "KP ", 3) == 0) {
float v = atof(line + 3);
noInterrupts(); Kp = v; interrupts();
BLE.println(F("OK KP"));
} else if (strncmp(line, "KI ", 3) == 0) {
float v = atof(line + 3);
noInterrupts(); Ki = v; integ = 0; interrupts();
BLE.println(F("OK KI"));
} else if (strncmp(line, "KD ", 3) == 0) {
float v = atof(line + 3);
noInterrupts(); Kd = v; interrupts();
BLE.println(F("OK KD"));
} else if (strncmp(line, "VMAX ", 5) == 0) {
float v = atof(line + 5);
noInterrupts(); max_vel_steps_s = v; interrupts();
BLE.println(F("OK VMAX"));
} else if (strncmp(line, "AMAX ", 5) == 0) {
float v = atof(line + 5);
noInterrupts(); max_acc_steps_s2 = v; interrupts();
BLE.println(F("OK AMAX"));
} else if (strncmp(line, "STATUS", 6) == 0) {
noInterrupts();
long t = target_pos_steps;
long m = measured_pos_steps;
long c = commanded_pos_steps;
float v = cmd_vel_steps_s;
float kp = Kp, ki = Ki, kd = Kd;
interrupts();
BLE.print(F("T=")); BLE.print(t);
BLE.print(F(" M=")); BLE.print(m);
BLE.print(F(" C=")); BLE.print(c);
BLE.print(F(" V=")); BLE.print(v, 1);
BLE.print(F(" KP=")); BLE.print(kp, 3);
BLE.print(F(" KI=")); BLE.print(ki, 3);
BLE.print(F(" KD=")); BLE.print(kd, 3);
BLE.println();
} else {
BLE.println(F("ERR CMD"));
}
}
void pollBLE() {
while (BLE.available()) {
char ch = BLE.read();
if (ch == '\r' || ch == '\n') {
if (ble_idx > 0) {
ble_buf[ble_idx] = '\0';
handleCommand(ble_buf);
ble_idx = 0;
}
} else {
if (ble_idx < sizeof(ble_buf) - 1) {
ble_buf[ble_idx++] = ch;
}
}
}
}
// ------------------------------- setup/loop ----------------------------------
void setup() {
pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
digitalWrite(STEP_PIN, LOW);
digitalWrite(DIR_PIN, LOW);
Serial.begin(115200); // USB (Programming Port)
while (!Serial) { ; }
Serial.println(F("Init: Arduino Due closed-loop stepper with TMC2209 + AS5600 + HM-10"));
BLE.begin(9600); // HM-10 default
Wire.begin(); // I2C
// Inicializar TMC2209
initTMC2209();
// Inicializar AS5600 base
last_raw_angle = readAS5600RawAngle();
turns = 0;
zero_offset_counts = 0;
// Timers
controlTimer.attachInterrupt(controlISR).setFrequency(1000).start(); // 1 kHz
stepTimer.attachInterrupt(stepISR).setFrequency(40000).start(); // 40 kHz (25 us)
Serial.println(F("Timers started. Send BLE commands: GOTO, ZERO, KP/KI/KD, VMAX/AMAX, STATUS"));
}
uint32_t lastLog = 0;
void loop() {
// Consola BLE
pollBLE();
// Log periódico por USB
uint32_t now = millis();
if (now - lastLog > 500) {
noInterrupts();
long t = target_pos_steps;
long m = measured_pos_steps;
long c = commanded_pos_steps;
float v = cmd_vel_steps_s;
interrupts();
Serial.print(F("[INFO] T=")); Serial.print(t);
Serial.print(F(" M=")); Serial.print(m);
Serial.print(F(" C=")); Serial.print(c);
Serial.print(F(" V=")); Serial.print(v, 1);
Serial.println();
lastLog = now;
}
}
Explicación breve de partes clave:
– initTMC2209 configura el driver para 1/16 microstepping, corriente RMS, stealthChop y UART activo en PDN.
– controlISR (1 kHz) ejecuta el PID de posición sobre la medición de AS5600; limita velocidad y aceleración para suavidad.
– stepISR (40 kHz) implementa un generador de pulsos con acumulador de fase: emite un pulso STEP cuando la “energía” acumulada supera 1 micro-paso.
– La multiturn del AS5600 detecta cruces por 0/4095 y ajusta un contador de vueltas; el comando ZERO re-referencia la posición a 0 pasos.
– La interfaz BLE acepta comandos de texto sencillos (por ejemplo: “GOTO 6400” para dos vueltas si 3200 steps/rev).
Compilación, flasheo y ejecución
A continuación, pasos reproducibles con Arduino CLI 0.35.3 usando Arduino Due (Programming Port).
Instalación de Arduino CLI y core arduino:sam
Linux (Ubuntu 22.04):
# 1) Instalar Arduino CLI 0.35.3 en $HOME/bin
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=$HOME/bin sh -s -- v0.35.3
echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
# 2) Verificar versión
arduino-cli version
# Debe mostrar: arduino-cli Version: 0.35.3
# 3) Inicializar configuración
arduino-cli config init
# 4) Actualizar índice de cores y librerías
arduino-cli core update-index
# 5) Instalar el core Arduino SAM (Due)
arduino-cli core install arduino:sam@1.6.12
# 6) Instalar librerías necesarias
arduino-cli lib install "TMCStepper@0.7.3"
arduino-cli lib install "DueTimer@1.7.2"
Windows 11 (PowerShell):
– Descarga binario de Arduino CLI 0.35.3 para Windows desde GitHub Releases, agrega su carpeta al PATH del usuario.
– En PowerShell:
arduino-cli version
arduino-cli core update-index
arduino-cli core install arduino:sam@1.6.12
arduino-cli lib install "TMCStepper@0.7.3"
arduino-cli lib install "DueTimer@1.7.2"
Nota: En Windows, instala los drivers Arduino (incluidos con IDE o CLI) para el “Arduino Due (Programming Port)”. El puerto aparecerá como COMx.
Compilación y subida
1) Conecta el Arduino Due por el Programming Port (no el Native USB Port).
2) Guarda el sketch anterior como carpeta/proyecto, por ejemplo: closed_loop_due/closed_loop_due.ino
3) Identifica el puerto:
– Linux:
arduino-cli board list
# Ejemplo de salida:
# Port Type Board Name FQBN
# /dev/ttyACM0 Serial Port (USB) Arduino Due (Programming) arduino:sam:arduino_due_x_dbg
- Windows:
arduino-cli board list
# Buscar COMx correspondiente al "Arduino Due (Programming Port)"
4) Compila:
arduino-cli compile --fqbn arduino:sam:arduino_due_x_dbg closed_loop_due
5) Sube el firmware:
# Linux: ajusta el puerto si es distinto
arduino-cli upload -p /dev/ttyACM0 --fqbn arduino:sam:arduino_due_x_dbg --verify closed_loop_due
# Windows (PowerShell), ajusta COMx
arduino-cli upload -p COM5 --fqbn arduino:sam:arduino_due_x_dbg --verify closed_loop_due
6) Abre la consola serie para logs (USB):
# Linux
screen /dev/ttyACM0 115200
# o
minicom -D /dev/ttyACM0 -b 115200
En Windows, usa PuTTY/Serial a 115200 baudios en el COMx del Programming Port.
Validación paso a paso
Objetivo: demostrar “closed-loop-stepper-positioning” con el AS5600 como sensor de posición y el TMC2209 como actuador, con comandos BLE y telemetría por USB.
1) Revisión eléctrica de seguridad
– Verifica que EN del TMC2209 esté inicialmente en HIGH (driver deshabilitado) antes de dar alimentación de motor.
– Asegúrate de GND común entre fuente del motor, driver y Arduino Due.
– Alimenta el TMC2209 con 12–24 V, sin motor inicialmente, para comprobar que no hay sobrecorriente.
– Conecta el motor después de la verificación de alimentación.
2) Puesta en marcha del software
– Conecta el Programming Port del Due, sube el firmware (ver comandos).
– Abre el monitor serie a 115200 baudios. Debes ver:
– “Init: Arduino Due closed-loop stepper …”
– “Timers started. Send BLE commands: …”
– Si no ves mensajes, revisa que usas el Programming Port y que el puerto serie es correcto.
3) Prueba del encoder AS5600
– Sin cerrar el lazo, ejecuta comandos BLE para ver STATUS.
– Desde el móvil, con la app BLE:
– Empareja con HM-10 (nombre por defecto “HMSoft” o similar).
– Abre la UART BLE y envía “STATUS”.
– Debes recibir algo como: “T=0 M=0 C=0 V=0.0 KP=2.000 KI=0.000 KD=0.020”
– Gira el eje manualmente: el campo M (medida) debe cambiar; si cambia al revés de lo esperado, luego invertirás DIR en el cableado o en software.
4) Cierre de lazo básico con ZERO y GOTO
– Envía “ZERO”: pondrá el origen en la posición actual y fijará T=0.
– Envía “GOTO 3200”: objetivo 1 vuelta (microstepping 1/16 => 3200 µpasos).
– Observa:
– El motor debe acelerar, moverse y detenerse cerca del objetivo.
– En Serial (USB), verás logs de T, M, C, V. M debe converger a T con error pequeño.
5) Ajuste PID (si es necesario)
– Si hay sobreoscilación (overshoot) o vibración:
– Reduce Kp o aumenta Kd ligeramente. Ejemplo:
– “KD 0.05”
– “KP 1.5”
– Si hay error permanente:
– Introduce una pequeña Ki. Ejemplo: “KI 0.005”
– Verifica el comportamiento repitiendo GOTO a varios objetivos: 0, 1600, 3200, -1600, etc.
6) Verificación de límites VMAX y AMAX
– Envía “VMAX 8000” para bajar velocidad máx si el motor salta pasos.
– Envía “AMAX 20000” si notas golpes al arrancar; valores bajos suavizan el arranque/parada.
– Comprueba estabilidad frente a cambios de objetivo consecutivos.
7) Evaluación de seguimiento
– Compara M (medido) y C (comandado). En un buen ajuste, ambos serán cercanos y convergerán al objetivo T.
– Un desfase sostenido indica desajuste de PID o saturación (VMAX/AMAX demasiado bajos).
8) Comando sostenido y multiturno
– Prueba GOTO 12800 (≈4 vueltas) y regresa a 0.
– Asegura que el multiturno no presenta saltos (M crece/ decrece continuamente).
9) Comprobación BLE frente a USB
– Confirma que los comandos por BLE afectan al comportamiento y se reflejan en el log USB.
10) Prueba de carga
– Si es posible, aplica una ligera carga resistiva al eje y verifica que el lazo corrige el error y sostiene la posición.
Troubleshooting
1) El Due no aparece en la lista de puertos o la subida falla
– Causa: cable USB inadecuado (solo carga), drivers no instalados o puerto incorrecto.
– Solución:
– Usa un cable USB de datos y el Programming Port.
– En Linux: agrega tu usuario al grupo dialout: sudo usermod -a -G dialout $USER y reabre sesión.
– Verifica con arduino-cli board list y ajusta el puerto en upload.
2) El motor vibra o no se mueve al enviar GOTO
– Causa: fase de motor mal cableada (A/B invertidas) o microstepping/dir invertido.
– Solución:
– Intercambia una bobina (A1/A2) o B1/B2 para corregir vibración.
– Invierte el sentido DIR en software (cambia HIGH/LOW) o invierte el cable DIR.
3) El encoder mide al revés del movimiento
– Causa: convención de sentido opuesta entre AS5600 y pasos.
– Solución:
– Cambia el sentido DIR en software o multiplica measured_pos_steps por -1 en el cálculo, o invierte el imán 180°.
4) Pérdida de pasos a alta velocidad
– Causa: VMAX/AMAX excesivos, corriente insuficiente o tensión de alimentación baja.
– Solución:
– Reduce VMAX/AMAX (comandos VMAX/AMAX).
– Aumenta rms_current en TMC (recompila con mayor driver.rms_current dentro de límite térmico).
– Sube VM a 24 V si tu hardware lo permite.
5) TMC2209 no responde por UART (config no se aplica)
– Causa: cableado UART half-duplex incorrecto o PDN no configurado como UART.
– Solución:
– Verifica resistencias de 1 kΩ desde TX2 y RX2 al pin PDN_UART del TMC2209.
– Asegura driver.pdn_disable(true) y velocidad 115200 en TMC_UART.
– Comprueba jumpers del módulo (algunos requieren puentear para UART).
6) Lectura del AS5600 salta o es ruidosa
– Causa: imán descentrado, distancia inadecuada o cable I2C largo sin pull-ups adecuadas.
– Solución:
– Centra mejor el imán, ajusta la distancia a 1–3 mm.
– Añade pull-ups de 4.7 kΩ a 3.3 V en SDA/SCL si el módulo no las trae.
– Filtra con media móvil o un pequeño filtro derivativo (aumenta Kd, reduce Kp).
7) HM-10 no conecta o no recibe comandos
– Causa: módulo BLE a baudios distintos o sin alimentación correcta.
– Solución:
– Asegura BLE.begin(9600) y que tu HM-10 esté a 9600 (de fábrica).
– Verifica VCC 3.3 V y conexión TXD→RX1, RXD→TX1.
– Reinicia el módulo y vuelve a parear.
8) El lazo oscila o tarda demasiado en asentar
– Causa: PID mal ajustado.
– Solución:
– Empieza con Ki = 0, aumenta Kp hasta un ligero overshoot, añade Kd para amortiguar.
– Introduce Ki pequeño para eliminar error de régimen permanente.
– Reajusta VMAX/AMAX para no saturar el actuador.
Mejoras/variantes
- Estrategia de control
- Reemplazar PID por control por perfil trapezoidal/cinco segmentos y lazo de seguimiento de velocidad + lazo de posición (cascada).
-
Añadir feedforward de velocidad/acceleración basado en la cinemática planeada.
-
Telemetría avanzada
-
Transmitir por BLE un paquete periódico JSON con {T, M, C, V, err} y visualizarlo en una app móvil o en un dashboard.
-
Gestión de fallos
- Añadir detección de pérdida de seguimiento (|T-M| > umbral por tiempo) y estrategia de reintento o alarma.
-
Monitorizar sobrecorriente/temperatura del driver con pines DIAG del TMC2209.
-
Multieje
-
Extender a dos ejes con Serial3 para el segundo TMC2209 y un segundo AS5600 en dirección I2C alternativa (usar versiones de AS5600 con ADDR o multiplexor I2C).
-
Autotuning
-
Implementar un procedimiento de sintonía automática: escalón pequeño, medir respuesta, estimar parámetros de planta y derivar Kp, Ki, Kd (método Ziegler-Nichols o IMC).
-
Sin librería de encoder
- Si deseas robustez total frente a dependencias, ya se usa lectura I2C directa; puedes añadir calibración del AS5600 (offset) escribiendo registros del chip.
Checklist de verificación
- [ ] Instalada Arduino CLI 0.35.3 y core arduino:sam 1.6.12
- [ ] Librerías TMCStepper 0.7.3 y DueTimer 1.7.2 instaladas
- [ ] Conexión eléctrica revisada: GND común, VM 12–24 V, motor conectado correctamente
- [ ] PDN_UART cableado con dos resistencias de 1 kΩ a TX2 y RX2
- [ ] AS5600 conectado a 3.3 V, SDA (D20), SCL (D21) y pull-ups si faltan
- [ ] HM-10 conectado a Serial1 (TX1/RX1), alimentado a 3.3 V, BLE funcional
- [ ] Firmware compilado con FQBN arduino:sam:arduino_due_x_dbg y subido sin errores
- [ ] Log USB visible a 115200 baudios con mensajes de inicio y estado
- [ ] Comando BLE “ZERO” responde “OK ZERO”
- [ ] Comando BLE “GOTO 3200” mueve 1 vuelta y asienta cerca del objetivo
- [ ] Ajuste PID realizado (sin oscilaciones, error de régimen pequeño)
- [ ] VMAX y AMAX adecuados (sin pérdidas de pasos ni golpes)
- [ ] Multiturno correcto (varias vueltas en ambos sentidos sin saltos)
Apéndice: configuración opcional del HM-10 mediante AT
Si deseas renombrar el HM-10 o fijar su velocidad, temporalmente conéctalo a un adaptador USB-UART a 9600 baudios y envía:
AT // debe responder OK
AT+NAMECLStepper // renombra el periférico
AT+BAUD4 // 9600 (por defecto); BAUD8 sería 115200 si lo cambias
AT+RESET
Asegúrate de mantener BLE.begin(9600) si usas 9600 baudios.
Notas finales sobre coherencia del hardware
- El tutorial está estrictamente alineado con el modelo: Arduino Due + TMC2209 stepper drivers + AS5600 encoders + HM-10 BLE. Todo el cableado, código y comandos se han ajustado a esta combinación.
- El uso del core arduino:sam 1.6.12 y la FQBN arduino:sam:arduino_due_x_dbg asegura compatibilidad con el Programming Port del Arduino Due en Arduino CLI 0.35.3.
Encuentra este producto y/o libros sobre este tema en Amazon
Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.



