這是在弄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做法如下
- PPM pin 設為input
- 註冊ISR(CHANGE)
- 設定timer1 每1us增加1
- arduino timer 0 已經被內建的delay/sleep...使用,用了會打亂原本的功能,所以要用timer 1
- timer的部分可參考
- 確認protocol, 對RF 模組做初始化與對頻
- 從Servo_data[chan]取出目前各通道的值
- 讀出目前timer值<==可得知經過多少us
- reset timer
- 小於510us 當作雜訊,紀錄長度
- 大於1910當作sync
- 其他則是將讀出的數據加上雜訊依序填入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
- 確認protocol, 對RF 模組做初始化與對頻
- 從Servo_data[chan]取出目前各通道的值
- 讀出目前timer值<==可得知經過多少us
- reset timer
- 目前timer小於PPM_IN_MIN當作雜訊,紀錄長度
- 目前timer大於PPM_IN_MAX當作sync
- 其他則是將讀出的數據加上雜訊依序填入Servo_data[chan]