Introduction: Nerf Bot - Cannon Project (simulation)

Olá! Resolvi automatizar um Nerf elite para dar tiro curvo em um alvo, utilizando o principio do lançamento de projéteis, visto nas aulas de física. A ideia básica foi a de atingir um alvo a uma certa distância, com alguma precisão. Para isso, utilizei um sensor ultrassônico para verificar a distância do alvo, um servomotor para alterar o ângulo de disparo e outro para acionar o gatilho, um display LCD para visualizar os dados como distância e ângulo e um Arduino para efetuar os cálculos, a leitura do sensor e acionar os servos.

Procurei algo na internet para servir como ponto de partida. Porém, não encontrava informações completas. Apenas fórmulas e alguns projetos prontos e sem maiores detalhes.

Iniciei o projeto fazendo os cálculos, depois utilizei as ferramentas do Tinkercad para simular tanto o software como o hardware, fiz um esboço de como seria o robô, em 3D e documentei alguns passos seguidos para compartilhar. Espero que gostem.

Step 1: Teoria:

O dardo é lançado e cai em diferentes distâncias, de acordo com a variação do ângulo de disparo (já que a velocidade inicial (V0) não será alterada). Após um breve estudo da física envolvida, peguei algumas equações para implementar neste projeto.

Com vários ângulos diferentes, várias contas deveriam ser feitas para obter a distância do objeto lançado. Daí a ideia de “automatizar” esses cálculos.

O esboço final do robô veio após algumas ideias de como seria feito:

1) Utilizar um potenciômetro para medir o ângulo do canhão e mostra-lo em um Lcd.

2) Utilizar um servo para variar o ângulo do canhão com a ajuda do potenciômetro.

3) Utilizar alguns botões para acrescentar informações como: altura máxima da bolinha, tempo de queda, distância e ângulo.

4) Utilizar um sensor de distância para o canhão “escolher” o ângulo certo para atirar no alvo.

Aos poucos fui implementando cada as funções e aprendendo coisas novas no Arduino.

Step 2: Fórmulas:

A distância máxima alcançada pelo projetil do NERF foi de 6 metros.

Para achar a V0 , utilizei um método indireto: Sabendo que o Alcance máximo dá-se com o ângulo de 45 graus, (seno de (2* 45) = 1),

Logo: V0= SQRT (A*g)

V0= SQRT(6 * 9.8)

V0= 7.668 m/s 2

No Arduino:

float V0= 7.668; // variável para estocar o valor da velocidade inicial

float g=9.8; // aceleração da gravidade

float A=0; // variável do Alcance máximo

Step 3: Para Saber Qual O Ângulo Que Deve Ter Para Acertar Um Objeto a “A” (em Metros) De Distância, a Fórmula Foi Arrumada E Ficou Assim:

No Arduino:

#include

#define RAD_TO_DEG 57.295779513082320876798154814105

double O=0; //variável para o ângulo

O= (asin((A * g)/(V0*V0)))/2; // fornece o valor do ângulo em radianos

O= O*RAD_TO_DEG; //transforma de radianos para graus

Step 4: Cálculo De Ângulos No Arduino

*O Resultado de uma conta com Seno e Cosseno da um resultado em radianos. Como eu precisava do valor em “graus” para enviar para o servo, tive que converter de radiano para graus.

Step 5: Escolha Da Parábola:

Obs.: Para um ângulo de (45 – x) ou (45 + x), o projétil cai no mesmo lugar.

Para um ângulo de (45 +x), a parábola tem um pico maior. Por isso, resolvi utilizar esse cálculo para o canhão.

No Arduino:
if (O >0 & O < 45){ O2= (45-O)+45; // encontra o ângulo que foi subtraído de 45, soma a 45 e estoca esse valor na variável O2

Serial.print("Angulo2= "); // imprime na serial a palavra Angulo2= Serial.println(O2); // imprime na serial o valor do ângulo

O2 myservo.write(O2); // envia o valor de O2 para o servo delay(15); // aguarda 15 ms para atualizar a posição do servo

Step 6: Para Um Ângulo De (45 +x), a Parábola Tem Um Pico Maior. Por Isso, Resolvi Utilizar Esse Cálculo Para O Canhão.

No Arduino:

if (O >0 & O < 45){

O2= (45-O)+45; // encontra o ângulo que foi subtraído de 45, soma a 45 e estoca esse valor na variável O2

Serial.print("Angulo2= "); // imprime na serial a palavra Angulo2=

Serial.println(O2); // imprime na serial o valor do ângulo O2

myservo.write(O2); // envia o valor de O2 para o servo

delay(15); // aguarda 15 ms para atualizar a posição do servo

Step 7: Modelagem 3D

Step 8: Simulador Do Circuito Lógico

Step 9: Software:

#include <LiquidCrystal.h>

#include <math.h>

#include <Servo.h>

#define RAD_TO_DEG 57.295779513082320876798154814105

#define DEG_TO_RAD 0.017453292519943295769236907684886

LiquidCrystal lcd(A5,A4,A3,A2,A1,A0); // Inicializa o LCD

int tempo =500; //variável para estocar o tempo

const int pin1gPin = 5; // pino para conectar o sensor ultrassonico

Servo fire; // criando o objeto servo para acionar o gatilho

Servo myservo; // criando o objeto servo para movimentar o ângulo

int firePin= 3; // pino para atirar (a interrupção externa no Arduino Uno fica nos botões 2 e 3)

int flagTiro= 0; // flag para verificar se o gatilho foi acionado

int pingPin= 5; // pino para receber o sinal do sensor

double h=0; // variável para a altura (Usei "double" para representar números com frações. Também pode ser usado "float")

double h2=0;

double O=0; //variável para o ângulo

double O2=0; // variável para o ângulo2

float dist1=0; // variável da distância da borda do canhao e a base fixa

float r= (0.12); //variável(em metros) para o valor da haste

float V0= 5.6609; // variável para estocar o valor da velocidade inicial

float g=9.8; // aceleração da gravidade

float A=0; // variável do Alcance máximo

void setup(){

Serial.begin(9600); // inicia a porta serial

// rotina par aescrever no LCD

lcd.begin(16, 2); // Define o LCD com 16 colunas e 2 linhas

lcd.setCursor(0,0); // (coluna, linha)

lcd.print("Nerf Bot"); // Mostra informacoes no display

delay(tempo*3); // aguarda 1,5 segundos

lcd.clear(); // apaga o display

lcd.setCursor(0,0);

lcd.print("Distancia:");

lcd.setCursor(0,2);

lcd.print ("Angulo:");

// rotina dos servos

myservo.attach(7); // Servo do ângulo no pino 9

myservo.write(0); // posição inicial do servo do ângulo

delay(250);

fire.attach(6); // Servo do gatinho no pino 6

fire.write(0); //posição inicial do servo do gatilho

delay(250);

pinMode(firePin, INPUT);

attachInterrupt(digitalPinToInterrupt(firePin),gatilho, HIGH ); // interrupção externa para ativar o gatilho

}

void loop()

{

// rotina para a leitura do sensor de distância

long duration, cm;

pinMode(pingPin, OUTPUT);

digitalWrite(pingPin, LOW);

delayMicroseconds(2);pinMode(pingPin, OUTPUT);

digitalWrite(pingPin, HIGH);

delayMicroseconds(5);

digitalWrite(pingPin, LOW);

pinMode(pingPin, INPUT);

duration = pulseIn(pingPin, HIGH);

cm = microsecondsToCentimeters(duration);

/*Serial.print(cm);

Serial.print("cm");

Serial.println();

*/

delay(100);

A= cm;

lcd.setCursor(11,0);

lcd.print(A);

lcd.setCursor(14,0);

lcd.print("cm");

Serial.print ("Distancia= ");

Serial.print(A);

Serial.println("cm");

delay(15);

A=(A/100);

O= (asin((A * g)/(V0*V0)))/2; // fornece o valor do ângulo em radianos

O= O*RAD_TO_DEG; //transforma de radianos para graus

Serial.print("Angulo= ");

Serial.println(O);

if (O >0 & O < 45){

O2= (45-O)+45;

Serial.print("Angulo2= ");

Serial.println(O2);

lcd.setCursor(8,1);

lcd.print(O2);

lcd.setCursor(10,1);

lcd.print("Graus");

delay(15);

myservo.write(O2);

delay(1000);

}

if (flagTiro > 0){

delay(500);

fire.write(0);

delay(500);

flagTiro= 0;

}

}

long microsecondsToCentimeters(long microseconds) {

return microseconds / 29 / 2;

}

void gatilho (){

fire.write(60);

flagTiro= 1;

}