¿Como Mover tu Brazo Robotico 6s Kimo con Control Remoto?

¿Como Mover tu Brazo Robotico 6s Kimo con Control Remoto?


Explora el emocionante mundo de la robótica con nuestra guía en línea. Aprende a controlar con precisión tu Brazo Robótico Kimo 6s utilizando un control infrarrojo y su módulo IR Remote. Te acompañaremos paso a paso en este fascinante proceso, asegurándonos de que domines cada detalle para sacar el máximo provecho de tu brazo robótico.

Materiales Necesarios:


Pasos a Seguir:

Primero debes realizar la siguiente conexión electrónica, se mostrara el esquema en Arduino UNO pero la conexión en expansión de Arduino Nano es la misma, si deseas descargar el esquema solo debes dar clic en la imagen del esquema:

2. Ahora debes cargar los códigos a tu Arduino, si no sabes  como cargar códigos a tu  Arduino a continuación puedes aprender como:  APRENDER

Librerías Necesarias:

El desarrollo de proyectos de robótica y automatización con Arduino requiere del uso de ciertas librerías especializadas que facilitan la programación y control de dispositivos. Algunas de las librerías necesarias en este proyecto son:

  • IRremote: Esta librería permite la recepción y decodificación de señales infrarrojas, lo cual es fundamental para interactuar con controles remotos infrarrojos y otros dispositivos de entrada. Descárgala AQUI
  • Servo: La librería Servo simplifica el control de servomotores, permitiendo configurar y mover los servomotores con facilidad mediante el protocolo PWM (modulación por ancho de pulso).

Código Completo:

Primero te mostraremos el código completo y luego procederemos a explicar paso a paso.

/*Movimiento Brazo Robotico con Monitor Serial
   Desarrollado por RDC - Robotica de Colombia
   Visitanos:
   www.facebook.com/roboticadecolombia
   www.youtube.com/@RoboticadeColombia
   www.instagram.com/roboticadecolombia/
   Mercadolibre: www.mercadolibre.com.co/perfil/ROBOTICADECOLOMBIA
*/

#include <IRremote.h>
#include <Servo.h>

Servo rotacion;
Servo Hombro1;
Servo Hombro2;
Servo Codo;
Servo muneca;
Servo Garra;

int angulorotacion = 90;
int angulohombro1 = 50;
int angulohombro2 = 130;
int angulocodo = 180;
int angulomuneca = 40;
int angulogarra = 20;

int RECV_PIN = 3;
int STATUS_PIN = 13;

IRrecv irrecv(RECV_PIN);
IRsend irsend;

decode_results results;

void setup() {
  Serial.begin(115200);
  Serial.println("Iniciando... ");

  irrecv.enableIRIn();  // Iniciar el receptor
  pinMode(STATUS_PIN, OUTPUT);

  rotacion.attach(2);
  Hombro1.attach(4);
  Hombro2.attach(5);
  Codo.attach(6);
  muneca.attach(7);
  Garra.attach(8);

  rotacion.write(angulorotacion);
  Hombro1.write(angulohombro1);
  Hombro2.write(angulohombro2);
  Codo.write(angulocodo);
  muneca.write(angulomuneca);
  Garra.write(angulogarra);
  delay(500);
}

void moverServoSuavemente(Servo& servo, int anguloInicio, int anguloFin, int tiempoTotal) {
  int pasos = 20;  // número de pasos para la rampa
  int incremento = (anguloFin - anguloInicio) / pasos;
  int delayTiempo = tiempoTotal / pasos;

  for (int i = 0; i <= pasos; i++) {
    servo.write(anguloInicio + incremento * i);
    delay(delayTiempo);
  }
}

// Almacenamiento para el código grabado
int codeType = -1;              // El tipo de código
unsigned long codeValue;        // El valor del código si no es crudo
unsigned int rawCodes[RAWBUF];  // Las duraciones si es crudo
int codeLen;                    // La longitud del código

// Almacena el código para su reproducción posterior
void storeCode(decode_results* results) {
  codeType = results->decode_type;
  int count = results->rawlen;
  if (codeType == UNKNOWN) {
    codeLen = results->rawlen - 1;
    for (int i = 1; i <= codeLen; i++) {
      if (i % 2) {
        rawCodes[i - 1] = results->rawbuf[i] * USECPERTICK - MARK_EXCESS;
      } else {
        rawCodes[i - 1] = results->rawbuf[i] * USECPERTICK + MARK_EXCESS;
      }
    }
  } else {
    if (codeType == NEC) {
      if (results->value == REPEAT) {
        return;
      }
    }
    Serial.print("NEC recibido: ");
    Serial.println(results->value, HEX);
    codeValue = results->value;
    codeLen = results->bits;
  }
}

void sendCode(int repeat) {
  if (codeType == NEC) {
    if (repeat) {
      irsend.sendNEC(REPEAT, codeLen);
    } else {
      irsend.sendNEC(codeValue, codeLen);
    }
  } else if (codeType == UNKNOWN /* es decir, crudo */) {
    irsend.sendRaw(rawCodes, codeLen, 38);
    Serial.println("Crudo enviado");
  }
}

void loop() {
  // Si se recibe un código IR
  if (irrecv.decode(&results)) {
    digitalWrite(STATUS_PIN, HIGH);
    storeCode(&results);

    switch (results.value) {
      case 0xFFA25D:
        Serial.println("Tecla 1");
        angulocodo -= 10;
        Codo.write(angulocodo);
        break;
      case 0xFF629D:
        Serial.println("Tecla 2");
        angulomuneca -= 10;
        muneca.write(angulomuneca);
        break;
      case 0xFFE21D:
        Serial.println("Tecla 3");
        angulogarra = 50;
        Garra.write(angulogarra);
        break;
      case 0xFF22DD:
        Serial.println("Tecla 4");
        angulocodo += 10;
        Codo.write(angulocodo);
        break;
      case 0xFF02FD:
        Serial.println("Tecla 5");
        angulomuneca += 10;
        muneca.write(angulomuneca);
        break;
      case 0xFFC23D:
        Serial.println("Tecla 6");
        angulogarra = 20;
        Garra.write(angulogarra);
        break;
      case 0xFFE01F:
        moverServoSuavemente(rotacion, rotacion.read(), 0, 300);
      moverServoSuavemente(Hombro1, Hombro1.read(), 130, 300);
      moverServoSuavemente(Hombro2, Hombro2.read(), 50, 300);
      moverServoSuavemente(Codo, Codo.read(), 140, 300);
      moverServoSuavemente(muneca, muneca.read(), 0, 300);
      Garra.write(20);

      delay(300); // Pequeño retraso para el efecto visual

      Garra.write(50);

      delay(500); // Pequeño retraso para el efecto visual

      moverServoSuavemente(rotacion, rotacion.read(), 180, 300);
      moverServoSuavemente(Hombro1, Hombro1.read(), 50, 300);
      moverServoSuavemente(Hombro2, Hombro2.read(), 130, 300);
      moverServoSuavemente(Codo, Codo.read(), 150, 300);
      moverServoSuavemente(muneca, muneca.read(), 0, 300);

      delay(300); // Pequeño retraso para el efecto visual

      Garra.write(20);

      delay(500); // Pequeño retraso para el efecto visual

      moverServoSuavemente(rotacion, rotacion.read(), 90, 300);
      moverServoSuavemente(Hombro1, Hombro1.read(), 50, 300);
      moverServoSuavemente(Hombro2, Hombro2.read(), 130, 300);
      moverServoSuavemente(Codo, Codo.read(), 180, 300);
      moverServoSuavemente(muneca, muneca.read(), 40, 300);
      moverServoSuavemente(Garra, Garra.read(), 20, 300);
        break;
      case 0xFFA857:
        Serial.println("Tecla 8");
        break;
      case 0xFF906F:
        Serial.println("Tecla 9");
        break;
      case 0xFF6897:
        Serial.println("Tecla *");
        break;
      case 0xFF9867:
        Serial.println("Tecla 0");
        break;
      case 0xFFB04F:
        Serial.println("Tecla #");
        break;
      case 0xFF18E7:
        Serial.println("Tecla arriba");
        angulohombro1 += 10;
        angulohombro2 -= 10;
        Hombro1.write(angulohombro1);
        Hombro2.write(angulohombro2);
        break;
      case 0xFF10EF:
        Serial.println("Tecla izquierda");
        angulorotacion += 10;
        rotacion.write(angulorotacion);
        break;
      case 0xFF5AA5:
        Serial.println("Tecla derecha");
        angulorotacion -= 10;
        rotacion.write(angulorotacion);
        break;
      case 0xFF4AB5:
        Serial.println("Tecla abajo");
        angulohombro1 -= 10;
        angulohombro2 += 10;
        Hombro1.write(angulohombro1);
        Hombro2.write(angulohombro2);
        break;
      case 0xFF38C7:
        Serial.println("Tecla ok");
        rotacion.write(90);
        Hombro1.write(90);
        Hombro2.write(90);
        Codo.write(180);
        muneca.write(40);
        Garra.write(20);
        break;
      default:
        break;
    }

    irrecv.resume();
    digitalWrite(STATUS_PIN, LOW);
  }
}

Si deseas descargar el código anterior, lo encuentras AQUI:

Explicación Código:

a. Importación de Librerías:

#include <IRremote.h>   //libreria IRRemote con la cual entenderemos las señales del control inflarrojo
#include <Servo.h>      //Libreria Servomotor con la cual controlaremos nuestro servomotor

Se importan las librerías necesarias para el funcionamiento del código. IRremote.h para el control remoto infrarrojo y Servo.h para controlar los servomotores.

b. Declaración de Objetos y Variables

Servo rotacion, Hombro1, Hombro2, Codo, muneca, Garra;

int angulorotacion = 90, angulohombro1 = 50, angulohombro2 = 130;
int angulocodo = 180, angulomuneca = 40, angulogarra = 20;

int RECV_PIN = 3, STATUS_PIN = 13;

IRrecv irrecv(RECV_PIN);
IRsend irsend;
decode_results results;

Se declaran los objetos de tipo Servo para cada parte del brazo robótico y se inicializan los ángulos. También se declaran pines para el receptor infrarrojo y un LED indicador. Se crean objetos IRrecv y IRsend para manejar el receptor y emisor infrarrojo.

c. Definición del pin de recepción IR:

int RECV_PIN = 3;       // Pin al cual conectaremos el Pin Señal de nuestro modulo AX-1838HS

Se define la variable RECV_PIN para almacenar el número de pin al cual está conectado el receptor infrarrojo.

d. Inicialización del receptor IR:

IRrecv irrecv(RECV_PIN); 

Se crea un objeto IRrecv que se encargará de recibir las señales infrarrojas en el pin definido anteriormente.

e. Definición de la variable para almacenar los resultados:

decode_results results; // Nombre en donde decodificará los valores 

Se define la variable results del tipo decode_results, que se utilizará para almacenar los datos decodificados de las señales infrarrojas recibidas.

f. Definición de los ángulos iniciales de los servomotores:

int angulocadera = 90;    // Nuestro servomotor iniciará siempre en 90º
int angulohombro1 = 90;   // Nuestro servomotor iniciará siempre en 90º
int angulohombro2 = 90;   // Nuestro servomotor iniciará siempre en 90º
int angulocodo = 0;       // Nuestro servomotor iniciará siempre en 75º
int angulomuneca = 70;    // Nuestro servomotor iniciará siempre en 50º
int angulogarra = 180;    // Nuestro servomotor iniciará siempre en 50º

Se definen las variables para almacenar los ángulos iniciales de cada servomotor. Estos ángulos se utilizarán como posiciones de inicio para cada servomotor.

g. Funición setup():

void setup() {
  Serial.begin(115200);
  Serial.println("Iniciando... ");

  irrecv.enableIRIn();  // Iniciar el receptor
  pinMode(STATUS_PIN, OUTPUT);

  rotacion.attach(2);
  Hombro1.attach(4);
  Hombro2.attach(5);
  Codo.attach(6);
  muneca.attach(7);
  Garra.attach(8);

  rotacion.write(angulorotacion);
  Hombro1.write(angulohombro1);
  Hombro2.write(angulohombro2);
  Codo.write(angulocodo);
  muneca.write(angulomuneca);
  Garra.write(angulogarra);

  delay(500);

}

Se establecen las configuraciones iniciales en el método setup(). Se adjuntan los servomotores a los pines correspondientes, se habilita la recepción de señales infrarrojas y se inicia la comunicación serial.

h. Función loop(), Bucle Principal:

void loop() { 
  if (irrecv.decode(&results)) { // Se verifica si hay una señal infrarroja recibida
    Serial.println(results.value, HEX); // Se imprime el valor recibido en hexadecimal por el control infrarrojo
    
    // Se utiliza una estructura switch-case para manejar diferentes valores recibidos
    switch(results.value){
      case 0xFF5AA5: // Si se recibe este valor, se incrementa el ángulo de la cadera
        angulocadera += 10;   
      break;
      
      // Otros casos similares para diferentes direcciones y movimientos del brazo
      // (izquierda, arriba, abajo, etc.)
      
      case 0xFF38C7: // Si se recibe este valor, se restablecen los ángulos a sus valores iniciales
        angulocadera = 90;      
        angulohombro1 = 90;    
        angulohombro2 = 90;    
        angulocodo = 140;      
        angulomuneca = 140;    
        angulogarra = 70;    
      break;
    }

    // Se aplican restricciones a los ángulos para asegurar que estén dentro de los límites deseados
    angulocodo = constrain(angulocodo, 0, 170);
    angulohombro1 = constrain(angulohombro1, 0, 170);
    angulohombro2 = constrain(angulohombro2, 0, 170);
    angulocadera = constrain(angulocadera, 0, 170);
    angulomuneca = constrain(angulomuneca, 0, 170);

    // Se escriben los ángulos en los servomotores correspondientes para controlar el brazo
    cadera.write(angulocadera);
    hombro1.write(angulohombro1);
    hombro2.write(angulohombro2);
    codo.write(angulocodo);
    muneca.write(angulomuneca);
    garra.write(angulogarra);
  
    irrecv.resume(); // Se reinicia la recepción de señales infrarrojas para esperar la próxima
    delay(10); // Se espera un breve tiempo antes de continuar para evitar lecturas erróneas
  }
}

La función loop() es el corazón del programa y se ejecuta continuamente después de que setup() haya completado su ejecución. En este caso:

3. Ahora solo debes enviar a través de tu control remoto a tu nuevo Brazo Robótico, a continuación te dejamos una imagen que ilustra los comandos y que rol cumplen.

4. Si seguiste los pasos al pie de la letra deberás tener tu Brazo Robótico totalmente funcional con control remoto, ya solo queda que añadas a los códigos faltantes espectaculares secuencias.

Nombre Articulaciones