IoT

Máquina de Vendas Automática com RFID e NodeMCU

Eletrogate 18 de fevereiro de 2022

Introdução

Com a crescente popularização dos microcontroladores no meio maker, diversos projetos ganharam destaque e foram reproduzidos em larga escala. Um desses projetos é a maquina de vendas automática (vending machine).  Nesse post, você vai aprender e ter condições de reproduzir essa máquina fielmente ou com características próprias do seu projeto.

O objetivo desse projeto é desenvolver uma máquina de vendas automática a partir do zero.  Explicaremos passo a passo a construção da máquina, além de disponibilizar todos os arquivos necessários para reprodução da mesma.

O conhecimento disponibilizado nesse post vai te permitir chegar mais longe nos seus projetos e você poderá replicar a máquina de vendas automática como a do vídeo a seguir:


Materiais Necessários para o Projeto Máquina de Vendas Automática com RFID e NodeMCU

Nesse protótipo utilizaremos os seguintes materiais:


Resumo do Projeto

A construção da máquina não é nenhum bicho de 7 cabeças. Entretanto, ela possuí vários elementos com suas próprias peculiaridades. A seguir, iremos descrever, brevemente, os itens principais da parte elétrica e eletrônica e, posteriormente, detalharemos melhor estes itens.

  • Microcontrolador: Utilizamos o NodeMCU 8266, que nada mais é que um microcontrolador que dispões de conectividade WiFi. Sua programação é similar à do Arduino e foi desenvolvida em linguagem C++ na própria IDE do Arduino. Digamos que o microcontrolador é o cérebro da máquina que irá controlar o funcionamento dos periféricos.
  • Módulo RFID: Este leitor é responsável por fazer a leitura dos cartões e tags e envia a leitura feita ao Microcontrolador, que irá processar esses dados.
  • Display 16 x 2: O display é responsável por fazer a interface com o usuário. Através do display, o usuário poderá verificar estados da máquina.
  • Módulo I2C: Este módulo facilita muito a vida de quem necessita utilizar um display juntamente ao microcontrolador e dispõe de GPIO’S limitadas (como em nosso caso).
  • Microservos: Os microservos são responsáveis por movimentar a mola para que o item desejado percorra a prateleira e seja disponibilizado para o usuário.
  • Botões: Servem para que seja feita a escolha do item desejado. 
  • Chave fim de curso: Serve para dar fim ao processo quando o usuário acionar a portinhola, retirando o item.
  • Buzzer: Soa alarme para retirada do item.

Arquitetura do Protótipo

Podemos definir a arquitetura da máquina em três blocos: controle, interação e Acionador.

A partir daqui, decorreremos um pouco sobre a teoria desses blocos e os itens que os compõe. Caso queira ir direto para a parte da montagem, siga para o item Construção da máquina.

Painel Frontal – Divisão em blocos

1. Bloco de Controle

O bloco de controle é um sistema utilizado para conter e receber informações sobre a execução de uma diversidade de tarefas simples a complexas do processo, sendo o bloco responsável por gerar todos os sinais que controlam as operações no interior da máquina. Este bloco se compõe de dois componentes, que serão apresentados a seguir.

O primeiro componente é o ESP 8266, um microcontrolador fabricado pela companhia Espressif Systems. Este microcontrolador detém um sistema de comunicação WiFi particular, sendo isso seu grande diferencial. Por isso, ele é grandemente utilizado como módulo WiFi para demais microcontroladores, como o Arduino, por exemplo, apesar de ter um processador próprio, e de ser praticável usar somente o ESP 8266 para produzir sistemas embarcados. Determinados trabalhos já foram realizados tendo como objetivo a utilização desse microcontrolador com variadas linguagens de programação e objetivos. Um benefício do ESP 8266 é seu baixo custo, habitualmente na faixa de 20 a 50 reais (OLIVEIRA, 2017).

O ESP 8266 está no mercado desde 2014. A principal propagação do mesmo é o livro que apresenta as maneiras de programar o ESP 8266 e quais suas usabilidades, bem como a eletrônica fundamental para concluir os projetos mostrados. Existem diferentes tipos de modelos do ESP 8266, como o ESP-1, ESP-12 e Esp Olimex, por exemplo. De maneira que o processador é o mesmo para todos modelos de ESP 8266, diferenciando exclusivamente o número de pinos de entrada e saída (GPIO) livres, memória disponível e o distanciamento entre pinos. A tabela 1 apresenta as especificações técnicas do ESP 8266:

Tabela 1: Especificações do ESP 8266.

Tensão 3,3 V
Consumo de corrente 10 µA
Memória flash 16MB máximo (512k normal)
Processador Tensilica L106 32 bits
Velocidade do processador 80-160MHz
RAM 32K + 80K
GPIOs 17(multiplexada com outras funções)
Analógica para digital 1 entrada com 1024 de resolução
Suporte 802.11 b/g/n/d/e/i/k/r
Máximo corrente conexão TCP 5

Fonte: Elaborado a partir de (OLIVEIRA, 2017).

O segundo componente é o módulo RFID, uma tecnologia que usufrui da rádio frequência para a transmissão de dados. Esta tecnologia é formada sucintamente por dois componentes, sendo eles: as etiquetas, também chamadas de tags ou transponders e o sistema/equipamento de leitura, que é formado pelo leitor e a antena. As tags têm a função de armazenar e transmitir os dados para o equipamento de leitura, que, por seu lado, tem a função de ser uma fonte de energia para as tags, caso seja necessário, para que ela possa concluir a transmissão dos dados. Posteriormente dos dados serem capturados pelo equipamento de leitura, eles são enviados, normalmente, para um computador que detém de um sistema que consiga tratar esses dados (BHUPTANI; MORADPOUR, 2005 e GLOVER, 2007).

As tags podem ter três tipos: tags passivas, ativas e semi-passivas/semi-ativas. As tags ativas dispõem de uma bateria interna, o que aceita elas enviarem os dados incessantemente e serem lidas a maiores distâncias comparado com os outros tipos de tags, não precisando ser energizada pelo equipamento de leitura para conseguir enviar seus dados. As tags passivas não dispõem de uma bateria interna e, por isso, necessitam da energia enviada pelo equipamento de leitura para se ativarem e enviarem seus dados. Essa é uma das razões pelas quais sua distância de leitura é menor quando comparada à das tags ativas. Outra grande discrepância entre esses dois tipos de tags é a durabilidade de sua vida útil, as tags ativas, por terem uma bateria interna, têm sua vida útil reduzida, de cerca de cinco anos, dependendo do local onde ela é usada. Por exemplo, locais com enormes alterações de temperatura podem modificar seu tempo de vida útil. Já as tags passivas, ponderando que não estão sujeitas a danos provocados por agentes externos, como por exemplo, batidas e contatos com água, sua vida útil seria incerta. As tags semi-passivas e semi-ativas têm a capacidade de fornecer energia para o seu circuito integrado (CI). Entretanto, não tem energia suficiente para enviar os seus dados, dependendo assim, do envio da fonte de energia do equipamento de leitura. A circunstância destas tags energizarem seus CIs, agiliza o processo de envio dos dados em comparação com as tags passivas (GLOVER, 2007 e DRESCH JUNIOR, 2007).

Geralmente, a maioria das tags já vêm do fabricante com um código único impresso nelas, para que seja possível realizar a identificação de forma particular de cada item. Também, existem tags que aceitam a impressão de dados, operando, entã,o como um banco de dados móvel, sendo possível a impressão de dados exclusivos de cada produto na própria tag, proporcionando assim, a identificação do produto (FAHL, 2005).

O leitor RFID tem por função a comunicação com as tags através de uma antena. Um leitor, normalmente, possui uma única antena, entretanto, existem leitores que dispõem de mais de uma. Suas principais tarefas são energizar a tag, quando ela for passiva ou semi-passiva, para que seja possível enviar seus dados, retransmiti-lo para um computador, e dependendo do leitor, conseguir também imprimir dados nas tags, se elas permitirem (BHUPTANI; MORADPOUR, 2005).

