匿名四軸地面站V4.5使用方法研究

匿名四軸作爲一個玩四軸的人必備入門級工具,匿名地面站簡直好用的一批,這裏有匿名科創對他們的地面站的介紹和下載方法,匿名視頻。可謂功能相當強大,使用起來及其方便,大家如果想獲得資源可以直接從網上尋找下載,本文主要對匿名地面站4.50版本進行協議解析,讓大家理解相關的通訊協議,便於使用先進的資源進行小四軸的調試使用。

地面站相關協議解析

所謂的通訊協議,說白了就是一個暗號,你要和地面站進行通訊,就要按照地面站制定的規則進行通訊,首先要先向地面站彙報統一暗號(0xaaa)然後是你來的任務(編碼位)有多少東西(數據位長度),你帶來的東西(想要傳輸的數據),最終確認(校驗值)。大家只需要按照這個已經約定好的暗號和地面站通訊,他就能理解我們帶來了什麼,同樣地面站也會以另一種格式傳輸給我們相關的指令但是基本類似,只需要按照約定好的內容對傳來的指令進行解析就能得到相應的數據。

數據傳輸指令

/////////////////////////////////////////////////////////////////////////////////////
//Data_Exchange函數處理各種數據發送請求,比如想實現每5ms發送一次傳感器數據至上位機,即在此函數內實現
void ANO_DT_Data_Exchange(void)
{
    static u8 cnt = 0;
    static u8 senser_cnt    = 10;
    static u8 status_cnt    = 15;
    static u8 rcdata_cnt    = 20;
    static u8 motopwm_cnt   = 20;
    static u8 power_cnt     =   50;
    
    if((cnt % senser_cnt) == (senser_cnt-1))
        f.send_senser = 1;  

    if((cnt % status_cnt) == (status_cnt-1))
        f.send_status = 1;  
    
    if((cnt % rcdata_cnt) == (rcdata_cnt-1))
        f.send_rcdata = 1;  
    
    if((cnt % motopwm_cnt) == (motopwm_cnt-1))
        f.send_motopwm = 1; 
    
    if((cnt % power_cnt) == (power_cnt-1))
        f.send_power = 1;       
    
    cnt++;
/////////////////////////////////////////////////////////////////////////////////////
    if(f.send_version)
    {
        f.send_version = 0;
        ANO_DT_Send_Version(4,300,100,400,0);
    }
/////////////////////////////////////////////////////////////////////////////////////
    else if(f.send_status)
    {
        f.send_status = 0;
        ANO_DT_Send_Status(Roll,Pitch,Yaw,baroAlt,0,fly_ready);
    }   
/////////////////////////////////////////////////////////////////////////////////////
    else if(f.send_senser)
    {
        f.send_senser = 0;
        ANO_DT_Send_Senser(mpu6050.Acc.x,mpu6050.Acc.y,mpu6050.Acc.z, mpu6050.Gyro.x,mpu6050.Gyro.y,mpu6050.Gyro.z,ak8975.Mag_Adc.x,ak8975.Mag_Adc.y,ak8975.Mag_Adc.z,0);
    }   
/////////////////////////////////////////////////////////////////////////////////////
    else if(f.send_rcdata)
    {
        f.send_rcdata = 0;
        ANO_DT_Send_RCData(Rc_Pwm_In[0],Rc_Pwm_In[1],Rc_Pwm_In[2],Rc_Pwm_In[3],Rc_Pwm_In[4],Rc_Pwm_In[5],Rc_Pwm_In[6],Rc_Pwm_In[7],0,0);
    }   
/////////////////////////////////////////////////////////////////////////////////////   
    else if(f.send_motopwm)
    {
        f.send_motopwm = 0;
        ANO_DT_Send_MotoPWM(1,2,3,4,5,6,7,8);
    }   
/////////////////////////////////////////////////////////////////////////////////////
    else if(f.send_power)
    {
        f.send_power = 0;
        ANO_DT_Send_Power(123,456);
    }
/////////////////////////////////////////////////////////////////////////////////////
    else if(f.send_pid1)
    {
        f.send_pid1 = 0;
        ANO_DT_Send_PID(1,ctrl_1.PID[PIDROLL].kp,ctrl_1.PID[PIDROLL].ki,ctrl_1.PID[PIDROLL].kd,ctrl_1.PID[PIDPITCH].kp,ctrl_1.PID[PIDPITCH].ki,ctrl_1.PID[PIDPITCH].kd,ctrl_1.PID[PIDYAW].kp,ctrl_1.PID[PIDYAW].ki,ctrl_1.PID[PIDYAW].kd);
    }   
/////////////////////////////////////////////////////////////////////////////////////
    else if(f.send_pid2)
    {
        f.send_pid2 = 0;
        ANO_DT_Send_PID(2,ctrl_1.PID[PID4].kp,ctrl_1.PID[PID4].ki,ctrl_1.PID[PID4].kd,ctrl_1.PID[PID5].kp,ctrl_1.PID[PID5].ki,ctrl_1.PID[PID5].kd, ctrl_1.PID[PID6].kp,ctrl_1.PID[PID6].ki,ctrl_1.PID[PID6].kd);
    }
/////////////////////////////////////////////////////////////////////////////////////
    else if(f.send_pid3)
    {
        f.send_pid3 = 0;
        ANO_DT_Send_PID(3,ctrl_2.PID[PIDROLL].kp,ctrl_2.PID[PIDROLL].ki,ctrl_2.PID[PIDROLL].kd,ctrl_2.PID[PIDPITCH].kp,ctrl_2.PID[PIDPITCH].ki,ctrl_2.PID[PIDPITCH].kd,ctrl_2.PID[PIDYAW].kp,ctrl_2.PID[PIDYAW].ki,ctrl_2.PID[PIDYAW].kd);
    }
/////////////////////////////////////////////////////////////////////////////////////
}

