【问题标题】:Python: how to interrupt, then return to while loop, without goto?Python:如何中断,然后返回while循环,没有goto?
【发布时间】:2016-01-21 07:30:51
【问题描述】:

我正在 python 中运行一个简单的 PID 控制程序。基本上是一个无限循环,从传感器读取然后计算适当的控制信号,并将诊断信息输出到终端。

但是,有时在查看诊断信息时,我想更改 PID 系数(本质上是循环使用的一些常数),方法是从循环中中断,接受用户输入,然后返回到同一个循环。我想这样做任意次数。

使用“goto”,这将是简单易行的,正是我想要的。有人可以给我一些 python 伪代码来做到这一点吗?我实在想不出该怎么做。我可以用 CTRL+C 异常处理程序中断循环,但是我不能回到主循环。

必须有一些非常简单的方法可以做到这一点,但我想不出。想法? 我的代码片段:

while True:
        t0 = get_temp_deg_c(thermocouple1)
        print "Hose Temperature = " + str(t0) + " deg C"

        t1 = get_temp_deg_c(thermocouple2)
        print "Valve Temperature = " + str(t1) + " deg C"

        # write temps to file
        fi.write(str(t0))
        fi.write(" " + str(t1) + "\n")

        error = setpoint - t0

        print "Setpoint = " + str(setpoint) + " deg C"
        print "Error = " + str(error) + " deg C"

        percent_error = error/setpoint*100
        print "Percent error = " + str(percent_error) + " %"

        duty_out = p.GenOut(percent_error)
        print "PID controller duty output: " + str(duty_out) + " %"
        # clamp the output
        if(duty_out) > 100:
            duty_out = 100
        if(duty_out < 0):
            duty_out = 0

        PWM.set_duty_cycle(PWM_pin, duty_out)

        # do we need to increment the setpoint?
        if( (setpoint - setpoint_precision) ... # omitted logic here

        # Here we return to the top

【问题讨论】:

  • 你能修改代码以在线程中运行主循环吗?
  • 也许线程 while 循环可以完成工作,但我不确定线程​​是否允许外部线程引用。你能给我们一个实际的代码示例吗?
  • 您可以构建交互式 shell,当 pid 循环在线程中运行时,用户可以在程序中查看变量,an example that will let you also throw the whole thing into the background
  • 基本上,您似乎想轮询键盘的输入缓冲区?这个答案提到了一些方法。 stackoverflow.com/questions/292095/…
  • 大家好,添加了包含要点的代码 sn-p。

标签: python pid goto


【解决方案1】:

您已经有几种与循环交互的方法,我想指出另一种方法:select()。使用select(),您可以等待任一用户输入。如果您添加超时,则可以在没有用户输入可用的情况下进入正常循环并在那里与您的硬件进行交互。

注意事项:

  • 这是 select 的文档,但请考虑顶部的警告并查看 selectors 模块。
  • 此解决方案与使用键盘中断的解决方案一样,将在更改参数时停止与硬件交互。如果这不可接受,则必须使用后台线程。
  • 使用select()更普遍适用,您也可以等待网络流量。
  • 您的硬件不会得到尽可能频繁的服务,但在两者之间会有固定的暂停。从好的方面来说,你也不会使用完整的 CPU。

【讨论】:

    【解决方案2】:

    如果您不想为 IO 使用单独的线程,则可以使用生成器来跨 KeyboardInterrupts 保留循环的状态。

    some_parameter = 1
    
    def do_pid_stuff():
        while True:
            sensor_data1 = 'data'
            sensor_data2 = 'data'
            sensor_data3 = 'data'
            yield 'based on sensor_data1 ' * some_parameter
            yield 'based on sensor_data2 ' * some_parameter
            yield 'based on sensor_data3 ' * some_parameter
    
    
    stuff = do_pid_stuff()
    while True:
        try:
            for control_signal in stuff:
                print(control_signal)
        except KeyboardInterrupt:
            some_parameter = int(input())
    

    所以主循环将继续使用上次执行的yield 中的新参数。然而,这需要重写你的循环。或许,它应该被拆分为一个生成器,该生成器将为您提供传感器数据,并拆分为一个根据传感器值实际执行操作的函数。

    【讨论】:

      【解决方案3】:

      只要您可以在每次中断后“从头开始”重新启动(而不是在发出信号时返回到循环中的确切点,这是一个更难的问题):

      while True:
          try:
              controller.main_loop()
          except KeyboardInterrupt:
              controller.set_coefficients()
      

      【讨论】:

        猜你喜欢
        • 2023-02-03
        • 1970-01-01
        • 1970-01-01
        • 2017-03-19
        • 2018-08-10
        • 1970-01-01
        • 1970-01-01
        • 2017-01-05
        • 1970-01-01
        相关资源
        最近更新 更多