Braço Robótico + Arduino UNO + Controle XBOX 360 V1.0 - Tutoriais #001

   



     O desenvolvimento do Braço Robótico iniciou-se na quinta fase do curso de Sistemas Eletrônicos, onde na disciplina de Microcontroladores, ministrada pelo Professor Leandro  Schwarz, foi apresentado como projeto final. Porém ainda nesse momento o projeto encontrava problemas de driver de corrente para os motores e também de controle, uma vez que estávamos utilizando um aplicativo para smartphone também desenvolvido exclusivamente para o controle do braço.
    
    Na sexta fase, recebi um convite do professor Fernando Pacheco para solucionar esses problemas e apresentá-lo durante a semana de tecnologia do IFSC. Assim iniciou uma nova etapa do projeto, o aperfeiçoamento do que já existia e também uma nova concepção do  controle.   

    Durante a fase de pesquisa encontrei alguns artigos onde se utilizava o controle do XBOX 360 junto à microcontroladores, e foi a partir dessas referencias e também do controle ser muito mais ergonômico e de fácil manipulação do operador, que iniciei a nova fase de desenvolvimento de controle do braco robótico.



Vídeo de Funcionamento





Estrutura Mecânica  
  
    Todo o projeto  da estrutura mecânica foi retirada da plataforma de compartilhamento opensource Thingverse, foram alterados apenas os ajustes de tamanhos dos cortes para o encaixe dos servos motores.

    Link do projeto mecânico: http://www.thingiverse.com/thing:2433

    O material escolhido para a estrutura foi o MDF e o corte das peças foi realizado no Lazer para garantir a precisão e acabamento.


Corte a laser da estrutura mecânica

    As peças foram pintadas com spray nas cores pretas e amarelas. A pintura preta por ser uma tinta fosca aderiu melhor  ao material.

Pintura da estrutura mecânica
    Na montagem foi necessário alguns parafusos e extensores, mitas vezes esses tiveram que ser adaptados ao que era encontrado no mercado mais próximo. 

     Lista de parafusos:
     40 - M2x15 com porca
     20 - M2x12 com porca
     6 - M2x20 com porca
     5 extensores extavado 50xM4
     4 extensores extavado 47xM2
     4 extensores extavado 17xM2

Montagem para testes e experimentação
    DICA: A tinta amarela utilizada foi à óleo e deixou o movimento da garra um pouco comprometido. Para amenizar e a garra continuar se movimentando teve-se que ajustar o aperto dos parafusos, porém se perdeu em força que a garra deveria ter.

    A mesma garra foi impressa em uma impressora 3D e também foi verificado o resultado de um outro projeto que o material utilizado foi o acrilico e devido à ambos materiais serem bem lisos a garra funciona de uma forma muito mais satisfatória.


Servo Motores
    
    Os servo motores são usados quando se deseja movimentar algo de forma precisa e controlada. No projeto foi necessário a utilização de sete servos motores para desempenhar os movimentos do Braço Robótico para se ter o grau de liberdade dos movimentos que se precisava, cinco servos MG995 da TowerPro e dois micro servos MG90S, também da TowerPro.

Servo motores TowerPro - MG995 e MG90s

Arduino UNO

    O arduino UNO possui como componente principal o ATMEGA 328p, 8bits da família AVR. Possui 32kB de memória Flash, 2kB de memória RAM, e 1kB de EEPROM. Trabalha com um cristal de 16MHz.
    Os pinos de 0 a 13, podem ser utilizados como entrada ou saída digitais. Especificamente os pinos 3,5,6,9,10 e 11 podem ser utilizados com saídas PWM de 8 bits.
    A comunicação serial é feita nos pinos 0 e 1.
Arduino UNO   

USB Host Shield
    
     No arduino, o USB Host Shield atua como um “servidor” USB, que gerencia a conexão, fornecendo alimentação e permitindo a comunicação entre o arduino e os periféricos USB conectados a porta.
USB Host Shield

Servo Motor Shield 16 Canais
    
    Neste projeto precisamos de 7 saídas PWM, quantidade maior que o arduino UNO disponibiliza. Assim de maneira simples podemos expandir esse número de saídas com a Servo Motor Shield, usando apenas dois pinos I2C.
    A Servo Motor Shield possui resolução de 12 bits e necessita de alimentação externa. Neste projeto utilizei uma fonte de 3,5A.