這個函數執行的功能其實就是判斷一下我多久該發一次數據,有些數據比較重要(比如姿態信息)需要經常傳輸一下,有些相對而言更新慢一點沒有太大問題(比如電壓),而有一些只需要等待接收到發送指令以後再發送就OK(比如PID信息),然後得到相應的命令以後將數據按照約定的格式傳輸給上位機。

數據傳輸

    void ANO_DT_Send_Power(u16 votage, u16 current)
{
    u8 _cnt=0;
    u16 temp;
    
    data_to_send[_cnt++]=0xAA;
    data_to_send[_cnt++]=0xAA;
    data_to_send[_cnt++]=0x05;
    data_to_send[_cnt++]=0;
    
    temp = votage;
    data_to_send[_cnt++]=BYTE1(temp);
    data_to_send[_cnt++]=BYTE0(temp);
    temp = current;
    data_to_send[_cnt++]=BYTE1(temp);
    data_to_send[_cnt++]=BYTE0(temp);
    
    data_to_send[3] = _cnt-4;
    
    u8 sum = 0;
    for(u8 i=0;i<_cnt;i++)
        sum += data_to_send[i];
    
    data_to_send[_cnt++]=sum;
    
    ANO_DT_Send_Data(data_to_send, _cnt);
}

這個是傳輸電壓和電源的傳輸協議,協議內容也是按照前面已經規定的格式進行傳輸的,發送幀頭,功能碼,數據內容,校驗值等相關的內容。函數任務就是將這些信息都整合到一個數組裏面,然後將相關的內容通過使用的數據傳輸方式進行數據傳輸。傳輸其他的內容乃至高級數據都是通過類似的方式完成的。在此不多做介紹。

傳輸方式定義並傳輸
void ANO_DT_Send_Data(u8 *dataToSend , u8 length)
{
#ifdef ANO_DT_USE_USB_HID
    Usb_Hid_Adddata(data_to_send,length);
#endif
#ifdef ANO_DT_USE_USART2
    Usart2_Send(data_to_send, length);
#endif
}

這個其實就是一個傳輸函數,前面兩個函數已經確定了數據格式,這裏只需要根據相關的東西進行數據傳輸,傳輸格式可以根據自己方便進行選擇,比如USB,或者串口模塊等等。

接收數據解析
void ANO_DT_Data_Receive_Prepare(u8 data)
{
    static u8 RxBuffer[50];
    static u8 _data_len = 0,_data_cnt = 0;
    static u8 state = 0;
    
    if(state==0&&data==0xAA)
    {
        state=1;
        RxBuffer[0]=data;
    }
    else if(state==1&&data==0xAF)
    {
        state=2;
        RxBuffer[1]=data;
    }
    else if(state==2&&data<0XF1)
    {
        state=3;
        RxBuffer[2]=data;
    }
    else if(state==3&&data<50)
    {
        state = 4;
        RxBuffer[3]=data;
        _data_len = data;
        _data_cnt = 0;
    }
    else if(state==4&&_data_len>0)
    {
        _data_len--;
        RxBuffer[4+_data_cnt++]=data;
        if(_data_len==0)
            state = 5;
    }
    else if(state==5)
    {
        state = 0;
        RxBuffer[4+_data_cnt]=data;
        ANO_DT_Data_Receive_Anl(RxBuffer,_data_cnt+5);
    }
    else
        state = 0;
}

首先將接收到的數據進行解析,解析主要是一位一位進行解析,層層遞進,將解析得到的數據傳過來,和相應的協議進行對比,如果正確就將數據傳輸到下一個模塊

