RPi als D/A-Wandler

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

von M. Knoop

Dieser Artikel nimmt am Artikelwettbewerb 2012/2013 teil.

Oft wird ein Computer 'nur' genutzt um darauf Software ablaufen zu lassen. Dessen Möglichkeit zur Steuerung von elektrischen und mechanischen Geräten wird dabei leicht übersehen.

Dieser Artikel richtet sich daher an Einsteiger, die mit dem Raspberry Pi ('RPi') Grundlagen der Computersteuerung mit Relais und Spannungsteilern nachvollziehen möchten. Es wird an einem konkreten Beispiel schrittweise dargestellt, wie mittels eines D/A-Wandlers (Digital/Analog-Wandler = Umwandlung von digitalen 1/0 Signale) die Steuerung einer stufenweise veränderbaren Ausgangsspannung aufgebaut werden kann.

Verwendete Hardware

RPi in Kombination mit der 'PiFace'-Karte als Bastelplattform

Dank der einfachen Bauweise bietet sich der RPi mit seinen frei zugänglichen GPIO-Pins als ideale Bastelplattform an. Trotzdem kann es beim anfänglichen Experimentieren mit Schaltungen öfters zu kleinen Fehlern kommen, die schlimmstenfalls die empfindliche Elektronik des RPi dauerhaft beschädigen können.

Daher wird bei diesem Projekt zusätzlich mit der 'PiFace[1]'-Karte gearbeitet, die man auf die GPIO-Pins stecken kann. Diese Erweiterungskarte verschaltet die GPIO-Pins auf je 8 digitale Ein- und Ausgänge sowie 2 Relais, die eine galvanische Trennung von Stromkreisen ermöglichen. Damit besteht auch für Einsteiger ein gewisser Schutz für die Steuerelektronik des RPi.

Auch im weiteren Verlauf dieser Einführung soll noch auf eine Trennung der Stromkreise Wert gelegt werden, so dass für erste digitale Schaltexperimente ein Optokoppler genutzt wird. Die spätere Nutzung der 'Input Pins' des PiFace um eine Steuerung der D/A-Wandlung durch bestimmte Ereignisse zu ermöglichen, erfolgt ebenfalls passiv.

Hinweis: Auch wenn mit vermeintlich 'sicheren' Transformatoren gebastelt wird, muss stets bedacht werden, dass diese an einem 230V-Stromnetz betrieben werden und man eher einmal mehr als weniger prüfen sollte, ob man durch eventuelle Fehler mit lebensgefährlicher Spannung in Berührung kommt!

Auswahl eines Beispielprojektes

Günstige Möglichkeiten ein Gerät zu finden, das mit analogen Spannungen arbeitet, bieten sich u.a. im Spielzeugbereich. Im Grunde eignet sich alles, was mit Batterien oder mit Gleichspannungen unter 24 V betrieben wird.

Da jedoch ein Ziel das Steuern von analogen Spannungen ist, bietet sich insbesondere alles an, bei dem Potentiometer eingesetzt werden. Einen dieser 'Handregler' sollte man übrig haben, da er von seinem Anschlusskabel abgetrennt werden muss, um den oft proprietären Steckanschluss nutzen zu können. In diesem Sinne wird hier eine handelsübliche Spielzeug-Autorennbahn mit Potentiometer-Handreglern genutzt.

Sonstige Bauteile

Für die ersten Grundlagen (s. Teile 2 & 3) genügen bereits rund 2 m isolierter Draht, der nicht aus verdrillten feinen Adern (Litze) bestehen sollte, 50 cm nicht-isolierter Draht, einige niederohmige Widerstände (z.B. je 2 mal 100 Ohm, 80, 60, sowie 20) und ein 'Experimentierbrett' (engl. Breadboard).


Grundlagen und Vorbereitung des Projekts

Umwandlung von 1/0 zu Ein/Aus mit einem Relais

Vom Prinzip her ist jede Umwandlung eines digitalen 0 oder 1 Signals (das über eine bestimmte Spannungsdifferenz festgelegt ist) in eine (nutzbare) Spannung bereits eine D/A-Wandlung. Dies wird schlicht so realisiert, dass mit einer Eingabe am RPi die Nutzspannung des 'Verbrauchers' zunächst einfach an- und ausgeschaltet wird.

Vorbereitung der zu steuernden Hardware

a. Um Fehlerquellen auszuschließen sollte zunächst (und ggf. auch später!) kurz getestet werden, ob der vorhandene Regler wie erwartet funktioniert.

Fixierung der Reglerkabel

b. Nach dem Trennen des Reglers von der Einspeisung (und ggf. Ziehen des Netzsteckers) muss das Regler-Kabel abgeschnitten werden (eher nahe beim Regler, da das Kabel bald bis zum Breadboard reichen soll). Die neuen Enden des Einspeiseteils werden abisoliert und auf dem Breadboard diagonal zueinander mit einigen Spalten Abstand fixiert. Auch können bereits die Drähte, die später zum RPi führen, jeweils in den passenden kontaktführenden Spalten eingesteckt werden, z. B. wie rechts zu sehen (die nicht beschrifteten Drähte können vorerst ignoriert werden):

c. Nun bietet sich eine gute Gelegenheit die maximale Spannung am Nutzgerät zu messen. Man verbindet das Regler-Kabel (nun ohne Regler) wieder mit der Einspeisung und die offenen Enden der Drähte mit dem Messgerät, bei dem zunächst ein Messbereich von ca. 10-50 Volt gewählt werden sollte. Dies sollte dann z.B. 14,8 V anzeigen. Natürlich können auch die beiden offenen Enden einen kleinen Moment kurz geschlossen werden, man sollte aber bedenken, dass das zu regelnde Nutzgerät dann die maximal vorgesehene Spannung erhält (hier: maximales Tempo).

Vorbereitung des RPi

Es wird davon ausgegangen, dass entsprechend des zugehörigen 'manual' das PiFace bereits auf den RPi gesteckt ist, die nötigen python-Bibliotheken installiert sind und man sich im Terminal-Arbeitsverzeichnis 'pi' befindet.

a. Zunächst wird der PiFace-Emulator (im Terminal direkt aus dem Arbeitsverzeichnis) gestartet: piface/scripts/piface-emulator

b. Wenn alles richtig installiert wurde, erscheint ein Fenster (unten links), bei dem die vorerst wichtigen blauen Signale am rechten Rand wie folgt angezeigt werden sollten:

Piface-Emulator im default-Zustand Piface-Relais 1 auf '1' geschaltet

c. Das rechte Fenster ergibt sich, wenn man nun im Fenster auf "Override Enable" und dann "Output Pin 1" klickt. Es müsste ein "Klick" vom Relais 1 zu hören sein sowie der Schaltzustand des unteren Relais 1 (das an den Output Pin 1 gekoppelt ist) auf die Verbindung der beiden unteren Anschlüsse wechseln. Zugleich wird das erste LED-Icon beim Output Pin 1 rot sowie das zugehörige LED-Icon blau.

Schema der Piface-Relais

d. Rechts ist der Schaltzustand der Relais, die zu Beginn genutzt werden, im Grundzustand dargestellt (jeweils der mittlere und obere Kontakt sind kurzgeschlossen, der jeweils untere Kontakt ist frei):

e. Ein weiterer Klick auf "Output Pin 1" versetzt das Relais in den Ausgangszustand, der vor dem nächsten Schritt wieder eingestellt werden sollte.

f. Das Relais lässt sich auch mittels eines Python-Scripts vom RPi aus ansteuern. Dazu wird folgende Textdatei "wandler.py" im Arbeitsverzeichnis abgespeichert und mit dem Befehl "python wandler.py" gestartet:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# wandler.py
from time import sleep
import piface.pfio as pfio
pfio.init()
pfio.digital_write(1,1)
print "Strom an"
sleep(2)
pfio.digital_write(1,0)
print "Strom aus"

