Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Manufacturing Technology >> Processo de manufatura

Garrafa de água alimentada por Arduino

Componentes e suprimentos

SparkFun Arduino Pro Mini 328 - 5 V / 16 MHz
× 1
Sensor ultrassônico à prova d'água
× 1
Relógio em tempo real (RTC)
× 1
SparkFun Common-cathode 4 dígitos 7 segmentos Display
× 1
Buzzer
× 1
SparkFun Botão de pressão 12 mm
× 1
Transistor de uso geral NPN
× 1
Bateria Li-Ion 1000mAh
× 1
Carregador de bateria de íon de lítio USB Adafruit
× 1
Resistor 221 ohm
× 8
Resistor 1k ohm
× 4
Resistor 4,75 k ohm
× 2

Ferramentas e máquinas necessárias

Ferro de soldar (genérico)
Pistola de cola quente (genérica)

Aplicativos e serviços online

Arduino IDE

Sobre este projeto





Introdução:


Beber bastante água é muito importante para nossa saúde. Beber mais água pode levar a uma pele mais clara, melhor saúde geral, maior produtividade e função cerebral, aumento dos níveis de energia e até mesmo perda de peso.

Em nossas vidas ocupadas, é muito difícil lembrar de beber água o suficiente. E na maioria das vezes nos esquecemos de beber água suficiente, quer estejamos em casa, no escritório ou em trânsito. Cerca de 75% dos americanos estão cronicamente desidratados o tempo todo.

Portanto, para construir um hábito saudável de beber água, é importante monitorar sua ingestão de água todos os dias.

Para monitorar minha ingestão de água, fiz minha garrafa de água inteligente usando o Arduino. Pode:

1. Monitore minha ingestão diária de água

2. Acompanhe minha ingestão média semanal de água

3. Lembre-me de levar água

4. Rastreie o tempo da última ingestão

5. Execute mais de um mês com uma única carga.





Fazendo Módulo RTC


Para registrar ou rastrear as informações de ingestão de água, é necessário que as informações de hora e data atuais sejam armazenadas junto com os dados acumulados. Um chip de relógio em tempo real (RTC) como o DS1307 com uma bateria de backup adequada pode ser usado para fornecer as informações necessárias. O processo de programação do chip RTC (no software) também é muito simples e é compatível com a maioria dos ambientes de programação.

Aqui está o design de um módulo RTC compacto, baseado no popular RTC IC DS1307, para seus projetos diários de microcontroladores. O relógio serial em tempo real (RTC) DS1307 é um relógio / calendário BCD (full binary coded decimal) de baixa potência mais 56 bytes de NV SRAM. O endereço e os dados são transferidos serialmente por meio de um barramento bidirecional I2C. O formato de relógio / calendário de 24 horas / 12 horas fornece informações de segundos, minutos, horas, dia, data, mês e ano, incluindo correções para ano bissexto.

Vamos fazer o módulo de relógio de tempo real de acordo com o esquema em anexo. O DS1307 RTC requer um cristal externo para operar corretamente. Dois resistores pull-up são necessários para o pino SCL e SDA do IC. O valor do resistor pode ser em torno de 2k a 10k. Usei 4,7k. Durante a soldagem, tentei manter o módulo o mais pequeno possível porque o espaço é limitado para o meu circuito. Você pode usar DS3231 em vez de DS1307 e o IC tem um oscilador de cristal interno. Portanto, você não precisa adicionar nenhum cristal externo. Você também pode comprar um pequeno módulo RTC pré-fabricado, se não gostar de fazê-lo. Como o sistema completo funcionará a partir de bateria, por isso conectei o pino VBAT do RTC ao terra sem usar célula tipo moeda.

Pinos importantes do DS1307:
  • Pin 5V :Quando este pino está alto, o ds1307 envia os dados e, quando está baixo, ele é executado na célula do botão de backup.
  • GND :Este é o pino de aterramento do módulo. O aterramento da bateria e a fonte de alimentação estão interligados.
  • SCL :É o pino do relógio I2C - que se comunica com o microcontrolador. Deve se conectar com o pino Arduino SCL.
  • SDA :É o pino de dados I2C - que se comunica com o microcontrolador. Deve se conectar com o pino SDA do Arduino.
  • VBAT :Entrada de bateria para qualquer célula de lítio 3V padrão ou outra fonte de energia. Deve ser aterrado se não for usado.





Fazendo quadro de exibição de sete segmentos


Para o módulo de exibição aqui, usei um módulo de cátodo comum compacto e autônomo contendo quatro visores numéricos de LED de 7 segmentos, bons para exibir dados numéricos com alguns caracteres simples.

Cada segmento no módulo de exibição é multiplexado, o que significa que compartilha os mesmos pontos de conexão do ânodo. E cada um dos quatro dígitos do módulo tem seu próprio ponto de conexão de cátodo comum. Isso permite que cada dígito seja ativado ou desativado independentemente. Além disso, essa técnica de multiplexação transforma a enorme quantidade de pinos do microcontrolador necessários para controlar uma tela em apenas onze ou doze (no lugar de trinta e dois)!

Os segmentos de LED do display requerem resistores limitadores de corrente quando alimentados por um pino lógico de 5 V. O valor do resistor é normalmente entre 330 e 470 ohms para 5 V. Para operação com bateria de íon-lítio, pode ser 220 ohms. E, transistores de driver são recomendados para fornecer corrente de condução adicional para os segmentos de LED, porque cada pino de um microcontrolador pode fornecer ou absorver cerca de 40 mA de corrente apenas. Quando todos os (sete) segmentos do display forem ligados de uma vez (o numeral 8), a demanda atual excederá este limite de 40 mA. A imagem mostrada abaixo indica o diagrama de fiação básico dos resistores limitadores de corrente e transistores do driver.

Esta seção de display de 4 dígitos e 7 segmentos é conectada em torno de quatro displays de LED de cátodo comum de 7 segmentos e quatro transistores NPN 2N2222. Os resistores 1K são usados ​​para limitar a corrente de base e os resistores 220R limitam a corrente operacional dos segmentos de tela de LED.

Na placa Arduino, as saídas digitais de D10 a D17 são usadas para direcionar segmentos (a a g &dp) e as saídas digitais D6 a D9 são usadas para os dígitos (D0-D3) do display LED 4 × 7.

Um interruptor de botão é adicionado com o módulo de exibição para acessar diferentes opções. Ele também será usado para despertar o Arduino do modo de hibernação usando interrupção de hardware externa. então, o botão é conectado ao pino digital nº 2 do Arduino (INT0).





Conectando placa de vídeo com Arduino Mini Pro


De acordo com o esquema fornecido, antes de soldar todos os pinos do segmento ao mini pino do Arduino. Em seguida, solde 4 pinos comuns ao pino coletor do transistor. As bases do transistor são conectadas ao pino do Arduino. Após conectar o display, conecte a chave do botão com o pino digital 2 do Arduino (INT 0). Certifique-se de ter conectado o botão ao pino 2 do Arduino, pois implementaremos uma interrupção de hardware externa para despertar o Arduino do modo de hibernação usando este botão.





Conectando Módulo RTC e Buzzer


Agora, conecte o módulo RTC que você fez anteriormente à placa Arduino. O pino SDA do módulo deve ser conectado ao pino SDA (A4) do pino Arduino e o pino SCL do módulo deve ser conectado ao pino SCL (A5) do Arduino. Em seguida, conecte a campainha à placa Arduino.

Conexões:

RTC ------> Arduino Mini Pro
  • SDA ------> A4
  • SCL ------> A5
  • Buzzer ------> D3





Fixação do sensor ultrassônico com tampa de garrafa


Faça um furo na tampa da garrafa como mostrado na imagem. Traga quatro fios do sensor ultrassônico através do orifício e fixe o sensor ultrassônico no meio da tampa da garrafa. O sensor deve ser colocado no lado interno da tampa do frasco e deve ser colocado na posição central.

Conexões:

Sensor ultrassônico ------> Arduino Mini Pro
  • VCC ------> VCC
  • GND ------> GND
  • Gatilho ------> D4
  • Eco ------> D5





Upload de programa e teste


Depois de completar toda a conexão, é o momento certo para fazer o upload do programa para a placa Arduino e testar a funcionalidade. Serão necessárias várias bibliotecas para que o programa funcione corretamente. Para interface de botão, você precisa adicionar a biblioteca OneButton. Como o dispositivo funciona com bateria, o consumo de energia é uma questão importante. Implementei o modo de espera em meu esboço do Arduino. O cronômetro do watchdog e a interrupção do hardware externo foram usados ​​para despertar o Arduino do modo de hibernação. O Arduino faz a leitura do sensor três vezes, calcula a média e calcula as informações necessárias e exibe as informações por 10 segundos e depois vai para o modo de espera por 1 minuto. Ele acorda a qualquer momento ao pressionar o botão conectado ao INT0 (pino digital 2). Portanto, se você quiser ver as informações sobre a sua ingestão de água, basta pressionar o botão de opção a qualquer momento. Ele vai acordar para você. Sem pressionar nenhum botão, a leitura será realizada a cada 1 minuto. Para implementar o modo de suspensão, usei a biblioteca Arduino Low-Power. Para ler o tempo do módulo DS1307 RTC, usei a biblioteca DS1307RTC. Portanto, para compilar o programa anexado, adicione toda a biblioteca ao seu ambiente.

