Controlar un brazo robótico de 4 motores con Arduino

Vamos a ver como controlar desde el ordenador un brazo robotico con cuatro motores. Aunque realmente del movimiento se ocupan tres, el cuarto es solo para abrir y cerrar «la pinza».Vamos a nombrar los servos de la siguiente manera:

  • base: se encuentra en la base del robot y controla el giro del brazo
  • hombro: controla «el hombro» del brazo
  • codo: controla «el codo» del brazo
  • mano: controla la apertura y cierre de la pinza

En las siguientes fotos puede verse el brazo que voy a usar. El servo «base» se encuentra en la parte inferior del brazo. El servo «hombro» en la parte superior de la fotografía (en la foto vista desde arriba), el servo «codo» en la inferior y el servo «mano» en la mano (este era sencillo).

Para controlar el movimiento de estos servos usaremos dos variables, una guardará el valor en grados actual, la otra el valor en grados al que debe de moverse. En cada iteración de la función loop() se llamara a la función ActualizarServos() que se ocupa de actualizar el valor del servo. Si ambas variables coinciden no se hace nada, si son distintas cada iteración se sumará o restará un grado para acercarse al valor deseado. Esto se hace así para evitar movimientos demasiado rápidos que puedan dañar el robot o golpear alguna cosa del entorno. La velocidad se puede controlar con el delay al final de la función loop()

Cada servo tendrá unos grados mínimos y máximos delos que no podrá pasar, delimitados por la estructura del brazo (por ejemplo, que choque con la propia estructura del brazo o que la articulación no «da más de si»). Se usaran dos variables para estar seguro que no pasamos esos limites. Por ejemplo para la base se usaran: basePosMax y basePosMin.

Si se intenta establecer un valor mayor o menor del fijado por esas dos variables se igualará al valor de estas. Asi evitamos situaciones que puedan dañar el brazo.

Para controlar el brazo usaremos comandos de texto enviados a través del puerto serie

Lo comandos son:

  • Sn:grados: n indica el servo y grados la posicion en grados a la que debe ir
  • Q: mueve cada servo a la «posición de apagado» / «posición de inicio»
  • W: escribe en consola la posición en grados de cada servo

El comando Q es necesario para poder «parar» el brazo. No se guarda el estado de los servos, por lo que para evitar que el brazo realice movimientos bruscos al iniciarse hay que llevarlo a la posición de «apagado» o de «arranque» (obviamente son la misma).

El comando S tiene las siguientes correspondencias con los servos:

  • S1 base
  • S2 codo
  • S3 hombro
  • S4 mano

Por ejemplo, para cerrar la mano se podria usar el comando S4:35

El código para el controlarlo es el siguiente:

#include <Servo.h> 

// Se definen los pines a los que están conectados los servos
const int basePin = 5;
const int hombroPin = 11;
const int codoPin = 3;
const int manoPin = 10;

// Se crean los objetos Servo correspondientes a cada servo
Servo baseServo;
Servo hombroServo;
Servo codoServo;
Servo manoServo;

// Variables para almacenar la posición actual y destino
int basePos = 90;
int hombroPos = 90;
int codoPos = 120;
int manoPos = 10;

int basePosDest = basePos;
int hombroPosDest = hombroPos;
int codoPosDest = codoPos;
int manoPosDest = manoPos;

int basePosMax = 180;
int hombroPosMax = 150;
int codoPosMax = 170;
int manoPosMax = 35;

int basePosMin = 0;
int hombroPosMin = 80;
int codoPosMin = 90;
int manoPosMin = 10;

void setup() {
  // Se inicializan los servos en la posición central
  baseServo.write(basePos);
  hombroServo.write(hombroPos);
  codoServo.write(codoPos);
  manoServo.write(manoPos);

  // Se inician los objetos Servo
  baseServo.attach(basePin);
  hombroServo.attach(hombroPin);
  codoServo.attach(codoPin);
  manoServo.attach(manoPin);

  // Se inicia la comunicación por el puerto serie
  Serial.begin(9600);
}

