Dict-Schlüssel als Objektnamen Benutzen

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
rob87
User
Beiträge: 45
Registriert: Donnerstag 17. Oktober 2019, 14:24

Hallo,

ich möchte auf sehr verständlich Weise Funktion und GPIO im Code hinterlegen.
Meine Idee war es ein Dict zu erstellen und nutzen um GPIO's als PWM zu deklarieren und Objekte zu erzeugen die dann genauso wie der Schlüssel des dict-Elements heißen. Hier mal mein Code:

Code: Alles auswählen

import RC_Funktion as RC
import RPi.GPIO as GPIO
import Bluetoothstatus as inputvalue


"""init Analogpins"""
analog_pin={lenkung:17,kupplung:27}

GPIO.setmode(GPIO.BCM)

for nummer in analog_pin:
	#[b]-----Hier ist die Lücke------[/b]
	key_name_als_Objektname = InitAnalog(analog_pin[nummer])
	
def InitAnalog(pin)
	GPIO.setmode(GPIO.BCM)
	pwm_pin = (17,13) #GPIO die als PWM genutzt werden dürfen
	#print("Analogfunktion: ",pin)
	if pin in pwm_pin:
		GPIO.setup(pin,GPIO.OUT)
		pwm = GPIO.PWM(pin,50) # 50 Hz (20 ms PWM period)
		pwm.start(2.5)# start PWM by rotating to 90 degrees
		return PWM
	else:
		print('Uebergabeparameter  Analog-Funktion falsch')
		
RC.Analog(Lenkung,inputvalue.stick1_x_achse) # Stellung X-Achse an GPIO 17 als PWM signal übergeben.

Alternativ würde ich die Definition des GPIO auch in die "Analog"-Funktion packen. Allerdings weiß ich nicht wie man abfragt ob ein Pin schon deklariert wurden.

Mein Code wäre dann aber kürzer:

Code: Alles auswählen

import RC_Funktion as RC
import RPi.GPIO as GPIO
import Bluetoothstatus as inputvalue

"""  Lenkservo ansteuern """		
RC.Analog(17,inputvalue.stick1_x_achse) # Stellung X-Achse an GPIO 17 als PWM-Signal übergeben.
Könnt Ihr mir weiterhelfen?
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn man einen Pin nimmt, der nicht PWM-tauglich ist, dann ist das ein Programmierfehler.
Die "Fehlerbehandlung" bei Dir ist also falsch, da sollte das Programm abbrechen.

`as` ist dazu da, um beim Import ein Modul umzubenennen, GPIO wird gar nicht umbenannt.
`Bluetoothstatus` ist ein komischer Name für ein Modul, `inputvalue` noch mehr.
`RC_Funktion` ist auch kein guter Modulname.
GPIO.setmode sollte nicht irgendwo versteckt im Code stehen.

Zu den Pins: mach es explizit:

Code: Alles auswählen

from RPi import GPIO
import RC_Funktion as RC
import Bluetoothstatus

PWM_PINS = [17, 13]
LENKUNGS_PIN = 17
KUPPLUNGS_PIN = 27

assert LENKUNGS_PIN in PWM_PINS, "kein PWM-pin"
assert KUPPLUNGS_PIN in PWM_PINS, "kein PWM-pin"

def initialize():
    GPIO.setmode(GPIO.BCM)
    lenkung = GPIO.PWM(LENKUNGS_PIN, 50)
    lenkung.start(2.5)
    kupplung = GPIO.PWM(KUPPLUNGS_PIN, 50)
    kupplung.start(2.5)
    return lenkung, kupplung

def main():
    try:
        lenkung, kupplung = initialize()
        # Stellung X-Achse an GPIO 17 als PWM signal übergeben.
        RC.Analog(lenkung, Bluetoothstatus.stick1_x_achse)
    finally:
        GPIO.cleanup()

if __name__ == "__main__":
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rob87: Noch eine Anmerkung: Literale Zeichenketten sind keine Kommentare. An einigen Stellen haben die für den Python-Compiler eine Bedeutung und an noch mehr Stellen für einige externe Dokumentationswerkzeuge.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
DeaD_EyE
User
Beiträge: 1012
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Alles PINs können SoftwarePWM (mit viel Jitter) und GPIO 18 ist in HardwarePWM (weniger Jitter), sofern es ein RPI ist.
Da es es 2 PWMs sein sollen, fehlt dir einer.

Wenn der Unterbau weiterhin ein Raspberry PI sein soll, kann man diesen auch mit dedizierten Hardware PWM z.B. via SPI verwenden: https://www.exp-tech.de/module/led-cont ... e-tlc59711 (der ist schon zu groß, wird normal für LEDs genommen)
Wenn du SoftwarePWM bei so einem kleinen Servo verwendest, ist die Bewegung ziemlich hakelig.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
rob87
User
Beiträge: 45
Registriert: Donnerstag 17. Oktober 2019, 14:24

Hi,

danke für den Code. Meiner sieht jetzt so aus:

Code: Alles auswählen

from evdev import InputDevice, categorize, ecodes, KeyEvent

import PC_Funktion as RC
from RPi import GPIO



gamepad = InputDevice('/dev/input/event0')

def initanalog(pin):
	GPIO.setmode(GPIO.BCM)
	PWMPIN = (17,18,13)
	#print("Analogfunktion: ",pin)
	if pin in PWMPIN:
		GPIO.setup(pin,GPIO.OUT)
		lenkung = GPIO.PWM(pin,50) # 50 Hz (20 ms PWM period)
		lenkung.start(2.5)
		return lenkung
	else:
		print('UebergabeparameterAnalog-Funktion falsch')

		
		
def main():
	try:
		global gamepad
		lenkung = initanalog(17)
		
		#evdev takes care of polling the controller in a loop
		for event in gamepad.read_loop():
			if event.type == ecodes.EV_ABS:
				RC.controller.InputABS(event.code,event.value)
				RC.Analog(lenkung,RC.controller.LS.X.bereiche100100)#--------Rc funktionen Aufuehren-------
	finally:
		GPIO.cleanup()

if __name__ == "__main__":
	main()

geht sicherlich noch schöner bin aber erstmal zu frieden. Bin grad noch dabei auf "pigpio" umzubauen.

Unterbau ist ein Pi Zero W. Ich muss noch schauen wie sich der Motorregler mit dem Jitter PWM verhält ggf. muss hier nachgebessert werden. Allerdings ist im RC Auto sehr wenig platz :S

Was ist mit Literale Zeichen gemeint? Die Unterstriche?
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Schau doch mal was Du da stehen hattest was syntaktisch kein Kommentar ist, also nicht mit "#" anfängt, aber inhaltlich ein Kommentar ist, weil der Wert ansonsten keinerlei Zweck erfüllt.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
rob87
User
Beiträge: 45
Registriert: Donnerstag 17. Oktober 2019, 14:24

Ahhh du meinst:
key_name_als_Objektname
das war tatsächlich nur fürs Forum ;)

Für pigpio wird bei Änderung der Pulsweite immer der Pin benötigt. Um mein Zeil den Funktionsauf wie folgt zu gestalten:

Code: Alles auswählen

RC.Analog(Ausgangsobjekt,)
,benötige ich ein Konstrukt das sowohl das PWM Objekt als auch die Pinnummer speichert. Liste, Menge, Klasse?
Klatte:

Code: Alles auswählen

import pigpio
from RPi import GPIO

 def initPWM(pin)
 	GPIO.setmode(GPIO.BCM)
	PWMPIN = (17,18,13)
	if pin in PWMPIN:
		pwm.pin = pin #WIE PWM STRUKTUR DEFINIEREN?
		pwm.obj = pigpio.pi() 
		pwm.obj = pwm.set_mode(pwm.pin, pigpio.OUTPUT)
		pwm.obj.set_PWM_frequency( pwm.pin, 50 )
		pwm.obj.set_servo_pulsewidth( pwm.pin, 500 ) ; # 0 grad
		return pwm
 
 def Analog(pwm,wert)
 	pwm.obj.set_servo_pulsewidth( pwm.pin, wert) ; # 90 grad
 
lenkung = initPWM(18)
 
Analog(lenkung,1500)
 
 
# turning off servo
pwm.set_PWM_dutycycle(servo, 0)
pwm.set_PWM_frequency( servo, 0 )
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Eingerückt wird immer mit 4 Leerzeichen pro Ebene, keine Tabs! Funktionen werden wie Variablennamen komplett klein geschrieben.
Du willst nicht Rpi.GPIO mit pigpio mischen.
Was ist denn pwm? Das ist nirgends definiert.
Du brauchst nur die pgpio.pi-Instanz und den Pin. Das kannst Du als zwei Parameter übergeben oder dafür natürlich auch eine Klasse definieren.
Es fehlt das pi.stop().
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rob87: Nein, meinte ich nicht. Das ist ein Name und keine Zeichenkette. Wenn Du nicht weisst wie eine literale Zeichenkette im Quelltext aussieht, solltest Du vielleicht mal ein Grundlagentutorial durcharbeiten.

Zum vorletzten Quelltext: Eingerückt wird per Konvention vier Leerzeichen pro Ebene; keine Tabs.

`categorize` und `KeyEvent` werden importiert, aber nirgends verwendet.

Namen sollten keine kryptischen Abkürzungen enthalten, oder gar nur aus solchen bestehen.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. ``global`` bitte gleich wieder vergessen.

Das Eingabegerät sollte man am Ende sauber schliessen.

Was soll `initanalog()` eigentlich bedeuten? Da wird ein digitaler PWM-Ausgang initialisiert — wo kommt das „analog“ hier ins Spiel?

Das `GPIO.setmode()` da nicht rein gehört wurde bereits erwähnt, ebenso das die Fehlerbehandlung kaputt ist. Wenn etwas nicht funktioniert gibt man das nicht einfach per `print()` aus und macht dann weiter als wäre nichts passiert, was dann unweigerlich in einen Folgefehler läuft.

Konstanten werden nicht lokal in Funktionen definiert.

Funktionen und Methoden werden üblicherweise nach der Tätigkeit benannt die sie durchführen, damit der Leser weiss was die machen. `Analog` ist keine Tätigkeit.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
from contextlib import closing

from evdev import InputDevice, ecodes
from PC_Funktion import analog
from PC_Funktion.controller import LS, input_abs
from RPi import GPIO

PWM_PINS = {13, 17, 18}


def initialisiere_lenkung(pin):
    # print("Analogfunktion:", pin)
    if pin not in PWM_PINS:
        raise ValueError(f"{pin!r} kein PWM pin ({sorted(PWM_PINS)})")

    GPIO.setup(pin, GPIO.OUT)
    lenkung = GPIO.PWM(pin, 50)  # 50 Hz (20 ms PWM period)
    lenkung.start(2.5)
    return lenkung


def main():
    with closing(InputDevice("/dev/input/event0")) as gamepad:
        try:
            GPIO.setmode(GPIO.BCM)
            lenkung = initialisiere_lenkung(17)
            for event in gamepad.read_loop():
                if event.type == ecodes.EV_ABS:
                    input_abs(event.code, event.value)
                    analog(lenkung, LS.X.bereiche100100)
        finally:
            GPIO.cleanup()


if __name__ == "__main__":
    main()
Für `pigpio` bräuchtest Du nicht PWM und Pin in einem Objekt sondern das `pi`-Objekt und die Pinnummer. Und genau wie `GPIO.setmode()` nicht versteckt in eine Funktion gehört die mehrfach aufgerufen werden kann, erstellt man auch das `pi`-Objekt nicht dort, sondern einmal am Anfang des Programmablaufs in der `main()`-Funktion.

Und ja, falls man nicht immer das `pi`-Objekt zusammen mit der Pin-Nummer übergeben will, könnte man die beiden Werte in einem Objekt zusammenfassen. Also eine eigene Klasse dafür schreiben.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
rob87
User
Beiträge: 45
Registriert: Donnerstag 17. Oktober 2019, 14:24

Hi,

Das mit dem sprechenden Namen für funktionen nehm ich mir geren zu Herzen.

Allerdings soll der Code für den User extrem einfach sein. Alles andere soll "automatisiert" ablaufen. Ich stell mir das Endprodukt so vor:

Code: Alles auswählen

from RC_Funktionen import servo_analog_ansteuern
from PiHardware import controller_signale as controller

def main():
    try:
        #Controllersignale kontinuierlich erfassen
        controller()
        # Stellung X-Achse des Rechten Sticks  an GPIO 18/Lenkservo als PWM Signal übergeben.
        servo_analog_ansteuern(18,controller.status.rechter_stick.x_achse.bereich100bis100)
        #Stellung Y-Achse des Linken Sticks an Motorregler als PWM übergeben.
        servo_analog_ansteuern(21,controller.status.linker_stick.y_achse.bereich100bis100)
        
    finally:
        controller.stop_erfassung()

if __name__ == "__main__":
    main()


Die Funktion servo_analog_ansteuern müsste also erkennen ob der Pin (18) belegt ist wenn ja -> neuen Wert einstellen, wenn nein initialisieren und Wert einstellen.

Das birgt natürlich die Gefahr das ein Pin doppelt verwendet wird. das wollte ich eigentlich mit dem dict abfangen...

Bin für Vorschläge offen.
Benutzeravatar
Dennis89
User
Beiträge: 1124
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

vielleicht liegt es nur an mir, aber ich verstehe nicht was du mit deinem letzten Code-Ausschnitt sagen willst.
Poste doch den vollständigen Code, ich zum Beispiel verliere mit der Scrollerei schnell den Zusammenhang.

Was mich aber am meisten wundert und ich will dich damit nicht angreifen, aber wieso sieht deine gezeigt 'main'-Funktion ganz anders aus, als die Verbesserung von @__blackjack__ ?
Das wäre doch zu schade, wenn er sich die Mühe umsonst gemacht hätte, nutze jeden Input den du bekommst.

Letzte Frage von mir, was meinst du damit dass der Code für den User 'extrem einfach' sein soll? Einfach zu lesen oder das Programm einfach zu bedienen?

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
rob87
User
Beiträge: 45
Registriert: Donnerstag 17. Oktober 2019, 14:24

Dennis89 hat geschrieben: Mittwoch 17. März 2021, 20:03 Hallo,

vielleicht liegt es nur an mir, aber ich verstehe nicht was du mit deinem letzten Code-Ausschnitt sagen willst.
Poste doch den vollständigen Code, ich zum Beispiel verliere mit der Scrollerei schnell den Zusammenhang.
Das da oben ist der Sollzustand den ich noch nicht erreicht habe.
Dennis89 hat geschrieben: Mittwoch 17. März 2021, 20:03 Was mich aber am meisten wundert und ich will dich damit nicht angreifen, aber wieso sieht deine gezeigt 'main'-Funktion ganz anders aus, als die Verbesserung von @__blackjack__ ?
Meine 'main' soll am Ende so aussehen weil...
Dennis89 hat geschrieben: Mittwoch 17. März 2021, 20:03 Letzte Frage von mir, was meinst du damit dass der Code für den User 'extrem einfach' sein soll? Einfach zu lesen oder das Programm einfach zu bedienen?
das Programm einfach zu bedienen sein soll. Ich möchte kein UI dafür basteln. Der Code soll von Usern genutzt werden können, die sonst am Sender Hebel A(Hier StickLinks_XAchse) in Buchse 3(hier Pin18) stecken und dann am Empfänger in Buchse 3(Hier Pin18) den Servo stecken und sich freuen wenn der Servo richtig rum dreht. Genau so einfach soll der Code sein.

Alles andere wird in anderen Modulen(Dateien) versteckt sein. Ich bin dankbar für jeden Input(@__blackjack__) und nutze auch viel davon, soweit ich damit mein Ziel erreiche.
Antworten