Programmierproblem Taster

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Benutzeravatar
juicyboose
User
Beiträge: 7
Registriert: Donnerstag 10. August 2017, 16:26
Wohnort: Schweinfurt
Kontaktdaten:

Programmierproblem Taster

Beitragvon juicyboose » Donnerstag 10. August 2017, 16:39

Guten Tag meine lieben Leute. Ich möchte euch mein Problem schildern. Ich bin neu in Sachen Python und Raspberry Pi.
Ich versuche gerade eine Möglichkeit, bzw. ein Programm zu erstellen, dass mir ermöglicht bestimmte Tasterabfolgen wiederzugeben.
D.h. Ich habe 4 Taster. Ich möchte, dass wenn ich die Taster 1 2 3 2 1 drücke eine 50 erscheint und wenn ich 1 2 1 drücke die 10 erscheint. Ich bekomme gerade bloß nicht heraus wie man Tastendrückabfolgen in Python hineinbekommt. Mein Code sieht bis jetzt so aus:

  1. import RPi.GPIO as GPIO
  2. import time
  3.  
  4. GPIO.setmode(GPIO.Board)
  5. GPIO.setup(37, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  6. GPIO.setup(35, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  7. GPIO.setup(33, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  8. GPIO.setup(31, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  9.  
  10. while True:
  11.  button_1 = GPIO.input(37)
  12.  button_2 = GPIO.input(35)
  13.  button_3 = GPIO.input(33)
  14.  button_4 = GPIO.input(31)
  15.  
  16.   if button_1 == False:
  17.     print ("random")
  18.     time.sleep(0.5)


Ich weis nun leider nicht wie ich dieses nacheinander drücken der Taster in den Code bekomme... Sowas wie.
if button1 then button 2 then button 1
print 10
if button 1 then button 2 then button 3 then button 2 then button 1
print 50

Ich wäre sehr dankbar für Hilfe :)
Zuletzt geändert von BlackJack am Donnerstag 10. August 2017, 17:21, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Benutzeravatar
BlackJack
Moderator
Beiträge: 32975
Registriert: Dienstag 25. Januar 2005, 23:29
Wohnort: Berlin
Kontaktdaten:

Re: Programmierproblem Taster

Beitragvon BlackJack » Donnerstag 10. August 2017, 17:38

@juicyboose: Du musst Dir die Tastendrücke merken, und jedes mal wenn einer dazu kommt, prüfen ob das eine Sequenz ergibt, zu der eine Ausgabe passieren soll.

Tastendrücke wirst Du wahrscheinlich am besten über die Flanken erkennen, und zwar nicht manuell, sondern über die entsprechende Funktionalität vom `GPIO`-Modul mit Rückruffunktionen. Das bedeutet dann allerdings nebenläufige Programmierung, mit all den Problemen die man sich damit einfängt. Du musst zum Beispiel den Programmteil der einen neuen Tastendruck verarbeitet und eventuell eine Ausgabe daraufhin auslöst durch eine Sperre absichern (`threading.Lock()`) damit keine Tastendrücke verloren gehen können, oder während des Prüfens auf eine Sequenz die Sequenz erweitert wird.

Durch die Nebenläufigeit wird es hier übrigens nicht mehr so einfach eine Lösung ohne objektorientierte Programmierung (OOP) zu schreiben.

`GPIO.setup()` kann man übrigens auch eine Sequenz von Pin-Nummern übergeben, da reicht dann *ein* Aufruf, wenn die anderen Argumente gleich bleiben.

Wenn man anfängt Namen zu nummerieren, möchte man meistens nicht einzelne Namen sondern einen Namen für eine Datenstruktur. Oft ist das eine Liste. Auch im Falle der `button_*` würde ich sagen. Die könnte man wenn man für das `setup()` sowieso schon eine Liste mit den Nummern hat, auch recht einfach mit einer „list comprehension“ erstellen.

Eingerückt wird per Konvention vier Leerzeichen pro Ebene.

Und am Programmende sollte man sicherstellen das `GPIO.cleanup()` aufgerufen wird. Dafür braucht man ``try``/``finally`` als Syntaxkonstrukt.
“Programs must be written for people to read, and only incidentally for machines to execute.” — Abelson & Sussman, SICP (preface to the first edition)
Benutzeravatar
noisefloor
User
Beiträge: 1735
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: Görgeshausen
Kontaktdaten:

Re: Programmierproblem Taster

Beitragvon noisefloor » Freitag 11. August 2017, 10:06

Hallo,

wenn du die neuere gpiozero Bibliothek benutzt ist das a) so wie so einfacher und b) kannst ganz einfach ein Callback Funktion wie `when_pressed()` an jeden Taster binden, der den Tastendruck dann wie von BlackJack beschrieben protokolliert.

Gruß, noisefloor
Benutzeravatar
juicyboose
User
Beiträge: 7
Registriert: Donnerstag 10. August 2017, 16:26
Wohnort: Schweinfurt
Kontaktdaten:

Re: Programmierproblem Taster

Beitragvon juicyboose » Freitag 11. August 2017, 11:41

Da ich wie gesagt totaler Anfänger bin bräuchte ich etwas direktes gesagt. Also mein Ziel ist es ein Programm zum Laufen zu kriegen, dass:
Bestimmt Werte nach einer Tasteneingabefolge addiert. D.h. Ich drücke Knopf 1 2 3 2 1 und es kommt 50 heraus. Diese Zahl soll gespeichert werden. Drücke ich nun 1 2 1 soll 10 entstehen und zu den 50 addiert werden und 60 anzeigen lassen. Gebe ich nun 1 2 3 4 3 2 1 ein habe ich 100 und es entsteht 160. Da ich mit den Codes nicht ganz vertraut bin würde ich auch über Hilfe in Skype sehr glücklich sein :) Wenn es jemanden möglich wäre und mir über Skype etwas nachhelfen könnte, würde ich auch etwas entgegenkommen :)
Benutzeravatar
__deets__
User
Beiträge: 728
Registriert: Mittwoch 14. Oktober 2015, 14:29

