找回密码
 注册
关于网站域名变更的通知
查看: 730|回复: 1
打印 上一主题 下一主题

基于9轴惯性运动传感器的三阶卡尔曼滤波器算法

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-2-21 12:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
基于9轴惯性运动传感器的三阶卡尔曼滤波器算法3 N$ W  _/ v2 M1 m* q

) G+ Q, G5 t5 K7 C9 k% J. }
最近在玩九轴的惯性传感器,很是有挑战性.九轴说的是三轴的加速度计、三轴的陀螺仪以及三轴的磁场传感器。但是只是单纯的测出九个轴的数据没什么用,关键是要能够融合这九轴数据得出我们想要的结果。这里就运用三阶卡尔曼滤波算法来融合这九轴运动数据为三轴的角度。运用这三个角度可以用来做自平衡车或者四轴飞行器.
一、卡尔曼算法理解
其实如果不去考虑kalman算法是怎么来的,我们只需要知道有下面几个式子就可以了,具体意思可以看上面的wikipedia链接
二 卡尔曼滤波算法的实现
这里我的算法是运行在avr单片机上的,所以采用的是c语言写的。下面的代码是要放到avr的定时器中断测试刷新的。用示波器测试了一下,这个算法在16M晶振下的运行时间需要0.35ms,而数据采集需要3ms左右,所以选定定时器时间为8ms.之前也写过一阶的kalman算法,运用在自平衡车上,这边是三阶的,主要是矩阵运算.
//kalman.c

" m" e/ x9 c4 ~5 Y/ c2 P
float dtTimer   = 0.008;

+ z& _( P0 \0 m' q# z# O
float xk[9] = {0,0,0,0,0,0,0,0,0};

7 g& Y7 f! n4 f; F
float pk[9] = {1,0,0,0,1,0,0,0,0};
  h& H$ G/ J+ Z5 o1 ~4 h! g
float I[9]  = {1,0,0,0,1,0,0,0,1};
3 q! p  ~+ n" ~- a% R' l* C" b
float R[9]  = {0.5,0,0,0,0.5,0,0,0,0.01};

) L7 ^1 S1 z0 Z# B, Y: X- a  ^
float Q[9] = {0.005,0,0,0,0.005,0,0,0,0.001};
2 z' K, K  Z% O: y2 y/ B

# R9 x& ~* ]1 y" L
void matrix_add(float* mata,float* matb,float* matc){

  H+ f& e& g; Y. s! y1 D) v
    uint8_t i,j;

# _, p3 P5 v8 P& Z$ O. c
    for (i=0; i<3; i++){
4 F" j( k. x+ C1 i% m
       for (j=0; j<3; j++){
4 e, Q- A4 B! E" n
          matc[i*3+j] = mata[i*3+j] + matb[i*3+j];
8 v. U& S4 t2 W  }" Y+ Z
       }
0 T( P/ S6 T' R* ^2 p/ E/ W
    }
7 |% w& r  Q0 s; q
}

& h9 H9 m. Y0 s% `5 B  p0 C& ?9 E( [& _6 B3 V. S, t
void matrix_sub(float* mata,float* matb,float* matc){
. E% d/ o2 Q% \2 s- e
    uint8_t i,j;
; ~0 C- {) y9 i! i% W5 g( [& E! e: ~5 W
    for (i=0; i<3; i++){

# ]7 M2 O# }$ ^% o" |! y( ?
       for (j=0; j<3; j++){

) O( }9 d) @# S/ e7 M8 |1 A
          matc[i*3+j] = mata[i*3+j] - matb[i*3+j];
% p6 e1 t  O+ p9 B) l0 y
       }
- y/ U$ B8 m, ?% `: F* }+ U
    }

6 |7 v, E' ~& D3 X+ |( g) U
}

, b$ j" C+ P1 Q4 g9 J* \% x9 _; {" g! M" |
void matrix_multi(float* mata,float* matb,float* matc){
4 G; y2 n* M) r# D% P- d" A
  uint8_t i,j,m;

; q  h: s* f* B% I8 @2 u
  for (i=0; i<3; i++)

+ t" l) p6 F% ?$ J9 U0 [+ Q
  {

' ^; w- ?& }  J0 J! O
    for (j=0; j<3; j++)
8 _" q0 y' s6 Y( E& E& U- L  y
   {

+ d$ l; p2 S8 T
      matc[i*3+j]=0.0;

6 k9 |, j/ H4 e
      for (m=0; m<3; m++)
5 C: a; N! g( W. U7 v
     {
. l  F- O+ e# p5 a6 ~3 x: O: H) D
        matc[i*3+j] += mata[i*3+m] *  matb[m*3+j];

+ |: L& _! a9 u
      }
3 f/ O% X$ E5 m
    }
! J' d. z: [* e& g! u) V" }
}

/ W5 l2 U: E1 C. X
}

