Noch ein DIY Controller

thisischris

New Member
Super Inputs, da mach' ich mich gleich mal ran (und vertraue auf die Stabilität meines restlichen Codes während des Pumpens). Dauert wohl etwas :?. Ich bleib' mal bei der TimeAlarms Library, Interrupts scheinen mir Overkill zu sein für die Situation und ich bin der beste Library-Einschrumpfer der Welt :).

Chris
 

thisischris

New Member
Das Messen von pH und Sauerstoffkonzentration war der spannendste Teil meines Arduino-Projektes, aber auch der, der mir am meisten Kopfzerbrechen bereitet hat. Dabei klang am Anfang alles ganz einfach: Messkit kaufen, anschliessen, Wasserwerte messen.

Was die Kits anbelangt, habe ich mich für diese beiden Komplettlösungen von AtlasScientific entschieden. Sie schienen mir einen guten Kompromiss zu bieten zwischen Preis, Robustheit und verfügbarer Dokumentation. Ich bin nach wie vor zufrieden damit.

https://www.atlas-scientific.com/product_pages/kits/ph-kit.html
https://www.atlas-scientific.com/product_pages/kits/do-kit.html

Jep, das Zeugs kostet. Angeschlossen habe ich alles nach Anleitung und dann begann das Kalibrieren und Messen. Und das Chaos.

Die Details der pH- und Sauerstoff-Sensortechnologie hier zu erklären würde zu weit gehen. Im Kern aber liefern beide Sonden ein sehr schwaches elektrisches Signal (Schwankungen im Millivolt-Bereich) an eine Art Verstärker, der dann an den Arduino angeschlossen wird. Weil nun aber keines der Geräte, das sonst noch so im und am Aquarium hängt (Pumpe, Heizer etc.) wirklich perfekt abgeschirmt ist, gibt es zahlreiche Möglichkeiten, wie die feinen Sonden-Signale gestört werden können und es ist anfangs, gar nicht leicht, diese möglichen Störfaktoren zu verstehen und zu isolieren. Ist die Sonde richtig kalibriert? Liefert die Sonde den richtigen Wert oder muss sie sich noch einpendeln? Hat das Aquarienwasser im Vergleichsglas nicht vielleicht wirklich einen anderen pH als im Aquarium, weil das CO2 ausgegast ist? Weshalb messe ich einen anderen Wert wenn ich den Laptop berühre, der am Arduino hängt? Weshalb springt der pH hoch wenn ich den Filter ausschalte? Weshalb schwankt der Sauerstoffwert wenn sich das Töchterchen im Nachbarzimmer mit dem Fön die Haare trocknet?

Die meisten Störungen, so konnte ich mir mit der Zeit zusammenreimen, hingen mit Erdschleifen zusammen, also mit ganz schwachen Fehlströmen, die sich durch die Sonden einen Weg in die Erde gebahnt haben. Andere könnten das sicher besser erklären als ich. Lösen liess sich das Problem am Schluss ganz einfach: ein fettes Kupferkabel führt nun bei mir aus dem Aquarienwasser zum Erden-Anschluss des Motor Shields. Dieser ist nahe genug am echten Erden-Anschluss des Arduino um die Fehlströme an den Sonden vorbeizuleiten, da Strom ja immer den Weg des geringsten Widerstandes geht.

Mittlerweile messen meine Sonden präszise und ich kann damit ganz gut den Verlauf der beiden Werte im Aquarium verfolgen. Welchen Einfluss hat die Oberflächenbewegung auf die Sauerstoffkonzentration bei Tag und bei Nacht? Wie hoch steigt die Sauerstoffkonzentration eigentlich, wenn es den Pflanzen gut geht? Assimilieren die Pflanzen oder kündigt sich da eine Algenblüte an? Zehrt EasyCarbo wirklich messbar Sauerstoff? Wie lange braucht es, bis sich der soilbedingt reduzierte pH nach einem Wasserwechsel wieder einpendelt? Das lässt sich alles messen und ist extrem spannend, weil man dank dieser Messungen eben Dinge sieht, die man sonst nicht sieht.

So, das war jetzt etwas nerdy. Nach dem Klick ein Bild von einem nicht ganz typischen Tagesverlauf (ich habe am Arduino gebastelt heute), wie ihn mein Logging-Programm ausspuckt. Man bemerke die extreme Sauerstoffübersättigung gestern Abend.

 

thisischris

