【樹莓派】Python開發工控機急停設計


背景

我們在一些工業產品中使用樹莓派替代了PLC和上位機,並借助樹莓派的算力將AI和機器視覺引入工業領域。
以前的產品都不存在動作機構,僅僅將結果輸出到指示燈、蜂鳴器或者顯示器上,沒有安全隱患,
現在引入了動作機構,需要根據結果驅動設備執行一定的動作,動作機構的引入,增加了產品的安全隱患,比如可能會夾手,撞機等。為此我們需要設計額外的保護程序,其中最重要的是急停功能的實現。

要求

  • 急停信號優先級最高,任何情況下按下急停都應該馬上停止

問題分析

  • 動作機構由24V供電,急停開關串聯在電源上,可以做到開關按下后,動作機構斷電。(急停開關都帶有鎖定機構,按下后不會彈起,會保持按下狀態)
  • 樹莓派獨立於動作機構供電,急停開關按下后,樹莓派收到信號,開始終止程序,之后一直監聽急停按鈕信號。
  • Python一般情況下是單線程運行,為了及時響應急停,需要將急停功能做成主進程,業務動作邏輯作為子進程,當監聽到急停信號后,馬上終止子進程

設計思路

  • 擇子進程而不是子線程的原因為:Python中子線程無法發送kill信號,沒有很好的辦法干預子線程的行為(除非每一步都判斷一下,會造成代碼復雜度升高),而子進程可以直接發送terminate信號殺死。
  • 急停使用低電平觸發原因為:我們認為低電平是一個穩定的狀態,高電平不是一個穩定的狀態,比如由於某種原因導致斷電,那么也應該觸發急停,發生任何非正常的情況,停下來總是沒錯的。

接線示意圖

Python程序流程圖

代碼實現

import RPi.GPIO as GPIO
import time
from multiprocessing import Process
# 定義信號引腳
button_stop = 20
button_reset = 21
button_start = 22


# 初始化GPIO
def init_gpio():
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    # 初始化按鈕,按鈕均為低電平觸發
    GPIO.setup(button_reset, GPIO.IN)
    GPIO.setup(button_start, GPIO.IN)
    GPIO.setup(button_stop, GPIO.IN)


# 業務動作
def step_1():
    time.sleep(3)
    return True


def step_2():
    time.sleep(3)
    return True


def step_3():
    time.sleep(3)
    return True


# 復位動作組合
def run_reset():
    move_reset_list = [
        step_3,
        step_2,
        step_1
    ]
    result = True
    try:
        for func in move_reset_list:
            func_name = func.__name__
            print("正在執行: %s" % func_name)
            func_result = func()
            if not func_result:
                result = False
                break
    except:
        result = False
    finally:
        if not result:
            exit(1)
        else:
            exit(0)


# 業務動作組合
def run_step():
    result = True
    try:
        auto_cover_list = [
            step_1,
            step_2,
            step_3
        ]
        for func in auto_cover_list:
            func_name = func.__name__
            print("正在執行: %s" % func_name)
            func_result = func()
            if not func_result:
                result = False
                break
    except:
        result = False
    finally:
        if not result:
            exit(1)
        else:
            exit(0)


if __name__ == '__main__':
    # 開始工作
    init_gpio()
    while True:
        if GPIO.input(button_start) == 0:
            try:
                p_run = Process(target=run_step, daemon=True)
                p_run.start()
                # 監聽急停信號
                while p_run.is_alive():
                    if GPIO.input(button_stop) == 0:
                        p_run.terminate()
                        break
                    else:
                        time.sleep(0.1)
                if p_run.exitcode == 0 or p_run.exitcode is None:
                    print("執行成功")
                else:
                    print("執行失敗")
            except:
                print("執行失敗")
        elif GPIO.input(button_reset) == 0:
            p_reset = Process(target=run_reset, daemon=True)
            p_reset.start()
            # 監聽急停信號
            while p_reset.is_alive():
                if GPIO.input(button_stop) == 0:
                    p_reset.terminate()
                    break
                else:
                    time.sleep(0.1)
        elif GPIO.input(button_stop) == 0:
            # 急停按鈕釋放后,再釋放程序
            while True:
                if GPIO.input(button_stop) == 0:
                    time.sleep(0.1)
                else:
                    break
        else:
            time.sleep(0.1)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM