PPM信號是航模遙控器輸出的一種標準信號,從PPM信號中可以獲取7-9個通道的遙控指令數據。PPM看起來很像PWM,很多模型愛好者對于它們產生了誤解,有些朋友認為PPM和PWM就是一回事,其實不然,下面我們先說明一下它們之間的區別和關系。 PWM,是英文Pulse Width Modulation的縮寫,意思就是脈沖寬度調制。脈沖就是由高、低電平組成的信號序列,其中高電平的時間就是這里所說的脈沖寬度,也就是高電平維持的時間,單位為微秒,范圍在500-2500微秒(us)內,或0.5毫秒-2.5毫秒(ms)。如下圖所示:
這樣的一個脈沖通常用來控制一個通道,即一個舵機,如要控制多個舵機,則需要多個這樣的通道,例如:我們要控制一架固定翼模型飛機,則我們至少需要四個通道來分別控制油門、副翼、升降舵、方向舵,各個通道的脈沖寬度控制各個舵機轉動。 而PPM是英文Pulse Position Modulation的縮寫,意思是脈沖位置調制,又稱脈位調制,實質上就是將多個通道的PWM放到“一根線”上進行傳輸,一個完整的PPM信號幀包含了多個通道的PWM值,下面看一個圖解: 圖中第一個波形為PPM信號,第二個波形為一通道的PWM,它對應到PPM信號的“K1”,第三個波形為二通道的PWM,它對應到PPM信號的“K2”,依次類推,“K8”對應到第八通道的PWM。K1的前面及K8后面還有一個比較“寬”的脈沖,它的寬度大于所有通道的脈沖寬度,這個也稱為“同步脈沖”,在這樣的一幀信號中,找出信號的“頭”很關鍵,就如同在SBUS信號解析的過程中,要找到數據的開頭,才能正確的解算出各通道的數據。PPM信號“同步脈沖”就可以作為“幀頭”來使用,只要判斷一個脈沖大于通道的“正常值”,那么接下來的一個脈沖就是1通道的數據。這里要注意的是:PPM中的通道脈寬比實際的PWM脈寬要“窄一點”,這里是由于在PPM信號中需要接入脈沖間隔,以區分通道,而PPM信號幀的總長又不宜過長,因此把每個通道的脈寬“砍掉”一個同樣的寬度作為間隔,我們在計算通道PWM脈寬時還應該把這個被砍掉的部分加上。 下面開始介紹我的解算思路。很顯然,PPM信號不能像SBUS解算那樣使用串口,因為PPM就沒有“波特率”,它的實質就是一序列串在一起的脈沖,要解算它實質就是要把這些脈沖一個一個地采集進來。在Arduino中有一個專門用于采集脈沖寬度的函數:pulseIn(),這個函數可以用來完成PPM解析,但是用這個函數有一些弊端:1、它會“死等”脈沖的到來,也就是脈沖不來,它就會在那里永遠等待;2、當在執行一個脈沖的采集時,程序依然會停在那里等待采集完畢,這樣的話,整個解算過程即要等待8個通道及一個同步脈沖的總時間,加在一起是20毫秒,如果這個解算過程只是用于演示,那么我們可以接受,但如果是用于實時控制,比如四軸飛行器,這么長的采集周期勢必會讓整個控制崩潰,因此,我們必須尋找其他的解算方法。(這里舉個例子,玩過APM飛控的朋友應該知道,APM的遙控信號輸入是使用的是PWM通道獨立輸入,而采集這些信號的任務都不是有主控芯片mega2560來完成的,完成這個任務是由協處理芯片:mega32,它同時也是USB轉TTL芯片,這說明采集多路PWM確實是一個比較“繁瑣”的過程)。那么采用什么辦法來做呢? 單片機系統都有外部中斷,可以用中斷來處理這些“粘在一起”的脈沖。這次試驗用的Arduino板為:NANO板,這個板(MEGA328)使用Arduino官方庫時有兩個外部中斷:D2及D3口,試驗中使用了D2,即外部中斷0,觸發方式設置為“跳變”,即脈沖的上升沿及下降沿均觸發中斷,并在中斷處理函數中判斷觸發方式(上升沿或下降沿),然后分別記錄進入中斷的時刻(使用Arduino的時間函數:micros()),然后下降沿時刻減去上升沿時刻,即可得到一個脈沖的寬度(這個方法同樣可以用于單通道PWM的采集,或者超聲波測距)。 那么如何處理這一串脈沖呢?如何正確獲得通道PWM呢?我的方法是:連續采集20個脈沖寬度放在一個數組中,然后去數組中尋找“同步脈沖”,找到它之后,緊隨其后的8個數組元素就是我們需要的通道PWM數據。為什么一定要采集20個呢?因為我們無法確定第一次采集到脈沖是哪個通道的,除非“運氣好”,一開始就獲取到了“同步脈沖”,因此,如果我們非常“小氣”地只采集9個,幾乎不可能容易地從中找到正確完整的數據,當然也可以做一個比較細致、復雜的解算程序來完成(如果你是一個拼圖高手),而每次采集20個,則保證了每一次采集到的脈沖序列中至少包含一幀完整的數據,這樣就可以簡化解算的過程,只需要找到“同步脈沖”,然后從它之后順序取8個脈沖,其余的數據丟棄,然后進入下一輪采集。
本次試驗中使用的遙控器仍為FUTABA T10CHG,試驗中將發射模式設置為“2.4G 7CH”,就是飛模擬器使用的模式,然后用一個音頻接頭改裝連線,連接遙控器背面的PPM信號線及地線。PPM信號線連接到NANO板的D2口,地線就在NANO上找一個GND接上。 下面是中斷處理函數及通道更新函數:
程序說明:在初始化中還必須將D2端口設置為輸入模式,并且設置中斷0:attachInterrupt(0,ppm_in,CHANGE)。其中ppm_flag用于控制采集脈沖的個數,并且將這些脈沖序列按順序存放到數組ppm_date[]中;flag_in用于確保采集脈沖是從上升沿開始(因為上升沿和下降沿都會觸發中斷),它在上升沿處理中被置1,在下降沿處理中被置0,達到的目的就是在沒有采集到上升沿時不對下降沿進行處理,因為我們要采集的是高電平的時間;flag_out用于判斷是否完成了脈沖采集和是否完成了通道解算,當完成采集時它被置1,這個時候中斷函數停止數據采集,只有等通道更新完畢后,它才會被置0,中斷函數才會進行新一輪的數據采集,而在它為0的期間,也就是在數據采集的期間,不會進行通道更新。接下來從串口監視器觀察原始數據,即采集到的ppm_date[]:
上圖中,每一行數字即是完整ppm_date[]幀,從數據中可以看到,每一行都有兩個比較大的數字:大于3000,這個就是我們要找的“同步脈沖”,找到一個之后,后面跟的8個數,就是要提取的通道數據。當然,從數據中能夠看到,有時每兩個“同步脈沖”之間偶爾會出現不足8個有效數據的情況,但這個影響暫且可以接受,我們可以設計更嚴密的通道更新程序將這樣的數據幀丟棄。下面來看看1通道的數據,在試驗過程中可以保持一通道(副翼)搖桿在中立位置(所有微調歸0),此時可以看到得到的數據為1120左右,在這種情況下,該通道的實際輸出脈寬(PWM)應為1520,這個我們可以對FUTABA接收機的一通道輸出PWM進行采樣驗證,因此從ppm中獲取的數據還應該加上400,這個就是低電平的持續時間即上面提到的“被砍掉的那一部分”,當然這個時間也可以用中斷去采集ppm的低電平間隔得到。在程序中我直接給每個通道加了400,通過與之前PWM采集的數據進行對比,得出的結果是一致的。下面從串口監視器觀察解算出來的通道數據channels[],channels[0]代表1通道,副翼通道:
至此,PPM信號解析完成,從實驗中可以看出,FUTABA T10CHG的ppm輸出確實為7個比例通道,第8個通道保持在中立位。這個試驗主要是針對FUTABA T10CHG,對于其他品牌的遙控器我將進行進一步的試驗,比如6通道的SPEKTRUM DX6I遙控器的PPM輸出,也許還是有差別的吧。希望各位大神批評指正,多多指導!
|