Aus Raspberry Pi Geek 10/2018

Fischertechnik-Förderbänder per Controllino ansteuern (Seite 2)

Programm

Das in unserem Konstrukt verwendete C-Programm besitzt keinen linearen Ablauf, wie Sie es vielleicht von vielen Beispielprogrammen kennen. Es besteht vielmehr aus kleinen Codestücken, die in einer Schleife immer wieder zur Ausführung kommen.

Die Codestücke fragen den Status von Eingängen und Variablen ab, um zu ermitteln, ob sie aktiv werden müssen. Diese Art der Programmierung erlaubt es, mehrere Aufgaben gleichzeitig zu erledigen, und ermöglicht daneben auch eine Flankentriggerung von Eingangssignalen. Wie Sie sehen werden, lassen sich Wartezeiten nur umständlich realisieren, eine delay()-Funktion würde den Ablauf des kompletten Programms stören. Den konkreten Beispielcode zeigt Listing 1.

Zu Beginn gilt es, die Headerdatei Controllino.h zu importieren (Zeile 1). Sie stellt alles zur Verfügung, was Sie benötigen, um Programme für das Controllino-Modul zu schreiben. Die #define-Anweisungen von Zeile 2 bis Zeile 13 deklarieren sprechende Namen für die Ein- und Ausgänge.

Das hat den Vorteil, dass sich die Werte vor dem Kompilieren einsetzen lassen, ohne gesonderten Speicherplatz für Variablen zu erfordern. Damit lassen sich Programme kleiner und schneller gestalten. Würden wir hier mit const arbeiten, hieße das, für jede Konstante Speicher zu reservieren. Da der Mikrocontroller des Controllino in lediglich 265 KByte RAM alle Variablen, die Software und die verwendeten Bibliotheken vorhalten muss, gehört ressourcenschonender Code hier zum Pflichtprogramm.

Nun folgt die Definition der globalen Variablen. Dabei enthalten b0 bis b6 (Zeile 14) die digitalen Werte der Eingänge B0 bis B6. Hier gilt es, für die Erklärung etwas auszuholen.

Die Lichtschranken arbeiten mit 5 Volt, der Controllino dagegen mit 12 Volt. Aus dem Controllino-Basics-Artikel in dieser Ausgabe wissen Sie, dass der Controllino bei einer Betriebsspannung von 12 Volt Eingangsspannungen ab 9 Volt aufwärts als logisch 1 interpretiert. Die Lichtschranke erreicht also nie den Spannungspegel, der für eine logische 1 nötig wäre. Daher behelfen wir uns mit einem Trick: Wir lesen die Eingänge der Lichtschranken als Analogwerte ein und generieren daraus die Digitalwerte für die Eingänge. Diese landen dann in den Variablen b0 bis b6. Da der Metallsensor ausreichend hohe Pegel benutzt, entfällt bei ihm dieser Kunstgriff.

Die Variablen, die auf _previous enden (Zeile 15), speichern die Werte des vorherigen Schleifendurchlaufs. Das benötigen wir, um auf Flanken zu reagieren. Die Variablen metall und roboter (Zeile 16) dienen als Hilfsvariablen, die sich merken, ob der Metallsensor angeschlagen hat und der Roboter benachrichtigt wurde. Um Wartezeiten zu realisieren, speichern die auf _timer endenden Variablen die Timestamps bestimmter Aktionen (Zeile 17).

Die Funktion setup() ab Zeile 19 setzt die Pin-Modes für alle Ein- und Ausgänge; es gibt keinen speziellen Pin-Mode für die Analogeingänge.

Die loop()-Funktion ab Zeile 34 läuft als Endlosschleife. Ihre ersten Zeilen lesen die Analogwerte der Lichtschranken sowie des Metallsensors ein und wandeln diese in boolesche Werte um. Dabei kommt der C-Operator ?: zum Einsatz. Falls der logische Ausdruck vor dem Fragezeichen wahr ist, gibt der Operator den Wert vor dem Doppelpunkt zurück, ansonsten den dahinter. Mit diesem Ausdruck lassen sich einfache Fallunterscheidungen mit Zuweisung sehr leicht realisieren. Die Variablen b0 bis b6 speichern mithilfe dieses Operators die logischen Zustände aller Eingänge.

Wie eingangs erwähnt, besteht der kompakte Code fast nur aus Bedingungen. Nehmen wir direkt das erste if in Zeile 43 als Beispiel: Durch die logische Bedingung b5&&!b5_previous erreichen wir, dass der Code innerhalb des If-Blocks nur dann ausgeführt wird, wenn eine positive Flanke am Eingang B5 auftritt. In diesem Fall setzen wir die Variable metal auf HIGH, sprich: Der Metallsensor hat ausgelöst und wir speichern den Wert für die Zukunft.

Die Lichtschranken zum Starten der Bänder verwenden diesen Trick ebenfalls, um nur auf die Flanke zu reagieren. Eine Flankenänderung passiert immer genau einmal, zu einem definierten Zeitpunkt. Die Codestücke dürfen keinesfalls so lange ausgeführt werden, wie der Eingang auf HIGH steht; wir benötigen genau einen Aufruf beim Auftreten eines Ereignisses.

Sobald eine der Lichtschranken zum Starten auslöst, speichert die entsprechende _timer-Variable den aktuellen Timestamp. Eine weitere If-Abfrage prüft, ob das Auftreten des Ereignisses schon mehr als 5000 Millisekunden zurückliegt (Zeilen 49, 58, 67), und startet nur dann das Förderband. Die Verzögerung dient dazu, dem Roboter genug Zeit zu verschaffen, um den Gegenstand abzulegen und sich wieder aus dem Bereich des Förderbands zu entfernen.

Das Abschalten eines Bands (Zeilen 52 und 61) benötigt keinen Flanken-Trigger – sobald die Lichtschranke auslöst, stoppt der Motor.

Interessant ist die Stelle, an der die Lichtschranke b4 auslöst (ab Zeile 70). Sie stoppt den Motor M3 und wertet gleichzeitig die Variable metal aus. Abhängig von deren Zustand bekommt der Roboter das Kommando, den Gegenstand entweder auf Band 1 oder Band 2 abzustellen.

Die letzten vier Anweisungen ab Zeile 83 speichern die aktuellen Variablen für den nächsten Schleifendurchlauf, um sie für die Flankenauswertung zu verwenden.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 5 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
RASPBERRY PI GEEK KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Raspberry Pi Geek bei Google Play Readly Logo
Nach oben