New Member
Die Programmierung, wo soll ich da bloss anfangen? In den 80er Jahren, als PCs noch einfach zu verstehen und das Verständnis von Maschinensprache für Programmierer noch Pflicht war? Die Arduino-Umgebung macht einen guten Job wenn es darum geht, die Komplexität der an sich schwierigen Ur-Programmiersprache C vor dem Nutzer zu verstecken. Gleichzeitig lassen die Anfängerbeispiele einige Dinge etwas gar einfach wirken, z.B. den Umgang mit Echzeit/parallel auszuführenden Arbeiten. Ihr konntet das hier in diesem Thread (Fred?) mitverfolgen, als es um die Feinheiten des Düngerpumpen-Timings ging.

Vielleicht bringt es etwas, wenn ich hier einige Beobachtungen weitergebe, die mir geholfen haben, als Arduino-Anfänger einen ganz passablen (und vor allem stabilen) Aquariencontroller zu programmieren.

1) Ressourcen
Der Arduino verfügt über drei Speichertypen und der erste Typ, der ausgehen wird ist nicht der Programmspeicher, über den die IDE nach jeder Compilierung berichtet, sondern der Arbeitsspeicher. Die verschiedenen Speichertypen zu kennen und zu nutzen ist wichtig für ein grösseres Projekt wie ein Aquariencontroller, ebenso ein grundlegendes Verständnis des Speicherbedarfs der Elemente in einem Projekt (eigene Variablen, Variablen in Libraries etc.).

Die zweite Ressource, die noch lange vor dem Programmspeicher ausgehen wird ist Zeit. Der Code wird langsam oder "hängt" sogar zeitweise. Hier ist es wichtig, den Zeitbedarf verschiedener Aktionen (z.B. Kommunikation mit Sensoren oder mit der Echtzeituhr via I2C) zu kennen.

2) Zustand
Der Arduino startet recht liberal neu, z.B. jedesmal wenn eine neue serielle Verbindung via USB aufgebaut wird, und er kann das auch sehr schnell. Wir möchten jedoch nicht, dass unser kleiner Controller durch einen Neustart in einen undefinierten Zustand kommt und z.B. mit voll laufenden Düngerpumpen einen neuen Tag beginnt, oder frisch aufgeweckt gleich alle Lichter ausmacht. Ich habe das für mich so gelöst, dass alle Programmkomponenten nach einem Neustart immer den gewünschten (richtigen) Zustand ermitteln und herstellen. Eine raffiniertere Lösung wäre die Nutzung des permanenten EEPROM Speichers.

3) Ausgabe
Speicher- und performancetechnisch wird's recht schnell haarig, wenn der Arduino intensiv kommunizieren, z.B. Statistiken erstellen oder gar eine Website ausliefern muss. Wer länger mit dem Arduino spielt versteht bald, weshalb typische Haushaltsgeräte oder der Radiowecker so kurz angebunden sind. Ich habe das Problem für mich so gelöst, dass ich den Arduino selber nur minimal/stark verkürz kommunizieren lasse und die "Outputs" für die weitere Verarbeitung von einem kleine PC (RaspberryPI) weiterverarbeiten lasse. Dabei habe ich stets sorgsam darauf geachtet, dass der Arduino völlig unabhängig bleibt vom RaspberryPI, d.h. dass er seine Controller-Arbeit, geschehe was wolle, immer leisten kann. Mit etwas mehr Sorgfalt und dem cleveren Einsatz eines Displays mit Tastatur liesse sich hier sicher viel mehr herausholen, aber für mich war dies der einfachste Weg, bzw. der mit dem höchsten Potential am Anfang.

4) Lernen
Das Arduino-Projekt ist ausgezeichnet dokumentiert und hat eine gigantische Community, gerade deshalb mischen aber auch viele Anfänger mit. So erreicht mancher Tipp aus einem Forum zwar kurzfristig das Ziel, hat aber oft längerfristige Folgen. Häufig wird z.B. die Nutzung von nicht im Arduino-Projekt dokumentierten, aber dennoch verfügbaren C-Standardfunktionen empfohlen (dtostrf, sprintf etc.). Leider sind diese Funktionen häufig extrem speicherintensiv, weil sie eben nie für den Arduino adaptiert wurden und können so später zu Arbeitsspeichermangel oder gar Programmspeichermangel führen. Alles in Allem lohnt es sich, zu experimentieren und Stück für Stück die wahren Tiefen der Arduino-Programmierung zu ergründen. Ein Trick aus dem Forum mag heute zum Erfolg führen und morgen bin ich dann stolz, dass ich dasselbe erreichen kann und dabei 20 Byte weniger Arbeitsspeicher verwende.

Wer interessiert ist, soll sich mal meinen Code auf Github ansehen (ich habe etwas aufgeräumt), Kommentare sind sehr willkommen, nicht zuletzt weil ich selbst noch Anfänger bin:

https://github.com/thisischris/aquarium_controller

Beste Grüsse

Chris
 

omega

Well-Known Member
Hallo Chris,

> Das Arduino-Projekt ist ausgezeichnet dokumentiert

