Sistema de controle automático de aquário no Arduino

Gostaria de compartilhar minha primeira experiência na criação de um aquário Arduino. Antes, eu não trabalhava com eletrônica e, além disso, não sabia como os microcontroladores são programados. No entanto, decidi tentar a minha mão e gostaria de compartilhar os resultados.



A ideia de criar um aquário


Aconteceu que eu estava envolvido principalmente na programação .NET e aprendi a ignorar o C ++. Provavelmente é por isso que nunca me encontrei com microcircuitos e microcontroladores, embora o desejo de conhecê-los cresça quase todos os anos. Especialmente, nos últimos anos em que descobri o Arduino. Mas era necessário apresentar uma aplicação prática para ele. E esse problema foi rapidamente resolvido.

Há um aquário em nosso quarto, e todos os dias tínhamos que subir debaixo da mesa, apagar a luz dos peixes e ligá-lo de manhã. Além disso, os peixes precisavam ligar o aquecedor quando estavam frios e desligá-los quando estavam quentes. Às vezes, meu esquecimento levou à morte de peixes no aquário e tive que comprar novos. Até o peixe tinha que mudar periodicamente 2/3 da água. E para o nosso aquário, esse procedimento foi muito longo e desagradável.

Antes de tudo, olhei para soluções prontas para aquários. Existem muitos deles. Estes são principalmente vídeos no youtube. Também existem artigos bastante interessantes sobre os tempos de nerd. Mas para o meu propósito - estudar e conhecer o mundo dos microcircuitos - era muito complicado, e um guia detalhado "do zero" na Internet não foi encontrado. A idéia de desenvolver um controlador de aquário teve que ser adiada até que o básico da microeletrônica fosse estudado.

Familiaridade com microeletrônica


Comecei minha jornada com um kit pronto para aprender Arduino. Provavelmente, todo mundo coletou algo semelhante quando se familiarizou com esta plataforma: uma



lâmpada comum (LED), um resistor de 220 Ohm. O Arduino controla a lâmpada usando um algoritmo C ++. Faça imediatamente uma reserva de que, após ter comprado qualquer conjunto pronto de Arduino ou seu análogo, é impossível montar uma coisa mais ou menos útil. Bem, exceto o tweeter ou, digamos, um termômetro doméstico. É possível aprender a própria plataforma através de lições, mas não mais. Para coisas úteis , tive que aprender solda, placas de circuito impresso, design de placas de circuito impresso e outras delícias eletrônicas.

Crie seu primeiro protótipo de aquário


Então, a primeira coisa que comecei com meu protótipo de aquário foi formular requisitos de papel para este dispositivo.

O aquário deve:

  1. , , ;
  2. , , ( ) ;
  3. ( ) ;
  4. , , ;
  5. « »
  6. ;
  7. . , 9:00 AM;
  8. , ;
  9. .
  10. A tela com a data em que você pressiona o botão no controle remoto deve ser destacada. Se nada for pressionado em 5 segundos, apague.

Decidi começar explorando o funcionamento do LCD e do Arduino.

Crie o menu principal. Operação do LCD


Para o LCD, decidi usar a biblioteca LiquidCrystal. Coincidentemente, além do Arduino, eu também tinha uma tela LCD no meu kit. Ele poderia produzir texto, números. Isso foi o suficiente e comecei a estudar a conexão dessa tela com o Arduino. Tirei as informações básicas de conexão daqui . Existem também exemplos de código para a saída de "Hello World".

Tendo um pouco de acordo com a tela, decidi criar o menu principal do controlador. O menu consistia nos seguintes itens:

  1. Informação básica;
  2. Ajuste de hora;
  3. Configuração de data;
  4. Temperatura;
  5. Clima;
  6. Luz de fundo
  7. Aparelhos

Cada item é um modo específico de saída de informações na tela de texto do LCD. Eu queria permitir a possibilidade de criar um menu de vários níveis, em que cada subnível terá sua própria implementação da saída na tela.

Na verdade, a classe base foi escrita em C ++, da qual todos os outros submenus serão herdados.

 class qQuariumMode
{
protected:
	LiquidCrystal* LcdLink;
public:

	//    ,   bool  isLcdUpdated.
	bool isLcdUpdated = false;
    
	//     .
	void exit();
	
	//  loop      . ,      
	//   .        .
	virtual void loop();

	// ,    virtual,      
	// . 
	virtual void OkClick();
	virtual void CancelClick();
	virtual void LeftClick();
	virtual void RightClick();
};

Por exemplo, para o menu "Dispositivos", a implementação da classe base qQuariumMode terá a seguinte aparência:

#include "qQuariumMode.h"
class qQuariumDevicesMode :
	public qQuariumMode
{
private:

	int deviceCategoryLastIndex = 4;
	
	//    
	enum DeviceCategory
	{
		MainLight, //   
		Aeration, //  
		Compressor, //  
		Vulcanius, //  
		Pump //  
	};
	
	DeviceCategory CurrentDeviceCategory = MainLight;

	char* headerDeviceCategoryText = NULL;

	//   "",      
	BaseOnOfDeviceHelper* GetDeviceHelper();

public:
	void loop();
	void OkClick();
	void CancelClick();
	void LeftClick();
	void RightClick();
};

Aqui está o resultado da implementação do primeiro nível do menu:



Peça de hardware. As nuances dos componentes de conexão


Quero dizer algumas palavras sobre o hardware do controlador do aquário. Para o funcionamento normal do controlador, tive que comprar:

  1. 1 x Arduino Uno / Mega. Mais tarde, ele decidiu trabalhar com Mego;
  2. 1 x relógio em tempo real, por exemplo DS1307;
  3. 2 x RTD14005, , .. 220 ;
  4. 1 x ;
  5. 1 x ;
  6. 5 x IRF-530 MOSFET N . (3 RGB , 1 , 1 );
  7. 1 x RGB . , . ;
  8. 1 x White ;
  9. 1 x LCD ;
  10. 1 x . DS18B20;
  11. 1 x . DHT11;

Cada componente possui seu próprio tipo de conexão e seus drivers para operação. Não descreverei as nuances da conexão de todos os componentes, pois eles podem ser encontrados no site do fabricante ou nos fóruns. Se você planeja usar os mesmos componentes que eu, não precisará alterar o código-fonte.

Deterioração de componentes


Seja cuidadoso. Tente ler sobre o componente do plug-in primeiro. Ele deve ser operado com precisão na faixa de tensão para a qual foi criado. Isso geralmente é indicado no site do fabricante. Enquanto desenvolvia o controlador do aquário, destruí 2 sensores de temperatura selados e um relógio em tempo real. Os sensores falharam devido ao fato de eu os conectar a 12V, e era necessário a 5V. O relógio em tempo real morreu devido a um curto-circuito "aleatório" no circuito devido à minha falha.

Faixa de LED RGB


Dificuldades particulares surgiram com tiras de LED. Eu tentei implementar o seguinte esquema:



Ao conectar-me ao Arduino, usei pinos compatíveis com PWM (Pulse Width Modulation). Ao ligar simultaneamente a tensão máxima de todos os 3 pinos, minha fita estava muito quente. Como resultado, se você deixar por uma hora ou duas, alguns LEDs deixarão de brilhar. Acredito que isso ocorreu devido à falha de alguns resistores. Outra desvantagem desse esquema é o brilho diferente da faixa de LEDs para cada uma das cores. Por exemplo, se eu colocar a tensão máxima no componente vermelho da fita, obterei o brilho condicional da fita vermelha em 255 unidades. Se eu ligar os componentes vermelho e azul na tensão máxima, o brilho será igual a 255 + 255 = 510 unidades e a cor será roxa. Em geral, esta solução não combina comigo.

Decidiu-se implementar o seguinte algoritmo:

void LedRgbHelper::Show(RGBColorHelper colorToShow)
{	
	// RGBColorHelper         . 
	//  ,     
	int sumColorParts = colorToShow.RedPart + colorToShow.GreenPart + colorToShow.BluePart;

	//      
	float rK = 0;
	float gK = 0;
	float bK = 0;

	if (sumColorParts != 0)
	{
		float redPartAsFloat = (float)colorToShow.RedPart;
		float greenPartAsFloat = (float)colorToShow.GreenPart;
		float bluePartAsFloat = (float)colorToShow.BluePart;

		float sumColorPartsAsFloat = (float)sumColorParts;

		int brightness = colorToShow.Brightness;
		

		//       .
		rK = redPartAsFloat / sumColorPartsAsFloat;
		gK = greenPartAsFloat / sumColorPartsAsFloat;
		bK = bluePartAsFloat / sumColorPartsAsFloat;
		
		//      
		rK = rK*brightness;
		gK = gK*brightness;
		bK = bK*brightness;
	}
		
	uint8_t totalCParts = (uint8_t)rK + (uint8_t)gK + (uint8_t)bK;
	
	if (totalCParts <= 255){
		//      .        255 .
		analogWrite(RedPinNum, (uint8_t)rK);
		analogWrite(GreenPinNum, (uint8_t)gK);
		analogWrite(BluePinNum, (uint8_t)bK);
	}	
}

Nesta modalidade, a cor vermelha e a violeta tinham o mesmo brilho. Essa. os LEDs vermelhos no primeiro caso brilhavam com um brilho de 255 unidades e, na cor violeta, o vermelho estava com um brilho de 127 unidades e o azul com um brilho de 127 unidades, que no final era aproximadamente igual a 255 unidades:



Fita LED branca


Com fita LED, foi provavelmente o mais fácil. O único momento difícil é garantir uma mudança suave no brilho ao alterar a hora do dia.

Para implementar essa idéia, apliquei um algoritmo linear para alterar o brilho de uma faixa de LED branca.

void MainLightHelper::HandleState()
{
	if (!IsFadeWasComplete)
	{
		unsigned long currentMillis = millis();
		if (currentMillis - previousMillis > 50) {
			previousMillis = currentMillis;

			switch (CurrentLevel)
			{
			case MainLightHelper::Off:
			{
				//    ,          .
				if (currentBright != 0)
				{
					if (currentBright > 0)
					{
						currentBright--;
					}
					else
					{
						currentBright++;
					}
				}
				else
				{
					//    ,     .
					currentBright = 0;
					IsFadeWasComplete = true;
				}
				break;
			}
			case MainLightHelper::Low:
			case MainLightHelper::Medium:
			case MainLightHelper::High:
			{
				//      ,         
				if (currentBright != CurrentLevel)
				{
					if (currentBright > CurrentLevel)
					{
						currentBright--;
					}
					else
					{
						currentBright++;
					}
				}
				else
				{
					currentBright = CurrentLevel;
					IsFadeWasComplete = true;
				}
			}
			break;
			}
			
			//         .
			analogWrite(PinNum, currentBright);
		}
	}
}

Ondulação "vulcão"


A ideia de implementação me veio por acaso. Eu só queria ligar e desligar o vulcão decorativo aplicando baixa e alta tensão ao transistor. Na loja de peixes, cuidei de um bom vulcão com um tubo de saída do compressor e um LED isolado da água.



Ele veio com um adaptador, cuja saída é 12V DC e a entrada é 220V AC. Eu não precisava de um adaptador, porque implementei a energia e o brilho do vulcão através do Arduino.

A pulsação do próprio vulcão foi implementada da seguinte forma:

long time = 0;
int periode = 10000;

void VulcanusHelper::HandleState()
{
	if (IsActive){
		// time -  cos     . 
		//   -       
		time = millis();
		int value = 160 + 95 * cos(2 * PI / periode*time);

		analogWrite(PinNum, value);
	}
	else
	{
		analogWrite(PinNum, 0);
	}
}

O vulcão ilumina perfeitamente o aquário à noite e a própria ondulação parece muito bonita:



Bomba de água. Substituindo a água do aquário


Uma bomba de água ajuda a mudar rapidamente a água no aquário. Comprei uma bomba que funciona com DC 12V. A bomba é controlada através de um transistor de efeito de campo. O driver do dispositivo em si pode fazer duas coisas: ligar a bomba, desligar a bomba. Ao implementar o driver, simplesmente herdei da classe base BaseOnOfDeviceHelper e não defini mais nada no driver. Todo o algoritmo do dispositivo pode muito bem implementar a classe base.


Eu testei a bomba no estande:



Embora a bomba funcionasse bem, me deparei com uma coisa não óbvia. Se você bombear água para outro tanque, a lei dos vasos comunicantes começará a ser aplicada. Como resultado, eu me tornei o culpado pela inundação na sala, porque se você desligar a bomba, a água ainda irá para outro tanque, se o nível da água estiver abaixo do nível da água no aquário. No meu caso, foi exatamente isso.

Porta infravermelha e o desejo de substituí-la


Realizei o gerenciamento do aquário via infravermelho, seguindo o exemplo de treinamento preliminar. A essência do exemplo é a seguinte: quando ligo o controlador na rede, interrogo as ações de esquerda, direita, cima, baixo, ok. O usuário escolhe quais botões do controle remoto ele associa a cada uma das ações. A vantagem dessa implementação é a capacidade de vincular qualquer controle remoto desnecessário.
O aquário é treinado pelo método Learn, cuja essência é exibida abaixo:

void ButtonHandler::Learn(IRrecv* irrecvLink, LiquidCrystal* lcdLink)
{
	//      
	irrecvLink->enableIRIn();
	
	//       
	decode_results irDecodeResults;
	...
	...
		while (true) {
		//       
		if (irrecvLink->decode(&irDecodeResults)) {
						
			//   
			irrecvLink->resume();

			//     .
			if (irDecodeResults.bits >= 16 && 
				irDecodeResults.value != 0xC53A9966// fix for Pioneer DVD
				) {
			
				lcdLink->setCursor(0, 1);
				//        HEX
				lcdLink->print(irDecodeResults.value, HEX);
				
				//     Arduino  
				irRemoteButtonId = irDecodeResults.value;
				
				...
				...

Mais tarde, cheguei à conclusão de que o controle remoto é inconveniente. Só porque você precisa procurá-lo e este é um dispositivo extra em casa. É melhor implementar o controle por meio de um telefone celular ou tablet. Tive a ideia de usar o microcomputador Raspberry PI para aumentar o aplicativo da Web ASP.NET MVC 5 através do Mono e do NancyFX. Em seguida, use a estrutura móvel jquery para aplicativos da web multiplataforma. Através do Raspberry, comunique-se com o Arduino via Wi-Fi ou LAN. Nesse caso, você pode até abandonar a tela LCD, porque todas as informações necessárias podem ser visualizadas em um smartphone ou tablet. Mas este projeto está apenas na minha cabeça.

Placa de circuito impresso e sua fabricação


De uma maneira ou de outra, cheguei à conclusão de que precisamos fazer uma placa de circuito impresso. Isso aconteceu depois que tantos fios apareceram no meu suporte que, ao montar o dispositivo acabado, alguns deles começaram a se desconectar da pressão acidental de outros fios. Isso acontece de forma invisível aos olhos e pode levar a resultados incompreensíveis. E a aparência de tal dispositivo deixou muito a desejar.

Montagem em placas de circuito (usada pelo Arduino Uno):



desenvolvi uma PCB de camada única no programa Fritzing. Aconteceu o seguinte (usando o Arduino Mega):



A coisa mais desagradável de se fazer uma placa de circuito era perfurar. Especialmente quando tentei criar uma placa de circuito do tipo Shield, ou seja, ela estava usando um arduino. Fazer mais de 50 furos com uma broca fina é uma tarefa tediosa. E o mais difícil é pegar o ferro novo da esposa e convencê-lo a comprar uma impressora a laser.

A propósito, se alguém tem medo da tecnologia de passar a laser, direi imediatamente que é muito simples. Fiz isso na primeira vez:



a montagem em si também era simples - bastava soldar os principais componentes da placa:



mas, apesar disso, a primeira e a última vez que criei uma placa de circuito impresso em casa. No futuro, encomendarei apenas na fábrica. E provavelmente você terá que dominar algo mais difícil do que Fritzing.

Conclusão


O projeto de firmware do aquário está disponível no GitHub . Adaptado para o Arduino Mega. Ao usar o Uno, você precisa se livrar de algumas das funcionalidades. Simplesmente não há memória, desempenho e pinos livres suficientes para conectar todos os módulos.

Source: https://habr.com/ru/post/pt387017/


All Articles