基于加速度传感器计算位置信息的学习过程

该文详细阐述了一种利用三轴传感器进行加速度测量并计算物体位置的算法,包括校准以去除重力加速度影响,采用低通滤波减少噪声,设定机械滤波窗口识别静止状态,以及通过双重积分确定位置。同时,文章还介绍了数据传输处理,确保32位数据能通过8位接口有效发送。
摘要由CSDN通过智能技术生成

一下内容是对这篇文章的解读

【翻译】利用加速度求解位置的算法——三轴传感器 - cposture - 博客园

1. 校准程序

原文解释:

    这个校准程序移除了加速度传感器的输出偏移分量,因为存在重力加速度(静态的加速度)。

    校准程序在加速度计处于无运动状态时,对加速度求平均值。采样的数量越多,加速度的校准结果越精确。

voidCalibrate(void)
{
    unsignedint count1;
    count1 =0;
    do{
    ADC_GetAllAxis();
    sstatex = sstatex +Sample_X;// Accumulate Samples
    count1++;
    }while(count1!=0x0400);// 1024 times
    sstatex=sstatex>>10;// division between 1024
}

理解解读:

这一步的意思就是将本身z轴上的加速度给求出来,然后方便后面算运动产生的加速度(用当时滤波取出的加速度减此处算出的初始的加速度)。

在do-while循环中进行对sstatex的累加,累加完0x0400(1024次)后,用>>10位的方式进行取平均值,左移10位和除以1024是等价的,之前一直不理解这一步的取均值在哪。

2. 滤波

原文解释:

低通滤波是消除加速度计中信号噪音(包括机械的和电子的)很好的方法。为了当对信号进行积分时减少大部分的错误,减少噪音对定位应用是至关重要的。

    一个简单的低通过滤采样信号的方式是执行滚动平均值。过滤简单地获得一组采样的平均值,获得稳定的采样总数的平均值是很重要的。采样数太多可能造成数据丢失,而太少又可能导致结果不精确。

do{
    accelerationx[1]=accelerationx[1]+Sample_X;//filtering routine for noise attenuation
    count2++;// average represents the acceleration of
    // an instant.
}while(count2!=0x40);// 64 sums of the acceleration sample
accelerationx[1]= accelerationx[1]>>6;// division by 64

理解解读

将每一次的加速度输出结果accelerationx[1]进行64次叠加然后取均值得到数据滤波效果。

3. 机械滤波窗口

原文解释

    当处于无运动状态时,加速度上的微小错误可能会被当作一个常量速度,因为在采样值加和之后,它并不等于0。在没有运动的理想情况下,所有的采样值都为0。该常速表示一个连续的移动和不稳定的位置。

    即使之前过滤的一些数据可能不正确,因此一个用于区别无运动状态的"有效数据"和"无效数据"的窗口必须实现。

1 if ((accelerationx[1] <=3)&&(accelerationx[1] >= -3)) //Discrimination window applied to
2 {
3     accelerationx[1] = 0;
4 } // the X axis acceleration variable

理解解读

当某个时间微元中的加速度值在3和-3的范围中时我们判定此时对象的运动状态是停止的。

4. 定位

原文解释

2b06af1e6227accab4f738ecc3270b5e.png

二重积分是利用加速度数据获取位置所需要的步骤。第一次积分获得速度,第二次积分获得位置。

1 //first integration
2 velocitx[1]= velocitx[0]+ accelerationx[0]+((accelerationx[1]- accelerationx[0])>>1)
3 //second integration
4 positionX[1]= positionX[0]+ velocitx[0]+((velocitx[1]- velocitx[0])>>1);

 5. 数据传输

原文解释

这部分主要目的是用于调试和显示;这个函数中32位的结果被切割分4个8位数据。

if (positionX[1]>=0)
{ //This line compares the sign of the X direction data
    posx_seg[0]= positionX[1] & 0x000000FF; // is set to 1 else it is set to 8
    posx_seg[1]= (positionX[1]>>8) & 0x000000FF; // the data is also managed in the
    // subsequent lines in order to be sent.
    posx_seg[2]= (positionX[1]>>16) & 0x000000FF;// The 32 bit variable must be split into
    posx_seg[3]= (positionX[1]>>24) & 0x000000FF;// 4 different 8 bit variables in order to
    // be sent via the 8 bit SCI frame
}
else
{
    positionXbkp=positionX[1]-1;
    positionXbkp=positionXbkp^0xFFFFFFFF;
    posx_seg[0]= positionXbkp & 0x000000FF;
    posx_seg[1]= (positionXbkp>>8) & 0x000000FF;
    posx_seg[2]= (positionXbkp>>16) & 0x000000FF;
    posx_seg[3]= (positionXbkp>>24) & 0x000000FF;
}

 以上是我对开头的文章的初步解读,但还没实际运用,而且也是第一次啃这么硬的文章,如果用错误的地方,欢迎大家指出让我学习。