Nach dem Absetzen des Befehls wechselt nun das blaue Signal an Relais 1 für 2 Sekunden und das Relais klickt entsprechend.

Einsatz eines Relais' zur Umsetzung von Spannungsänderungen

a. Ist das Relais wieder im Ausgangszustand, befestigt man nun einen der vom Breadboard führenden Drähte am unteren und einen am mittleren Relaiseingang (im Moment ist die Polarität noch egal). Zunächst sollte nichts passieren (das Relais hält diesen ja Stromkreis noch offen).

b. Startet man aber das Script wieder (python wandler.py) oder klickt auf 'Output Pin 1' wird der Nutzstromkreis geschlossen. Nochmals aufgepasst: unser Nutzer erhält wieder die maximal vorgesehene Spannung - also besser vorher im Script "sleep(0.3)" setzen und speichern.

c. Im Prinzip ist damit die programmgesteuerte Umsetzung eines 0/1 Signals in z.B. eine 0V/15V Spannung erreicht.

d. Da wir bald verschiedene Steuerspannungen schalten wollen, geht es jetzt darum herauszufinden, bei welcher Spannung unser Nutzgerät gerade noch bewegt wird. Dies probiert man aus - mit dem kleinsten Widerstand beginnend: indem einer der Drähte in eine freie Breadboardspalte gesteckt wird und aus dieser Spalte der Widerstand zu dem 'alten' Steckplatz des Drahtes geführt wird. Nun startet man jeweils das Script bis der Widerstand so hoch ist, dass die Anlaufspannung beim Nutzgerätes gut ausreicht, eine Reaktion des Nutzgerät (Fahrzeug bewegt sich) zu bewirken (z.B. bei 50 Ohm beträgt der Strom im Mittel ca. 130 mA während ohne 190 mA fließen).


Ansteuerung von 3 Schaltstufen

Kombination von 2 Relais

Beschaltung der Relais

a. Die einfachste Stufe der weiteren Verschaltung erreicht man, indem der Widerstand mit einem 2. Relais überbrückt wird. Relais 1 kann dann als 'Hauptschalter', Relais 2 als Spannungsumschalter genutzt werden:

b. Diese Beschaltung kann sogleich mit dem PiFace-Emulator ausprobiert werden. Damit können wir bereits 3 Schaltstufen steuern: keine, verminderte und volle Spannung.

c. Theoretisch ließe sich auch noch eine 4. Spannungsstufe erzeugen, da mit 2 'Bits' (Ein/Aus bei 2 Relais) bereits 4 verschiedene Signale darstellbar sind. Beim jetzigen Aufbau werden aber lediglich die (pin1,pin2)-Signale (0,0), (1,0) und (1,1) 'genutzt', da Relais 1 als Hauptschalter vorgesehen ist und die Kombination (0,1) so nicht ausgewertet wird.

Programmgesteuerte Schaltung von 2 Relais

a. Mit einem veränderten python-Script "wandler2.py" ist auch die programmgesteuerte Schaltung möglich. Dabei werden zusätzlich die Tasten 1 und 2 des PiFace genutzt, um nach dem Start des Scripts (python wandler2.py) den Hauptschalter (Relais 1) zu steuern:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# wandler2.py

from time import sleep
import piface.pfio as pfio
pfio.init()

taste_1=0
taste_2=0
intervall_a=0.1
intervall_b=0.5
# Die Intervalle bestimmen die Schaltzeit für volle/verminderte Spannung

print "Zum Start Taste 1 drücken, zum Stoppen Taste 2"
pfio.digital_write(1,0)
pfio.digital_write(2,0)
while taste_1 == 0:
  sleep(intervall_a)
  taste_1=pfio.digital_read(1)
# Der o.g. 'sleep'-Befehl bestimmt die Abfragepausen für Taste 1

pfio.digital_write(1,1)
print "Strom an!"

