In diesem Abschnitt werden die Grundsätze für die Implementierung von HAL-Komponenten mit der Programmiersprache Python erläutert.
1. Grundlegendes Anwendungsbeispiel
Eine Nicht-Echtzeit-Komponente beginnt mit der Erstellung ihrer Pins und Parameter und tritt dann in eine Schleife ein, die periodisch alle Ausgänge von den Eingängen steuert. Die folgende Komponente kopiert den Wert an ihrem Eingangspin (passthrough.in) etwa einmal pro Sekunde an ihren Ausgangspin (passthrough.out).
#!/usr/bin/env python3 import hal, time h = hal.component("passthrough") h.newpin("in", hal.HAL_FLOAT, hal.HAL_IN) h.newpin("out", hal.HAL_FLOAT, hal.HAL_OUT) h.ready() try: while 1: time.sleep(1) h['out'] = h['in'] except KeyboardInterrupt: raise SystemExit
Kopieren Sie das obige Listing in eine Datei mit dem Namen "passthrough", machen Sie es ausführbar (chmod +x), und legen Sie es in Ihren $PATH. Dann probieren Sie es aus:
$ halrun
halcmd: loadusr passthrough
halcmd: show pin
Komponenten-Pins:
Owner Typ Richtung Wert Name
03 float IN 0 passthrough.in
03 float OUT 0 passthrough.out
halcmd: setp passthrough.in 3.14
halcmd: show pin
Komponenten-Pins:
Owner Typ Richtung Wert Name
03 float IN 3.14 passthrough.in
03 float OUT 3.14 passthrough.out
2. Nicht-Echtzeit-Komponenten und Verzögerungen
Wenn Sie schnell "show pin" eintippen, sehen Sie vielleicht, dass "passthrough.out" immer noch den alten Wert von 0 hat. Das liegt an dem Aufruf von "time.sleep(1)", der dafür sorgt, dass die Zuweisung an den Ausgangspin höchstens einmal pro Sekunde erfolgt. Da es sich um eine Nicht-Echtzeit-Komponente handelt, kann die tatsächliche Verzögerung zwischen den Zuweisungen viel länger sein, wenn der von der Passthrough-Komponente verwendete Speicher auf die Festplatte ausgelagert wird, da die Zuweisung verzögert werden könnte, bis dieser Speicher wieder ausgelagert wird.
So eignen sich Nicht-Echtzeit-Komponenten für benutzerinteraktive Elemente wie Bedienfelder (Verzögerungen im Bereich von Millisekunden werden nicht bemerkt, und längere Verzögerungen sind akzeptabel), nicht aber für das Senden von Schrittimpulsen an eine Stepper-Treiberkarte (Verzögerungen müssen immer im Bereich von Mikrosekunden liegen, egal wie).
3. Pins und Parameter erstellen
h = hal.component("passthrough")
Die Komponente selbst wird durch einen Aufruf des Konstruktors hal.component erzeugt. Die Argumente sind der HAL-Komponentenname und (optional) das für Pin- und Parameternamen verwendete Präfix. Wird das Präfix nicht angegeben, wird der Komponentenname verwendet.
h.newpin("in", hal.HAL_FLOAT, hal.HAL_IN)
Dann werden Pins durch Aufrufe von Methoden auf dem Komponentenobjekt erstellt. Die Argumente sind: Suffix des Pin-Namens, Pin-Typ und Pin-Richtung. Bei Parametern lauten die Argumente: Parameternamenssuffix, Parametertyp und Parameterrichtung.
Pin- und Parametertypen: |
HAL_BIT |
HAL_FLOAT |
HAL_S32 |
HAL_U32 |
HAL_S64 |
HAL_U64 |
Pin-Richtungen: |
HAL_IN |
HAL_OUT |
HAL_IO |
Parameter-Richtungen: |
|||
HAL_RO |
HAL_RW |
Der vollständige Pin- oder Parametername wird durch Verbinden des Präfixes und des Suffixes mit einem "." gebildet. Im Beispiel heißt der erstellte Pin also passthrough.in.
h.ready()
Sobald alle Pins und Parameter erstellt wurden, rufen Sie die Methode .ready() auf.
3.1. Ändern des Präfixes
Das Präfix kann durch den Aufruf der Methode .setprefix() geändert werden. Das aktuelle Präfix kann durch den Aufruf der Methode .getprefix() abgefragt werden.
4. Lesen und Schreiben von Pins und Parametern
Bei Pins und Parametern, die auch echte Python-Bezeichner sind, kann der Wert unter Verwendung der Attributsyntax aufgerufen oder gesetzt werden:
h.out = h.in
Für alle Pins, unabhängig davon, ob sie auch echte Python-Bezeichner sind oder nicht, kann der Wert unter Verwendung der tiefgestellten Syntax aufgerufen oder gesetzt werden:
h['out'] = h['in']
Um alle Pins mit ihren Werten zu sehen, gibt getpins alle Werte in einem Wörterbuch dieser Komponente zurück.
h.getpins()
>>>{'in': 0.0, 'out': 0.0}
4.1. Ansteuerung der Ausgangsstifte (HAL_OUT)
In regelmäßigen Abständen, in der Regel als Reaktion auf einen Timer, sollten alle HAL_OUT-Pins "getrieben" werden, indem ihnen ein neuer Wert zugewiesen wird. Dies sollte unabhängig davon geschehen, ob sich der Wert von dem zuletzt zugewiesenen unterscheidet oder nicht. Beim Verbinden eines Pins mit einem Signal wird sein alter Ausgangswert nicht in das Signal kopiert, so dass der richtige Wert erst auf dem Signal erscheint, wenn die Komponente einen neuen Wert zuweist.
4.2. Ansteuerung von bidirektionalen (HAL_IO) Pins
Die obige Regel gilt nicht für bidirektionale Pins. Stattdessen sollte ein bidirektionaler Pin nur dann von der Komponente angesteuert werden, wenn die Komponente den Wert ändern möchte. In der kanonischen Encoder-Schnittstelle beispielsweise setzt die Encoder-Komponente den Pin index-enable nur auf FALSE (wenn ein Indeximpuls gesehen wird und der alte Wert TRUE ist), aber niemals auf TRUE. Das wiederholte Setzen des Pins auf FALSE könnte dazu führen, dass die andere angeschlossene Komponente sich so verhält, als ob ein weiterer Indeximpuls gesehen worden wäre.
5. Beenden
Eine halcmd unload Anforderung für die Komponente wird als KeyboardInterrupt Ausnahme geliefert. Wenn eine Entladeanforderung eintrifft, sollte der Prozess entweder in kurzer Zeit beendet werden oder die Methode .exit() für die Komponente aufrufen, wenn umfangreiche Arbeiten (wie das Lesen oder Schreiben von Dateien) durchgeführt werden müssen, um den Abschaltvorgang abzuschließen.
6. Hilfreiche Funktionen
Siehe Python HAL Interface für eine Übersicht der verfügbaren Funktionen.
7. Konstanten
Verwenden Sie diese, um Details zu spezifizieren, und nicht den Wert, den sie enthalten.
-
HAL_BIT
-
HAL_FLOAT
-
HAL_S32
-
HAL_U32
-
HAL_S64
-
HAL_U64
-
HAL_IN
-
HAL_OUT
-
HAL_RO
-
HAL_RW
-
MSG_NONE
-
MSG_ALL
-
MSG_DBG
-
MSG_ERR
-
MSG_INFO
-
MSG_WARN
8. System-Informationen
Lesen Sie diese, um Informationen über das Echtzeitsystem zu erhalten.
-
is_kernelspace
-
is_rt
-
is_sim
-
is_userspace