我发现原文的例程没有tab而且没有空行看起来太难受了,我翻译了部分函数解释和加入了基本的tab希望能够帮助大家理解

#include <hidef.h>
#include "derivative.h"
#include "adc.h"
#include "buzzer.h"
#include "SCItx.h"
#pragma DATA_SEG MY_ZEROPAGE
unsigned char near Sample_X;
unsigned char near Sample_Y;
unsigned char near Sample_Z;
unsigned char near Sensor_Data[8];
unsigned char near countx,county ;
signed int near accelerationx[2], accelerationy[2];
signed long near velocityx[2], velocityy[2];
signed long near positionX[2];
signed long near positionY[2];
signed long near positionZ[2];
unsigned char near direction;
unsigned long near sstatex,sstatey;
#pragma DATA_SEG DEFAULT
void init(void);
void Calibrate(void);
void data_transfer(void);
void concatenate_data(void);
void movement_end_check(void);
void position(void);
void main (void)
{
 init();
 get_threshold();
 do
 {
 position();
 }while(1);
}
/*******************************************************************************
校准例程的目的是获得参考阈值的值。

在无运动条件下,它由1024个样本平均值组成。
********************************************************************************/
void Calibrate(void)
{
	 unsigned int count1;
	 count1 = 0;
	 
	 do{
		 ADC_GetAllAxis();
		 sstatex = sstatex + Sample_X; // 积累的样本
		 sstatey = sstatey + Sample_Y;
		 count1++;
	 }while(count1!=0x0400); // 1024 times
	 
	 
	 sstatex=sstatex>>10; // division between 1024
	 sstatey=sstatey>>10;
}
/*****************************************************************************************/
/******************************************************************************************
这个函数得到大小和方向

在这个特殊的协议中,方向和大小以不同的变量发送。

管理可以通过许多其他不同的方式来完成。
*****************************************************************************************/
void data_transfer(void)
{
	 signed long positionXbkp;
	 signed long positionYbkp;
	 unsigned int delay;
	 unsigned char posx_seg[4], posy_seg[4];
	 if (positionX[1]>=0)
	 { //这一行比较X方向数据的符号
		 direction= (direction | 0x10); //如果它是正的,那就是最高位字节
		 posx_seg[0]= positionX[1] & 0x000000FF; // is set to 1 else it is set to 8
		 posx_seg[1]= (positionX[1]>>8) & 0x000000FF; // the data is also managed in the
		 // subsequent lines in order to
		 posx_seg[2]= (positionX[1]>>16) & 0x000000FF; // be sent. The 32 bit variable must be
		 posx_seg[3]= (positionX[1]>>24) & 0x000000FF; // split into 4 different 8 bit
		 // variables in order to be sent via
		 // the 8 bit SCI frame
	}
	else {direction=(direction | 0x80);
		 positionXbkp=positionX[1]-1;
		 positionXbkp=positionXbkp^0xFFFFFFFF;
		 posx_seg[0]= positionXbkp & 0x000000FF;
		 posx_seg[1]= (positionXbkp>>8) & 0x000000FF;
		 posx_seg[2]= (positionXbkp>>16) & 0x000000FF;
		 posx_seg[3]= (positionXbkp>>24) & 0x000000FF;
	}
	if (positionY[1]>=0) { // Same management than in the previous case
		 direction= (direction | 0x08); // but with the Y data.
		 posy_seg[0]= positionY[1] & 0x000000FF;
		 posy_seg[1]= (positionY[1]>>8) & 0x000000FF;
		 posy_seg[2]= (positionY[1]>>16) & 0x000000FF;
		 posy_seg[3]= (positionY[1]>>24) & 0x000000FF;
	}
	else {direction= (direction | 0x01);
		 positionYbkp=positionY[1]-1;
		 positionYbkp=positionYbkp^0xFFFFFFFF;
		 posy_seg[0]= positionYbkp & 0x000000FF;
		 posy_seg[1]= (positionYbkp>>8) & 0x000000FF;
		 posy_seg[2]= (positionYbkp>>16) & 0x000000FF;
		 posy_seg[3]= (positionYbkp>>24) & 0x000000FF;
	}
	 delay = 0x0100;
	 Sensor_Data[0] = 0x03;
	 Sensor_Data[1] = direction;
	 Sensor_Data[2] = posx_seg[3];
	 Sensor_Data[3] = posy_seg[3];
	 Sensor_Data[4] = 0x01;
	 Sensor_Data[5] = 0x01;
	 Sensor_Data[6] = END_OF_FRAME;
	 while (--delay);
	 SCITxMsg(Sensor_Data); // Data transferring function
	 while (SCIC2 & 0x08);
}
/*****************************************************************************************/
/******************************************************************************************
这个函数将数据格式返回到原始状态。当得到大小和

在位置的方向上,做一个逆二补。这个函数等于2

补充,以便将数据返回到原始状态。

重要的是要注意,灵敏度调整在这里受到很大的影响

在掩模中插入的“1”必须等于在移位中丢失的“1”

对前面的功能进行敏感性修改。
 ******************************************************************************************/
void data_reintegration(void)
{
	 if (direction >=10)
	{
		positionX[1]= positionX[1]|0xFFFFC000;
	} 
	// 18 "ones" inserted. Same size as the
	 //amount of shifts
	 
	 direction = direction & 0x01;
	 if (direction ==1)
	 {
		positionY[1]= positionY[1]|0xFFFFC000;
	}
}
/******************************************************************************************
此功能允许运动结束检测。如果有一定数量的加速度样本

等于0,我们可以假设运动停止了。速度产生的累积误差

通过重新设置速度变量来消除计算。这将停止位置增量

并大大消除了位置误差。
******************************************************************************************/
void movement_end_check(void)
{
	if (accelerationx[1]==0) //we count the number of acceleration samples that equals cero
	{ countx++;}
		else { countx =0;}
		if (countx>=25) //if this number exceeds 25, we can assume that velocity is cero
		{
			velocityx[1]=0;
			velocityx[0]=0;
		}
	if (accelerationy[1]==0) //we do the same for the Y axis
	{ county++;}
	else { county =0;}
	if (county>=25)
	{
		velocityy[1]=0;
		velocityy[0]=0;
	}
}
/*****************************************************************************************/
/******************************************************************************************
这个函数通过积分将加速度转换成一个比例位置

两次加速数据。它还通过乘以“positionX”和来调整灵敏度

“positionY”变量。

这个积分算法带有误差,在“movenemt_end_check”中得到补偿。

子例程。更快的采样频率意味着更少的错误,但需要更多的内存。保持

记住,同样的过程也适用于X轴和Y轴
*****************************************************************************************/
void position(void)
{
	unsigned char count2 ;
	count2=0;

	 do{
		 ADC_GetAllAxis();
		 accelerationx[1]=accelerationx[1] + Sample_X; //filtering routine for noise attenuation
		 accelerationy[1]=accelerationy[1] + Sample_Y; //64 samples are averaged. The resulting
		//average represents the acceleration of
		 //an instant
		 count2++;
	 }
	 while (count2!=0x40); // 64 sums of the acceleration sample
	 
	 
	 accelerationx[1]= accelerationx[1]>>6; // division by 64
	 accelerationy[1]= accelerationy[1]>>6;
	 accelerationx[1] = accelerationx[1] - (int)sstatex; //eliminating zero reference
	 //offset of the acceleration data
	 accelerationy[1] = accelerationy[1] - (int)sstatey; // to obtain positive and negative
	 
	 
	 //acceleration
	 if ((accelerationx[1] <=3)&&(accelerationx[1] >= -3)) //Discrimination window applied
	 {accelerationx[1] = 0;} // to the X axis acceleration
	 
	 
	 //variable
	 if ((accelerationy[1] <=3)&&(accelerationy[1] >= -3))
	 {accelerationy[1] = 0;}
	 
	 
	 //first X integration:
	velocityx[1]= velocityx[0]+ accelerationx[0]+ ((accelerationx[1] -accelerationx[0])>>1);
	 //second X integration:
	positionX[1]= positionX[0] + velocityx[0] + ((velocityx[1] - velocityx[0])>>1);
	 //first Y integration:
	velocityy[1] = velocityy[0] + accelerationy[0] + ((accelerationy[1] -accelerationy[0])>>1);
	 //second Y integration:
	positionY[1] = positionY[0] + velocityy[0] + ((velocityy[1] - velocityy[0])>>1);
	
	
	 accelerationx[0] = accelerationx[1]; //The current acceleration value must be sent
	//to the previous acceleration
	 accelerationy[0] = accelerationy[1]; //variable in order to introduce the new
	//acceleration value.
	
	
	 velocityx[0] = velocityx[1]; //Same done for the velocity variable
	 velocityy[0] = velocityy[1];
	 positionX[1] = positionX[1]<<18; //The idea behind this shifting (multiplication)
	 //is a sensibility adjustment.
	 positionY[1] = positionY[1]<<18; //Some applications require adjustments to a
	 //particular situation
	 //i.e. mouse application
	 data_transfer();
	 positionX[1] = positionX[1]>>18; //once the variables are sent them must return to
	 positionY[1] = positionY[1]>>18; //their original state
	 movement_end_check();
	 positionX[0] = positionX[1]; //actual position data must be sent to the
	 positionY[0] = positionY[1]; //previous position
	 direction = 0; // data variable to direction variable reset
}
/*****************************************************************************************/

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 基于STM32F103的ADXL345加速度传感器程序可以通过以下步骤实现: 1. 配置STM32F103的GPIO引脚,将SCL和SDA引脚连接到ADXL345的SCL和SDA引脚。 2. 初始化I2C总线,使用STM32F103的I2C模块来与ADXL345进行通信。设置ADXL345的I2C地址,并使能I2C总线。 3. 配置ADXL345的寄存器,设置测量范围、输出数据速率等参数。可以使用I2C总线向ADXL345的控制寄存器写入配置数据。 4. 进入连续测量模式,使ADXL345开始采集加速度数据,并存储在其数据寄存器中。 5. 使用I2C总线读取ADXL345的数据寄存器,将加速度数据读取到STM32F103的缓冲区中。 6. 对读取的加速度数据进行解析和处理,如进行单位转换和数据滤波等操作。 7. 将处理后的加速度数据用于其他应用或进行进一步分析。 8. 可以在程序中设置一个延时,来控制采样频率,以控制ADXL345的数据输出速率。 9. 程序可以通过串口或其他方式将加速度数据输出,也可以使用LCD显示屏等外设进行实时显示。 需要注意的是,在实现该程序时,需要参考STM32F103的开发文档和ADXL345的数据手册,了解其I2C通信协议和寄存器配置等相关信息。同时,还需根据具体的应用需求进行适当的修改和优化。 ### 回答2: 基于STM32F103的ADXL345加速度传感器程序的开发可以分为以下几个步骤: 1. 硬件连接:将ADXL345与STM32F103连接,通过I2C接口进行数据传输。根据硬件接口和引脚连接规格进行正确的连接。 2. 初始化配置:在STM32F103的程序中,首先需要对IIC总线进行初始化配置,包括设置时钟速率、IIC模式等。接着需要对ADXL345进行初始化配置,包括设置测量范围、数据输出率等。 3. 数据读取:在程序中使用I2C读取数据的函数,从ADXL345中读取加速度数据。可以使用连续读取模式,读取X、Y、Z轴的加速度数据,然后进行数据处理。 4. 数据处理:读取到的原始加速度数据是16位的,需要进行数据转换和处理。可以根据ADXL345的配置参数和数据格式,通过相应的转换公式将原始数据转换为实际的加速度值。 5. 数据应用:将处理后的加速度数据应用到具体的应用场景中。例如可以用于姿态检测、运动检测等,根据具体的需求进行相应的应用开发。 需要注意的是,为了确保程序的准确性和稳定性,还需要进行异常处理,如通信异常、超时等情况的处理。同时,根据具体的要求和功能开发,可能还需要进行数据滤波、校准等处理,以提高传感器的精度和稳定性。 整个程序开发过程中,需要根据ADXL345的数据手册和STM32F103的技术手册进行相应的开发和调试。最终,通过编译、下载和运行代码,在STM32F103上成功读取并处理ADXL345的加速度数据。 ### 回答3: 基于STM32F103的ADX345加速度传感器程序主要包括以下几个步骤: 1. 硬件连接:确保ADX345传感器正确连接到STM32F103开发板上。ADX345传感器一般使用I2C或SPI接口与STM32F103通信。根据实际情况选择连接方式,并确保连接正确。 2. 寄存器初始化:使用STM32F103的I2C或SPI接口向ADX345传感器写入初始化参数,包括传感器工作模式、采样率等。 3. 数据读取:使用STM32F103的I2C或SPI接口从ADX345传感器读取加速度数据。根据ADX345传感器的数据格式,进行相应的数据解析。 4. 数据处理和应用:获取到的加速度数据可以进行各种处理和应用。例如,可以计算加速度的绝对值、角度、速度等;或者根据具体需求进行其他各种数据处理和应用。 5. 输出结果:可以通过串口、LCD显示屏或其他外设输出加速度数据。根据实际需求选择相应的输出方式,并将处理后的数据进行格式化输出。 编写ADX345加速度传感器程序需要熟悉STM32F103的编程和外设驱动,同时了解ADX345传感器的工作原理和数据格式。根据具体需求,可以进一步扩展和优化程序,实现更多功能和应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值