ich hab jetzt 1h versucht, mich in Arduino einzulesen, um u.a. rauszubekommen, wann ein Sketch ausgeführt wird und ob mehrere Sketches gleichzeitig laufen können, also ob Arduino multitasking-fähig ist. Auf http://arduino.cc konnte ich diesbzgl. keinerlei Info finden. Woanders las ich von einem Real Time Multi Tasking Operating System für Arduino. Der kann das wohl doch nicht von Haus aus.
In Deinem Projekt befinden sich ja mehrere Sketches. Vielleicht kannst Du mir die grundlegende Funktionsweise von Sketches erklären.
Ich selbst kenne mich mit Softwareentwicklung gut aus, aber mit so kleinen "Dingern" hatte ich noch nicht zu tun.

Viele Grüße, Markus
 

MajorMadness

Active Member
Grundsätzlich ist ein Arduino nicht mulittasking fähig und auch nicht in der lage 2 Sketches aus zu führen. Das sieht man alleine daran das der loop immer wieder ausgeführt wird und linear abgearbeitet wird. Vergleichbar ist das mit der void main() aus C.
Das Script was du meinst macht den Arduino nicht Tasking fähig sondern implentiert nur eine nicht lineare abarbeitung durch setzen verschiedener interrupts und aufrufen von programmschritten nach einander, unabhängig von einander.
Wenn du dich gut mit Softwareentwicklung auskennst (nicht webentwicklung) dann solltest du C, evt auch C++ kennen und alle damit verbundenen vor und nachteile.

