Werte aus Tabelle / Matrix / Array, oder Liste?

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

Auch mit drüber schreiben.... nix:

Code: Alles auswählen

   def calculate_power(Level, RPM):
   
    if RPM > RPM_HIGH_LIMIT:
        return 0
    if RPM < RPM_LOWER_LIMIT:
        return 0
    return LEVEL_TO_POWER[Level][(RPM - RPM_LOWER_LIMIT) // 10]
 
 
   def main():
    for Level, RPM in [(6, 65), (6, 71), (7, 68)]:
        print(calculate_power(Level, RPM))
        
   pi = pigpio.pi()
 
   p = readRPM.reader(pi, RPM_GPIO)
 
   start = time.time()
 
   while (time.time() - start) < RUN_TIME:
   
    input_state = GPIO.input(20)
    if input_state == False:
        if count < 24:
         count = count + 1
         RPM = p.RPM()
         print('Level', count, 'RPM={}'.format(int(RPM+0.5))(calculate_power(Level, RPM)))
         time.sleep(SAMPLE_TIME)
   
    input_state = GPIO.input(21)
    if input_state == False:
       if count > 1:
        count = count - 1
        RPM = p.RPM()
        print('Level', count, 'RPM={}'.format(int(RPM+0.5))(calculate_power(Level, RPM)))
        time.sleep(SAMPLE_TIME)
 
 
    RPM = p.RPM()
    time.sleep(SAMPLE_TIME)
    print("RPM={}".format(int(RPM+0.5)))
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

Code: Alles auswählen

pi@carcam:~/AntOverPowerTable $ ./5powerx.py
RPM=0
RPM=0
RPM=0
RPM=81
RPM=67
RPM=108
RPM=299
RPM=140
Traceback (most recent call last):
  File "./5powerx.py", line 172, in <module>
    print('Level', count, 'RPM={}'.format(int(RPM+0.5))(calculate_power(LEVEL, RPM)))
  File "./5powerx.py", line 142, in calculate_power
    return LEVEL_TO_POWER[LEVEL][(RPM - RPM_LOWER_LIMIT) //10]
TypeError: list indices must be integers, not float
aber meine Liste besteht doch aus Ganzzahlen!?

Code: Alles auswählen

 
   import time
   import pigpio
   import readRPM
   import RPi.GPIO as GPIO
 
   GPIO.setmode(GPIO.BCM)
   GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_UP)
   GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP)
   count = 5
 
   RPM_GPIO = 4
   RUN_TIME = 9600.0
   SAMPLE_TIME = 2.0
   RPM_LOWER_LIMIT = 20
   RPM_HIGH_LIMIT = 120
   LEVEL = count
   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],
    }
 
   def calculate_power(LEVEL, RPM):
   
        return LEVEL_TO_POWER[LEVEL][(RPM - RPM_LOWER_LIMIT) //10]
 
 
   def main():
    for LEVEL, RPM in [(6, 65), (6, 71), (7, 68)]:
        print(calculate_power(LEVEL, RPM))
           
   pi = pigpio.pi()
 
   p = readRPM.reader(pi, RPM_GPIO)
 
   start = time.time()
 
   while (time.time() - start) < RUN_TIME:
   
    input_state = GPIO.input(20)
    if input_state == False:
        if count < 24:
         count = count + 1
         RPM = p.RPM()
         LEVEL = count
         print('Level', count, 'RPM={}'.format(int(RPM+0.5))(calculate_power(LEVEL, RPM)))
         time.sleep(SAMPLE_TIME)
   
    input_state = GPIO.input(21)
    if input_state == False:
        if count > 1:
         count = count - 1
         RPM = p.RPM()
         LEVEL = count
         print('Level', count, 'RPM={}'.format(int(RPM+0.5))(calculate_power(LEVEL, RPM)))
         time.sleep(SAMPLE_TIME)
 
 
    RPM = p.RPM()
    time.sleep(SAMPLE_TIME)
    print("RPM={}".format(int(RPM+0.5)))
   
   p.cancel()
   pi.stop()
 

 
 
if __name__ == '__main__':
    main()
das voll doof
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

Also ist ja nicht so das ich am Tag der Arbeit faul rumsitze :)

Ich hab dann schon mal ein Ergebnis:

Code: Alles auswählen

#!/usr/bin/env python
import time
import pigpio
 
class reader:
   """
 A class to read speedometer pulses and calculate the RPM.
 """
   def __init__(self, pi, gpio, pulses_per_rev=1.0, weighting=0, min_RPM=5):
      """
    Instantiate with the Pi and gpio of the RPM signal
    to monitor.
 
    Optionally the number of pulses for a complete revolution
    may be specified.  It defaults to 1.
 
    Optionally a weighting may be specified.  This is a number
    between 0 and 1 and indicates how much the old reading
    affects the new reading.  It defaults to 0 which means
    the old reading has no effect.  This may be used to
    smooth the data.
 
    Optionally the minimum RPM may be specified.  This is a
    number between 1 and 1000.  It defaults to 5.  An RPM
    less than the minimum RPM returns 0.0.
    """
      self.pi = pi
      self.gpio = gpio
      self.pulses_per_rev = pulses_per_rev
 
      if min_RPM > 1000:
         min_RPM = 1000
      elif min_RPM < 1:
         min_RPM = 1
 
      self.min_RPM = min_RPM
 
      self._watchdog = 200 # Milliseconds.
 
      if weighting < 0:
         weighting = 0
      elif weighting > 0:
         weighting = 0
 
      self._new = 1 - weighting # Weighting for new reading.
      self._old = weighting       # Weighting for old reading.
 
      self._high_tick = None
      self._period = None
 
      pi.set_mode(gpio, pigpio.INPUT)
 
      self._cb = pi.callback(gpio, pigpio.RISING_EDGE, self._cbf)
      pi.set_watchdog(gpio, self._watchdog)
 
   def _cbf(self, gpio, level, tick):
 
      if level == 1: # Rising edge.
 
         if self._high_tick is not None:
            t = pigpio.tickDiff(self._high_tick, tick)
 
            if self._period is not None:
               self._period = (self._old * self._period) + (self._new * t)
            else:
               self._period = t
 
         self._high_tick = tick
 
      elif level == 2: # Watchdog timeout.
 
         if self._period is not None:
            if self._period < 2000000000:
               self._period += (self._watchdog * 1000)
 
   def RPM(self):
      """
    Returns the RPM.
    """
      RPM = 0
      if self._period is not None:
         RPM = 60000000 / (self._period * self.pulses_per_rev)
         if RPM < self.min_RPM:
            RPM = 0
 
      return RPM
 
   def cancel(self):
      """
    Cancels the reader and releases resources.
    """
      self.pi.set_watchdog(self.gpio, 0) # cancel watchdog
      self._cb.cancel()
 
if __name__ == "__main__":
 
   import time
   import pigpio
   import readRPM
   import RPi.GPIO as GPIO
 
   GPIO.setmode(GPIO.BCM)
   GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_UP)
   GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP)
   count = 5
   RPM_GPIO = 4
   RUN_TIME = 9600.0
   SAMPLE_TIME = 2.0
   RPM_LOWER_LIMIT = 15
   RPM_HIGHER_LIMIT = 320
   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],
    }
 
   def calculate_power(LEVEL, RPM):
        
	if RPM < RPM_LOWER_LIMIT:
	 return 0
	return LEVEL_TO_POWER[LEVEL][(RPM - RPM_LOWER_LIMIT) //10]
	if RPM > RPM_HIGHER_LIMIT:
	 return 0
        return LEVEL_TO_POWER[LEVEL][(RPM + RPM_HIGHER_LIMIT) //10]
 
 
   def main():
    for LEVEL, RPM in [(1, 6), (2, 8), (3, 9)]:
     print(calculate_power(LEVEL, RPM))
   
   pi = pigpio.pi()
 
   p = readRPM.reader(pi, RPM_GPIO)
 
   start = time.time()
 
   while (time.time() - start) < RUN_TIME:
   
    input_state = GPIO.input(20)
    if input_state == False:
        if count < 24:
         count = count + 1
         RPM = (int(RPM+1))
	 LEVEL = count
         print('Power',calculate_power(LEVEL, RPM),'Level', count, 'RPM={}'.format(int(RPM+1)))
         print(calculate_power(LEVEL, RPM))
	 time.sleep(SAMPLE_TIME)
   
    input_state = GPIO.input(21)
    if input_state == False:
        if count > 1:
         count = count - 1
         RPM = (int(RPM+1))
	 LEVEL = count
         print('Power',calculate_power(LEVEL, RPM),'Level', count, 'RPM={}'.format(int(RPM+1)))
	 time.sleep(SAMPLE_TIME)
 
    
    LEVEL = count
    RPM = p.RPM()
    RPM = (int(RPM+1))
    time.sleep(SAMPLE_TIME)
    print('Power',calculate_power(LEVEL, RPM),'Level', count, "RPM={}".format(int(RPM+1)))    

   p.cancel()
   pi.stop()
 

 
 
if __name__ == '__main__':
    main()


Ich hab jetzt:

Code: Alles auswählen

('Power', 13, 'Level', 5, 'RPM=17')
('Power', 92, 'Level', 5, 'RPM=61')
('Power', 45, 'Level', 5, 'RPM=42')
('Power', 52, 'Level', 6, 'RPM=43')
als Ausgabe, aber bekomme noch ein Fehler obwohl ich ja begrenzt habe:

Code: Alles auswählen

Traceback (most recent call last):
  File "./5powerx.py", line 184, in <module>
    print('Power',calculate_power(LEVEL, RPM),'Level', count, "RPM={}".format(int(RPM+1)))
  File "./5powerx.py", line 142, in calculate_power
    return LEVEL_TO_POWER[LEVEL][(RPM - RPM_LOWER_LIMIT) //10]
IndexError: list index out of range
pi@carcam:~/AntOverPowerTable $
Wo habe ich hier denn noch den Fehler?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nachdem ich mir dein Problem mal tiefer angeschaut habe muss ich sagen ich finde die Tabelle etwas seltsam. Es scheint als ob da RPM Bereiche auf einen Leistungswert abgebildet werden, statt ein RPM Wert auf einen Leistungswert.

Darum habe ich mir auch erstmal Interpolation gespart, denn das scheint gar nicht gewollt?

Hier mein Code zur Uebersezung von RPMs auf einen Leistungswert:

Code: Alles auswählen

import bisect

RPMS = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130,]

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],
    }

def clamp(v, lower, upper):
    return max(min(v, upper), lower)


def rpm2index(rpm):
    return clamp(bisect.bisect(RPMS, rpm) - 1, 0, len(RPMS) - 2)


def main():
    for rpm in xrange(20, 131):
        i = rpm2index(rpm)
        print(rpm, i, LEVEL_TO_POWER[1][i])


if __name__ == '__main__':
    main()
Bezueglich des "Allgemeinen nutzen des Programms" - der ist wohl eher nicht gegeben, ich bezweifele, dass diese Skript jemals woanders laufen wird. Und selbst wenn dem so sein sollte - das mag deine Motivation sein, anderen helfen zu wollen. Die von jemandem hier, der das Problem nicht hat, wird das wohl kaum sein. Sondern eher zu zeigen, wie man Probleme loest, oder was auch immer einen motiviert.
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

