天天看點

用jxTMS開發智能轉運箱(2)

本系列以開發管控類危化品的智能轉運箱為例講述了jxTMS的智能硬體支援下的業務管控體系:

用jxTMS開發智能轉運箱(1)

jxTMS目前已打包為docker容器,可以下拉jxTMS的docker鏡像并按jxTMS使用示例嘗試使用。

裝置

在jxTMS的智能控制體系中,所有的裝置都是用go實作的。其實作層次如下:

用jxTMS開發智能轉運箱(2)

即所有的智能硬體都統一抽象為Dev的接口,python代碼根據這個抽象統一對所有前端裝置的讀取、操作與控制。這樣,一個裝置在python主代碼中隻要簡單的聲明即可:

#智能轉運箱中用于控制電鎖、訓示燈、高音警号的Modbus裝置
devBoxControl = jxGoDev('modbus','boxControl')
           

也就是說:一個裝置就是一個jxGoDev類的對象,隻要在初始化時指定裝置類型和裝置名即可。

目前已實作的裝置類型包括:

  • timer:定時器,一次性或可重複的間隔指定秒數後觸發事件
  • cron:unix中cron格式的定時器,按cron格式在符合指定格式的時間點,觸發事件
  • local:本地裝置,将輸入直接饋送到輸出,主要用途一是在開發測試階段用本地裝置旁路掉具體的硬體以防止邏輯錯誤導緻損失,同時提高開發測試的效率;二是将使用者指令轉換為裝置的輸入輸出,進而統一邏輯部件的事件機制
  • modbus:modbus裝置,同時支援rtu、tcp等連接配接方式,以及DIDO【數字型輸入輸出子產品】類型等
  • pi:樹莓派的各管腳,目前包括gpio的輸入輸出和pwd

注:目前的jxTMS的智能控制都是對實時性要求不高的安防、環控等弱電系統的控制,這樣的控制系統系統開銷極低,而目前卡片式計算機性能更新很快,是以暫不考慮對實時性的要求

裝置配置

jxTMS的智能硬體抽象,本質上就是四種能力的集合:輸入、動作、配置、設定。

輸入顯然就是從裝置讀取資料,而動作、配置、設定其實都是向裝置寫資料,但這三者在邏輯上是有着明顯的差別的:

  • 動作是系統指令裝置指定輸出【直接對外部産生作用】,設定則是系統指令裝置對其自身進行調整【間接的影響到外部】
  • 配置是裝置使用前對裝置進行初始化,設定則是在裝置運作中對裝置進行調整

智能硬體的配置同樣采取了jxTMS中的文本定義的方式,例如上面聲明的devBoxControl裝置的配置是:

@devBoxControl.config(vl=localConfig)
def devBoxControlConfig(self):
	'''
	rtu DIDO dev='{rtuDev}',addr={busNo},baudRate={baudRate},readInterval={readInterval},readNum={readNum},writeNum={writeNum};
	'''
	pass
           

即用前面所定義的modbus類型的jxGoDev對象的config函數來修飾devBoxControlConfig,其實就是用定義在該函數的__doc__中的配置文本來執行初始化。

其中的vl是用于關聯一個用于歸攏配置參數的局部變量:

localConfig = {
	#轉運逾時時鐘逾時時間,秒
	'transTimeover_interval' : '3600',
	#四路輸入輸出裝置的master裝置名
	'rtuDev' : '/dev/ttyUSB0',
	#四路輸入輸出裝置的總線位址
	'busNo' : '1',
	#rtu的波特率
	'baudRate' : '9600',
	#輪詢讀的間隔,毫秒
	'readInterval' : '500',
	#輸入端口數
	'readNum' : '4',
	#輸出線圈數
	'writeNum' : '4',
	#門狀态
	'input_doorState' : '0',
	#門鎖
	'output_door' : '0',
	#喇叭
	'output_horn' : '1',
	#綠燈
	'output_Green' : '2',
	#黃燈
	'output_Yellow' : '3'
}
           

是以devBoxControl也可按如下的形式進行配置:

@devBoxControl.config(vl=None)
def devBoxControlConfig(self):
	'''
	rtu DIDO dev='/dev/ttyUSB0',addr=1,baudRate=9600,readInterval=500,readNum=4,writeNum=4;
	'''
	pass
           