Servo Motor Shield - I2C to pwm

Controle XBOX 360 e Receiver Wirelles

    Os controles do XBOX 360 utilizam wireless para se comunicar com o console, visando a utilização com computadores a microsoft desenvolveu um receptor wireless para o controle, com USB 2.0.
    Durante a fase de pesquisa quando encontrei o receptor em algumas referências de projetos, percebi a perfeita funcionabilidade para controlar o braço robótico, sem falar na ergonomia do controle.
Controle XBOX 360 + Receiver Microsoft


Programação

    Para o funcionamento do código é necessário incluir as bibliotecas:


 #include <Wire.h>  
 #include <Adafruit_PWMServoDriver.h>  
 #include <XBOXRECV.h>  
 #ifdef dobogusinclude  
 #include <spi4teensy3.h>  
 #include <SPI.h>  
 #endif  
 USB Usb;  
 XBOXRECV Xbox(&Usb);  
 Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();  
 #define SERVO1MIN 150 //SERVO BASE  
 #define SERVO1MAX 500 //SERVO BASE  
 #define SERVO2MIN 150 //SERVO 1 COTOVELO   
 #define SERVO2MAX 400 //SERVO 1 COTOVELO   
 #define SERVO3MIN 150   
 #define SERVO3MAX 400   
 #define SERVO4MIN 200   
 #define SERVO4MAX 500   
 #define SERVO5MIN 150   
 #define SERVO5MAX 500  
 #define SERVO6MIN 150   
 #define SERVO6MAX 500  
 #define SERVO7MIN 350   
 #define SERVO7MAX 510  
 // our servo # counter  
 uint8_t servo1 = 0; //SERVO BASE  
 uint8_t servo2 = 1; //SERVO 1 COTOVELO   
 uint8_t servo3 = 2; //SERVO 2 COTOVELO   
 uint8_t servo4 = 3;  
 uint8_t servo5 = 4;  
 uint8_t servo6 = 5;  
 uint8_t servo7 = 6;  
 double angle1 = SERVO1MAX/2;  
 double angle2 = 350; //angulo do SERVO 1 e servo 2 COTOVELO  
 double angle4 = SERVO4MAX/2;  
 double angle5 = SERVO5MAX/2;  
 double angle6 = SERVO6MAX/2;  
 double angle7 = SERVO7MAX/2;  
 void setup() {  
  pwm.begin();  
  pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates  
  Serial.begin(115200);  
 #if !defined(__MIPSEL__)  
  while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection  
 #endif  
  if (Usb.Init() == -1) {  
   Serial.print(F("\r\nOSC did not start"));  
   while (1); //halt  
  }  
  Serial.print(F("\r\nXbox Wireless Receiver Library Started"));  
 }  
 void loop() {  
  Usb.Task();  
  if (Xbox.XboxReceiverConnected) {  
   for (uint8_t i = 0; i < 4; i++) {  
    if (Xbox.Xbox360Connected[i]) {  
     if (Xbox.getButtonPress(L2, i) || Xbox.getButtonPress(R2, i)) {  
      Serial.print("L2: ");  
      Serial.print(Xbox.getButtonPress(L2, i));  
      Serial.print("\tR2: ");  
      Serial.println(Xbox.getButtonPress(R2, i));  
      Xbox.setRumbleOn(Xbox.getButtonPress(L2, i), Xbox.getButtonPress(R2, i), i);  
     }  
     if (Xbox.getAnalogHat(LeftHatX, i) > 7500 || Xbox.getAnalogHat(LeftHatX, i) < -7500 || Xbox.getAnalogHat(LeftHatY, i) > 7500 || Xbox.getAnalogHat(LeftHatY, i) < -7500 || Xbox.getAnalogHat(RightHatX, i) > 7500 || Xbox.getAnalogHat(RightHatX, i) < -7500 || Xbox.getAnalogHat(RightHatY, i) > 7500 || Xbox.getAnalogHat(RightHatY, i) < -7500) {  
      if (Xbox.getAnalogHat(LeftHatX, i) > 7500) {  
       if (Xbox.getAnalogHat(LeftHatX, i) == 32767){  
       incrementa_base();  
       }  
       Serial.print(F("LeftHatX: "));  
       Serial.print(Xbox.getAnalogHat(LeftHatX, i));  
       Serial.print("\t");  
      }  
      if (Xbox.getAnalogHat(LeftHatX, i) < -7500) {  
       if (Xbox.getAnalogHat(LeftHatX, i) == -32768){  
       decrementa_base();  
       }  
       Serial.print(F("LeftHatX: "));  
       Serial.print(Xbox.getAnalogHat(LeftHatX, i));  
       Serial.print("\t");  
      }  
      if (Xbox.getAnalogHat(LeftHatY, i) > 7500) {  
       if (Xbox.getAnalogHat(LeftHatY, i) == 32767){  
       incrementa_cotovelo();  
       }  
       Serial.print(F("LeftHatY: "));  
       Serial.print(Xbox.getAnalogHat(LeftHatY, i));  
       Serial.print("\t");  
      }  
      if (Xbox.getAnalogHat(LeftHatY, i) < -7500) {  
       if (Xbox.getAnalogHat(LeftHatY, i) == -32768){  
       decrementa_cotovelo();  
       }  
       Serial.print(F("LeftHatY: "));  
       Serial.print(Xbox.getAnalogHat(LeftHatY, i));  
       Serial.print("\t");  
      }  
      if (Xbox.getAnalogHat(RightHatX, i) > 7500) {  
       if (Xbox.getAnalogHat(RightHatX, i) == 32767){  
       incrementa_servo4();  
       Serial.print(F("RightHatX: "));  
       Serial.print(Xbox.getAnalogHat(RightHatX, i));  
       Serial.print("\t");  
       }  
      }  
      if (Xbox.getAnalogHat(RightHatX, i) < -7500) {  
       if (Xbox.getAnalogHat(RightHatX, i) == -32768){  
       decrementa_servo4();  
       Serial.print(F("RightHatX: "));  
       Serial.print(Xbox.getAnalogHat(RightHatX, i));  
       Serial.print("\t");  
       }  
      }    
      if (Xbox.getAnalogHat(RightHatY, i) > 7500) {  
       if (Xbox.getAnalogHat(RightHatY, i) == 32767){  
       decrementa_servo5();  
       Serial.print(F("RightHatY: "));  
       Serial.print(Xbox.getAnalogHat(RightHatY, i));  
       Serial.print("\t");  
       }  
      }  
      if (Xbox.getAnalogHat(RightHatY, i) < -7500) {  
       if (Xbox.getAnalogHat(RightHatY, i) == -32768){  
       incrementa_servo5();  
       Serial.print(F("RightHatY: "));  
       Serial.print(Xbox.getAnalogHat(RightHatY, i));  
       Serial.print("\t");  
       }  
      }   
      Serial.println();  
     }  
     if (Xbox.getButtonClick(UP, i)) {  
      Xbox.setLedOn(LED1, i);  
      Serial.println(F("Up"));  
     }  
     if (Xbox.getButtonClick(DOWN, i)) {  
      Xbox.setLedOn(LED4, i);  
      Serial.println(F("Down"));  
     }  
     if (Xbox.getButtonClick(LEFT, i)) {  
      Xbox.setLedOn(LED3, i);  
      Serial.println(F("Left"));  
     }  
     if (Xbox.getButtonClick(RIGHT, i)) {  
      Xbox.setLedOn(LED2, i);  
      Serial.println(F("Right"));  
     }  
     if (Xbox.getButtonClick(START, i)) {  
      Xbox.setLedMode(ALTERNATING, i);  
      Serial.println(F("Start"));  
     }  
     if (Xbox.getButtonClick(BACK, i)) {  
      Xbox.setLedBlink(ALL, i);  
      Serial.println(F("Back"));  
     }  
     if (Xbox.getButtonClick(L3, i))  
      Serial.println(F("L3"));  
     if (Xbox.getButtonClick(R3, i))  
      Serial.println(F("R3"));  
     if (Xbox.getButtonClick(L1, i))  
      Serial.println(F("L1"));  
     if (Xbox.getButtonClick(R1, i))  
      Serial.println(F("R1"));  
     if (Xbox.getButtonClick(XBOX, i)) {  
      Xbox.setLedMode(ROTATING, i);  
      Serial.print(F("Xbox (Battery: "));  
      Serial.print(Xbox.getBatteryLevel(i)); // The battery level in the range 0-3  
      Serial.println(F(")"));  
     }  
     if (Xbox.getButtonClick(SYNC, i)) {  
      Serial.println(F("Sync"));  
      Xbox.disconnect(i);  
     }  
     if (Xbox.getButtonClick(A, i)){  
      rotaciona1_mao();  
      Serial.println(F("A"));  
     }  
     if (Xbox.getButtonClick(B, i)){  
     abre_garra();  
     Serial.println(F("B"));  
     }  
     if (Xbox.getButtonClick(X, i)){  
     fecha_garra();  
     Serial.println(F("X"));  
     }  
     if (Xbox.getButtonClick(Y, i)){  
      rotaciona2_mao();  
      Serial.println(F("Y"));  
     }   
    }  
   }  
  }  
 }  
 void setServoPulse(uint8_t n, double pulse) {  
  double pulselength;  
  pulselength = 1000000;  // 1,000,000 us per second  
  pulselength /= 60;  // 60 Hz  
  Serial.print(pulselength); Serial.println(" us per period");   
  pulselength /= 4096; // 12 bits of resolution  
  Serial.print(pulselength); Serial.println(" us per bit");   
  pulse *= 1000;  
  pulse /= pulselength;  
  Serial.println(pulse);  
  pwm.setPWM(n, 0, pulse);  
 }  
 void incrementa_base(){  
 Serial.println(F("Incrementou na Base"));  
 if(angle1==SERVO1MAX){  
 }  
 else  
 angle1++;  
  Serial.print("angle: ");  
  Serial.print(angle1);  
  Serial.print("\t");  
  pwm.setPWM(servo1, 0, angle1);  
  }  
 void decrementa_base(){  
 Serial.println(F("DEcrementou na Base"));  
 if(angle1==SERVO1MIN){  
 }  
 else  
 angle1--;  
  Serial.print("angle: ");  
  Serial.print(angle1);  
  Serial.print("\t");  
  pwm.setPWM(servo1, 0, angle1);  
  }  
 void incrementa_cotovelo(){  
 Serial.println(F("Incrementou no Cotovelo"));  
 if(angle2==SERVO2MAX){  
 }  
 else  
 angle2++;  
  Serial.print("angle: ");  
  Serial.print(angle2);  
  Serial.print("\t");  
  pwm.setPWM(servo2, 0, angle2);  
  pwm.setPWM(servo3, 0, angle2);  
  }  
 void decrementa_cotovelo(){  
 Serial.println(F("DEcrementou no Cotovelo"));  
 if(angle2==SERVO2MIN){  
 }  
 else  
 angle2--;  
  Serial.print("angle: ");  
  Serial.print(angle2);  
  Serial.print("\t");  
  pwm.setPWM(servo2, 0, angle2);  
  pwm.setPWM(servo3, 0, angle2);  
  }  
  void incrementa_servo4(){  
 Serial.println(F("Incrementou no Servo 4"));  
 if(angle4==SERVO4MAX){  
 }  
 else  
 angle4++;  
  Serial.print("angle: ");  
  Serial.print(angle4);  
  Serial.print("\t");  
  pwm.setPWM(servo4, 0, angle4);  
  }  
 void decrementa_servo4(){  
 Serial.println(F("DEcrementou no Servo 4"));  
 if(angle4==SERVO4MIN){  
 }  
 else  
 angle4--;  
  Serial.print("angle: ");  
  Serial.print(angle4);  
  Serial.print("\t");  
  pwm.setPWM(servo4, 0, angle4);  
  }  
 void incrementa_servo5(){  
 Serial.println(F("Incrementou no Servo 5"));  
 if(angle5==SERVO5MAX){  
 }  
 else  
 angle5++;  
  Serial.print("angle: ");  
  Serial.print(angle5);  
  Serial.print("\t");  
  pwm.setPWM(servo5, 0, angle5);  
  }  
 void decrementa_servo5(){  
 Serial.println(F("DEcrementou no Servo 5"));  
 if(angle5==SERVO5MIN){  
 }  
 else  
 angle5--;  
  Serial.print("angle: ");  
  Serial.print(angle5);  
  Serial.print("\t");  
  pwm.setPWM(servo5, 0, angle5);  
  }   
  void fecha_garra(){  
   Serial.print("Fechou garra ");  
   angle7=SERVO7MAX;  
   pwm.setPWM(servo7, 0, angle7);  
  }  
  void abre_garra(){  
   Serial.print("abriu garra ");  
   angle7=SERVO7MIN;  
   pwm.setPWM(servo7, 0, angle7);  
  }  
  void rotaciona1_mao(){  
   Serial.print("girou mao 1 ");  
   angle6=SERVO6MIN;  
   pwm.setPWM(servo6, 0, angle6);  
  }   
  void rotaciona2_mao(){  
   Serial.print("girou mao 1 ");  
   angle6=SERVO6MAX;  
   pwm.setPWM(servo6, 0, angle6);  
  }   

12 comentários:

  1. Ola, vc conseguiria me fazer o corte da estrutura e me vender?

    ResponderExcluir
    Respostas
    1. Ola, infelizmente não possuo a máquina de corte a laser, mas essa estrutura pode ser encontrada no mercado libre para compra.
      Um segunda opção seria imprimir na impressora 3D a estrutura do robô.

      Excluir
  2. Olá, você poderia explicar melhor a programação do controle?

    ResponderExcluir
    Respostas
    1. Olá, posso sim, Qual seria a dúvida na programação? Você possui o hardware para testar, fica mais fácil para compreender o código do controle.

      Excluir
  3. Bom dia, se eu copiar e colar essa programação no meu arduino ele vai funcionar ?

    ResponderExcluir
    Respostas
    1. Bom dia Leandro, se você estiver utilizando o mesmo hardware que eu a programação teria que funcionar sim.

      Excluir
  4. eu tenho que criar subpastas com as outras programaçoes pra funcionar ?

    ResponderExcluir
  5. Tente entender o que está sendo feito através das bibliotecas padrões de cada dispositivo e então implemente as funções que você irá precisar em sua programação.

    ResponderExcluir
  6. assim eu estou fazendo um robo de combate, eu vi seu video e vou utilizar os mesmo materiais , tanto que ja comprei todos, é meu primeiro projeto e estou com as duvidas de programação

    ResponderExcluir
  7. Ola Matheus, gostei desse seu projeto e montei um igual para apresentação do meu TCC na faculdade, mas estou tendo alguns problemas com o meu robo, estou utilizando as mesmas peças, placas,etc que o seu, mas os meus servos MG995 não estão respondendo os comandos, ao ligar eles no shild pwm ele começam a girar apenas para um sentindo, e todos os 5 servos MG995 estão assim, ja os MG90S estão funcionando normal, sera que você consegue me ajudar com esse problema? obrigado

    ResponderExcluir
    Respostas
    1. Ola, vou tentar te ajudar como eu sempre faço quando encontro problemas de programação e hardware.
      1. Isole o problema. Faça um programa "teste_de_motor" para acionar um único motor que automaticamente gire o motor para um lado e depois de um tempo gire o motor para o outro lado;
      2. Teste individualmente cada motor nesse programa "teste_de_motor";
      3. Se todos os motores funcionarem individualmente faça um programa "teste_shield_pwm", onde esse programa será a cópia do programa "teste_de_motor", porém vc vai alternar a porta PWM. Primeiro aciona a PWM1, para esquerda-direita, depois aciona a PWM2, para a esquerda-direita, e assim por diante, até testar todas as portas necessárias para o projeto.

      Relate os problemas que for tendo aqui e vou tentando te ajudar. Qualquer coisa pode me mandar um e-mail também. matheus.amartim@gmail.com

      Excluir
    2. Ola, primeiro quero lhe agradecer pela prestatividade, lhe enviei um e-mail relatando todo o caso, mas para não ficar algo vago ou sem explicação aqui no blog vou dar uma breve explicação pra quem um dia vier a ler os comentários. Bom meu problema foi que os servos motores que comprei vieram digitais e não analógicos, são da mesma marca e modelo dos que aqui postado, mas o meu veio com uma versão nova, uma versão digital, então montei um outro tipo de braço robótico que tenho e ele utiliza servos mecânicos, todo o resto do o resto do projeto funcionou perfeitamente, só precisei ajustar a posição dos servos pelo código fonte e funcionou, sendo assim só tenho a agradecer

      Excluir

Deixe suas considerações e comentários aqui.

Tecnologia do Blogger.