Como é o leitor RFID que energiza as tags, é considerável apresentar a frequência em que ele opera. A frequência define a taxa de transferência dos dados entre a tag e o leitor RFID, quanto maior a frequência, mais veloz a taxa de transmissão (BHUPTANI; MORADPOUR, 2005). As faixas de frequência mais usadas pela tecnologia RFID são Low Frequency (LF), High Frequency (HF) e Ultra High Frequency (UHF) (COUTO, 2003).

A seguir a divisão das faixas de frequência pode ser observada na tabela 1.

Frequências LF HF VHF UHF SHF EHF
Faixas de frequência 30KHz até 300KHz 3MHz até 30MHz 30MHz até 300MHz 300MHz até 30GHz 3GHz até 30GHz 30GHz até 300 Ghz

Tabela 1: Faixas de frequência.

Fonte: Elaborado a partir de (SYBASE, 2006).

A comunicação entre os leitores RFID e as tags é feita pelas antenas presentes nos dois componentes. Dois dos fatores que indicam a distância e a área de cobertura das antenas usadas são a potência e o tipo de propagação do sinal emitido pela antena. Quanto maior a potência, maior é a distância e a área de cobertura. Os tipos de propagação mais usados pela tecnologia RFID são circular e linear. A circular faz uma leitura do local mais ampla, criando um campo circular ao seu redor. Já na linear, a leitura é situada apenas em uma direção (BHUPTANI; MORADPOUR, 2005).

2. Bloco de interação

O bloco de interação com o usuário é um recurso que atua como mediador da interação entre o usuário e um sistema de automação. Ou seja, como dispositivos e máquinas ainda não dispõem de consciência, esses equipamentos necessitam de alguma interação externa para monitora-los ou para conferir o correto cumprimento das suas funções.

Os Módulos de display LCD de caracteres alfanuméricos são áreas de interações de comunicação visual muito convenientes. Eles podem ser localizados em quase todos aparelhos eletrodomésticos, eletroeletrônicos, automóveis, instrumentos de medição e entre outros. São equipamentos que têm interfaces elétricas padronizadas e recursos internos gráficos e de software que aceitam tranquilamente a modificação por outros controladores de outros fabricantes, sem que seja preciso modificar o programa de aplicação. Por ser elevadamente padronizado, seu custo é baixo. É um recurso envelhecido, deve ter uns vinte anos de idade ou mais, mas continua atual, com suas variadas formas, cores, tamanhos e preços. A tecnologia principal continua sendo o LCD (Liquid Crystal Display), entretanto, já se pode achar alguns embasado em LEDs orgânicos (PUHLMANN, 2015).

Os módulos LCD são especificados especialmente por sua capacidade gráfica de comunicação, ou melhor dizendo, o número de caracteres por linha e o número de linhas. Alguns valores característicos para essas especificações são:

Número de caracteres: 8, 12, 16, 20, 24 e 40.

Número de linhas: 1, 2 e 4.

Outras especificações essenciais que devemos examinar são as dimensões físicas do módulo, a tensão de alimentação, a disposição física dos pontos de conexão externa, a localização desses pontos de conexão em relação ao display, dos lados direito ou esquerdo, em cima ou abaixo, o tipo de interface eletrônica, paralela (principal) ou serial, backlight (luz de fundo) e, finalmente, o controlador do display.

INTERFACE DE CONEXÃO EXTERNA

A interface de conexão com um microcontrolador também é padronizada. Ela pode ter de 14 a 16 pinos, podendo variar se o módulo possui ou não backlight para aceitar a leitura do display em ambientes com baixa luminosidade. Na figura 6 pode-se observar a função de cada pino.

Fonte: PUHLMANN, 2015

3. Bloco acionador

Este bloco é composto pelos dispositivos que exigem dados e informações processadas pelo bloco controlador, também chamados de unidades de saída.

O servo motor é um circuito fechado, um servo mecanismo que usa realimentação de posição final, aceitando o controle exato da posição angular medida, bem como a velocidade do eixo de saída pela transmissão de um sinal na entrada. Utilizados em sistemas de controle que precisa de elevada precisão, tais como robótica e CNC (MEDEIROS, 2011).

Os benefícios de se utilizar servo-acionamentos se dão por conta da sua alto dinâmica de torque, alta dinâmica de velocidade, alta capacidade de sobrecarga mecânica, projeto compacto (alta relação de potência/volume), elevada precisão no posicionamento, baixa manutenção e relação de custo/desempenho admissível (TOMASCHITZ, 2013).

Existe um grupo para cada tipo de servos motores:

  • Servos motores CC (Corrente continua).
  • Servos motores CA (Corrente alternada).

Os servos motores de CC são, resumidamente, motores de corrente continua, sendo o estator feito de imãs permanentes e seu rotor bobinado. Dispõe sua posição controlada por meio de um modulador de largura de pulso (PWM). Além disso, podem ser utilizados para conceder uma ação corretiva no controle de sistemas remotos de posicionamento ou em dispositivos de velocidade controlada.

Em seu estrutural, localiza-se um taco gerador, sendo um pequeno gerador elétrico de corrente continua, com campo provido por imã. A diferença de potencial criada é proporcional à velocidade com que o fluxo magnético é cortado pelo enrolamento do rotor. Desta forma, o taco gerador é um transdutor mecânico elétrico linear. Também possui um encoder que, resumidamente, é um equipamento que contém um disco perfurado e um sistema de componentes opto – eletrônicos (TOMASCHITZ, 2013).

Servos motores de corrente alternada, também chamado de servo motor CC sem escovas (servo motor brushless), são motores CA, tendo seu estator bobinado e o rotor de ferro sólido, obtendo certo número de pares de imãs permanentes. Uma das suas fases é alimentada com tensão alternada de frequência e amplitude continua e a outra fase recepciona uma tensão de igual frequência, mas defasada em 90° em fase e com amplitude flexível. Existem dois tipos de servos motores de corrente alternada, o assíncrono e o síncrono.


Funcionamento da Máquina

O funcionamento da máquina pode ser dividido em 5 passos.

1° Passo

O usuário se dirige à máquina e faz a apresentação do cartão ou tag. A máquina, então, faz uma verificação se o cartão é habilitado ou não para seguir com o processo.

2° Passo

Caso o cartão seja habilitado para continuar o processo, o bloco de interação com o usuário apresenta o saldo disponível no cartão e, logo após, a interface mostrar as opções de alimentos disponíveis na máquina. Caso não seja cadastrado, aparece uma mensagem de saldo insuficiente.

3° Passo

Após a apresentação das opções disponíveis, o usuário faz a escolha do item desejado através dos botões. Com isso, o bloco de interação com o usuário apresenta o item selecionado, seu custo e, logo após, exibe a quantidade de créditos restantes no cartão.

4° Passo

Seguindo, é realizado a ativação do atuador do item selecionado para que o item se movimente e fique disponível para retirada do usuário.

5° Passo

Disponível o item, o bloco de interação com o usuário apresenta a mensagem “retire o item” e um efeito sonoro, para ficar mais claro. A máquina é mantida neste estado até que seja retirado o item de seu interior.

A seguir, o Fluxograma da máquina:

Autores, 2021

 

Funcionamento da máquina

Caso o saldo seja menor que o custo do item desejado, aparece a mensagem de credito insuficiente.

 

Caso o item desejado tenha acabado, aparece a mensagem de item insuficiente.

 

Ao iniciar, a máquina fica em loop tentando se conectar à rede Wi-Fi programada até que consiga ou seja apertado o botão 1

 

Se o cartão (ou tag) lida não tiver cadastro, aparece a mensagem de cartão não cadastrado.


Construção da Máquina

Agora que você já sabe os principais itens da máquina, vamos colocar a mão na massa.

PROCESSO DE FABRICAÇÃO

Os componentes estruturais do projeto são confeccionados no método de fabricação com corte a laser, pois é um processo avançado para cortes térmicos, que possibilita maior economia, precisão, qualidade superior, pouca perda de material, corte de figuras complexas, sem desgaste da ferramenta, programação flexível e agilidade na produção. Ainda entre as vantagens, está a variedade dos materiais que podem ser cortados, desde madeira, MDF, alumínio, borrachas, papel, vidros, tecidos, EVA, acrílico, plástico ABS, bambu, isopor, couro, cortiça, fórmica, metais e entre outros.

Neste projeto em específico foi selecionada a matéria prima em MDF, para ter uma redução dos custos e também por ser um material com boa estética, que atenderá satisfatoriamente as necessidades do projeto.

O desenho da estrutura da máquina foi desenvolvido no software Inventor e os arquivos estão disponibilizados no Github. Com os arquivos em mão, é só procurar uma empresa que forneça o serviço de corte de MDF a laser.

MDF cortado a laser

Montagem da estrutura

Nesta etapa é realizada uma fixação permanente, também através do método da cola de artesanato. As chapas internas horizontais têm por função o armazenamento dos alimentos a serem colocados na máquina, já as chapas internas perpendiculares às chapas horizontais têm por função a fixação dos servos motores que farão a movimentação das molas que estarão acopladas ao seu eixo. Por fim, teremos as chapas internas que têm por objetivo criar divisórias entre os alimentos, com isso, dando maior estética e organização nas áreas internas da máquina.

CIRCUITO ELETRÔNICO

Nesta etapa da montagem é feito o desenvolvimento do circuito do projeto.

1° Passo

Com base no microcontrolador e o respectivo número de GPIO’s, foi desenvolvido o circuito buscando otimizar seu uso. Cada GPIO dele possuí funções específicas e, por isso, é importante utilizar os periféricos nas portas específicas.

A seguir, temos o diagrama do circuito representado pelo desenho.

Na prática, a fonte de alimentação que utilizaremos no projeto final virá de uma fonte ATX, mas foi representada por pilhas no desenho.

 

Desenho da ligação eletrônica

A tabela a seguir dispõe dos pinos do nodeMCU, sua nomenclatura, função específica e a aplicação no circuito, para facilitar na hora de montar o circuito.

Tabela PINOUT nodeMCU esp8266

2° Passo

Para facilitar a montagem e testar o funcionamento dos periféricos junto ao microcontrolador, foi desenvolvido a montagem do circuito na protoboard, conforme o esquema a seguir.

A sugestão que deixamos é de que você comece pelo microcontrolador e, com base nele, faça as ligações nos demais componentes eletrônicos.

Ligação na Protoboard

A montagem na protoboard é simples, apesar de parecer complicada. Você pode realizar a montagem se baseando no desenho do projeto ou seguindo o passo a passo a seguir. Iremos detalhar item a item para facilitar a compreensão:

  • FONTE:  Na protoboard, o uso da fonte ajustável é uma ótima saída, pois possibilita uma ótima fixação e deixa o projeto mais limpo. Nessa etapa, não utilizaremos os microservos, fazendo com que não seja necessária uma corrente mais elevada na fonte.

Aqui, estamos trabalhando com duas fontes (3v3 e 5V)

A 3v3 (lado esquerdo) deve ligar o pino 3v3 do RFID RC522 e alimentar o positivo dos 4 servos.

O 5V (lado direito) está energizando os barramentos da protoboard. Ele energiza:

ânodo (+) dos led’s dos botões

positivo do buzzer

pino VIN do ESP 8266

pino VCC do modulo I2C 

DISPLAY LCD:   É ligado ao módulo i2c

  • MÓDULO I2C:

SCL: D1 ESP

SDA : D2 ESP

VCC: 5VCC FONTE

GND: GND COMUM 

  • RFID RC522: É alimentado com 3v3 e segue a ligação da tabela do ESP

SDA : D3 ESP

SCK: D5 ESP

MOSI: D7 ESP

MISO: D6 ESP

IRQ:       –

GND: GND ESP

RST: D0 ESP

3V3: 3V3 FONTE

  • BOTÕES:  Todos os botões e o micro estão ligados a entrada A0 do ESP.

Obs.: A ligação utilizada dos botões é de contato aberto. Ligação do resistor do VCC no pino inferior esquerdo. Ligação dos jumpers e saída para A0 no superior direito.

O fio branco que vem do ESP é comum a todos os botões e ao microservo (microservo simulado pelo último botão (branco)).  Eles são interligados pelos jumpers laranjas e têm um resistor de pulldown (ligado ao GND) para garantir o sinal LOW na entrada do ESP quando nenhum botão for acionado (resistor de 10K).

Do outro lado dos botões, há vários resistores de diversos valores e esses resistores são ligados ao 3v3 que vem do ESP. Ou seja, de um lado, os botões estão ligados à porta A0 com um resistor de pulldown e o outro lado dos botões está recebendo 3v3, que será enviado à entrada quando acionado o botão.

BOTÃO 1: 560 Ω

BOTÃO 2: 1K1 Ω

BOTÃO 3: 2K2 Ω

BOTÃO 4: 4K7 Ω

MICRO   : 10K Ω

MICRO: (Na foto está sem, mas é simulado pelo botão branco). Segue a mesma ligação dos botões. De um lado, recebe 3v3, que passa pelo resistor de 10K e, do outr,o é interligado com os outros botões, passa pelo resistor de pulldown e vai para o fio branco que vai para A0 ESP.

  • TRANSISTOR LED’s BOTÕES:  Utilizaremos o transistor como drive para chavear o GND e para proteger a IO do ESP, tanto para os LED’s quanto para o BUZZER. TRANSISTOR TIP 122 NPN.

BASE PIN 1: Vem um fio do SD3 ESP, passa por um resistor para limitar a corrente da base 22K Ω e vai para base.

COLETOR PIN2: Na protoboard, está ligado ao resistor do catodo do LED. Mas, na prática, ele alimentará os 4 resistores dos 4 leds dos botões, enviando assim o GND ao catodo dos LEDS quando for polarizado o transistor. Nos LEDS, serão utilizado 4 resistores de 180 Ω para limitar a corrente em seus catodos.

EMISSOR PIN 3: Ligado ao GND comum que vem da fonte.

  • TRANSISTOR BUZZER:

BASE PIN 1: Vem um fio do SD2 ESP, passa por um resistor para limitar acorrente da base 22K Ω e vai para base.

COLETOR PIN2: Ligado ao negativo do Buzzer

EMISSOR PIN 3: Ligado ao GND comum que vem da fonte

O positivo do buzzer é ligado direto no +5VCC que vem da fonte

  • SERVOS: Positivos (fio vermelho) ligados ao 3v3 da fonte e negativos (fio marrom) no GND da fonte. Sinais (fio laranja) ligados ao respectivo IO do ESP conforme tabela do pinout do ESP.

Após realizar a montagem na protoboard, é necessário carregar o código do programa e testar o funcionamento de todos os periféricos e do microcontrolador. Tendo sucesso no funcionamento, podemos passar para o próximo passo.

3° Passo

Depois de tudo testado, vamos passar nosso projeto para uma placa universal. Você pode desenvolver o layout da placa de forma mais profissional em softwares como kicad e Protheus e até mesmo mandar produzir sua placa em empresas do ramo.

Para facilitar nosso trabalho, utilizamos a placa universal perfurada que facilita a montagem direta dos componentes interligando-os por meio de trilhas com solda ou fios. Esteticamente, o resultado é muito inferior às placas feitas de forma artesanal ou profissional, entretanto, é mais simples e de fácil construção.

Na montagem da placa universal não tem muito segredo. A dica é colocar o microcontrolador no ponto desejado, os demais componentes em volta dele e fazer as ligações seguindo a tabela e o desenho apresentados até aqui.

Na construção da nossa placa, decidimos organizar o layout de forma que os demais componentes ficassem na face superior da placa e o leitor RFID ficasse na face de baixo, permitindo assim que a placa fosse fixada no local de leitura dos cartões na parte frontal da máquina, conforme imagens a seguir:

Superior placa

Inferior placa

Para não soldarmos os demais fios de máquina direto na placa, utilizamos bornes na placa para facilitar a ligação.

4° Passo

Para finalizar, é realizada montagem e fixação do circuito no estrutural da máquina.

Componentes na frontal da máquina

5° Passo

Por fim, foi desenvolvido a fixação da fonte de energia do circuito eletrônico, que é uma fonte ATX retirada de um gabinete de computador. Esse tipo de fonte será de grande ajuda no projeto, pois ela dispõe de vários níveis de tensões, se tornando muito versátil. Para facilitar na hora de montar, utilizamos o Módulo Adaptador XH-M299 para interligar nossa fonte ATX ao projeto.

Fonte ATX

DOBRADIÇAS E FIM DE CURSO

Seguindo, foi realizado a fixação por parafusos das dobradiças na portinhola da máquina e, em conjunto, foi feito a fixação do fim de curso, de modo que, quando a portinhola seja aberta, acione o fim de curso.

Portinhola e fim de curso

ACRÍLICO

A seguir, foi efetuada a fixação do acrílico através da cola de artesanato, para que a máquina tenha exatamente a mesma estética de uma máquina de vendas automática.

Acrílico

MOLAS

A construção das molas foi feita de forma artesanal, utilizando um pedaço de cano e pedaços de arame. Para produzir as molas é necessário envolver o cano com o arame de forma que o arame vá se moldando no formato helicoidal.

 

Prosseguindo, foi desenvolvido a fixação das quatro molas nos eixos dos servos motores. A fixação da mola foi feita através de uma tampa de tubo de pvc, cortada e usada como suporte para fixação das molas.

Após a fixação das tampas de tubo pvc utilizadas como suporte para as molas, foi efetuado a fixação do suporte junto a mola nos eixos dos servos motores através de cola quente.

LEDS DE ILUMINAÇÃO INTERNA

Nesta etapa da montagem é efetuada a instalação de quatro leds de alta potência no interior da máquina para ter uma maior luminosidade e visibilidade dos produtos que estão em exposição.

Leds internos

CHAPA FRONTAL

Para finalizar a montagem, foi realizada a fixação da chapa frontal da máquina, compactando todos os dispositivos listados em seu interior.

Chapa frontal


Código

/* ============================================================================
        SENAI "Antônio Ermírio de Morais"
        TCC Curso Técnico 4 Termo
        Tema: Vending machine
        Versão 1.0
        Data: 10/2021   
  
      Autor: Luiz Ortega
      email: Luiz.n.a@hotmail.com
  Instagram: @microcontrolando
============================================================================ */

/* ========================================================================= */
/* --- Bibliotecas  --- */

#include <Wire.h>                                               /*Comunicação I2C*/
#include <LiquidCrystal_I2C.h>                                  /*Comunicação do display através da comunicação I2C*/
#include <SPI.h>                                                /*Comunicação do RFID pelo protocolo SPI*/
#include <MFRC522.h>                                            /*Biblioteca que atua na biblioteca SPI*/
#include <Servo.h>                                              /*Biblioteca dos Servos*/
#include "ThingSpeak.h"                                         /*Comunicação com o THINGSPEAK*/
#include <ESP8266WiFi.h>                                        /*Conectividade WIFI*/

/* --- Parâmetros  --- */

#define SS_PIN  D3                                              /*Pino SDA RFID{houve alteração do pin D8 pelo D3*/
#define RST_PIN D0                                              /*Pino RST RFID*/
const char* ssid = "ortega";                                    /*Passa nome da rede*/
const char* password = "05/11/94";                              /*Passa senha da rede*/

  MFRC522::MIFARE_Key key;                                      /*Objeto "chave" utilizado para autentificação*/      
  LiquidCrystal_I2C lcd(0x27,16,2);                             /*Passa parametros do display (endereço, número de colunas e linhas (16x2))*/
  MFRC522 rfid(SS_PIN, RST_PIN);                                /*Passa parametros para função*/
  Servo servo_1;                                                /*Instancia Servo_1*/
  Servo servo_2;                                                /*Instancia Servo_2*/
  Servo servo_3;                                                /*Instancia Servo_3*/
  Servo servo_4;                                                /*Instancia Servo_4*/
/* ========================================================================= */

/* ========================================================================= */
/* --- Macros --- */
#define delay_Servo      5000                                   /*Tempo Servo on*/
#define pisca            500                                    /*Valor do delay do pisca backlight LCD no setup*/
#define led_pin          10                                     /*Pino do LED*/
#define bip              9                                      /*Pino do bip*/
#define timeOnBip        400                                    /*Time On Buzzer*/
#define timeOffBip       2100                                   /*Time Off Buzzer*/
#define postandoInterval 30000                                  /*Intervalo para realizar leitura e escrita no THINGSPEAK*/
#define valor_item1      1                                      /*Custo do item 1*/
#define valor_item2      2                                      /*Custo do item 2*/                      
#define valor_item3      3                                      /*Custo do item 3*/
#define valor_item4      4                                      /*Custo do item 4*/


/* ========================================================================= */
/* --- Variáveis Globais --- */
int     saldo  =  0,                                            /*Variável que recebe o saldo das TAG's*/
        card_1 = 100,                                           /*Saldo Card 1*/
        card_2 = 10,                                            /*Saldo Card 2*/  
item_escolhido =  0;                                            /*Variável que recebe Qual item foi escolhido*/ 
       
bool    acesso =  0,                                            /*Variável de controle de acesso*/
     _continue =  1;                                            /*Variável de controle que limita o funcionamento em caso de falta de saldo*/
                                                 
byte    item_1 =  1,                                            /*Variável que guarda o valor do item 1*/
        item_2 =  2,                                            /*Variável que guarda o valor do item 2*/
        item_3 =  3,                                            /*Variável que guarda o valor do item 3*/
        item_4 =  4;                                            /*Variável que guarda o valor do item 4*/

float   und_item_1 = valor_item1,                               /*Váriavel para controle da quantidade to item 1*/
        und_item_2 = valor_item2,                               /*Váriavel para controle da quantidade to item 2*/
        und_item_3 = valor_item3,                               /*Váriavel para controle da quantidade to item 3*/
        und_item_4 = valor_item4;                               /*Váriavel para controle da quantidade to item 4*/
      
unsigned long tempoAnterior =  0;                               /*Variável que armazena o tempo Anterior para soar o buzzer no processo (Retire o item)*/                
unsigned long channel = 1446032;                                /*Número de canal do THINGSPEAK*/

String      apiKey = "POU7C1109BWPQGE2";                        /*API Write do THINGSPEAK*/
const char* server = "api.thingspeak.com";                      /*Endereço server*/              
int         estado_1;                                           /*Variável que recebe resultado da leitura do field 5*/                                    
WiFiClient  client;                                             /*chama função WiFiclient*/
unsigned long lastConnectionTime = 0;                           /*Tempo da última conexão*/
unsigned long lastUpdateTime = 0;                               /*Tempo do último update*/

/* ========================================================================= */
/* --- Protótipo das funções --- */

    void leitura_RFID     ( );                                  /*Função responsável por ler as TAG's*/
    void imprime_LCD      ( );                                  /*Função responsável por Imprimir no LCD*/ 
    void le_botao         ( );                                  /*Função responsável por ler os botões*/ 
    void item_selecionado ( );                                  /*Função responsável por ligar o motor selecionado,ler o micro e finalizar processo*/
    void liga_servo       ( );                                  /*Função responsável por ligar os servos*/
    void alarme           ( );                                  /*Função responsável soar bip*/  
    void app              ( );                                  /*Função que recebe e envia dados para o o THINGSPEAK*/
    
