基于STM32读取SBG Ellipse A型号惯导数据

2023-05-16

之前在飞控上用的都是mpu6050,但AUV在执行任务时主要在水下环境,收不到GPS信号,因此对INS的精度要求较高,在姿态解算时要考虑地球自转等因素,因此需要一款惯导器件能够感受到地球自转,经测量,SBG公司生产的Ellipse A并不能满足要求。下面介绍一下采集系统的软件架构。

组合导航系统需要同时采集多种传感器,进行多传感器融合,以提高导航系统精度。初步准备用SBG和GPS进行融合,将GPS的更新频率降低到1Hz以模拟USBL的水环境状况,本篇文章仅介绍读取SBG部分。

SBG传感器使用的接口是RS232,说到此惭愧不已,因为学术不精,最开始直接用USB转TTL线来读数据,结果在串口助手上看到的全是乱码。

虽然都是串口设备,RS-232的通讯电平:逻辑1是-15V~-3V,逻辑0是+3V~+15V,而TTL的通讯电平:逻辑1是2.4V~5V,逻辑0是0~0.5V。从电压等级也可以看出RS-232的远距离传输和抗干扰能力更强一些。

下面看一下sbg的协议格式

 除了帧头以外,协议规定了消息ID和消息类,简单的说,消息类用于区分消息内容是传感器数据还是需要执行的命令,消息ID中将数据进行了分类,我只需要加速度计测得的加速度值和陀螺仪测得的角速度值。

读取数据协议的策略是这样的,当传感器向stm32的串口发送数据时,就会使能相应的串口中断,每中断一次接收1个字节,因此在中断函数中需要一个预处理部分,将需要解读的一组完整的imu数据存入缓存区。中断函数如下:

void USART2_IRQHandler(void)
{
	uint8_t ch;
	if(USART_GetITStatus(USART2,USART_IT_RXNE)) {
			USART_ClearITPendingBit(USART2, USART_IT_RXNE);	
			ch=USART_ReceiveData(USART2);
			SBG_Data_Receive_Prepare(ch);
	}	 
}

最初我犯了一个低级错误,将读取数据分成了两部分,一部分是将数据存入缓存区,第二部分是将缓存区数据按协议解析。这本没有问题,但是我将第一部分放在了串口中断中,将第二部分放在了定时器中断中每5ms解析一次。虽听起来不错,但有个严重的问题,当协议解析的时候并不能保证缓存区中是一组完整的数据,这就导致了读出来的数每隔几十个就会有组极大值。

正确的做法是将两部分写在同一流程中,也就是一起放到串口中断中,待数组存放完全,再去解析,而定时器则每5ms调用一次解析出的数据进行融合等操作,这样就没有问题了~

下面为两部分的函数实现:

数据预处理

extern uint8_t SBG_Data[100];
u8 sbg_data_state = 0;
u16 _data_len = 0,_data_cnt = 0;
void SBG_Data_Receive_Prepare(u8 data)
{
	//static u16 _data_len = 0,_data_cnt = 0;
	//static u8 sbg_data_state = 0;
	
	if(sbg_data_state==0&&data==0xFF) {
		sbg_data_state=1;
		_data_cnt = 0;
		SBG_Data[_data_cnt]=data;//0
		_data_cnt++;//1
	}
	else if(sbg_data_state==1&&data==0x5A) {
		sbg_data_state=2;
		SBG_Data[_data_cnt]=data;//1
		_data_cnt++;//2
	}
	else if(sbg_data_state==2&&data==0x03) {
		sbg_data_state=3;
		SBG_Data[_data_cnt]=data;//2
		_data_cnt++;//3
	}
	else if(sbg_data_state==3&&data==0x00) {
		sbg_data_state=4;
		SBG_Data[_data_cnt]=data;//3
		_data_cnt++;//4
	}
	else if(sbg_data_state==4&&_data_cnt<67) {
		SBG_Data[_data_cnt]=data;
		_data_cnt++;
		if(_data_cnt==67) {
			GET_SBG_DATA(SBG_Data);
		}
	}
	else
		sbg_data_state = 0;
}

 

union 
{
	float a;
	uint8_t b[4];
} hex_receive;
float hex2flo(uint8_t *buffer)
{
	int i = 0;
	for(i = 0; i < 4; i++) hex_receive.b[i] = *(buffer+i);
	return hex_receive.a;
}

/*!
* Compute a CRC for a specified buffer.
* \param[in] pBuffer Read only buffer to compute the CRC on.
* \param[in] bufferSize Buffer size in bytes.
* \return The computed 16 bit CRC.
*/
u16 calcCRC(const void *pBuffer, u16 bufferSize)
{
		const u8 *pBytesArray = (const u8*)pBuffer;
		u16 poly = 0x8408;
		u16 crc = 0;
		u8 carry;
		u8 i_bits;
		u16 j;
		for (j =0; j < bufferSize; j++)
		{
				crc = crc ^ pBytesArray[j];
				for (i_bits = 0; i_bits < 8; i_bits++)
				{
						carry = crc & 1;
						crc = crc / 2;
						if (carry)
						{
								crc = crc^poly;
						}
				}
		}
		return crc;
}
/******************»ñÈ¡SBGÊý¾Ý******************/
  u16 SBG_Cnt = 0;
	u32 TIME_STAMP; //Time since sensor is powered up
	u16 IMU_STATUS; //IMU Status bitmask
float ACCEL_X, ACCEL_Y, ACCEL_Z;   //Filtered Accelerometer - X axis
float GYRO_X, GYRO_Y, GYRO_Z;  //Filtered Gyroscope - X axis
float ACCEL_X_past, ACCEL_Y_past, ACCEL_Z_past;   //Filtered Accelerometer - X axis
float GYRO_X_past, GYRO_Y_past, GYRO_Z_past;  //Filtered Gyroscope - X axis
   u8    state_ins = 0;//0±íʾpastδ¸üÐÂ
float TEMP;  //Internal Temperature
float DELTA_VEL_X, DELTA_VEL_Y, DELTA_VEL_Z;  //Sculling output - X axis
float DELTA_ANGLE_X, DELTA_ANGLE_Y, DELTA_ANGLE_Z;   //Coning output - X axis
float ROLL, PITCH, YAW;
float Q0, Q1, Q2, Q3;
float MAG_X, MAG_Y, MAG_Z;
	u16 CRC_Num;
	u16 CRC_Receive;
	u16 Data_Len;
void GET_SBG_DATA(uint8_t *data_buf)//´«ÈëSBG_Data[0]
{
	/*IEEE754: 1λ·ûºÅ룬8λָÊý£¬23λβÊý(СÊý²¿·Ö)*/
	if(!(*(data_buf+0)==0xFF && *(data_buf+1)==0x5A)) return;
	Data_Len = ((vs16)(*(data_buf+5)<<8)|*(data_buf+4));
	if(*(data_buf+6+Data_Len+2)!=0x33) return;
	/*
	******************************************************************************
  * @name    SBG_ECOM_LOG_IMU_DATA
  * @MSGid   0x03
  * @brief   Includes IMU status, acc., gyro, temp delta speeds and delta angles values
	* @ps      Just DATA, no CRC, ETX
  ******************************************************************************
	*/
	if(*(data_buf+2)==0x03 && *(data_buf+3)==0x00) {
			
			CRC_Num       =  calcCRC((data_buf+6), Data_Len);
			CRC_Receive   =  ((vs16)(*(data_buf+65)<<8)|*(data_buf+64));
	//		if(CRC_Num == CRC_Receive) {
					TIME_STAMP    =  ((vs32)(*(data_buf+9)<<24)|(*(data_buf+8)<<16)|(*(data_buf+7)<<8)|(*(data_buf+6)));
					IMU_STATUS    =  ((vs16)(*(data_buf+11)<<8)|*(data_buf+10));
					ACCEL_X       =  hex2flo(data_buf+12);
					ACCEL_Y       =  hex2flo(data_buf+16);
					ACCEL_Z       =  hex2flo(data_buf+20);
					GYRO_X        =  hex2flo(data_buf+24);
					GYRO_Y        =  hex2flo(data_buf+28);
					GYRO_Z        =  hex2flo(data_buf+32);
					TEMP          =  hex2flo(data_buf+36);
					DELTA_VEL_X   =  hex2flo(data_buf+40);
					DELTA_VEL_Y   =  hex2flo(data_buf+44);
					DELTA_VEL_Z   =  hex2flo(data_buf+48);
					DELTA_ANGLE_X =  hex2flo(data_buf+52);
					DELTA_ANGLE_Y =  hex2flo(data_buf+56);
					DELTA_ANGLE_Z =  hex2flo(data_buf+60);

	}
	/*
	******************************************************************************
  * @name    SBG_ECOM_LOG_EKF_EULER
  * @MSGid   0x06
  * @brief   Includes roll, pitch, yaw and their accuracies on each axis
  ******************************************************************************
	*/
	else if(*(data_buf+2)==0x06 && *(data_buf+3)==0xFF) {
			//LEN:data_buf+4   data_buf+5 
			//TIME_STAMP = ((vs32)(*(data_buf+6)<<24)|(*(data_buf+7)<<16)|(*(data_buf+8)<<8)|(*(data_buf+9)));
			//IMU_STATUS = ((vs16)(*(data_buf+10)<<8)|*(data_buf+11));
			ROLL   =  hex2flo(data_buf+10);
			PITCH  =  hex2flo(data_buf+14);
			YAW    =  hex2flo(data_buf+18);
	}
	/*
	******************************************************************************
  * @name    SBG_ECOM_LOG_EKF_QUAT
  * @MSGid   0x07
  * @brief   Includes the 4 quaternions values
  ******************************************************************************
	*/
	else if(*(data_buf+2)==0x07 && *(data_buf+3)==0xFF) {
			Q0 = hex2flo(data_buf+10);
			Q1 = hex2flo(data_buf+14);
			Q2 = hex2flo(data_buf+18);
			Q3 = hex2flo(data_buf+22);
	}
	/*
	******************************************************************************
  * @name    SBG_ECOM_LOG_MAG
  * @MSGid   0x04
  * @brief   Magnetic data with associated accelerometer on each axis
  ******************************************************************************
	*/
	else if(*(data_buf+2)==0x04 && *(data_buf+3)==0xFF) {
			MAG_X = hex2flo(data_buf+12);
			MAG_Y = hex2flo(data_buf+16);
			MAG_Z = hex2flo(data_buf+20);
	}
	else {
			SBG_Cnt = 0;
	}
	
}