Grundsätzlich wird ein Sketch eigentlich nie ausgeführt. Er dient nur dazu den Code zu schreiben. Ein Sketch wird kompiliert und dann als HEX auf den Controller überspielt. Wichtig dabei ist zu wissen wie der Build Prozess ist:
Zuerst werden Header files ausgewertet (*.h) und preProzessor anweisungen (#define, incluide) interpretiert. Danach werden aus allen Files function defines und typedefs gesucht. Damit hat Arduino eine Struktur die an C erinnert (.h, .ccp).
Zur besseren Struktur kann man Teile des programms in andere Files lagern. Diese haben immer die endung .ino und werden vom kompiler gelesen als ständen sie UNTER dem main file (der heist wie der Ordner). Hierbei geht der Kompiler von links nach rechts vor. Sollte also eine Typedef in einem File mit Namen zweitertab.ino sein "kennt" Arduino diese nicht in erstertab.ino. Will man dies doch machen muss statt eine rino ein header file gebaut werden und dieser VOR der verwendung mit #include eingebunden werden.

Wenn man dies alles bedenkt ist es ganz einfach:
Arduino startet,
Setup wird ausgeführt,
loop läuft permanent durch und ruft alle funktionen ect aus allen anderen files auf, wertet sie aus und startet von neuem mit dem loop. Der loop wird dabei so schnell wie möglich immer wieder aufgerufen.

@Chris:
update.ino:
Code:
  // check switch states every 6 "update" calls (60 seconds)
  updateRuns++;
  if(updateRuns > 5){
    checkSwitches();
    updateRuns = 0;
  }
Wenn du gegen Zeit checken willst empfield sich der vergleich zu millis.
Code:
unsigned long previousMillis = 0;  
if(millis() - previousMillis >= 60000) {
  previousMillis = millis();   
  checkSwitches();
}
Verbraucht zwar 1byte mehr SRAM, läuft dann aber garantiert alle 60sek, egal wie schnell der loop ist und wie oft Update() aufgerufen wird.
Ansonsten finde ich deinen Code schon viel besser zu lesen. :bier:
 

omega

Well-Known Member
Hallo Moritz,

danke Moritz, jetzt wird mir einiges klarer, aber noch nicht alles:
Chris' Projekt beinhaltet mehrere Sketches, was mich verwirrt. Ein Sketch - sketch_aquarium_a4 - ist das eigendliche Programm und ruft alle Funktionen wie Pumpensteuerung, Switch-Checking, pH- und Sauerstoff-Elektrodenverarbeitung auf und steuert ein LCD an? Und die anderen sind Utilities und werden bei Bedarf in den Arduino geladen, überschreiben somit sketch_aquarium_a4, um andere Tätigkeiten auszuführen?

MajorMadness":1wjknvxs schrieb:
Das Script was du meinst macht den Arduino nicht Tasking fähig sondern implentiert nur eine nicht lineare abarbeitung durch setzen verschiedener interrupts und aufrufen von programmschritten nach einander, unabhängig von einander.
Aber genau das ist Multi-Tasking, hier genauer Multi-Threading. Multi-Tasking deckt auch Multi-Processing ab, wozu es aber der Process-Isolation bedarf, die Arduino nicht kennt und sich ohne Hardwareunterstützung (MMU) nicht robust implementieren läßt.
Preemptiv wie schon zu Amiga-Zeiten ist ChibiOS/RT nicht, aber kooperativ wie zu Windows 3.1- und Atari ST-Zeiten, wenn auch auf eine recht einfache Weise. Threads ermöglichen ja, unterschiedliche Aufgaben - wenn schon nicht physisch durch je einen eigenen Adressraum - zumindest aber logisch voneinander zu trennen. Diese logische Trennung macht ein Programm erheblich übersichtlicher, leichter zu verstehen und zu warten. Dadurch erhöht sich die Robustheit und reduziert sich die Fehleranfälligkeit. Insgesamt erhöht sich also die Stabilität, und zwar ganz erheblich, genauso wie bei sauber geschnittenen Modulen/Klassen/Packages in C, C++ und Java. Sogenannte God-Classes in z.B. C++ und Java wären das genau Gegenteil.

Wenn ich das richtig sehe, verfügt ein Arduino über sehr wenig Speicher, weshalb man wohl eher God-Class-like implementiert, weil zusätzlicher Verwaltungsaufwand zusätzlich Speicher kostet?
Man kann sich das Leben aber dennoch leichter gestalten und sich dem Thread-Konzept nähern, indem man vielleicht keine Thread-Library wie ChibiOS/RT nutzt, aber die unterschiedlichen Aufgaben, mit denen man seinen Arduino betreut, dennoch wie in C modularisiert oder objektorientiert wie in C++ jeweils in eine Hauptklasse mit optional zusätzlichen Delegate-Classes packt (also pro Aufgabe ein oder mehrere Objekte verwaltet).

All diese Hauptklassen können dieselbe Basisklasse besitzen. Diese Basisklasse könnte man Task nennen, und sie könnte eine virtual execeute-Methode besitzen. Ein Sketch instanziiert diese Klassen in der setup-Funktion (mit new auf dem Heap, nicht auf dem Stack!), hält sich die Instanzen in einem Pointer-Array und führt sie in der loop-Funktion mit einer Schleife über den Pointer-Array aus. Der Sketch muß diese Klassen in der setup-Funktion natürlich kennen. Dabei handelt es sich aber um einfachen flachen Code ohne große Logik, ist also hierfür extrem leicht wartbar. In der loop-Funktion muß der Sketch die einzelnen Klassen aber nicht mehr kennen. Die loop-Funktion muß - einmal codiert - nie mehr angefaßt werden, da sie nur noch abstrakte Task-Objekte, aber nicht mehr die einzelnen Klassen kennt. So wie in diesem Beispiel, nur halt nicht mit einzelnen Pointer auf A- und B-Instanzen sondern als Array deklariert und mit einer Schleife über diesen Array.

Beispielsweise bezogen auf Chris' Projekt: es gäbe dann die definitions.h in der Form nicht mehr. Aktuell stellt sie ein All-In-One-Sammelsurium von Konstanten und Variablen quer über alle Funktionalitäten des Programms dar. Das widerspricht den Grundsätzen der Modularisierung, dem Information Hiding und dem Separation-Of-Concern Principle (kann man alles Ergoogeln).
pH-relevanter Teile würden in eine pH-Klasse wandern, O2-relevant in eine O2-Klasse etc. Die Datei definitions.h würde dann nur noch echte Globals enthalten, die also von mehr als einer Klasse oder dem Haupt-ino und mindestens einer Klasse benutzt werden.
definitions.h birgt auch eine Gefahr: würde sie von mehreren Modulen/Klassen included, würden die dort definierten Variablen mehrfach existieren (wenn es dieses Konzept in Arduino überhaupt gibt, ich seh auch nur einen Include dieser Datei).
sketch_aquarium_a4.ino würde auch viel schlanker. Aktuell widerspricht sie dem Single-Responsibility-Principle, da sie sich recht detailliert um alle Aufgaben kümmert. In C++/Java würde man sie als Monster-Class bezeichnen, würde sie eine Klasse beinhalten.

MajorMadness":1wjknvxs schrieb:
Wenn du dich gut mit Softwareentwicklung auskennst (nicht webentwicklung) dann solltest du C, evt auch C++ kennen und alle damit verbundenen vor und nachteile.
Und weiter?

MajorMadness":1wjknvxs schrieb:
Grundsätzlich wird ein Sketch eigentlich nie ausgeführt. Er dient nur dazu den Code zu schreiben. Ein Sketch wird kompiliert und dann als HEX auf den Controller überspielt.
Mit Sketch meine ich natürlich schon den Maschinencode, der aus dem Sketch etc. beim Compile entsteht. Das war mir zu lang, so zu formulieren. Mit "HEX" (also hexadezimal) meinst Du wohl "binär", also z.B. ein ELF-Binary?

MajorMadness":1wjknvxs schrieb:
Wichtig dabei ist zu wissen wie der Build Prozess ist:
Zuerst werden Header files ausgewertet (*.h) und preProzessor anweisungen (#define, incluide) interpretiert. Danach werden aus allen Files function defines und typedefs gesucht. Damit hat Arduino eine Struktur die an C erinnert (.h, .ccp).
Zur besseren Struktur kann man Teile des programms in andere Files lagern. Diese haben immer die endung .ino und werden vom kompiler gelesen als ständen sie UNTER dem main file (der heist wie der Ordner). Hierbei geht der Kompiler von links nach rechts vor. Sollte also eine Typedef in einem File mit Namen zweitertab.ino sein "kennt" Arduino diese nicht in erstertab.ino. Will man dies doch machen muss statt eine rino ein header file gebaut werden und dieser VOR der verwendung mit #include eingebunden werden.
Chris' "sketch_aquarium_a4.ino" ist also vergleichbar mit einer C-Datei, die die main-Funktion enthält. Und die anderen INOs in dem Ordner "sketch_aquarium_a4" sind Module? Das gesamte Programm besteht also aus dem Ordner "sketch_aquarium_a4"? Die anderen Odner sind jeweils ein eigenes Programm?

Jetzt seh' ich's auch langsam auf arduino.cc. Man muß die Beispiele durchackern, um rauszufinden, wie Arduino-Software grundlegend funktioniert oder zigfach Google fragen. Find ich schon blöd und zeitaufwendig, daß es da keine gscheite Systembeschreibung gibt, um einen Überblick zu erhalten.

Viele Grüße,
Markus
 

thisischris

New Member
Lieber Markus

Das mit den mehreren Sketch-Dateien (innerhalb des Controller-Sketchverzeichnisses) hat mir Moritz beigebracht, die nennen sich in der Arduino-IDE "Tabs" (Quelle) und dienen bloss der Code-Organisation, die IDE klebt sie vor dem Compilieren schlicht zusammen. Als alter C-Ler hat mich das anfangs mächtig verwirrt. Die anderen Sketches (z.B. Hilfs-Sketches) lade ich auf den Arduino wenn ich sie brauche.

Chris
 

thisischris

New Member
Und hier noch zum Multitasking/Threading, zur Kapselung von Funktionen und Variablen etc., hach, da kommen bei mir Kindheitserinnerungen auf. Dein Lösungsvorschlag liesse sich so umsetzen, Du unterschätzt dabei ev. drei Dinge:

- Wie wenig Speicher der Uno wirklich hat
- Wie klein Arduino-Projekte im Vergleich zu anderen Projekten am Schluss doch bleiben
- Meine Faulheit

Ein Beispiel: Ich habe einen ersten solchen Kapselungsversuch gemacht für die LeanAlarms Library (siehe Github). Die Library habe ich gebraucht, weil die Standard-Library des Arduino a) etwas fett ist und b) keine Timeout-Timer im Millisekundenbereich erlaubt, letzteres brauche ich fürs Düngerpumpen. Die Library kann Alarme (so viele Du willst) und Timer (so viele Du willst), aber sie ist etwas schwerfällig, weil jeder Alarm/Timer zuerst als Objekt erzeugt, dann gesetzt (set) und dann im Loop regelmässig geprüft werden muss (check). Dieser check im Loop ist in ganz primitiver Form das Multithreading, das Du beschreibst. Ich könnte nämlich den beiden Alarm-Typen eine gemeinsame Basisklasse geben, so check universell abrufbar machen, die Alarm-Objekte jeweils bei der Library einfordern anstatt sie selber zu erzeugen und die Library dazu bringen, eine Liste der aktiven Objekte zu verwalten. Dann müsste nur noch ein "check" aufgerufen werden aus dem Loop, den Rest könnte die Library über die verwaltete Liste von Alarm-Objekten mit der universellen check-Funktion übernehmen. Bloss: a) der Aufwand, eine solche Library zu schreiben wäre deutlich höher (Faulheit) und b) die Library würde mehr Ressourcen brauchen, denn sie müsste einen Mechanismus haben, um die aktiven Objekte zu verwalten. Sie könnte das wie TimeAlarms tun mit einem Array, müsste dafür aber den festen Raum reservieren oder sie könnte es dynamisch tun, was eine ganze Liste neuer Aufwände und Ressourcen-Verbrauchsmöglichkeiten mit sich bringen würde. Sogar Gefahren lägen da, denn dynamische Speicherverwaltung ist nicht so das Arduino-Ding, da kollidieren ganz schnell mal Stack und Heap.

