Robô seguidor de linha
Robô seguidor de linha
Neste tutorial vamos aprender a fazer um robô seguidor de linha utilizando o sensor de obstaculo infravermelho (Você poderá usar o Módulo Segue Faixa - TCRT5000) em conjunto com um Arduino.
Para melhor entendimento deste tutorial é necessário que você já tenha um conhecimento prévio sobre Arduino e ponte H. Mas não se preocupe pois nossa equipe já produziu outros tutoriais sobre esse assuntos e você pode conferir alguns destes nos seguintes links: Entradas e Saídas Analógicas e Módulo Ponte H L298n .
[toc]
A importância do robô seguidor de linha
O robô seguidor de linha, também conhecido como seguidor de faixa, é um projeto bem famoso entre os apaixonados por robótica. Quase sempre é o primeiro projeto de robótica móvel.
Em todo o mundo, competições de robótica possuem modalidades únicas para o seguidor de linha, o que faz deste projeto algo que nunca irá deixar de ser melhorado.
Seu projeto envolve conceitos de dimensionamento de energia, controle de motores, programação de embarcados, entre outros.
Esses mesmos conceitos são levados para projetos maiores e mais complexos, tanto acadêmicos quanto industriais.
Robôs seguidores de linha na industria
As aplicações industriais são bem diversificadas. Os robôs que gerenciam o estoque da grande rede de varejos Alibaba, começaram a funcionar com os princípios do seguidor de linha.
Eles manejavam as prateleiras de produtos dentro do estoque por meio de orientação de faixas no chão. Sua função era transportar os materiais de um lado para outro, seja para reajustar o estoque ou para levar para uma área de exportação.
Atualmente o Alibaba evoluiu os robôs, de forma que eles se comunicam, e se localizam, por meio de IA (Inteligência Artificial).
Como um robô seguidor de linha funciona ?
O funcionamento do robô seguidor de linha é simples. Ele deve seguir andando por cima de uma linha de cor preta (fita isolante) ou branca.
Os circuitos podem alternar entre as cores do campo e da faixa, no nosso caso iremos assumir que a pista é branca e a faixa é preta.
Usaremos 2 sensores infravermelho que detectam a presença ou não desta faixa. De acordo com a combinação dos sensores, o carrinho irá para frente ou virar para um dos lados.
Funcionamento do sensor infravermelho
O módulo sensor de obstáculo infravermelho IR é bem simples. Ele emite uma luz infravermelha por um LED negro e capta o reflexo com um LED receptor (LED claro).
Como sabemos, a luz reflete em superfícies claras e é absorvida em superfícies negras, como a fita isolante. Sendo assim o LED receptor irá detectar a luz infravermelha no branco e não detectar no preto.
Para uma melhor eficácia do sensor, a superfície em contraste com a faixa preta deve ser branca. Para ajustar a sensibilidade ao contraste, o modulo possui um potenciômetro de calibração.
Diferença entre sensores infravermelho obstaculo e o TCRT5000
Você pode usar diferentes sensores infravermelhos para o projeto seguidor de linha, o que você precisa levar em conta é as especificações de cada um.
Um sensor infravermelho amplamente utilizado é o TCRT5000, que tem como vantagem seu tamanho e preço. Porem, ele precisa está próximo ao chão para que seja capaz de identificar a faixa, uma vez que seu alcance é de até 8mm. Entretanto, ele possui a vantagem de sofrer menos interferências de luzes infravermelhas externas.
Em contrapartida, a vantagem de usar o sensor de obstaculo é o seu maior alcance possuir ajuste, porem ele é mais suscetível a interferências das luzes ambientes.
Nesse tutorial, usaremos o sensor de obstaculo infravermelho. Dessa forma, caso esteja usando o TCRT5000, fique atento com a distância do chão. Ele precisa ficar com uma distância entre 1mm e 8mm para ser capaz de detectar a faixa.
Controlando motores com Ponte H
Quando lidamos com controle de cargas que consomem grande quantidade de energia, é importante que essas cargas sejam controladas com circuitos que separem o circuito de controle do circuito de potência.
Para controlar motores, é comum usarmos um circuito chamado ponte H, ele é capaz por controlar o sentido de giro do motor e a sua velocidade, usando o PWM.
PWM
PWM (Pulse Width Modulation – Modulação por Largura de Pulso) é uma técnica para obter resultados analógicos por meios digitais (Leia mais sobre Grandezas digitais e analógicas e PWM).
Essa técnica consiste na geração de uma onda quadrada em uma frequência muito alta em que pode ser controlada a porcentagem do tempo em que a onda permanece em nível lógico alto, alterando, assim, a tensão média.
Por exemplo, se a saída é de 5V, porem ela fica apenas 50% do tempo em 5V e outros 50% do tempo em nível lógico baixo, isso resulta em uma tensão média de 2,5V (50% x 5V).
Dessa forma, esta variável de tempo é capaz de controlar de velocidade do nosso carrinho alterando a tensão média aplicada no motor.
Os valores de PWM variam de 0 (parado) até 255 (velocidade máxima ou 5 V).
Controlando a velocidade do motor através da Ponte H
Existem varias opções de Ponte H, nesse tutorial usaremos o módulo Ponte H com CI L298N que dispões de duas pontes H, sendo capaz assim de controlar dois motores.
Cada ponte H possui um pino que ativa ou não a ponte H. Caso tenha um sinal de 5V aplicado nele, a ponte estará ligada, caso seja 0V a ponte estará desligada. Como temos 2 pontes H, temos o Enable A(Ativa A) e o Enable B (Ativa B).
Normalmente os Enables A e B ficam em curto com um sinal de 5V da placa através de um jumper.
Se retiramos esse jumper e inserimos um sinal PWM nessas entradas, modularemos a tensão que é enviada para o motor. Isso ocorre porque a ponte H só ira “funcionar” enquanto o sinal de Enable estiver com 5V, assim teremos o mesmo efeito de tensão média explicado anteriormente.
Apesar de a ponte H ser controlada por um sinal de 5V, elá pode chavear uma tensão diferente. Podemos, por exemplo, controlar uma tensão de 6V, vindo de um conjunto de 4 pilhas AA. Nesse caso, apesar de o sinal PWM ser de 5V ele modulará os 6V nos motores.
A descrição completa sobre como funciona uma ponte H L298N e como controlar a velocidade de um motor usando uma ponte H L298N pode ser visto nos nossos tutoriais sobre os respectivos assuntos.
Montado um robô seguidor de linha com sensor infravermelho
A partir de agora iremos mostrar como montar o seu próprio robô seguidor de linha.
Componentes Necessários
Para este projeto iremos utilizar:
- 1 x Arduino UNO
- 2 x Sensores de obstaculo infravermelho (ou módulo TCRT5000)
- 1 x Chassi Robô móvel 2WD ( Ou 2 x Motores DC 5 v com roda + um suporte para o carrinho)
- 1 x Ponte H L298N
- 1 x Bateria 9 V + conector (ou fonte semelhante)
- Protoboard e Jumpers
Montando o projeto do robô seguidor de linha
Abaixo segue um esquema de ligações e montagem ELETRÔNICA do projeto:
Este projeto possui um procedimento de montagem complexo devido ao fato da necessidade de termos que passar vários fios por um espaço limitado ao tamanho do chassi do seu carrinho.
Calibração do Sensor infravermelho
Ao usar o sensor infravermelho, seja o sensor de obstaculo ou o TCRT5000, você precisa calibrar o sensor para que seja capaz de detectar adequadamente a mudança de cor entre preto e branco.
No vídeo a segui eu mostramos como fazer essa calibração.
Programando o controle do Robô seguidor de linha
A programação do projeto é bem simples. O carrinho precisa fazer a leitura dos sensores e definir pra qual lado ele deve ir, somente isso, até por que um programa muito extenso pode prejudicar o rendimento.
/*DECLARAÇÃO DE VARIAVEIS*/ #define MotorA_sentido1 2 #define MotorA_sentido2 4 #define MotorB_sentido1 8 #define MotorB_sentido2 9 #define MotorA_PWM 3 #define MotorB_PWM 10 #define veloc0 0 #define veloc1 80 #define veloc2 180 #define veloc3 255 #define Sensor_direita 6 #define Sensor_esquerda 7 bool direita, esquerda; void setup() { Serial.begin(9600); pinMode(MotorA_sentido1, OUTPUT); pinMode(MotorA_sentido2, OUTPUT); pinMode(MotorB_sentido1, OUTPUT); pinMode(MotorB_sentido2, OUTPUT); pinMode(MotorA_PWM, OUTPUT); pinMode(MotorB_PWM, OUTPUT); pinMode(Sensor_direita, INPUT); pinMode(Sensor_esquerda, INPUT); } void loop() { //Define o sentido de rotação dos motores digitalWrite(MotorA_sentido1, LOW); digitalWrite(MotorA_sentido2, HIGH); digitalWrite(MotorB_sentido1, HIGH); digitalWrite(MotorB_sentido2, LOW); //Leituras dos Sensores direita = digitalRead(Sensor_direita); esquerda = digitalRead(Sensor_esquerda); Serial.print(direita); Serial.print(" || "); Serial.println(esquerda); //Rodando os motores dependendo das leituras if(direita == false && esquerda == false){ analogWrite(MotorA_PWM, veloc2); analogWrite(MotorB_PWM, veloc2); } else if(direita == false && esquerda == true){ delay(400); analogWrite(MotorA_PWM, veloc2); analogWrite(MotorB_PWM, veloc1); delay(400); }else if(direita == true && esquerda == false){ delay(400); analogWrite(MotorA_PWM, veloc1); analogWrite(MotorB_PWM, veloc2); delay(400); }else if(direita == true && esquerda == true){ analogWrite(MotorA_PWM, veloc0); analogWrite(MotorB_PWM, veloc0); } }
Colocando o Robô seguidor de linha para funcionar
Agora é só por o carrinho pra rodar na pista !
Problemas comuns e como resolver
Vale notar que ele pode não fazer o percurso de primeira, o que significa que ajustes devem ser feitos no código ou ate mesmo no hardware. Alguns problemas comuns de acontecer:
- Bateria fraca - Os testes podem ter consumido a bateria e talvez seja necessário o uso de uma nova. Baterias abaixo de 6,5 Volts já começam a diminuir a eficiência do carrinho.
- Carrinho saindo da pista - Isso pode acontecer por ele estar rápido de mais ou por falha do infravermelho. Em caso de ele estar muito rápido basta trocar a velocidade dos motores em cada situação, o nosso código já possui outras velocidades definidas no cabeçalho. Se o problema for com o contraste da pista (talvez parte dela esteja mais escura) use 2 LEDs de alto brilho na frente do carrinho para iluminar a pista próximo aos sensores. Os LEDs podem ir conectados diretos no 5 V do arduino (lembrando de por um resistor de 300Ohms).
- Carrinho não roda - Este é um problema complexo, pois podem ser infinitas possibilidades. Tente isolar os componentes e testar 1 por 1, principalmente os motores e a ponte H. Em alguns casos pode ser problemas de aterramento da bateria também.
Entendendo a fundo o Software
Declaração de Variáveis
Na primeira parte do código é feita a declaração das variáveis a serem utilizadas. Nota-se que a existe um grande numero de variáveis utilizando #define, isto é por conta de serem apenas nomes associados a números, não precisamos fazer contas com essas variáveis, portanto elas não precisam ser do tipo INT, FLOAT, entre outras.
O fato de declarar algo por meio de #define ocupa menos espaço de memória, o que dá um ganho na velocidade de execução do programa. As únicas variáveis a serem definidas por um tipo são as que armazenarão os valores lidos dos sensores (direita e esquerda), essas variáveis são do tipo bool e portanto só assumem dois estados (FALSE e TRUE).
/*DECLARAÇÃO DE VARIAVEIS*/ #define MotorA_sentido1 2 #define MotorA_sentido2 4 #define MotorB_sentido1 8 #define MotorB_sentido2 9 #define MotorA_PWM 3 #define MotorB_PWM 10 #define veloc0 0 #define veloc1 80 #define veloc2 180 #define veloc3 255 #define Sensor_direita 6 #define Sensor_esquerda 7 bool direita, esquerda;
Cada motor possui 3 pinos: 2 para definir o sentido de rotação da roda (IN1 e IN2 / IN3 e IN4) e 1 pra definir a velocidade de rotação (Enable A / Enable B)por meio de valores PWM. Lembre-se de que os pinos de velocidade devem conter o "~" desenhado ao lado da porta na placa Arduino, caracterizando o pino como PWM.
Declaramos também 4 velocidades de PWM que podem ser interpretadas como PARADO, DEVAGAR, NORMAL e RÁPIDO, respectivamente. Os sensores foram definidos em suas respectivas portas digitais(6 e 7) e por fim, foram declaradas 2 variáveis do tipo BOOL para armazenar os valores dos sensores.
Função Void Setup()
A função void setup, que roda apenas uma vez, defini todas as configurações necessárias para funcionamento do sistema.
void setup() { Serial.begin(9600); pinMode(MotorA_sentido1, OUTPUT); pinMode(MotorA_sentido2, OUTPUT); pinMode(MotorB_sentido1, OUTPUT); pinMode(MotorB_sentido2, OUTPUT); pinMode(MotorA_PWM, OUTPUT); pinMode(MotorB_PWM, OUTPUT); pinMode(Sensor_direita, INPUT); pinMode(Sensor_esquerda, INPUT); }
Nesta função declaramos as variáveis que definem os pinos utilizados no Arduino como sendo Entrada(INPUT) ou Saída(OUTPUT). Além disso colocamos a função Serial.begin() que inicializa a comunicação serial entre o Arduino e o computador.
MAS O CARRINHO NÃO RODA LIGADO NA BATERIA ?!?!?! Sim, porém precisamos fazer testes antes de executar a versão final, para isso utilizamos alguns comandos via serial para poder calibrar sensores, averiguar execução do programa, entre outros.
Função Void Loop ()
Em seguida temos o loop do nosso programa onde o carrinho ira fazer suas principais funções.
- Definindo sentido de giro dos motores
Primeiro é necessário definir o sentido de rotação das rodas.
//Define o sentido de rotação dos motores digitalWrite(MotorA_sentido1, LOW); digitalWrite(MotorA_sentido2, HIGH); digitalWrite(MotorB_sentido1, HIGH); digitalWrite(MotorB_sentido2, LOW);
Nesta parte do código precisamos mandar um sinal alto e um sinal baixo entre os pares de portas IN1/IN2 e IN3/IN4. Como nosso carrinho não anda pra trás nós vamos setar essas configurações para que as rodas girem no mesmo sentido(pra frente no caso).
Veja que os pares no nosso código estão invertidos, isso acontece por que a montagem de hardware foi invertida entre os motores.
É como se os polos fossem trocados de lugar entre os motores, porém lembre-se que motores DC não possuem polaridade definida, logo podemos inverter a ligação + e - sem problemas. Isso altera apenas o sentido para o qual o motor gira. Essa é uma das partes que devem ser testadas antes da montagem final do carrinho.
- Leituras dos Sensores
Adiante, temos as leituras dos sensores infravermelhos e a impressão na serial dos valores lidos. Isso é apenas para verificar se os sensores estão funcionando corretamente, não interferindo no funcionamento final do projeto.
//Leituras dos Sensores direita = digitalRead(Sensor_direita); esquerda = digitalRead(Sensor_esquerda); Serial.print(direita); Serial.print(" || "); Serial.println(esquerda);
As variáveis do tipo BOOL são utilizadas para armazenar os valores digitais lidos pelos sensores.
- Controlando a direção do robô
Por fim, temos as condições de giro do motor com base no sensores infravermelhos.
//Rodando os motores dependendo das leituras if(direita == false && esquerda == false){ analogWrite(MotorA_PWM, veloc2); analogWrite(MotorB_PWM, veloc2); } else if(direita == false && esquerda == true){ delay(400); analogWrite(MotorA_PWM, veloc2); analogWrite(MotorB_PWM, veloc1); delay(400); }else if(direita == true && esquerda == false){ delay(400); analogWrite(MotorA_PWM, veloc1); analogWrite(MotorB_PWM, veloc2); delay(400); }else if(direita == true && esquerda == true){ analogWrite(MotorA_PWM, veloc0); analogWrite(MotorB_PWM, veloc0); }
Para isso, utilizamos as condições IF Else, que são mais comum. São 2 variáveis combinatórias que geram 4 possibilidades, porém a ultima condição é quase "impossível" (true e true), pois seria a leitura dos sensores detectando a faixa preta ao mesmo tempo (como é um erro estranho, o carrinho deve parar).
Os motores estão ligados em portas DIGITAIS mas lembre-se que estamos utilizando valores PWM, logo as funções de comando são do tipo analogWrite(porta, PWM). Para que o carrinho possa ter tempo de verificar o estado dos sensores novamente, alguns delays de curto período são utilizados, mas isso pode variar de projeto para projeto.
Entendendo a fundo o Hardware
O carrinho funciona com uma comunicação entre os sensores, o Arduino e a ponte H controlando os motores.
Através das leituras do sensores enviadas para o Arduino por meio das portas digitais, o controlador irá acionar um motor mais rápido ou mais devagar do que o outro. Os sensores emitem 5 V (faixa preta) ou 0 V(pista branca) para as portas digitais. O Arduino modula os valores de velocidade pelos valores PWM que variam de 0 volts (0) até 5 volts (255), fazendo isso ao longo de todo trajeto.
Observe que utilizamos apenas 1 bateria para todo o sistema. A bateria que alimenta o Arduino pelo pino P4 energiza não somente o controlador como também a ponte H dos motores por meio do pino Vin do Arduino. Esta porta é capaz de emitir valores maiores do que os 5 volts que o regulador de tensão da placa utiliza. Sendo assim a tensão de entrada no pino P4 é a mesma do pino Vin.
Conclusão
Este é um dos projetos mais simples de robótica móvel utilizando Arduino e claro que pode ser melhorando em muitos aspectos.
Algumas sugestões de melhorias são: controle de velocidade PID, desvio de obstáculos, reconhecimento de pista, machining learning, etc.
Desafio
Crie uma função para o robô desviar de obstáculos e retornar para a pista. O sensor ultrassônico é uma ótima opção para ajudar nesse desafio.
Controle de potência via PWM - ESP32
Controle de potência via PWM - ESP32
A modulação por largura de pulso (PWM) é uma técnica amplamente utilizada em diversos meios, principalmente para controle de potência e velocidade. Neste tutorial, você aprenderá a configurar o PWM no ESP32 através do recurso LED PWM e fazer um LED "respirar" (fade) ou acender com metade do brilho.
[toc]
Pulse Width Modulation
Com o PWM, podemos controlar a tensão média em um componente, e por consequência a potência, como um LED, a velocidade de um motor DC ou até converter o sinal PWM criado (onda quadrada) para uma onda senoidal com a adição de alguns poucos itens.
As imagens (GIF) abaixo mostram o duty cycle variando, que altera a tensão média entregue ao componente. Em alguns casos como motores, também é preciso configurar corretamente a frequência de chaveamento e ter atenção ao nível de pico máximo aceito na alimentação, entretanto isso ficará de "lição de casa" para pesquisarem.
Mãos a obra - Variando o brilho do LED
Componentes necessários
- 1x - LED (Usaremos o LED Onboard).
- 1x - ESP32 (Usaremos o NodeMCU-32).
Código do projeto
void setup() { pinMode(2, OUTPUT);//Definimos o pino 2 (LED) como saída. ledcAttachPin(2, 0);//Atribuimos o pino 2 ao canal 0. ledcSetup(0, 1000, 10);//Atribuimos ao canal 0 a frequencia de 1000Hz com resolucao de 10bits. } void loop() { for (int i = 0; i < 1024; i++) { ledcWrite(0, i);//Escrevemos no canal 0, o duty cycle "i". delay(2); } for (int i = 1023; i > 0; i--) { ledcWrite(0, i); delay(2); } }
Colocando para funcionar
O código fará um "fade" no LED, dando a sensação de "respiração", aumentando e diminuindo o brilho gradativamente.
Entendendo a fundo
Software
-Função ledcAttachPin()
ledcAttachPin(PINO, CANAL);
Esta função apenas atribui um pino a um canal. Podemos escolher qualquer pino a qualquer canal, este vai de 0 a 15, totalizando 16 canais.
Cada canal é independente do outro, mas você também pode atribuir vários pinos a um mesmo canal.
Pino: Qualquer.
Canal: 0 - 15.
-Função ledcSetup()
ledcSetup(CANAL, FREQUENCIA, RESOLUCAO);
Esta função configura um canal para trabalhar a uma determinada frequência e resolução.
Canal: 0 - 15.
Frequência: 1 - 40MHz.
Resolução: 1 - 16 bits.
-Função ledcWrite()
ledcWrite(CANAL, DUTY CYCLE);
Esta função "escreve" o duty cycle ao canal. Lembramos que o valor colocado no parâmetro duty cycle não é em porcentagem e sim em decimal.
Exemplo: para um duty cycle de 50% com 10bits (2^10 = 1024) de resolução, devemos escrever 512.
Canal: 0 - 15.
Duty cycle: 0 - 100% (em decimal).
Indo além com PWM
Tensão média
Podemos calcular a tensão média (V) entregue ao componente através de uma simples conta que relaciona o sinal HIGH com o duty cycle.
Sinal HIGH do ESP32 (Vcc): ~3.3V.
Duty cycle: 32%.
Ao efetuar a conta de 3.3*0.32, chegamos a conclusão que a tensão média (Vm) entregue será de 1.056V!
Vamos testar este código e verificar as tensões com um multímetro.
void setup() { pinMode(23, OUTPUT);//Definimos o pino 23 como saída. pinMode(22, OUTPUT);//Definimos o pino 22 como saída. pinMode(21, OUTPUT);//Definimos o pino 21 como saída. pinMode(19, OUTPUT);//Definimos o pino 19 como saída. ledcAttachPin(23, 0);//Atribuimos o pino 23 ao canal 0. ledcSetup(0, 1000, 10);//Atribuimos ao canal 0 a frequencia de 1000Hz com resolucao de 10bits. ledcWrite(0, 256);//Escrevemos um duty cycle de 25% no canal 0. ledcAttachPin(22, 1);//Atribuimos o pino 22 ao canal 1. ledcSetup(1, 1000, 10);//Atribuimos ao canal 1 a frequencia de 1000Hz com resolucao de 10bits. ledcWrite(1, 512);//Escrevemos um duty cycle de 50% no canal 1. ledcAttachPin(21, 2);//Atribuimos o pino 21 ao canal 2. ledcSetup(2, 1000, 10);//Atribuimos ao canal 2 a frequencia de 1000Hz com resolucao de 10bits. ledcWrite(2, 768);//Escrevemos um duty cycle de 75% no canal 2. ledcAttachPin(19, 3);//Atribuimos o pino 19 ao canal 3. ledcSetup(3, 1000, 10);//Atribuimos ao canal 3 a frequencia de 1000Hz com resolucao de 10bits. ledcWrite(3, 1023);//Escrevemos um duty cycle de 100% no canal 3. } void loop() { }
Testando este código e verificando o pino respectivo com um multímetro, podemos perceber que as contas são iguais ou próximas. Lembrando que o próprio multímetro tem sua faixa de precisão (erro), que neste caso é (+-0.5% + 3D com 1mV de resolução).
Todos os testes a seguir tem Vcc teórico de 3.3V, as imagens são as leituras do nosso multímetro.
Caso 1, 25% = 0.825V
Caso 2, 50% = 1.65V
Caso 3, 75% = 2.475V
Caso 4, 100% = 3.3V
Todos os valores lidos, mesmo estando próximos aos teóricos, há o erro do multímetro. Aplicando a formula de erro ao valor lido, todos os valores obtidos estão dentro da faixa tolerável de erro, ou seja, estão corretos!
Frequência X resolução
Um problema recorrente com alguns componentes é a frequência necessária de funcionamento. Motores por exemplo, é bastante usado entre 20kHz e 200kHz.
O recurso "LED PWM" do ESP32 é baseado em um clock de 80MHz, logo podemos fazer algumas contas básicas para se chegar a frequência máxima com a resolução escolhida.
Nos exemplos acima, foi usado uma frequência de 1kHz com 10bits de resolução, entretanto pode ser necessário o uso de uma frequência muito maior e a resolução é uma das barreiras para isso. Vamos fazer essa conta com os dados citados para chegar na frequência máxima (Fm).
A resolução deve ser em decimal e não "bits".
80MHz / 10bits
80000000 / 1024 = 78125Hz
A frequência máxima que conseguimos chegar com uma resolução de 10bits no ESP32 é de ~78kHz. Vamos testar!
Caso 1, 32kHz com 10bits
Caso 1.1, 80kHz com 10bits
Como feito nas contas, a frequência máxima realmente foi de ~78kHz para 10bits, mesmo atribuindo 80kHz no código. Agora vamos brincar com frequências mais altas deixando a resolução em 3bits e ver a frequência máxima.
80MHz / 3bits = Fm
80000000 / 8 = 10MHz
Caso 2, 2MHz com 3bits
Caso 2.1: 11MHz com 3bits
Novamente, as contas mostraram um máximo de 10MHz e mesmo atribuindo 11MHz, ficou limitado a 10MHz.
Considerações finais
O PWM é extremamente útil em diversos projetos, permitindo o controle de potência, velocidade, brilho e até inversores (DC-AC) através da modulação da tensão. Apesar de parecer simples apenas "inverter o estado do pino", com frequências um pouco mais altas, não é qualquer microcontrolador que aguenta se manter com uma frequência estável ou se quer chegar em frequências acima de 10MHz. O ESP32 com 1bit de resolução nos permite chegar a 40MHz, dando uma vasta gama de possibilidades em aplicações.
Arduino - Entradas e Saídas Analógicas - PWM
Arduino - Entradas e saídas analógicas
Com um pouco de atenção, podemos perceber que a todo momento estamos rodeados de situações nas quais existem elementos que podem ser definidos como grandezas analógicas, como por exemplo, posição e temperatura. Sabendo a importância deste tipo de grandeza, torna-se necessário que nós aprendamos a lidar com este tipo de informação dentro do cenário que estamos adentrando, sendo assim, neste tutorial abordaremos com maior enfoque, o modo utilizado por uma placa Arduino para lidar com o tipo de grandeza citada.
Para acompanhar este tutorial com maior compreensão, recomendamos que o leitor acompanhe nosso tutorial sobre grandezas digitais, analógicas e PWM.
[toc]
Pinos de entrada e "saída" analógica
Como dissemos no tutorial citado anteriormente, as grandezas analógicas são aquelas que, ao contrário das grandezas digitais, podem assumir infinitos valores de amplitude dentro de uma faixa de valores. Além disso, demos também como exemplo, o velocímetro de um carro, que por sua vez, pode ser considerado analógico, pois o ponteiro gira continuamente conforme o automóvel acelera ou freia. Se o ponteiro girasse em saltos, o velocímetro seria considerado digital.
Uma placa Arduino possui um conjunto de pinos destinados a lidar com este tipo de grandeza, onde, alguns são utilizados como entradas analógicas, isto é, possuem a função de receber dados provenientes de grandezas analógicas, enquanto outros, possuem a função de produzir informações que simulam o comportamento de grandezas analógicas, aqui estamos falando da utilização de uma técnica chamada PWM.
Em um Arduino UNO, as entradas analógicas estão localizadas do pino A0 até o pino A5. Por outro lado, os elementos que podem atuar fornecendo sinais que simulam o comportamento de uma grandeza analógica, são alguns dos pinos caracterizados como pinos de entrada/saída digital (de maneira específica, os pinos 3,5,6,9,10 e 11).
Mãos à obra - Variando a luminosidade de um led com um potenciômetro utilizando PWM
Neste tutorial iremos elaborar um projeto onde você poderá compreender tanto o processo de aquisição de dados a partir das portas de entrada analógicas quanto os procedimentos de utilização do PWM. O hardware consistirá em uma estrutura onde será possível variar a luminosidade de um led através de um potenciômetro..
Componentes utilizados
- 1 x Arduino UNO Rev 3
- 1 x Protoboard
- 1 x Resistor 330 Ω
- 1 x Potenciômetro linear 10kΩ
- 1 x Led verde difuso
Montagem do projeto
Veja como ficou o nosso:
Programando
Antes de adentrarmos na apresentação do código, disponibilizamos uma seção para ajudar aqueles que são iniciantes no assunto. Sinta-se livre para prosseguir caso você já tem domínio da IDE do Arduino.
Conectando o Arduino ao computador
Primeiramente, conecte seu Arduino ao computador e abra a IDE Arduino. Em seguida, é necessário selecionar a porta COM na qual o Arduino está conectado (este procedimento pode ser feito clicando no menu Ferramentas (tools) e em seguida escolhendo-se a porta correspondente no submenu Porta (port). Neste caso, a porta na qual está o Arduino é apresentada da seguinte maneira: COM3 (Arduino UNO).
Por fim, garanta também que o tipo de placa apropriado esteja selecionado (isso pode ser feito acessando o menu Ferramentas (tools) e o submenu Placa (board)).
– Código do projeto
Segue o código a ser utilizado no Arduino UNO para alterar a luminosidade do led através do potenciômetro.
unsigned int potenciometro unsigned int pwm void setup() { pinMode(10,OUTPUT); } void loop() { potenciometro = analogRead(A0); pwm = map(potenciometro,0,1023,0,255); analogWrite(10,pwm); }
Entendendo a fundo
Hardware
- Potenciômetro e trimpot
Potenciômetros e trimpots são resistores variáveis e ajustáveis, portanto, são bastante utilizados para realizar o controle analógico de algumas funcionalidades de aparelhos eletrônicos, como por exemplo, o volume de um aparelho de som.
Geralmente, estes dispositivos possuem três pernas, de modo que, duas destas são ligadas às extremidades de um material resistivo resistência (A e B), que por sua vez, são ligadas em dois potenciais distintos, enquanto a terceira, é conectada a um cursor que se movimenta ao longo do material citado. Este deslocamento faz com que seja possível obtermos diferentes níveis de tensão, obviamente, entre os valores de potenciais citados anteriormente.
- Divisor de tensão
O princípio de funcionamento descrito na seção anterior corresponde ao conceito de divisor de tensão. Imagine a seguinte configuração:
Sabemos que, quando temos duas resistências são associadas em série e o conjunto é sujeito a uma diferença de potencial, ambas serão percorridas pela mesma corrente. A equação que rege o comportamento do conjunto citado é dada por:
Se aplicarmos uma tensão de 5V nos terminais do conjunto, teremos:
Onde a corrente é o resultado da razão entre a tensão pela soma dos valores das resistências. Observe que, apesar de termos a mesma corrente passando pelos resistores, os mesmos estão sujeitos a tensões diferentes em seus respectivos terminais.
e
Pelos cálculos realizados acima, podemos perceber que a queda de tensão será maior no resistor de maior resistência.
Um circuito divisor de tensão é justamente aquele em que podemos extrair apenas uma fração da tensão aplicada nos terminais do mesmo. Observe como podemos calcular a tensão em um dos resistores de forma direta:
O exemplo a seguir mostra como funciona o cálculo o para dois resistores.
- Em resumo
Quando estamos utilizando um potenciômetro, estamos recorrendo ao conceito de divisor de tensão para obter diferentes valores de tensão em virtude da rotação do mesmo, de modo que, com a tensão total e a resistência total fixas, o divisor de tensão vai variar com a resistência entre A0 e GND (Considere no GIF que 0 a 100% é a posição inicial e final de rotação do potenciômetro. Teremos a tensão sobre o pino central variando conforme a posição angular do potenciômetro.)
Software
– Declarando as variáveis
O primeiro passo realizado neste código foi a declaração das variáveis que serão utilizadas ao longo do código do projeto. Observe que a declaração de uma variável é feita colocando-se o tipo da mesma (neste caso, as duas variáveis declaradas são do tipo unsigned int, pois, consistem apenas em números positivos) e em seguida, o seu nome (potenciometro e pwm).
A diferença entre os tipos int e unsigned int consiste no fato de que, no arduino UNO, uma variável do tipo int pode armazenar números que vão de -32.768 a 32.767, portanto, perceba que neste tipo de variável é possível que haja a ocorrência de números negativos em seu conteúdo. Em contrapartida, quando uma variável é do tipo unsigned int, ela pode armazenar números de 0 a 65.535, portanto, positivos.
unsigned int potenciometro unsigned int pwm
– Definindo as configurações iniciais
Em seguida, devemos determinar o modo de operação do pino utilizado para acionar o led, fazendo com que o mesmo se comporte como uma saída digital. Para isso, dentro da função setup() (lembre-se que esta função é executada apenas quando o Arduino UNO é ligado) utiliza-se a função pinMode(), onde os parâmetros passados para a mesma são: o número do pino a ser utilizado e o modo de operação do mesmo (neste caso, definimos o pino 10 como uma saída digital através da palavra OUTPUT).
void setup() { pinMode(10,OUTPUT); }
– Realizando a leitura de uma entrada analógica
Em primeiro lugar, como vimos no tutorial sobre grandezas digitais, analógicas e pwm, o Arduino UNO possui conversores A/D com resolução de 10 bits e que trabalham com intervalos de tensão de referência de 0 a 5V. Estes conversores são responsáveis por transformar o sinal de tensão aplicado nas suas entradas analógicas em informações digitais que possam ser interpretadas pelo Arduino UNO.
Basicamente, o que os conversores citados fazem é dividir o intervalo citado (0 a 5V) em 1024 (210, onde 10 é a resolução do conversor) pedaços, que por sua vez, estão distantes uns dos outros por 0,0048828 V (5/1024 V) e além disso, relacionar o sinal de tensão presente em uma determinada porta de entrada analógica com um destes pedaços.
Por exemplo: imagine que um potencial de 3,25V esteja presente em um pino de entrada analógica, neste caso, o valor retornado pela conversão será:
Como o resultado deve ser um número inteiro para que o conversor consiga representá-lo, o Arduino UNO escolhe o valor 666 (por ser o inteiro mais próximo) para representar o nível de tensão aplicado.
Sabendo disso, utilizamos a função analogRead() para que o Arduino UNO realize a leitura do valor entregue pelo potenciômetro à porta de entrada analógica A0, realize a conversão do mesmo e por fim, armazene ele na variável potenciometro . Esta função recebe apenas um parâmetro que consiste na porta de entrada analógica que está sendo utilizada na aquisição dos dados.
potenciometro = analogRead(A0);
– Convertendo intervalos de entrada em intervalos de saída
Para realizarmos a alteração na luminosidade do led, devemos relembrar o conceito de PWM. No nosso artigo sobre entradas digitais, analógicas e pwm explicamos que este recurso consiste na geração de uma onda quadrada, na qual, definimos a porcentagem do tempo em que a onda permanece em nível lógico alto (Duty cycle), provocando a mudança no valor médio da onda, que por sua vez, está relacionada com a potência entregue ao led e consequentemente com o brilho emitido pelo mesmo.
Além disso, mostramos também que, no código, o Duty Cycle corresponde a um número inteiro de 8 bits, variando, portanto, de 0 (0% de Duty cycle) a 255 (100% de Duty cycle).
De posse destas informações, observe que, de um lado, temos uma sinal analógico de 0 a 5 V que é entendido pelo Arduino UNO como um número inteiro que vai de 0 a 1023 e de outro temos um sinal PWM que deve ser aplicado a um dispositivo cujo valor do Duty cycle corresponde, no código, a um valor que varia de 0 e 255.
Neste momento, você deve ter percebido temos a necessidade de elaborar algo para que seja possível estabelecer uma correspondência entre os valores de entrada e os valores de saída citados, conforme a figura abaixo.
Este procedimento pode ser realizado através da função map(), confira:
A função map() permite o mapeamento de um intervalo numérico em outro intervalo numérico. Basicamente, o que a função map() faz é pegar um intervalo possua os extremos X1 e X2 e transformar-lo em um outro intervalo cujos valores extremos são Y1 e Y2.
A utilização da função map() requer o uso de 5 parâmetros, onde, o primeiro diz respeito à variável cujo intervalo queremos converter, o segundo e a terceiro correspondem aos extremos mínimo e máximo do intervalo original e os dois últimos estão relacionados com os extremos mínimo e máximo do intervalo novo. Na linha de código abaixo, a variável pwm (criada anteriormente) recebe o valor resultante da conversão da posição do potenciômetro no valor adequado para utilização do PWM, isto é, um valor entre 0 e 255.
pwm = map(potenciometro,0,1023,0,255);
– Acionando o led através de um sinal PWM
Em seguida recorremos à função analogWrite() para aplicar o sinal PWM na saída em que o led está conectado. Esta função possui dois parâmetros, onde, o primeiro corresponde ao pino utilizado e o segundo diz respeito ao número inteiro que representa o Duty cycle (lembre-se que este número está armazenado na variável pwm) do sinal PWM que será entregue pelo Arduino UNO.
analogWrite(10,pwm);
Por fim, devemos lembrar que todo conteúdo apresentado anteriormente faz parta da função loop(), pois, desta maneira, é possível realizar de maneira contínua e constante tanto a leitura do potenciômetro quanto o acionamento do led através da utilização do sinal PWM.
void loop() { potenciometro = analogRead(A0); pwm = map(potenciometro,0,1023,0,255); analogWrite(10,pwm); }
Considerações finais
Este conteúdo foi elaborado para que você possa compreender o básico para poder manipular as entradas analógicas bem como fazer a utilização do PWM para acionar uma infinidade de dispositivos. Esperamos que você tenha gostado deste tutorial e sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.