Automatische Aquariensteuerung auf Arduino

Ich möchte meine ersten Erfahrungen mit der Schaffung eines Arduino-Aquariums teilen. Früher habe ich überhaupt nicht mit Elektronik gearbeitet und außerdem wusste ich nicht, wie Mikrocontroller programmiert sind. Trotzdem habe ich mich entschlossen, mich zu versuchen und möchte die Ergebnisse teilen.



Die Idee, ein Aquarium zu schaffen


Es ist einfach so passiert, dass ich hauptsächlich an der .NET-Programmierung beteiligt war und gelernt habe, C ++ zu umgehen. Dies ist wahrscheinlich der Grund, warum ich nie auf Mikroschaltungen und Mikrocontroller gestoßen bin, obwohl der Wunsch, sie kennenzulernen, fast jedes Jahr wuchs. Besonders in den letzten Jahren, als ich von Arduino erfuhr. Es war jedoch notwendig, eine praktische Anwendung für ihn zu finden. Und dieses Problem wurde schnell behoben.

In unserem Zimmer gibt es ein Aquarium, und wir mussten jeden Tag unter den Tisch klettern, das Licht für den Fisch ausschalten und es dann morgens einschalten. Außerdem mussten die Fische die Heizung einschalten, wenn sie kalt waren, und sie ausschalten, wenn sie warm waren. Manchmal führte meine Vergesslichkeit zum Tod von Fischen im Aquarium und musste neue kaufen. Sogar die Fische mussten regelmäßig 2/3 des Wassers wechseln. Und für unser Aquarium war dieses Verfahren sehr lang und unangenehm.

Zunächst habe ich mir vorgefertigte Lösungen für Aquarien angesehen. Da sind viele von denen. Dies sind hauptsächlich Videos auf Youtube. Es gibt auch sehr interessante Artikel über Geektimes. Aber für meinen Zweck - die Welt der Mikroschaltungen zu studieren und kennenzulernen - war es zu kompliziert, und eine detaillierte Anleitung „von Grund auf neu“ wurde im Internet nicht gefunden. Die Idee, einen Aquarium-Controller zu entwickeln, musste verschoben werden, bis die Grundlagen der Mikroelektronik selbst untersucht wurden.

Bekanntschaft mit Mikroelektronik


Ich begann meine Reise mit einem vorgefertigten Kit zum Erlernen von Arduino. Wahrscheinlich hat jeder etwas Ähnliches gesammelt, als er diese Plattform kennengelernt hat: Eine



gewöhnliche Glühbirne (LED), einen 220-Ohm-Widerstand. Arduino steuert die Glühbirne mithilfe eines C ++ - Algorithmus. Machen Sie sofort eine Reservierung, dass es unmöglich ist, eine mehr oder weniger nützliche Sache zusammenzubauen, nachdem Sie ein fertiges Arduino-Set oder ein analoges Produkt gekauft haben. Nun, bis auf den Hochtöner oder beispielsweise ein Heimthermometer. Es ist möglich, die Plattform selbst durch Lektionen zu lernen, aber nicht mehr. Für nützliche Dinge haben hatte ich löten, Leiterplatten, Design von Leiterplatten und anderen elektronischen Köstlichkeiten zu lernen.

Bauen Sie Ihren ersten Aquarium-Prototyp


Das erste, was ich mit meinem Prototyp-Aquarium begann, war die Formulierung der Papieranforderungen für dieses Gerät.

Das Aquarium sollte:

  1. , , ;
  2. , , ( ) ;
  3. ( ) ;
  4. , , ;
  5. « »
  6. ;
  7. . , 9:00 AM;
  8. , ;
  9. .
  10. Der Bildschirm mit dem Datum, an dem Sie die Taste auf der Fernbedienung drücken, sollte hervorgehoben sein. Wenn innerhalb von 5 Sekunden nichts gedrückt wird, gehen Sie aus.

Ich beschloss, zunächst die Funktionsweise von LCD und Arduino zu untersuchen.

Erstellen Sie das Hauptmenü. LCD-Betrieb


Für LCD habe ich mich für die LiquidCrystal-Bibliothek entschieden. Zufälligerweise hatte ich neben Arduino auch einen LCD-Bildschirm in meinem Kit. Er konnte Text und Zahlen ausgeben. Das war genug und ich begann die Verbindung dieses Bildschirms mit dem Arduino zu untersuchen. Ich habe die grundlegenden Verbindungsinformationen von hier genommen . Es gibt auch Beispiele für Code für die Ausgabe von "Hello World".

Nachdem ich mich ein wenig mit dem Bildschirm beschäftigt hatte, beschloss ich, das Hauptmenü des Controllers zu erstellen. Das Menü bestand aus folgenden Elementen:

  1. Grundinformation;
  2. Zeiteinstellung;
  3. Datumseinstellung;
  4. Temperatur;
  5. Klima;
  6. Hintergrundbeleuchtung
  7. Geräte

Jedes Element ist ein bestimmter Informationsmodus, der auf dem LCD-Textbildschirm ausgegeben wird. Ich wollte die Möglichkeit ermöglichen, ein mehrstufiges Menü zu erstellen, in dem jede Unterebene ihre eigene Implementierung der Ausgabe auf dem Bildschirm hat.

Tatsächlich wurde die Basisklasse in C ++ geschrieben, von dem alle anderen Untermenüs geerbt werden.

 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();
};

Für das Menü "Geräte" sieht die Implementierung der qQuariumMode-Basisklasse beispielsweise folgendermaßen aus:

#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();
};

Hier ist das Ergebnis der Implementierung der ersten Ebene des Menüs:



Hardware-Teil. Die Nuancen verbindender Komponenten


Ich möchte ein paar Worte zur Hardware des Aquarium-Controllers sagen. Für den normalen Betrieb des Controllers musste ich kaufen:

  1. 1 x Arduino Uno / Mega. Später beschloss er, mit Mego zu arbeiten;
  2. 1 x Echtzeituhr, zum Beispiel 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;

Jede Komponente hat ihren eigenen Verbindungstyp und ihre Treiber für den Betrieb. Ich werde die Nuancen des Verbindens aller Komponenten nicht beschreiben, da sie auf der Website des Herstellers oder in den Foren zu finden sind. Wenn Sie die gleichen Komponenten wie ich verwenden möchten, müssen Sie den Quellcode nicht ändern.

Verderb von Bauteilen


Seien Sie vorsichtig. Versuchen Sie zuerst, etwas über die Plug-In-Komponente zu lesen. Es muss genau in dem Spannungsbereich betrieben werden, für den es erstellt wurde. Dies wird normalerweise auf der Website des Herstellers angegeben. Während ich den Aquarium-Controller entwickelte, zerstörte ich 2 versiegelte Temperatursensoren und eine Echtzeituhr. Die Sensoren fielen aus, weil ich sie an 12 V angeschlossen hatte und 5 V erforderlich waren. Die Echtzeituhr starb aufgrund eines "zufälligen" Kurzschlusses im Stromkreis aufgrund meines Fehlers.

RGB LED Strip


Besondere Schwierigkeiten traten bei LED-Streifen auf. Ich habe versucht, das folgende Schema zu implementieren:



Bei der Verbindung mit Arduino habe ich Pins verwendet, die PWM (Pulse Width Modulation) unterstützen. Während ich gleichzeitig die maximale Spannung aller 3 Pins einschaltete, war mein Band sehr heiß. Wenn Sie es ein oder zwei Stunden stehen lassen, leuchten einige LEDs nicht mehr. Ich glaube, dass dies auf den Ausfall einiger Widerstände zurückzuführen war. Ein weiterer Nachteil dieses Schemas ist die unterschiedliche Helligkeit des LED-Streifens für jede der Farben. Wenn ich zum Beispiel die maximale Spannung an die rote Komponente des Bandes lege, erhalte ich die bedingte Helligkeit der Bürokratie bei 255 Einheiten. Wenn ich sowohl die rote als auch die blaue Komponente bei maximaler Spannung einschalte, beträgt die Helligkeit 255 + 255 = 510 Einheiten und die Farbe ist lila. Im Allgemeinen passte diese Lösung nicht zu mir.

Es wurde beschlossen, den folgenden Algorithmus zu implementieren:

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);
	}	
}

In dieser Ausführungsform hatten die rote Farbe und die violette Farbe die gleiche Helligkeit. Jene. rote LEDs leuchteten im ersten Fall mit einer Helligkeit von 255 Einheiten, und mit violetter Farbe war Rot mit einer Helligkeit von 127 Einheiten und Blau mit einer Helligkeit von 127 Einheiten, was am Ende ungefähr 255 Einheiten entsprach:



LED-Streifen weiß


Mit LED-Streifen war es wahrscheinlich das einfachste. Der einzige schwierige Moment besteht darin, beim Ändern der Tageszeit eine gleichmäßige Helligkeitsänderung sicherzustellen.

Um diese Idee umzusetzen, habe ich einen linearen Algorithmus zum Ändern der Helligkeit eines weißen LED-Streifens angewendet.

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);
		}
	}
}

Welligkeit "Vulkan"


Die Idee zur Umsetzung kam mir zufällig. Ich wollte nur den dekorativen Vulkan ein- und ausschalten, indem ich den Transistor mit Niederspannung und Hochspannung versorgte. Im Fischgeschäft habe ich mich um einen guten Vulkan mit einem Auslaufrohr für den Kompressor und einer vom Wasser isolierten LED gekümmert.



Es wurde mit einem Adapter geliefert, dessen Ausgang 12 V DC und dessen Eingang 220 V AC beträgt. Ich brauchte keinen Adapter, weil ich die Leistung und Helligkeit des Vulkans über Arduino implementiert habe.

Das Pulsieren des Vulkans selbst wurde wie folgt durchgeführt:

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);
	}
}

Der Vulkan beleuchtet das Aquarium abends perfekt und die Welligkeit selbst sieht sehr schön aus:



Wasserpumpe. Aquarienwasser ersetzen


Eine Wasserpumpe hilft, das Wasser im Aquarium schnell zu wechseln. Ich habe eine Pumpe gekauft, die mit 12 V Gleichstrom betrieben wird. Die Pumpe wird über einen Feldeffekttransistor gesteuert. Der Treiber für das Gerät selbst kann zwei Dinge tun: Pumpe einschalten, Pumpe ausschalten. Bei der Implementierung des Treibers habe ich einfach von der Basisklasse BaseOnOfDeviceHelper geerbt und nichts anderes im Treiber definiert. Der gesamte Algorithmus des Geräts kann die Basisklasse gut implementieren.


Ich habe die Pumpe am Stand getestet:



Obwohl die Pumpe gut funktionierte, stieß ich auf eine nicht offensichtliche Sache. Wenn Sie Wasser in einen anderen Tank pumpen, gilt das Gesetz der Kommunikation von Schiffen. Infolgedessen wurde ich der Schuldige der Flut im Raum, denn wenn Sie die Pumpe ausschalten, wird das Wasser immer noch in einen anderen Tank geleitet, wenn sein Wasserstand unter dem Wasserspiegel im Aquarium liegt. In meinem Fall war es genau das.

Infrarotanschluss und der Wunsch, ihn zu ersetzen


Ich habe die Verwaltung des Aquariums über Infrarot nach dem Vorbild der Vorschulung durchgeführt. Das Wesentliche des Beispiels ist wie folgt: Wenn ich den Controller im Netzwerk einschalte, frage ich die Aktionen von links, rechts, oben, unten, ok ab. Der Benutzer wählt aus, welche Fernbedienungstasten er den einzelnen Aktionen zuordnet. Der Vorteil dieser Implementierung ist die Möglichkeit, unnötige Fernbedienungen zu binden.
Das Aquarium wird durch die Lernmethode trainiert, deren Essenz unten dargestellt wird:

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;
				
				...
				...

Später kam ich zu dem Schluss, dass die Fernbedienung unpraktisch ist. Nur weil Sie danach suchen müssen und dies ein zusätzliches Gerät im Haus ist. Es ist besser, die Steuerung über ein Mobiltelefon oder Tablet zu implementieren. Ich hatte die Idee, den Raspberry PI-Mikrocomputer zu verwenden, um die ASP.NET MVC 5-Webanwendung über Mono und NancyFX darauf zu starten. Verwenden Sie als Nächstes das mobile jquery-Framework für plattformübergreifende Webanwendungen. Kommunizieren Sie über Raspberry mit Arduino über WLAN oder LAN. In diesem Fall können Sie den LCD-Bildschirm sogar verlassen, da alle erforderlichen Informationen auf einem Smartphone oder Tablet angezeigt werden können. Aber dieses Projekt ist nur in meinem Kopf.

Leiterplatte und ihre Herstellung


Auf die eine oder andere Weise kam ich zu dem Schluss, dass wir eine Leiterplatte herstellen müssen. Dies geschah, nachdem so viele Drähte auf meinem Stand erschienen waren, dass sich einige beim Zusammenbau des fertigen Geräts vom versehentlichen Druck anderer Drähte zu lösen begannen. Dies geschieht unsichtbar für die Augen und kann zu unverständlichen Ergebnissen führen. Und das Aussehen eines solchen Geräts ließ zu wünschen übrig.

Montage auf Leiterplatten (von Arduino Uno verwendet):



Ich habe im Fritzing-Programm eine einschichtige Leiterplatte entwickelt. Es stellte sich Folgendes heraus (unter Verwendung von Arduino Mega):



Das Schlimmste an der Herstellung einer Leiterplatte war das Bohren. Insbesondere, als ich versuchte, eine Shield-Leiterplatte zu erstellen, d.h. Sie zog sich ein Arduino an. Das Bohren von mehr als 50 Löchern mit einem dünnen Bohrer ist eine mühsame Aufgabe. Und das Schwierigste ist, ihr neues Eisen von seiner Frau zu holen und ihn zum Kauf eines Laserdruckers zu überreden.

Übrigens, wenn jemand Angst vor der Laserbügeltechnologie hat, sage ich sofort, dass dies sehr einfach ist. Ich habe es das erste Mal gemacht:



Die Montage selbst war auch einfach - es war genug, um die Hauptkomponenten auf die Platine zu löten:



Trotzdem habe ich das erste und letzte Mal zu Hause eine Leiterplatte erstellt. In Zukunft werde ich nur noch im Werk bestellen. Und höchstwahrscheinlich müssen Sie etwas Schwierigeres als Fritzing meistern.

Fazit


Das Aquarium-Firmware-Projekt ist auf GitHub verfügbar . Angepasst an Arduino Mega. Wenn Sie Uno verwenden, müssen Sie einige der Funktionen entfernen. Es gibt einfach nicht genug Speicher, Leistung und freie Pins, um alle Module zu verbinden.

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


All Articles