這兩種形式在功能上沒有差別,隻是第一種形式将所有的配置參數集中了起來,如果對裝置比較熟悉,則在裝置定義好後,就不再需要查找定義配置代碼,在調試時較為便利;而第二種形式則是看到代碼就可知道裝置的具體定義,這樣在裝置較多的時候,就非常直覺。即第一種形式側重于調試,尤其是多種裝置的聯合調試;第二種形式則側重于代碼了解,讓代碼閱讀起來更為直覺。

程式設計模型

輸入是從裝置的某輸入端口,讀取一個值。通常的處理方法是直接讀,然後對讀到的值處理條件判斷來調用對應的處理函數。但這種處理方式把應用邏輯和程式設計邏輯混在了一起,對開發者的要求較高,程式品質依賴于開發者的技術水準。

是以jxTMS采取的是三層處理模型:

  • 輸入層,用文本化的條件等式将輸入識别為事件
  • 邏輯層,go中預定義好的、功能強大的、可靠而穩定的邏輯部件,使用者用易于了解的文本來描述控制邏輯,兩者相結合就成為高度穩定、可靠的、定制的控制器
  • 執行層,使用者用python編寫的控制動作

也就是說,jxTMS的智能控制程式設計模型是:

用jxTMS開發智能轉運箱(2)

即邏輯部件加載描述控制邏輯的文本成為滿足使用者需要的特定的控制器,輸入被條件識别為事件,事件驅動控制器工作來篩選符合控制邏輯的動作加以執行。

這樣一來,開發者所做的事情就分為了三個部分:

1、輸入轉換為事件,如:

event local eNextTask from 'local.stateMgr:cmd' == 'nextTask' ;
           

意為:當本地輸入【local.stateMgr:cmd】的值是【nextTask】時,識别為事件eNextTask。

注:事件的識别一般都是邏輯部件的一部分,是以這一布其實是合并到邏輯部件的控件邏輯描述中的

2、控制邏輯描述。詳見第三部分

3、動作程式設計。具體的控制動作,利用python豐富的而可靠的第三方庫來大幅度提高代碼品質、提高開發速度。如智能轉運箱中實作掃描藍牙、測距以識别是否進入到安全區中:

def _beaconScan(self):
	while self.scanBT:
		#反複掃描藍牙基站
		bs = BeaconService()
		devices = bs.scan(3)
		self._log('my uuid:{}/rssi:{}'.format(self.uuid,self.rssi))
		for address, data in list(devices.items()):
			self._log('scan uuid:{}/rssi:{}'.format(data[0],data[4]))
			#掃描到目的基站且基站的rssi強于指定值
			if data[0] == self.uuid  and self.rssi <= data[4]:
				#判定和目标基站的距離接近到足夠近的距離
				self.event('scanBT')
				return
		time.sleep(10)
           

由于實作控制邏輯的邏輯部件是預先實作、良好測試過的通用化工具,是以系統的穩定性與可靠性大幅度的提升;同時各動作被邏輯部件所分割隻需程式設計實作非常明确的動作要求,是以代碼的複雜度顯著下降,代碼的開發成本自然也會顯著下降。

此外,控制邏輯不是用代碼來實作的,而是用符合文法要求的文本進行描述,這樣就可以避免由不熟悉控制需要的代碼開發人員來開發控制邏輯,而是由更熟悉現場、熟悉業務、熟悉需求的人來讨論恰當的控制邏輯。是以控制邏輯會更符合實際情況與需求、更全面、更可行。

依據這一思路,jxTMS中的輸入到事件的轉換過程是:

  • 輪詢讀【如modbus設定】或觸發讀【支援硬體讀事件的裝置,如jxTMS所實作的時鐘裝置、本地裝置等】
  • 将讀到的值依次發送給注冊到該端口上的監聽器
  • 各監聽器用注冊時給定的條件表達式對該值進行判斷,使得條件表達式結果為真的,或未指定表達式的,識别為觸發
  • 監聽器觸發,則廣播一個注冊該監聽器時關聯的事件并輸入值;為觸發則丢棄
  • 對此事件感興趣的控制器,監聽該事件,接收到此事件廣播後送入邏輯部件中,根據邏輯部件的目前邏輯,如需動作則執行相應的動作

上述過程的主體都為jxTMS實作,使用者需要做的是:

  • 根據需要定義條件表達式來篩選合适的輸入值
  • 定義接收事件的控制邏輯描述
  • 對要執行的動作進行程式設計

進而大大減少了對程式設計的需要,可以讓更大的人員參與到開發中來,同時動作程式設計部分也較為單一且要求明确,這同樣也降低了對程式設計的需要。