while taste_2 == 0:
  pfio.digital_write(2,1)
  sleep(intervall_a)
  pfio.digital_write(2,0)
  sleep(intervall_b)
  taste_2=pfio.digital_read(2)

pfio.digital_write(1,0)
print "Strom aus!"

b. Falls beim Ausprobieren von Script-Änderungen mal was schief geht, kann das Script stets auch mit der Tastenkombination (CTRL-C) gestoppt werden. U.U. muss dann noch zusätzlich Relais 1 und/oder 2 via Emulator zurückgesetzt werden.

c. Beim Verändern des Scripts fällt bald auf, dass die bisherige Programmsteuerung keine direkte Möglichkeit vorsieht, auf Ereignisse zu reagieren. Immerhin wird ein mechanisches Gerät gesteuert, bei dem mit Ausfällen, Fertigungstoleranzen, Umwelteinflüssen etc. zu rechnen ist (im Script wird dies bislang 'nur' durch die Abbruchbedingung 'Taste 2' berücksichtigt).

Einfache Sensor-Signale als steuernde Elemente eines Programms

a. Eine wichtige Anwendung von D/A-Steuerungen ist die mögliche Reaktion dieser Steuerung auf 'äußere' Ereignisse, die z.B. mit Hilfe von Sensoren leistbar ist.

einfacher Sensor

b. Für unsere Zwecke genügt zunächst ein sehr einfacher Sensor, der ein 0- oder 1-Signal liefert und idealerweise direkt am 'Input Pin 1' des PiFace angeschlossen werden kann. So liegt beim Input Pin 1 das Signal '1' an, wenn eine Verbindung zu 'Input GND' besteht.

Z.B. können 2 unisolierte Drähte so platziert werden, dass ein vorbeifahrendes Fahrzeug einen von ihnen genügend bewegt um den Kontakt kurze Zeit zu öffnen. Genau dann liefert dieser 'Sensor' das Signal '0'. Eine - die Schwerkraft nutzende - mögliche Bauform ist rechts abgebildet ;-)

c. Natürlich werden zusätzlich 2 isolierte Drähte benötigt, um jeden der beiden offenen Drähte geschützt mit Input Pin 1 und Input GND zu verbinden.

d. Bei jeder Durchfahrt liefert der Sensor nun ein '0'-Signal, was im Script sowohl für eine Zeitmessung als auch für ein 'Schaltintervall-Array' genutzt werden kann. Dort können abwechselnd für beide Spannungen Zeiten (die in etwa zum jeweiligen Streckenabschnitt passen) 'programmiert' werden. Statt Taste 1 wird nun der Sensor ausgewertet (wobei Taste 1 als Sensor-Ersatz insoweit genutzt werden kann, dass sie gedrückt bleiben bzw. kurz losgelassen werden muss). Zur genaueren Zeitmessung wird noch das modul 'clock' benötigt. "wandler3.py" könnte also so aussehen:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# wandler3.py

from time import clock
import piface.pfio as pfio
sensor_1=1
sensor_2=0
rundenzahl=0
v_wechsel=0
vorrunde=0
index_zaehler=1

zeit_array=[0,0.2,0.4,0.2,0.4,0.2,0.4,0.2,5,0.2,6]
# dieses array enthält die sek. bis zum Spannungswechsel
array_laenge=9
# legt fest, wie viel Werte des arrays genutzt werden sollen

sensor_aus=1.3
# bis der Sensor sicher in die Ruhestellung kippt, wird er nicht ausgelesen
 
pfio.init()
pfio.digital_write(2,0)
pfio.digital_write(1,1)
# das Fahrzeug wird langsam zum Start (=Sensor) bewegt
while sensor_1 == 1 :
  sensor_1=pfio.digital_read(1)
 
print "fliegender Start... zum Beenden Taste 2 drücken"
print "Runde Nr., Ges.Zeit, Rundenzeit, mittlere Rundenzeit"
start_zeit=clock()
runden_start=start_zeit
 
