Der Flowgrow Aquacomp

MajorMadness

Active Member
Hallo zusammen,
angelehnt an den Beitrag von Riff Aquaristik und durch meine Bastelei grade möchte ich für Flowgrow auch mal das Projekt eines AQ Computers starten.
Schwerpunkt hierbei soll natürlich auf den Pflanzen liegen und uns das Düngen und die AQ Steuerung abnehmen. Gplant ist dies ebenfalls als Roll up Treat zum nachbauen. Ich fange also an mit den Basics und wir werden das Projekt immer erweitern bis der Comuter fertig ist. Einfach zum nachbauen und/oder nachvollziehen um selbst etwas zu entwickeln.

Am Anfang aber eine Warnung:
Wir werden mit Strom im AC und DC Bereich mit bis zu 250Volt arbeiten, Kabel anschliessen, löten und mit Temperaturen über 70° uns beschäftigen müssen. Dies sollte nur mit Kenntnissen oder unter aufsicht geschehen!

Fangen wir also einmal an mit der ersten Planung. Was wollen wir am Ende haben?
Eine AQ Steuerung. Toll, das kann alles sein, also bischen genauer. Was wollen wir steuern?
Licht. Klar, ohne das wachsen Pflanzen ja nicht.
Dünger. Jup den brauchen wir.
Temperatur. Klar, mir ist ja auch grade kalt.
PH. Sehr wichtig für gutes Pflanzenwachstum.
Mondlicht/Sonnen auf-, untergang. Warum eigentlich nicht?
Verlaufskurve der Werte. Wir wollen ja nicht immer aufs Display schauen.
Display. Worauf sollen wir sonst schauen?
Filterkontrolle? Füllstand? Wasserwechsel? Warten wir mal ab...
Jemand noch Ideen was ein must have ist? Postet es und wir werden schauen. :bier:


Nun dann, Genug der Einführung, wir wollen beginnen.
Zuerst brauchen wir einmal das Herzstück. Wie manche schon ahnen wird dies ein Arduino sein. Gründe sind ganz einfach:
Er ist klein, einfach zu programmieren (Programmierkenntnisse voraus gesetzt, ansonsten viel probieren), nicht zu teuer, einfach zu beschaffen und zu erweitern.
Ich hab mich für das Mega2560 Board entschieden da es 40 Digital Pins, 14 weitere Digital PWM und 16 Analoge Inputs hat. Kostet in China 15€, Deutsches Lager 25€, Deutscher Shop 47€.
Als nächstes brauchen wir dann noch einige andere sehr wichtige Grund Dinge: eine Uhr (RTC -> Real Time Clock), Breatboard (Steckbrett) zum testen, Jumper wires (Steckbrettkabel) und wer für später schn mitkaufen möchte eine Leiterplatte (Streifen oder IC-Platine), Kabel (Telefonkabel mit Rot,Gelb,Schwarz,Weiss,Grün,Braun ist klasse und günstig), Stiftleisten, Stecker. Das müsste es erstmal sein. Finden können wir alles in der Bucht oder bei Contrad. Wer in der Bucht grade surft und über etwas stolpert was sich TIP122 (10x), BC547 (20x), BC557 (5x), PCF8574 (2x), LM324 (4x) heisst kann das in einem mit bestellen. Wir werden nicht alles brauchen, aber die Menge kommt so schon hin.
Ausserdem werden wir noch Elkos (4,7µF,10µF,und paar andere) und Widerstände (3,3ohm, 1k, 2,2k, 10k, 22k, 200ohm und andere) brauchen. Dann noch nen paar Minitaster, Potis (10k) und natürlich Lötkolben, Cuttermesser, Zinn, Voltmeter und viiiiiel Geduld.

Jetzt gehts aber endlich los:
Die Uhr: Welche nehmen wir? Im Prinzip haben wir 3 Möglichkeiten. Wir holen uns ein fertiges RTC-Modul (Breackout) mit DS1307 Chip, wir besorgen uns den DS1307+Quarz+Batterie einzeln oder wir versuchen den Ti BQ3200 + Quarz und Batterie zu bekommen. (Kleiner Tip hier am Rande -> Texas Instrument hat nen Free Sample Programm wo man immer mal wieder gute Chips für lau bekommt ;) )
Auch wenn das Löten der eigenen RTC nicht so schwer ist, fangen wir doch mal einfach an und nehmen das fertige Modul. Kostet 8€ bei Komputer.de und ist das einfachste. Kommentare wie "oder in der Bucht" spar Ich mir ab sofort direkt und verlinke nur noch Shops. :cool:
Stecker oder Kabel müssen wir leider trotzdem dran Löten (zumindest bei meiner) und dann können wir das anschliessen.
5V an 5V
Ground an Ground
SDA an SDA (Mega Pin 20)
SDL an SDL (Mega Pin 21)
Wir laden uns die DS1307 lib ins lib verzeichniss und Starten nen Test Scratch. Und siehe da: Nix klappt. Komische Zeichen und Schrott. Also Modul kaputt und neues gekauft. STOP! Nein das ist leider etwas was passieren kann. probiert daher die DS1307new aus. Es war auch die einzige lib die bei mir die Uhr ans laufen brachte...
Wer nicht weis was Ich hier grade schreibe oder wovon ich rede, der möchte bitte einmal unter http://arduino.cc/en/Guide/HomePage nachlesen.