數據賦值
void ANO_DT_Data_Receive_Anl(u8 *data_buf,u8 num)
{
    u8 sum = 0;
    for(u8 i=0;i<(num-1);i++)
        sum += *(data_buf+i);
    if(!(sum==*(data_buf+num-1)))       return;     //判斷sum
    if(!(*(data_buf)==0xAA && *(data_buf+1)==0xAF))     return;     //判斷幀頭
    
    if(*(data_buf+2)==0X01)
    {
        if(*(data_buf+4)==0X01)
            mpu6050.Acc_CALIBRATE = 1;
        if(*(data_buf+4)==0X02)
            mpu6050.Gyro_CALIBRATE = 1;
        if(*(data_buf+4)==0X03)
        {
            mpu6050.Acc_CALIBRATE = 1;      
            mpu6050.Gyro_CALIBRATE = 1;         
        }
    }
    
    if(*(data_buf+2)==0X02)
    {
        if(*(data_buf+4)==0X01)
        {
            f.send_pid1 = 1;
            f.send_pid2 = 1;
            f.send_pid3 = 1;
            f.send_pid4 = 1;
            f.send_pid5 = 1;
            f.send_pid6 = 1;
        }
        if(*(data_buf+4)==0X02)
        {
            
        }
        if(*(data_buf+4)==0XA0)     //讀取版本信息
        {
            f.send_version = 1;
        }
        if(*(data_buf+4)==0XA1)     //恢復默認參數
        {
            Para_ResetToFactorySetup();
        }
    }

    if(*(data_buf+2)==0X10)                             //PID1
    {
        ctrl_1.PID[PIDROLL].kp  = 0.001*( (vs16)(*(data_buf+4)<<8)|*(data_buf+5) );
        ctrl_1.PID[PIDROLL].ki  = 0.001*( (vs16)(*(data_buf+6)<<8)|*(data_buf+7) );
        ctrl_1.PID[PIDROLL].kd  = 0.001*( (vs16)(*(data_buf+8)<<8)|*(data_buf+9) );
        ctrl_1.PID[PIDPITCH].kp = 0.001*( (vs16)(*(data_buf+10)<<8)|*(data_buf+11) );
        ctrl_1.PID[PIDPITCH].ki = 0.001*( (vs16)(*(data_buf+12)<<8)|*(data_buf+13) );
        ctrl_1.PID[PIDPITCH].kd = 0.001*( (vs16)(*(data_buf+14)<<8)|*(data_buf+15) );
        ctrl_1.PID[PIDYAW].kp   = 0.001*( (vs16)(*(data_buf+16)<<8)|*(data_buf+17) );
        ctrl_1.PID[PIDYAW].ki   = 0.001*( (vs16)(*(data_buf+18)<<8)|*(data_buf+19) );
        ctrl_1.PID[PIDYAW].kd   = 0.001*( (vs16)(*(data_buf+20)<<8)|*(data_buf+21) );
        ANO_DT_Send_Check(*(data_buf+2),sum);
                Param_SavePID();
    }
    if(*(data_buf+2)==0X11)                             //PID2
    {
        ctrl_1.PID[PID4].kp     = 0.001*( (vs16)(*(data_buf+4)<<8)|*(data_buf+5) );
        ctrl_1.PID[PID4].ki     = 0.001*( (vs16)(*(data_buf+6)<<8)|*(data_buf+7) );
        ctrl_1.PID[PID4].kd     = 0.001*( (vs16)(*(data_buf+8)<<8)|*(data_buf+9) );
        ctrl_1.PID[PID5].kp     = 0.001*( (vs16)(*(data_buf+10)<<8)|*(data_buf+11) );
        ctrl_1.PID[PID5].ki     = 0.001*( (vs16)(*(data_buf+12)<<8)|*(data_buf+13) );
        ctrl_1.PID[PID5].kd     = 0.001*( (vs16)(*(data_buf+14)<<8)|*(data_buf+15) );
        ctrl_1.PID[PID6].kp   = 0.001*( (vs16)(*(data_buf+16)<<8)|*(data_buf+17) );
        ctrl_1.PID[PID6].ki     = 0.001*( (vs16)(*(data_buf+18)<<8)|*(data_buf+19) );
        ctrl_1.PID[PID6].kd     = 0.001*( (vs16)(*(data_buf+20)<<8)|*(data_buf+21) );
        ANO_DT_Send_Check(*(data_buf+2),sum);
                Param_SavePID();
    }
    if(*(data_buf+2)==0X12)                             //PID3
    {   
        ctrl_2.PID[PIDROLL].kp  = 0.001*( (vs16)(*(data_buf+4)<<8)|*(data_buf+5) );
        ctrl_2.PID[PIDROLL].ki  = 0.001*( (vs16)(*(data_buf+6)<<8)|*(data_buf+7) );
        ctrl_2.PID[PIDROLL].kd  = 0.001*( (vs16)(*(data_buf+8)<<8)|*(data_buf+9) );
        ctrl_2.PID[PIDPITCH].kp = 0.001*( (vs16)(*(data_buf+10)<<8)|*(data_buf+11) );
        ctrl_2.PID[PIDPITCH].ki = 0.001*( (vs16)(*(data_buf+12)<<8)|*(data_buf+13) );
        ctrl_2.PID[PIDPITCH].kd = 0.001*( (vs16)(*(data_buf+14)<<8)|*(data_buf+15) );
        ctrl_2.PID[PIDYAW].kp   = 0.001*( (vs16)(*(data_buf+16)<<8)|*(data_buf+17) );
        ctrl_2.PID[PIDYAW].ki   = 0.001*( (vs16)(*(data_buf+18)<<8)|*(data_buf+19) );
        ctrl_2.PID[PIDYAW].kd   = 0.001*( (vs16)(*(data_buf+20)<<8)|*(data_buf+21) );
        ANO_DT_Send_Check(*(data_buf+2),sum);
                Param_SavePID();
    }
    if(*(data_buf+2)==0X13)                             //PID4
    {
        ANO_DT_Send_Check(*(data_buf+2),sum);
    }
    if(*(data_buf+2)==0X14)                             //PID5
    {
        ANO_DT_Send_Check(*(data_buf+2),sum);
    }
    if(*(data_buf+2)==0X15)                             //PID6
    {
        ANO_DT_Send_Check(*(data_buf+2),sum);
    }
}

本模塊代碼雖多,但執行的功能相對比較簡單,主要是將傳過來的八位數據轉換成對應格式的數據然後更新到相對應的變量裏面。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章