2016年8月7日 星期日

arduino 解析PPM 訊號


這是在弄X9D+ 搖控器控制jj1000四軸時,因為發現四軸飛在空中時偶爾會抖一下,debug後發現問題的紀錄
http://ddddiy.blogspot.tw/2016/08/x9d-nrf24l01-v2x2-protocoljj1000.html


PPM(Pulse code Modulation mode) 訊號格式可以參考這邊
http://diydrones.com/profiles/blogs/705844:BlogPost:38393

基本上就是把PWM 訊號全部編碼整合在一個pin 上
在遙控模型的領域內,PWM 格式"一般"定義如下

  • 每個clock周期總長20ms
  • 拉high 
    • 1ms: 通道最小值
    • 1.5ms: 通道最小值
    • 2ms: 通到最大值

而PPM 內每個通道用的時間相同,只是改成時間到時瞬間拉一下high(送interrupt)
可參考網路上這張圖
https://www.google.com.tw/search?biw=1280&bih=614&tbm=isch&sa=1&q=PPM+&oq=PPM+&gs_l=img.3..0i19l10.7835.7835.0.8134.1.1.0.0.0.0.54.54.1.1.0....0...1c.1.64.img..0.1.53.DsrA7tEbXa8#imgrc=68KP1G0WoL6ovM%3A

一開始先來個脈波,之後依各通道的值對應的時間到了送出一個脈波,最後low的時間夠長,可以用來判斷一個大週期的結束

舉個例子來說,假設共四通道,各通道的值為

  • CH1: 最小值
  • CH2: 中立點
  • CH3: 中立點
  • CH4: 最大值

實際上送出的訊號如下
|上一個週期| ↑↓(1ms)↑↓(1.5ms)↑↓(1.5ms)↑↓(2ms)↑↓(明顯大於2ms的時間) |下一個週期|
所以只要用中斷抓rising edge並計算間隔後,即可知道各通道對應的值,最後剩下來的時間,長度明顯大於2ms, 當作sync 訊號來判斷此次周期已結束
照這個設計來看,20ms 可放入8通道的訊號(9通道無法分辨sync)




來看一下之前控制jj1000四軸的程式,這個project一開始是clone網路上其他玩家的project
原本的設計有一些問題
https://github.com/goebish/nrf24_multipro/

原本的code做法如下

  • setup
  • loop
    • 確認protocol, 對RF 模組做初始化與對頻
    • 從Servo_data[chan]取出目前各通道的值
  • ISR
    1. 讀出目前timer值<==可得知經過多少us
    2. reset timer
    3. 小於510us 當作雜訊,紀錄長度
    4. 大於1910當作sync
    5. 其他則是將讀出的數據加上雜訊依序填入Servo_data[chan]
這個做法沒有判斷目前PPM 訊號的high/low,每次狀態改變都會觸發中斷,會造成中斷數量增加,且以PPM設計來說拉high時間短,很有可能掉中斷(level trigger的狀況,如果轉換過快,沒有在high or low停留一段時間,比較可能會漏掉),使得干擾等因速會影響到該大週期內,每個channel 的對應
以工作的經驗來說,這類型的訊號適合用edge trigger, 搭配PPM 的設計,使用rising edge trigger較合適
實際遇到問題,通常下一個大週期就會回復正常,但飛行時就會導致四軸在空中會突然抖一下

修正成下面的做法後調整PPM判斷參數與interrupt,中斷數量可以也少一半,且實際飛行也穩定多了
  • initial
    • PPM_IN_MIN=510
    • PPM_IN_MAX=2200
  • setup
    • PPM pin 設為input
    • 註冊ISR(rising)
    • 設定timer1 每1us增加1
  • loop
    • 確認protocol, 對RF 模組做初始化與對頻
    • 從Servo_data[chan]取出目前各通道的值
  • ISR
    1. 讀出目前timer值<==可得知經過多少us
    2. reset timer
    3. 目前timer小於PPM_IN_MIN當作雜訊,紀錄長度
    4. 目前timer大於PPM_IN_MAX當作sync
    5. 其他則是將讀出的數據加上雜訊依序填入Servo_data[chan]

沒有留言:

張貼留言