4 d' h1 H- ?' ?
4 d, B6 k7 \! N' J
void KalmanFilter(float* am_angle_mat,float* gyro_angle_mat){

; @4 j* Y+ T/ S6 n3 Q! G
uint8_t i,j;

( v, p+ R  R* T6 f" _+ n
float yk[9];

+ u, s. W8 r  G) F$ R/ @
float pk_new[9];
. H; ?8 d7 T' y
float K[9];

$ ^4 V; e* G! b8 t  f+ f& O5 x
float KxYk[9];

& e7 l% T$ X# v. Y5 r
float I_K[9];
+ F1 v. _: k# I* {0 R
float S[9];

1 \; m; ^1 D* X( _" s+ D: F
float S_invert[9];

1 ~+ j- k2 L, D/ Y9 L$ u  A9 S. s* R; P
float sdet;
: h* S2 G4 W+ v" `* \7 T

7 |6 C' H: h$ u4 ^9 D$ M
//xk = xk + uk
4 ?, f& B" h* g
matrix_add(xk,gyro_angle_mat,xk);
+ x& ^, `% R. q1 V1 W! k+ e* u
//pk = pk + Q
6 V! e+ {5 T8 p# W/ e/ ?$ ~" A+ C
matrix_add(pk,Q,pk);
. q5 L5 v( u, |- Y
//yk =  xnew - xk

' f8 n3 J$ j! t/ k' P5 z0 Q
matrix_sub(am_angle_mat,xk,yk);

8 B; W1 N" q* Z; W* ?6 Z
//S=Pk + R

. \( c& G! _/ B
matrix_add(pk,R,S);

/ \( x2 ^6 F$ D8 V0 m  A( ~
//S求逆invert

9 O* S7 H4 g/ J2 U' y
sdet = S[0] * S[4] * S[8]
3 t2 ]8 |2 J( N9 X8 ]+ A
          + S[1] * S[5] * S[6]
: c9 E/ a8 s6 I  t; `9 o/ X8 f
          + S[2] * S[3] * S[7]

6 q: C! _$ ^" p0 _% M
          - S[2] * S[4] * S[6]
9 s: W& g/ f, N
          - S[5] * S[7] * S[0]
$ w4 E5 Q' e0 b4 z& o
          - S[8] * S[1] * S[3];
/ N, W5 D' w& p& q1 c0 t' ~

7 v) K) ?$ M: L& n1 O
S_invert[0] = (S[4] * S[8] - S[5] *  S[7])/sdet;
3 c8 c& H* n+ d
S_invert[1] = (S[2] * S[7] - S[1] *  S[8])/sdet;
8 t- L4 N. ?" O. B3 @* F3 C
S_invert[2] = (S[1] * S[7] - S[4] *  S[6])/sdet;
8 z- j. y# O+ ^- Q$ J& D

6 e! w" y# b1 s6 \% ?, }
S_invert[3] = (S[5] * S[6] - S[3] *  S[8])/sdet;

& C  |, K+ e1 F+ ^, G7 J$ I
S_invert[4] = (S[0] * S[8] - S[2] *  S[6])/sdet;
' \$ S4 x& t3 J, L3 ?
S_invert[5] = (S[2] * S[3] - S[0] *  S[5])/sdet;

! }/ V2 r( [/ @
9 r8 i* L+ t+ c, p
S_invert[6] = (S[3] * S[7] - S[4] *  S[6])/sdet;

4 l' R9 X) u- F
S_invert[7] = (S[1] * S[6] - S[0] *  S[7])/sdet;

& h0 d" \" T' ^6 g/ w8 W/ |
S_invert[8] = (S[0] * S[4] - S[1] *  S[3])/sdet;
1 j: y! ^, P# ]  D- p
//K = Pk * S_invert
9 f& M  n9 r/ H, [& j5 k3 p
matrix_multi(pk,S_invert,K);
0 _3 r  G. t3 b& R2 V
//KxYk = K * Yk

) j$ b3 W# C5 F
matrix_multi(K,yk,KxYk);

/ _' s8 |* a; A- {( q
//xk = xk + K * yk
) v3 ~  a2 h5 {9 _9 g  B
matrix_add(xk,KxYk,xk);
! s! J/ C; O- q3 Q
//pk = (I - K)*(pk)

) V; S( Y* }- z& G
matrix_sub(I,K,I_K);
9 }( \; J; M3 b) F4 F4 s, X+ [
matrix_multi(I_K,pk,pk_new);
& p0 h9 Y& W' J& H: D2 x; e2 Q4 F
//update pk
+ R) J. _1 a( E
//pk = pk_new;

; [0 u, K* h3 r) m+ U# x  B) m, J1 F
for (i=0; i<3; i++){
4 _3 l  A% L6 W! d- x+ X# k4 p2 d
    for (j=0; j<3; j++){
- @" ~. P: T+ p9 C. m  U
        pk[i*3+j] = pk_new[i*3+j];
2 p5 F. X, g! p, E. R
    }
1 h$ Y9 t9 J  y8 z7 L0 r! H
  }
3 p8 x0 z# |- V* ]  m) P
}
3 I; |4 j6 }# v: o# f
; G" r2 I5 g6 A/ [7 _* u9 `* r0 h
三 运用卡尔曼滤波器
这里的kalman滤波器是离散数字滤波器,需要迭代运算。这里把算法放到avr的定时器中断里面执行,进行递归运算.
//isr.c
" b$ w) s* a! F9 i# M$ ^( Y
#include "kalman.h"
( g* |; M3 ?0 A2 R3 B
float mpu_9dof_values[9]={0};
$ M2 M. ^4 S( b
float am_angle[3];
% \" \7 x& b  C& M& G
float gyro_angle[3];

+ ?9 k: C5 W8 [
float am_angle_mat[9]={0,0,0,0,0,0,0,0,0};

  y+ }) \) n7 C5 s# d* ?) V; z
