2016-04-05 4 views
2

Travailler pour créer un système d'acquisition de données pour un véhicule hors route personnalisé. Utilisation de Raspberry Pi et d'un tachymètre personnalisé (testé et confirmé) pour mesurer RPM. Utilisation d'interruptions dans le code suivant pour obtenir la valeur RPM.Utiliser Python pour obtenir l'état du moteur à combustion en fonction de l'activation de la bougie

def get_rpm():           
    GPIO.wait_for_edge(17, GPIO.FALLING) 
    start = time.time() 
    GPIO.wait_for_edge(17, GPIO.FALLING) 
    end = time.time() 
    duration = end - start 
    rpm = (1/duration)*60 
    return rpm 

Ce code ne fonctionne que si le moteur tourne et produit une étincelle. S'il n'y a pas d'étincelle, le code attend pour ce bord et ne continue pas. Lorsque vous appelez get_rpm(), si le code attend un tronçon, les autres processus sont bloqués.

Ma solution de contournement prévue pour ceci est d'obtenir l'état du moteur dans un autre processus. Je pense que cela fonctionnera mieux en deux parties.

partie 1, en cours d'exécution (boucle) dans un thread séparé:

GPIO.wait_for_edge(17, GPIO.RISING) 
last = time.time 

partie 2, en cours d'exécution appelé en fonction au besoin:

def get_state(): 
    while time.time - last < .5: 
     engine_state = true 
    else: 
     engine_state = false 
    return engine_state 

à la partie 1 d'économie last de mémoire accessible à La partie 2, partie 2 déterminera si la voiture fonctionne ou non en fonction de la dernière fois que la bougie s'est déclenchée. En utilisant engine_state comme comparateur, le système d'acquisition de données obtiendra et stockera la valeur RPM de get_rpm() uniquement lorsque engine_state est vrai.

Comment puis-je implémenter la partie 1 de telle sorte que je puisse utiliser la variable last dans la partie 2? last va changer très, très rapidement. Je ne veux pas le stocker dans un fichier texte sur la carte SD du Raspberry Pi chaque fois que last est mis à jour. Je veux stocker last en RAM.

Merci beaucoup!

+0

'last' est déjà dans la RAM, je pense que tout ce que vous avez besoin est de passer comme une variable' get_State (dernier) '' .. –

+0

time.time' devrait être 'time.time()' Je pense – jDo

+0

Est-ce que vous configurez la configuration des broches ailleurs ou pas du tout? Ne pourriez-vous pas utiliser les rappels d'interruption à la place? Ils sont enfilés par la nature et ne bloqueront pas. Je ne pense pas que vous deviez attendre le bord. Projet intéressant btw. :) – jDo

Répondre

1

Ceci est juste pour l'inspiration. Je n'ai pas mon Pis à portée de main, donc c'est écrit aveuglément de mémoire.

import RPi.GPIO as GPIO 
import time 

GPIO.setmode(GPIO.BCM) 
GPIO.setup(17, GPIO.IN) 
# the line below is important. It'll fire on both rising and falling edges 
# and it's non-blocking 
GPIO.add_event_detect(17, GPIO.BOTH, callback=callback_func) 

length_of_last_high = 0 
length_of_last_low = 0 

last_rise = 0 
last_fall = 0 
last_callback = 0 

def callback_func(pin): 
    # all of these global variables aren't needed 
    # but I left them in for demo purposes 
    global last_rise 
    global last_fall 
    global last_callback 
    global length_of_last_high 
    global length_of_last_low 
    last_callback = time.time() 
    if GPIO.input(17): 
     print "Pin 17 is rising!" 
     length_of_last_high = last_callback - last_rise 
     last_rise = last_callback 
    else: 
     print "Pin 17 is falling!" 
     length_of_last_low = last_callback - last_fall 
     last_fall = last_callback 


# last passed as parameter (the preferred solution if it works). 
# You test it - I can't at the moment 
def get_state(last=last_rise): 
    engine_state = False 
    if time.time() - last < .5: 
     engine_state = True 
    return engine_state 

# last as global variable. 
# This works too but global is bad practice if it can be avoided  
# (namespace littering) 
def get_state2(): 
    global last_rise 
    engine_state = False 
    if time.time() - last_rise < .5: 
     engine_state = True 
    return engine_state 


def main(): 
    while True: 
     print "Not blocking! This loop could sleep forever. It wouldn't affect the readings" 
     time.sleep(1) 
     print get_state() 

""" 
GPIO.cleanup() 
""" 
+0

Ceci est un très bon exemple de comment utiliser les rappels à threads, et est utile à coup sûr. Une chose sur laquelle je suis coincé est comment obtenir précisément RPM en utilisant cette méthode. Le temps que passe notre signal n'est pas égal au temps qu'il passe bas. Le temps entre les étincelles (de bas en haut) est plus grand que le temps nécessaire à une étincelle pour passer de haut en bas. Le cycle de service pourrait être quelque chose comme 20%. (https: //en.wikipedia.org/wiki/Duty_cycle #/media/Fichier: PWM_duty_cycle_with_label.gif) Pour cette raison, nous devons trouver le temps entre deux fronts montants ou entre deux fronts descendants pour calculer RPM. Nous ne pouvons pas utiliser (cont.) – Bobothetwit

+0

Nous ne pouvons pas utiliser le temps entre un front montant et un front descendant pour calculer RPM. À l'aide d'un rappel fileté, le rappel s'exécute chaque fois que le front descendant (ou montant) est détecté. Ceci est incompatible avec notre méthode actuelle de détermination de RPM. Wait_for_edge sur la broche 17 ne peut pas être utilisé conjointement avec add_event_detect dans le même fichier de code. Des idées ici? @jDo La fonctionnalité get_state fonctionne GREAT, mais nous ne pouvons pas l'utiliser en même temps dans le même code que get_RPM comme c'est le cas actuellement. – Bobothetwit

+0

@Bobothetwit Je n'ai pas oublié votre question btw. Je viens de lire à ce sujet, par exemple [ici] (http://forums.hybridz.org/topic/14725-pulsewidth-vs-dutycycle-vg30et-ecu/), et faire quelques tests en utilisant des threads et le hasard pour émuler l'entrée du tachymètre. Savez-vous à peu près ce que devrait être le RPM lorsque le coefficient d'utilisation est de 20%? (il me dirait si mes tests sont loin ou produisent quelque chose d'utile). – jDo