Sodale, wir haben viel geschafft. Ne menge Geld ausgegeben und eine Uhr gebaut die nur am PC läuft. Naja, wir haben nen Beispiel geöffnet. Damit das für uns etwas nützliches ergibt legen wir uns einmal ein neues Projekt an wo wir unsere Sachen Speichern.
Also Datei/Neu geklickt, dann Datei/Speichern unter und nen kreativen Namen überlegen. Meins heist "Mein AQ"... Sehr kreativ. :stumm:
In unserem neuen Sketch können wir dann erstmal ne Basisstruktur aufbauen:
Code:
#include <Wire.h>  
#include <DS1307new.h>    // Unsere Uhr

// ********************************************* //
//                 VARIABLES                     //
// ********************************************* //
uint16_t startAddr = 0x0000;            // Start address to store in the NV-RAM
uint16_t lastAddr;                      // new address for storing in NV-RAM
uint16_t TimeIsSet = 0xaa55;            // Helper that time must not set again

float timestamp = 0;

// Hilfe für Loop ohne Delay -> mach nur was wenn es eine neue Sekunde ist
int loopTime =0;

// ********************************************* //
//       Sensor Variablen und Pin Layout         //
// ********************************************* //


// ********************************************* //
//                   Main Code                   //
// ********************************************* //


void setup() {
  Serial.begin(9600);    // Ausgabe am PC
  pinMode(2, INPUT);                    // Test of the SQW pin, D2 = INPUT
  digitalWrite(2, HIGH);                // Test of the SQW pin, D2 = Pullup on
  
  
}

void loop() {
	RTC.getTime();    // Aktuelle Uhrzeit holen
	if(loopTime !=int(RTC.second)){            // Kleine Hilfe das wir nicht immer alles machen müssen.
	    loopTime =int(RTC.second);
	}

}
Wow, das sieht ja schon mal toll aus.
Erklärbär":i8sgm20c schrieb:
#include "name.h" bindet Headerfiles von anderen Libaries ein.

Wenn wir eine Variable benutzen wollen müssen wir diese erstmal unserem Programm bekannt machen und sagenwas es ist. Type Name; ODER Type Name = Wert; <= ";" am ende ganz wichtig ;)
Hierbei ist zu beachten:
Variablen verbrauchen Speicher. wenn Ich die Zahl 3 in nem float speichere verbraucht das 4byte (0.0000038147 MB) es würde aber auch ein int tuen (2byte). Spart euch Platz für später ;)
Variablen sind type spezifisch. D.h. float a= 6; int b = 3; long c = a-b; großer scheiss... Besser vorher nachdenken und wenn nötig "typecasten". D.h. long c= long(a-float(b)); (Behandel b als float und behandel die rechnung als long)
Wer Klugscheissen möchte: Jup ich weis kann man besser ausdrücken und erklären, so isset aber verständlich und das wissen reicht (erstmal).

void steht für eine funktion ohne rückgabewert. Das Schema ist immer:
Type Name ( type variablenname, type variablenname2 ) { unsercode}
Besonderheit: wenn es kein void ist muss am ende ein return gleichertype; vor } stehen.
void setup(){} MUSS da sein,
void loop(){} ist die Funktion die immer wieder aufgerufen wird und zwar so schnell wie möglich.
Ich finde sauberen Code auch ganz klasse, also legen wir uns direkt mal ne neue Datei an wo wir alles von unserer Uhr (Alle Zeit funktionen) speichern. Rechts am Rand sehen wir nen kleinen Pfeil nach unten. Draufgeklickt, Neuer Tab, kreativname (Uhr oder Clock), "OK".
Damit unsere Uhr funktioniert müssen wir diese Initialiesieren und einiges aufrufen. Der übersichtshalber machen wir das in der Datei Clock:
Code:
void setupClock(){
  RTC.setRAM(0, (uint8_t *)&startAddr, sizeof(uint16_t));// Store startAddr in NV-RAM address 0x08 

// Set new Time Value
/*
  TimeIsSet = 0xffff;
  RTC.setRAM(54, (uint8_t *)&TimeIsSet, sizeof(uint16_t));  
*/

  RTC.getRAM(54, (uint8_t *)&TimeIsSet, sizeof(uint16_t));
  if (TimeIsSet != 0xaa55){
    RTC.stopClock();
        
    RTC.fillByYMD(2012,12,31);  // year,month,day
    RTC.fillByHMS(2,27,0);  //hour,min,sek
    
    RTC.setTime();
    TimeIsSet = 0xaa55;
    RTC.setRAM(54, (uint8_t *)&TimeIsSet, sizeof(uint16_t));
    RTC.startClock();
  }else{
    RTC.getTime();
  }

/*
   Control Register for SQW pin which can be used as an interrupt.
*/
  RTC.ctrl = 0x00;   // 0x00=disable SQW pin, 0x10=1Hz, 0x11=4096Hz, 0x12=8192Hz, 0x13=32768Hz
  RTC.setCTRL();

  uint8_t MESZ;

  MESZ = RTC.isMEZSummerTime();
}