while sensor_2 == 0 :
  sensor_2=pfio.digital_read(2)
  v_wechsel=1-v_wechsel
  pfio.digital_write(2,v_wechsel)
  sensor_zeit=clock()
 
  while zeit_array[index_zaehler]+sensor_zeit > clock() :
    if runden_start+sensor_aus < clock() :

      sensor_1=pfio.digital_read(1) 
      if sensor_1 == 0 :
        rundenzahl=rundenzahl+1
        runden_start=clock()
        zeit=runden_start-start_zeit
        print rundenzahl, zeit, zeit-vorrunde, zeit/rundenzahl
        vorrunde=zeit
        sensor_zeit=0
        index_zaehler=0
        v_wechsel=0
 
  index_zaehler=index_zaehler+1
  if index_zaehler > array_laenge :
    sensor_2=1
    print "array-Ende erreicht!"
 
pfio.digital_write(2,0)
pfio.digital_write(1,0)
print "Outp 1 & 2 auf 0!"

Wird das Array-Ende erreicht, wurden entweder zu wenige Einträge vorgesehen oder es befindet sich kein Fahrzeug (mehr) auf der Strecke, das den Sensor und damit des Zurücksetzen des Arrays auslösen konnte.

e. Das Array ist an die jeweilige Strecke anzupassen, wobei der vorderste Eintrag ungenutzt bleibt und dann mit der Dauer für maximale Spannung begonnen wird. Solange man mit Relais arbeitet, sollten die Schaltzeiten nicht zu kurz sein (>0.1 sek.), da diese eine gewisse mechanische Trägheit besitzen.

f. Eben diese mechanische Beschaffenheit der Relais (Verschleiß) ist auch ein guter Grund, auf 'volle' digitale Signalumwandlung umzustellen.


Optokoppler als Ersatz für Relais

Ähnlich wie ein Relais dient ein Optokoppler dazu, eine Signalübertragung zwischen zwei getrennten Stromkreisen zu ermöglichen. Bei diesem Projekt liegt der Einsatz von Optokopplern nahe, da sie schneller schalten und keine beweglichen Teile besitzen. Für unsere Zwecke benötigen wir nun als zusätzliche Elemente: Optokoppler (CNY 17-4), npn-Transistoren (BC 337-40) zur Signalverstärkung sowie einige Widerstände im Bereich von 2k und 400 Ohm.

Kaskadierung von Transistoren zur Signalverstärkung

a. Entsprechend Schritt 2.4.d. (ein Relais bei 50 Ohm) wird zunächst ein Optokoppler eingesetzt, dessen Signal durch einen Transistor verstärkt wird, um die 'Grundspannung' zu schalten (Pin 3 und 6 beim Optokoppler sollten unbeschaltet bleiben, allein der 'Lichtstrom' reicht für eine Ansteuerung aus):

Optokoppler mit Transistor

b. Da immer mit einer gewissen Toleranz bei allen Komponenten zu rechnen ist, kann es sein, dass u.U. die Widerstände etwas größer oder kleiner gewählt werden müssen. Beim Ausprobieren sollte man hier in 10% Schritten variieren.

c. Bei Austesten mit Emulator oder Script ist auch zu beachten, dass nun 'Output Pin 8' genutzt wird, da dieser nicht mit den Relais verschaltet ist.

Umsetzung von 3 Schaltstufen mit Optokopplern

a. Entsprechend dem Vorgehen beim Relais kann nun auch der kleine Widerstand zusätzlich beschaltet werden um seine gesteuerte Überbrückung zu ermöglichen. Da hier eine relativ geringe Spannung aufgeschaltet wird, kann zu Beginn eine Diode eingesetzt werden, die die Schaltstufe 'maximale Spannung' anzeigt.

Kombination von 2 Optokopplern

b. Vor dem Testen ist wieder zu beachten, dass nun zusätzlich 'Output Pin 7' genutzt wird (statt Output Pin 2).

c. Neben dem Weglassen der Diode (was die Maximalgeschwindigkeit leicht erhöht), können auch statt der 400 Ohm Widerstände 1k-Werte oder höher gewählt werden, wenn dadurch der jeweilige Basisstrom noch hoch genug ist. Im vorliegenden Fall war erst ab 400 Ohm keine weitere Tempoerhöhung mehr feststellbar.

d. Eine mögliche Realisierung sieht so aus: http://youtu.be/xQ7N-PrIULk

Zusätzliche Erhöhung der Schaltstufen bei D/A-Wandlern

a. Zwar benötigen wir in unserem speziellen Beispiel eine 'Grundspannung', die sich dahingehend auswirkt, dass - wie unter 3.1.c. erwähnt - eine Signalkombination nicht ausgewertet wird, aber mit jeder weiteren Schaltstufe würde sich dieses Problem (theoretisch) relativieren, da bei geschickter Auswahl der Widerstände (z.B. im Verhältnis 1 zu 2) jeweils eine Verdoppelung der Kombinationsmöglichkeiten erreichbar ist.

b. Wird hier der 50 Ohm Widerstand asymmetrisch geteilt (z.B. 15 + 35 Ohm, s.a. Spannungsteiler) um dort ein weiteres Signal umsetzen zu können, ergeben sich direkt folgende 5 Schaltstufen (aus, 50, 35, 15 und 0 Ohm) u.s.w.:

Erhöhung der Schaltstufen

c. Zur Ansteuerung dieser Schaltstufen wäre das Script so zu ändern, dass nun zwischen mehr als 2 Stufen gewechselt werden kann und im Array entsprechende Zusatzdaten vorgegeben und ausgelesen werden. Mehr als diese Stufen sind im konkreten Fall aber nicht sinnvoll, da die entstehende Verlustleistung in der Schaltung die maximal verfügbare Leistung reduziert.


Weiterführende Ideen

Die Ausbaumöglichkeiten dieses Projektes sind vielfältig:

Hardwareseitige Ausbauvarianten

- beispielhafte Umsetzung einer differenzierten Abstufung mittels eines möglichst oft durch 2 teilbaren Anfangswertes und der Teiler (640 Ohm, 320, 160...) oder in 10er Potenzen. Denkbar wäre auch eine Parallelschaltung der 'zuschaltbaren' Widerstände [2] - je nach Umsetzung wären natürlich die Vorwiderstände der Transistoren anzupassen;

- Nachbau des Projekts mit einem Mikrocontroller (ggf. mit LCD-Anzeige);

- Umbau der Steuerung mit dem Ziel, sie direkt an die GPIO-Pins des RPi anzuschließen;

- Entwurf einer Zusatzschaltung, die in diesem Beispiel eine Rückmeldung liefert, ob ein Verbraucher aktiv ist oder nicht (Fahrzeug noch auf der Strecke?);

- Entwurf einer Zusatzschaltung, die erkennt wie viel Strom fliesst: damit wären Rückschlüsse auf den Streckenverlauf möglich (Kurve=etwas mehr Strom, Steigung=noch mehr Strom nötig, etc.) und so auch eine programmgesteuerte Optimierung der Array-Schaltzeiten dankbar;

- Einsatz anderer Sensortechniken und/oder mehrerer Sensoren zur Optimierung der Schnelligkeit oder parallelen Steuerung eines 2. Fahrzeuges;

Softwareseitige Ausbauvarianten

- Optimierung des Scripts, indem die Sensor-Abfrage über einen 'Listener' umgesetzt wird;

- Erweiterung des Scripts um eine GUI mit Hilfe der python-lib Tkinter, um einen Nutzerzugriff auf das Steuerarray und/oder eine 'Verwaltung' mehrerer Fahrzeuge;

- Einbindung eines Web-Interface um eine 'Fernsteuerung' zu ermöglichen...

...in jedem Fall: viel Spaß beim Basteln!

Siehe auch