Ein Multithreading-Lösung, wie Du sie beschreibst, wäre auch nur sehr schwierig innerhalb der "primitiven Verständlichkeit" zu halten wie sie vom Style Guide für Arduino Libaries gefordert wird und so geschieht's halt, dass eher faule Programmierer wie ich, in Projekten die auch nicht so gross werden, und unter akutem Speichermangel einfach alle regelmässigen Updates in eine Funktion "Update" knallen, oder alle Definitionen in "definitions.h", unabhängig davon, ob das dann die Nachwelt (oder ich selber in 2 Monaten) noch verstehen kann.

That said, in diese Richtung wird es sicher gehen, vor allem wenn man grössere Projekte auf grösseren Arduinos betrachtet. Mich hat's auch schon gejuckt, wieder "richtig" zu programmieren anstatt nur mehr oder weniger mit C zu skripten.

Chris
 

thisischris

New Member
@Moritz: da Update von einer Funktion in LeanAlarms aufgerufen wird, die genau diesen millis() Check macht, habe ich mir die paar Byte an dieser Stelle gespart. Aber Markus hat da schon recht, diese Sparerei wird schnell zur Besessenheit. An sich ist so eine Update-Funktion, die irgendwas tut von Seriell über LCD-Anzeige bis Ventilation ja schon ein Unding. Die Switches checke ich übrigens bloss seltener weil dieser Check recht viel Zeit frisst. Um DAS dann wiederum besser zu machen müsste man die Switches z.B. einzeln checken und nach jedem Check wieder an die restlichen "Threads" yielden. Eine noch extremere Variante wäre, das Senden der RC-Switch-Pulse selber asynchron zu machen mit Interrupts. So, das waren glaub' ich genug Kindheitserinnerungen für heute.

