arduino-brazo-robotico-4dof

Cómo controlar un brazo robótico de cuatro ejes con Arduino

  • 7 min

Un brazo robótico es un mecanismo articulado capaz de posicionar un elemento terminal mediante el movimiento coordinado de varias articulaciones.

Hasta ahora hemos movido un servo (en la Caja Fuerte) o dos (en el Seguidor Solar). Pero coordinar cuatro o más articulaciones para mover un objeto en el espacio tridimensional es un salto cualitativo enorme.

En este artículo vamos a montar y controlar un brazo robótico de tipo antropomórfico (imita un brazo humano) con 4 Grados de Libertad (4-DOF).

¿Qué es un Grado de Libertad (DOF)? En robótica, cada articulación independiente que puede controlar el robot se considera un grado de libertad. Nuestro brazo tendrá:

  1. Cintura (Base): Rotación horizontal.
  2. Hombro: Elevación del brazo principal.
  3. Codo: Elevación del antebrazo.
  4. Garra (End Effector): Apertura y cierre.

Cinemática directa e inversa

Antes de programar, debemos entender el problema matemático al que nos enfrentamos. Hay dos formas de controlar un robot:

  1. Cinemática Directa (Forward Kinematics): Nosotros le decimos al robot los ángulos de cada motor (ej: “Pon el codo a 90º y el hombro a 45º”) y la mano del robot acaba en una posición resultante. Esto es fácil de programar, pero difícil de usar si queremos coger un objeto en una mesa.
  2. Cinemática inversa (inverse kinematics): Indicamos una coordenada, por ejemplo (x, y, z), y el controlador calcula qué ángulos necesitan las articulaciones para alcanzarla.

En este proyecto inicial, implementaremos una Cinemática Directa Manual: usaremos potenciómetros para controlar directamente el ángulo de cada articulación. Es el paso previo necesario para verificar que la mecánica funciona antes de meterse en las complejas ecuaciones de la cinemática inversa.

Componentes

  • [1x|blue] Arduino Uno | O Nano + Shield de expansión (recomendado)
  • [2x|green] Servo SG90 | Para Garra y Base
  • [2x|orange] Servo MG90S (piñonería metálica) | Para Hombro y Codo {recomendado}
  • [4x|yellow] Potenciómetros lineales 10kΩ | Control manual de articulaciones
  • [1x|red] Fuente externa regulada | Dimensionada para la corriente de bloqueo de los servos

La mecánica es crítica. Puedes usar un kit ligero o imprimir la estructura en 3D, pero debes comprobar que el par de los servos sea suficiente para el peso y la longitud de cada brazo.

Nunca alimentes 4 servos desde el pin 5V de Arduino. El consumo pico puede reiniciar la placa (Brown-out) o quemar el regulador. Necesitas una fuente externa (baterías o transformador) compartiendo la tierra (GND) con Arduino.

Esquema de conexión

El cableado puede convertirse en una ensalada rápidamente. Mantén los conductores ordenados y deja holgura suficiente en cada articulación.

Potenciómetros de control

Cada potenciómetro funciona como divisor de tensión. El pin central va a la entrada analógica correspondiente.

[ { “from”: “Potenciómetro 1 (Wiper)”, “to”: “Pin A0”, “color”: “yellow”, “note”: “Extremos a 5V y GND” }, { “from”: “Potenciómetro 2 (Wiper)”, “to”: “Pin A1”, “color”: “yellow”, “note”: “Extremos a 5V y GND” }, { “from”: “Potenciómetro 3 (Wiper)”, “to”: “Pin A2”, “color”: “yellow”, “note”: “Extremos a 5V y GND” }, { “from”: “Potenciómetro 4 (Wiper)”, “to”: “Pin A3”, “color”: “yellow”, “note”: “Extremos a 5V y GND” }, { “from”: “Extremos potenciómetros”, “to”: “5V y GND Arduino”, “color”: “gray” } ]

Servos del brazo

Servo.h genera los pulsos mediante temporizadores, así que estos pines no necesitan PWM por hardware.

[ { “from”: “Servo Base señal”, “to”: “Pin 3”, “color”: “green” }, { “from”: “Servo Hombro señal”, “to”: “Pin 5”, “color”: “green” }, { “from”: “Servo Codo señal”, “to”: “Pin 6”, “color”: “green” }, { “from”: “Servo Garra señal”, “to”: “Pin 9”, “color”: “green” }, { “from”: “Servos VCC (todos)”, “to”: “Fuente externa 5V”, “color”: “red”, “note”: “NO al pin 5V de Arduino” }, { “from”: “Servos GND (todos)”, “to”: “GND fuente + GND Arduino”, “color”: “black”, “note”: “Tierra común obligatoria” } ]