String printTime()
{
  String sReturn;
  
 // sReturn = String(int(value));
    sReturn = "";
    RTC.getTime();
  if (RTC.hour < 10) {                    // correct hour if necessary
    sReturn += "0";
    sReturn += String(int(RTC.hour));
  }else{
    sReturn += String(int(RTC.hour));
  }
    sReturn += ":";
  if (RTC.minute < 10) {                  // correct minute if necessary
    sReturn += "0";
    sReturn += String(int(RTC.minute));
  }else{
    sReturn += String(int(RTC.minute));
  }
    sReturn += ":";
  if (RTC.second < 10) {                  // correct second if necessary
    sReturn += "0";
    sReturn += String(int(RTC.second));
  }else{
    sReturn += String(int(RTC.second));
  }
  /*
  Serial.print(" ");
  if (RTC.day < 10) {                    // correct date if necessary

    Serial.print("0");
    Serial.print(RTC.day, DEC);
  }else{
    Serial.print(RTC.day, DEC);
  }
  Serial.print("-");
  if (RTC.month < 10)                   // correct month if necessary
  {
    Serial.print("0");
    Serial.print(RTC.month, DEC);
  }
  else
  {
    Serial.print(RTC.month, DEC);
  }
  Serial.print("-");
  Serial.print(RTC.year, DEC);          // Year need not to be changed
  Serial.print(" ");
  switch (RTC.dow)                      // Friendly printout the weekday
  {
    case 1:
      Serial.print("MON");
      break;
    case 2:
      Serial.print("TUE");
      break;
    case 3:
      Serial.print("WED");
      break;
    case 4:
      Serial.print("THU");
      break;
    case 5:
      Serial.print("FRI");
      break;
    case 6:
      Serial.print("SAT");
      break;
    case 7:
      Serial.print("SUN");
      break;
  }
  Serial.print(" seconds since 1.1.2000:");
  Serial.print(RTC.time2000, DEC);
  uint8_t MESZ = RTC.isMEZSummerTime();
  Serial.print(" MEZ=0, MESZ=1 : ");
  Serial.print(MESZ, DEC);  
  
  Serial.print(" - Address in NV-RAM is: ");
  RTC.getRAM(0, (uint8_t *)&lastAddr, sizeof(uint16_t));
  Serial.print(lastAddr, HEX);
  lastAddr = lastAddr + 1;              // we want to use it as addresscounter for example
  RTC.setRAM(0, (uint8_t *)&lastAddr, sizeof(uint16_t));
  RTC.getRAM(54, (uint8_t *)&TimeIsSet, sizeof(uint16_t));
  if (TimeIsSet == 0xaa55)              // check if the clock was set or not
  {
    Serial.println(" - Clock was set!");
  }
  else
  {
    Serial.println(" - Clock was NOT set!");
  } 
*/  
  return sReturn;
}

String printDate()
{
  String sReturn;
  
 // sReturn = String(int(value));
    sReturn = "";
    RTC.getTime();
/*  if (RTC.hour < 10) {                    // correct hour if necessary
    sReturn += "0";
    sReturn += String(int(RTC.hour));
  }else{
    sReturn += String(int(RTC.hour));
  }
    sReturn += ":";
  if (RTC.minute < 10) {                  // correct minute if necessary
    sReturn += "0";
    sReturn += String(int(RTC.minute));
  }else{
    sReturn += String(int(RTC.minute));
  }
    sReturn += ":";
  if (RTC.second < 10) {                  // correct second if necessary
    sReturn += "0";
    sReturn += String(int(RTC.second));
  }else{
    sReturn += String(int(RTC.second));
  }
*/
//  Serial.print(" ");
  if (RTC.day < 10) {                    // correct date if necessary
    sReturn += "0";
    sReturn += String(int(RTC.day));

 //   Serial.print("0");
 //   Serial.print(RTC.day, DEC);
  }else{
    sReturn += String(int(RTC.day));
 //   Serial.print(RTC.day, DEC);
  }
//  Serial.print("-");
    sReturn += ".";
  if (RTC.month < 10) {                   // correct month if necessary
    sReturn += "0";
    sReturn += String(int(RTC.month));
 //   Serial.print("0");
 //   Serial.print(RTC.month, DEC);
  }else{
    sReturn += String(int(RTC.month));
 //   Serial.print(RTC.month, DEC);
  }
    sReturn += ".";
 //   String y = String(int(RTC.year))
 //   sReturn += y.replace("20","");  // Year need not to be changed
  String DoW ="";
  switch (RTC.dow)                      // Friendly printout the weekday
  {
    case 1:
      DoW="Mo ";
      break;
    case 2:
      DoW="Di ";
 //     Serial.print("TUE");
      break;
    case 3:
      DoW="Mi ";
 //     Serial.print("WED");
      break;
    case 4:
      DoW="Do ";
 //     Serial.print("THU");
      break;
    case 5:
      DoW="Fr ";
 //     Serial.print("FRI");
      break;
    case 6:
      DoW="Sa ";
 //     Serial.print("SAT");
      break;
    case 7:
      DoW="So ";
 //     Serial.print("SUN");
      break;
  }
  sReturn = DoW+sReturn;
  /*
  Serial.print(" seconds since 1.1.2000:");
  Serial.print(RTC.time2000, DEC);
  uint8_t MESZ = RTC.isMEZSummerTime();
  Serial.print(" MEZ=0, MESZ=1 : ");
  Serial.print(MESZ, DEC);  
  
  Serial.print(" - Address in NV-RAM is: ");
  RTC.getRAM(0, (uint8_t *)&lastAddr, sizeof(uint16_t));
  Serial.print(lastAddr, HEX);
  lastAddr = lastAddr + 1;              // we want to use it as addresscounter for example
  RTC.setRAM(0, (uint8_t *)&lastAddr, sizeof(uint16_t));
  RTC.getRAM(54, (uint8_t *)&TimeIsSet, sizeof(uint16_t));
  if (TimeIsSet == 0xaa55)              // check if the clock was set or not
  {
    Serial.println(" - Clock was set!");
  }
  else
  {
    Serial.println(" - Clock was NOT set!");
  } 
*/  
  return sReturn;
}

float get_ts(int h, int m, int s){
  float r;
  uint32_t t;
  t = h;
  t *= 60;
  t += m;
  t *= 60;
  t += s;
  r=float(t);
  return r;
}
OK, was ist hier passiert? Es gibt nun eine Funktion setupClock(). Diese macht nix anderes als die Uhr (unser RTC Modul) zu initialisieren und wenn nötig ein neues Datum speichern. (Hierzu einfach ganz oben /* */ entfernen und paar zeilen drunter RTC.fillByYMD(2012,12,31); RTC.fillByHMS(2,27,0); mit eigenen werten ersetzen.)
Dann gibt es jetzt String printTime(), eine funktion die uns die Uhrzeit als string (Text) zurück gibt und String printDate() die das gleiche mit Datum macht. Ausserdem eine Funktion get_ts(int h, int m, int s). Diese rechnet uns eine Uhrzeit (z.B. 9:30) in einen Timestamp um. Dies brauchen wir später um Uhrzeiten zu vergleichen.
Man erkennt, Ich hab viel auskommentiert (// oder /*text*/), das könnte man auch löschen.
Jetzt noch mal schnell auf unsere erste Seite (MeinAQ) und die Funktion setupClock(); in die void setup() kopiert:
Code:
void setup() {
  Serial.begin(9600);    // Ausgabe am PC
  pinMode(2, INPUT);                    // Test of the SQW pin, D2 = INPUT
  digitalWrite(2, HIGH);                // Test of the SQW pin, D2 = Pullup on
  setupClock();
}
Damit das ganze auch mal Sinn ergibt was wir hier gemacht haben, Lasst uns das mal im serial Monitor ausgeben:
Code:
void loop() {
	RTC.getTime();

	if(loopTime !=int(RTC.second)){
	    loopTime =int(RTC.second);
		Serial.println (printTime());
		Serial.println (printDate());
        }
}
Mein Arduino hängt leider am AQ dran, Ihr müsstet aber jetzt jede Sekunde das Datum und die Zeit sehen.

Ich mach an der stelle Jetzt mal schluss, wenn es euch gefällt setz Ich mich die Tage wieder dran und es geht weiter.

Beste Grüße
 

RobertS

Member
Hallo Moritz,

genau über so ein Projekt dachte ich gestern auch nach, allerdings auf Basis vom Raspberry Pi. Fehlende RTC und höherer Komplexität (Abstürze!) sprechen aber wirklich mehr für Arduino.

Ich finde es jedenfalls klasse, dass du dir die Mühe machst :thumbs: und sobald ich wieder mehr Zeit habe werde ich sehen, ob ich dem Projekt folgen kann. Mich interessiert vor allem die Steuerung von 3 ZSU und das Dimmen von 2 LED-Feldern. Richtig deluxe wäre natürlich Steuerung und Kontrolle über WLAN/BT...
Liebe Grüße
-Robert
 

ClaRod

Member
Re: AW: Der Flowgrow Aquacomp

Hi Moritz!

Tolles Projekt und super erklärt. Werde auf jeden Fall treuer Mitleser und wer weiß...vielleicht muss meine Logo dann ja doch irgendwann mal weichen ;)
Auf jeden Fall aber: weiter so!!!

Gruß

Claudius
 

*AquaOlli*

Member
Hallo Moritz,

das find ich super. Genau das hab ich nämlich auch vor, nur leider fehlte mir in letzter Zeit etwas die Zeit. Ich hab schon ein großen Teil an Klamotten hier Zuhause liegen. Unter anderem das Mega2560, das Uno, eine Relaiskarte für die Pumpen, ein RTC-Modul und noch eine Ethernet W5100 mit Speicherkarte. Achja und erstmal ein 16x2 LCD Keypadshield zum warm werden. Du hast jetzt meine volle Aufmerksamkeit... :)
 

MajorMadness

Active Member
Freut mich das es welche gibt dehnen das gefällt.
Es wird auch balt weiter gehen nur um es besser nach zu bauen musste ich auch erstmal teile kaufen. Nächster schritt wird dann die Düngung sein.
Also wer will schonmal nach Dosierpumpen schauen (s.h, mein posting von der Abdeckung), 3er Leiterplatte, Tip122 Transistoren und ein 5 und 12 Volt Netzteil brauchen wir auch. Aach und natürlich Lötkolben.

Bis denne dann

Ach Robert: was Ist ne zsu?
 

RobertS

Member
Sorry, war etwas schreibfaul - die Abkürzung steht für Zeitschaltuhr. In diesem Fall geht es aber eher um schaltbare Steckdosen.
Ich weiß es kommt eher zuletzt, aber hast du dir zum Thema Gehäuse schon Gedanken gemacht?
Gruß
-Robert
 

MajorMadness

Active Member
Aso, naja, zsu werden wir in diesem sinne nicht haben, dafür schalten wir relais wenn wir strom bauchen.
Mein aqua comp ist in der abdeckung eingebaut. Aber win 10x20x6 cm gehäuse(conrad) sollte reichen für elektrik. Netzteile für leds, dosierpumpen ect brauchen mehr platz. Und wohin mit den 6düngerflaschen?
 

MajorMadness

