惯性导航解算程序C++实现

惯性导航解算程序C++实现

本文为惯性导航解算程序,为sdust本科课程《惯性导航基础》随课实验及课程设计。
在此首先感谢石波老师对小组的支持与帮助,另感谢组员对这一项目作出的贡献!

由于编者水平有限,错误在所难免,望读者指正!!!

程序开源地址:https://github.com/ethanjinhuang/inertial-navigation
欢迎收藏!共同交流进步!


1 性质、目的和任务

1.1性质、目的和任务

1.2组织和分工情况

小组中共三人,分别为hj、pzl和myj,每人协作、独立进行了惯导解算程序的设计。

小组成员分工
hj解算程序的算法部分、可视化界面主体功能的实现
pzl界面换肤、图标、按钮换颜色和保存图片与日志功能、软件测试
myj说明帮助文档的撰写、程序介绍视频、软件测试

2 重点及内容

主要包含以下几个主要内容,分别为:1. 编程实现欧拉角、方向余弦阵、四元数以及等效旋转矢量之间的相互转换;2. 编程实现大地坐标与地心直角坐标相互转换;3. 编程实现IMR格式惯导数据的读取与解析;4. 编程实现地理坐标系下的姿态更新;5.编程实现地理坐标系下的速度和位置更新;6. 编程实现解析粗对准。

2.1 欧拉角、方向余弦阵、四元数、等效旋转矢量转换

参考严恭敏老师《捷联惯导算法与组合导航原理》

2.2 大地坐标与地心直角坐标相互转换

参考严恭敏老师《捷联惯导算法与组合导航原理》

2.3 IMR格式惯导数据的读取与解析

IMR格式的数据读取即通过给定的IMR格式编写读写程序。其数据结构如下表所示:

IMR Header Struct Definition
WordSize (bytes)TypeDescription
szHeader8char[8]“$IMURAW0” – NULL terminated ASCII string
bIsIntelOrMotorola1int8_t0 = Intel (Little Endian), default 1 = Motorola (Big Endian)
dVersionNumber8doubleInertial Explorer program version number (e.g. 8.80)
bDeltaTheta4int32_t0 = Data to follow will be read as scaled angular rates 1 = (default), data to follow will be read as delta thetas, meaning angular increments (i.e. scale and multiply by dDataRateHz to get degrees/second)
bDeltaVelocity4int32_t0 = Data to follow will be read as scaled accelerations 1 = (default), data to follow will be read as delta velocities, meaning velocity increments (i.e. scale and multiply by dDataRateHz to get m/s2)
dDataRateHz8doubleThe data rate of the IMU in Hz. e.g. 0.01 second data rate is 100 Hz
dGyroScaleFactor8doubleIf bDeltaTheta == 0, multiply the gyro measurements by this to get degrees/second If bDeltaTheta == 1, multiply the gyro measurements by this to get degrees, then multiply by dDataRateHz to get degrees/second
dAccelScaleFactor8doubleIf bDeltaVelocity == 0, multiply the accel measurements by this to get m/s2 If bDeltaVelocity == 1, multiply the accel measurements by this to get m/s, then multiply by dDataRateHz to get m/s2
iUtcOrGpsTime4int32_tDefines the time tags as GPS or UTC seconds of the week 0 = Unknown, will default to GPS 1 = Time tags are UTC seconds of week 2 = Time tags are GPS seconds of week
iRcvTimeOrCorrTime4int32_tDefines whether the time tags are on the nominal top of the second or are corrected for receiver time bias 0 = Unknown, will default to corrected time 1 = Time tags are top of the second 2 = Time tags are corrected for receiver clock bias
dTimeTagBias8doubleIf you have a known bias between your GPS and IMU time tags enter it here
szImuName32char[32]Name of the IMU being used
reserved14uint8_t[4]Reserved for future use
szProgramName32char[32]Name of calling program
tCreate12time_typeCreation time of file
bLeverArmValid1boolTrue if lever arms from IMU to primary GNSS antenna are stored in this header
lXoffset4int32_tX value of the lever arm, in millimeters
lYoffset4int32_tY value of the lever arm, in millimeters
lZoffset4int32_tZ value of the lever arm, in millimeters
Reserved[354]354int8_t[354]Reserved for future use

The single header, which is a total of 512 bytes long, is followed by a structure of the following type for each IMU measurement epoch:

IMR Record Struct Definition
WordSizeTypeDescription
Time8doubleTime of the current measurement
gx4int32_tScaled gyro measurement about the IMU X-axis
gy4int32_tScaled gyro measurement about the IMU Y-axis
gz4int32_tScaled gyro measurement about the IMU Z-axis
ax4int32_tScaled accel measurement about the IMU X-axis
ay4int32_tScaled accel measurement about the IMU Y-axis
az4int32_tScaled accel measurement about the IMU Z-axis

2.4 地理坐标系下的姿态更新

参考严恭敏老师《捷联惯导算法与组合导航原理》

2.5 地理坐标系下的速度和位置更新

参考严恭敏老师《捷联惯导算法与组合导航原理》

2.6 解析粗对准

参考严恭敏老师《捷联惯导算法与组合导航原理》

3 解算程序设计思路原理

参考严恭敏老师《捷联惯导算法与组合导航原理》

3.1编译环境概述:

  1. 操作系统: Windows 10专业版 19042.685

  2. 主要IDE: Microsoft Visual Studio 2019 + Qt Creator 4.11.1(Community)

  3. 程序语言:C++ 11

  4. 其他实现IDE: PyCharm Professional 2020.3.1, MATLAB 2020a

3.2程序组织架构:

算法的主要实现结构如下图所示:

在这里插入图片描述

3.2代码设计:

3.2.1姿态转换矩阵

欧拉角类的类架构如下所示:

// 欧拉角
class Euler_angle
{
public:
    // 三个参数对应
    // phi		航向角
    // theta	俯仰角
    // gamma	横滚角
    Vector3d value = Eigen::Vector3d::Zero();
    Euler_angle() { value = Eigen::Vector3d::Zero(); }
    Euler_angle(Euler_angle const &input) { value = input.value; }	// 对象初始化
    Euler_angle(double phi, double theta, double gamma);	// 数值初始化
    Euler_angle(Vector3d input_vector);	// Vector3d初始化
    //transform function
    Matrix3d EA2DCM();	// 欧拉角 --> 方向余弦阵
    Vector4d EA2QV();	// 欧拉角 --> 四元数
    Vector3d EA2ERV();	// 欧拉角 --> 等效旋转矢量
    // caculate function
    Matrix3d EA2ssm();	//Skew-symmetric matrix	欧拉角 --> 反对称阵ssm
    // Basic function
    void show();
    void initialize() { value = Eigen::Vector3d::Zero(); };		//初始化
    void operator<<(Vector3d vector3);			// 重载<<,便于向量赋值
    void operator=(Euler_angle input);	// 重载=,便于对象间赋值
    //Euler_angle operator*(Euler_angle& input);	// 重载*,便于进行乘法运算
    Euler_angle operator+(Euler_angle& input);
};

方形余弦阵类架构的如下所示:

// 方向余弦阵
class Direct_cosine_matrix
{
public:
    Matrix3d value = Eigen::Matrix3d::Zero();
    Direct_cosine_matrix() { value = Eigen::Matrix3d::Zero(); }
    Direct_cosine_matrix(Direct_cosine_matrix& input) { value = input.value; }	// 对象初始化
    Direct_cosine_matrix(Matrix3d input_matrix);
    //transform function
    Vector3d DCM2EA();	// 方向余弦阵 --> 欧拉角
    Vector4d DCM2QV();	// 方向余弦阵 --> 四元数
    Vector3d DCM2ERV();	// 方向余弦阵 --> 等效旋转矢量
    // Basic function
    void show();
    void initialize() { value = Eigen::Matrix3d::Zero(); };		//初始化
    void operator<<(Matrix3d matrix3);			//重载<<,便于向量赋值
    void operator=(Direct_cosine_matrix input);	//重载=,便于对象间赋值
};

四元数类的架构如下所示:

// 四元数
class Quaternion_vector
{
public:
    Vector4d value = Eigen::Vector4d::Zero();
    Quaternion_vector() { value = Eigen::Vector4d::Zero(); }
    Quaternion_vector(Quaternion_vector& input) { value = input.value; }	// 对象初始化
    Quaternion_vector(Vector4d input);
    //transform function
    Vector3d QV2EA();	//四元数 --> 欧拉角
    Matrix3d QV2DCM();	//四元数 --> 方向余弦阵
    Vector3d QV2ERV();	//四元数 --> 等效旋转矢量
    // Basic function
    void show();
    void initialize() { value = Eigen::Vector4d::Zero(); };		//初始化
    void operator<<(Vector4d& matrix3);		//重载<<,便于向量赋值
    void operator=(Quaternion_vector& input);//重载=,便于对象间赋值
    Quaternion_vector operator*(Quaternion_vector& input);	//重载四元数相乘
};

等效旋转矢量类的架构如下所示:

// 等效旋转矢量
class Equivalent_rotation_vector
{
public:
    Vector3d value = Eigen::Vector3d::Zero();
    Equivalent_rotation_vector() { value = Eigen::Vector3d::Zero(); }
    Equivalent_rotation_vector(Equivalent_rotation_vector& input) { value = input.value; }	// 对象初始化
    Equivalent_rotation_vector(Vector3d input);
    //transform function
    Vector4d ERV2QV();	//等效旋转矢量 --> 四元数
    Matrix3d ERV2DCM();	//等效旋转矢量 --> 方向余弦阵
    Vector3d ERV2EA();	//等效旋转矢量 --> 欧拉角
    // Basic function
    void show();
    void initialize() { value = Eigen::Vector3d::Zero(); };		//初始化
    void operator<<(Vector3d& vector3);							//重载<<,便于向量赋值
    void operator=(Equivalent_rotation_vector& input);		//重载=,便于对象间赋值
};

3.2.2坐标转换

坐标转化的相应函数如下所示:

Vector3d gcs2gc(double lambda, double L, double h);         // 大地坐标转换为地心直角坐标
Vector3d gc2gcs(double x, double y, double z);              // 地心直角坐标转换为大地坐标
Vector3d gcs2gc(Vector3d BLH);                              // 大地坐标转换为地心直角坐标
Vector3d gc2gcs(Vector3d XYZ);                              // 地心直角坐标转换为大地坐标
Vector3d gc2gcs(double x, double y, double z);              // 地心直角坐标转换为大地坐标
double acu_tan_l(double t, double x, double y, double z);   // 迭代计算 大地纬度L

3.2.3 IMR文件的读取与解析

IMR 文件头的组织架构

struct IMR_Header
{
    char szHeader[8];				// "$IMURAW\0"
    int8_t bIsIntelOrMotorola;		// 0 表示小字节, 1表示大字节
    double dVersionNumber;			// 惯性资源管理器程序版本号
    int32_t bDeltaTheta;			// 0 接下来的数据将以变化的角度速率读取
                                    // 1 (默认)接下来的数据将被读取为delta,即角增量
    int32_t bDeltaVelocity;			// 0 接下来的数据将以变化的加速度读取
                                    // 1 (默认)接下来的数据将被读取为速度,即速度增量
    double dDataRateHz;				// IMU 的采样率 (Hz)
    double dGyroScaleFactor;		// bDeltaTheta == 0 将陀螺仪的测量值乘以该值得到 度/秒
                                    // bDeltaTheta == 1 将陀螺仪的测量值乘以该值得到 度,然后乘以dDataRateHz得到 度/秒
    double dAccelScaleFactor;		// bDeltaVelocity == 0 将实测数据乘以该值得到 m/s^2
                                    // bDeltaVelocity == 1 将实测数据乘以该值得到 m/s, 再乘以dDataRateHz就得到 m/s^2
    int32_t iUtcOrGpsTime;			// 将时间标记定义为一周的GPS或UTC秒
                                    // iUtcOrGpsTime == 0 未知,默认为GPS
                                    // iUtcOrGpsTime == 1 时间标签是每周的UTC秒
                                    // iUtcOrGpsTime == 2 时间标签是每周的GPS秒
    int32_t iRcvTimeOrCorrTime;		// 定义时间标记是否在第二个标称的顶部或为接收机时间偏差进行校正
    double dTimeTagBias;			// GPS和IMU时间标签之间的偏差
    char szImuName[32];				// 使用的IMU名称
    unit8_t reserved1[4];			// 暂无,留空
    char szProgramName[32];			// 调用程序名称
    char tCreate[12];				// 创建文件时间
    bool bLeverArmValid;			// 如果IMU至主GNSS天线的杆臂存储在此标头中,则为此项值为真
    int32_t lXoffset;				// 杠杆臂X mm
    int32_t lYoffset;				// 杠杆臂Y mm
    int32_t lZoffset;				// 杠杆臂Z mm
    int8_t Reserved[354];			// 留作未来使用
};

IMR 数据结构:

struct IMR_Record
{
    double Time;		// 当前观测的时间
    int32_t gx;			// 关于IMU x轴的缩放陀螺测量量
    int32_t gy;			// 关于IMU y轴的缩放陀螺测量量
    int32_t gz;			// 关于IMU z轴的缩放陀螺测量量
    int32_t ax;			// 关于IMU x轴的缩放加速测量
    int32_t ay;			// 关于IMU y轴的缩放加速测量
    int32_t az;			// 关于IMU z轴的缩放加速测量
};

struct adj_IMR_Record
{
    double Time;		// 当前观测的时间
    double gx;			// 关于IMU x轴的缩放陀螺测量量
    double gy;			// 关于IMU y轴的缩放陀螺测量量
    double gz;			// 关于IMU z轴的缩放陀螺测量量
    double ax;			// 关于IMU x轴的缩放加速测量
    double ay;			// 关于IMU y轴的缩放加速测量
    double az;			// 关于IMU z轴的缩放加速测量
};

IMR数据读取结构

class imr_data
{
public:
    IMR_Header* file_header;
    vector<adj_IMR_Record> file_data;
    void read_data(char* filepath);
    void initial();
private:
    void read_imr_header(fstream& imrfile, IMR_Header* imrheader);
    void read_imr_data(fstream& imrfile, vector<adj_IMR_Record>& adj_data, IMR_Header imr_header);
};

3.2.4 姿态、速度、位置更新

class update
{
public:
    // 存放m-1时刻的方向余弦阵,存放m,m-1时刻的采样数据分别于vector[2],vecotr[1],存放m-1时刻,m-2时刻的位置数据于vector[1],vector[0],存放m-1,m-2时刻的速度数据于vector[1],vector[0], 存放采样周期
    update(Direct_cosine_matrix a1, vector<Vector3d> a2, vector<Vector3d> a3, vector<Vector3d> a4, vector<Vector3d> a5, double a7);
    void initialize(Direct_cosine_matrix a1, vector<Vector3d> a2, vector<Vector3d> a3, vector<Vector3d> a4, vector<Vector3d> a5, double a7);    // 初始化函数
    input_data inputdata;   // 输入数据
    attitude_updating_data attitude_data;           // 姿态更新结果
    vector<speed_updating_data> speed_data;         // 速度更新结果,通常存放三次速度更新结果,[0] m-2 时刻的速度更新,[1],m -1 时刻的速度更新,[2],m 时刻的速度更新
    vector<position_updating_data> position_data;   // 位置更新结果,通常存放三次位置更新结果,[0] m-2 时刻的位置,[1],m-1 时刻的位置,[2],m 时刻的速度更新
    vector<position_updating_data> position_result; // 存放结果
    void attitude_update();		// 姿态更新
    void speed_update();		// 速度更新
    void position_update();		// 位置更新
    void initial_alignment();	// 初始对准
    // 定义通用变量
private:
    double sinl, cosl, tanl;
    double Rm;
    double Rn;
    double Rmh;
    double Rnh;
};

4 软件概述及功能介绍