/* ========================================================================= */
/* --- Função Principal --- */

    void setup( ){                                              /*Inicio da Função Setup*/
      
  pinMode(A0, INPUT);                                           /*Declara A0 como Entrada*/
  pinMode(bip, OUTPUT);                                         /*Declara bip como saída*/ 
  digitalWrite(bip, 0);                                         /*Bip nível baixo*/
  pinMode(led_pin, OUTPUT);                                     /*Declara led_pin como Saída*/
  digitalWrite(led_pin, 0);                                     /*led_pin nível baixo*/
  /*Serial.begin(115200);                                       -->Inicia Monitor Serial (utilizado para testes)*/
  lcd.init( );                                                  /*Inicia LCD*/
  lcd.backlight( );                                             /*Inicia Backlight*/
  SPI.begin( );                                                 /*Inicia SPI*/
  rfid.PCD_Init( );                                             /*Inicia RFID*/
  lcd.clear( );                                                 /*Limpa LCD*/
  lcd.setCursor(0,0);                                           /*Posiciona Cursor*/
  lcd.print("*****Maquina****");                                /*Exibe mensagem no LCD*/
  lcd.setCursor(0,1);                                           /*Posiciona Cursor*/
  lcd.print("****Solidaria***");                                /*Exibe mensagem no LCD*/
  delay(pisca);                                                 /*Delay de pisca*/
  lcd.setBacklight(LOW);                                        /*Backlight OFF*/
  delay(pisca);                                                 /*Delay de pisca*/
  lcd.setBacklight(HIGH);                                       /*Backlight ON*/
  delay(pisca);                                                 /*Delay de pisca*/              
  lcd.setBacklight(LOW);                                        /*Backlight OFF*/
  delay(pisca);                                                 /*Delay de pisca*/
  lcd.setBacklight(HIGH);                                       /*Backlight ON*/
  delay(pisca);                                                 /*Delay de pisca*/
  lcd.clear();                                                  /*Limpa LCD*/  
  /*Serial.println();                                           -->Pula linha*/
  /*Serial.println("Maquina Solidaria:");                       -->Exibe mensagem no Monitor Serial*/
  /*Serial.println("Aproxime seu cartao");                      -->Exibe mensagem no Monitor Serial*/
  servo_1.attach ( 2);                                          /*Instancia objeto Servo_1 pin  2*/
  servo_2.attach (15);                                          /*Instancia objeto Servo_2 pin 15*/
  servo_3.attach ( 3);                                          /*Instancia objeto Servo_3 pin  3*/
  servo_4.attach ( 1);                                          /*Instancia objeto Servo_4 pin  1*/
  delay(1000);                                                  /*Delay*/

  WiFi.begin(ssid, password);                                   /*Inicia WIFI(passa parametros)*/
  lcd.clear( );                                                 /*Limpa LCD*/
  lcd.setCursor(0,0);                                           /*Posiciona Cursor*/
  lcd.print("Conectando WiFi");                                 /*Exibe mensagem no LCD*/
  lcd.setCursor(0,1);                                           /*Posiciona Cursor*/
  
while(WiFi.status( ) != WL_CONNECTED && analogRead(A0) < 1000){ /*loop que espera conectar na rede*/  
        lcd.print(".");                                         /*Exibe mensagem no LCD*/
        delay(500);                                             /*delay*/
}/*end while*/

    lcd.clear( );                                               /*Limpa LCD*/  
    if(WiFi.status( ) == WL_CONNECTED)                          /*Testa se houve conexão*/
    {
      lcd.setCursor(1,0);                                       /*Posiciona Cursor*/
      lcd.print("WiFi CONECTADO ");                             /*Exibe mensagem no LCD*/
    }/*end if*/
    else                                                        /*Se não houve conexão*/
    {
      lcd.setCursor(1,0);                                       /*Posiciona Cursor*/
      lcd.print("NAO CONECTADO");                               /*Exibe mensagem no LCD*/
    }/*end else*/
  delay(5000);                                                  /*delay*/
  lcd.clear( );                                                 /*limpa LCD*/
  ThingSpeak.begin(client);                                     /*Inicia client ThingSpeak*/
  
    }/*end setup*/

/* ========================================================================= */

    void loop( ){                                               /*Início da Função loop*/
       
    if (_continue==1)                                           /*Se _continue verdadeiro chama funções dentro do if*/
    {       
      app         ( );                                          /*Função que recebe e envia dados para o o THINGSPEAK*/
      imprime_LCD ( );                                          /*Função responsável por Imprimir no LCD*/
      leitura_RFID( );                                          /*Função responsável por ler as TAG's*/

    }/*end if continue*/
      else
      {                                                         /*Se _continue falso Reseta variáveis, limpa LCD e reinicia loop*/
        item_escolhido = 0;                                     /*Zera item_escolhido*/
        acesso = 0;                                             /*Zera acesso*/
        saldo  = 0;                                             /*Zera saldo*/
        lcd.clear( );                                           /*Limpa LCD*/ 
        _continue=1;                                            /*Continue passa a ser verdadeiro e reinicia loop*/                                              
      }/*end else*/
    }/*end void loop*/

/* ========================================================================= */
/* --- Desenvolvimento das funções --- */
/*---------------------------------------------------------------------------*/
    void app ( )
    {
      
      if (millis ( ) - lastUpdateTime >= postandoInterval)      /*Testa se a diferença do tempo atual com o ultimo update é maior igual do que o tempo de intervalo*/
      {     
        lastUpdateTime = millis ( );                            /*atualiza último update*/
        estado_1 = ThingSpeak.readFloatField(channel, 5);       /*faz leitura do campo 5 e guarda em estado_1*/
          if(estado_1)                                          /*Se verdadeiro estado_1*/
          {
            lcd.clear( );                                       /*limpa LCD*/
            lcd.setCursor(5,0);                                 /*Posiciona cursor*/  
            lcd.print("Maquina");                               /*Imprime no LCD*/
            lcd.setCursor(4,1);                                 /*Posiciona cursor*/  
            lcd.print("Completa");                              /*Imprime no LCD*/
            delay(pisca);                                       /*Delay de pisca*/
            lcd.setBacklight(LOW);                              /*Backlight OFF*/
            delay(pisca);                                       /*Delay de pisca*/
            lcd.setBacklight(HIGH);                             /*Backlight ON*/
            delay(pisca);                                       /*Delay de pisca*/              
            lcd.setBacklight(LOW);                              /*Backlight OFF*/
            delay(pisca);                                       /*Delay de pisca*/
            lcd.setBacklight(HIGH);                             /*Backlight ON*/
            delay(pisca);                                       /*Delay de pisca*/
            und_item_1 = valor_item1;                           /*Reseta quantidade do und_item_1*/
            und_item_2 = valor_item2;                           /*Reseta quantidade do und_item_2*/
            und_item_3 = valor_item3;                           /*Reseta quantidade do und_item_3*/
            und_item_4 = valor_item4;                           /*Reseta quantidade do und_item_4*/
            delay(60000);                                       /*delay de 1 minuto*/
            lcd.clear( );                                       /*limpa LCD*/
          }       
 
          if (client.connect(server,80)) {                      /*Inicia um client TCP para o envio dos dados*/
            String postStr = apiKey;                            /*Cria string postStr e passa apiKey*/
            postStr +="&field1=";                               /*Concatena field1*/
            postStr += String(und_item_1);                      /*Concatena und_item_1*/
            postStr +="&field2=";                               /*Concatena field2*/
            postStr += String(und_item_2);                      /*Concatena und_item_2*/
            postStr +="&field3=";                               /*Concatena field3*/
            postStr += String(und_item_3);                      /*Concatena und_item_3*/
            postStr +="&field4=";                               /*Concatena field4*/
            postStr += String(und_item_4);                      /*Concatena und_item_4*/
            postStr += "\r\n\r\n";                              /*Caractere nulo, encerra strg*/
 
     client.print("POST /update HTTP/1.1\n");                   /*Faz update da string, protocolo HTTP*/
     client.print("Host: api.thingspeak.com\n");                
     client.print("Connection: close\n");                       
     client.print("X-THINGSPEAKAPIKEY: "+apiKey+"\n");         
     client.print("Content-Type: application/x-www-form-urlencoded\n");
     client.print("Content-Length: ");
     client.print(postStr.length());
     client.print("\n\n");
     client.print(postStr);
  }
  client.stop();                                                /*Encerra client*/
  }
}

