標(biāo)題:
無人機(jī)加速計(jì)、氣壓計(jì)、GPS數(shù)據(jù)融合
[打印本頁]
作者:
涂覆莉娜
時(shí)間:
2019-8-9 22:54
標(biāo)題:
無人機(jī)加速計(jì)、氣壓計(jì)、GPS數(shù)據(jù)融合
在無人機(jī)控制當(dāng)中,傳感器的參與那是必不可少的,特別是陀螺儀,最經(jīng)典的為MPU6050,目前大部分的無人機(jī)都是用的這個(gè)器件。熟悉MPU6050的都知道,這個(gè)傳感器可以輸出三軸加速計(jì)、三軸陀螺儀;加速計(jì),顧名思義,直接測得物體的加速度。理論上 加速度積分得到速度,速度再積分得到位移:S = V0 * t + 1/2 * a * t ^ 2;V = v0 + a * t;按照此理想情況下:一個(gè)加速計(jì)直接積分算得速度跟位移就得了呀,為啥還要?dú)鈮河?jì)、GPS呢。無人機(jī)為了定點(diǎn)懸停,需要計(jì)算XYZ三軸的速度跟位移,而加速度計(jì)有一個(gè)致命的缺點(diǎn)就是它積分會(huì)漂移,而且是漂移非常大的那種,如果直接用這個(gè)數(shù)據(jù)做控制,飛機(jī)都不知道要飄到哪里去了。所以才借助外部傳感器氣壓計(jì)、GPS修正加速計(jì)的漂移。加速計(jì)在無人機(jī)三軸位置速度計(jì)算時(shí)也有很大的優(yōu)點(diǎn),就是其靈敏度相對很高,無人機(jī)稍微動(dòng)一點(diǎn)加速計(jì)都可以感受的出來,然后把數(shù)據(jù)傳到無人機(jī),無人機(jī)得以做相應(yīng)的調(diào)整。
數(shù)據(jù)融合
具體數(shù)據(jù)怎么融合呢?我們先來總結(jié)一下加速計(jì)、氣壓計(jì)、gps各自的優(yōu)缺點(diǎn):加速計(jì):優(yōu)點(diǎn)反應(yīng)速度快,缺點(diǎn)積分漂移嚴(yán)重。氣壓計(jì)GPS:優(yōu)點(diǎn)絕對位置比較平穩(wěn),缺點(diǎn)反應(yīng)速度比較慢。所以就有了互補(bǔ)濾波這個(gè)偉大的,簡單易懂的濾波算法。
以下為互補(bǔ)濾波代碼:
void Gps_Acc_Delay(void){ volatile uint8 i; for (i = 0; i < XY_VEL_HISTORY - 1; i++) { x_vel_history = x_vel_history[i+1]; y_vel_history = y_vel_history[i+1]; x_pos_history = x_pos_history[i+1]; y_pos_history = y_pos_history[i+1]; } x_vel_history[XY_VEL_HISTORY - 1] = x_est[1]; y_vel_history[XY_VEL_HISTORY - 1] = y_est[1]; x_pos_history[XY_VEL_HISTORY - 1] = x_est[0]; y_pos_history[XY_VEL_HISTORY - 1] = y_est[0];}void ObservationOPT_Update(float pos_x,float vel_x,float pos_y,float vel_y) //have data and update{ uint8 i; corrOPT_xpos = pos_x-x_est[0]; corrOPT_xvel = vel_x-x_est[1]; corrOPT_ypos = pos_y-y_est[0]; corrOPT_yvel = vel_y-y_est[1]; return;}void ObservationUpdate(int baro_disdance,int16 baro_vel){ uint8 i; corr_baro = (float)baro_disdance - z_est[0]; if (fly_status.HOLD_STATUS == HOLD_STOP) { z_est[0] = baro_disdance; z_est[1] = 0; } return;}void TimeUpdate(struct vertical_information *pAltitude,realacc* acc){ static float high_pass_zvel = 0; z_est[2]=acc->zz-z_bias; accel_filter_predict(INAV_T,z_est); z_est[0] += corr_baro * w_z_baro * INAV_T; z_bias -= corr_baro * 0.001f * INAV_T; z_est[1] += corr_baro * baro_vel_gain * INAV_T; high_pass_zvel = z_est[1]; pAltitude->altitude_hat=z_est[0]; pAltitude->velocity_hat=high_pass_zvel; ObservationOPT_Update(x_est[0],optflow.velx,y_est[0],optflow.vely); x_est[2]=acc->xx-x_bias; accel_filter_predict(INAV_TXY,x_est); x_est[0] += corrGPS_xpos * x_pos_gain * INAV_TXY; x_est[1] += (corrOPT_xvel*0 + corrGPS_xpos * 1.0f + corrGPS_xvel * 0.2f) * x_vel_gain * INAV_TXY; y_est[2]=acc->yy-y_bias; accel_filter_predict(INAV_TXY,y_est); y_est[0] += corrGPS_ypos * y_pos_gain * INAV_TXY; y_est[1] += (corrOPT_yvel*0 + corrGPS_ypos * 1.0f + corrGPS_yvel * 0.2f) * y_vel_gain * INAV_TXY; if (GPS_is_Good) { if (corrGPS_xvel > -10 && corrGPS_xvel < 10) x_bias -= (corrGPS_xpos*0.3f + corrGPS_xvel) * INAV_TXY * 0.1f; if (corrGPS_yvel > -10 && corrGPS_yvel < 10) y_bias -= (corrGPS_ypos*0.3f + corrGPS_yvel) * INAV_TXY * 0.1f; } else { x_est[1] = Body_dat.vel_x; y_est[1] = Body_dat.vel_y; x_est[0] = Body_dat.pos_x1; y_est[0] = Body_dat.pos_y1; } pos_vel_xy.posx = Body_dat.pos_x1; pos_vel_xy.posy = Body_dat.pos_y1; pos_vel_xy.velx = x_est[1]; pos_vel_xy.vely = y_est[1];}
以上代碼就是無人機(jī)里的互補(bǔ)濾波修正。如有不懂歡迎留言或扣我1836703877。無人機(jī)四軸本人做了五年,以上代碼全部自己寫,上傳的沒來的及添加注釋,但是代碼時(shí)成功在飛機(jī)上跑的并且無人機(jī)出貨的。
作者:
51hei團(tuán)團(tuán)
時(shí)間:
2019-8-10 16:10
好東東啊,樓主能把代碼放在代碼框中嗎?
作者:
涂覆莉娜
時(shí)間:
2019-8-12 19:55
可以的,待我整理一下
作者:
007cad
時(shí)間:
2019-8-13 15:30
無人機(jī) 未來發(fā)展前途廣闊
大家說一下哪家的無人機(jī)技術(shù)優(yōu)秀
作者:
涂覆莉娜
時(shí)間:
2019-8-14 10:36
目前來看,還是大疆的比較牛逼,各方面穩(wěn)定,控制,都沒得說
作者:
涂覆莉娜
時(shí)間:
2019-8-14 10:38
_POS_NOWstatus pos_vel_xy;
float z_est[3]={0,0,0},x_est[3]={0,0,0},y_est[3]={0,0,0};
typedef struct {
float R[3][3]; /**< Rotation matrix body to world, (Tait-Bryan, NED)*/
}vehicle_attitude_s;
vehicle_attitude_s vehicle_att;
vehicle_attitude_s vehicle_optical;
realacc real_acceleration;
_vertical_information baro_acc_alt;
//#define ALT_VEL_HISTORY 10
//volatile float alt_vel_history[ALT_VEL_HISTORY] = {0};
//#define XY_VEL_HISTORY 3
//volatile float x_vel_history[XY_VEL_HISTORY] = {0}, y_vel_history[XY_VEL_HISTORY] = {0};
static float z_bias = 0,x_bias = 0,y_bias = 0;
float w_z_baro=0.5f;
static float corr_baro = 0;//corr_baro_filter = 0;
static float corr_xvel = 0,corr_yvel = 0;
static float corr_xpos = 0,corr_ypos = 0;
static float acck = 0;
void accel_filter_predict(float dt,float x[3])
{
x[0] += x[1] * dt + x[2] * dt * dt / 2.0f;
x[1] += x[2] * dt;
}
void inertial_filter_correct(float e,float dt,float x[3],int i,float w,float vp)
{
float ewdt = e * w * dt;
x[i] += ewdt;
if(i == 0)
{
x[1] += vp*w * ewdt;
}
}
void check_stop(int16 accz_velocity,int16 accz)
{
static uint8 slow_down_count=0;
static uint16 down_time=0;
down_time++;
if(fly_status.HOLD_STATUS == HOLD_DOWN)
{
if(down_time>=200)
{
if((accz_velocity>=0&&accz<50&&accz>-50) || (accz_velocity>=50) || (accz>300 || accz<-300))
{
slow_down_count++;
if(slow_down_count>3)
{
fly_status.HOLD_STATUS=HOLD_STOP;
}
}
else if(slow_down_count>0)
{
if(accz_velocity<0)
slow_down_count=0;
else
slow_down_count--;
}
}
}
else
{
down_time=0;
slow_down_count=0;
}
}
void accel_baro_mag_gps_calculator(int16 accel_x,int16 accel_y,int16 accel_z)
{
static uint8 usart1_count = 0;
static int16 acc_xyz[3];
static float no_filteraccxx,no_filteraccyy,no_filteracczz;
if (accel_x != 0 && accel_y != 0 && accel_z != 0)
{
acck=(1/Fylib_Qrsqrt(accel_x*accel_x + accel_y*accel_y+accel_z*accel_z)-MV_ACC_RP)/MV_ACC_RP;
if(acck<0) acck=-acck;
}
acc_xyz[0]=accel_x*980/MV_ACC_RP;acc_xyz[1]=accel_y*980/MV_ACC_RP;acc_xyz[2]=accel_z*980/MV_ACC_RP;
//ÉÏÕýϸº£¬±±ÕýÄϸº£¬¶«ÕýÎ÷¸º
no_filteracczz=-acc_xyz[1]*vehicle_att.R[2][0]-acc_xyz[0]*vehicle_att.R[2][1]+acc_xyz[2]*vehicle_att.R[2][2]-980;
no_filteraccxx=-(-acc_xyz[1]*vehicle_optical.R[0][0]-acc_xyz[0]*vehicle_optical.R[0][1]+acc_xyz[2]*vehicle_optical.R[0][2]);
no_filteraccyy=(acc_xyz[1]*vehicle_optical.R[1][0]+acc_xyz[0]*vehicle_optical.R[1][1]-acc_xyz[2]*vehicle_optical.R[1][2]);
// no_filteracczz += (float)(agx + agy);
// no_filteraccxx += (float)(agy + agz);
// no_filteraccyy += (float)(agx + agz);
//high_pass
real_acceleration.xx=(int16)no_filteraccxx;
real_acceleration.yy=(int16)no_filteraccyy;
real_acceleration.zz=(int16)no_filteracczz;
TimeUpdate(&baro_acc_alt,(realacc*)&real_acceleration);
check_stop(baro_acc_alt.velocity_hat,no_filteracczz);
usart1_count++;
if(usart1_count>=1)
{
usart1_count = 0;
// SendDatShowINT((int)z_est[0],(int)(baro_data.baro_home),(int)(baro_data.velocity*3.1f),(int)baro_to_alt);
SendDatShow((int)y_est[1],(int)x_est[1],(int)(acck * 100),(int)baro_data.baro_home);
}
}
void ahrs_update_R_bf_to_ef(float angle_pitch,float angle_roll,float angle_yaw)
{
float sin_pitch = sin(angle_pitch * M_DEG_TO_RAD);
float cos_pitch = cos(angle_pitch * M_DEG_TO_RAD);
float sin_roll = sin(angle_roll * M_DEG_TO_RAD);
float cos_roll = cos(angle_roll * M_DEG_TO_RAD);
float sin_yaw = sin(angle_yaw * M_DEG_TO_RAD);
float cos_yaw = cos(angle_yaw * M_DEG_TO_RAD);
vehicle_att.R[0][0] = cos_pitch * cos_yaw;
vehicle_optical.R[0][0]=cos_pitch;
vehicle_att.R[0][1] = sin_roll * sin_pitch * cos_yaw + cos_roll * sin_yaw;
vehicle_optical.R[0][1] = 0;//sin_roll * sin_pitch + cos_roll;
vehicle_att.R[0][2] = cos_roll * sin_pitch * cos_yaw - sin_roll * sin_yaw;
vehicle_optical.R[0][2] = sin_pitch;//cos_roll * sin_pitch - sin_roll;
vehicle_att.R[1][0] = cos_pitch * sin_yaw;
vehicle_optical.R[1][0] = 0;//cos_pitch;
vehicle_att.R[1][1] = -sin_roll * sin_pitch * sin_yaw - cos_roll * cos_yaw;
vehicle_optical.R[1][1] =cos_roll;// -sin_roll * sin_pitch - cos_roll;
vehicle_att.R[1][2] = cos_roll * sin_pitch * sin_yaw + sin_roll * cos_yaw;
vehicle_optical.R[1][2] =-sin_roll;// cos_roll * sin_pitch;// + sin_roll;
vehicle_att.R[2][0] = -sin_pitch;
vehicle_att.R[2][1] = sin_roll * cos_pitch;
vehicle_att.R[2][2] = cos_roll * cos_pitch;
}
#define HIGH_PASS_PARAM 0.999f
float baro_vel_gain = 0.2f, x_vel_gain = 1.8f, y_vel_gain = 1.8f;
float baro_gain=0.05f;
void TimeUpdate(struct vertical_information *pAltitude,realacc* acc)
{
static float high_pass_zvel = 0;//, z_est1f = 0;
z_est[2]=acc->zz-z_bias;
accel_filter_predict(INAV_T,z_est);
z_est[0] += corr_baro * w_z_baro * INAV_T;
z_bias -= corr_baro * 0.001f * INAV_T;
z_est[1] += corr_baro * baro_vel_gain * INAV_T;
// if (z_est[1] >-20 && z_est[1] <20)
// high_pass_zvel = (high_pass_zvel + z_est[1] - z_est1f) * HIGH_PASS_PARAM;
// else
high_pass_zvel = z_est[1];
// z_est1f = z_est[1];
pAltitude->altitude_hat=z_est[0];
pAltitude->velocity_hat=high_pass_zvel;
ObservationOPT_Update(x_est[0],optflow.velx,y_est[0],optflow.vely);
x_est[2]=acc->xx-x_bias;
accel_filter_predict(INAV_T,x_est);
x_est[1] += corr_xvel * x_vel_gain * INAV_T;
y_est[2]=acc->yy-y_bias;
accel_filter_predict(INAV_T,y_est);
y_est[1] += corr_yvel * y_vel_gain * INAV_T;
pos_vel_xy.posx = 0;
pos_vel_xy.posy = 0;
pos_vel_xy.velx = optflow.velx;//x_est[1];
pos_vel_xy.vely = optflow.vely;//y_est[1];
}
__AVERAGE_DATAF altitude_vcal={0,0};
float ABS_f(float values)
{
if (values < 0 )
return -values;
else
return values;
}
void ObservationUpdate(int baro_disdance,int16 baro_vel)
{
uint8 i;
corr_baro = (float)baro_disdance - z_est[0];
if (corr_baro >20 || corr_baro <-20)
baro_vel_gain = 0.4f;
else
baro_vel_gain = 0.2f;
if (fly_status.HOLD_STATUS == HOLD_STOP)
{
z_est[0] = baro_disdance;
z_est[1] = 0;
}
return;
}
void ObservationOPT_Update(float pos_x,float vel_x,float pos_y,float vel_y)
{
uint8 i;
corr_xpos = pos_x-x_est[0];
corr_xvel = vel_x-x_est[1];//x_vel_history[0]);
corr_ypos = pos_y-y_est[0];
corr_yvel = vel_y-y_est[1];//y_vel_history[0]);
// for (i = 0; i < XY_VEL_HISTORY - 1; i++)
// {
// x_vel_history[i] = x_vel_history[i+1];
// y_vel_history[i] = y_vel_history[i+1];
// }
// x_vel_history[XY_VEL_HISTORY - 1] = x_est[1];
// y_vel_history[XY_VEL_HISTORY - 1] = y_est[1];
return;
}
復(fù)制代碼
以上代碼是我的加速計(jì)跟光流,氣壓計(jì)的融合算法
作者:
gasarakl
時(shí)間:
2019-9-29 22:10
現(xiàn)在正需要這個(gè)研究下,謝謝樓主
作者:
回回憶
時(shí)間:
2020-3-10 13:50
謝謝分享,學(xué)習(xí)
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1