float gyro_angle_mat[9]={0,0,0,0,0,0,0,0,0};
  t$ @) Z, J5 i/ h

$ T" X( q# u! I; m/ l
//8MS

( }* X; N# x2 `- R; z/ w1 t( X
ISR(TIMER0_OVF_vect){
! k( B: l! U! {  U
//设置计数开始的初始值
9 ~) A0 _) e. d4 l" m! k6 F5 ?; c4 A
TCNT0 = 130 ;  //8ms
1 F# p+ U9 F0 Z- p5 ?% a
sei();

, N' P* \4 z9 e+ z
//采集九轴数据

6 U& F7 L* P1 }3 z5 H1 W+ Q3 w
//mpu_9dof_values 单位为g与度/s

+ V( M- `( X2 P8 G1 ^" x7 i, u
//加速度计和陀螺仪
- F1 f/ c3 P- K3 S% }
mpu_getValue6(&mpu_9dof_values[0],&mpu_9dof_values[1],&mpu_9dof_values[2],&mpu_9dof_values[3],&mpu_hmc_values[4],&mpu_hmc_values[5]);

& ]8 L" f" ^1 |9 j9 y# C' j
//磁场传感器
! r* q( u4 v% `& A" g9 V0 ?
compass_mgetValues(&mpu_9dof_values[6],&mpu_9dof_values[7],&mpu_9dof_values[8]);
/ y" ?- q- L0 \: c: n

+ Z/ [7 U3 @1 ?9 e  e  h1 d
accel_compass2angle(&mpu_9dof_values[0],&mpu_9dof_values[6],am_angle);

/ h# M0 X7 M+ Z' r
gyro2angle(&mpu_9dof_values[3],gyro_angle);

9 b+ {; x9 u* B4 I+ z2 m' o
- s7 Z: H8 s( r, W" I
am_angle_mat[0] = am_angle[0];
+ x  x. @9 ~0 m1 ?* E: z
am_angle_mat[4] = am_angle[1];

- z1 M: h  |3 ?5 T) Y
am_angle_mat[8] = am_angle[2];
. c3 J" |9 ~$ ^4 K! Z* O  e9 h0 e' w
/ M4 _6 s2 i" N3 Z: e
gyro_angle_mat[0] = gyro_angle[1];

, o+ j* X/ u+ N* q" w
gyro_angle_mat[4] = - gyro_angle[0];
* `6 x: Q5 l; h1 u) W" `8 J
gyro_angle_mat[8] = - gyro_angle[2];
0 G; B, g2 q5 T. t

- @1 S& G4 Q( h; o8 K
//卡尔曼

% O9 ~" ^* F, g" ]* @( `4 A
KalmanFilter(am_angle_mat,gyro_angle_mat);

1 ]; ?# A" |* h! F/ m
" _/ B* a* e2 p. T# o) v8 W0 A
//输出三轴角度
0 V1 _4 K# U1 W" U5 ^4 Y5 C
//xk[0] xk[4] xk[8]
; r9 w8 x3 _7 |2 [, A
}

4 Q9 g! L9 M; ]; I
4 ]2 T# B/ o, I- z
实测可以准确的输出三轴的角度,为了获得更好的响应速度和跟踪精度还需调整参数.
; E( o$ H6 g% M) L0 _

该用户从未签到

2#
发表于 2019-2-21 16:18 | 只看该作者
研究一下,谢谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-7-17 15:32 , Processed in 0.125000 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表