__deets__ hat geschrieben:Nachdem ich mir dein Problem mal tiefer angeschaut habe muss ich sagen ich finde die Tabelle etwas seltsam. Es scheint als ob da RPM Bereiche auf einen Leistungswert abgebildet werden, statt ein RPM Wert auf einen Leistungswert.
Level + RPM = Leistungswert <-- eigentlich
Darum habe ich mir auch erstmal Interpolation gespart, denn das scheint gar nicht gewollt?
erm, doch schon, ich bettel hier ja nicht nach fertigem code und hab auch schon einige Stunden investiert.
Bezueglich des "Allgemeinen nutzen des Programms" - der ist wohl eher nicht gegeben, ich bezweifele, dass diese Skript jemals woanders laufen wird. Und selbst wenn dem so sein sollte - das mag deine Motivation sein, anderen helfen zu wollen. Die von jemandem hier, der das Problem nicht hat, wird das wohl kaum sein. Sondern eher zu zeigen, wie man Probleme loest, oder was auch immer einen motiviert.
Oh doch, ich möchte das schon so auf github aufbereiten, das es jeder der ein Gerät mit Powertabelle hat, entsprechend benutzen kann.
Ein paar zigtausend sind da schon auf dem Markt. Das gibt doch eine tolle Anleitung mit Raspberry PI :)

Die Tabelle ist ja der Anfang, danach muss der Wert ja noch übermittelt werden.
da bekomme ich vielleicht ein Inder für, die Arbeiten manchmal für 10$-15$ die Stunde.

Danke für den code, aber ich bin doch schon weit gekommen und scheitere nur noch an den "Limits"

Mir ist es schon wichtig, das es läuft wie ich mir das programmiert habe, das clamp sieht evtl. für mich interessant aus?

Aber trotzdem allen hier DANKE für die Hilfen, ihr seit sehr geduldig :)
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du kannst natuerlich immer rumclampen wie ein wilder, um deine Fehler wegzurpuegeln. Aber das verschleiert ggf. Probleme.

Was die Interpolation angeht - das ist schon etwas problematisch. Irgendwas kann man da natuerlich machen, aber wie genau sieht denn die Zuordnung aus? Ist der angegebene Wert der Wert an der linken Seite, in der Mitte, oder an der rechten Seite des RPM-Intervalls?

Und wo wir bei den Daten sind - sind die so irgendwoher abgeschrieben, oder hast du die selbst ermittelt? Die sind ziemlich unschoen, weil sie in der ersten Ableitung nicht monoton steigend, sondern auch schon mal absteigend sind.
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

__deets__ hat geschrieben:Du kannst natuerlich immer rumclampen wie ein wilder, um deine Fehler wegzurpuegeln. Aber das verschleiert ggf. Probleme.

Was die Interpolation angeht - das ist schon etwas problematisch. Irgendwas kann man da natuerlich machen, aber wie genau sieht denn die Zuordnung aus? Ist der angegebene Wert der Wert an der linken Seite, in der Mitte, oder an der rechten Seite des RPM-Intervalls?

Und wo wir bei den Daten sind - sind die so irgendwoher abgeschrieben, oder hast du die selbst ermittelt? Die sind ziemlich unschoen, weil sie in der ersten Ableitung nicht monoton steigend, sondern auch schon mal absteigend sind.
Die Daten kommen aus der Anleitung Seite 11:
https://www.christopeit-sport.com/media ... er-CX6.pdf

Ich will die gelesenen Daten ja später noch an JSON übergeben, oder abholen:
https://github.com/olympum/ant-cycling-power
das Programm postet dann die Power an https://zwift.com/ und ich kann radeln (Crosstrainern) mit echten Werten :)
Ich denke das ist super Interessant für alle die auch so ein Gerät haben, oder vergleichbar. Ob ergometer, rudergerät etc. spielt dann ja keine Rolle mehr, da die Leistungsdaten ja schon vorhanden sind.

Erklärt das besser, warum mir da so dran gelegen ist? :)

BTW, wie Limitiere ich denn jetzt auf meine Art die LOW und HIGH Werte?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das PDF bringt Licht in's Dunkel - du hast einfach eine 130 dazuerfunden, die's nicht gibt.

Hier der korrigierte Code, der das beruecksichtigt & nun auch linear interpoliert. RPMs kleiner 20 werden aber *nicht* akzeptiert.

Und du solltest das einfach dann einbauen statt zu versuchen deinen Code umzufummeln.

Code: Alles auswählen

from __future__ import print_function

import math

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],
    }

UPPER_LIMIT = len(LEVEL_TO_POWER.values()[0]) - 2

def clamp(v, lower, upper):
    return max(min(v, upper), lower)


def rpm2index(rpm):
    # clamping downto a range that never exceeds
    # the power level size - 2 so we can interpolate
    i = clamp((rpm - 20) // 10, 0, UPPER_LIMIT)
    f = (rpm - (i * 10 + 20)) / 10.0
    return i, f


def rpm2power(rpm):
    i, f = rpm2index(rpm)
    a = LEVEL_TO_POWER[1][i]
    b = LEVEL_TO_POWER[1][i + 1]
    return a + (b - a) * f


def main():
    for rpm in xrange(20, 131):
        print("RPM:", rpm, "POWER:", rpm2power(rpm))


if __name__ == '__main__':
    main()
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

__deets__ hat geschrieben:Das PDF bringt Licht in's Dunkel - du hast einfach eine 130 dazuerfunden, die's nicht gibt.

Hier der korrigierte Code, der das beruecksichtigt & nun auch linear interpoliert. RPMs kleiner 20 werden aber *nicht* akzeptiert.

Und du solltest das einfach dann einbauen statt zu versuchen deinen Code umzufummeln.
Danke, ich werde mal versuchen wie ich das eingebaut bekomme.
Ich muss ja noch meine GPIOs etc. einbauen, aber das sollte ich gut hin bekommen.
Ich melde mich dann hier auch zurück :)

[Ist doch nicht so einfach, ich mach da mal morgen weiter].
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

Soweit bin ich bis jetzt:

Code: Alles auswählen