Vou explicar aqui apenas o algoritmo de cálculo resumidamente. Veja o preenchimento em anexo para um esboço completo. O cálculo é feito a partir da média de cinco leituras do sensor para torná-lo preciso o suficiente. A leitura diária é redefinida em 24 horas e preparada para uma nova leitura no novo dia.

A ingestão média de água é preparada com base na ingestão média diária dos sete dias anteriores. Duas horas se passaram sem ingestão de água, ele alertará o usuário com dois bipes a cada 15 minutos e parará nas próximas 2 horas após a ingestão de água.

Baixe o código em anexo e envie-o para o seu Arduino Mini Pro. Conecte todo o módulo e ligue-o para testar se todos os componentes estão funcionando corretamente ou não. Se o display mostrar algum resultado, então parabéns! Você já fez as coisas difíceis.





Consertando Arduino com tampa de garrafa


Usando cola quente, o Arduino mini na parte superior da tampa da garrafa. Lembre-se de que você deve fixar todos os componentes na tampa do frasco. Adicione cola suficiente para que fique bem presa à tampa do frasco.





Conectando o Módulo de Bateria e Carregador


Agora, fixe a bateria de íon de lítio na parte superior do Arduino. Tenha cuidado ao encurtar a bateria com qualquer pino aberto. Em seguida, conecte o módulo carregador com a tampa. Mantenha a porta USB facilmente acessível pelo lado externo para que possa ser conectada facilmente ao carregador.





Tornando todos os circuitos à prova d'água


Depois de conectar todos os componentes e modulá-lo é o momento certo para tornar nosso dispositivo totalmente à prova d'água. É muito importante porque é uma garrafa de água e a qualquer momento pode cair água no circuito e danificá-lo. Para torná-lo totalmente à prova d'água, adicione cola suficiente em todas as partes externas dos circuitos, sem a porta USB. Você pode deixar a tampa bonita usando cola para torná-la redonda na tampa original.

Não afunde a tampa da garrafa na água.





Aproveite



Código

  • Arduino Sketch
