Forum: Mikrocontroller und Digitale Elektronik GPIO Ansteuerung eines RaspberryPi mit Multithreading in Python


von ManuH (Gast)


Lesenswert?

Momentan versuche ich zwei Schrittmotoren über einen RaspberryPi 
anzusteuern. Die Steuerung habe ich in Python geschrieben und um die 
Geschwindigkeit der beiden Motoren seperat und Zeitgleich steuern zu 
können möchte ich die Funktionen zur Steuerung in zwei Threads laufen 
lassen.

Wenn ich versuche meinen Code auszuführen bekomme ich immer die 
Error-Meldung : Please set pin numbering mode using 
GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM). Sie tritt auf wenn 
ich von der main in die Threads springe.

Ich habe GPIO.setmode(GPIO.BCM) direkt nach den imports implementiert, 
allerdings vermute ich dass ich meinen Threads diesen "parameter" beim 
aufruf irgendwie mitgeben muss damit er auf die GPIO's zugreifen kann.

t1=Thread(target=MotorSteuerung1,args(iMotorSchritteWeg,iDelay,iDrehrich 
tung)
t2=Thread(target=MotorSteuerung2, 
args=(iMotorSchritteWeg,iDelay,(iDrehrichtung+1)))

t1.start()
t2.start()

So sieht momentan mein Aufruf der Threads aus.

def MotorSteuerung1(MotorSchritteWeg, iDelay, Drehrichtung):
     GPIO.setup(8, GPIO.OUT)
     GPIO.setup(10, GPIO.OUT)

so der Anfang meiner Aufgerufenen Funktion.

Der GPIO.setup aufruf ist auch der most recent call vor der 
Error-Meldung.


Ich bedanke mich für die Hilfe bereits im Vorraus.

Mit vielen Grußen

Manuel

von H. E. (hobby_elektroniker)


Lesenswert?

Wie gehst du dabei vor? Sieht mir fast so aus, als wäre die Umsetzung 
oder das Verständnis von Multithreads ein anderes.

Hast du schon sowas in der Richtung versucht? Dabei entstehen wirklich 
unterschiedliche Prozesse die autark arbeiten.
1
#!/usr/bin/python
2
3
import RPi.GPIO as GPIO
4
from time import sleep
5
import time
6
import sys
7
usleep = lambda x: time.sleep(x/1000.0)
8
import signal
9
import json
10
from StringIO import StringIO
11
import thread
12
13
# create threads
14
try:
15
   thread.start_new_thread( launch_switches, () )
16
   thread.start_new_thread( launch_nfc_tags, () )
17
   thread.start_new_thread( launch_your_own_method, () )
18
  
19
except Exception, e:
20
   print "Error: unable to start thread" + str(e)
21
22
while 1:
23
   sleep(1)
24
   pass

: Bearbeitet durch User
von ManuH (Gast)


Lesenswert?

Vielen dank für die schnelle Antwort.

Das öffnen meiner Threads ist nicht das problem ich habe getestet ob 
beide laufen und es Funktioniert. Mein problem tritt erst auf sobald ich 
versuche die GPIO Ports für meinen Raspberry zu initialisieren.

Dann kommt die Fehlermeldung wie oben beschrieben dass ich 
GPIO.setmode(BCM) verwenden soll. Allerdings habe ich dies schon an 
jeder erdenklichen Stelle versucht, direkt hinter den Imports, vor dem 
Thread aufruf oder auch in der Funktion welche der Thread aufruft 
selbst.

Mit vielen Grüßen

Manuel

von H. E. (hobby_elektroniker)


Lesenswert?

Oh, ich habe etwas total überlesen vor lauter Multithread...

Hast deine Fehlermeldung schon mal genauer angeschaut? ;)

Please set pin numbering mode using
GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)

: Bearbeitet durch User
von ManuH (Gast)


Lesenswert?

Thread 1 opened
Thread 2 opened
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 763, in run
    self.__target(*self.__args, **self.__kwargs)
  File "./Motorsteuerung_VS.py", line 156, in MotorSteuerung2
    GPIO.setup(16, GPIO.OUT)
RuntimeError: Please set pin numbering mode using 
GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)

Dies ist die genaue Fehlermeldung. Meine Imports sehen wiefolgt aus:

#!/usr/bin/python
# -*- coding: latin-1 -*-
import os, sys
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
import time
from threading import Thread

Ich habe auch schon versucht es direkt in die Funkiton Motorsteuerung 
welche vom Thread aufgerufen wird zu schreiben ganz am Anfang, die 
Fehlermeldung hat sich allerdings nicht verändert.

Mit vielen Grüßen

Manuel

von H. E. (hobby_elektroniker)


Lesenswert?

Dein Problem ist, dass irgendwo vom ersten Byte bis dahin versucht wird, 
zwei unterschiedliche Modi zu benutzen.

GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)

Das heißt, irgendwo wird einmal BCM und woanders BOARD benutzt. Das kann 
auch daher kommen, wenn du andere Scripte einbindest, die das setzen. Du 
solltest das zuerst prüfen.

Ggf. hilft es schon, dass du einfach BOARD benutzen. Allerdings musst 
du dann auch deine Script ggf. anpassen um sicherzustellen dein Raspi 
nicht zu beschädigen.

Ich bin mir nicht sicher, wie sich das verhält, wenn andere Scripte im 
Hintergrund laufen, die GPIO aktiv benutzen und einen anderen Modi 
gesetzt haben.

: Bearbeitet durch User
von ManuH (Gast)


Lesenswert?

Ich habe es mit GPIO.BOARD versucht und es hat zur selben Fehlermeldung 
geführt. Außerdem habe ich es komplett gelöscht um zu sehen ob sich die 
Fehlermeldung verändert, aber selbst wenn ich überhaupt keinen setmode 
verwende bleibt die Fehlermeldung gleich.

Vielleicht erkennt der geöffnete Thread einfach nicht dass es gesetzt 
wurde bzw. vielleicht muss ich ihm im Threadaufruf etwas mitgeben zur 
GPIO konfiguration.

Mit vielen Grüßen

Manuel

von H. E. (hobby_elektroniker)


Lesenswert?

Du könnetest mal noch GPIO.cleanup() versuchen.

Der Fehler ist aber, dass zwei Modi gesetzt werden sollen.

Nochmal: Du solltest alle involvierte Scripte genau überprüfen ob und 
was gesetzt wird.

Anderenfalls musst du zunächst einen anderen Weg einschlagen und 
systematisch vorgehen:

- Bastel dir ein Script, dass eine LED zum leuchten bringt.
- Versuche es in beide Modi und finde heraus, ob das zu Problemen führt.
- Wenn alles klappt, lagere es in ein Thread aus mit so wenig Script und 
Imports wie möglich

Ein kompletter Quellcode sollte ggf. mehr nützen als zu spekulieren.

Grüße

: Bearbeitet durch User
von ManuH (Gast)


Lesenswert?

1
#!/usr/bin/python
2
# -*- coding: latin-1 -*-
3
import os, sys
4
import RPi.GPIO as GPIO
5
GPIO.setmode(GPIO.BOARD)
6
import time
7
from threading import Thread
8
9
10
def main ():
11
  
12
    pi = 3.14
13
    fGeschwindigkeit = 0
14
    iWeg = 0
15
    fStreckePMS = 0
16
    iDrehrichtung = 0
17
    xRichtigeEingabe = 1
18
    iDemoAuswahl = 0
19
    checker = 0
20
    counter = 0
21
22
    try :
23
        iQuickStart = int(input(("Herzlich willkommen, wollen sie einen Quickstart machen? 1 fuer Ja 2 fuer nein.")))
24
25
        if iQuickStart == 2:
26
            iProgrammAuswahl = int(input("Herzlich willkommen zur Motorsteuerung. \nMoechten Sie den Motor manuell steuern oder ein Demo-Programm starten? (1 = manuelle Steuerung ; 2 = Demo - Programm): \n"))
27
28
            if iProgrammAuswahl == 2:
29
                iDemoAuswahl = int(input("Ihnen stehen 3 verschiede Demo-Programme zur Auswahl:\n1.Vorwaerts/Rueckwarts fahrt\n2.Kurvenfahrt\n3.Dauerbetrieb: \n"))
30
31
                # Einlesen der Schrittweite des Schrittmotors (z.B. 1,8)
32
                fSchrittweite = float(input("Bitte geben Sie die Schrittweite Ihres Schrittmotors ein: \n"))
33
                # Einlesen der Geschwindigkeit die der Motor fahren sollen
34
35
                print(fSchrittweite)
36
                while xRichtigeEingabe == 1:
37
                    fGeschwindigkeit = float(input("Bitte geben Sie die Geschwindigkeit des Motors an (sie darf maximal 0.5 m/s betragen): \n"))
38
            # Falls Geschwindigkeit zu hoch wird der Wert erneut abegefragt
39
                    if fGeschwindigkeit > 0.5:
40
41
                        print("Die maximale Geschwindigkeit beträgt 0.5 m/s.\n")
42
43
                    else:
44
                        xRichtigeEingabe = 0
45
46
            # Einlesen des Radius des Reifens den der Schrittmotor antreibt
47
48
            iReifenRadius = int(input("Bitte geben Sie den Radius der Reifen des Fahrzeuges an (halber Durchmesser): \n"))
49
50
            # Einlesen der Strecke die das Fahrzeug zurücklegen soll
