四軸飛行器1.8 通訊協議擬定、協議驗證與飛控輸出驗證


原創文章,歡迎轉載,轉載請注明出處。

        上個周末其實通訊協議就已經擬定完成了,這一個星期主要成了通訊協議的解析,然后通過通訊協議的實現,加入遙控器的控制和飛控信息的傳遞,從飛控傳到遙控器,再從遙控器傳到電腦上,通過matlab現實姿態信息和電機輸出控制信息。這章會一步一步介紹實現的過程。

1:遙控和飛控之間的通訊。

2:通訊協議的擬定。

3:通訊協議的實現與解析。

4:通過遙控控制飛控並且飛控姿態通過nrf上傳數據。

  

先上通過遙控控制飛控並且飛控姿態通過nrf上傳數據的視頻哈,看看效果,解釋在后面;

視頻地址http://v.youku.com/v_show/id_XNzg3NjcwMDc2.html

 

 

1:遙控和飛控之間的通訊

      有了上章的環形緩沖和通訊的基礎,現在就驗證下環形緩沖和通訊結合起來的工作效果。

      有了環形緩沖,我們實現發送和接收就比較簡單了,需要發送數據的時候,我們只要把數據push到緩沖里面,接收數據的時候在接受中斷了里將數據push進緩沖。我們有一個專門通訊管理的task,用來判斷緩沖里面是否有數據,如果發送緩沖里面有數據,就讀取數據,發送,發送后然后將數據pop,如果接收緩沖里面有數據,就讀取數據,並且根據協議解析,然后pop。

    根據上面的說明,我們在遙控上面發送數據,然后飛控接到數據后會返回數據給遙控,如此往復。。具體通訊效果如下圖。

上圖左邊是遙控器的串口輸出信息,右邊是飛控輸出的信息。圖中txds為收到ACK包,txed為發送完成,rxed為接受完成,trmax為重試了設定的次數還沒收到ACK包,意味着發送失敗。發送失敗的還是有的哈,不過暫時沒有做發送失敗的處理,也沒有判斷。。我們可以失敗了不pop,稍微等待個幾毫秒再試着發送一次。。

2:通訊協議的擬定

     通訊協議需要簡單,盡量少的數據傳輸盡量多的信息。。。

     首先我們將協議進行了分類,分為控制類,查詢類,和主動上報類,一共三類,所以需要占用2位,一個字節里面占2位后還有6位,有64種組合,目前看應該夠我們用了,然后后面就是根據各個命令來傳輸數據了。協議大致如下圖:

 

根據協議我們定義了如下結構體:

 1 typedef union
 2 {
 3     u8                         mode;                    //飛行模式的mode參數
 4     Com_Att_t               Att;                    //姿態信息
 5     u32                        Height;                    //高度參數
 6     Com_PID_t                Pid;                    //PID信息                
 7     u8                       RetPara;                //返回信息
 8     Com_Sensor_t            Sensor;                    //傳感器數據
 9     u8                        Battery;                //電池電量
10 }Comm_Para_tu;
11 
12 typedef struct
13 {
14     u8                        Command:6;                //0~5位為命令
15     u8                        ComType:2;                //6~7位為命令類型
16 }Order_t;
17 
18 
19 typedef struct
20 {
21     u8                       Len;                    //數據長度
22     Order_t                 Order;                //命令類型
23     Comm_Para_tu            Para;                    //參數
24 }Comm_Data_ts;

Comm_Data_ts是我們通訊用到的結構體,根據協議,里面有數據長度,然后有命令類型和對應的命令,后面就跟着參數。發送數據只需要對這個結構體賦值,接收數據后解析只需要根據這個機構體的Order找到對應的命令,然后根據對應的參數讀取數據就好了,這樣在上層操作的時候,我們不需要管通訊協議的哪個字節存什么數據,只需要對結構體進行操作。

 

3:通訊協議的實現與解析

   為了方便代碼的實現,我們對每個命令寫了一個解析函數。那我們是怎樣找到這個函數的呢?雖然我們可以按照命令的排序做一個指向函數的指針數組,調用的時候根據命令就可以直接調用,而且速度非常快,但是這樣並不利於我們后期的維護,不能根據后期協議的更改方便的添加和刪除命令,所以我們棄用那種方法。而是創建一個結構體,里面有命令和命令對應的處理函數的函數指針,我們只需要進行命令匹配,匹配好后,就調用對應的函數指針調用對應的函數,這樣就完成了解析。