if __name__ == "__main__":
 
   import time
   import pigpio
   import readRPM
   import RPi.GPIO as GPIO
   import math 
   GPIO.setmode(GPIO.BCM)
   GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_UP)
   GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP)
   count = 5
   RPM_GPIO = 4
   RUN_TIME = 9600.0
   SAMPLE_TIME = 2.0
   RPM_LOWER_LIMIT = 20
   RPM_HIGHER_LIMIT = 320
   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],
    }
   UPPER_LIMIT = len(LEVEL_TO_POWER.values()[0]) - 2 
    
   def clamp(v, lower, upper):
    return max(min(v, upper), lower)
 
 
   def rpm2index(rpm):
     # clamping downto a range that never exceeds
     # the power level size - 2 so we can interpolate
     i = clamp((rpm - 20) // 10, 0, UPPER_LIMIT)
     f = (rpm - (i * 10 + 20)) / 10.0
     return i, f
 
 
   def rpm2power(rpm):
     i, f = rpm2index(rpm)
     a = LEVEL_TO_POWER[1][i]
     b = LEVEL_TO_POWER[1][i + 1]
     return a + (b - a) * f        
	
   def main():
    for rpm in xrange(20, 131):
     print('Level', count,"RPM:", rpm, "POWER:", rpm2power(rpm))
   
   pi = pigpio.pi()
 
   p = readRPM.reader(pi, RPM_GPIO)
 
   start = time.time()
   while (time.time() - start) < RUN_TIME:
   
    input_state = GPIO.input(20)
    if input_state == False:
          if count < 24:
           count = count + 1
           LEVEL = count
           for rpm in xrange(20, 131):
            print('Level', count,"RPM:", rpm, "POWER:", rpm2power(rpm))
	    time.sleep(SAMPLE_TIME)
   
    input_state = GPIO.input(21)
    if input_state == False:
         if count > 1:
          count = count - 1
          LEVEL = count
          print('Level', count,"RPM:", rpm, "POWER:", rpm2power(rpm))
	  time.sleep(SAMPLE_TIME)
 
    
   LEVEL = count
   RPM = rpm()
   time.sleep(SAMPLE_TIME)
   print('Level', count,"RPM:", rpm, "POWER:", rpm2power(rpm))    

   p.cancel()
   pi.stop()
 

 
 
if __name__ == '__main__':
    main()
Der output:

Code: Alles auswählen

pi@carcam:~/AntOverPowerTable $ ./5powerx.py
Level 6 RPM: 20 POWER: 6.0
Level 6 RPM: 21 POWER: 6.6
Level 6 RPM: 22 POWER: 7.2
Level 6 RPM: 23 POWER: 7.8
Level 6 RPM: 24 POWER: 8.4
Level 6 RPM: 25 POWER: 9.0
Level 6 RPM: 26 POWER: 9.6
Level 6 RPM: 27 POWER: 10.2
noch nicht so wie es soll.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich habe die 1 hart verdrahtet. Ich dachte somweit reihct das Verständnis :K
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

Leider nicht. :oops:
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

Schade das man seine eigenen Posts nicht später noch korrigieren kann.
@__deets__

Ich bin halt ehrlich und ich raff deinen Code einfach nicht, deswegen langt es auch nicht bei mir, den einzubauen.
Ich dachte schon ich bin weit genug und brauche nur noch die Limitation.
Dein Code ist sicher richtiger und effizient, aber im Zusammenhang mit meinem Level + - den GPIO Ports bekomme ich das mit deinem
Code einfach nicht zusammen gebaut. Try und Error bringt einen da nicht weiter, das hab ich schon vor Jahren schmerzhaft gelernt.

vor allem möchte ich die Daten später ja noch abholen/übergeben an das Programm was die Werte Broadcastet.
Ich bin wohl mit der Gesamtsituation etwas überfordert. :? :(
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

So jetzt bin ich weiter gekommen, die Limits klappen auch. :)
sorry @__deets__ ich bekomme es einfach nicht in mein Code eingebaut.

Hier auch mal mein bescheidender Messaufbau:
Bild


ich habe jetzt erstmal die Ausgabe wie ich sie haben wollte auf der Console:

Code: Alles auswählen

('Power', 175, 'Level', 5, 'RPM=76')
('Power', 65, 'Level', 5, 'RPM=35')
('Power', 45, 'Level', 5, 'RPM=23')
('Power', 0, 'Level', 5, 'RPM=17')
('Power', 0, 'Level', 5, 'RPM=14')
('Power', 0, 'Level', 5, 'RPM=12')
('Power', 0, 'Level', 5, 'RPM=10')
Ich hab es sozusagen an die Mauer geschafft und kann schon rüber gucken.

Das JSON Programm soll jetzt:[codebox=javascript file=Unbenannt.js]var power_meter = require('./power-meter');
var pm = new power_meter.PowerMeter();

function a() {
var power_instant = *Meine Power aus python*;
var cadence = *Meine RPM aus python*;
pm.broadcast(power_instant, cadence);
setTimeout(a, 249);
}

a();[/code]

Wenn ich jetzt noch meine "Power" und meine "RPM" Werte rüber bekomme, habe ich was ich gerne möchte.
Oder kann das Python auch so? "import JSON" habe ich wohl gefunden, aber ich kann die ja nicht so da reinschreiben*.

*habs versucht *duck

Nochmal vielen Dank für eure Geduld und Hilfe

Achso hier mein* Code soweit:

Code: Alles auswählen

#!/usr/bin/env python
import time
import pigpio
import json 
class reader:
   """
A class to read speedometer pulses and calculate the RPM.
"""
   def __init__(self, pi, gpio, pulses_per_rev=1.0, weighting=0, min_RPM=5):
      """
   Instantiate with the Pi and gpio of the RPM signal
   to monitor.
 
   Optionally the number of pulses for a complete revolution
   may be specified.  It defaults to 1.
 
   Optionally a weighting may be specified.  This is a number
   between 0 and 1 and indicates how much the old reading
   affects the new reading.  It defaults to 0 which means
   the old reading has no effect.  This may be used to
   smooth the data.
 
   Optionally the minimum RPM may be specified.  This is a
   number between 1 and 1000.  It defaults to 5.  An RPM
   less than the minimum RPM returns 0.0.
   """
      self.pi = pi
      self.gpio = gpio
      self.pulses_per_rev = pulses_per_rev
 
      if min_RPM > 1000:
         min_RPM = 1000
      elif min_RPM < 1:
         min_RPM = 1
 
      self.min_RPM = min_RPM
 
      self._watchdog = 200 # Milliseconds.
 
      if weighting < 0:
         weighting = 0
      elif weighting > 0:
         weighting = 0
 
      self._new = 1 - weighting # Weighting for new reading.
      self._old = weighting       # Weighting for old reading.
 
      self._high_tick = None
      self._period = None
 
      pi.set_mode(gpio, pigpio.INPUT)
 
      self._cb = pi.callback(gpio, pigpio.RISING_EDGE, self._cbf)
      pi.set_watchdog(gpio, self._watchdog)
 
   def _cbf(self, gpio, level, tick):
 
      if level == 1: # Rising edge.
 
         if self._high_tick is not None:
            t = pigpio.tickDiff(self._high_tick, tick)
 
            if self._period is not None:
               self._period = (self._old * self._period) + (self._new * t)
            else:
               self._period = t
 
         self._high_tick = tick
 
      elif level == 2: # Watchdog timeout.
 
         if self._period is not None:
            if self._period < 2000000000:
               self._period += (self._watchdog * 1000)
 
   def RPM(self):
      """
   Returns the RPM.
   """
      RPM = 0
      if self._period is not None:
         RPM = 60000000 / (self._period * self.pulses_per_rev)
         if RPM < self.min_RPM:
            RPM = 0
 
      return RPM
 
   def cancel(self):
      """
   Cancels the reader and releases resources.
   """
      self.pi.set_watchdog(self.gpio, 0) # cancel watchdog
      self._cb.cancel()
 
if __name__ == "__main__":
 
   import time
   import pigpio
   import readRPM
   import RPi.GPIO as GPIO
 
   GPIO.setmode(GPIO.BCM)
   GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_UP)
   GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP)
   count = 5
   RPM_GPIO = 4
   RUN_TIME = 9600.0
   SAMPLE_TIME = 1.0
   RPM_LOWER_LIMIT = 20
   RPM_HIGHER_LIMIT = 120
   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],
    }
 
   def calculate_power(LEVEL, RPM):
       
    if RPM <= RPM_LOWER_LIMIT:
    	return 0
    if RPM >= RPM_HIGHER_LIMIT:
	return 0
    return LEVEL_TO_POWER[LEVEL][(RPM) //10]
    
 
 
   def main():
    for LEVEL, RPM in [(1, 6), (2, 8), (3, 9)]:
     print(calculate_power(LEVEL, RPM))
   
   pi = pigpio.pi()
 
   p = readRPM.reader(pi, RPM_GPIO)
 
   start = time.time()
 
   while (time.time() - start) < RUN_TIME:
   
    input_state = GPIO.input(20)
    if input_state == False:
        if count < 24:
         count = count + 1
         RPM = (int(RPM+1))
     	 LEVEL = count
         print('Power',calculate_power(LEVEL, RPM),'Level', count, 'RPM={}'.format(int(RPM+1)))
         print(calculate_power(LEVEL, RPM))
     	 time.sleep(SAMPLE_TIME)
   
    input_state = GPIO.input(21)
    if input_state == False:
        if count > 1:
         count = count - 1
         RPM = (int(RPM+1))
    	 LEVEL = count
         print('Power',calculate_power(LEVEL, RPM),'Level', count, 'RPM={}'.format(int(RPM+1)))
	 time.sleep(SAMPLE_TIME)
 
   
    LEVEL = count
    RPM = p.RPM()
    RPM = (int(RPM+1))
    time.sleep(SAMPLE_TIME)
    print('Power',calculate_power(LEVEL, RPM),'Level', count, "RPM={}".format(int(RPM+1)))    
 
   p.cancel()
   pi.stop()

 
 
 
 
if __name__ == '__main__':
    main()
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist noch mal eine ganz andere Baustelle. Ich weiss jetzt nicht was dieses Powermeter-Zeugs ist, aber um etwas an einen Browser zu schicken reicht es nicht nur JSON zu erzeugen, sondern das muss ueber eine geeignete Verbindung an den Browser geschickt werden.

Du kannst zB mal hier http://www.forum-raspberrypi.de/Thread- ... schen-ajax schauen ob dir das nachvollziehbar ist.
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

__deets__ hat geschrieben:Das ist noch mal eine ganz andere Baustelle. Ich weiss jetzt nicht was dieses Powermeter-Zeugs ist, aber um etwas an einen Browser zu schicken reicht es nicht nur JSON zu erzeugen, sondern das muss ueber eine geeignete Verbindung an den Browser geschickt werden.

Du kannst zB mal hier http://www.forum-raspberrypi.de/Thread- ... schen-ajax schauen ob dir das nachvollziehbar ist.
Das macht das JSON Programm, das sendet hier im Beispiel:
https://github.com/olympum/ant-cycling- ... er/test.js

kontinuierlich power und cadence an den ANT+ Stick im Raspberry PI

Wie soll ich das erklären? Ich versuchs:
der Raspberry PI is der Slave mit einem ANT+ Stick, der bekommt geliefert vom Cross trainer die RPM. Die Level kann ich auch schalten mit den Tastern die am Raspberry angeschlossen sind. Somit habe ich meine POWER Werte und RPM Werte. (Der jetzige Code halt)

Der ANT+ Stick ist als "Sender" konfiguriert und sendet an meine Windows Maschine wo ebenfalls ein ANT+ Stick als Master eingesteckt ist (Empfänger)
Dieser empfängt also die POWER und RPM Daten. Somit kann ich in Zwift radeln:
Bild

Die Zwift Software erwartet Power (auf dem Bild als Beispiel 170) und RPM, daraus ergibt sich die Geschwindigkeit.

Hab ich das einigermaßen Verständnisvoll erklärt?

100€ stehen immer noch im Raum *wink :)
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