值得注意的是,在解析时,我们应该注意大小端,即传感器先发送的字节是高8位还是低8位。第二个需要注意的点就是,SBG传输的float数据格式是IEEE754格式,因此并不能用位操作去直接合并,一个小技巧是使用union联合体,在联合体中定义一个float和一个有4个元素的字符数组,这样当我们把收到的字节依次传入数组中后,float变量就是我们要的值。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于STM32读取SBG Ellipse A型号惯导数据 的相关文章

随机推荐

  • 最新ChatGPT GPT-4 NLU实战之智能多轮对话机器人(附ipynb与python源码及视频)——开源DataWhale发布入门ChatGPT技术新手从0到1必备使用指南手册(七)

    目录 前言最新ChatGPT GPT 4 自然语言理解NLU实战之智能多轮对话机器人概述分类不是万物都要ChatGPT的任务对话机器人设计要点 以订餐机器人设计为例使用目的使用方法消息查询 存储消息解析实时干预更新策略 敏感性检查 xff0
  • SIM868模块+Arduino将位置信息上传到服务器

    SIM868模块 43 Arduino将位置信息上传到服务器 一 简要介绍 商家提供的资料中 xff0c 有将GPS信息发送到OneNet平台的源码 xff0c 本文就是在此基础上进行修改 xff0c 将数据发送到自己的服务器中 二 源码
  • 登录和第三方授权(Cookie和Authorization)

    文章目录 1 登录和授权的区别2 Cookie2 1 Cookie的工作机制2 2 Cookie的作用2 3 Cookie存在的问题 xff08 了解即可 xff09 3 Authorization3 1 Basic3 2 Bearer3
  • VSCode下便捷编译运行C++代码——Code Runner配置及说明

    本文将描述如何使用VScode及其插件方便快速编译运行C 43 43 代码 下面举例均以C 43 43 为例 其他语言不再赘述 安装VSCode 官方地址配置好你的编译器路径 确保可以 如何验证 在命令行输入 若有相关信息输出则说明已配置成
  • ros如何获取topic中的md5sum及类型等

    string doQueue const ros MessageEvent lt topic tools ShapeShifter const gt amp msg event string const amp topic shared p
  • C语言使用 学习记录(1)

    本人没学过C xff0c 但是工作中赶鸭子上架 xff0c 得接触一些 对于一些开源代码 xff0c 编译配置 动态库 静态库之类的稍稍掌握了一些 xff0c 但写起代码来 xff0c 还是一头雾水 最近项目上的机会 xff0c 跟人学了些
  • 英伟达TX2的USB口无法使用的解决办法

    新做了一块TX2的底板 xff0c 但是USB口无法使用 xff0c 插上去USB设备之后什么反应都没有 这是由于官方的底板上采用INA3221芯片做了电源监控电路 xff0c 只有确保5V电源达到要求的情况下才会使能USB口 而新做的板子
  • Socket编程 ——UDP 实验报告

    一 客户端数据反射交互 xff08 1 xff09 实验内容 要求 xff1a 利用数据报套接字实现数据传输 客户端创建UDP套接字 xff0c 向指定的服务端发送数据 xff1b 服务端接收到新数据 xff0c 显示是谁发送过来的 xff
  • Ubuntn设置程序开机启动 指定浏览器

    setp1 xff1a 设置jar开机启动 xff08 非服务启动方式 xff09 1 新建启动脚本 auto start sh xff08 并基于权限命令 xff1a sudo chmod 777 auto start sh xff09
  • 企业微信开发实战:自建审批流引擎

    1 概述 企业微信上是这样介绍的 不过经本人的研究测试 xff0c 该工作流引擎的功能是比较有限的 首先只有移动端才能发起 xff0c 流程的定义是必须在企业微信控制台中定义 xff0c 而且不支持条件分支 xff0c 适用于比较简单的应用
  • CmakeLists 复杂c++工程应用实例

    project vir data process cmake minimum required VERSION 2 8 add compile options std 61 c 43 43 11 include directories us
  • ROS学习笔记7_服务端Server

    在上图所示的模型中 xff0c Client作为请求的发送端 xff0c Server端接收Client发送的指令 xff0c 并且完成topic指令的发送 其中请求的信息类型是std srvs Trigger类 xff0c 同时返回一个R
  • char和int转换

    char和int的转换有两种方式 最简单的方法就是利用ASSCII码的差值 xff0c 直接用char的值减去 0 就行了 eg xff1a char a 61 39 9 39 int a 61 a 39 0 39 或者就用atof函数 x
  • printf缓冲区踩坑

    问题 碰到了这样一段代码 经过简化的 span class token macro property span class token directive hash span span class token directive keywo
  • PSINS学习笔记---姿态解算(1)---圆锥运动

    PSINS堪称中国导航领域的福音了 计划将工具箱中常用于工程实际中的相关算法根据个人理解做个解读注释 并且利用严老师网站中公开的数据集进行测试 由于个人水平有限 料想会漏洞百出 希望大家发现了不吝赐教 xff0c 感谢 xff01 1 加载
  • 使用matlab读取excel并作图

    在写论文时无奈非要用matlab xff0c 于是用地面站把传感器数据导出到了excel xff0c 用matlab画个图 用地面站向excel中读入数据 读入完保存即可 我读的是两种传感器数据 xff0c 一个是光流的位置值 xff0c
  • 坐标系梳理

    在很久以来 xff0c 我以为世界上只有两种坐标系 n系导航系和b系机体坐标系 最近在调试厂实验期间才知道原来还有特么这么多坐标系 机体系 xff1a 无人机 潜航器这些刚体自身的坐标系 xff0c 坐标系符合右手法则 xff0c x轴为机
  • 串口通信实现Int或float类型数据传输的方法

    方法 xff1a 发送方拆分数据为多个字节 xff0c 接收方再合并 串口通信程序中发送和接受数据以字节为单位 xff0c 将int或float类型的数据拆成单个字节存放到发送字符数组中 xff0c 然后接收方按照大小端模式将其重新合并为i
  • Gazebo Plugins教程

    Overview of Gazebo plugins Gazebo插件通过标准C 43 43 类直接控制Gazebo模型 xff0c 其具有以下优点 可以控制gazebo中几乎各个方面 xff1b 容易共享 xff1b 能够在运行的系统中插
  • 基于STM32读取SBG Ellipse A型号惯导数据

    之前在飞控上用的都是mpu6050 xff0c 但AUV在执行任务时主要在水下环境 xff0c 收不到GPS信号 xff0c 因此对INS的精度要求较高 xff0c 在姿态解算时要考虑地球自转等因素 xff0c 因此需要一款惯导器件能够感受