【问题标题】:Use Python to get state of combustion engine based on spark plug actuation使用 Python 获取基于火花塞驱动的内燃机状态
【发布时间】:2016-04-05 22:41:11
【问题描述】:

致力于为定制越野车创建数据采集系统。使用 Raspberry Pi 和自定义转速计(经过测试并确认工作)来测量 RPM。在以下代码中使用中断来获取 RPM 值。

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

此代码仅在引擎正在运行并产生火花时才有效。如果没有火花,则代码将等待该边缘并且不会继续。在调用get_rpm() 时,如果代码正在等待边缘,这会导致其他进程挂起。

我打算解决此问题的方法是在另一个进程中获取引擎的状态。我认为它最好分为两部分。

第 1 部分,在单独的线程中运行(循环):

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

第 2 部分,根据需要作为函数调用:

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

在第 1 部分将last 保存到第 2 部分可访问的内存中后,第 2 部分将根据火花塞最后一次点燃的时间确定汽车是否正在运行。使用engine_state 作为比较器,只有当engine_state 为真时,数据采集系统才会从get_rpm() 获取并存储RPM 值。

如何实现第 1 部分,以便可以在第 2 部分中使用 last 变量? last 将会非常非常快地发生变化。我不想在每次更新last 时将其存储到树莓派 SD 卡上的文本文件中。我想将last 存储在 RAM 中。

非常感谢!

【问题讨论】:

  • last 已经在 RAM 中,我认为您只需将其作为变量传递给 get_state(last)..
  • time.time 应该是time.time() 我认为
  • 您是在其他地方设置引脚配置还是根本不设置?你不能用中断回调代替吗?它们天生就有螺纹,不会阻塞。我认为您不必等待边缘。顺便说一句,有趣的项目。 :)
  • @jDo 是的,引脚都配置在其他地方。没有将其包含在问题中,因为它已经确定工作。您能否提供一个中断回调实现的快速示例?我是 Python 新手,非常感谢您的帮助!
  • @IronFist 感谢您重新格式化我的代码 sn-ps。您能否提供一个示例来说明“将其作为变量传递”的含义?我是 Python 新手,不熟悉所有的命名法。非常感谢!

标签: python raspberry-pi data-acquisition


【解决方案1】:

这只是为了灵感。我手头没有我的 Pis,所以这是凭记忆盲目写的。

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()
"""

【讨论】:

  • 这是一个关于如何使用线程回调的非常好的示例,并且肯定会有所帮助。我坚持的一件事是如何使用这种方法准确地获得 RPM。我们的信号花在高电平的时间不等于它花在低电平的时间。火花之间的时间(低到高)大于火花从高到低的时间。占空比可能约为 20%。 (en.wikipedia.org/wiki/Duty_cycle#/media/…) 因此,我们需要找到两个上升沿之间或两个下降沿之间的时间来计算 RPM。我们不能使用(续)
  • 我们不能使用上升沿和下降沿之间的时间来计算 RPM。使用线程回调,每次检测到下降(或上升)沿时都会运行回调。这与我们当前确定 RPM 的方法不兼容。引脚 17 上的 Wait_for_edge 不能与同一代码文件中的 add_event_detect 一起使用。这里有什么想法吗? @jDo get_state 功能很好用,但我们不能在与 get_RPM 相同的代码中同时使用它,就像它当前的实现方式一样。
  • @Bobothetwit 顺便说一句,我没有忘记你的问题。我一直在阅读它,例如here,并使用线程和随机性进行一些测试来模拟转速计输入。您是否知道占空比为 20% 时的 RPM 应该是多少? (它会告诉我我的测试是否已经完成或实际产生了有用的东西)。
  • @Bobothetwit 我想我了解您 "(...) 需要找到两个上升沿之间或两个下降沿之间的时间来计算 RPM。"。如果你保存上升时间和下降时间,然后从另一个中减去一个,你会得到脉冲宽度;这不是你想要的,对吧?相反,您想测量正弦数学中可能是波长:从这个上升(忽略下降)--> _|‾‾|___|‾ length_of_last_high 实际上是secs_since_last_high,可能就是你所追求的
猜你喜欢
  • 1970-01-01
  • 2015-03-20
  • 1970-01-01
  • 2018-12-26
  • 1970-01-01
  • 1970-01-01
  • 2015-10-01
  • 2018-12-10
  • 1970-01-01
相关资源
最近更新 更多