錯誤處理與復原#
工業攝影機系統運作的環境中,故障不僅可能發生,甚至可說是預料之中的。與典型的桌面應用程式不同,這些系統通常會連續運行數小時甚至數天,並與外部硬體進行互動。正因如此,錯誤處理並非可有可無的選項,而是系統設計的核心環節。
常見的錯誤來源包括:
- 網路中斷,特別是在使用 GigE 攝影機時
- USB 斷開連接
- 觸發訊號缺失或不穩定
- CPU 負載過高或影像處理速度緩慢
- 頻寬限制
- 相機配置無效或取決於系統狀態
以下這些視覺化圖表說明了為何錯誤處理如此重要:
若未妥善處理:
若操作得當:
目標並非要防止所有可能發生的失敗。目標是讓失敗變得可見、可控且可恢復。
pypylon 中的錯誤類型#
不同的錯誤類型需要採取不同的處理策略。
擷取錯誤#
抓取錯誤表示雖然已傳回抓取結果,但影像本身卻無效。
with camera.RetrieveResult(2000) as grab_result:
if grab_result.GrabSucceeded():
image = grab_result.Array
else:
print(grab_result.ErrorCode)
print(grab_result.ErrorDescription)
常見原因:
- GigE 連線期間的封包遺失
- 頻寬不足
- 臨時性的傳輸層問題
- 攝影機或駕駛的不穩定性
此類錯誤通常僅影響單一幀。應用程式通常可將此問題記錄在日誌中,跳過該幀,並繼續進行擷取。
超時錯誤#
在以下情況下發生超時: RetrieveResult() 等待一張圖片,但在設定的超時時間內未收到任何圖片。
with camera.RetrieveResult(
1000,
pylon.TimeoutHandling_ThrowException
) as grab_result:
image = grab_result.Array
常見原因:
- 觸發模式已啟用,但未接收到觸發訊號
- 攝影機無法擷取畫面
- 曝光時間比預期更長
- 超時值過短
- 相機設定不一致
超時現象在觸發式系統中尤其常見。超時並不一定代表攝影機故障,通常只是表示應用程式正在等待一個從未發生的事件。
執行時期例外#
執行時例外表示問題超出單一幀的擷取範圍。
例如:
- 相機已拔除電源線
- 網路連線中斷
- 裝置重設
- 相機狀態無效
- 參數存取無效
這些錯誤通常需要執行復原邏輯,例如停止擷取、等待、重新枚舉攝影機,或重新開啟裝置。
錯誤處理策略#
一個穩健的系統通常會結合多種策略。
每幀處理#
當攝影機仍在運作,但個別畫面可能出現錯誤時,請使用此功能。
with camera.RetrieveResult(2000) as grab_result:
if grab_result.GrabSucceeded():
process(grab_result.Array)
else:
log_error(grab_result.ErrorDescription)
當偶發性的幀丟失尚可接受時,此方法便相當實用。它能維持擷取迴路的運作,並避免因單張不良影像而導致整個系統停止運作。
典型使用案例:
- 即時顯示
- 監測系統
- 非關鍵影像串流
例外處理#
使用 try/except 針對可能在執行時發生失敗的操作。
try:
with camera.RetrieveResult(
2000,
pylon.TimeoutHandling_ThrowException
) as grab_result:
if grab_result.GrabSucceeded():
process(grab_result.Array)
except Exception as e:
print("Error:", e)
這可防止應用程式立即當機。然而,僅僅擷取例外並不足夠。應用程式還必須決定是要繼續執行、重新嘗試、重置獲取,還是安全關機。
復原迴圈模式#
復原迴圈結合了錯誤偵測與自動復原功能。以下程式碼範例展示了建構復原迴圈的建議模式。
import time
with pylon.InstantCamera(pylon.FirstFound) as camera:
while True:
try:
if not camera.IsGrabbing():
camera.StartGrabbing()
with camera.RetrieveResult(
2000,
pylon.TimeoutHandling_ThrowException
) as grab_result:
if grab_result.GrabSucceeded():
image = grab_result.Array
process(image)
else:
log_error(grab_result.ErrorDescription)
except Exception as e:
log_error(f"Acquisition error: {e}")
if camera.IsGrabbing():
camera.StopGrabbing()
time.sleep(0.5)
以下是使用復原迴路時的操作流程:
- 擷取程序運作正常。
- 發生錯誤。
- 觸發了一個例外。
- 例外處理程式會將問題記錄至日誌中。
StopGrabbing()重置擷取流程。- 應用程式會短暫等待。
- 該迴圈會重新嘗試進行擷取。
此模式可讓系統在無需人工干預的情況下,從暫時性故障中恢復。
發生擷取錯誤後,內部緩衝區或擷取狀態可能不再能代表一個完整的擷取管線。
這就是為什麼要呼叫 StopGrabbing() 是恢復循環中不可或缺的一部分。它有助於達成以下目標:
- 停止當前的擷取操作
- 釋放或回收內部緩衝區
- 讓相機進行乾淨重啟的準備工作
雖然這無法解決所有可能發生的硬體故障,但這通常是第一個安全的復原步驟。
相機斷開連接的處理方式#
物理斷開是現實世界中最常見的故障情況之一。
一個穩健的應用程式應預設硬體可能在任何時候消失。
此處展示了一個典型的恢復流程:
Detect error
↓
Stop acquisition
↓
Wait briefly
↓
Re-enumerate cameras if needed
↓
Reconnect or report fatal failure
對於生產系統而言,重新連線邏輯通常是在比基本抓取迴圈更高的層級上實現的。
資源安全#
要 with 對於抓取結果而言,這點至關重要。
這可確保即使在該區塊內發生例外情況,抓取結果仍會被釋放。
若未進行適當的善後處理,收購案可能會陷入停滯:
這就是為什麼本指南中的所有範例都使用上下文管理器來擷取結果。
使用日誌記錄取代列印#
舉例來說, print() 既簡單又易讀。在生產環境中,使用 Python logging 建議使用模組。
記錄功能可為長期運行的系統提供時間戳記、嚴重性等級、持久化檔案,以及更完善的診斷功能。
可恢復錯誤與致命錯誤#
並非所有錯誤都應以相同的方式處理。
| 錯誤 | 典型處理方式 |
|---|---|
| 單一幀失敗 | 登入並繼續 |
| 觸發模式下的超時 | 請檢查觸發器設定或重新嘗試 |
| 暫時性的頻寬問題 | 記錄、減少負載、繼續 |
| 相機已斷開連接 | 停止、重新枚舉、重新連線 |
| 啟動時缺少必要的攝影機 | 盡早失敗 |
| 設定無效 | 停止並回報錯誤 |
生產環境中的應用程式應明確區分可重試的錯誤與需要操作員介入的錯誤。
重點摘要#
- 在工業環境中,發生錯誤是常有的事。
- 同時處理框架層級的錯誤與系統層級的例外狀況。
- 請考慮使用超時機制,並設定適當的超時時間。
- 使用
with以確保資源得以清理。 - 針對無人值守系統實作復原迴圈。
- 在生產環境中使用日誌記錄功能,並明確分類錯誤。
一套設計完善的錯誤處理策略,能確保攝影機應用程式的穩定運作與自主性。