Active Member
So, pünktlich zum WE gehts dann mal weiter für alle die die noch nix vor haben.
Also was haben wir bis jetzt? Ne nutzlose uhr die uns die Zeit nur anzeigt wenn wir die Uhr im Taskmanager auch sehen könnten. Vom AQ Computer noch nen ganzes Stück weg, dafür aber eine super Grundlage mit paar kniffen etwas zu bauen was viele Sich schon immer gewünscht haben: Eine Automatiesierte Düngung.
Also überlegen wir einmal was wir dafür bräuchten?
Dosierpumpen, Düngebehälter. Alles andere ist ja dann nur an/aus. Aber moment... Unser Arduino hängt am USB Port. Also müssen wir uns jetzt erstmal um nen Netzgerät kümmern. Ich empfehle hier nen Günstiges 6-12V Netzteil mit 1A. Das reicht vollkommen und hat der eine oder andere sicher noch rumliegen. Bitte nur nicht mehr als 12V benutzen, auch nicht "mal kurz" versuchen!
2tes Problem: Unsere Dosierpumpen und einiges andere braucht entweder 5V oder 12V und dann uch noch 80-400mA. Wer sich schonmal mit dem Arduino auseinander gesetzt hat stellt fest das dieser nur 40mA am digital ausgang liefern kann und das bei 40mA... Klappt also alles nicht so wirklich. Also muss noch nen Netzteil her. Hierbei hätten wir nun paar möglichkeiten:
1. Wir holen uns nen netzteil mit 5 und 12V z.B. http://www.elpro.org/shop/shop.php?p=PS ... 205V%2012V
2. Wir holen uns ein 5V und ein 12V Steckernetzteil
3. Wir schauen mal ob wir noch nen älteres Externes Festplatten NT haben. diese haben praktischer weise 12V und 5V mit einem gemeinsamen Ground und liefern genug Ampere. Wer sich nicht sicher ist, schaut mal auf die Rückseite, wenn da 5V/12V steht habt Ihr Glück.
Dann gehts weiter: Wie schliessen wir alles an? naja wir können alles auf nen Breatboard stecken. Wenn es Größer oder mehr wird aber nicht so prickelnd. Der Arduino ist zwar suber geeignet um Shields zusammen zu stecken, aber finden wir genau das was wir suchen? Leiter nicht. Also müssen wir uns mal mit Löten auseinander setzen.
Dort haben wir 3 möglichkeiten wieder:
Lochraster, Streifenraster oder was Ich empfehle http://www.conrad.de/ce/de/product/5305 ... 0&ref=list - 3er Raster. Weniger zum durchtrennen, gut geeignet für das meiste was wir machen wollen.
Nun dann, für heute brauchen wir nur noch 2 dinge:
ein paar TIP122, 1K Widerstände und und natürlich unsere Dosierpumpen... Doch welche? Naja es gehen alle die <60ml/Min Pumpen, Ich empfehle aber DIESE. Nebenbei: Dieser Verkäufer ist klasse.
So, Ich glaube Ich hab nix vergessen, also lasst uns anfangen:

Als erstes Löten wir uns auf einer seite Der platine 3 durchgehende Bahnen. Diese sind für 12V+, 5V- und Ground. Das nimmt uns nen bisschen Arbeit ab da wir Ground und die beiden Spannungen öffters brauchen. Außerdem können wir uns noch Stecker an eine Seite Löten. Ich hab mich für Schraubklemmen entschieden. So kann Ich später besser Kabel mal tauschen und es ist Trotzdem sicherer als Stecker.
Dann sollten wir, bevor wir die TIP verlöten mal nen Blick ins Datenblatt werfen und mal google Bilder nach nem Beispiel durchsuchen. Ok dadurch wissen wir das wir Base links haben, der Collector ist in der Mitte und Rechts der Emitter. Und das bedeutet?
Erklärbär":1xxv7mig schrieb:
Transistoren funktionieren fast alle gleich (zumindest die die wir benutzen). Spannung am Base pin Schaltet den Transistor. dadurch kann Strom vom Collector zum Emitter fliessen (oder nicht). Wichtig ist zu wissen wieviel Spannung benötigt wird damit der Transistor schaltet und wieviel er schalten kann. Beim TIP122 z.b. sind das 2mA um maximal 5A zu schalten. Der BC547 kann maximal 100mA schalten.
Ausserdem gibt es 2 Arten: PNP und NPN: Vereinfacht ausgedrückt kann man sagen NPN schalten an, PNP aus wenn Spannung an Base anliegt.
Mit den gesuchten Bildern der Schaltung+Datenblatt können wir uns ans Löten machen (wer sich nicht auskennt, bitte erstmal auf dem Steckbrett/Breatboard testen). Zuerst verbinden wir alles Emitter mit einaner und den letzten mit unserem Ground. Dann jeweils 1K an Base löten und die Collector Pins mit den Schraubklemmen Verlöten. Das Ganze sieht dann so aus:

Wenn Ich Zeit habe kommen nochmal bessere Bilder. Ich hoffe für im moment reicht das. So, nun können wir noch alle Pumpen parallel mit 12V verbinden und die Minus Pole an die jeweiligen Emitter. Also Pumpe1 - an den ersten TIP122 usw.
Ufta, lange geschrieben, mich hat das ne Stunde gekostet zu löten (mit allen vorbereitungen...).

