Curso Arduino – #10 – Gráficos, Números Aleatórios e Condições
Chegamos ao último artigo do Curso Arduino! Neste, vamos abordar alguns aspetos que vão melhorar a programação: combinação de condições e números aleatórios. Também vamos ver como é fácil apresentar a informação enviada para o PC na forma de um gráfico!
Desenho de Gráficos
O Arduino IDE possui uma característica muito conveniente que permite desenhar rapidamente diagramas a partir das informações enviadas via UART. Para usar esta ferramenta, tem de ter o IDE atualizado. Se não tiver, atualize-o antes de continuar. Deverão aparecer, na secção Ferramentas, as seguintes opções: Monitor Série e Plotter Série.
Para desenhar um gráfico, devemos, de preferência, enviar os números para o computador em diferentes linhas. Primeiramente, vamos criar um sistema que desenhe um gráfico da tensão medida na entrada A5, à qual ligamos um potenciómetro.
Material necessário:
- 1x Arduino UNO e cabo USB;
- 1x Breadboard;
- 1x Potenciómetro;
- 5x Cabos jumper.
O diagrama de ligação é o seguinte:
A versão normal do programa a enviar informações para o monitor série seria a seguinte:
int dadosRecebidos = 0; void setup() { Serial.begin(9600); //Configuração da velocidade de transmissão } void loop() { dadosRecebidos = analogRead(A5); //Leitura do valor da tensão Serial.println(dadosRecebidos); //Envio para o monitor série delay(200); //Atraso para melhor efeito }
Ao usar a opção “Monitor Série”, quando rodar o seu potenciómetro verá o seguinte efeito:
Pouco legível, não acha? Agora abra o “Plotter Série”. Muito melhor, certo? Os dados recebidos são apresentados num gráfico, como podemos ver no vídeo abaixo:
Quando é que esta opção é útil na prática? Quando usamos sensores (distância, temperatura, etc.), claro! No artigo anterior abordamos o sensor de distância ultrassónico HC-SR04. Vamos tentar desenhar um gráfico da distância medida!
Exercício Prático – Gráfico da Distância de um Obstáculo
Para isto, voltamos ao diagrama do artigo anterior:
Também executamos o código escrito no artigo anterior. Só precisa fazer duas alterações. A primeira é exibir o resultado numa nova linha sem referência à unidade de medida. A segunda é aumentar a frequência das medições – graças a isso, o gráfico será mais fluido.
#define trigPin 12 #define echoPin 11 void setup() { Serial.begin (9600); pinMode(trigPin, OUTPUT); //Definição do pino 12 como saída pinMode(echoPin, INPUT); //Definição do pino 11 como entrada } void loop() { long tempo, distancia; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); tempo = pulseIn(echoPin, HIGH); distancia = tempo / 58; Serial.println(distancia); delay(100); }
Vamos então desenhar o gráfico! Este às vezes funciona bem, mas outras vezes não. Quando usamos este tipo de sensores, corremos o risco de receber alguma interferência. Neste caso, pode causar o envio de medições incorretas para o computador. A imagem abaixo mostra medições acima dos 2400cm, o que é impossível, sendo que o fabricante indica que o sensor tem como valor de medição máximo 400cm.
Isto resulta da seleção automática da escala do gráfico. Como solucionar o problema? Vamos adicionar uma condição que irá verificar o valor enviado para o computador:
if (distancia > 400) { //Se a distância medida for maior do que 400cm distancia = 400; //Definir distância como 400cm (valor máximo indicado pelo fabricante) }
Graças a esta função, nunca mais será enviada uma medição acima do valor máximo do sensor. Vejamos o programa completo:
#define trigPin 12 #define echoPin 11 void setup() { Serial.begin (9600); pinMode(trigPin, OUTPUT); //Definição do pino 12 como saída pinMode(echoPin, INPUT); //Definição do pino 11 como entrada } void loop() { long tempo, distancia; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); tempo = pulseIn(echoPin, HIGH); distancia = tempo / 58; if (distancia > 400) { //Se a distância medida for maior do que 400cm distancia = 400; //Definir distância como 400cm (valor máximo indicado pelo fabricante) } Serial.println(distancia); delay(100); }
Agora, o gráfico apresentará sempre valores dentro da faixa de medição do sensor:
Exercício Prático – Gráficos com Vários Valores
Esta característica de desenho de gráficos também permite incluir diversos valores de uma só vez. Para usufruir desta opção, deve enviar números na mesma linha separados por um caracter tab. O caracter para início de uma nova linha, deverá aparecer no final.
Na prática, o código é este:
Serial.print(valor1); Serial.print("\t"); // Tab Serial.print(valor2); Serial.print("\t"); // Tab Serial.print(valor3); Serial.print("\t"); // Tab Serial.print(valor4); Serial.println(""); // Transição para nova linha
Trabalho de Casa nº32
Use, na prática, a capacidade de desenhar vários gráficos ao mesmo tempo. Ligue dois sensores LDR ao Arduino. De seguida, meça o nível de luz que cada um deles recebe. Ambos os valores devem ser apresentados num gráfico.
Números Aleatórios
Às vezes pretendemos que um programa funcione de forma imprevisível. Um exemplo? Um robot que, depois de detetar um obstáculo, roda para um lado de forma aleatória.
Neste tipo de situações, uma função que envia um valor aleatório é bastante útil. A função random () é responsável por enviar um valor aleatório, e pode conter dois argumentos. Graças a eles, definimos o intervalo dos números a serem enviados. Na prática, a função usada frequentemente de duas formas. Indicação do limite superior:
random(500); //Número aleatório no intervalo de 0 a 499
Indicação dos limites inferior e superior:
random(100, 500); //Número aleatório no intervalo de 100 a 499
Vamos agora verificar a função na prática. Para isso, copie o seguinte código. O seu objetivo é enviar números aleatórios para o monitor série a cada segundo.
void setup() { Serial.begin(9600); } void loop() { Serial.println(random(300)); delay(1000); }
Como esperado, no monitor série verá o seguinte:
Vamos fazer uma experiência: reinicie o programa várias vezes e veja o que acontece. Já deve ter reparado que os números são sempre iguais. Infelizmente, recebemos a mesma string de números de todas as vezes que reiniciamos o programa. Neste sentido, a “aleatoriedade não é totalmente aleatória”. O microcontrolador da placa Arduino é um sistema muito preciso que realiza operações programadas. Não existem valores aleatórios no seu mundo.
A fim de melhorar o funcionamento do algoritmo de aleatoriedade, vamos utilizar uma nova função: randomSeed (). Com esta função, os números gerados vão ser determinados pelo valor inicial – seed. Vejamos a utilização desta:
randomSeed(valor_inicial);
No argumento, que está indicado como valor_inicial, deve inserir um número aleatório. É um pouco confuso… Para gerar valores aleatórios, é necessário um valor aleatório. Sabe como obtê-lo? Se não, reveja o artigo sobre o Conversor Analógico-Digital.
O que é que acontece se nenhum sinal estiver ligado à entrada a ser lida? Recebe interferências do ambiente, que são aleatórias. Até agora, era um problema para nós, mas encontramos um propósito para isso. Desta forma, para recebermos números “mais aleatórios”, vamos colocar a seguinte linha:
randomSeed(analogRead(A0));
Graças a ela, cada vez que o programa é iniciado, existe uma medição da tensão na entrada A0. De seguida, esse valor será fornecido como seed ao gerador de números pseudoaleatórios.
Aqui está o código completo. Vamos testá-lo.
void setup() { Serial.begin(9600); randomSeed(analogRead(0)); } void loop() { Serial.println(random(300)); delay(1000); }
De agora em diante, de cada vez que iniciar o programa, obterá valores diferentes:
Claro que ainda não é um gerador de números aleatórios perfeito, mas é suficiente para o uso em projetos Arduino.
Trabalho de Casa nº33
Verifique o que acontece se, em vez de fornecer a leitura da entrada analógica como seed, fornece um valor fixo. Como é que o gerador de números pseudoaleatórios vai reagir?
Trabalho de Casa nº34
Escreva um programa que funciona como um dado eletrónico. Ligue um botão de pressão ao Arduino. Cada vez que pressionar o botão, deve enviar para o computador (via UART) um valor compreendido entre 1 e 6.
Exercício Prático – Piscar do LED Aleatório
Vamos usar o conhecimento adquirido anteriormente para escrever um programa, que tenha como objetivo piscar o LED do pino 13 de forma aleatória. Vamos assumir que o tempo que o LED está ligado varia entre 100ms e 990ms. E o tempo que está desligado entre 50ms e 490ms. Ambos os valores devem mudar em intervalos de 10ms. Para isto, vamos precisar de dois valores aleatórios:
int tempoLigado = random(100, 1000); int tempoDesligado = random(50, 500);
Poderíamos colocar estes valores na função delay, mas o atraso poderia assumir qualquer valor de 100 a 999, ou seja, não íamos respeitar os intervalos de 10ms. Como solucionar? Tudo o que temos de fazer é inserir valores 10 vezes menores, que serão multiplicados por 10 antes de substituí-los pela função delay:
int tempoLigado = random(10, 100); //Valor varia entre 10 e 99 int tempoDesligado = random(5, 50); //Valor varia entre 5 e 49 tempoLigado = tempoLigado * 10; //Valor varia entre 100 e 990, a cada 10ms tempoDesligado = tempoDesligado * 10; //Valor varia entre 50 e 499, a cada 10ms
Assim, podemos finalizar o código:
void setup() { pinMode(13, OUTPUT); randomSeed(analogRead(0)); } void loop() { int tempoLigado = random(10, 100); //Valor varia entre 10 e 99 int tempoDesligado = random(5, 50); //Valor varia entre 5 e 49 tempoLigado = tempoLigado * 10; //Valor varia entre 100 e 990, a cada 10ms tempoDesligado = tempoDesligado * 10; //Valor varia entre 50 e 499, a cada 10ms digitalWrite(13, HIGH); delay(tempoLigado); digitalWrite(13, LOW); delay(tempoDesligado); }
Na prática, o piscar do LED será totalmente aleatório!
Combinação de Funções Condicionais
No início do curso Arduino, abordamos a função condicional if, que é usada para controlar o programa dependendo de uma determinada condição. Na maioria das vezes, utilizamos apenas uma condição, por exemplo: “O botão foi pressionado?”. Todavia, na prática, pode acontecer que queira verificar duas condições simultaneamente. O exemplo mais simples é verificar se o utilizador pressionou mais do que um botão. É claro que, pode fazê-lo tradicionalmente:
if (digitalRead(7) == LOW) { //Se o primeiro botão for pressionado, verificar... if (digitalRead(8) == LOW) { //... se o segundo botão foi pressionado //Realizar determinada ação } }
A solução é eficaz, mas terá alguns problemas em perceber o código, principalmente se quiser incluir mais condições. Portanto, é muito mais fácil quando utilizamos os seguintes operadores lógicos:
- Produto lógico – &&
- Soma lógica – ||
Usamos o primeiro quando queremos verificar se a primeira e a segunda condição foram atendidas:
if (condicao1 ==1 && condicao2 ==1)
O segundo é usado quando queremos verificar se a primeira condição foi atendida ou se a segunda condição foi atendida (ou as duas):
if (condicao1 == 1 || condicao2 == 1)
Exercício Prático – Combinação de Condições
Material necessário:
- 1x Arduino UNO e cabo USB;
- 1x Breadboard;
- 2x LEDs (verde e vermelho);
- 2x Botões de pressão;
- 2x Resistências de 330Ω;
- 7x Cabos jumper.
Para este propósito, ligue dois LEDs (vermelho e verde) e dois botões ao Arduino. O diagrama de montagem é o seguinte:
Agora, escreva um programa que ligue o LED verde quando pressiona um dos botões de pressão. O código poderá ser o seguinte:
void setup() { pinMode(10, INPUT_PULLUP); //Botão como entrada pinMode(9, INPUT_PULLUP); //Botão como entrada pinMode(8, OUTPUT); //LED como saída pinMode(7, OUTPUT); //LED como saída digitalWrite(8, LOW); //Desligar LED verde digitalWrite(7, LOW); //Desligar LED vermelho } void loop() { if (digitalRead(9) == LOW || digitalRead(10) == LOW) { //Se o primeiro ou o segundo botão forem pressionados digitalWrite(8, HIGH); //LED verde liga } else { digitalWrite(8, LOW); //LED verde desliga } }
A parte mais importante deste código é a função que verifica os estados dos dois botões. Se pelo menos um deles for pressionado, o LED verde acende.
Vamos expandir o programa e criar uma condição que ligue o LED vermelho quando os dois botões forem pressionados simultaneamente:
void setup() { pinMode(10, INPUT_PULLUP); //Botão como entrada pinMode(9, INPUT_PULLUP); //Botão como entrada pinMode(8, OUTPUT); //LED como saída pinMode(7, OUTPUT); //LED como saída digitalWrite(8, LOW); //Desligar LED verde digitalWrite(7, LOW); //Desligar LED vermelho } void loop() { if (digitalRead(9) == LOW || digitalRead(10) == LOW) { //Se o primeiro ou o segundo botão forem pressionados digitalWrite(8, HIGH); //LED verde liga } else { digitalWrite(8, LOW); //LED verde desliga } if (digitalRead(9) == LOW && digitalRead(10) == LOW) { //Se os dois botões forem pressionados simultaneamente digitalWrite(7, HIGH); //LED vermelho liga } else { digitalWrite(7, LOW); //LED vermelho desliga } }
Exercício Prático – Sensor de Distância Ultrassónico
Os exemplos acima mostraram o funcionamento do sistema, mas não são exemplos propriamente úteis. Vamos tentar fazer algo mais prático. Ligue ao Arduino um botão de pressão, um sensor de distância ultrassónico HC-SR04 e um buzzer. O sistema irá emitir um som se um obstáculo estiver entre 20 e 40 cm do sensor ou se pressionar o botão de pressão.
Material necessário:
- 1x Arduino UNO e cabo USB;
- 1x Breadboard;
- 1x Sensor de distância ultrassónico HC-SR04;
- 1x Buzzer;
- 1x Botão de Pressão;
- 10x Cabos jumper.
Primeiro, temos de fazer as conexões necessárias. Para tornar o exercício mais complexo, desta vez não vamos fornecer diagrama de montagem. Vamos sim, indicar uma lista de conexões a realizar e mostrar uma imagem auxiliar. Por esta altura do curso, já todos devem conseguir fazer as ligações sem qualquer problema.
Lista de conexões:
- Ligar pino trigger do sensor ao pino 12 do Arduino;
- Ligar pino echo do sensor ao pino 9 do Arduino;
- Ligar buzzer ao pino 11 do Arduino;
- Ligar botão ao pino 10 do Arduino.
Adicionalmente, deverá fazer as ligações para alimentação e GND. Vejamos a imagem ilustrativa:
Vamos passar à programação. Nós já conseguimos ler a distância e verificar o status do botão já não é um problema. Portanto, vamos focar-nos na análise da condição. Como foi referido, pretendemos ativar o buzzer quando um obstáculo estiver entre 20 e 40 cm do sensor. Para isso, temos de verificar se o valor lido pelo sensor é maior do que 20 cm e, ao mesmo tempo, menor do que 40 cm. Fazemo-lo numa condição:
if (distancia > 20 && distancia < 40) { digitalWrite(11, HIGH); //Ativar buzzer } else { digitalWrite(11, LOW); //Desativar buzzer }
Vamos passar para o botão. É claro que podemos utilizar duas condições:
if (distancia > 20 && distancia < 40) { digitalWrite(11, HIGH); //Ativar buzzer } else { digitalWrite(11, LOW); //Desativar buzzer } if (digitalRead(10) == LOW) { //Se o botão for pressionado digitalWrite(11, HIGH); //Ativar buzzer } else { digitalWrite(11, LOW); //Desativar buzzer }
Mas, para quê? Se o objetivo das duas condições é igual, não as podemos juntar? Claro que podemos! Assim, o que pretendemos verificar é:
(a distância medida é maior do que 20 cm e menor do que 40 cm) ou (o botão é pressionado)
Traduzindo isto para a linguagem C:
if ((distancia > 20 && distancia < 40) || digitalRead(10) == LOW) { digitalWrite(11, HIGH); //Ativar buzzer } else { digitalWrite(11, LOW); //Desativar buzzer }
O código completo é o seguinte:
#define trigPin 12 #define echoPin 9 void setup() { pinMode(trigPin, OUTPUT); //Definição do pino 12 como saída pinMode(echoPin, INPUT); //Definição do pino 9 como entrada pinMode(10, INPUT_PULLUP); //Botão como entrada pinMode(11, OUTPUT); //Buzzer como saída digitalWrite(11, LOW); //Desligar buzzer } void loop() { long tempo, distancia; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); tempo = pulseIn(echoPin, HIGH); distancia = tempo / 58; if ((distancia > 20 && distancia < 40) || digitalRead(10) == LOW) { digitalWrite(11, HIGH); //Ativar buzzer } else { digitalWrite(11, LOW); //Desativar buzzer } }
Na prática, o programa funciona exatamente como previsto.
Trabalho de Casa nº35
Escreva um programa que escolha aleatoriamente um número de 0 a 100, e verifique se esse valor é/está:
- Menor do que 10 ou maior do que 90;
- Maior do que 50, mas que não se encontre dentro do intervalo 70-85;
- Igual a 20, 30, 40 ou 50;
- Incluído no intervalo 10-40 ou 60-100.
Em cada alínea, envie o número escolhido para o monitor série e indique se cumpriu ou não a condição.
Sumário do Curso Arduino!
É verdade, chegamos ao fim do curso. Tudo o que tínhamos planeado abordar, já foi mencionado. Esperamos que os conhecimentos adquiridos ao longo do curso sejam de grande utilidade para os vossos próximos projetos. Mal podemos esperar por ver as vossas invenções! Obrigado por frequentarem o nosso curso e continuação de bons projetos!
___________
O que achou deste artigo? Deixe o seu comentário abaixo, e partilhe nas Redes Sociais que certamente será útil e interessante para os seus amigos!
Curso Arduino – #0 – Introdução
Curso Arduino – #1 – O Básico do Arduino e o Software de Programação
Curso Arduino – #2 – O Básico da Programação e as Portas I/O
Curso Arduino – #3 – UART e Variáveis
Curso Arduino – #4 – Conversor Analógico-Digital
Curso Arduino – #5 – PWM, Servomecanismos e Bibliotecas
Curso Arduino – #6 – UART (continuação) e Servos
Curso Arduino – #8 – Controlo de Motores DC
Curso Arduino – #9 – Sensor de Distância Ultrassónico HC-SR04 e Novas Funções
Curso Arduino – #10 – Gráficos, Números Aleatórios e Condições