Re: Programmierproblem Taster

Beitragvon __deets__ » Freitag 11. August 2017, 12:34

Dieses Forum hilft Leuten, die wirklich *anfangen* wollen zu programmieren. Wenn du jemanden suchst, der dir für Geld ein Programm schreibt, gibt es dafür spezielle Dienste. ZB Rent a Coder.
Benutzeravatar
juicyboose
User
Beiträge: 7
Registriert: Donnerstag 10. August 2017, 16:26
Wohnort: Schweinfurt
Kontaktdaten:

Re: Programmierproblem Taster

Beitragvon juicyboose » Freitag 11. August 2017, 12:49

Ich möchte keinen Dienst kaufen. Ich schätze es wenn sich jemand Zeit für mich nimmt. In dieser Zeit könnte er natürlich auch wesentlich interessantere Sachen für sich selbst machen. Nur dass ich eben ganz am Anfang stehe. Falls hilfe möglich ist habe ich auch meinen Stream angeschalten.
www.twitch.tv/juicyboose
Benutzeravatar
BlackJack
Moderator
Beiträge: 32975
Registriert: Dienstag 25. Januar 2005, 23:29
Wohnort: Berlin
Kontaktdaten:

Re: Programmierproblem Taster

Beitragvon BlackJack » Freitag 11. August 2017, 20:15

@juicyboose: Kannst Du verraten worum es geht? Also was die ganzen Zahlen und Zahlenfolgen bedeuten sollen? Dann ist es vielleicht einfacher die tatsächlichen Anforderungen besser zu bestimmen. Also beispielsweise was passieren soll wenn der Benutzer andere Folgen drückt. Oder auch ob es Zufall ist das alle Deine Beispiele von Zahlenfolgen einen präfixfreien Code darstellen, oder ob das garantiert ist. Falls nicht, was soll dann in Fällen passieren bei dem eine Zahlenfolge Präfix einer anderen ist? Oder auch schon bei einem präfixfreiem Code: was soll passieren wenn eine Zahlenfolge in einer anderen enthalten ist?

Bevor man etwas Lösen kann, muss man das Problem ja erst einmal ausreichend verstanden haben.
“Programs must be written for people to read, and only incidentally for machines to execute.” — Abelson & Sussman, SICP (preface to the first edition)
Benutzeravatar
juicyboose
User
Beiträge: 7
Registriert: Donnerstag 10. August 2017, 16:26
Wohnort: Schweinfurt
Kontaktdaten:

Re: Programmierproblem Taster

Beitragvon juicyboose » Samstag 12. August 2017, 04:40