Grüsse, zur Abwechslung mal aus München

Chris
 

omega

Well-Known Member
Hallo Chris,

thisischris":1iu63vc4 schrieb:
Das mit den mehreren Sketch-Dateien (innerhalb des Controller-Sketchverzeichnisses) hat mir Moritz beigebracht, die nennen sich in der Arduino-IDE "Tabs" (Quelle) und dienen bloss der Code-Organisation
"bloß" ist gut. Code-Organisation ist das A und O in der Software-Entwicklung. Ich liebe es zu abstrahieren, objektorient zu entwickeln, multifunktional, gekapselt, belastbare Contracts und an der Trivialitätsgrenze, so einfach, daß andere manchmal staunen, wie minimalistisch man programmieren könne. Wenn mich Stack, Heap und Speicherverwaltung aber darin einschränken, den Code so zu organisieren, daß er modernen Paradigmen entspricht, vergeht mir der Spaß.
Ich habe Deinen Thread gelesen, um mal in einen aktuellen µController reinzuschnuppern, weil ich schon lange mal selbst ein Projekt (Robotik) mit einem aufsetzen wollte. Bisher hatten die mich immer abgeschreckt, weil zu stark limitierend. Da fühlte ich mich immer ins Studium zurückversetzt, als wir einen Intel 8259 oder Interdata 6/16 (Kernspeicher) in Assembler programmieren durften. Das war Frickelei ohne Ende.
Raspberry Pi verfügt über weit mehr Speicher. Warum machst Du das nicht mit dem? Hast doch einen.

thisischris":1iu63vc4 schrieb:
die IDE klebt sie vor dem Compilieren schlicht zusammen.
Ok, was die IDE dann daraus macht, kann mir als Entwickler egal sein, Hauptsache das Ergebnis performt. Ich weiß, wie Compiler etc. arbeiten. Mich als Entwickler interessieren eher die Konzepte, die dahinter stecken, wie alles zusammenhängt, Language Specs, Libraries, Systemarchitektur. Aber ich seh schon, ein Arduino ist nichts für mich.

Aber ich danke Dir und Moritz für einen Einblick in Arduino. Interessant war's trotzdem. Viel Spaß und Erfolg weiterhin, Euch beiden.

Viele Grüße,
Markus
 

thisischris

New Member
Lieber Markus

Du hast recht, die Einfachheit des Arduino kann fast abschreckend sein - aber auch faszinierend, wenn man sich wie ich manchmal gerne an diese Zeiten zurückerinnert.

m.E. gibt es zwei Gründe, weshalb Mikroprozessoren hauptsächlich eingesetzt werden: a) Der Preis: für 10€ gibt's einen Arduino-Klon, für 4 Euro oder so einen Selbstbau, d.h. die Dinger können in Massen eingesetzt, modifziziert oder gar abgefackelt werden ohne dass es wirklich weh tut. b) Die extreme Stabilität, die durch diese Einfachheit entsteht. Versuch' mal mit einem RaspberryPI Ereignisse im Mikrosekunden-Bereich zu timen, das ist eine Qual, weil Dich der Scheduler früher oder später dabei unterbrechen wird. Ich brauche für den Aquarien-Controller zwar keine Mikrosekunden, dennoch möchte ich sowas wie Düngerpumpen oder CO2 und Licht steuern nicht einem so komplexen System wie dem RaspberryPI überantworten.

Chris
 

MajorMadness

Active Member
Dito!
Ich arbeite ja als Programmierer, schwerpunkt php, C#, objC, Java und wenn ich dran denke das mein Blog 65.536 mal mehr Ram verbraucht als der Arduino überhaupt zur verfügung hat und das selbst ein Programm was mir NUR die Uhrzeit auf dem PC zeigt größer ist als der komplette Controllercode... Also da wird es für mich frustrierend.
Klar OOP ect sind was feines und in meinen Projekten auch nicht konsequent durchgeszogen weil Ich linear und für meinen Zweck programmiere. Später sollen zwar Sachen wie Licht Dimmung, Dosierung ect alle mal gekapselt werden und eigene libs dafür gebaut werden aber das macht es wieder komplexer und schwerer verständlich. Grade die einfachheit ist ja die Stärke des Arduinos und das er ohne die ganzen Fremdwörter die du hier in den Raum schmeißt einfach nur stabil läuft.
Eine interface ICollection<T> und abgeleitete class List<T> in C# sind natürlich viel praktischer als feste Arrays, $arr=array(1=>"foo", ...); einfacher zu handhaben als typedef struct {int k;char[10] val;}keyValue ; keyValue arr[10]; arr[0]="foo"; aber hey, das ist doch grade der Spaß und wenn ich an meine Ausbildung zurück denke: Wieviele gab es da die SUPER programmieren konnten mit VS2010 und keiner wusste was da überhaupt passiert.

Noch ein Wort zu "moderne Paradigmen": Das was du alles aufzählst was modern ist, ist erst möglich wenn aufgaben parallelisieret werden können, genug speicher und ram zur verfügung steht, chipsätze gewisse instructions implentiert haben und und und. Ein Arduino basiert (zumindest Nano, Uno, Mega ect) auf einem 8bit Chip. Er kann all dies nicht oder nur durch sehr starke zweckentfremdung. Doch grade dann liegt es an dir als Programmierer effektive und gut zu programmieren, Speicherleaks zu vermeiden und SEHR genau auf zu passen wie du etwas schreibst.
Geh mal zu Ikea und kauf dir nen PAX system, bau dein haus drumrum und es sieht super aus. Aber ein wirklich guter Schreiner, Der kann dir den Kleiderschrank auch ins Dachgeschoß mit schrägen und Ecken bauen. Jetzt die Frage, Was ist besser? Modernes IKEA oder altes Handwerk? :bier:
 

omega

Well-Known Member
Hi,

thisischris":3qw7jf98 schrieb:
b) Die extreme Stabilität, die durch diese Einfachheit entsteht. Versuch' mal mit einem RaspberryPI Ereignisse im Mikrosekunden-Bereich zu timen, das ist eine Qual, weil Dich der Scheduler früher oder später dabei unterbrechen wird. Ich brauche für den Aquarien-Controller zwar keine Mikrosekunden, dennoch möchte ich sowas wie Düngerpumpen oder CO2 und Licht steuern nicht einem so komplexen System wie dem RaspberryPI überantworten.
ja, echtzeitfähig scheint der Raspberry PI von Hause aus nicht zu sein. Das braucht es für einen Aquariencomputer m.M.n. aber auch gar nicht zu sein. Ein Arduino ist es von Haus aus auch nicht. Derart zeitkritisch sind die Anforderungen dort nicht. Timer-Interrupts kann ja jedes System verarbeiten. Eine Interrupt Service Routine (ISR) kann vom Scheduler nicht unterbrochen werden, sondern höchstens durch einen anderen Interrupt.
Wenn man allerdings Funktionalitäten, die man normalerweise von außen (Timer, I/O-Port) antriggern läßt, statt in eine ISR in einen User-Thread packt und dort während der Verarbeitung auch noch pollt und delayed, wird diese vom Scheduler unterbrochen, wodurch es zu unvorhersehbaren Seiteneffekten kommen kann. Daher packt man derartige Funktionalitäten auch nicht in einen User-Thread sondern in eine ISR. Eine ISR schaltet z.B. bei einer Pumpensteuerung die Pumpe an und ab etc. Der User-Thread initailisiert nur die ISRs und wartet auf das Programmende.
Mal die extreme Stabilität angesprochen: Du hattest mit der Pumpensteuerung ja größere Probleme. Nun ist die auf Timersteuerung umgesetzt und die Probleme scheinen weg zu sein? Unter Linux und anderen OSs würde man genauso vorgehen.