/*---------------------------------------------------------------------------*/
    void leitura_RFID( )                                        /*Função responsável por ler as TAG's*/
    {  
    if (! rfid.PICC_IsNewCardPresent( ) )    return;            /*Se não houver leitura de novo cartão, reinicia loop*/       
    if (! rfid.PICC_ReadCardSerial  ( ) )    return;            /*Se não houver leitura de cartão na //Serial, reinicia loop*/  

String strID = "";                                              /*Cria variável String nula*/
    for (byte i = 0; i < 4; i++)                                /*Concatena Bytes e monta a String da TAG em HEXA*/
    {                        
      strID +=  (rfid.uid.uidByte[i] < 0x10 ? "0" : "")+          
                      String (rfid.uid.uidByte[i], HEX)+          
                                      (i!=3 ? ":" : "");          
    strID.toUpperCase( );                                       /*Converte string para sua versão em Letras Maiúsculas*/
    }/*end for*/
  
    /*Serial.println("==========================");             -->Imprime no monitor Serial*/    
    /*Serial.println("      TAG DETECTADA");                    -->Imprime no monitor Serial*/    
    /*Serial.println("==========================");             -->Imprime no monitor Serial*/    
 
    if (strID == "2A:C0:36:59")                                 /*Compara TAG lida com TAG 1*/
    {     
      saldo = card_1;                                           /*Atualiza variável saldo para valor de card_1*/
      acesso=1;                                                 /*Concede acesso*/
    }/*end if*/
  
      else if (strID == "F4:F0:10:2A")                          /*Compara TAG lida com TAG 2*/
      {
        saldo  = card_2;                                        /*Atualiza variável saldo para valor de card_2*/
        acesso = 1;                                             /*Concede acesso*/
      }/*end else if*/
        else                                                    /*Se a TAG lida não for igual as TAG'S Cadastradas*/
        { 
          lcd.clear( );                                         /*limpa LCD*/                     
          /*Serial.println("Cartão INVÁLIDO     ");             -->Imprime no monitor Serial*/
          /*Serial.println( );                                  -->Pula linha*/
          lcd.setCursor(3,0);                                   /*Posiciona cursor*/  
          lcd.print("Cartao nao");                              /*Imprime no LCD*/
          lcd.setCursor(3,1);                                   /*Posiciona cursor*/  
          lcd.print("CADASTRADO");                              /*Imprime no LCD*/
          delay(5000);                                          /*delay*/
          lcd.clear( );                                         /*limpa LCD*/
         }/*end else*/
     }/*end leitura_RFID*/
/*---------------------------------------------------------------------------*/
    void imprime_LCD( )                                         /*Função responsável por Imprimir no LCD*/
    {
      if(acesso)                                                /*Se Acesso for concedido*/
      {
        digitalWrite(led_pin, HIGH);                            /*led_pin ON*/
        lcd.clear( );                                           /*limpa LCD*/
        lcd.setCursor(4,0);                                     /*Posiciona cursor*/  
        lcd.print("Creditos:");                                 /*Imprime no LCD*/
        lcd.setCursor(7,1);                                     /*Posiciona cursor*/  
        lcd.print(saldo);                                       /*Imprime no LCD*/
        delay(5000);                                            /*delay*/
        lcd.clear( );                                           /*limpa LCD*/
        lcd.setCursor(0,0);                                     /*Posiciona cursor*/  
        lcd.print("Escolha o item:");                           /*Imprime no LCD*/
        le_botao    ( );                                        /*Chama função de leitura dos botoes*/
        acesso = 0;                                             /*reseta acesso*/
        lcd.clear( );                                           /*limpa LCD*/  
      }/*end while*/
        else                                                    /*Se não foi concedido acesso*/
        {         
          digitalWrite(led_pin, LOW);                           /*led_pin OFF*/
          lcd.setCursor(2,0);                                   /*Posiciona cursor*/  
          lcd.print("Aproxime seu");                            /*Imprime no LCD*/
          lcd.setCursor(0,1);                                   /*Posiciona cursor*/  
          lcd.print("Cartao solidario");                        /*Imprime no LCD*/
        }/*end else*/  
     }/*end imprime_LCD*/