Kommen wir aber zum Interesannten Teil: Wie steuern wir das jetzt? Ok, also an jeden Widerstand noch nen Kabel gelötet und das können wir dann erstmal testweise in nen digital Pin am Arduino Stecken. Später wollen wir das bisschen flexibler haben, weswegen Ich mir nen Protoshield von DF Robot gekauft hab. (http://www.komputer.de/zen/index.php?ma ... ucts_id=30) Hierdran können wir unsere Kabel fest löten und haben So ne super verbindung. Aber was soll jetzt an welchen Pin? Naja, zuerst einmal 12 und 5V an unser Netzteil und Ground vom Netzteil mit dem Arduino Ground verbinden.
Dann haben wir noch 54 digital Pins die wir eigentlich nutzen könnten. Manche davon (0-21) haben aber sonderfunktionen und auch 50-53 sind kritisch. Ich hab mir daher mal nen Pin mapping gebastelt damit Ich nicht den Überblick verliehre. Ihr findet das im Anhang. Da sthehen zwar meine gnzen Sachen schon drin, aber Ich hoffe es hilft. Die Farbigen bitte mit vorsicht geniessen. Das sind besondere Pins.
Also, im Sheet sehen wir wir wollen 27,28,29,30 und 31 benutzen. Dann bereiten wir das mal vor:
Code:
// ********************************************* //
//       Sensor Variablen und Pin Layout         //
// ********************************************* //

int pumpD1=27;
int pumpD2=28;
int pumpD3=29;
int pumpD4=30;
int pumpD5=31;
und in void Setup() noch
Code:
  pinMode(pumpD1, OUTPUT);
  pinMode(pumpD2, OUTPUT);
  pinMode(pumpD3, OUTPUT);
  pinMode(pumpD4, OUTPUT);
  pinMode(pumpD5, OUTPUT);
Was ist passiert? wir haben unseren Pins namen gegeben, haben gesagt das wir nen "Status" haben der LOW (aus) ist und haben unsere pins als outputs definiert.
Jetzt müssten wir nur noch das ganze schalten, zu ner bestimmten Zeit.
Also einmal nen neuen Tab gemacht den Wir Düngung nennen und da alle funktionen rein die mit der Düngung zu tuen haben.
Code:
void Duenung(float Daystamp){
  float duenger1 = 3.00;    // Spezial N 1ml/50L
  float duenger2 = 1.00;    // Spezial Flowgrow 2ml/100L
  float duenger3 = 2.00;    // Mikro Basis Eisen 2ml/100L
  float duenger4 = 1.00;
  float duenger5 = 3.00;    // Estimate Index 5ml/40l
  float d1Time= get_ts(9,0,0);    // 9:00
  float d2Time= get_ts(10,0,0);
  float d2Time1= get_ts(15,0,0);
  float d3Time= get_ts(11,0,0);    // 11:00
  float d4Time= get_ts(20,0,0);    // 18:00
  float d5Time= get_ts(21,0,0);    // 12:00
 
 // Pumpe 1 
  if(Daystamp>=d1Time && Daystamp<d1Time+duenger1&&pumpD1State==LOW){
    pumpD1State=HIGH;
    digitalWrite(pumpD1,pumpD1State);
  }else if((Daystamp<d1Time || Daystamp>d1Time+duenger1) && pumpD1State==HIGH){
    pumpD1State=LOW;
    digitalWrite(pumpD1,pumpD1State);
  }
 // Pumpe 2 
  if(Daystamp>=d2Time && Daystamp<d2Time+duenger2&&pumpD2State==LOW){
    pumpD2State=HIGH;
    digitalWrite(pumpD2,pumpD2State);
  }else if((Daystamp<d2Time || Daystamp>d2Time+duenger2) && pumpD2State==HIGH){
    pumpD2State=LOW;
    digitalWrite(pumpD2,pumpD2State);
  }
  if(Daystamp>=d2Time1 && Daystamp<d2Time1+duenger2&&pumpD2State==LOW){
    pumpD2State=HIGH;
    digitalWrite(pumpD2,pumpD2State);
  }else if((Daystamp<d2Time1 || Daystamp>d2Time1+duenger2) && pumpD2State==HIGH){
    pumpD2State=LOW;
    digitalWrite(pumpD2,pumpD2State);
  }
 // Pumpe 3 
  if(Daystamp>=d3Time && Daystamp<d3Time+duenger3 && pumpD3State==LOW){
    pumpD3State=HIGH;
    digitalWrite(pumpD3,pumpD3State);
  }else if((Daystamp<d3Time || Daystamp>d3Time+duenger3) && pumpD3State==HIGH){
    pumpD3State=LOW;
    digitalWrite(pumpD3,pumpD3State);
  }
  /*
 // Pumpe 4 
  if(Daystamp>=d4Time && Daystamp<d4Time+duenger4&&pumpD4State==LOW){
    pumpD4State=HIGH;
    digitalWrite(pumpD4,pumpD4State);
  }else if((Daystamp<d4Time || Daystamp>d4Time+duenger4) && pumpD4State==HIGH){
    pumpD4State=LOW;
    digitalWrite(pumpD4,pumpD4State);
  }
  */
 // Pumpe 5 
  if(Daystamp>=d5Time && Daystamp<d5Time+duenger5 && pumpD5State==LOW){
    pumpD5State=HIGH;
    digitalWrite(pumpD5,pumpD5State);
  }else if((Daystamp<d5Time || Daystamp>d5Time+duenger5) && pumpD5State==HIGH){
    pumpD5State=LOW;
    digitalWrite(pumpD5,pumpD5State);
  }
  
}
und was bedeutet das jetzt was wir da gemacht haben?
void Duenung(float Daystamp){} ist eine Funktion die aus dem loop() aufgerufen werden kann und dann die düngung steuert.
float duenger1 = 3.00; gibt die Menge an die bei einem mal düngen ins Wasser kommt. 1.2 wären 1,2ml
float d1Time= get_ts(9,0,0); // 9:00 Erkennt ihr es? Die funktion die wir uns geschrieben haben. die rechnet unsere Uhrzeit in nen Timestamp (Zeitstempel) um. (10,38,22) wären 10 Uhr 38 Minuten und 22 Sekunden oder 10:38:22 Uhr.
Dann kommt nur noch für jede Pumpe die frage ein oder ausschalten?
// Pumpe 1
if(Daystamp>=d1Time && Daystamp<d1Time+duenger1&&pumpD1State==LOW){
// Wenn unsere Zeit größer als die von pumpe 1 ist UND kleiner als zeit+menge (Da meine pumpe 1ml pro sek fördert ca.) UND die pumpe ausgeschaltet ist, dann einschalten.
pumpD1State=HIGH;
digitalWrite(pumpD1,pumpD1State);
}else if((Daystamp<d1Time || Daystamp>d1Time+duenger1) && pumpD1State==HIGH){
// falls sonst die zeit kleiner als pumpenzeit ODER grösser als zeit+düngemenge UND sie ein ist, dann ausschalten.
pumpD1State=LOW;
digitalWrite(pumpD1,pumpD1State);
}

Bei pumpe 4 Sieht man das sie immer aus ist (ausgeklammert). Schlauhe und aufmerksame haben erkannt das pumpe 2 2 mal schaltet (2 zeiten). Dafür einfach die funktion kopieren und anpassen.

Ich kann das ganze mal wieder nicht testen da mein neuer / Test Mega irgendwo zwischen hier und China ist, es sollte aber klappen. daher hier mal Meine Projektmappe als Zip. Morgen kommt noch nen Schaltplan hinzu.

Wer etwas nicht verstaanden hat, bitte nachfragen.
 

Anhänge

  • IMG_6151.JPG
    IMG_6151.JPG
    235,9 KB · Aufrufe: 14.455
  • IMG_6153.JPG
    IMG_6153.JPG
    189,9 KB · Aufrufe: 14.438
  • IMG_6152.JPG
    IMG_6152.JPG
    273,1 KB · Aufrufe: 14.430
  • Arduino Pin Mapping.xlsx
    16,7 KB · Aufrufe: 470
  • MAQ.zip
    2,9 KB · Aufrufe: 428

heiko77

New Member
Hallo,

super Projekt! Ich baue mir gerade etwas ähnliches auf Basis eines Scatterweb Knotens (http://www.mi.fu-berlin.de/inf/groups/a ... SB-A2.html). Wenn Du Unterstützung beim Programmieren brauchst, kannste gerne bescheid sagen, mein Projekt ist auch komplett in c geschrieben. Ich habe dazu noch ein php-Gateway geschrieben, so dass ich das ganze über einen Webbrowser grafisch konfigurieren kann.

Viele Grüße,
Heiko
 

MajorMadness

Active Member
Och das Programmieren find Ich einfacher als das löten... arbeite seit paar Jahren als Software Entwickler. Zwar meist in C# und PHP, aber man erinnert sich noch an die Basics ;)
Der MSB 430-A2 hört sich nett an, frage mich nur ob er wirklich besser geeignet ist? Bisschen überdimensioniert find ich und ob es soviele Bauteile wie für den Aruino gibt die zusätzlich noch so einfach an zu sprechen sind? Ich bin ja jetzt schon fast am PIN Max und alles über I2C shift o.ä. zu machen ist doch komplizierter...
 

heiko77

New Member
Hallo,

Der MSB A2 ist sicher überdimensioniert, aber ich arbeite mit den Teilen und habe den daher "rumliegen". Bauteile die ich an den Arduino anschliessen kann, kann ich ja auch einfach anschliessen. Wenn die Pins zu Ende gehen würde ich frühzeitig einen dicken Multiplexer einsetzen, dann muss man später nicht alles umbauen. Hätte ich keinen MSB A2 hier liegen, würde ich auch einen Arduino oder gleich einen Rasperry Pi nehmen.

Was mich am meisten stört ist, dass es keine gute Sensorik gibt. Ich würde gerne KH und co. elektrisch messen können. habe schon überlegt das mit einem Fotometer zu automatisieren, aber das wird mechanisch sehr aufwändig...

Bei den Düngerintervallen würde ich darüber nachdenken noch den Wochentag mit angeben zu können. Dann kann man einen Dünger auch wöchentlich dosieren, oder jeden 2. tag, etc.

Dosierpumpen habe ich aus elektrischen Seifenblasenpistolen für 3€ genommen, weiss abe rnoch nicht genau wie die sich schlagen...

Grüße,
Heiko
 

MajorMadness

Active Member
So, für 2 Dinge war es gestern zu spät...
1. Wie bekommen wir unsere Düngung jetzt dazu aufgerufen zu werden? Das geht ganz einfach indem wir in den Loop
Duenung(RTC.daystamp);
schreiben.
2. Warum bekomme Ich jetzt Fehler? Das liegt daran das RTC keinen Member daystamp hat. Bitte was? :? Also, eine Libary ist im Prinzip nix anderes als eine Formel und variablen Sammlung. Sie besteht immer aus 2 Teilen: einem header (.h) und einer code (.cpp) datei. In der Programmierung nennen wir das Klasse (nein nicht klasse wie toll, sondern Klasse wie Klasse ;))
In der .h stehen zuerst libaries die diese Klasse benötigt und dann alle Funktionen und Variablen die wir angeben können. Da wir den fehler bei unserer Uhr haben, öffnen wir uns den header file einmal.
hier finden wir:
class DS1307new
{
public:
Hier finden wir alle funktionen und variablen die wir ansprechen können. Ist nix anderes als wir mit int loopTime =0; gemacht haben. Hier steht aber auch
uint8_t minute;
ahhh hierher kommt also RTC.minute :flirt: aber wo ist der daystamp? Tia den gibt es nicht, wir haben aber eine Zeile
uint16_t year; und darunter schreiben wir jetzt
float daystamp;
Bisschen weiter unten sind dann noch sogenannte private functions. Das sind Funktionen die zwar unser Programm, nicht aber wir verwenden können. Dort gibt es void calculate_time2000(void); und dadrunter kopieren wir jetzt:
void calculate_daystamp(void); // calculate daystamp from hour, minute & second

Weiter geht es mit der .cpp Datei.
DS1307new::DS1307new() <- Das ist unser Konstructor. Der wird aufgerufen wenn wir die Datei einbinden.
void DS1307new::getTime(void) <- Das ist eine funktion die aufgerufen wird wenn wir RTC.getTime(); aufrufen. Das schauen wir uns genauer an:
second = bcd2dec(Wire.read() & 0x7f);
minute = bcd2dec(Wire.read());
hour = bcd2dec(Wire.read());
ahhh hierher kommt also RTC.minute :flirt: aber wo ist der daystamp? Tia den gibt es nicht, wir haben aber eine Zeile
" // recalculate all other values" und da calculate_time2000();. Unter diese schreiben wir uns jetzt: calculate_daystamp();. So ruft man Private funktionen auf. Jetzt müssen wir uns die funktion nur noch schreiben. Eigentlich können wir die calculate_time2000() einfach kopieren.
Code:
void DS1307new::calculate_time2000(void)
{
  uint32_t t;  // ein unsigned int von 32-bit länge
  t = cdn;    // t = Tage seit 2000
  t *= 24; // *=24 ist das gleiche wie t=t*24, schreibweise für faule
  t += hour;   // t=t+stunden
  t *= 60;
  t += minute;
  t *= 60;
  t += second;
  time2000 = t;   // weise dem wert der public (öffentlichen) variable den wert der private function zu.
}
Das sollte als erklärung reichen, machen wir das für uns:
Code:
void DS1307new::calculate_daystamp(void)
{
  uint32_t t;
  t = hour;
  t *= 60;
  t += minute;
  t *= 60;
  t += second;
  daystamp = float(t);
}
Wem das zuviel war, Ich häng die geänderte DS1307 in den Anhang.

Auf jeden fall können wir nur RTC.daystamp benutzen und bekommen dafür (((std*60)+min)*60)+sek zurück.

So und für die, die kein DS1307 Modul kaufen wollen und weil meins z.Z. verbaut ist hab Ich das ganze mal kurz gelötet:Wie Ihr seht, ist das nicht wirklich kompliziert. Ich hab sogar 2 Pullups über nen Jumper mit eingebaut. Die könnte man aber weglassen.

Zum ganzen bisher hab Ich dann noch nen Schaltplan gemacht: (Jetzt in korrigierter Version ;) )

Bis denne dann Moritz
 

Anhänge

  • IMG_6150.JPG
    IMG_6150.JPG
    368 KB · Aufrufe: 13.851
  • DS1307new.zip
    88 KB · Aufrufe: 548
  • Schaltplan.png
    Schaltplan.png
    15,7 KB · Aufrufe: 13.832

Alexk2508

Member
Hallo Moritz ,

eine wirklich sehr interessante Doku die du da bisher Aufgebaut hast . Respekt für dein Engagement das hier so Detailiert zu Präsentieren .

Wollte aber eigentlich nur Kurz anmerken das die Beschriftung vor SV1 ein klein wenig verutscht ist und somit eventuell ein wenig verwirrend wirken könnte .
 
Ähnliche Themen
Themenersteller Titel Forum Antworten Datum
Tobias Coring Flowgrow - das gelebte Miteinander in der Community Ankündigungen 0
Ewald Flowgrow Forum Uhr - der Zeit voraus? Kein Thema - wenig Regeln 2
HaManFu HaManFu grüßt den Rest der Welt@Flowgrow Mitgliedervorstellungen 15
Tobias Coring Der Flowgrow Dünger ist da ;) Nährstoffe 127
D Neu in der Aquaristik (Benjamin aus Raum Köln/Bonn) Mitgliedervorstellungen 4
D Was kann der Sera CO2-Dauertest (nicht)? Technik 2
Maj.Monogwam Hilfe bei der Geschlechtsbestimmung, Königssalmler. Fische 2
Heiko Muth (Sumpfheini) Leptochilus pteropus, der Javafarn... Pflanzen Allgemein 0
T Weiß jemand, wer der Hersteller des Harzes ist, das sich "Purigen" nennt? Technik 11
Benjamin87 Der Zustand meiner Aquarium Pflanzen Pflanzen Allgemein 4
Benjamin87 Klares Wasser nach der Einlaufphase Technik 2
Benjamin87 Unerfahren in der Düngung Nährstoffe 1
Benjamin87 Trübung in der Einfahrphase Erste Hilfe 8
T In Zeiten der sog. Klimakrise ... Was ist Eure Sicht auf das "Teufelszeug" CO2? Kein Thema - wenig Regeln 10
S Optimierung der Düngung Nährstoffe 40
E Kalium Mangel (meine Pflanzen sagen ja der Test sagt nein) Nährstoffe 42
T Hilfe bei der Namenssuche Artenbestimmung 1
S Düngen in der Einfahrphase Nährstoffe 315
J Tropica Dünger in der Einfahrphase Nährstoffe 19
B4m8i Aquarium in der Arbeit - Proxima 250 ohne allem Aquarienvorstellungen 12

Ähnliche Themen

Oben