subprocess 用法 – 【Python 學習筆記】

先前使用 Mono 執行 C# 程式,和運行 ntripclient 這類程式時,因為不熟悉 C# 語言、想開發的後續應用需要 ROS or OpevCV ( C# 不支援)、或是想保持原程式的獨立性,而不想在既有程式碼做後續開發,此時 subprocess是一個不錯的方法。

簡述

將想運行的程式 ( exe or binary )透過subprocess設定為子程序,並帶入相關參數,透過標準輸出 stdout,將子程序輸出到 Terminal 的訊息,讀取到 main 函數 / 主程序,就可以對數據做後續的開發處理,而不必修改原本的程式碼。可以達成下圖中的概念:

subprocess

官方說明:

https://docs.python.org/3/library/subprocess.html

Python 運行 C# subprocess

以 Mono 運行一支 C# exe 程式為例,將 C# 程式以subprocess運行,就可以在 Python 環境接收該程式的輸出,並做後續的應用開發,不論是想使用 ROS 或 OpenCV 等各種函式庫來處理數據都很方便。以我的經驗為例, 該 C# 程式是一個 UWB (超寬帶) 的定位系統,用這個方法我就可以把定位結果在 Python 環境下做其他開發。範例程式碼:

#import subprocess

cmd = ['mono', 'C#_Program.exe']
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

while process.poll() is None: # 表示子程序還在運行
    print(process.stdout.readline().decode("utf-8"))
print("subprocess close")
process.stdout.close()

Mono 運行 C# 程式的介紹可以參考前文:

https://mapostech.com/mono-linux/

Python 運行 C binary subprocess

以運行一支 C 的 binary 執行檔為例,範例是 ntripclient。主程式除了從 Serial port 接收 GNSS RTK 設備的 NMEA 封包以外,還建立一個執行緒 Thread 將 ntripclient 以subprocess運行。

該執行緒的作用是透過 ntripclient 接收 RTK server 傳送來的 RTCM 封包,並透過 Serial port 寫入到 GNSS RTK 設備。 Terminal 可以同時看到 ntripclient 接收的 RTCM 封包,以及設備從 Serial port 傳輸的 NMEA 封包,換言之,也可以在主程序做後續的整合開發。

import subprocess
import serial
import threading

# 定義 RTCM_sender 函數使用subprocess運行 ntripclient 接收 RTCM 封包
def RTCM_sender():
    cmd = ['./ntripclient', '-s', 'xxx.xx.xxx.xxx', '-r', '2101', '-u', 'USER', '-p', 'PASSWORDS', '-m', 'MOUNTPOINT', '-M', '3']
    process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    
    while process.poll() is None: # 表示子程序還在運行
    	rtk_data = process.stdout.readline().strip()
    	rtk_rover.write(rtk_data)
    	print(rtk_data)
    	
    print("subprocess close")
    process.stdout.close()

# 宣告 GNSS RTK 設備的 Serial port
rtk_rover = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)

# 以 Thread 執行 ntripclient
rtk_sender = threading.Thread(target = RTCM_sender)
rtk_sender.start()

# 讀取 GNSS RTK 設備的 NMEA 輸出
while True: 
    nmea_data = rtk_rover.readline().strip()
    print(nmea_data.decode('ascii'))

# 等待 ntripclient thread 結束      
rtk_sender.join()
print("Done.")

這個範例的原意是想把 RTK Server 送過的 RTCM 封包,轉送到 GNSS RTK 設備,執行 RTK 定位解算 ( GNSS RTK 設備需要 RTCM 封包執行 RTK 運算),但後來發現 ntripclient 本身就有這個功能,可以參考前文:

https://mapostech.com/linux-ntripclient/

換言之,這個範例可以簡化成像 C# 範例一樣,單純接收subprocess的輸出。只需修改subprocess的參數:

cmd = ['./ntripclient', '-s', 'xxx.xx.xxx.xxx', '-r', '2101', '-u', 'USER', '-p', 'PASSWORDS', '-m', 'MOUNTPOINT', '-M', '3', '-D', '/dev/ttyUSB', '-B', '115200', '-n', 'GNGGA']

參考資源:

連結1

連結2

上一篇:
下一篇: