O Problema
Uma das coisas mais chatas que há de se fazer quando não se tem vontade de aprender, é programar. Isso é uma realidade, programar por programar é muito chato para quem não ama isso. A paixão tem o poder de mudar toda uma vida de um indivíduo. Ela é capaz de “fazer acontecer” aquilo que parecia inalcançável.
Motivação
O curso de Engenharia Florestal que minha irmã mais nova faz, a Bruna Elisa Trentin, como todo bom curso de engenharia, tem uma matéria de programação. A pergunta é: como ensinar programação para alguém que lida com a natureza e, por padrão, não quer nem saber de ficar digitando texto puro em uma interface não muito amigável? Sem falar quando se trata de aprender a programar em C!
Esse desafio me chamou muito a atenção, e então comecei a bolar alguma coisa que pudéssemos fazer, com Arduino, para ensinar-lhe a programar. Inicialmente pensei em desenvolver um medidor de água para o bebedouro de seu hamster. Seria simples, porém o problema é que mesmo tendo água, esta deve ser trocada, afinal ele não bebe tanta água assim. Então não teria tanta emoção. A segunda ideia foi desenvolver um elevador para o bixano, sempre quis fazer isso! Porém ao fazer os primeiros esboços mentais me deparei com o primeiro grande problema: que material leve e forte eu iria usar para que o rato não roesse todo o elevador? Bom, a ideia do elevador basicamente é essa:
Como podemos perceber, o projeto não iria durar muito tempo e o Arduino, após ingerido, poderia causar alterações nas funções básicas do bixinho roedor, o que acredito eu, minha maninha não iria gostar.
O papel do Arduino
Atualmente não tem, é moda, Arduino pegou e veio para ficar (essa afirmação não é necessariamente válida, vendo que minha experiência com eletrônica e programação embarcada é mínima). O que quero dizer é que, como já escrevi em outro tutorial, Arduino é capaz de tirar suas ideias do papel e isso sim eu garanto!
Devido a facilidade em comprar, programar, e montar dispositivos, o padrão Arduino de desenvolvimento mostra-nos que você não precisa ser um expert em eletrônica e programação para conseguir fazer algo. Você pode simplesmente conectar um led e fazer um programa que interaja com ele diretamente, em menos de 5 minutos! A “temível” programação em C, vira brincadeira com essa plataforma, pois com ela, você pode finalmente enteder variáveis, a lógica booleana, controles de fluxo, funções e tudo mais.
A Proposta
Nossa aplicação encontrada para estudar C com Arduino, foi desenvolver um medidor de árvores. Não necessariamente árvores, pois também pode ser usado para medir quaisquer objetos com alguns metros de altura. Portanto, o foco do nosso medidor é ser capaz de medir um objeto na sua vertical. Para tal, foi usado um chip Atmega328, um acelerômetro, um sensor de distância, toda a parafernália de fios para ligar tudo isso e claro, um suporte improvisado.
Como Funciona
O segredo de tudo isso é a trigonometria, ramo da matemática qual é responsável por estudar as relações de dois lados de um triângulo retângulo (triângulo que possui um ângulo de 90º)[1]. Na prática, o que precisamos é saber a distância de nós até o objeto (a árvore) e depois o ângulo de inclinação até o topo do objeto (árvore feliz), como podemos ver em um de nossos rascunhos feitos:
Para lermos a distância entre o medidor e a árvore (objeto), usamos o sensor HC-SR04, que segundo este manual,ele é capaz de medir até 5 metros de distância. Na prática porém, conseguimos medir até 3,30 metros.
O ângulo de inclinação é lido a partir do eixo X do acelerômetro. Usamos o módulo DC-SS009 que é um circuito completo e pronto para usar seu chip A7260, que é um acelerômetro capacitivo.
Todo o processamento de informações é feito através do nosso querido amigo Atmega328 que foi montado diretamente numa protoboard de forma simples e prática. Futuramente desenvolverei um tutorial que explique passo-a-passo como isso foi feito, por hora o video pode servir de grande ajuda. Caso deseje colocar em prática o que foi feito aqui, entre em contato comigo por email, que terei prazer em lhe ajudar!
Após ler a distância entre o objeto e o sensor, aplicamos o cálculo da tangente do ângulo, de acordo com a tabela de razões trigonométricas. Esse cálculo nada mais é que a multiplicação entre a distância (em CM) e a tangente do ângulo. O ângulo de 45º, por exemplo, possui tangente 1. Isso indica que à 45º a altura do objeto será o mesmo que a distância entre este e o sensor de distância.
Testando sensor de distância
Aqui estamos o sensor de distância, para garantir que está funcionando.
Abaixo o código fonte usado neste teste. Ele foi obtido em http://fristec.blogspot.com/2011/01/14-aplicacao-sensor-de-distancia-hc.html:
#include "Ultrasonic.h" Ultrasonic ultrasonic(12,13); // TRIG = pino 12 ECHO = pino 13 void setup() { pinMode(10, OUTPUT); Serial.begin(9600); } void loop() { digitalWrite(10, HIGH); Serial.print("distancia em centimetros : "); Serial.println(ultrasonic.Ranging(CM)); digitalWrite(10, LOW); delay(100); }Testando o Acelerômetro
Aqui vemos um teste simples com o acelerômetro, que infelizmente, não dispõem de muita precisão
Na maioria das aplicações acredito que esta imprecisão não causará maiores problemas, porém aqui ela faz grande diferença, afinal, podemos ter uma variação de 3 ângulos (-1, 0 e 1). Isso significa que à 3.2 metros de distância do objeto com um ângulo de 70 graus, teremos um metro de erro!
Seguindo os dados feitos com testes de medidas, para garantir precisão, o ângulo máximo de inclinação deveria ser em torno de 35º. Isso à 3.2 metros do objeto nos permite medir objetos de no máximo 2.2 metros.
Porém, com margem de erro de 50CM, podemos usar ângulos de até 60º, o que nos permite medir, à 3.2 metros de distância, objetos de até 5.5 metros.
Tentamos corrigir o erro visto na tabela ao lado lendo esse post, e este, porém, ambos apenas citam correções na leitura de acordo com o ângulo. E o problema visto aqui é que mesmo parado, o leitor apresenta essa variação de 5 pontos. E esse problema continua ainda sem solução.
Abaixo o software usado para fazer a medida do eixoX, mostrada acima.
void setup (){ Serial.begin (9600); } void loop (){ int eixoX = analogRead(A3); // Mapeia a escala do sensor para um angulo entre 0 e 90 graus int novoX = map(eixoX, 332,167,0,90); Serial.print ("Valor do eixo X: "); Serial.print (eixoX); Serial.print (" valor convertido: "); Serial.println(novoX); delay (500); }Funcionamento do programa
Inicialmente vamos recorrer ao fluxograma desenvolvido.
Seguindo o fluxograma, percebemos que a primeira coisa a se fazer ao ligar o dispositivo, é ler o botão. Enquanto não for pressionado o programa ficará num “looping infinito”.
Após pressionado, será então medida a distância entre o medidor e o objeto. Enquanto não conseguir verificar a distância, ficará alertando o usuário através do led vermelho e um “beep”.
Ao fazer a leitura da distância, é acionado o led verde indicando sucesso e um “beep” um pouco mais suave que o anterior. O próximo estágio novamente é aguardar o pressionamento do botão, pois nesse momento o software está aguardando o usuário mirar no topo do objeto.
Assim que o usuário pressiona esse botão, o software faz então a leitura da inclinação do aparelho, calcula a alutra do objeto de acordo com a tabela de valores das tangentes, informa ao usuário a altura calculada e por fim, gera 3 “beeps” informando o término do processo, possibilitando então que o usuário faça uma nova medida.
Fotos do desenvolvimento
[nggallery id=4]
Video apresentando o projeto
Código fonte do programa
#include "Ultrasonic.h" Ultrasonic ultrasonic(12,13); // TRIG = pino 12 ECHO = pino 13 float tangentes[] = { 0.017455, 0.034921, 0.052408, 0.069927, 0.087489, 0.105104, 0.122785, 0.140541, 0.158384, 0.176327, 0.19438, 0.212557, 0.230868, 0.249328, 0.267949, 0.286745, 0.305731, 0.32492, 0.344328, 0.36397, 0.383864, 0.404026, 0.424475, 0.445229, 0.466308, 0.487733, 0.509525, 0.531709, 0.554309, 0.57735, 0.600861, 0.624869, 0.649408, 0.674509, 0.700208, 0.726543, 0.753554, 0.781286, 0.809784, 0.8391, 0.869287, 0.900404, 0.932515, 0.965689, 1, 1.03553, 1.072369, 1.110613, 1.150368, 1.191754, 1.234897, 1.279942, 1.327045, 1.376382, 1.428148, 1.482561, 1.539865, 1.600335, 1.664279, 1.732051, 1.804048, 1.880726, 1.962611, 2.050304, 2.144507, 2.246037, 2.355852, 2.475087, 2.605089, 2.747477, 2.904211, 3.077684, 3.270853, 3.487414, 3.732051, 4.010781, 4.331476, 4.70463, 5.144554, 5.671282 }; int pinoBotao = 9; int ledVerde = 3; int ledVermelho = 2; int pinoX = A3; void setup (){ Serial.begin (9600); Serial.println("Pronto para uso. Mire no objeto e pressione o botao."); pinMode(pinoBotao, INPUT); pinMode (ledVermelho, OUTPUT); pinMode (ledVerde, OUTPUT); } void loop (){ /* Calcula altura da árvore (ou objeto) de acordo com valores dos sensores */ // Enquanto o usuário não apertar o botão, fica aguardando aguardaBotao(); // Lê a distância int distancia = verificaDistancia(); Serial.print("Distancia lida: "); Serial.print(distancia); Serial.println("cm"); // Aguarda o usuário mirar no topo do objeto e apertar novamente o botão Serial.println("Mire na ponta do objeto e pressione o botao novamente."); aguardaBotao(); // Calcula o ângulo int anguloInclinacao = verificaAngulo(); Serial.print("Angulo de inclinacao lido: "); Serial.print(anguloInclinacao); Serial.println(" graus"); /* Finalmente, calcula a altura. Para isso, pega a tangente correspondente do ângulo e multiplica pela distância lida */ float tangente = tangentes[anguloInclinacao - 1]; Serial.print("tangente obtida: "); Serial.println(tangente); float altura = distancia * tangente; // Exibe a altura Serial.print("Altura do objeto: "); Serial.print(altura); // Exibe outras informaçoes Serial.print("cm, baseada na distancia de "); Serial.print(distancia); Serial.print(" CM e no angulo de "); Serial.print(anguloInclinacao); Serial.println(" graus."); Serial.println(); // Informa fim de leitura com 3 bips geraBipOk(); delay(100); geraBipOk(); delay(100); geraBipOk(); } /* Lê o sensor do ângulo do eixo X do acelerômetro. Faz uma média de leituras e retorna o valor delas */ int verificaAngulo() { // Define a quantidade de leituras para uma média byte quantiaLeituras = 10; // Cria um vetor para alocar as médias int leiturasAngulo[quantiaLeituras]; // Cria variável de controle do laço (for) int i; // Lê-se: Para i = 1, enquanto o valor de i for menor que // a quantiaDeleituras, incremente i e faça for (i = 0; i < quantiaLeituras; i = i + 1){ // Lê o valor do sensor e coloca-o na variável eixoX (esse valor vai de 0 à 1023) int eixoX = analogRead(pinoX); // Mapeia o valor lido que normalmente é de 332 à 165 para 0 e 90 (Graus) int novoX = map(eixoX, 332,167,0,90); // Aloca no vetor leiturasAngulo os valores leiturasAngulo[i] = novoX; } // Calcula a média aritmética do ângulo int somaAngulos = 0; for (i = 0; i < quantiaLeituras; i++){ somaAngulos = somaAngulos + leiturasAngulo[i]; } // Retorna o valor do cálculo (arredonda a média) return somaAngulos / quantiaLeituras; } /* Lê o botão usado para interagir com o usuário Enquanto a leitura retornar 0, fica lendo o botão */ void aguardaBotao() { /* O ! é usado para negar o resultado da leitura. Se o resultado for 0 ele vira 1 Se o resutlado for 1 ele vira 0 Lê-se: enquanto o botão não estiver pressionado (negação de 0 é 1) fique lendo */ while(! digitalRead(pinoBotao)); /* // A mesma coisa que a linha de cima boolean botaoNaoPressionado = true; while(botaoNaoPressionado){ if (digitalRead(pinoBotao)){ botaoNaoPressionado = false; } } */ // Aguarda 1 segundo para evitar varios acionamentos pelo botao delay(1000); } /* Lê o sensor ultrassom até receber 3 valores e gerar a média entre eles. Após lido os três valores, a luz verde irá ligar e um "bip" soará indicando a correta leitura Por fim, retorna a distância em CM */ int verificaDistancia() { int quantiaLeituras = 10; int leiturasUltrassom[quantiaLeituras]; int i; boolean lido; for (i = 0; i < quantiaLeituras; i++){ lido = false; while(!lido){ int valorUltrassom = ultrasonic.Ranging(CM); int valorAngulo = verificaAngulo(); if (valorUltrassom < 1000){ lido = true; leiturasUltrassom[i] = valorUltrassom; }else{ delay(500); geraBipFalha(); ativaLedVermelho(); } } } // Gera o "BIP" e ativa o led ativaLedVerde(); geraBipOk(); // Calcula a média aritmética da distância int somaDistancias = 0; for (i = 0; i < quantiaLeituras; i++){ somaDistancias = somaDistancias + leiturasUltrassom[i]; } Serial.print("soma das distancias: "); Serial.print(somaDistancias); Serial.print(" quantiaLeituras: "); Serial.println(quantiaLeituras); // Retorna o valor do cálculo return somaDistancias / quantiaLeituras; } void ativaLedVerde() { digitalWrite(ledVerde, HIGH); desativaLedVermelho(); } void desativaLedVerde() { digitalWrite(ledVerde, LOW); } void ativaLedVermelho() { digitalWrite(ledVermelho, HIGH); desativaLedVerde(); } void desativaLedVermelho() { digitalWrite(ledVermelho, LOW); } void geraBipOk() { tone(8,256,50); } void geraBipFalha() { tone(8,104,50); }Agradecimentos
A construção desse projeto no tempo esperado não teria sido possível se o Herculano não tivesse emprestado o acelerômetro e o sensor de distância, valeu professor!
Conclusão
É evidente no video que o projeto precisa de melhorias em relação à precisão da leitura, exceto se for para medir a cabeça de um gato hehe. Essas melhorias basicamente estão nos sensores usados.
Acreditamos, no entando, que a ideia foi validada, visto que comprovamos que é possível medir objetos com Arduino um acelerômetro e um sensor de distância.
Adorei os desenhos hahahahah
ok gostei do projeto também!
parabéns manos!
heheh, oi mana, você por aqui??
Que bom que gostou! Thanks!
Muito bom e muito bem elaborado, parabéns aos dois.
Como sempre o Arduino mostrando o quanto é útil para o aprendizado, não importando o assunto.
Oi amigo Antonio,
realmente o Arduino é muito útil para a aprendizagem…
Continue com seu blog, sempre muito informativo e bem desenvolvido, parabéns!
obrigado pelo retorno!
Cara, voce me ajudou muito, estudo engenharia e estou ajudando a divulgar teu blog, ja que me ajudou muito!
Opa, que bom de alguma forma que lhe ajudei. Obrigado pela divulgação William!
Cara, muito interessante o medidor de altura. Parabéns!
Muito legal! Gostaria de ter metade de seus conhecimentos p/ tocar um projeto que venho sonhando a tempos…
Obrigado Luis, tenho certeza de que aos poucos, resolvendo um problema de cada vez, você consegue tirar do papel seu projeto!
Sou apaixonado por ELETRÔNICA e gostei muito do que vi no seu titorial criado para ajudar sua irmã. Rsss…
Gostei muito do ratinho gordinho apos comer os componentes. Rsss…
Mais adorei mesmo a sua abordagem simples e himilde para apredizes como eu.
Responda meu e-mail.
Boa noite. Obrigado!