You dont have javascript enabled! Please enable it!

Caso práctico: Bucle cerrado: Arduino Due+TMC2209+AS5600

Caso práctico: Bucle cerrado: Arduino Due+TMC2209+AS5600 — hero

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

Ir a 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.

Quiz rápido

Pregunta 1: ¿Cuál es la versión probada de Ubuntu mencionada en el artículo?




Pregunta 2: ¿Qué tipo de controlador se menciona como parte del dispositivo del proyecto?




Pregunta 3: ¿Cuál es la versión del Arduino CLI utilizada en el artículo?




Pregunta 4: ¿Qué tipo de sensor se utiliza en el proyecto?




Pregunta 5: ¿Cuál es el voltaje de operación del Arduino Due?




Pregunta 6: ¿Qué librería se menciona para el manejo de temporizadores?




Pregunta 7: ¿Qué tipo de motor se menciona en el artículo?




Pregunta 8: ¿Cuál es la capacidad típica de la fuente de alimentación para el motor?




Pregunta 9: ¿Qué software auxiliar se menciona como opcional para validación?




Pregunta 10: ¿Qué es R_SENSE en el contexto del controlador TMC2209?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Ingeniero Superior en Electrónica de Telecomunicaciones e Ingeniero en Informática (titulaciones oficiales en España).

Sígueme:
Scroll al inicio