Schalten und walten mit dem Bastel-PC

Hardwarezugriff am Raspberry Pi: Node.js versus PHP
Keine Kommentare

Der Tessel brachte Entwickler erstmals auf den Gedanken, dass man nicht echtzeitkritische Embedded-Systeme auch mit Programmiersprachen abseits von C entwickeln kann. Die hauseigene JavaScript Runtime und die Hardware haben in der Praxis allerdings keine wirkliche Massenmarktpenetration erreicht: Der Standardprozessrechner bleibt der Raspberry Pi. Der Artikel nutzt einen Raspberry Pi 3 B, um Möglichkeiten zum Zugriff auf reale Hardware zu evaluieren. Schon aus Platzgründen ist es völlig unmöglich, die Thematik komplett zu erschlagen – es geht uns vielmehr darum, einen Überblick über die Möglichkeiten zu schaffen.

Wer mit einer Webapplikation arbeitet, hat mitunter das Bedürfnis, diverse Güter der realen Welt zu steuern. Neben dem klassischen Beispiel des Ein- und Ausschaltens von Lampen über Relais oder Schaltelemente gäbe es beispielsweise auch Systeme, die Sensorinformationen – Stichwort: Temperatur – bereitstellen und auf eine grafische Art und Weise zur Verfügung stellen. Beim Entwerfen derartiger Solutions kann es vernünftig sein, auf Webtechnologien zu setzen. Ein in JavaScript gehaltenes Produkt ist vom Handling her wesentlich bequemer als ein klassischer C++-Monolith – insbesondere dann, wenn man als Entwickler bisher wenig Erfahrung mit C++ und Co. gesammelt hat.

Welches Betriebssystem?

Auch wenn sowohl Android Things als auch Windows 10 for IoT unsere beiden Schwestermagazine gut beschäftigen, wollen wir in den folgenden Schritten beim Betriebssystem auf eine klassische Version von Raspbian setzen. Laden Sie das Produkt wie gewohnt herunter und installieren Sie es auf Ihren Prozessrechner. Schon im Interesse der Bequemlichkeit ist es empfehlenswert, einen Ethernetanschluss bereitzustellen, um benötigte Komponenten schnell herunterzuladen. Als Zielhardware soll in den folgenden Schritten ein Raspberry Pi 3B dienen – ältere und neuere Rechner sollten sich im Großen und Ganzen ohne Probleme verwenden lassen, bei nativen Codeinseln ist mitunter eine kleine Anpassung der Registeradressen und Co. erforderlich. Wie dem auch sei, Sie müssen sich im ersten Schritt für eine Arbeitsumgebung entscheiden. Unser erster Versuch soll Node.js betreffen.

Ärgerlich ist, dass die Raspberry Pi Foundation in Raspbian nur eine sehr veraltete Version von Node.js bereitstellt: Zum Zeitpunkt der Drucklegung war es Version 4.8.irgendwas. Zur Umgehung des Problems bietet es sich an, den Prozessrechner als stinknormale Workstation zu betrachten und wie gewohnt mit folgenden Kommandos aufzurüsten:

pi@raspberrypi:~ $ curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
## Installing the NodeSource Node.js v8.x LTS Carbon repo...
. . .
pi@raspberrypi:~ $ sudo apt-get install -y nodejs

Node.js liegt seit längerer Zeit nicht mehr nur als x86- bzw. x64-, sondern auch als ARM-Binärpaket vor. So ist sichergestellt, dass wir eine vergleichsweise aktuelle Version verwenden.

Wie steuern?

Wer Google nach Möglichkeiten des Zugriffs auf die GPIO-Pins des Raspberry Pi unter Node.js befragt, fühlt sich einer geradezu erschlagenden Menge von Optionen gegenübergestellt. Erfreulicherweise hat sich onoff mittlerweile als Quasistandard herauskristallisiert, weshalb wir es in den folgenden Schritten verwenden wollen (Kasten: „Was passiert im Hitergrund?“). Nach dem gewöhnlichen Anlegen eines neuen Node-Projekts unter Nutzung des Node Package Managers müssen Sie im nächsten Schritt onoff installieren. Dies erfolgt bei bestehender Internetverbindung idealerweise unter Nutzung von npm init: pi@raspberrypi:~/rpispace/onoff1 $ npm install onoff.

Was passiert im Hintergrund?

Auch unter Linux gibt es mehrere Arten, mit den GPIO-Pins des Prozessrechners zu interagieren. onoff nutzt hierbei ein als sysfs bezeichnetes Teil des Dateisystems, in dem die einzelnen Pins als Dateien abgebildet werden. Der Zugriff auf sysfs ist einerseits zwar sehr stabil, verhindert andererseits aber die Konfiguration von Pull-ups und ist von der Performance her nicht unbedingt die beste Lösung.

Im nächsten Schritt können wir uns der Realisierung eines primitiven Beispielprogramms zuwenden: Als Klassiker bietet sich hierbei das Ausgeben einer Rechteckwelle an, deren Frequenz und Frequenzstabilität sodann mit diversen rüstungselektronischen Messgeräten näher analysiert werden können. Öffnen Sie deshalb die JavaScript-Datei unseres Node-Projekts, und beginnen Sie mit der Codeanpassung, wie in Listing 1 dargestellt.

const Gpio = require('onoff').Gpio;
const led = new Gpio(17, 'out');
while(1==1)
{
  led.writeSync(1);
  led.writeSync(0);
  led.writeSync(1);
  led.writeSync(0);
  led.writeSync(1);
  led.writeSync(0);
}

onoff bietet sowohl ein synchrones als auch ein asynchrones API an: Für einen ersten Versuch wollen wir auf die synchrone Methode zurückgreifen. Von besonderem Interesse ist hier fürs Erste eigentlich nur, welche Zahl die an new Gpio() übergebenen Parameter beschreiben. Die Antwort ist, dass man im Hause onoff auf die Broadcomm-Pins setzt: Der hier verwendete Pin Numero 17 würde beispielsweise dem elften physikalischen Pin entsprechen. Als nächsten Test können Sie einen Oszillografen und einen Modulationsdomänenanalysator an den Prozessrechner anschließen, um mehr Informationen über Signalqualität und Co. zu erhalten.

Eine Messung mit dem Oszilloskop zeigt sich an dieser Stelle als wenig wertvoll. Zwischen den einzelnen Durchläufen der Schleife ist soviel Varianz, dass es nur schwer möglich ist, festzustellen, welche der Wellenformen nun für einen bestimmten Teil der Schleife verantwortlich sind. Wesentlich vernünftiger ist in diesem Zusammenhang die Nutzung des MDAs, der das in Abbildung 1 gezeigte Bild liefert.

Abb. 1: In der Modulationsdomäne sieht man klarer

Abb. 1: In der Modulationsdomäne sieht man klarer

Die erreichte Hauptleistung im Bereich von 160 kHz mag im Vergleich zu nativem Code gering erscheinen, dürfte in der Praxis aber für viele Mess-, Steuer- und Regelaufgaben problemlos ausreichen. Kritisch ist in diesem Zusammenhang nur die unten links hervorgehobene Verletzung – manche Durchläufe der Runtime nehmen wesentlich mehr Zeit in Anspruch. Dies kann insofern problematisch sein, als in einer derartigen Totzeit – zwar nur selten, aber doch – ein wichtiges und zu überwachendes Ereignis geschehen könnte.

Wie dem auch sei, wir wollen im nächsten Schritt noch einen weiteren Versuch machen und die Runtime mit Superuser-Rechten aufrufen – das in Abbildung 1 gezeigte Diagramm entstand, man glaubt es kaum, ohne sudo-Rechte. Abbildung 2 zeigt das Vergleichsdiagramm, das bei Nutzung von sudo entsteht.

Abb. 2: Mit „sudo“ arbeitet Node.js etwas schneller

Abb. 2: Mit „sudo“ arbeitet Node.js etwas schneller

Bevor wir uns weiteren Aufgaben zuwenden, sei allerdings noch angemerkt, dass das Durchführen von Benchmarks auf unixoiden Prozessrechnern alles andere als einfach ist. Ein Prozessrechner dient nämlich fast nie nur einem Herrn – in der Praxis ist es so gut wie immer so, dass eine Vielzahl verschiedener Tasks die Prozessoren beeinflusst. So könnte beispielsweise ein apt-get-Lauf oder ein ähnlicher Prozess dafür sorgen, dass die Leistung kurzfristig wesentlich geringer ist. Wir versuchen, dieses Problem hier zu kompensieren, indem wir die Speichertiefe des HP 53310A komplett ausnutzen. Eine Rundumgarantie für das Vermeiden solcher Effekte stellt allerdings auch das nicht dar.