Guten Tag. Also es gibt nur die maximalen Zahlenfolgen 1 2 3 4 5 6 7 8 7 6 5 4 3 2 1. D.h. es entsteht ein Gerät das Bauteile misst. Ist das Bauteil 10mm lang, setzt man es in eine Vorrichtung. Diese Vorrichtung besteht aus verschiedenen Kontaktleitbahnen. Ein Kontakt ist dauerhaft auf 1. D.h. wird das kleinste Bauteil eingesetzt, so bewegt sich die Abfrage auf Kontakt 2. Nimmt man das Bauteil nun raus, zieht eine Feder die Abfrage wieder auf Kontakt 1, damit die Rücksetzung entsteht. Nehme ich nun ein großes Bauteil, bewegt sich die Abfrage über 2 3 4 5. Nehme ich das Bauteil nun wieder raus, ist es eigentlich nur wichtig, den Kontakt 1 abzufragen, da er ja sowieso 4 3 2 "überspringt". Um es Prototypenhaft abzubilden habe ich es zuerst mit Tastern probiert, da es für mich vorerst zu teuer wäre eine eigene Platine herstellen zu lassen, da ich erst über die Logik des Programms Bescheid wissen muss, bevor ich solche Platinen fertigen lassen kann. Nun zur Frage, wenn die Zahlenfolgen anders sind. Es soll immer der höchste Wert abgefragt werden. Kommt nun jemand auf die Idee, ein kleines Bauteil einzusetzten und ohne Rücksetzung direkt das große Teil einzusetzen, soll nur das große Bauteil ausgegeben werden. Kommt jemand auf die Idee ein mittleres Bauteil einzusetzen. Sagen wir mal. Es geht von 1 - 5 dann geht er von 5 auf 2 und dann mit einem größeren Bauteil wieder auf 7 und dann auf 3 und wieder auf 5 und dann erst auf 1 zum Zurücksetzen, soll auch nur das größte Bauteil angenommen werden. D.h. die 7. Ich hoffe das macht die Erklärung einfacher. Falls weitere Fragen bestehen kann ich gerne antworten. Ich werde nun weiter nach einer Programmierungshilfe suchen, die eine Sequenz unterstützt :) Vielen dank im Voraus und ich würde mich auf neue Nachrichten freuen.
Benutzeravatar
BlackJack
Moderator
Beiträge: 32975
Registriert: Dienstag 25. Januar 2005, 23:29
Wohnort: Berlin
Kontaktdaten:

Re: Programmierproblem Taster

Beitragvon BlackJack » Sonntag 13. August 2017, 16:59

@juicyboose: Mist, das Muster in den Zahlenfolgen hätte einem ja eigentlich auffallen können/müssen. :-)

Also hat man sozusagen Rahmen von Werten die mit einer 0 anfangen und enden, und man sucht den Maximalwert innerhalb des Rahmens. Und den bildet man noch einmal auf eine Länge ab.

Ich habe jetzt 0 geschrieben, weil Programmierer üblicherweise mit 0 anfangen zu zählen.

Vollkommen ungetestet (bis auf die Beispiele in den DocStrings):
  1. #!/usr/bin/env python
  2. # coding: utf-8
  3. from __future__ import absolute_import, division, print_function
  4. from contextlib import closing
  5. from functools import partial
  6. from itertools import imap, takewhile
  7. from Queue import Queue
  8. from RPi import GPIO
  9.  
  10. CONTACT_PINS = [37, 35, 33, 31]
  11.  
  12.  
  13. def create_contact_stream(pins):
  14.     """Create an iterable of values for rising edges on given pins.
  15.  
  16.    The values are the index values of the given pins.  So the first pin will
  17.    yield 0, the second 1, the third 2, and so on.
  18.  
  19.    The returned object has as ``close()`` method which detaches the
  20.    callbacks/listeners for the pins.  If you don't close the object and don't
  21.    consume the iterable, the values for rising edges will be queued and fill
  22.    the memory over time.
  23.    """
  24.     GPIO.setup(pins, GPIO.IN, GPIO.PUD_UP)
  25.  
  26.     queue = Queue()
  27.     for i, pin in enumerate(pins):
  28.         GPIO.add_event_detect(pin, GPIO.RISING, lambda _, i=i: queue.put(i))
  29.  
  30.     try:
  31.         while True:
  32.             yield queue.get()
  33.     finally:
  34.         for pin in pins:
  35.             GPIO.remove_event_detect(pin)
  36.  
  37.  
  38. def iter_peak_values(contact_values):
  39.     """Return the peak values between two zero values.
  40.  
  41.    >>> list(iter_peak_values([0, 1, 2, 1, 0, 0, 1, 0, 0, 1, 2, 3, 2, 1, 0]))
  42.    [2, 1, 3]
  43.  
  44.    Values between an ending zero and the starting zero of the next measurement
  45.    are silently ignored.  Like the 42 in this example:
  46.  
  47.    >>> list(iter_peak_values([0, 1, 2, 1, 0, 42, 0, 1, 0]))
  48.    [2, 1]
  49.    """
  50.     contact_values = iter(contact_values)
  51.     takewhile_not_zero = partial(takewhile, bool)
  52.     while True:
  53.         #
  54.         # Skip to first zero value.
  55.         #
  56.         for _ in takewhile_not_zero(contact_values):
  57.             pass
  58.  
  59.         try:
  60.             yield max(takewhile_not_zero(contact_values))
  61.         except ValueError:
  62.             #
  63.             # When `max()` gets an empty iterable we are finished.
  64.             #
  65.             break
  66.  
  67.  
  68. def iter_lengths(lengths, peak_values):
  69.     """Map an iterable of peak values to the given lengths.
  70.  
  71.    >>> list(iter_lengths([10, 50, 100], [2, 1, 3]))
  72.    [50, 10, 100]
  73.    """
  74.     return imap(lambda x: lengths[x - 1], peak_values)
  75.  
  76.  
  77. def main():
  78.     GPIO.setmode(GPIO.BOARD)
  79.     try:
  80.         lengths = [10, 50, 100]
  81.         with closing(create_contact_stream(CONTACT_PINS)) as contact_values:
  82.             total_length = 0
  83.             for length in iter_lengths(
  84.                 lengths, iter_peak_values(contact_values)
  85.             ):
  86.                 total_length += length
  87.                 print(total_length)
  88.     finally:
  89.         GPIO.cleanup()
  90.  
  91.  
  92. if __name__ == '__main__':
  93.     main()
“Programs must be written for people to read, and only incidentally for machines to execute.” — Abelson & Sussman, SICP (preface to the first edition)
Benutzeravatar
juicyboose
User
Beiträge: 7
Registriert: Donnerstag 10. August 2017, 16:26
Wohnort: Schweinfurt
Kontaktdaten:

Re: Programmierproblem Taster

Beitragvon juicyboose » Montag 14. August 2017, 11:11

Teste gerade
Benutzeravatar
juicyboose
User
Beiträge: 7
Registriert: Donnerstag 10. August 2017, 16:26
Wohnort: Schweinfurt
Kontaktdaten:

Re: Programmierproblem Taster

Beitragvon juicyboose » Montag 14. August 2017, 14:14

Also ich habe den Code jetzt so in Python 2 eingegeben und auf 8 Taster erhöht und es wird zwar kein Fehler dargestellt aber nachdem ich die Knöpfe in der Reihenfolge drücke passiert auch nichts. Kann es sein dass die Tasten bei dem Code garnicht abgefragt werden oder woran erkenne ich dies?

  1. #!/usr/bin/env python
  2. # coding: utf-8
  3. from __future__ import absolute_import, division, print_function
  4. from contextlib import closing
  5. from functools import partial
  6. from itertools import imap, takewhile
  7. from Queue import Queue
  8. from RPi import GPIO
  9.  
  10. CONTACT_PINS = [40, 38, 37, 36, 35, 33, 32, 31]
  11.  
  12. def create_contact_stream(pins):
  13.    
  14.     GPIO.setup(pins, GPIO.IN, GPIO.PUD_UP)
  15.    
  16.     queue = Queue()
  17.     for i, pin in enumerate(pins):
  18.         GPIO.add_event_detect(pin, GPIO.RISING, lambda _, i=i: queue.put(i))
  19.  
  20.     try:
  21.         while True:
  22.             yield queue.get()
  23.     finally:
  24.         for pin in pins:
  25.             GPIO.remove_event_detect(pin)
  26.  
  27. def iter_peak_values(contact_values):
  28.    
  29.     contact_values = iter(contact_values)
  30.     takewhile_not_zero = partial(takewhile, bool)
  31.     while True:
  32.         for _ in takewhile_not_zero(contact_values):
  33.             pass
  34.        
  35.         try:
  36.             yield max(takewhile_not_zero(contact_values))        
  37.         except ValueError:
  38.             break
  39.                      
  40. def iter_lengths(lengths, peak_values):
  41.     return imap(lambda x: lengths[x - 1], peak_values)
  42.  
  43. def main():
  44.     GPIO.setmode(GPIO.BOARD)
  45.     try:
  46.         lengths = [1, 5, 10, 20, 50]
  47.         with closing(create_contact_stream(CONTACT_PINS)) as contact_values:
  48.             total_amounts = 0
  49.             for length in iter_lengths(
  50.                 lengths, iter_peak_values(contact_values)):
  51.                 total_length += length
  52.                 print(total_length)
  53.     finally:
  54.         GPIO.cleanup()
  55.  
  56. if __name__ == '__main__':
  57.     main()
Zuletzt geändert von BlackJack am Montag 14. August 2017, 14:23, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Benutzeravatar
BlackJack
Moderator
Beiträge: 32975
Registriert: Dienstag 25. Januar 2005, 23:29
Wohnort: Berlin
Kontaktdaten:

Re: Programmierproblem Taster

Beitragvon BlackJack » Montag 14. August 2017, 14:32

@juicyboose: Du müsstest halt schauen an welcher Stelle keine Werte (mehr) generiert werden. Da die beiden Generatorfunktionen die nichts mit der Hardware zu tun haben, (oberflächlich) getestet sind, würde ich mit `create_contact_stream()` anfangen. Ob das bei steigender Flanke jeweils eine Zahl liefert.

Und schaust Du auch nach Ausnahmen die ausgelöst werden? Denn die `total_length`-Zeile wird beispielsweise eine Ausnahme auslösen weil Du das dort nicht umbenannt hast, aber bei der Initialisierung zu `total_amount`.

Und Du hast mehr Taster als Werte in `lengths`. Das wird auch zu einer Ausnahme (`IndexError`) führen.
“Programs must be written for people to read, and only incidentally for machines to execute.” — Abelson & Sussman, SICP (preface to the first edition)
Benutzeravatar
juicyboose
User
Beiträge: 7
Registriert: Donnerstag 10. August 2017, 16:26
Wohnort: Schweinfurt
Kontaktdaten:

Re: Programmierproblem Taster

Beitragvon juicyboose » Dienstag 15. August 2017, 17:50

Hallo noch einmal. Also ich habe jetzt alles durchgetestet und es kommt mir etwas komisch vor. Es entstehen immer 4 Fälle.
Bild
Der erste Fall gibt mir einfach eine 1 wieder wenn ich 0 1 0 sehr schnell drücke.
Der zweite Fall schließt den Prozess ab sobald ich 0 drücke.
Der dritte Fall ist weiter unten zu erkennen. ich habe es geschafft 2 mal die 010 combo zu machen.
Und der vierte Fall gibt mir die untere Fehlermeldung aus. Diese Meldung erhalte ich aber auch manchmal, wenn ich nach dem Restart nur die 0 drücke.
Falls Interesse an der ganzen Aufgabe besteht könnte ich ein Video von meinem Aufbau machen und einfach mal hochladen. Mein Youtubechannel ist folgender:
www.youtube.com/juicyboose
Benutzeravatar
BlackJack
Moderator
Beiträge: 32975
Registriert: Dienstag 25. Januar 2005, 23:29
Wohnort: Berlin
Kontaktdaten:

Re: Programmierproblem Taster

Beitragvon BlackJack » Mittwoch 16. August 2017, 11:12

@juicyboose: `SystemError` ist gar nicht gut. Da ist irgendwas im Python-Interpreter oder einem in C geschriebenen Modul fehlerhaft. Ich tippe hier mal auf das GPIO-Modul. Eventuell kann man das up- oder downgraden. Oder Du schaust Dich nach einem anderen Modul um um die GPIOs anzusprechen. `pigpio` zum Beispiel.
“Programs must be written for people to read, and only incidentally for machines to execute.” — Abelson & Sussman, SICP (preface to the first edition)

Zurück zu „Raspberry Pi und Co.“

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder