惯性导航基础练习1
- 一、仿真imu数据,并用Allan分析方差
-
- 1.使用gnss-ins-sim进行imu数据仿真
-
- (1)官方例程demo_allan.py代码解析
- (2)官方例程demo_allan.py运行
- 2.使用imu_utils进行imu数据仿真
- 二、设计转台旋转方案,并根据模拟数据验证内部参考解
-
- 1.使用gnss-ins-sim定义标定的运动场景
- 2.使用gnss-ins-sim分级标定加速度计
-
- (1)读取仿真文件中的加速度计数据
- (2)分级分析法标定加速度计
- (3)分级分析法标定加速度计实验比较
- 2.使用gnss-ins-sim分级标定陀螺仪
- 三、推导基础LM在陀螺仪中进行加速度计和参考估计的优化过程。根据误差模型,并根据模拟数据实现。
-
- 1.用半系统级(不依赖转台)标定加速度计
-
- (1)雅克比矩阵的原理和推导
- (2)代码实现加速度计半系统级标定
- (3)实验对比
- 2.用半系统级(不依赖转台)标定陀螺仪
一、仿真imu数据,并用Allan分析方差
imu数据仿真程序地址: https://github.com/Aceinna/gnss-ins-sim. Allan方差分析代码地址: https://github.com/gaowenliang/imu_utils.
1.使用gnss-ins-sim进行imu数据仿真
如表所示:
文件名 | 描述 |
---|---|
demo_no_algo.py | 一个生成数据的例子,将生成的数据保存到文件中并绘制(2D / 3D)感兴趣的数据。没有用户指定的算法. |
demo_allan.py | 陀螺仪和加速度计数据Allan方差分析演示和绘制Allan方差的图。 |
demo_free_integration.py | 一个简单的捷联系统演示。模拟运行1000次。生成1000个模拟INS统计信息的结果。 |
demo_inclinometer_mahony.py | 基于Mahony动态测斜仪算法演示理论。演示了如何生成感兴趣数据的误差图。 |
demo_aceinna_vg.py | DMU演示380动态倾斜算法。该算法首先被编译成共享库。演示了如何调用共享库。Aceinna的VG / MTLT产品中的算法。 |
demo_aceinna_ins.py | DMU380 GNSS / INS演示集成算法。该算法首先被编译成共享库。演示了如何调用共享库。Aceinna的INS产品中的算法。 |
demo_multiple_algorithms.py | 模拟中的多种算法演示。演示演示了如何比较多种算法的结果。 |
demo_gen_data_from_files.py | 演示演示了如何模拟记录的数据文件。 |
(1)官方例程demo_allan.py代码解析
import os import math import numpy as np from gnss_ins_sim.sim import imu_model from gnss_ins_sim.sim import ins_sim # globals D2R = math.pi/180 motion_def_path = os.path.abspath('.//demo_motion_def_files//') fs = 100.0 # IMU sample frequency def test_allan(): ''' An Allan analysis demo for Sim. ''' #### Customized IMU model parameters, typical for IMU381 ''' 关于imu建立模型: 1.accuracy精度 该系统定义了可直接使用的三种精度 : 'low-accuracy', 'mid-accuracy' , 'high accuracy'. 或以下自定义精度模型: 'gyro_b':陀螺仪bias,度/小时 'gyro_arw随机游走陀螺角度,度/ RT-小时 'gyro_b_stability':陀螺仪bias不稳定,度/小时 'gyro_b_corr陀螺仪偏置不稳定相关性(秒)。 将其设置为‘’inf使用随机游走模型 使用一阶高斯-马尔可夫模型将其设置为正实数 'accel_b加速度计bias,米/秒^ 2 'accel_vrw加速度计速度随机游走,米/秒/ RT-小时 'accel_b_stability加速度计bias不稳定性,米/秒^ 2 'accel_b_corr加速度计偏置不稳定性相关性(秒)。 'mag_std磁噪声STD,UT 2.axis 6:只生成陀螺仪和加速度计数据。 'mag_std磁噪声STD,UT 2.axis 6:仅生成陀螺仪和加速度计数据。 9:除陀螺仪和加速度计数据外,生成磁力计数据。 3.gps True生成GPS数据,False不生成。 ''' imu_err =
{
'gyro_b'
: np
.array
(
[
0.0
,
0.0
,
0.0
]
)
,
'gyro_arw'
: np
.array
(
[
0.25
,
0.25
,
0.25
]
)
*
1.0
,
'gyro_b_stability'
: np
.array
(
[
3.5
,
3.5
,
3.5
]
)
*
1.0
,
'gyro_b_corr'
: np
.array
(
[
100.0
,
100.0
,
100.0
]
)
,
'accel_b'
: np
.array
(
[
0.0e-3
,
0.0e-3
,
0.0e-3
]
)
,
'accel_vrw'
: np
.array
(
[
0.03119
,
0.03009
,
0.04779
]
)
*
1.0
,
'accel_b_stability'
: np
.array
(
[
4.29e-5
,
5.72e-5
,
8.02e-5
]
)
*
1.0
,
'accel_b_corr'
: np
.array
(
[
200.0
,
200.0
,
200.0
]
)
,
'mag_std'
: np
.array
(
[
0.2
,
0.2
,
0.2
]
)
*
1.0
}
# do not generate GPS and magnetometer data imu
= imu_model
.IMU
(accuracy
=imu_err
, axis
=
6
, gps
=
False
)
#### Allan analysis algorithm
from demo_algorithms
import allan_analysis algo
= allan_analysis
.Allan
(
)
#### start simulation
''' 关于Sim的说明: [fs, 0.0, 0.0]:imu(陀螺仪和加速度计),GPS和磁力计的采样频率,此demo中没有后两者 motion_def_path+"//motion_def-Allan.csv":初始条件和运动定义,需要指定算法和运动场景。参考ins_sim.py 对于Allan方差分析,需要采集的是IMU静止时的传感器数据,因此,运动场景非常简单:保持静止。 在完整的运动仿真中,运动场景定义需要包含一系列的运动模式或机动指令。 ref_frame:0代表NED坐标系,1代表惯性系 mode:车辆操纵能力,[最大加速度,最大角加速度,最大角速度] env: algorithm:算法对象 ''' sim
= ins_sim
.Sim
(
[fs
,
0.0
,
0.0
]
, motion_def_path
+
"//motion_def-Allan.csv"
, ref_frame
=
1
, imu
=imu
, mode
=
None
, env
=
None
, algorithm
=algo
)
''' run():参数为执行次数,默认1 results():保存数据,参数为路径,空则不保存 plot():画图 ''' sim
.run
(
)
# generate simulation results, summary, and save data to files sim
.results
(
)
# save data files
# plot data sim
.plot
(
[
'ad_accel'
,
'ad_gyro'
]
)
if __name__
==
'__main__'
: test_allan
(
)
(2)官方例程demo_allan.py运行
2.使用imu_utils进行imu数据仿真
挖个坑,还没尝试~~
二、设计一种转台旋转方案,并基于仿真数据进行内参求解的验证
1.使用gnss-ins-sim定义标定的运动场景
Ini lat 经度(deg) | ini lon 纬度(deg) | ini alt 高度(m) | ini vx_body (m/s) | ini vx_body (m/s) | ini vy_body (m/s) | ini vz_body (m/s) | ini pitch (deg) | ini roll (deg) |
---|---|---|---|---|---|---|---|---|
command type命令类型 | yaw (deg) | pitch (deg) | roll (deg) | vx_body (m/s) | vy_body (m/s) | vz_body (m/s) | command duration 持续时间(s) | GPS visibilityGPS个数 |
对于其中的命令类型,官方有如下说明:
Command type | Comment |
---|---|
1 | 直接定义欧拉角变化率和车架速度变化率。变化率在第2〜7栏给出。单位是度/秒和米/秒/秒。第8列给出了该命令将持续多长时间。如果要完全控制每个命令的执行时间,则应始终将运动类型选择为12 |
2 | 定义要达到的绝对姿态和绝对速度。目标姿态和速度在第2〜7列中给出。单位是度和m / s。第8列定义了执行命令的最长时间。如果实际执行时间少于最大时间,则将不使用剩余时间,并且将立即执行下一条命令。如果命令不能在最大时间内完成,则在最大时间后将执行下一条命令。 |
3 | 定义姿态变化和速度变化。姿态和速度变化在第2〜7列中给出。单位是度和m / s。第8列定义了执行命令的最长时间。 |
4 | 定义绝对姿态和速度变化。绝对姿态和速度变化由第2〜7列给出。单位是度和m / s。第8列定义了执行命令的最长时间。 |
5 | 定义姿态变化和绝对速度。姿态变化和绝对速度由第2〜7列给出。单位是度和m / s。第8列定义了执行命令的最长时间。 |
对于使用转台的IMU分立级标定而言,至少需要6个不同的转台位置:Z轴朝上,Z轴朝下,X轴朝上,X轴朝下,Y轴朝上,Y轴朝下(定义时多了两个复位)。 根据上述的说明定义转台的运动场景: 在demo_motion_def_files文件夹下定义motion_def_my_imu.csv: 接下来参考demo_allan.py,在gnss-ins-sim文件夹下使用我们刚刚定义的运动模式产生仿真的imu数据,在这里我们要将加速度计三个轴的零偏设置为[0.1,0.2,0.3],具体实现Sim_IMU.py如下:
import numpy as np
import os
import math
from gnss_ins_sim.sim import imu_model
from gnss_ins_sim.sim import ins_sim
# globals
D2R = math.pi/180
motion_def_path = os.path.abspath('.//demo_motion_def_files//')
fs = 100.0 # IMU sample frequency
def create_sim_imu(): #生成 imu 方针imu数据
### Customized IMU model parameters, typical for IMU381
imu_err = {
'gyro_b': np.array([0.0, 0.0, 0.0]),
'gyro_arw': np.array([0.25, 0.25, 0.25]) * 1.0,
'gyro_b_stability': np.array([3.5, 3.5, 3.5]) * 1.0,
'gyro_b_corr': np.array([100.0, 100.0, 100.0]),
'accel_b': np.array([0.1, 0.2, 0.3]),
'accel_vrw': np.array([0.03119, 0.03009, 0.04779]) * 1.0,
'accel_b_stability': np.array([4.29e-5, 5.72e-5, 8.02e-5]) * 1.0,
'accel_b_corr': np.array([200.0, 200.0, 200.0]),
'mag_std': np.array([0.2, 0.2, 0.2]) * 1.0
}
# do not generate GPS and magnetometer data
imu = imu_model.IMU(accuracy=imu_err, axis=6, gps=False)
#### start simulation
sim = ins_sim.Sim([fs, 0.0, 0.0],
motion_def_path+"//motion_def_my_imu.csv",
ref_frame=1,
imu=imu,
mode=None,
env=None,
algorithm=None)
sim.run(1)
# generate simulation results, summary, and save data to files
sim.results('.//my_sim_imu//') # save data files
if __name__ == '__main__':
create_sim_imu()
在进行imu仿真的时候,ins_sim.Sim函数内部会调用acc_gen()函数,该函数在gnss-ins-sim/gnss_ins_sim/pathgen/pathgen.py中定义,在这里函数里可以修改刻度系数和安装误差,修改函数如下:
ks=np.array([[1.02,0.02,-0.03],[0.03,0.96,0.01],[0.04,0.05,1.05]])
ks=np.transpose(ks)
ref_a2=np.dot(ref_a,ks)
a_mea = ref_a2 + acc_bias + acc_bias_drift + acc_noise + acc_vib
修改后产生的加速度数据的内参矩阵为 [ 1.02 0.03 0.04 0.02 0.96 0.05 − 0.03 0.01 1.05 ] \begin{bmatrix} 1.02&0.03 &0.04 \\ 0.02& 0.96 & 0.05\\ -0.03& 0.01 &1.05 \end{bmatrix} ⎣⎡1.020.02−0.030.030.960.010.040.051.05⎦⎤ 产生了如下仿真数据:
The following results are saved:
time: sample time
ref_pos: true position in the local NED frame
ref_vel: true vel in the NED frame
ref_att_euler: true attitude (Euler angles, ZYX)
ref_accel: true accel in the body frame
ref_gyro: true angular velocity in the body frame
accel: accel measurements
gyro: gyro measurements
ref_att_quat: true attitude (quaternion)
代码采样频率为100hz,每个位置停留20s,即每个位置会产生2000个数据.
2.使用gnss-ins-sim分立级标定加速度计
(1)读取仿真文件中的加速度计数据
在读取的时候遇到了一些问题,我首先打开了文件查看数据格式(默认wps),看起来非常的规范(没有逗号之类的间隔),可是我单个数据读取的时候,莫名其妙的多了很多的间隔,一个数据有些被分成了两个,完全错乱,所以后来改成行读入,按逗号分隔,读入成功.
#include <vector>
#include <Eigen/Core>
#include <iostream>
#include <fstream>
#include <Eigen/Geometry>
#define D2R 0.017453292519943295 //角度转弧度
bool ReadData(const std::string &path ,std::vector<Eigen::Vector3d ,Eigen::aligned_allocator<Eigen::Vector3d>> &dataVector)
{
//清除原有数据
dataVector.clear();
std::ifstream fin(path);
std::string line="";
std::string temp="";
int cnt=0;
while (std::getline(fin,line))
{
cnt++;
if (cnt==1)
{
line="";
temp="";
continue;
}
std::vector<double> acc;
for (int i=0;i<line.size();i++)
{
if (line[i]==',')
{
acc.push_back(std::stod(temp));
temp="";
}
else
{
temp+=line[i];
}
}
acc.push_back(std::stod(temp));
line="";
temp="";
dataVector.push_back(Eigen::Vector3d(acc[0],acc[1],acc[2]));
std::cout<<cnt<<": "<<acc[0]<<", "<<acc[1]<<", "<<acc[2]<<std::endl;
}
if (cnt==0)
{
std::cerr<<"read fail"<<std::endl;
return false;
}
return true;
}
(2)分立级解析法标定加速度计实现
在读取数据的时候我注意到其实数据总共只有15725个(仿真出来的数据也就这么多,不是没有读取到),但是按照推算,8个场景(算上两次复位动作),100hz,20s。那么应该产生16000个数据,显然这存在一些问题.但是我们的标定最少只需要6个不同位置的数据,所以,我们要对这些数据进行一些优化,然后进行标定,代码如下:
void Calibration(std::vector<Eigen::Vector3d ,Eigen::aligned_allocator<Eigen::Vector3d>> &accs)
{
Eigen::Vector3d truth_z_down=CalculateMean(accs,1000,1500);
Eigen::Vector3d truth_z_up=CalculateMean(accs,3000,3500);
Eigen::Vector3d truth_y_down=CalculateMean(accs,7000,7500);
Eigen::Vector3d truth_y_up=CalculateMean(accs,9000,9500);
Eigen::Vector3d truth_x_up=CalculateMean(accs,13000,13500);
Eigen::Vector3d truth_x_down=CalculateMean(accs,15000,15500);
/* std::cout<<"truth_z_up :"<<std::endl; std::cout<<truth_z_up<<std::endl; std::cout<<"truth_z_down :"<<std::endl; std::cout<<truth_z_down<<std::endl; std::cout<<"truth_y_up :"<<std::endl; std::cout<<truth_y_up<<std::endl; std::cout<<"truth_y_down :"<<std::endl; std::cout<<truth_y_down<<std::endl; std::cout<<"truth_x_up :"<<std::endl; std::cout<<truth_x_up<<std::endl; std::cout<<"truth_x_down :"<<std::endl; std::cout<<truth_x_down<<std::endl; */
Eigen::Vector3d calib_bias;
Eigen::Matrix3d calib_sacle_factor;
Eigen::Matrix3d calib_installation_error;
Eigen::Matrix3d calib_internal_matrix=Eigen::Matrix3d::Identity();
//解析法求解 利用6组数据建立六个方程
calib_bias=(truth_z_up+truth_z_down)/2;
Eigen::Vector3d calib_internal_matrix_col3=(truth_z_up-calib_bias)/g;
Eigen::Vector3d calib_internal_matrix_col2=(truth_y_up-calib_bias)/g;
Eigen::Vector3d calib_internal_matrix_col1=(truth_x_up-calib_bias)/g;
calib_internal_matrix<<calib_internal_matrix_col1[0],calib_internal_matrix_col1[1],calib_internal_matrix_col1[2],calib_internal_matrix_col2[0],calib_internal_matrix_col2[1],calib_internal_matrix_col2[2],calib_internal_matrix_col3[0],calib_internal_matrix_col3[1],calib_internal_matrix_col3[2];
calib_internal_matrix.transpose();
std::cout<<"calib_internal_matrix: "<<std::endl;
std::cout<<calib_internal_matrix<<std::endl;
std::cout<<"calib_bias: "<<std::endl;
std::cout<<calib_bias<<std::endl;
}
int main(int argc ,char** argv)
{
//加速度计仿真数据
std::string accel_csv_path="./gnss-ins-sim/my_sim_imu/accel-0.csv";
std::vector<Eigen::Vector3d ,Eigen::aligned_allocator<Eigen::Vector3d>> accs;
ReadData(accel_csv_path,accs);
Calibration(accs);
}
(3)分立级解析法标定加速度计实验对比
设定的真实内参矩阵: [ 1.02 0.03 0.04 0.02 0.96 0.05 − 0.03 0.01 1.05 ] \begin{bmatrix} 1.02&0.03 &0.04 \\ 0.02& 0.96 & 0.05\\ -0.03& 0.01 &1.05 \end{bmatrix} ⎣⎡1.020.02−0.030.030.960.01