El código

Vamos a crear un código escalable. En lugar de copiar y pegar 4 veces lo mismo, usaremos Arrays y Bucles para gestionar las articulaciones. Esto hace que el código sea profesional y fácil de ampliar a robots de 6 ejes.

Objetos y estructuras

Usaremos la librería Servo.h. Además, definiremos un “mapa” de nuestros límites. No todos los servos pueden girar de 0 a 180º en el robot montado; a veces la mecánica choca antes.

#include <Servo.h>

// Definimos el número de articulaciones
const int NUM_SERVOS = 4;

// Creamos los objetos Servo
Servo brazo[NUM_SERVOS];

// Pines de conexión
const int pinesPot[NUM_SERVOS]   = {A0, A1, A2, A3};
const int pinesServo[NUM_SERVOS] = {3, 5, 6, 9};

// --- CALIBRACIÓN MECÁNICA ---
// Ajusta estos valores para no forzar los motores
// Orden: {Base, Hombro, Codo, Garra}
const int anguloMin[NUM_SERVOS] = {0, 15, 0, 10};   // Mínimo físico
const int anguloMax[NUM_SERVOS] = {180, 165, 180, 100}; // Máximo físico

// Variables para suavizado (evitar temblores)
int valorLeido[NUM_SERVOS];
int anguloActual[NUM_SERVOS];
Copied!

setup

Inicializamos los servos e iteramos por los arrays para configurarlo todo.

void setup() {
  Serial.begin(9600);

  for (int i = 0; i < NUM_SERVOS; i++) {
    brazo[i].attach(pinesServo[i]);
    
    // Inicializamos en una posición segura (90 grados)
    // para que el robot no dé un "latigazo" al encender
    brazo[i].write(90);
  }
  
  Serial.println("Robot Iniciado. Control Manual Activado.");
  delay(1000);
}
Copied!

Lectura y mapeo en loop

Aquí es donde traducimos el movimiento de nuestra mano (potenciómetro) al movimiento del robot.

Un problema común es el “jitter” (temblor). Los potenciómetros baratos fluctúan. Para evitarlo, solo actualizaremos el servo si el valor cambia significativamente.

void loop() {
  for (int i = 0; i < NUM_SERVOS; i++) {
    // 1. Leer el valor analógico (0 - 1023)
    int lectura = analogRead(pinesPot[i]);
    
    // 2. Mapear al rango de ángulos permitido para esa articulación
    int anguloDeseado = map(lectura, 0, 1023, anguloMin[i], anguloMax[i]);
    
    // 3. Filtro simple para evitar jitter
    // Solo movemos si la diferencia es mayor a 2 grados
    if (abs(anguloDeseado - anguloActual[i]) > 2) {
      brazo[i].write(anguloDeseado);
      anguloActual[i] = anguloDeseado;
    }
  }
  
  // Un pequeño delay para dar estabilidad al ADC
  delay(15);
}
Copied!

Suavizado exponencial del movimiento

El código anterior funciona, pero el movimiento será tan brusco como tu mano. Los robots industriales se mueven con elegancia. Podemos mejorar esto añadiendo una pequeña inercia por software.

Sustituye el bloque del loop por este concepto:

// Factor de suavizado (0.1 = muy suave/lento, 0.9 = rápido/brusco)
float alpha = 0.1; 

// En variables globales cambiamos anguloActual a float
// float anguloSuavizado[NUM_SERVOS];

// Dentro del loop...
int lectura = analogRead(pinesPot[i]);
int target = map(lectura, 0, 1023, anguloMin[i], anguloMax[i]);

// Fórmula de media móvil exponencial
anguloSuavizado[i] = (alpha * target) + ((1.0 - alpha) * anguloSuavizado[i]);

brazo[i].write((int)anguloSuavizado[i]);
Copied!

Esto hará que el robot parezca tener “peso” e inercia, moviéndose de forma orgánica y fluida.

Retos y siguientes pasos

Construir el brazo es solo el principio. Los verdaderos desafíos vienen ahora:

  1. Grabar y Reproducir: ¿Podrías añadir un botón que, al pulsarlo, guarde la posición de los 4 servos en un array? Si guardas varios pasos, podrías hacer que el robot repita una secuencia (coger objeto -> moverlo -> soltarlo) automáticamente.
  2. Cinemática Inversa: El “Santo Grial”. Implementar las matemáticas para que tú le digas al robot irA(10, 5, 4) (coordenadas cm) y él solo calcule los ángulos.
  3. Bluetooth: Sustituir los potenciómetros por una App en tu móvil que envíe las coordenadas vía Bluetooth (HC-05).