/*---------------------------------------------------------------------------*/
    void le_botao    ( )                                        /*Função que faz leitura dos botões e Micro*/
    {                                                           
byte  n=0;                                                      /*Variável que se altera ao selecionar item. Usara para imprimir "item_n" no LCD*/
bool  leitura_botao = 1;                                        /*Variável de condição para execurar while de leitura de botão*/
   
      while(leitura_botao)                                      /*Faz leitura de botão enquanto leitura_botao for verdadeiro*/
      {   
int  le_analog = analogRead(A0);                                /*Armazena leitura de A0 na variável le_analog*/
      delay(50);
         
      if(le_analog >= 1000  &&   le_analog <= 1024)             /*Faixa de leitura de A0 para que item seja item_1*/
      { 
        if(saldo >= item_1 && und_item_1 > 0)                   /*Se item igual a 1 e und_item_1 for maior que zero*/
        {
          /*Serial.println("Item 1");                           -->Imprime na Serial*/
          n=1;                                                  /*Atribui n = 1*/
          item_escolhido = item_1;                              /*Atribui item_1 ao item_escolhido*/
          leitura_botao=0;                                      /*Reseta leitura_botao*/
          und_item_1 = und_item_1 - 1;                          /*Debita und_item_1*/   
         }/*end if*/
            else if (saldo < item_1)                            /*Se o saldo for menor que o item_1*/
            {
              lcd.clear( );                                     /*Limpa LCD*/
              lcd.setCursor(4,0);                               /*Posiciona cursor*/  
              lcd.print("Credito");                             /*Imprime no LCD*/
              lcd.setCursor(2,1);                               /*Posiciona cursor*/ 
              lcd.print("Insuficiente");                        /*Imprime no LCD*/
              delay(2000);                                      /*Delay*/
              lcd.clear( );                                     /*Limpa LCD*/
              lcd.setCursor(4,0);                               /*Posiciona cursor*/  
              lcd.print("Procure");                             /*Imprime no LCD*/
              lcd.setCursor(2,1);                               /*Posiciona cursor*/ 
              lcd.print("Assistencia");                         /*Imprime no LCD*/
              delay(5000);                                      /*Delay*/
              _continue = 0;                                    /*Se saldo insuficiente, encerra if do loop e reinicia*/
              leitura_botao = 0;                                /*Reseta leitura_botao*/
              item_escolhido = 0;                               /*Reseta item_escolhido*/
             }/*end else if*/
                else if (und_item_1 == 0)                       /*Testa se acabou und_item_1*/
                {
                  lcd.clear( );                                 /*Limpa LCD*/
                  lcd.setCursor(6,0);                           /*Posiciona cursor*/  
                  lcd.print("Item 1");                          /*Imprime no LCD*/
                  lcd.setCursor(2,1);                           /*Posiciona cursor*/ 
                  lcd.print("Insuficiente");                    /*Imprime no LCD*/
                  delay(5000);                                  /*Delay*/
                  lcd.clear( );                                 /*Limpa LCD*/
                  _continue = 0;                                /*Se saldo insuficiente, encerra if do loop e reinicia*/
                  leitura_botao = 0;                            /*Reseta leitura_botao*/
                  item_escolhido = 0;                           /*Reseta item_escolhido*/
                 }/*end else if*/
      }/*end if*/
      
      else if(le_analog >= 960  &&   le_analog < 1000)          /*Faixa de leitura de A0 para que item seja item_2*/
      {
        if(saldo >= item_2 && und_item_2 > 0)                   /*Se item igual a 2, testa se saldo é maior que item_2*/
        {
          /*Serial.println("Item 2");                           -->Imprime na Serial*/
          n=2;                                                  /*Atribui n = 2*/
          item_escolhido = item_2;                              /*Atribui item_2 ao item_escolhido*/
          leitura_botao = 0;                                    /*Encerra leitura_botao*/  
          und_item_2 = und_item_2 - 1;                          /*Decrementa und_item2*/
        }/*end if*/        
            else if (saldo < item_2)                            /*Testa se saldo é menor que o item_2*/
            {    
                lcd.clear( );                                   /*Limpa LCD*/
                lcd.setCursor(4,0);                             /*Posiciona cursor*/  
                lcd.print("Credito");                           /*Imprime no LCD*/
                lcd.setCursor(2,1);                             /*Posiciona cursor*/                                  
                lcd.print("Insuficiente");                      /*Imprime no LCD*/
                delay(2000);                                    /*Delay*/
                lcd.clear( );                                   /*Limpa LCD*/
                lcd.setCursor(4,0);                             /*Posiciona cursor*/  
                lcd.print("Procure");                           /*Imprime no LCD*/
                lcd.setCursor(2,1);                             /*Posiciona cursor*/               
                lcd.print("Assistencia");                       /*Imprime no LCD*/
                delay(5000);                                    /*Delay*/  
                _continue = 0;                                  /*Encerra _continue (if principal do void loop)*/ 
                leitura_botao = 0;                              /*Encerra leitura_botao*/
                item_escolhido = 0;                             /*Encerra item_escolhido*/
            }/*end else if*/
             
                else if (und_item_2 == 0)                       /*Testa se acabou und_item_2*/
                {
                  lcd.clear( );                                 /*Limpa LCD*/
                  lcd.setCursor(6,0);                           /*Posiciona cursor*/  
                  lcd.print("Item 2");                          /*Imprime no LCD*/
                  lcd.setCursor(2,1);                           /*Posiciona cursor*/ 
                  lcd.print("Insuficiente");                    /*Imprime no LCD*/
                  delay(5000);                                  /*Delay*/
                  lcd.clear( );                                 /*Limpa LCD*/
                  _continue = 0;                                /*Encerra _continue (if principal do void loop)*/
                  leitura_botao = 0;                            /*Encerra leitura_botao*/
                  item_escolhido = 0;                           /*Encerra item_escolhido*/
                }/*end else if*/
      }/*end else if*/
    
      else if(le_analog >= 870  &&   le_analog < 960)           /*Faixa de leitura de A0 para que item seja item_3*/
      {
        if(saldo>=item_3 && und_item_3 > 0)                     /*Se item igual a 2 e und_item_2 for maior que zero*/                     
        {
          /*Serial.println("Item 3");                           -->imprime na serial*/ 
          n=3;                                                  /*Atribui n = 3*/
          item_escolhido = item_3;                              /*Atribui item_3 ao item_escolhido*/                              
          leitura_botao=0;                                      /*Encerra leitura_botao*/ 
          und_item_3 = und_item_3 - 1;                          /*Decrementa und_item3*/
        }/*end if*/
            else if (saldo < item_3)                            /*Testa se saldo é menor que o item_3*/
            {
              lcd.clear( );                                     /*Limpa LCD*/ 
              lcd.setCursor(4,0);                               /*Posiciona cursor*/  
              lcd.print("Credito");                             /*Imprime no LCD*/
              lcd.setCursor(2,1);                               /*Posiciona cursor*/  
              lcd.print("Insuficiente");                        /*Imprime no LCD*/
              delay(2000);                                      /*Delay*/ 
              lcd.clear( );                                     /*Limpa LCD*/ 
              lcd.setCursor(4,0);                               /*Posiciona cursor*/  
              lcd.print("Procure");                             /*Imprime no LCD*/
              lcd.setCursor(2,1);                               /*Posiciona cursor*/ 
              lcd.print("Assistencia");                         /*Imprime no LCD*/
              delay(5000);                                      /*Delay*/    
              _continue = 0;                                    /*Encerra _continue (if principal do void loop)*/ 
              leitura_botao = 0;                                /*Encerra leitura_botao*/
              item_escolhido = 0;                               /*Encerra item_escolhido*/
            }
                else if (und_item_3 == 0)                       /*Testa se acabou und_item_2*/
                {
                  lcd.clear( );                                 /*Limpa LCD*/
                  lcd.setCursor(6,0);                           /*Posiciona cursor*/  
                  lcd.print("Item 3");                          /*Imprime no LCD*/
                  lcd.setCursor(2,1);                           /*Posiciona cursor*/ 
                  lcd.print("Insuficiente");                    /*Imprime no LCD*/
                  delay(5000);                                  /*Delay*/
                  lcd.clear( );                                 /*Limpa LCD*/
                  _continue = 0;                                /*Encerra _continue (if principal do void loop)*/
                  leitura_botao = 0;                            /*Reseta leitura_botao*/
                  item_escolhido = 0;                           /*Reseta item_escolhido*/
                }/*end else if*/
      }/*end else if*/
      
      else if(le_analog >= 650  &&   le_analog < 870)           /*Faixa de leitura de A0 para que item seja item4_*/
      {
        if(saldo >= item_4 && und_item_4 > 0)                   /*Se item igual a 2 e und_item_2 for maior que zero*/
        {
          /*Serial.println("Item 4");                           -->Imprime na Serial*/ 
          n=4;                                                  /*Atribui n = 4*/    
          item_escolhido = item_4;                              /*Atribui item_4 ao item_escolhido*/
          leitura_botao=0;                                      /*Encerra leitura_botao*/
          und_item_4 = und_item_4 - 1;                          /*Decrementa und_item4*/
        }/*end if*/
            else if (saldo < item_4)                            /*Testa se saldo é menor que o item_4*/
            {
              lcd.clear( );                                     /*Limpa LCD*/ 
              lcd.setCursor(4,0);                               /*Posiciona cursor*/  
              lcd.print("Credito");                             /*Imprime no LCD*/
              lcd.setCursor(2,1);                               /*Posiciona cursor*/ 
              lcd.print("Insuficiente");                        /*Imprime no LCD*/
              delay(2000);                                      /*Delay*/ 
              lcd.clear( );                                     /*Limpa LCD*/ 
              lcd.setCursor(4,0);                               /*Posiciona cursor*/  
              lcd.print("Procure");                             /*Imprime no LCD*/
              lcd.setCursor(2,1);                               /*Posiciona cursor*/  
              lcd.print("Assistencia");                         /*Imprime no LCD*/
              delay(5000);                                      /*Delay*/    
              _continue = 0;                                    /*Encerra _continue (if principal do void loop)*/
              leitura_botao  = 0;                               /*Encerra leitura_botao*/
              item_escolhido = 0;                               /*Encerra item_escolhido*/                               
            }/*end else if*/         
                else if (und_item_4 == 0)                       /*Testa se acabou und_item_4*/
                  {
                    lcd.clear( );                               /*Limpa LCD*/                                         
                    lcd.setCursor(6,0);                         /*Posiciona cursor*/  
                    lcd.print("Item 4");                        /*Imprime no LCD*/
                    lcd.setCursor(2,1);                         /*Posiciona cursor*/ 
                    lcd.print("Insuficiente");                  /*Imprime no LCD*/
                    delay(5000);                                /*Delay*/
                    lcd.clear( );                               /*Limpa LCD*/
                    _continue = 0;                              /*Se saldo insuficiente, encerra if do loop e reinicia*/
                    leitura_botao = 0;                          /*Reseta leitura_botao*/
                    item_escolhido = 0;                         /*Reseta item_escolhido*/
                  }
      }/*end else if*/   
      }/*end while*/

      if (item_escolhido != 0)                                  /*Testa se algum item foi escolhido*/ 
      {
        lcd.clear( );                                           /*Limpa LCD*/
        lcd.setCursor(5,0);                                     /*Posiciona cursor*/  
        lcd.print("Item ");                                     /*Imprime no LCD*/
        lcd.print(n);                                           /*Imprime no LCD*/
        lcd.setCursor(2,1);                                     /*Posiciona cursor*/
        lcd.print("Creditos: ");                                /*Imprime no LCD*/    
        lcd.print(item_escolhido);                              /*Imprime no LCD*/  
        delay(5000);                                            /*Delay*/
        
            if(saldo == card_1)                                 /*Se o saldo for igual ao card_1*/
            {
              card_1 = card_1 - item_escolhido;                 /*Decrementa item_escolhido saldo do card_1*/
              saldo  = card_1;                                  /*Atribuí card_1 a variável saldo*/
            }/*end if*/        
                else if(saldo == card_2)                        /*Se o saldo for igual ao card_2*/
                {
                  card_2 = card_2 - item_escolhido;             /*Decrementa item_escolhido saldo do card_2*/
                  saldo  = card_2;                              /*Atribuí card_1 a variável saldo*/        
                }/*end else if*/
        lcd.clear( );                                           /*Limpa LCD*/ 
        lcd.setCursor(2,0);                                     /*Posiciona cursor*/  
        lcd.print("Saldo Atual");                               /*Imprime no LCD*/
        lcd.setCursor(2,1);                                     /*Posiciona cursor*/  
        lcd.print(saldo);                                       /*Imprime no LCD*/
        lcd.print(" Creditos");                                 /*Imprime no LCD*/
        delay(5000);                                            /*Delay*/
        item_selecionado( );                                    /*Chama função item_selecionado*/
        }/*end if*/
    }/*end le_botao*/
/*---------------------------------------------------------------------------*/
    void item_selecionado( )                                    /*Função responsável por ligar o motor selecionado, ler o micro e finalizar processo*/
    {   
      liga_servo( );                                            /*Chama Função responsável por ligar os servos*/
      lcd.clear( );                                             /*Limpa LCD*/  
      lcd.setCursor(4,0);                                       /*Posiciona cursor*/  
      lcd.print("Retire o");                                    /*Imprime no LCD*/
      lcd.setCursor(6,1);                                       /*Posiciona cursor*/  
      lcd.print("Item");                                        /*Imprime no LCD*/
      delay(1000);                                              /*Delay*/
             
bool micro_acionado = 0;                                        /*Variável de controle do Micro*/

        while(!micro_acionado)                                  /*Se o micro for acionado*/
        {
int       le_analog = analogRead(A0);                           /*Variável que recebe leitura analógica A0*/
          delay(50);                                            /*Delay*/
            if(le_analog >= 500  &&   le_analog < 650)          /*Faixa de leitura de A0 para que Micro seja acionado*/
            {
            /*Serial.println("MICRO");                          -->Imprime na Serial*/                  
            micro_acionado = 1;                                 /*Atribuí condição verdadeira a micro_acionado e encerra while*/
            digitalWrite(bip, 0);                               /*Garante que o buzzer permaneça desligado*/
            lcd.setBacklight(HIGH);                             /*Garante que o backlight permaneça ligado*/
            
            }/*end else if*/
                else                                            /*Se Micro não for acionado*/
                {
                  alarme ( );                                   /*Chama função responsável soar bip*/
                }/*end else*/
          
        }/*end while*/
        lcd.clear( );                                           /*Limpa LCD*/
        lcd.setCursor(3,0);                                     /*Posiciona cursor*/  
        lcd.print("OBRIGADO!!!");                               /*Imprime no LCD*/
        delay(5000);                                            /*Delay*/
        item_escolhido = 0;                                     /*Encerra item_escolhido*/                                     
        acesso = 0;                                             /*Encerra acesso*/        
        lcd.clear( );                                           /*Limpa LCD*/

     }/*end item_selecionado( )*/
/*---------------------------------------------------------------------------*/
    void liga_servo( )                                          /*Função responsável por ligar os servos*/
    {
      if(item_escolhido == item_1)                              /*Se o item_escolhido for o item 1*/
      {
        servo_1.write(50);                                      /*Liga Servo 1*/
        delay(delay_Servo );                                    /*Delay*/
        servo_1.write(90);                                      /*Desliga Servo 1*/
        delay(delay_Servo );                                    /*Delay*/
      }/*end if*/ 

          if(item_escolhido == item_2)                          /*Se o item_escolhido for o item 2*/
          {
            servo_2.write(50);                                  /*Liga Servo 2*/
            delay(delay_Servo );                                /*Delay*/
            servo_2.write(90);                                  /*Desliga Servo 2*/
            delay(delay_Servo );                                /*Delay*/
          }/*end if*/

              if(item_escolhido == item_3)                      /*Se o item_escolhido for o item 3*/
              {
                servo_3.write(50);                              /*Liga Servo 3*/
                delay(delay_Servo );                            /*Delay*/
                servo_3.write(90);                              /*Desliga Servo 3*/
                delay(delay_Servo );                            /*Delay*/
              }/*end if*/
                  if(item_escolhido == item_4)
                  {
                    servo_4.write(50);                          /*Liga Servo 4*/
                    delay(delay_Servo );                        /*Delay*/
                    servo_4.write(90);                          /*Desliga Servo 4*/
                    delay(delay_Servo );                        /*Delay*/
                  }/*end if*/      
    }/*end liga_servo*/

    void alarme ( )                                             /*Função responsável soar bip*/ 
    {
unsigned long tempoAtual = millis( );                           /*Atribuí millis( ) a variável tempoAtual*/
bool buzzer = 1;                                                /*Variável de controle para do buzzer. Inicia em nível alto*/
      if(tempoAtual - tempoAnterior > timeOnBip)                /*Enquanto tempoAtual - tempoAnterior for menor que timeOnBip, buzzer ligado*/
      {
        buzzer = 0;                                             /*Quando a condição for verdadeira, buzzer fica em nível baixo*/
      }/*end if*/
          if(tempoAtual - tempoAnterior > timeOffBip)           /*Enquanto tempoAtual - tempoAnterior for menor que timeOffBip, buzzer desligado*/
          {
            buzzer = 1;                                         /*Quando a condição for verdadeira, buzzer fica em nível alto*/
            tempoAnterior = tempoAtual;                         /*Atribuí tempoAtual à tempoAnterior*/
          }/*end if*/
      digitalWrite (bip, buzzer);                               /*Alterna nível lógico de bip conforme valor de buzzer*/
      lcd.setBacklight (!buzzer);                               /*Alterna condição do backlight LCD conforme a negação de buzzer*/
    }/*end alarme*/


    
/* ============================================================================  
                                                           
        *******   ***      **     **     ***   *******
      ******   *****       *********      *****    *****
    ******  ********       *********       ******    *****
   ****   **********       *********       *********   *****
  ****  **************    ***********     ************   ****
 ****  *************************************************  ****
****  ***************************************************  ****
****  ****************************************************  ****
****  ****************************************************  ****
 ****  ***************************************************  ****
  ****  *******     ****  ***********  ****     *********  ****
   ****   *****      *      *******      *      ********  ****
    *****   ****             *****             ******   *****
      *****   **              ***              **    ******
       ******   *              *              *   *******
         *******                                *******
            ********                         *******
               *********************************
                    ***********************
                                                              
                                                              
============================================================================ */
                  /* --- Final do Programa --- */

Considerações Sobre o Código

  • Cadastro dos cartões e tags – O cadastro desses itens é feito por meio do próprio código fonte. É necessário decodificar o código dos cartões e tags que irá utilizar (Através de um sketch que faça isso) e alterar isso no código da máquina.
  • Outros parâmetros – É necessário modificar os demais parâmetros para adequar a máquina a sua necessidade, tais como:
    • Nome da Rede Wi-Fi e senha;
    • Saldo dos cartões e TAG’s cadastradas;
    • Quantidade de cada item da máquina;
    • Custo de cada item;
    • API write do thingspeak;

Aplicativo

Foi criado um simples aplicativo que monitorar a quantidade de itens que existem na máquina. A cada compra de cada item, é debitado uma unidade, até que zere.

APP tela1

O mantenedor da máquina poderá monitorar quando a máquina está sem itens e ir abastece-la. Ao fazer isso, ele deverá acessar o botão “Máquina Completa” com a senha de acesso para informar a máquina que todos os itens foram abastecidos.

APP tela 2

O aplicativo foi feito através da plataforma MIT APP INVENTOR e ficará disponível através do link do gitHub.


Arquivos

Os arquivos estão todos disponibilizados nesse link do GitHub.

Contém a programação, os desenhos da estrutura da máquina e demais arquivos que completam esse post.


Conclusão

Com conhecimento em programação em linguagem C e com base na eletrônica, foi possível construir nossa máquina de vendas automática do zero.

A versatilidade dos microcontroladores e sistemas embarcados nos permitem realizar  projetos de forma muito mais simplificada, fornecendo ferramentas para que todos possam desenvolver seus projetos e adquirir mais conhecimento.

Esperamos que nossa máquina sirva de inspiração para o desenvolvimento de quaisquer tipos de protótipos e que nosso conteúdo tenha sido de grande ajuda.

Deixe o seu comentário e nos marque nas redes sociais @eletrogate com sua vending machine em mãos.

Conheça a Metodologia Eletrogate e ofereça aulas de robótica em sua escola!


Sobre o Autor


Luiz Fernando
@microcontrolando

Técnico em Eletroeletrônica, Eletricista de manutenção e aspirante a maker.


Eletrogate

18 de fevereiro de 2022

A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.

Tenha a Metodologia Eletrogate dentro da sua Escola! Conheça nosso Programa de Robótica nas Escolas!

Eletrogate Robô

Cadastre-se e fique por
dentro de novidades!