Arduino Sketch Arduino
 // Funções de data e hora usando um DS1307 RTC conectado via I2C e Wire lib # include  #include  #include  #include  #include " LowPower.h "#include" OneButton.h "botão OneButton (2, verdadeiro); const byte interruptPin =2; volatile int state =0; const int trigPin =4; const int echoPin =5; int piezoPin =3; const int dígito [4] ={9,6,7,8}; int dígito_valor [4]; int dígito_valor1 [4]; int button_press_count =1; const int segmento [8] ={16,10,12,14,15, 17,11,13}; número de bytes const [10] [8] ={{1,1,1,1,1,1,0,0}, // 0 {0,1,1,0,0, 0,0,0}, // 1 {1,1,0,1,1,0,1,0}, // 2 {1,1,1,1,0,0,1,0}, / / 3 {0,1,1,0,0,1,1,0}, // 4 {1,0,1,1,0,1,1,0}, // 5 {1,0,1 , 1,1,1,1,0}, // 6 {1,1,1,0,0,0,0,0}, // 7 {1,1,1,1,1,1,1 , 0}, // 8 {1,1,1,1,0,1,1,0}}; // 9const byte d [8] ={0,1,1,1,1,0,1,1}; const byte a [8] ={1,1,1,0,1,1,1,1 }; const byte r [8] ={0,0,0,0,1,0,1,1}; const byte t [8] ={0,0,0,1,1,1,1,1 }; int segundos, minutos, horas; int water_in_ounch [15]; int water_intake_ounch [15]; int water_intake_days [7]; int water_intake_times =0; int previous_water_atount =0; int total_water_intake_today =0; int média_intake_last_week_week =0; 1; float nível_média_água =0; // armazena a média de vários readingint water_amount_in_ounce =0; // armazena a quantidade calculada de waterint idle_time =0; int ingestão_day =1; int previous_value =0; void setup () {Serial.begin (9600); pinMode (interruptPin, INPUT_PULLUP); // coloque seu código de configuração aqui, para executar uma vez:for (int i =6; i <=17; i ++) pinMode (i, OUTPUT); pinMode (trigPin, OUTPUT); pinMode (echoPin, INPUT); button.attachClick (pressionado); button.attachDoubleClick (clique duplo); button.attachLongPressStart (longPressStart); button.attachDuringLongPress (longPress);} long previous_state =millis (); int count =1; int daily_intake =0; int semanal_intake =0; long sleep_time =millis (); void loop () {read_time (); button.tick (); // continue observando os botões de ação:cálculo (); ingestão_diariamente =ingestão_de_água_total_in_dia (); entrada_semanal =média_entrada_água_da_volta_semana (); if (button_press_count ==1) {display_d (); display_number (daily_intake); } else if (button_press_count ==2) {display_a (); display_number (semanal_intake); } else if (button_press_count ==3) {display_r (); display_number (water_amount_in_ounce); } else if (button_press_count ==4) {display_first_2 (horas); display_last_2 (minutos); } if (idle_time> =120) {alert (); alerta(); } if ((millis () - sleep_time)> =15000) {display_off (); attachInterrupt (digitalPinToInterrupt (interruptPin), em branco, FALLING); LowPower.powerDown (SLEEP_8S, ADC_OFF, BOD_OFF); LowPower.powerDown (SLEEP_8S, ADC_OFF, BOD_OFF); LowPower.powerDown (SLEEP_8S, ADC_OFF, BOD_OFF); LowPower.powerDown (SLEEP_8S, ADC_OFF, BOD_OFF); LowPower.powerDown (SLEEP_8S, ADC_OFF, BOD_OFF); LowPower.powerDown (SLEEP_8S, ADC_OFF, BOD_OFF); detachInterrupt (digitalPinToInterrupt (interruptPin)); sleep_time =millis (); }} void display_digit (int dígito) {for (int i =0; i <8; i ++) {digitalWrite (segmento [i], número [dígito] [i]); }} void display_number (int number) {int i =0; enquanto (número> 0) {digit_value [2-i] =número% 10; número =número / 10; i ++; } digitalWrite (dígito [1], HIGH); digitalWrite (dígito [2], LOW); digitalWrite (dígito [3], LOW); display_digit (digit_value [0]); atraso (5); digitalWrite (dígito [1], LOW); digitalWrite (dígito [2], HIGH); digitalWrite (dígito [3], LOW); display_digit (digit_value [1]); atraso (5); digitalWrite (dígito [1], LOW); digitalWrite (dígito [2], LOW); digitalWrite (dígito [3], HIGH); display_digit (digit_value [2]); atraso (5); digitalWrite (dígito [3], LOW); valor_digital [0] =0; valor_digital [1] =0; valor_digital [2] =0; } void display_first_2 (número interno) {digitalWrite (dígito [2], LOW); digitalWrite (dígito [3], LOW); int i =0; enquanto (número> 0) {digit_value [1-i] =número% 10; número =número / 10; i ++; } digitalWrite (dígito [0], HIGH); digitalWrite (dígito [1], LOW); display_digit (digit_value [0]); atraso (3); digitalWrite (dígito [0], LOW); digitalWrite (dígito [1], HIGH); display_digit (digit_value [1]); atraso (3); } void display_last_2 (número int) {digitalWrite (dígito [0], LOW); digitalWrite (dígito [1], LOW); int i =0; enquanto (número> 0) {digit_value1 [1-i] =número% 10; número =número / 10; i ++; } digitalWrite (dígito [2], HIGH); digitalWrite (dígito [3], LOW); display_digit (digit_value1 [0]); atraso (3); digitalWrite (dígito [2], LOW); digitalWrite (dígito [3], HIGH); display_digit (digit_value1 [1]); atraso (3); } void display_d () {digitalWrite (dígito [0], HIGH); para (int i =0; i <8; i ++) {digitalWrite (segmento [i], d [i]); } atraso (5); digitalWrite (dígito [0], LOW); } void display_a () {digitalWrite (dígito [0], HIGH); para (int i =0; i <8; i ++) {digitalWrite (segmento [i], a [i]); } atraso (5); digitalWrite (dígito [0], LOW); } void display_r () {digitalWrite (dígito [0], HIGH); para (int i =0; i <8; i ++) {digitalWrite (segmento [i], r [i]); } atraso (5); digitalWrite (dígito [0], LOW); } void display_t () {digitalWrite (dígito [0], HIGH); para (int i =0; i <8; i ++) {digitalWrite (segmento [i], t [i]); } atraso (5); digitalWrite (dígito [0], LOW); } void display_off () {digitalWrite (dígito [0], LOW); digitalWrite (dígito [1], LOW); digitalWrite (dígito [2], LOW); digitalWrite (dígito [3], LOW); para (int i =0; i <8; i ++) {digitalWrite (segmento [i], LOW); } atraso (5); } void read_time () {tmElements_t tm; if (RTC.read (tm)) {segundos =tm.Segundo; minutos =tm.Minuto; horas =tm.Hour; }} distância interna_em_cm () {longa duração, cm; // O sensor é acionado por um pulso HIGH de 10 ou mais microssegundos. // Dê um pulso BAIXO curto de antemão para garantir um pulso ALTO limpo:digitalWrite (trigPin, LOW); atrasoMicrosegundos (2); digitalWrite (trigPin, HIGH); atrasoMicrosegundos (10); digitalWrite (trigPin, LOW); // Lê o sinal do sensor:um pulso HIGH cuja // duração é o tempo (em microssegundos) desde o envio // do ping até a recepção de seu eco de um objeto. duração =pulseIn (echoPin, HIGH); // converte o tempo em uma distância cm =microssegundosToCentímetros (duração); return cm; } longo microssegundosToCentímetros (longos microssegundos) {// A velocidade do som é 340 m / s ou 29 microssegundos por centímetro. // O ping viaja para fora e para trás, então, para encontrar a distância do // objeto, pegamos metade da distância percorrida. retornar microssegundos / 29/2; } void alert () {tom (piezoPin, 2000, 50); tom (piezoPin, 2000, 200); // atraso (10); } void blank () {// tom (piezoPin, 2000, 100); // estado ++;} // Esta função será chamada quando o botão1 for pressionado 1 vez (e nenhum 2. botão pressionado seguido) .voidushed () {//Serial.println("Button 1 clique. "); button_press_count ++; alerta(); if (button_press_count ==5) {button_press_count =1; }} // click // Esta função será chamada quando o botão1 for pressionado 2 vezes em um curto período de tempo.void doubleclick () {Serial.println ("Button 1 doubleclick.");} // doubleclick // Esta função irá ser chamado uma vez, quando o botão1 for pressionado por um longo tempo.void longPressStart () {Serial.println ("Button 1 longPress start");} // longPressStart // Esta função será chamada frequentemente, enquanto o botão1 for pressionado por a longpress.void longPress () {Serial.println ("Button 1 longPress ..."); water_intake_ounch [water_intake_times - 1] =0; // ignorar o último valor} // cálculo longPressvoid () {float water_level =0; // armazenar o nível em cada etapa int read_value =0; // lê a leitura do sensor em cm para (int i =0; i <5; i ++) {// faz cinco leituras read_value =distance_in_cm (); if (read_value> 16 || read_value <3) {// retorno de leitura instável; // retorna à função de chamada porque a leitura é instável} else if (read_value <=16 &&read_value> =3) {// valor válido water_level =water_level + read_value; } atraso (10); } nível_água_média =17 - nível_água / 5; // encontrar a média de cinco leituras, 17 =altura do botole water_amount_in_ounce =int (average_water_level * 1,87); // nível de água de 16 cm =30 onças if (water_intake_times ==0) {previous_water_amount =water_amount_in_ounce; water_intake_times =1; } if ((quantidade_da_água_in_ounce  previous_water_amount) {// água é recarregada // reabastecer água aqui previous_water_amount =water_amount_in_ounce; } else if (water_amount_in_ounce ==previous_water_amount) {// nenhuma água consumida ou reabastecer idle_time + =1; } if (hours ==23 &&minutes ==59) {// um dia acabou e todos os valores começam de zero para o novo dia para (int i =0; i <15; i ++) {water_intake_ounch [i] =0; } tempos de entrada_de_água =0; ingestão_dia ++; if (ingestão_dia ==8) {ingestão_dia =1; }}} int total_water_intake_in_day () {// calcular a ingestão total de água em um dia total_water_intake_today =0; for (int i =0; i  

Esquemas


Processo de manufatura

  1. Aspersor de gramado
  2. Máquina de lavar louça
  3. Pistola de água
  4. Vaso sanitário
  5. Hidrante
  6. Garrafa isolada
  7. Água
  8. Shampoo
  9. Drywall
  10. MOSMusic