51
52
            if iDemoAuswahl != 3:
53
                iWeg = int(input("Bitte geben sie an wie Weit der Motor fahren soll: \n"))
54
55
            # Eingabe der Drehrichtung des Motors
56
57
            if iProgrammAuswahl == 1:
58
                iDrehrichtung = int(input("Bitte geben sie die Drehrichtung des Motors ein ( 1 = Vorwaerts, 2 = Rueckwerts) : "))
59
60
            # Startaufforderung
61
62
            cStart = input("Moechten Sie den Motor jetzt starten? 1 fuer Start 2 fuer Abbruch: \n")
63
            print("Vielen dank!\n")
64
65
            print("Bruuummmmmm")
66
67
        else :
68
            print("Let's go!")
69
            iProgrammAuswahl = 2
70
            iDemoAuswahl = 3
71
            fSchrittweite = 1.8
72
            fGeschwindigkeit = 0.5
73
            iReifenRadius = 75
74
            iDrehrichtung = 1
75
            iWeg = 10
76
77
78
79
80
81
        def GeschwindigkeitDelayBerechnung(fSchrittweite, fStreckePMS, fGeschwindigkeit):
82
            PausenZeitFloat = (1.0 / (fGeschwindigkeit / fStreckePMS) * 1000.0)
83
            Pause = round(PausenZeitFloat)
84
            return Pause
85
86
87
        def StreckePMS(fSchrittweite, iReifenRadius):
88
            StreckePMS = 0
89
            StreckePMS = ((2.0 * pi * (iReifenRadius / 1000.0)) / (360.0 / fSchrittweite))
90
            return StreckePMS
91
92
93
        def WegSchrittBerechnung(fSchrittweite, fStreckePMS, iReifenRadius, iWeg):
94
            MotorSchritte = iWeg / fStreckePMS
95
            return MotorSchritte
96
97
98
        def round(x):
99
            if (x > 0):
100
                x = x + 0.5
101
                ausgabe = 0
102
                ausgabe = x
103
                return ausgabe
104
105
            return (int)(x - 0.5)
106
107
108
        def MotorSteuerung1(MotorSchritteWeg, iDelay, Drehrichtung):
109
            # Die GPIO-PINs des RaspberryPi müssen vor der Verwendung Deklariert werden (Input/Output)
110
            
111
            print("Thread 1 opened")
112
113
            i = 0
114
            #GPIO.setup(16, GPIO.OUT)
115
            # GPIO.setup(10, GPIO.OUT)
116
            # GPIO.setup(11, GPIO.OUT)
117
            GPIO.setup(8, GPIO.OUT)
118
            GPIO.setup(10, GPIO.OUT)
119
            checker = 0
120
            counter = 0
121
            
122
            while checker == 0 :
123
124
                counter = counter + 1
125
                if counter == MotorSchritteWeg:
126
                    checker = 1
127
                if Drehrichtung == 1:
128
                    # GPIO 15 bestimmt die Drehrichtung des Schrittmotors ( 1 = Vorwärts; 2 = Rückwärts)
129
                    # GPIO.output(16, GPIO.HIGH)
130
131
132
                    GPIO.output(10, GPIO.HIGH)
133
                    time.sleep((iDelay/1000))
134
                    GPIO.output(10, GPIO.LOW)
135
                    print("1")
136
137
                if (Drehrichtung == 2):
138
                    # GPIO.output(16, GPIO.LOW)
139
140
                    GPIO.output(10, GPIO.HIGH)
141
                    time.sleep((iDelay / 1000))
142
                    GPIO.output(10, GPIO.LOW)
143
                    print("2")
144
145
146
        def MotorSteuerung2(MotorSchritteWeg, iDelay, Drehrichtung):
147
            # Die GPIO-PINs des RaspberryPi müssen vor der Verwendung Deklariert werden (Input/Output)
148
149
            print("Thread 2 opened")
150
            i = 0
151
            # GPIO.setup(16, GPIO.OUT)
152
            # GPIO.setup(10, GPIO.OUT)
153
            # GPIO.setup(11, GPIO.OUT)
154
            GPIO.setup(16, GPIO.OUT)
155
            GPIO.setup(18, GPIO.OUT)
156
            checker = 0
157
            counter = 0
158
            print("Came here")
159
            while checker == 0 :
160
161
                counter = counter + 1
162
                if counter == MotorSchritteWeg:
163
                    checker = 1
164
                if Drehrichtung == 1:
165
                    # GPIO 15 bestimmt die Drehrichtung des Schrittmotors ( 1 = Vorwärts; 2 = Rückwärts)
166
                    # GPIO.output(16, GPIO.HIGH)
167
168
169
                    GPIO.output(16, GPIO.HIGH)
170
                    time.sleep((iDelay/1000))
171
                    GPIO.output(16, GPIO.LOW)
172
                    print("1")
173
174
                if (Drehrichtung == 2):
175
                    # GPIO.output(16, GPIO.LOW)
176
177
                    GPIO.output(16, GPIO.HIGH)
178
                    time.sleep((iDelay / 1000))
179
                    GPIO.output(16, GPIO.LOW)
180
                    print("2")
181
182
183
        def Dauerbetrieb() : 
184
185
            #GPIO.setup(4, OUTPUT)
186
            
187
            GPIO.setup(16, OUTPUT)
188
            GPIO.setup(8, OUTPUT)
189
            GPIO.setup(10, OUTPUT)
190
191
          #GPIO 4 ist der ENABLE eingang am Motortreiber
192
            GPIO.output(16,HIGH)
193
194
          #Zugriff auf die Delayzeit die im struct übergeben wurde
195
            while 1 :
196
                GPIO.output(16, HIGH)
197
                counter += counter 
198
                delay(delays)
199
                GPIO.output(16, LOW)
200
201
202
        fStreckePMS = StreckePMS(fSchrittweite, iReifenRadius)
203
204
        iDelay = GeschwindigkeitDelayBerechnung(fSchrittweite, fStreckePMS, fGeschwindigkeit)
205
206
        iMotorSchritteWeg = WegSchrittBerechnung(fSchrittweite, fStreckePMS, iReifenRadius, iWeg)
207
208
        print(iDelay)
209
        print(fStreckePMS)
210
        print(iMotorSchritteWeg)
211
212
213
        if iProgrammAuswahl == 1:
214
            t1 = Thread(target=MotorSteuerung, args=(iMotorSchritteWeg,iDelay,iDrehrichtung))
215
            t2 = Thread(target=MotorSteuerung, args=(iMotorSchritteWeg,iDelay,(iDrehrichtung+1)))
216
            t1.start()
217
            t2.start()
218
            
219
        elif iDemoAuswahl == 3 :
220
221
            t1 = Thread(target=MotorSteuerung1, args=(iMotorSchritteWeg,iDelay,iDrehrichtung))
222
            t2 = Thread(target=MotorSteuerung2, args=(iMotorSchritteWeg,iDelay,(iDrehrichtung+1)))
223
224
            t1.start()
225
            t2.start()
226
227
    except KeyboardInterrupt :
228
        print("Bye!")
229
    finally:
230
        GPIO.cleanup()
231
232
main()

Ich werde dem Vorschlag folgen und in einem extra Programm versuchen 
mich an das Problem anzunäheren. Oberhalb habe ich noch einen Prototypen 
von meinem Source-Code angehängt vielleicht fällt Ihnen da noch etwas 
auf. Vielen Dank für Ihre Hilfe.

Mit vielen Grüßen

Manuel

von H. E. (hobby_elektroniker)


Lesenswert?

Was erhälst du denn, wenn du print GPIO.getmode() ausliest? Kann das 
nicht leider testen, da ich momentan keinen RaspPi in der Nähe habe.

Kriegst du den Fehler erst, wenn ein Thread gestartet wird oder schon 
zuvor?

von ManuH (Gast)


Lesenswert?

Den Fehler bekomme ich erst im Thread sobald ich zum ersten mal versuche 
auf eine GPIO. Funktion zuzugreifen.
print (GPIO.getmode()) hat mir eine 10 auf der Konsole ausgegeben.

Gruß
Manuel

von H. E. (hobby_elektroniker)


Lesenswert?

Gibt es denn neue Erkenntnisse?

von Lothar (Gast)


Lesenswert?

RISC OS pico und BASIC wäre eine gute Alternative zu Python und 
Multithreading

von ManuH (Gast)


Lesenswert?

Das Problem hat sich jetzt durch ändern der verwendeten GPIO-Pins 
erledigt, mir ist allerdings nicht ganz bewusst warum weil die zuvor 
verwendeten auch funktionieren müssten. Vielleicht liegt in diesem Fall 
an den entsprechenden Pins einfach ein Hardware defekt vor.

Gruß Manuel

von H. E. (hobby_elektroniker)


Lesenswert?

ManuH schrieb:
> Das Problem hat sich jetzt durch ändern der verwendeten GPIO-Pins
> erledigt, mir ist allerdings nicht ganz bewusst warum weil die zuvor
> verwendeten auch funktionieren müssten. Vielleicht liegt in diesem Fall
> an den entsprechenden Pins einfach ein Hardware defekt vor.
>
> Gruß Manuel

Das würde u.U. bedeuten, dass der PI kaputt ist? Die Frage bleibt, ob du 
ohne Threads damit Input/Output steuern kannst. Z.b. eine LED.

Grüße

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.