結構體如下:

 1 /*命令回調結構*/
 2 typedef struct
 3 {
 4     void (*Comm_CallBack)(Comm_Data_ts *msg);
 5     u8                 command;
 6 } SubComm_Fun;
 7 
 8 
 9 typedef struct
10 {
11     const SubComm_Fun         *SubComm;        //指向子命令
12     u8                         ComType;        //命令類型
13     u8                        Len;            //子命令個數,優化搜索時間
14 } Comm_Fun;

因為我們命令分兩層,所以先對命令類型解析,然后搜索下一層命令,然后再運行對應的函數指針,打個比方,上面結構體的部分初始化如下:

 1 //查詢類命令於對應函數定義
 2 //注意,一定要注意,一定要修改FLY_QUERY_FUN_LEN宏定義
 3 const SubComm_Fun Fly_Query_Fun[]=
 4 {
 5     {
 6         Fly_Query_Sensor,
 7         FLY_QUERY_SENSOR
 8     },
 9     
10     {
11         Fly_Query_Attitude,
12         FLY_QUERY_ATTITUDE
13     },
14 
15     {
16         Fly_Query_System_Sta,
17         FLY_QUERY_SYSTEM_STA
18     },
19 
20     {
21         Fly_Query_Battery,
22         FLY_QUERY_BATTERY
23     },
24 };
25 #define FLY_QUERY_FUN_LEN    4
26 
27 
28 //命令類型對子命令數定義
29 //注意,一定要注意,一定要修改Comm_Fun_Len宏定義
30 const Comm_Fun Fly_Fun[]=
31 {
32     {
33         Fly_Ctrl_Fun,
34         FLY_CTRL,
35         FLY_CTRL_FUN_LEN
36     },
37     
38     {
39         Fly_Query_Fun,
40         FLY_QUERY,
41         FLY_QUERY_FUN_LEN
42     },
43     
44     {
45         Fly_Report_Fun,
46         FLY_REPORT,
47         FLY_REPORT_FUN_LEN
48     },
49 };

初始化上面的機構體后,我們就根據命令來解析,解析代碼如下:

 1 void Comm_Decode(Comm_Data_ts *msg)
 2 {
 3     u8 i,k;
 4     
 5     for(i = 0 ; i < COMM_FUN_LEN; i++)
 6     {
 7         /*查詢消息命令*/
 8         if(msg->Order.ComType == Fly_Fun[i].ComType)
 9         {
10             for(k = 0 ;k < Fly_Fun[i].Len; k++)
11             {
12                 if(Fly_Fun[i].SubComm[k].command == msg->Order.Command)
13                 {
14                     Fly_Fun[i].SubComm[k].Comm_CallBack(msg);
15                     break;
16                 }
17             }
18             break;
19         }
20                         
21     }
22 
23 }

這樣一是代碼重用率很高,而且增加和刪減命令很簡單。不過我們可以將命令類型改成枚舉類型,可以避免出現錯誤的命令可能。

解析的效果如下圖:

上圖左邊為遙控器的nrf的debug信息,右邊為遙控器接收到數據后的解析的debug信息。遙控器通過手柄的及格按鍵發送不同的命令進行測試,通過實際觀察,運行良好。

4:通過遙控控制飛控並且飛控姿態通過nrf上傳數據

   將上面功能全部結合起來,同時實現無線姿態采集,都是通過協議實現的。

   先說明下我們的運行方式:飛控定時給遙控器發送傳感器信息和姿態信息,遙控通過串口發給matlab,並且進行實時現實。這里我們上傳的信息添加了電機的控制信息,包括總油門和每個電機的單獨油門,通過這個我們可以觀察飛控對槳的操作邏輯是否正確。同時遙控可以發送遙控命令,命令飛控的目標姿態。效果圖圖下:

左邊的柱狀圖12345分別為moto1,moto2,moto3,moto4和油門。

電機位置示意如下:

 

字很丑哈,隨便畫的當時,看不太明白的可以到如下網址看,電機的方位和角度的定義有點不同哈,但是原理是一樣的。

網址:http://bbs.21ic.com/icview-605405-1-1.html

最后聯機測試的視頻見頂端,通過測試,電機輸出邏輯正常,放心了哈。。后面加電調控制進去,調下PID,應該可以飛了。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM