模组知识之三轴
1. 名词释义
请问什么是三轴,什么是6轴
请问什么是加速度,陀螺仪,罗盘
- 三轴加速度
三轴加速度传感器是加速度传感器中用来测量空间加速度的传感器,即测量物体在空间中速度变化的快慢,三轴加速度传感器与单轴、两轴加速度传感器在测量原理上没有差别,他们的主要差别在于测量的维度不同,三轴加速度传感器主要是将空间加速度在X、Y、Z三个轴上进行分解,在一定的技术上三个单轴就可以变成一个三轴
先看下加速度计和陀螺仪的区别
测量类型:加速度计测量线性运动(直线运动),而陀螺仪测量旋转运动。
数据输出:加速度计输出的是加速度,单位通常是米/秒²;
陀螺仪输出的是角速度,单位通常是度/秒或弧度/秒。
(加速度的单位在国际单位制(SI)中是 米每二次方秒(meter per second squared),通常写作 m/s² 或者 m·s⁻²。这个单位用来衡量速度随时间变化的速率,即物体的速度每秒钟增加或减少多少米每秒。
加速度是一个矢量量,它不仅有大小,还有方向。加速度的方向与引起速度变化的力的方向一致。例如,在直线运动中,如果一个物体的速度在增加,那么它的加速度方向就与它的运动方向相同;反之,如果速度在减小,则加速度方向与运动方向相反)
应用:虽然两者都被用于确定设备的方向,
但加速度计更常用于测量设备的倾斜(如智能手机的屏幕方向),
而陀螺仪更常用于测量设备的转动(如无人机的航向)
通常来讲,所谓的几轴传感器,一般是泛指:加速度计(ACCELEROMETER)、陀螺仪(GYROSCOPE)、电子罗盘(COMPASS),这三类传感器
- 加速度:可以感知任意方向上的加速度,通过测量组件在某个轴向的受力情况来得到结果,表现形式为轴向的加速度大小和方向(X、Y、Z)
- 陀螺仪:通过测量自身的旋转运动状态(角速度),判断出设备当前运动状态(向前、向后、向左、向右、向上、向下),不能判断出设备的方位(东、西、南、北)。
- 电子罗盘:可以测量出当前设备与东、南、西、北四个方向上的夹角。有时候还会见到,一些设备标注装备了:磁力计(Magnetic、M-Sensor),磁力计作用和电子罗盘差不多,都是利用并测量地球磁场的传感器,磁力计测量数据之后需要自己读数,电子罗盘则进一步把测量后的结果显示出来。
6轴传感器:通常由多种3轴传感器组合而成,3轴加速度计+3轴陀螺仪
9轴传感器:就是3轴加速度计+3轴陀螺仪+3轴电子罗盘,通过欧拉角加四元数数据融合后的组合,在飞行器上是广泛应用的。
举个例子来说:当日常佩戴装备加速度计、陀螺仪、电子罗盘的智能穿戴设备时,相当于:加速计知道“我们开始运动了(监测运动中加速度)”,陀螺仪知道“我们在何时转了个身(监测运动中角速度)”、磁力计则知道“我们是运动的具体方向(监测运动方位:东南西北)”。
- 加速度:检测物体的加速度,判断倾角(三轴加速度计的原理能够用来测量角度)
- 陀螺仪:检测物体的运行方向
- 电子罗盘:检测物体的世界方位
参考链接:
[学习IMU](MEMS 三轴加速计、三轴陀螺仪、三轴磁力计)6轴IMU+磁力计,9轴传感器讲解
加速计和陀螺仪的区别
介于其测量角度的工作原理三轴加速度计无法测量偏航角
可测量俯仰角和横滚角
2. 三轴模组ADXL35
参考链接
ADXL345传感器介绍
使用IIC通讯
请看使用数据手册
-
ADXL345自动调节功耗,与输出数据速率成比例
-
数据读取方式IIC
-
ALT ADDRESS引脚处于高电平,器件的7位I2C地址是0x1D,随后为R/W位。这转化为
0x3A写入,0x3B读取。 -
通过ALT ADDRESS引脚(引脚12)接地,可以选择备用I2C地址0x53(随后为R/W位)。
-
这转化为0xA6写入,0xA7读取
IIC通讯的时序 -
ADXL345为驱动中断提供两个输出引脚:INT1和INT2。
这两个中断引脚都是推挽低阻抗引脚,其输出规格如表
1 3所 示 。 中 断 引 脚 默 认 配 置 为 高 电 平 有 效 。 设 置
DATA_FORMAT寄存器(地址0x31)中的INT_INVERT
位,可以更改为低电平有效。所有功能都可以同时使
用
每一个寄存器的研究设置是一个力气活
3.代码参考
/*
* 初始化: 角度测量+阀值触发活动中断
* /
rt_err_t triaxial_init(rt_device_t dev)
{
uint8_t init_read =0;
//打开
ADXL345_HIGH;
TRIAX_SCL_HIGH;
TRIAX_SDA_HIGH;
rt_thread_mdelay(1000);
user_iic_init_extend(&iic_ctl_triaxial);
user_read_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, ADXL345_START, &init_read);
LOG_OUT("triaxial_init=[%x]\r\n", init_read);
if(init_read == 0xE5)
{
LOG_OUT("triaxial ok\r\n");
}
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x2E,0x00); //禁用中断
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x1E,0x00); //X 偏移量 根据测试传感器的状态写入
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x1F,0x00); //Y 偏移量 根据测试传感器的状态写入
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x20,0x00); //Z 偏移量 根据测试传感器的状态写入
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x1D,0x10); //敲击阀值
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x21,0x00); //持续时间
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x22,0x00); //开始延迟
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x23,0x00); //敲击窗口
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x24,0x0A); //活动阀值
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x25,0x05); //静止阀值
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x26,0x01); //进入静止时间
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x27,0xFF); //三轴参与
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x28,0x05); //自由落体阀值
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x29,0x14); //自由落体时间
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x2A,0x00); //抑制双击检测
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x2C,0x0A); //标准默认速率
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x2D,0x08); //测量不休眠
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x31,0x0B); //测量范围,正负16g,13位模式
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x38,0xA0); //流
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x2F,0xEF); //使能中断引脚
user_write_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x2E,0x93); //使能中断
// 设置参数查看
// uint8_t data_read =0;
// for(uint8_t t=29; t<58; t++)
// {
// user_read_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, t, &data_read);
// LOG_OUT("%x=%x\r\n", t, data_read);
// }
return RT_EOK;
}
/*
* 数据读取
* /
rt_size_t triaxial_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
LOG_OUT("triaxial_read\r\n");
// int a[3][4];
// 定义了一个 3 行 4 列的二维数组
triaxial_init(NULL);
uint8_t data_buff[6] = {0};
int16_t data_xyz[ADXL345_BUFF_ROW][ADXL345_BUFF_COL] = {0};
uint8_t irq_flag = 0;
int data_x = 0;
int data_y = 0;
int data_z = 0;
uint8_t shake_flag = 0;
uint8_t *data_p = buffer;
rt_thread_mdelay(100);
user_read_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x30, &irq_flag);
LOG_OUT("irq_flag=%x\r\n", irq_flag);
for(uint8_t t=0; t<ADXL345_BUFF_ROW; t++)
{
user_iic_read_byte_more_extend(&iic_ctl_triaxial, ADXL345_ADDR, ADXL345_ADDR_X1, data_buff, 6);
//LOG_OUT("%x %x %x %x %x %x\r\n", data_buff[0], data_buff[1], data_buff[2], data_buff[3], data_buff[4], data_buff[5]);
data_xyz[t][0] = data_buff[0] | data_buff[1]<<8;
data_xyz[t][1] = data_buff[2] | data_buff[3]<<8;
data_xyz[t][2] = data_buff[4] | data_buff[5]<<8;
if(data_xyz[t][0] < 0)
data_xyz[t][0] = -data_xyz[t][0];
if(data_xyz[t][1] < 0)
data_xyz[t][1] = -data_xyz[t][1];
if(data_xyz[t][2] < 0)
data_xyz[t][2] = -data_xyz[t][2];
LOG_OUT("x=%d y=%d z=%d\r\n", data_xyz[t][0], data_xyz[t][1], data_xyz[t][2]);
rt_thread_mdelay(15);
}
user_read_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x30, &irq_flag);
LOG_OUT("irq_flag=%x\r\n", irq_flag);
rt_thread_mdelay(500);
if(TRIAX_READ == GPIO_PIN_SET)
{
LOG_OUT(">>> INT1=HIGH\r\n");
shake_flag = 1;
}
else
{
LOG_OUT(">>> INT1=LOW\r\n");
shake_flag = 0;
}
user_read_byte_extend(&iic_ctl_triaxial, ADXL345_ADDR, 0x30, &irq_flag);
LOG_OUT("irq_flag=%x\r\n", irq_flag);
//关闭
ADXL345_LOW;
TRIAX_SCL_LOW;
TRIAX_SDA_LOW;
for(uint8_t t=0; t<ADXL345_BUFF_ROW; t++)
{
data_x += data_xyz[t][0];
data_y += data_xyz[t][1];
data_z += data_xyz[t][2];
}
data_x = data_x / ADXL345_BUFF_ROW;
data_y = data_y / ADXL345_BUFF_ROW;
data_z = data_z / ADXL345_BUFF_ROW;
LOG_OUT("average x=%d y=%d z=%d\r\n", data_x, data_y, data_z);
data_x = sqrt(data_y*data_y + data_z*data_z)/data_x;
data_x = atan(data_x)*180/3.14;
data_x = 90 - data_x;
data_y = sqrt(data_x*data_x + data_z*data_z)/data_y;
data_y = atan(data_y)*180/3.14;
data_y = 90 - data_y;
data_z = sqrt(data_x*data_x + data_y*data_y)/data_z;
data_z = atan(data_z)*180/3.14;
data_z = 90 - data_z;
LOG_OUT("ret angle:x=%d y=%d z=%d\r\n", data_x, data_y, data_z);
*data_p = data_x&0xFF;
*(data_p+1) = data_y&0xFF;
*(data_p+2) = data_z&0xFF;
*(data_p+3) = shake_flag;
return RT_EOK;
}
注意0x30寄存器,读取数据后数据位清零
4. 角度计算
pitch是俯仰角,是“点头“,(在固定翼飞机中则由升降舵舵机控制)
yaw是偏航角,是‘摇头’,(在固定翼飞机中则由方向舵舵机控制)
roll是旋转角,是“翻滚”,(在固定翼飞机中则由副翼舵机控制)
换算角度
ax = atan(sqrt(y*y+z*z)/x)*180/3.14;
ay = atan(sqrt(x*x+z*z)/y)*180/3.14;
az = atan(sqrt(x*x+y*y)/z)*180/3.14
dev=sqrt( x*x+y*y)/(z);//分母是谁,就是谁的倾角
dev=atan(dev)*180/3.1416;
sprintf(str," qj %3.2f",dev)
角度转换参考
LOG_OUT("average x=%d y=%d z=%d\r\n", data_x, data_y, data_z);
data_x = sqrt(data_y*data_y + data_z*data_z)/data_x;
data_x = atan(data_x)*180/3.14;
data_x = 90 - data_x;
data_y = sqrt(data_x*data_x + data_z*data_z)/data_y;
data_y = atan(data_y)*180/3.14;
data_y = 90 - data_y;
data_z = sqrt(data_x*data_x + data_y*data_y)/data_z;
data_z = atan(data_z)*180/3.14;
data_z = 90 - data_z;
LOG_OUT("ret angle:x=%d y=%d z=%d\r\n", data_x, data_y, data_z);
分享链接
【嵌入式模块芯片开发】ADXL345的优化精确测量和角度计算(中断单次测量、卡尔曼滤波)
shineblink ADXL345传感器测量三轴加速度/倾斜角
/*******************************************************************************
* 函 数 名 : ADXL345_Get_Angle
* 函数功能 : 得到角度
* 输 入 : x,y,z:x,y,z方向的重力加速度分量(不需要单位,直接数值即可)
dir:要获得的角度.0,与Z轴的角度;1,与X轴的角度;2,与Y轴的角度.
* 输 出 : 无
* 返 回 值 :返回值:角度值.单位0.1°.
*******************************************************************************/
short ADXL345_Get_Angle(float x,float y,float z,u8 dir)
{
float temp;
float res=0; //res得到的是弧度值,需要将其转换为角度值也就是*180/3.14
switch(dir)
{
case 0: //与自然Z轴的角度
temp=sqrt((x*x+y*y))/z;
res=atan(temp);
break;
case 1: //与自然X轴的角度
temp=x/sqrt((y*y+z*z));
res=atan(temp);
break;
case 2: //与自然Y轴的角度
temp=y/sqrt((x*x+z*z));
res=atan(temp);
break;
}
return res*180/3.14*10; //乘以10是为了取一位小数,角度精确到0.1°所以要乘以10
}
- 关于角度的计算网上的资料很多,详细介绍的很少,慢慢整理