void loop() {
  // Se actualizan los servos
  ActualizarServos();

  // Se espera para que los servos alcancen su nueva posición
  delay(20);
}

// Función que se llama al final decada iteracion de loop
void serialEvent() {
  // Se lee la línea recibida del puerto serie
  String data = Serial.readStringUntil('\n');
  char command = data.charAt(0);
  if(command == 'Q'){
    basePosDest = 90;
    hombroPosDest = 90;
    codoPosDest = 120;
    manoPosDest = 10;
  }

  if(command == 'W'){
    Serial.print("S1 Base:   ");
    Serial.print(basePosDest);
    Serial.print("   [");
    Serial.print(basePosMin);
    Serial.print(" - ");
    Serial.print(basePosMax);
    Serial.println("]");

    Serial.print("S2 Codo: ");
    Serial.print(codoPosDest);
    Serial.print("   [");
    Serial.print(codoPosMin);
    Serial.print(" - ");
    Serial.print(codoPosMax);
    Serial.println("]");    

    Serial.print("S3 Hombro: ");
    Serial.print(hombroPosDest);
    Serial.print("   [");
    Serial.print(hombroPosMin);
    Serial.print(" - ");
    Serial.print(hombroPosMax);
    Serial.println("]");

    Serial.print("S4 Mano:   ");
    Serial.print(manoPosDest);
    Serial.print("   [");
    Serial.print(manoPosMin);
    Serial.print(" - ");
    Serial.print(manoPosMax);
    Serial.println("]");
  }
  if(command == 'S'){
    // Se separa la información de servo y ángulo
    // Se obtiene el índice del servo a partir del segundo caracter
    int servoIndex = data.charAt(1) - '0'; 
    // Se obtiene el ángulo a partir del cuarto caracter hasta el final
    int angle = data.substring(3).toInt(); 
    
    // Se actualiza la posición deseada del servo correspondiente
    switch (servoIndex) {
      case 1:
        basePosDest = angle;
        if(basePosDest > basePosMax){
          basePosDest = basePosMax;
        }
        if(basePosDest < basePosMin){
          basePosDest = basePosMin;
        }
        break;
      case 2:
        codoPosDest = angle;
        if(codoPosDest > codoPosMax){
          codoPosDest = codoPosMax;
        }
        if(codoPosDest < codoPosMin){
          codoPosDest = codoPosMin;
        }
        break;
      case 3:
        hombroPosDest = angle;
        if(hombroPosDest > hombroPosMax){
          hombroPosDest = hombroPosMax;
        }
        if(hombroPosDest < hombroPosMin){
          hombroPosDest = hombroPosMin;
        }
        break;
      case 4:
        manoPosDest = angle;
        if(manoPosDest > manoPosMax){
          manoPosDest = manoPosMax;
        }
        if(manoPosDest < manoPosMin){
          manoPosDest = manoPosMin;
        }
        break;
      default:
        break;
    }
  }
}

// Función que actualiza la posición de los servos
void ActualizarServos() {
  if (basePos < basePosDest) {
    basePos++;
  } else if (basePos > basePosDest) {
    basePos--;
  }
  baseServo.write(basePos);

  if (hombroPos < hombroPosDest) {
    hombroPos++;
  } else if (hombroPos > hombroPosDest) {
    hombroPos--;
  }
  hombroServo.write(hombroPos);

  if (codoPos < codoPosDest) {
    codoPos++;
  } else if (codoPos > codoPosDest) {
    codoPos--;
  }
  codoServo.write(codoPos);

  if (manoPos < manoPosDest) {
    manoPos++;
  } else if (manoPos > manoPosDest) {
    manoPos--;
  }
  manoServo.write(manoPos);
}

Puedes ver más detalles sobre este tema en el siguiente vídeo de mi canal deYoutube:

Haz click para ver el vídeo en mi canal deYoutube

Y si estas interesado en el tema puedes ver la lista de vídeos.

Un comentario en “Controlar un brazo robótico de 4 motores con Arduino

  1. Pingback: Controlar Arduino desde el navegador | Construyendo a Chispas

Los comentarios están cerrados.