4.1 概述

  1. 操作系统:Windows 10

  2. IDE:Microsoft Visual Studio 2015

  3. 程序语言:C++ 11

  4. 主程序文件构成:GPSsolving.h GPSsolving.cpp question.cpp

矩阵类文件构成:Matrix.h Matrix.cpp

4.2软件功能概述

软件功能如下图所示:
在这里插入图片描述

本惯性导航数据解算软件主要基于Qt开发,主要实现了下述的一些功能:

  1. 在数据解算方面,软件实现了IMR数据文件的解算读取、初始姿态数据的保存、惯导数据的解算(其中包括了欧拉角、方形余弦阵、四元数、等效旋转矢量的转换、大地坐标与地心直角坐标相互转换、地理坐标系的姿态更新、速度更新、位置更新、解析粗对准等功能)。

  2. 在数据的存储方面、主要实现了解算数据的存储、打开、绘图功能、绘图结果的存储、软件日志的存储。

  3. 在软件功能方面,软件实现了日志功能、撰写了相应的帮助文档、通过邮件联系作者以及切换软件界面视图等功能。

5 程序运行介绍

  1. IMR文件读取

在这里插入图片描述

  1. 初始解算数据保存
    在这里插入图片描述

  2. 进行粗对准

在这里插入图片描述

  1. 解算惯导数据

在这里插入图片描述

  1. 绘图显示

在这里插入图片描述

  1. 软件初始化

在这里插入图片描述

  1. 数据保存

在这里插入图片描述

  1. 数据导入

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  1. 保存图片显示与程序日志

在这里插入图片描述

在这里插入图片描述

  1. 程序帮助文档与界面切换

在这里插入图片描述

在这里插入图片描述

  • 26
    点赞
  • 199
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
实现惯性导航的C语言程序需要使用传感器(如加速度计、陀螺仪、磁力计等)采集飞行器的运动状态,并根据导航算法计算出飞行器的位置、速度和姿态等信息。 以下是一个简单的惯性导航C语言程序的示例代码: ```c #include <stdio.h> #include <math.h> #define PI 3.14159265358979323846 #define RAD_TO_DEG (180/PI) #define G 9.81 int main() { // 初始化变量 double dt = 0.01; // 时间间隔 double ax = 0, ay = 0, az = 0; // 加速度计读数 double gx = 0, gy = 0, gz = 0; // 陀螺仪读数 double mx = 0, my = 0, mz = 0; // 磁力计读数 double pitch = 0, roll = 0, yaw = 0; // 姿态角 double vx = 0, vy = 0, vz = 0; // 速度 double x = 0, y = 0, z = 0; // 位置 // 循环采集传感器数据并更新导航信息 while (1) { // 读取传感器数据 // TODO: 实现传感器数据的读取 // 计算欧拉角 roll = atan2(ay, sqrt(ax*ax + az*az)) * RAD_TO_DEG; pitch = atan2(-ax, sqrt(ay*ay + az*az)) * RAD_TO_DEG; yaw = atan2(my, mx) * RAD_TO_DEG; // 计算加速度在地球坐标系下的分量 double ax_n = ax * cos(pitch/RAD_TO_DEG) * cos(yaw/RAD_TO_DEG); double ay_n = ay * cos(pitch/RAD_TO_DEG) * sin(yaw/RAD_TO_DEG); double az_n = -G + ax * sin(pitch/RAD_TO_DEG); // 计算速度 vx += ax_n * dt; vy += ay_n * dt; vz += az_n * dt; // 计算位置 x += vx * dt; y += vy * dt; z += vz * dt; // 输出导航信息 printf("Pitch: %.2f, Roll: %.2f, Yaw: %.2f\n", pitch, roll, yaw); printf("Vx: %.2f, Vy: %.2f, Vz: %.2f\n", vx, vy, vz); printf("X: %.2f, Y: %.2f, Z: %.2f\n", x, y, z); // TODO: 实现延时函数,控制循环时间间隔 } return 0; } ``` 需要注意的是,该示例代码仅为演示用途,实际应用中需要根据具体的传感器和导航算法进行相应的修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值