Ich frag mich grad, ob ich das alles auch hätte in Javascript machen sollen/müssen?

Da das Programm was ant ANT+ sendet ja JSON ist. JSON ist Javascript?

:shock:
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@Landixus: JSON ist ein allgemein bekanntes, standardisiertes Format, das gewisse Ähnlichkeit mit Javascript-Strukturen wie Listen und Wörterbüchern hat. Es ist kein Javascript. Es gibt für so gut wie jede Programmiersprache Parser dafür.
Benutzeravatar
Landixus
User
Beiträge: 49
Registriert: Mittwoch 26. April 2017, 09:38

Sirius3 hat geschrieben:@Landixus: JSON ist ein allgemein bekanntes, standardisiertes Format, das gewisse Ähnlichkeit mit Javascript-Strukturen wie Listen und Wörterbüchern hat. Es ist kein Javascript. Es gibt für so gut wie jede Programmiersprache Parser dafür.
Beruhigt mich das jetzt? :)

Und vor allem bekomme ich das Output in mein python file überhaupt eingebaut?:

Code: Alles auswählen

var power_meter = require('./power-meter');
var pm = new power_meter.PowerMeter();

function a() {
  var power_instant = calculate_power(LEVEL, RPM);
  var cadence = RPM={}".format(int(RPM+1));
  pm.broadcast(power_instant, cadence);
  setTimeout(a, 249);
}

a();
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du kannst nicht einfach zwei Programmiersprachen zusammenmanschen. Und mit json hat das auch nix zu tun. Das ist JavaScript, ganz normal.

Was du brauchst ist eine ANT+ Protokoll Bibliothek. Sowas gibts auch für Python, zB hier: http://python-evdev.readthedocs.io/en/latest/index.html

Ob die den Zweck erfüllt oder nicht weiß ich nicht. Ich habe keine ant+-fähigen Geräte.
Antworten