RPM PIGPIO falsche Werte "entprellen"

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Uiui, was habe ich getan? Jetzt haut euch dochnicht wegen mir.

    Vom python forum bin ich abgeschweift, da ich dachte ich hatte das Problem gelöst und muss nur noch entprellen.
    War ja leider nicht so wie wir gemerkt haben. Springen wollte ich zwischen den Foren dann nicht.
    Sicher sind alle sehr hilfsbereit, dafür bin ich auch wirklich dankbar.

    Zum verstehen... ich brauche dieses Wissen einmal, dann nie wieder, da ich nicht programmiere.
    Bis jetzt habe ich alles mit dem Raspberry hin bekommen, aber wenn ich weiss das ich nicht mehr weiter komme, bin ich raus.

    Ja das 3. ist Interessant, Geschwindigkeit und Weg brauche ich nicht.
    Am Ende sollte es halt so sein, dass mit den RPM(Umdrehungen pro Minute) und LEVEL der richtige Powerwert ausgegeben wird. Diesen greif ich dann von der Konsole ab.
    Ob da jetzt 3 RPM mehr oder weniger sind finde ich undramatisch. *Wieso habe ich immer das Gefühl das ich das falsch erkläre?

    Zum Kollegen, er dachte eher ich hätte ein kleineres Problem, da auch er Haus Kinder etc. hat wollte ich ihn auch nicht bedrängen.
    Was ich auch nicht machen möchte, ist hier rum heulen wie wenig Zeit ich habe für sowas. Das der Grund warum ich Jemanden möchte der mir das proggt und den ich dafür bezahlen kann. Ich bezahle für sowas auch gerne und bin natürlich auch hilfsbereit an der Seite wie ich kann. Das hat bis jetzt eigentlich auch immer erfolgreich funktioniert.

    zu __deets__ der war sowas von geduldig, das mir das schon etwas unangenehm war. Ich glaub der mag mich jetzt nicht mehr. :)

    Wie auch immer, ohne Programmierer lass ich das sein, bevor meine Familie vergisst wie ich aussehe.

    Einmal editiert, zuletzt von Landixus (9. Mai 2017 um 14:14)


  • Um die Genauigkeit zu steigern wären mehrere Erfassungspunkte gut, also nicht nur ein Sensor sondern mehrere. Dann würde es nicht nur einen Impuls für eine volle Umdrehung benötigen, sondern zum Beispiel drei. Hat man mehrere Sensoren kann man auch Halbe Umdrehungen (oder weniger) verwerten/erfassen.

    Bist du sicher, dass es genauer wird, wenn du den gleichen Sachverhalt mehrfach misst, bzw. um einen halben/drittel/viertel Intervall versetzte Messungen machst? Wenn du zwei Messungen pro Umdrehung machst, ist der eine um soviel höher, wie der andere niedriger ist. Eine genauere Erfassung der "Momentangeschwindigkeit" innerhalb von weniger als einer Umdrehung ist in dem Fall doch gar nicht praktikabel. So schnell kann ja keiner das Display ablesen, wie die Werte dann geliefert werden. Und am Ende bildest du womöglich einen Mittelwert - was hast du dann gewonnen?
    Ich meine, es ist eher sinnvoll, zwei (oder mehr) Messungen über zwei (oder mehr) Umdrehungen zu machen und gleitende Durchschnitte zu bilden, oder? Das reduziert dann auch das Springen der Werte und führt zu gleitenden Änderungen der Anzeige.

    Oh, man kann hier unliebsame Nutzer blockieren. Wie praktisch!

  • Also zunächst kümmern wir uns um den Impulszähler...

    Wie viel Zeit zwischen den Impulsen vergangen ist interessiert uns nicht.
    Ein Impuls wird bei jeder Umdrehung durch deinen Reed-Switch ausgelöst. Wichtig hierbei ist besagter "timeout" damit der Zähler auch wieder zurück gesetzt wird falls zum Beispiel innerhalb 5 Sekunden kein neuer Impuls hinzu kommt - du also aufgehört hast zu strampeln.

    Das zählen der Impulse erledigen wir am besten über eine Klasse, wo wir auch direkt Methoden einbauen zum auslesen und resetten des Zählers. Alles andere machen wir wo anders...
    Diese Klasse könnte zum Beispiel wie folgt aussehen:

    [code=php]
    class impuls_counter:
    def __init__(self, pi, gpio):
    self.pi = pi
    self.gpio = gpio
    self.count = 0
    pi.set_mode(gpio, pigpio.INPUT)
    pi.set_pull_up_down(gpio, pigpio.PUD_UP)
    self._cb = pi.callback(gpio, pigpio.EITHER_EDGE, self._callback)

    def _callback(self, gpio, level, tick):
    self.count += 1

    def get(self):
    return self.count

    def reset(self):
    self.count = 0

    def cancel(self):
    self._cb.cancel()
    [/php]

    Verwenden könnte man das zB wie folgt:

    [code=php]
    #!/usr/bin/python3
    from time import sleep, time
    import pigpio

    class impuls_counter:
    def __init__(self, pi, gpio):
    self.pi = pi
    self.gpio = gpio
    self.count = 0
    pi.set_mode(gpio, pigpio.INPUT)
    pi.set_pull_up_down(gpio, pigpio.PUD_UP)
    self._cb = pi.callback(gpio, pigpio.EITHER_EDGE, self._callback)

    def _callback(self, gpio, level, tick):
    self.count += 1

    def get(self):
    return self.count

    def reset(self):
    self.count = 0

    def cancel(self):
    self._cb.cancel()


    sensor = 4
    timeout = 5
    previous_count = 0

    pi = pigpio.pi()
    impuls = impuls_counter(pi, sensor)

    start_time = time()
    while True:
    counter = impuls.get()
    if previous_count == counter:
    if (time() - start_time) >= timeout:
    impuls.reset()
    counter = impuls.get()
    start_time = time()
    print("counter: %d" % counter)
    previous_count = counter
    sleep(2)
    [/php]

    Die while Schleife und die _callback laufen wie gesagt voneinander getrennt, parallel, und beeinträchtigen sich nicht. Findet ein Flankenwechsel statt, also ein Impuls, wird "count" um 1 erhöht.

    Wir erzeugen also erst ein Klassen-Objekt auf "impuls" und können dann auf Methoden oder Variablen innerhalb dieser Klasse zugreifen und Einfluss nehmen.
    Anschließend kommt die while Schleife wodurch wir ein stetiges Auslesen der Werte erreichen. Hier lesen wir erst den aktuellen Zählerstand aus und kümmern uns anschließend um die timeout Behandlung: Sind mehr als 5 Sekunden vergangen und der Wert hat sich zum vorherigen nicht verändert wird der Zähler auf 0 zurück gesetzt.
    Eine Ausgabe erfolgt alle 2 Sekunden.

    Bevor du jetzt anfängst da irgendwas bzgl. LEVEL einzubauen, bitte erst ausprobieren und Rückmeldung geben bzw die Ausgabe bitte posten. Danke.


    //EDIT:


    Bist du sicher, dass es genauer wird, wenn du den gleichen Sachverhalt mehrfach misst, bzw. um einen halben/drittel/viertel Intervall versetzte Messungen machst? Wenn du zwei Messungen pro Umdrehung machst, ist der eine um soviel höher, wie der andere niedriger ist. Eine genauere Erfassung der "Momentangeschwindigkeit" innerhalb von weniger als einer Umdrehung ist in dem Fall doch gar nicht praktikabel. So schnell kann ja keiner das Display ablesen, wie die Werte dann geliefert werden. Und am Ende bildest du womöglich einen Mittelwert - was hast du dann gewonnen?
    Ich meine, es ist eher sinnvoll, zwei (oder mehr) Messungen über zwei (oder mehr) Umdrehungen zu machen und gleitende Durchschnitte zu bilden, oder? Das reduziert dann auch das Springen der Werte und führt zu gleitenden Änderungen der Anzeige.

    Etwas aus dem Kontext gerissen aber egal :fies:

    Es geht da nicht um die Genauigkeit sondern dem auslesen der Messung, da hier ein Reed-Switch zum Einsatz kommt ;)
    Angenommen du steigst auf ein Hochrad und trittst nur soweit dass das Rad bei der Hälfte stehen bleibt. Es gab da zwar eine gewisse Geschwindigkeit aber da man nur einen Messpunkt hat konnte die nicht ermittelt werden.

  • [code=php]#!/usr/bin/python3
    import time
    import pigpio


    class ImpulsCounter:
    def __init__(self, pi, gpio):
    self.pi = pi
    self.gpio = gpio
    self.count = 0
    pi.set_mode(gpio, pigpio.INPUT)
    pi.set_pull_up_down(gpio, pigpio.PUD_UP)
    self._cb = pi.callback(gpio, pigpio.EITHER_EDGE, self._callback)
       
    def _callback(self, gpio, level, tick):
    self.count += 1
       
    def get(self):
    return self.count
       
    def reset(self):
    return self.count = 0
       
    def cancel(self):
    self._cb.cancel()


    sensor = 4
    timeout = 5
    previous_count = 0

    pi = pigpio.pi()
    impuls = ImpulsCounter(pi, sensor)

    start_time = time.time()
    while True:
    counter = impuls.get()
    if previous_count == counter:
    if time.time() - start_time >= timeout:
    impuls.reset()
    impuls.get()
    start_time = time.time()
    print("counter: {0}".format(counter))
    previous_count = counter
    time.sleep(2)
    [/php]
    :rolleyes:

    EDIT:
    1. PEP8 ist kein Geschwafel, sondern ein von der Python-Community im Allgemeinen geschaffenes und anerkanntes Styleguide.
    2. Ich hab den Code für dich angepasst und habe nie gesagt, dass du es so machen musst. Aber ich werde ja wohl für "Ordnung" sorgen dürfen, machst du ja auch ganz gerne ;)

    In diesem Sinne: Happy Coding!

  • Irgendwer hat mir mal gesagt dass laut PEP alles klein geschrieben werden muss - denn "früher" hab ich auch blaBlub usw genutzt, dann kam jmd an und meckerte "näää, das darf man laut pep nicht" ... dann änder ich das und nun meckert der nächste?

    Und nur wegen des "ImpulsCounter" und "format" im print schiebste hier son Hanz wegen PEP8?


    Bitte nicht schon wieder mit eurem PEP8 Geschwafel daher kommen - sonst vergeht mir wirklich die Lust.

    ich möchte Schritt für Schritt erklären. Klein anfangen, warten bis der TE es verstanden hat, dann darauf aufbauend weiter. Dabei finde ich es hinderlich auf __main__ und das ganze Zeug zu achten.

    Wenn ihr da was gegen habt dann setzt Euch doch selber hin und helft selbst! Aber bitte nicht von anderen verlangen "du musst das so oder so posten sonst sieht das kacke aus!"

    Aber an anderen herum meckern ist freilich immer einfacher als sich selbst die Zeit nehmen um ausführliche Hilfestellung zu geben

    //EDIT: Und das dir Andreas für diese Rüge auch noch dankt ist mal wieder typisch.

    Könnt oder wollt ihr nicht anders?
    Könnt ihr nicht einfach mal drüber hinweg sehen und euch wie normale menschen verhalten?

    Da krieg ich mal wieder echt das kotzen. Sorry aber is mir grad echt wurscht wie das rüber kommt


  • Es geht da nicht um die Genauigkeit sondern dem auslesen der Messung, da hier ein Reed-Switch zum Einsatz kommt ;)
    Angenommen du steigst auf ein Hochrad und trittst nur soweit dass das Rad bei der Hälfte stehen bleibt. Es gab da zwar eine gewisse Geschwindigkeit aber da man nur einen Messpunkt hat konnte die nicht ermittelt werden.


    Ach so meintest du das. Gut, aber interessiert sich denn jemand bei nem Hometrainer dafür, ob sich das Rad eine halbe Umdrehung gedreht hat - geschweige denn für die dabei erreichte Geschwindigkeit? Falls doch: Wenns drum geht, Bewegungen innerhalb geringer Bandbreiten von wenigen cm zu messen, würde ich nicht mehrere Sensoren nehmen, sondern mehrere Magnete eben im gleichmäßigen Abstand. Natürlich muss man dann bei X Magneten für die RPM die Anzahl Signale durch X teilen oder nur jeden X auswerten..

    Oh, man kann hier unliebsame Nutzer blockieren. Wie praktisch!

  • OT:
    Der Autor von ``pigpio`` joan2937 schreibt selbst im https://www.raspberrypi.org/forums/, dass er nicht "viel" Ahnung von Python hat (Namenskonvention, "_" bei Methodennamen, globals etc...) darum sollte man ggf. nicht alles 1:1 übernehmen was da so an Beispielcodes auf der Seite zur Verfügung steht.

    Ich gebe da meigrafd recht, dass hier Stück für Stück vorgegangen werden muss.
    Über die Klasse darf zurecht diskutiert werden. Zumindest später, wenn es um Performance geht, sollt man sich mit den Eigenschaften einer Python Klasse intensiver auseinandersetzte. Python bietet für Klassen von Haus aus Iteratoren-Methoden an ``__iter__()`` was sich für das Zählen besser anböte als händisch zu zählen.

    • Offizieller Beitrag

    Ich schlag mich in dem Fall mal auf die Seite des Grafen (ja, auch das passiert ;) ). Dieses "PEP8 or die" geht mir auch auf den Sack. Für mich, als Mensch der programmiert um ein bestimmtes Ziel zu erreichen, steht lauffähiger Code an erster Stelle, dann kommt performance und dann "design"...wobei letzteres meistens durch ein neues Projekt ersetzt wird ;). Und bitte hört auf euch wegen ein paar __ gegenseitig vollzupflaumen.

    Der Unterschied zwischen Genie und Wahnsinn definiert sich im Erfolg.

    Einmal editiert, zuletzt von dbv (9. Mai 2017 um 16:25)

  • @ meigrafd: Wenn ich deinen Code richtig verstehe, zählt das Programm die Impulse und setzt alle 5 Sekunden auf null zurück. Daraus kann man die Umdrehungen pro Minute berechnen (Faktor 12). Ok.
    Die Ausgabe alle 2 Sekunden ist nur zum Test gedacht, oder? Denn bei sagen mir mal 10 Umdrehungen pro Sekunde würde ja ungefähr folgende Zahlenreihe rauskommen:
    20, 40, 10, 30, 0, 20, 40, 10, 30, 0, ... sehe ich das richtig?
    Die Berechnung der Umdrehungen dürfte dann nur alle 5 Sekunden, kurz vor dem Rücksetzen erfolgen. Entsprechend träge wäre die Anzeige. Oder hab ich was übersehen?

    Sehr geringe Drehzahlen (< ca. 50-120 RPM) führen zu Sprüngen in den Werten, wenn ein Impuls mal gerade so noch in dem einen Intervall liegt und beim anderen Intervall gerade noch raus fällt. Also z.B. bei sieben Impulsen in 10 Sekunden kommen quasi abwechselnd einmal 4 Impulse, einmal 3 Impulse. Ist aber wahrscheinlich in der Praxis beim "Power-Spinning" nicht relevant.

    Oh, man kann hier unliebsame Nutzer blockieren. Wie praktisch!

  • Angenommen man setzt einen runden Teller (whatever) auf die Welle eines Motors, platziert den Reed-Switch passend und schaltet den Motor ein....

    Dann zählt mein (bisheriges) Script einfach nur die Interrupts und gibt den aktuellen Wert alle 2 Sekunden aus.
    Stoppt man dann den Motor wird der Zähler (count) nach 5 Sekunden auf 0 gesetzt - vorher nicht. Denn die Anzahl der Umdrehungen hat sich dann nicht geändert "previous_count == counter" und "time.time() - start_time > = timeout" trifft zu.

    Ob "Umdrehungen pro Minute" überhaupt wichtig sind weiß ich nicht.

    Wie gesagt, Schritt für Schritt.


  • Also zunächst kümmern wir uns um den Impulszähler...
    Bevor du jetzt anfängst da irgendwas bzgl. LEVEL einzubauen, bitte erst ausprobieren und Rückmeldung geben bzw die Ausgabe bitte posten. Danke.

    Ich habe mir erlaubt die Zeile:

    Code
    def reset(self):
    
    
            return self.count = 0


    in

    Code
    def reset(self):
    
    
            return self.count == 0

    zu ändern, da sonst ein Syntaxfehler kommt. OK?


    Meine Ausgabe


    Wenn ich aufhöre wiederholt sich die letzte Zahl.


  • Ich habe mir erlaubt die Zeile:

    Code
    def reset(self):
    
    
            return self.count = 0


    in

    Code
    def reset(self):
    
    
            return self.count == 0

    zu ändern, da sonst ein Syntaxfehler kommt. OK?

    Nein, nicht OK ;)
    Das war aber auch mein Fehler.
    Richtig müsste das so aussehen:

    Code
    def reset(self):
            self.count = 0



    Wenn ich aufhöre wiederholt sich die letzte Zahl.

    Ja und nach 5 Sekunden müsste 0 ausgegeben werden sofern "reset" angepasst wurde.


    Erweiterung zu dem bisherigen Script sähe dann so aus - bitte ausprobieren und Ausgabe posten:

    [code=php]
    #!/usr/bin/python3
    from functools import partial
    from queue import Queue
    from time import sleep, time
    import pigpio


    class ImpulsCounter:
    def __init__(self, pi, gpio):
    self.pi = pi
    self.gpio = gpio
    self.count = 0
    pi.set_mode(gpio, pigpio.INPUT)
    pi.set_pull_up_down(gpio, pigpio.PUD_UP)
    self._cb = pi.callback(gpio, pigpio.EITHER_EDGE, self._callback)

    def _callback(self, gpio, level, tick):
    self.count += 1

    def get(self):
    return self.count

    def reset(self):
    self.count = 0

    def cancel(self):
    self._cb.cancel()


    def calculate_power(level, rpm, level_to_power, lower_limit, higher_limit):
    if rpm <= lower_limit:
    return 0
    if rpm >= higher_limit:
    return 0
    return level_to_power[level][(rpm) // 10]


    def switch_callback(queue, gpio, level, tick):
    queue.put( gpio )


    def main(sensor=4, btnPlus=21, btnMinus=20, timeout=5.0, sample_time=2.0):

    LEVEL_TO_POWER = {
    1: [6, 12, 20, 29, 40, 53, 69, 79, 92, 106, 121],
    2: [8, 16, 26, 38, 53, 68, 88, 103, 120, 138, 152],
    3: [9, 20, 32, 47, 66, 84, 107, 125, 148, 172, 186],
    4: [11, 23, 39, 56, 79, 101, 126, 150, 173, 206, 219],
    5: [13, 27, 45, 65, 92, 117, 145, 175, 202, 238, 254],
    6: [15, 31, 52, 75, 105, 135, 166, 202, 231, 275, 289],
    7: [16, 35, 58, 85, 118, 152, 185, 226, 260, 305, 332],
    8: [18, 39, 65, 96, 131, 169, 208, 249, 289, 333, 375],
    9: [19, 42, 71, 104, 144, 184, 227, 272, 318, 361, 408],
    10: [21, 46, 77, 113, 157, 199, 245, 295, 345, 386, 442],
    11: [23, 50, 84, 123, 170, 216, 262, 318, 372, 413, 480],
    12: [24, 53, 89, 131, 183, 230, 279, 342, 398, 441, 512],
    13: [26, 56, 94, 139, 196, 245, 296, 365, 424, 468, 548],
    14: [28, 60, 101, 148, 209, 261, 318, 389, 449, 494, 585],
    15: [30, 64, 108, 158, 222, 277, 337, 415, 476, 518, 620],
    16: [32, 68, 115, 168, 235, 296, 355, 439, 503, 548, 658],
    17: [33, 72, 122, 177, 248, 312, 373, 463, 530, 576, 694],
    18: [35, 76, 129, 187, 261, 328, 390, 484, 556, 606, 727],
    19: [37, 79, 134, 195, 274, 342, 407, 507, 572, 632, 763],
    20: [39, 83, 140, 204, 287, 354, 424, 528, 598, 659, 790],
    21: [40, 87, 146, 213, 300, 368, 442, 551, 616, 689, 812],
    22: [42, 91, 153, 223, 313, 385, 461, 574, 645, 720, 840],
    23: [44, 95, 160, 234, 326, 401, 479, 598, 673, 752, 872],
    24: [47, 101, 171, 246, 340, 418, 501, 625, 706, 788, 908],
    }
    level = 5

    switch_queue = Queue()
    pi = pigpio.pi()

    pi.set_mode(btnPlus, pigpio.INPUT)
    pi.set_mode(btnMinus, pigpio.INPUT)
    pi.set_pull_up_down(btnPlus, pigpio.PUD_UP)
    pi.set_pull_up_down(btnMinus, pigpio.PUD_UP)
    pi.callback(btnPlus, pigpio.EITHER_EDGE, partial(switch_callback, switch_queue))
    pi.callback(btnMinus, pigpio.EITHER_EDGE, partial(switch_callback, switch_queue))

    previous_count = 0
    start_time = time()
    impuls = ImpulsCounter(pi, sensor)

    try:
    while True:
    sleep(sample_time)

    count = impuls.get()
    if previous_count == count and time() - start_time >= timeout:
    impuls.reset()
    count = impuls.get()
    start_time = time()
    print("count: {0}".format(count))
    previous_count = count

    if not switch_queue.empty():
    pin = switch_queue.get()
    if pin == btnPlus:
    if level < 24:
    level = level + 1
    elif pin == btnMinus:
    if level > 1:
    level = level - 1

    print( calculate_power(level, count, LEVEL_TO_POWER, 20, 120) )

    except (KeyboardInterrupt, SystemExit):
    pi.stop()
    print('\nQuit\n')


    if __name__ == '__main__':
    main()

    #EOF
    [/php]
    => http://codepad.org/gLULFkos


  • Erweiterung zu dem bisherigen Script sähe dann so aus - bitte ausprobieren und Ausgabe posten:

    => http://codepad.org/gLULFkos

    Meine Ausgabe:

    Wenn ich eine Taste drücke:

    Einmal editiert, zuletzt von Landixus (9. Mai 2017 um 19:37)

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!