Und jetzt: die Eingabe

Das Ausgeben von Signalen mag eine durchaus attraktive Aktivität sein – in der Praxis hat ein Prozessrechner allerdings so gut wie immer auch die Aufgabe, Informationen einzulesen. Zum Bewerten der Leseperformance bietet es sich an, den Prozessrechner mit einer bekannten Welle zu ärgern und dann zu messen, wie viele Samplepunkte er jeweils im High- und Low-Bereich aufnehmen kann.

Bevor wir uns der vergleichsweise komplexen Konfiguration der Software zuwenden, wollen wir mit der Einrichtung der Hardware beginnen. Als Signalquelle kann so ziemlich alles dienen, was ein Rechtecksignal vergleichsweise geringer Frequenz und guter Stabilität generieren kann. Wir wollen in den folgenden Schritten auf den AWG2021 setzen, der im Labor des Autors seit vielen Jahren unauffällig seinen Dienst tut. Seine Konfiguration präsentiert sich wie in Abbildung 3 gezeigt.

Abb. 3: AWG lassen sich meist auch als gewöhnliche Funktionsgeneratoren nutzen

Abb. 3: AWG lassen sich meist auch als gewöhnliche Funktionsgeneratoren nutzen

Besonders relevant ist in diesem Zusammenhang nur, dass ältere AWG nur sehr eingeschränkt mit Lasten umgehen können, die keine 50-Ohm-Impendanz darstellen. Zur Umgehung dieses Problems reicht es allerdings aus, einen derartigen Widerstand parallelzuschalten. Der Autor dieser Zeilen löst das gerne mit einer kleinen Platine (Abb. 4), die – einmal vorbereitet – schnell zur Hand ist.

Abb. 4: Diese kleine Platine sichert die Impendanz

Abb. 4: Diese kleine Platine sichert die Impendanz

Als Nächstes wollen wir abermals in den Korpus der Index.js zurückkehren, der sich nun wie in Listing 2 präsentiert.

const Gpio = require('onoff').Gpio;
const pin = new Gpio(17, 'in');

var lowers = [];
var highers = [];
var readingNow = 0;
var inval;
var i=0;

while(1==1) {
  //Array laden
  lowers = [];
  highers = [];
  for(i=0;i<5000;i++) {
    lowers.push(0); 
    highers.push(0);
}

Aufgrund der zuvor angesprochenen Problematik der Varianz der Ergebnisse beginnen wir unsere Arbeiten damit, einen Speicher für 5 000 Durchläufe anzulegen: Auf diese Art und Weise sind sehr kurzfristige Störungen bis zu einem gewissen Grad ausgeschaltet. Die Erstinitalisierung des Arrays sorgt dafür, dass Garbage Collector, Speicherallokation und sonstige Nettigkeiten während der Messung mattgesetzt sind (Listing 3).

readingNow=false;
i=0;
while(i<5000) {
inval=pin.readSync();
if(readingNow==0) {
if(inval==0)lowers[i]++;
else readingNow=1;
}
if(readingNow==1) {
if(inval==1)highers[i]++;
else {
readingNow=0;
i++;
}
}
}

Im nächsten Schritt beginnt der eigentliche Messalgorithmus, den wir weiter oben besprochen haben. Wir zählen so lange, bis eine Wertänderung auftritt. Sobald diese passiert, wechseln wir den Modus. Nach jeder erfolgreich abgearbeiteten Wellenform – also einer Low- und einer High-Zone – inkrementieren wir den Speicher um eins, um nach dem Abarbeiten aller Speicherzellen aus der Endlosschleife auszubrechen (Listing 4).

lowSum=0;
highSum=0;
for(i=0;i<5000;i++) {
  lowSum+=lowers[i];  
  highSum+=highers[i];
}
lowSum/=5000;
highSum/=5000;
console.log("LowSum = " + lowSum);
console.log("HighSum = " + highSum);

Danach bilden wir einen gleitenden Durchschnitt, der in die Konsole von Node.js ausgegeben wird. In der Arbeitssituation des Autors entstand das in Listing 5 gezeigte Ergebnis.

pi@raspberrypi:~/rpispace/onoff2 $ node index.js
LowSum = 108.5104
HighSum = 22.47
LowSum = 21.4836
HighSum = 22.4128
LowSum = 21.6458
HighSum = 22.6912
. . .

Der erste Durchlauf dauerte insofern länger, als der Funktionsgenerator erst nach dem Anwerfen des Messprogramms aktiviert wurde. Im Zusammenspiel mit der weiter oben beschriebenen Wellenform – ein 5-kHz-Rechteck besteht pro Sekunde aus 5 000 High- und 5 000 Low-Zonen – können wir die Samplinggeschwindigkeit ermitteln: Pro Sekunde arbeitet der Prozessrechner etwa 220 000 Punkte ab.

Und jetzt in effizient

Unsere soeben realisierte Stressbenchmark ist eine höchst ungewöhnliche Aufgabe für einen Prozessrechner: Normalerweise verbringen die Teile den Großteil ihrer aktiven Zeit damit, auf Ereignisse zu warten. Sogenannte Hardware-Interrupts sorgen an dieser Stelle insofern für Abhilfe, als sie das Warten auch ohne Einbeziehen des Hauptprozessors bewerkstelligen. Dahinter steht die Idee, dass der Prozessrechner in seiner GPIO-Hardware ein Modul enthält, das Pegeländerungen erkennt und den Hauptprozessor in diesem Fall mit einem als Interrupt bezeichneten Signal weckt.

Zur Implementierung dieser Funktion wollen wir ein drittes Beispiel namens onoff3 realisieren, dessen Korpus wie in Listing 6 aussieht.

const Gpio = require('onoff').Gpio;
const scope = new Gpio(4, 'out');
const insig = new Gpio(17, 'in', 'both');

insig.watch(function (err, value) {
  scope.writeSync(value);
});

Anstatt wie bisher nur ein GPIO-Objekt anzulegen, erzeugen wir derer nun zwei. Interessant ist, dass der Eingang im Rahmen seiner Deklaration einen Wert übergeben bekommt, der angibt, bei welchen Flankentransaktionen ein Interrupt auslösen soll. Im nächsten Schritt rufen wir die Funktion watch auf, um dafür zu sorgen, dass eingehende Interrupt-Ereignisse auch bei unserer Programmlogik ankommen. Die eigentliche Verarbeitung ist dann simpel: Wir schreiben den angelieferten Wert in Richtung des Ausgangspins, wo er zum Abernten bereitsteht.

Zum Bemessen der Ergebnisse wollen wir an dieser Stelle auf einen digitalen Phosphoroszillografen zurückgreifen: Es handelt sich dabei um ein Oszilloskop, das die Häufigkeit der verschiedenen Ereignisse durch farbige Intensität anzeigt. Wer die beiden Kanäle verbindet, sieht bei Nutzung eines Danaher TDS 754D (Kasten: „Am Graumarkt“) das in Abbildung 5 gezeigte Resultat.

Abb. 5: Der Abstand zwischen Ereignis und Auslösung beträgt etwa 120 µs.

Am Graumarkt

DPO ist ein Markenzeichen von Danaher: Andere Hersteller bieten ähnliche Funktionen an. Wer – wie der Autor – eine Vorliebe für die Analysefunktionen von LeCroy hat, findet im Gebrauchtmarkt in der LC-Serie Kandidaten. Alternativ bietet es sich an, einen Tektronix 7xxD mit einem LeCroy 93xx zu kombinieren. Danaher-Oszilloskope der A-, B- und C-Serie sind weniger empfehlenswert, weil ihre DPO-Funktion Häufigkeitsinformationen verwirft.

Auch hier gilt, dass schnelles Reagieren nicht unbedingt gewünscht ist. Knöpfe bzw. Taster – insbesondere jene der eher preiswerten Bauart – haben nämlich die unangenehme Eigenschaft, beim Einschalten zu prellen. Zur Umgehung dieses Problems bietet sich folgendes Codestück an: const button = new Gpio(4, ‚in‘, ‚rising‘, {debounceTimeout: 10});.

Der Konstruktor des GPIO-Objekts bekommt nun ein zusätzliches JSON-Element übergeben, das diverse Eigenschaften anliefern kann. Das hier verwendete Flag debounceTimeout teilt der Engine mit, dass sie 10 ms lang warten muss, bevor ein Knopfereignis ausgelöst werden darf. Auf diese Art und Weise ist sichergestellt, dass kurzfristiges Prellen des Knopfs nicht zu Problemen führt. Beachten Sie allerdings, dass eine derartige Lösung langsamer auf Eingaben reagiert. Insbesondere bei Knöpfen, die zur Bewegung von Cursors oder anderen Bildschirmelementen vorgesehen sind, ist es empfehlenswert, defensiv zu agieren und kurze Werte auszuwählen.

Ohne Software

Die Performance von onoff mag zum Bit-Banging gerade noch ausreichend sein, doch wirklich komfortabel ist es schon ob des Risikos des nebenher laufenden Garbage Collectors nicht. Wesentlich vernünftiger wäre es da, wenn man die Kommunikationsarbeit auf eine dedizierte Hardwareeinheit abladen kann und sich der in JavaScript gehaltene Code ausschließlich auf das Entgegennehmen von Informationen beschränkt. In den meisten Programmierumgebungen –Beispiele wären WiringPi, aber auch Android Things – sind hardwarebeschleunigte Busse Teil der gewöhnlichen APIs. Das onoff-Team hält sich hier nobel zurück und empfiehlt stattdessen die beiden Bibliotheken fivdi/i2c-bus und fivdi/spi-device.

Wer einen Logic Analyzer in der Hinterhand hat, findet in der Praxis schnell heraus, wie die Produkte funktionieren: Sie nutzen im Hintergrund allesamt die in Linux exponierten sysfs-Dateisystemelemente, um die Kommunikation mit der Hardware auch abseits des Raspberry Pi halbwegs einheitlich zu halten. Der Vollständigkeit halber wollen wir uns an dieser Stelle kurz einige Beispielprogramme ansehen. Als Erstes werfen wir einen Blick auf die SPI-Bibliothek, die unter anderem für die Ansteuerung von preiswert erhältlichen Displays ideal geeignet ist. Auch sie wird sowohl synchron als auch asynchron angeboten. Im Interesse der Einfachheit wollen wir ein asynchrones Beispiel des Entwicklers durchgehen.

Da eine vollständige Besprechung von SPI den Rahmen dieses Artikels sprengen würde, wollen wir uns an dieser Stelle etwas kürzer fassen. SPI-Transaktionen erfolgen prinzipiell bidirektional: Der Master wackelt mit dem Clock Pin und sendet und empfängt dabei Daten. Diese Transaktionen werden in der Bibliothek über Arrays abgebildet, die die beiden Puffer, die Länge der Transaktion und die Arbeitsgeschwindigkeit des Gesamtbusses beschreiben (Listing 7).

const message = [{
  sendBuffer: Buffer.from([0x01, 0xd0, 0x00]),
  receiveBuffer: Buffer.alloc(3),
  byteLength: 3,
  speedHz: 20000
}];

Das eigentliche Übertragen erfolgt sodann über eine Transfermethode, die neben dem Feld mit den verschiedenen Nachrichten auch einen Event Handler entgegennimmt, der beim erfolgreichen Durchlaufen der Transaktion aufgerufen wird. Er ist dafür verantwortlich, die im receiveBuffer angelieferten Informationen des Slave weiterzuverarbeiten:

mcp3008.transfer(message, function (err, message) {
  const rawValue = ((message[0].receiveBuffer[1] & 0x03) << 8) +
  . . .

SPI kann seine Stärken immer dann ausspielen, wenn ein Gerät mit möglichst hoher Bandbreite an den Prozessrechner angeschlossen werden soll. I2C ist immer dann stark, wenn es darum geht, eine Gruppe von möglichst vielen Sensoren, die individuell moderate Bandbreitenansprüche stellen, mit einem Prozessrechner zu verbinden. Von fivdi gibt es auch für I2C eine Bibliothek. Die Kommunikation über I2C erfolgt – prinzipbedingt – durch das Lesen und Schreiben einzelner Register. Daraus ergibt sich ein vergleichsweise einfaches API, das vom Entwickler der Bibliothek in einer synchronen und einer asynchronen Variante angeboten wird. Als Beispiel hierfür folgender Befehl, der 1 Byte auf synchrone Art und Weise in ein Register schreibt:

var i2c = require('i2c-bus'),
i2c1 = i2c.openSync(1);
. . .
i2c1.writeByteSync(DS1621_ADDR, CMD_ACCESS_CONFIG, 0x01);

Neben dem Herausfinden der korrekten Register ist eigentlich nur der Aufruf von openSync wichtig, der den Bus einsatzbereit macht. Das Ermitteln der Adresse der verschiedenen Geräte kann sodann unter Nutzung des Werkzeugs i2cdetect erfolgen – beachten Sie, dass die Arbeitsfrequenz von I2C unter Nutzung dieser Bibliothek nicht vom Entwickler festgelegt werden kann. Alternativ dazu gibt es allerdings eine zusätzliche Gruppe von Funktionen, die auf Intels SM-Bus optimiert sind: ein Protokoll, das man auf Hauptplatinen immer wieder findet und das beim Zugriff auf diverse Managementelemente der darunterliegenden Hardware hilfreich sein kann.

Und jetzt mit PHP

Auch wenn JavaScript und Co. der PHP-Programmierung mittlerweile bis zu einem gewissen Grad das Wasser abgegraben haben: Der LAMP-Stack begleitet den Autor dieser Zeilen seit seiner Jugend und ist kein Produkt, das man aus den Augen verlieren sollte. Da unser Raspberry Pi von Haus aus ohne die diversen Module ausgeliefert wird, müssen wir die fehlende Software im ersten Schritt nachinstallieren. Wir wollen in den folgenden Schritten auf Apache setzen, um die generierten Webseiten auszuliefern. Es steht Ihnen natürlich frei, einen leichteren Webserver zu nutzen – in diesem Fall ist die Einrichtung mitunter allerdings etwas komplizierter:

pi@raspberrypi:/var/www/html $ sudo apt-get install apache2  php libapache2-mod-php
Reading package lists... Done
Building dependency tree

In der Literatur findet man immer wieder Verweise auf die Pakete php5 oder php7: Sie werden von Raspbian nicht unterstützt. Das verwendete Paket php macht den Job allerdings genauso gut – es lädt einfach eine aktuelle Version von PHP herunter und macht sie für den Prozessrechner ansprechbar. Ob der engen Verzahnung zwischen der PHP Runtime und dem zugrunde liegenden Betriebssystem bietet es sich in einem ersten Versuch an, die in WiringPi inkludierten Kommandozeilenutilitys zur Steuerung der GPIO-Pins zu nutzen. Hierzu reicht beispielsweise der Code in Listing 8 aus.

<?php
$gpio_on = shell_exec("/usr/bin/gpio -g mode 17 out");
while(1){
           shell_exec("/usr/bin/gpio -g write 17 1");
           shell_exec("/usr/bin/gpio -g write 17 0");
           shell_exec("/usr/bin/gpio -g write 17 1");
           shell_exec("/usr/bin/gpio -g write 17 0");
}
?>

Aus systemtechnischer Sicht findet sich hier keine Raketenwissenschaft: Wir nutzen die in der PHP Runtime enthaltene Funktion shell_exec, um das Programm /usr/bin/gpio aufzurufen. Es sorgt sodann dafür, dass abwechselnd ein High-und ein Low-Wert am Ausgangspin erscheinen. Da unser Raspberry Pi von Haus aus inert ist, müssen wir vor der Endlosschleife noch einen Aufruf von mode platzieren, um die Pins in einen Ausgang umzuwandeln. Im nächsten Schritt können Sie das Programm wie gewohnt über einen Webbrowser ihrer Wahl auslösen. Ob der Endlosschleife wird das Laden der Webseite nie abgeschlossen – wundern Sie sich nicht darüber, wenn der Fortschrittsbalken des Browsers permanent pulsiert. Schließen Sie stattdessen einen Oszillographen an Pin 17 an, um die Ergebnisse der Arbeit unseres PHP-Programms näher in Blick nehmen zu können.

Das Messen des vorliegenden Programms wird dadurch erschwert, dass PHP in den Hauseinstellungen einem leeren Skript nur maximal 30 Sekunden Rechenzeit zugesteht: Das bedeutet, dass die Wellenformausgabe auf jeden Fall nach dem Laden der Seite nur 30 Sekunden lang andauert. Zudem ist das vorliegende Programm auch auf einem Raspberry Pi 3 ob des immensen Overheads alles andere als schnell. Abbildung 6 zeigt, was auf einem Modulationsdomänenanalysator zu sehen ist.

Abb. 6: Eine Arbeitsfrequenz im Bereich von 50 Hz ist nicht besonders schnell

Abb. 6: Eine Arbeitsfrequenz im Bereich von 50 Hz ist nicht besonders schnell

Schon aus der Logik heraus folgt, dass diese Vorgehensweise nur teilweise zielführend ist. Andererseits ist PHP auch nicht wirklich dafür vorgesehen, langfristig laufenden Code abzubilden – die Aufgabe der Sprache ist und bleibt nun mal das kurzfristige bevölkern dynamischer Inhalte. Wie dem auch sei, es gibt neben dem direkten Zugriff unter Nutzung der WiringPi-Hilfsprogramme mit der Bibliothek https://github.com/ronanguilloux/php-gpio auch eine Alternative. Das unter GitHub bereitstehende und als Standard geltende Projekt wurde allerdings seit mehreren Jahren nicht mehr gewartet, und taugt deswegen nur für Raspberry Pi der allerersten Generation. Unter https://github.com/calcinai/phpi gibt es allerdings eine weitere Alternative, die sich – zumindest laut der Beschreibung auf GitHub – wesentlich mehr Unterstützung erfreut. Kritisch ist hier allerdings, dass die Bibliothek nur für den Einsatz im CLI-Betrieb vorgesehen ist. Der Entwickler rät aus Stabilitätsgründen explizit davon ab, seine Bibliothek in „vom Web gesteuerten“ PHP-Programmen zu verwenden.

Aus Platzgründen können wir hier auf das Produkt nur konzeptionell eingehen: Von Bedeutung ist, dass neben einer installierten Python-Runtime unbedingt auch der unter https://getcomposer.org/download/ im Detail beschriebene Paketmanager Composer zur Verfügung stehen muss. Die eigentliche Beschaffung erfolgt dann im Großen und Ganzen so, wie man es erwartet. Das in Listing 9 gezeigte Beispiel erzeugt beispielsweise eine Instanz eines GPIO-Objekts, über das sie dann mit diversen Hardwareelementen interagieren können.

use Calcinai\PHPi\Pin;
use Calcinai\PHPi\Pin\PinFunction;
$loop = \React\EventLoop\Factory::create();
$board = \Calcinai\PHPi\Factory::create($loop);
$pin = $board->getPin(17) //BCM pin number
             ->setFunction(PinFunction::INPUT)
             ->setPull(Pin::PULL_UP);

Aus der Logik heraus folgt, dass das Produkt – unter anderem – aufgrund der Nutzung von mmap vergleichsweise schnell ist: In der Dokumentation verspricht man unter Python eine Schaltfrequenz von etwa 20 kHz, während das Deployment einer zusätzlichen nativen Erweiterung Geschwindigkeiten von bis zu 80 kHz ermöglicht. Unser weiter oben besprochenes JQuery-System ist schneller: Das ist allerdings nicht verwunderlich, haben Google und Co. doch in der Vergangenheit im Rahmen der Browserkriege Unmengen von Ressourcen in die Beschleunigung von JavaScript investiert.

Fazit

Ein alter Kalauer besagt, dass es am Ende in vielen Fällen ausschließlich darauf ankommt, ob das Endergebnis die geforderten Kriterien einhalten kann. Die hier besprochenen Möglichkeiten bieten einen „unbürokratischen“ und „niederschwelligen“ Weg an, um per Raspberry Pi mit Webtechnologien auf Hardware zuzugreifen. Dass sie damit nicht unbedingt harte Echtzeitanforderungen erfüllen können, folgt aus der Logik. Allerdings muss man sich an dieser Stelle ehrlich – Hand aufs Herz – fragen: Wie viele Aufgaben brauchen ein derartig genaues Timing wirklich?

PHP Magazin

Entwickler MagazinDieser Artikel ist im PHP Magazin erschienen. Das PHP Magazin deckt ein breites Spektrum an Themen ab, die für die erfolgreiche Webentwicklung unerlässlich sind.

Natürlich können Sie das PHP Magazin über den entwickler.kiosk auch digital im Browser oder auf Ihren Android- und iOS-Devices lesen. In unserem Shop ist das Entwickler Magazin ferner im Abonnement oder als Einzelheft erhältlich.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu:
X
- Gib Deinen Standort ein -
- or -