This section explains principles behind the implementation of HAL components with the Python programming language.
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
import 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 True:
h['out'] = h['in']
time.sleep(1)
except KeyboardInterrupt:
raise SystemExit
Copy the above listing into a file named "passthrough", make it executable (chmod +x). Then try it out (assuming the cpmponent "passthrough" is located in the current directory):
$ halrun
halcmd: loadusr ./passthrough
halcmd: show pin
Component Pins:
Owner Type Dir Value Name
4 float IN 0 passthrough.in
4 float OUT 0 passthrough.out
halcmd: setp passthrough.in 3.14
halcmd: show pin
Component Pins:
Owner Type Dir Value Name
4 float IN 3.14 passthrough.in
4 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
mycomp = 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.
mycomp.newpin("in", hal.HAL_FLOAT, hal.HAL_IN)
mycomp.newparam("has-feature-rotate", hal.HAL_BIT, hal.HAL_RO)
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: |
|
|
|
|
|
|
|
Pin-Richtungen: |
|
|
|
||||
Parameter-Richtungen: |
|
|
|
Note
|
Only pins and signals can use the |
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.
mycomp.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:
mycomp.out = mycomp.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:
mycomp['out'] = mycomp['in']
Um alle Pins mit ihren Werten zu sehen, gibt getpins alle Werte in einem Wörterbuch dieser Komponente zurück.
mycomp.getpins()
>>>{'in': 0.0, 'out': 0.0}
4.1. Ansteuerung der Ausgangsstifte (HAL_OUT)
Periodically, usually in response to a timer, all HAL_OUT pins should be "driven" by assigning them a new value. This should be done whether or not the value is different than the last one assigned. When a pin is connected to a signal, its old output value is not copied into the signal. The proper value will only appear on the signal once the component assigns a new value.
4.2. Ansteuerung von bidirektionalen (HAL_IO) Pins
The above rule does not apply to bidirectional pins. Instead, a bidirectional pin should only be driven by the component when the component wishes to change the value. For instance, in the canonical encoder interface, the encoder component only sets the index-enable pin to False (when an index pulse is seen and the old value is True), but never sets it to True. Repeatedly driving the pin False might cause the other connected component to act as though another index pulse had been seen.
5. Beenden
A halcmd unload request for the component is delivered as a KeyboardInterrupt exception. When an unload request arrives, the process should either exit in a short time, or call the .exit() method on the component if substantial work (such as reading or writing files) must be done to complete the shutdown process.
6. HAL Python module reference
See Python HAL Interface for an overview and description of available classes and methods.
7. Konstanten
Verwenden Sie diese, um Details zu spezifizieren, und nicht den Wert, den sie enthalten.
-
Pin, parameter and signal types:
-
HAL_BIT -
HAL_FLOAT -
HAL_S32 -
HAL_U32 -
HAL_S64 -
HAL_U64
-
-
Pin direction:
-
HAL_IN -
HAL_OUT
-
-
Parameter access:
-
HAL_RO -
HAL_RW
-
-
Message severity:
-
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.
-
lcnc_realtime: See Python module for managing the realtime backend. -
is_kernelspace -
is_userspace -
get_realtime_type()