MajorMadness":3qw7jf98 schrieb:
Klar OOP ect sind was feines und in meinen Projekten auch nicht konsequent durchgeszogen weil Ich linear und für meinen Zweck programmiere. Später sollen zwar Sachen wie Licht Dimmung, Dosierung ect alle mal gekapselt werden und eigene libs dafür gebaut werden aber das macht es wieder komplexer und schwerer verständlich.
Kapselung macht es nicht komplexer und schwerer verständlich. Ganz im Gegenteil. Das sind nur die üblichen Ausreden für Faulheit (nicht böse gemeint). Warum soll man seinen Code refaktorieren (umstrukturieren), wenn er doch läuft? Geht mir auch nicht anders. Soll den Code aber jemand anders verstehen und nutzen oder will man sich auf Dauer selbst einen Gefallen tun, refaktoriert man ihn dann doch irgendwann, schon allein deshalb, weil ich anderen meinen Spagetticode nicht antun will. Heute versuche ich von Anfang an, möglichst gleich alles sauber zu kapseln, damit ich hinterher nicht vor einem Scherbenhaufen stehe und alles refaktorieren muß. Warum? Weil ich eben faul bin.

Viele Grüße,
Markus
 

thisischris

New Member
Bei der Frage nach der Stabilität geht's um mehr als nur um's Timing. Ein Beispiel aus dem Alltag: nach einem regulären System-Update kam mein mehr oder weniger standard-konfigurierter RaspberryPI einfach nicht mehr hoch. Ich habe ca. 5 Stunden gebraucht, um dieses Problem auf einen Fehler im Ethernet-Treiber zurückzuführen (war früher teilzeitlich Linux-Sysadmin). Wäre da das ganze Aquarium drangehangen, wäre schnell Panik ausgebrochen. Beim Arduino habe ich bisher noch nie ein Problem erlebt, das mich länger als 5 Minuten "offline" genommen hätte.

Etwas abstrakter gesagt läuft auf einem Arduino nicht viel mehr als Dein Code (das ist doch auch eine Form von Kontrolle, oder?). Auf einem RaspberryPI läuft der Code von Generationen von Programmierern. Bei dieser Form von Stabilität geht es also letzte Endes um Kontrolle und ich denke, das ist der Grund weshalb auch in der Industrie für besonders kritische Tasks dedizierte Mikroprozessoren/Mikrocontroller eingesetzt werden und nicht alles an einem zentralen PC hängt. Bei meinem Auto piepst die Parkhilfe auf jeden Fall auch dann noch, wenn der Bordcomputer wieder mal, wie so oft, abgestürzt ist.

Die andere Frage bezüglich Code-Qualität und Refactoring diskutiere ich täglich (ich habe eine Firma mit aufgebaut, die Websites entwickelt und eine App mit fast 1 Mio. Nutzer betreibt), es juckt mich, dazu was zu sagen, aber das wäre glaub' ich wirklich "off topic".

Die Stabilität ist m.E. fürs Aquarium hoch relevant und basierend auf meinen Erfahrungen würde ich dringend davon abraten, einen Aquariencontroller auf einem RaspberryPI oder einem ähnlich komplexen System aufzubauen, nur weil es sich darauf moderner programmieren lässt

Chris
 

omega

Well-Known Member
Hallo Chris,

das Argument mit dem eigenen, abgeschotteten System hat was, ja. Und wenn ein µController wegen ausgehender Resourcen nicht mehr reichen sollte, kann man ja zu einem zweiten greifen. Die kleinen kosten ja kaum was. Ich mußte schon staunen, wie günstig die einfacheren Arduinos sind. Auf reichelt.de sind die aber nicht so günstig, wohl weil keine China-Klons. Ich hab aber was gegen Produktpiraterie: http://elektronik-experimente.sebastian-hehn.de/?p=68
Und bei 2K SRAM muß es ja nicht bleiben.

BTW: warum verwendest Du Funksteckdosen und nicht eine Relais-Karte wie diese hier: http://eckstein-shop.de/navi.php?a=62&lang=ger& ? Die hat Optokoppler verbaut, 230V und die Steuerelektronik sind also galvanisch voneinander getrennt.

Ich überlege mir, meine Beleuchtung auf LED umzustellen und mit einem µController zu steuern, wie das z.B. ein Storm X kann. Nun könnte ich der Einfachheit halber gleich auf einen solchen zurückgreifen, aber dann fange ich ja wieder kein eigenes Projekt an. Und mehr als Lichtsteuerung kann der nicht. Ein RPi wäre dafür zu umfangreich, sehe ich mittlerweile ein.

Viele Grüße,
Markus
 

Ähnliche Themen

Oben