0

我正在尝试创建一个函数来查找 Arduino 上的传感器值的平均值以对其进行校准,但是总和无法正常工作,因此平均值不正确。下表显示了输出示例。左列应该是右列中显示的输出的滚动总和(负数如何进入那里?)

-10782      17112        
  6334      17116       
 23642      17308        
-24802      17092        
 -7706      17096        
  9326      17032        
 26422      17096        
-21986      17128  

应该执行此操作的calibrateSensors()函数如下所示

void calibrateSensors(int16_t * accelOffsets){

  int16_t rawAccel[3];
  int sampleSize = 2000;


  Serial.println("Accelerometer calibration in progress...");

  for (int i=0; i<sampleSize; i ++){

    readAccelData(rawAccel);        // get raw accelerometer data
    accelOffsets[0] += rawAccel[0]; // add x accelerometer values
    accelOffsets[1] += rawAccel[1]; // add y accelerometer values
    accelOffsets[2] += rawAccel[2]; // add z accelerometer values
    Serial.print(accelOffsets[2]);
    Serial.print("\t\t");
    Serial.print(rawAccel[2]);
    Serial.print("   \t FIRST I:");
    Serial.println(i);
  }

  for (int i=0; i<3; i++)
  {
    accelOffsets[i] = accelOffsets[i] / sampleSize;
    Serial.print("Second I:");
    Serial.println(i);
  }

  Serial.println("Accelerometer calibration complete");
  Serial.println("Accelerometer Offsets:");
  Serial.print("Offsets (x,y,z): ");
  Serial.print(accelOffsets[0]);
  Serial.print(", ");
  Serial.print(accelOffsets[1]);
  Serial.print(", ");
  Serial.println(accelOffsets[2]);
}

readAccelData()功能如下

void readAccelData(int16_t * destination){
  // x/y/z accel register data stored here
  uint8_t rawData[6];
  // Read the six raw data registers into data array
  I2Cdev::readBytes(MPU6050_ADDRESS, ACCEL_XOUT_H, 6, &rawData[0]);  
  // Turn the MSB and LSB into a signed 16-bit value
  destination[0] = (int16_t)((rawData[0] << 8) | rawData[1]) ;  
  destination[1] = (int16_t)((rawData[2] << 8) | rawData[3]) ;  
  destination[2] = (int16_t)((rawData[4] << 8) | rawData[5]) ; 

知道我哪里出错了吗?

4

2 回答 2

1

你有两个问题:

  1. 你不初始化你的数组。它们从其中的垃圾数据开始(分配了空间,但未清除)。您可以通过执行以下操作将数组初始化为全零:

int array[5] = {};

这将产生一个最初看起来像的数组[0,0,0,0,0]

您的第二个问题是您正在创建一个 16 位有符号整数数组。一个 16 位整数可以存储 65536 个不同的值。问题是因为您使用的是有符号类型,所以您只能使用 32767 个正整数值。当您尝试存储大于该值的值时,您会溢出并得到负数。

我相信 arduino 支持 32 位整数。如果您只想要正数,请使用无符号类型。

要使用显式 32 位整数:

#include <stdint.h>
int32_t my_int = 0;

关于标准可变尺寸的一些信息(请注意,它们可以是基于代码构建的 arduino 模型的不同尺寸):

https://www.arduino.cc/en/Reference/Int

在 Arduino Uno(和其他基于 ATMega 的板)上,一个 int 存储一个 16 位(2 字节)的值。这会产生 -32,768 到 32,767 的范围(最小值为 -2^15,最大值为 (2^15) - 1)。在基于 Arduino Due 和 SAMD 的板(如 MKR1000 和 Zero)上,一个 int 存储一个 32 位(4 字节)的值。这产生了 -2,147,483,648 到 2,147,483,647 的范围(最小值为 -2^31,最大值为 (2^31) - 1)。

https://www.arduino.cc/en/Reference/UnsignedInt

在 Uno 和其他基于 ATMEGA 的板上,无符号整数(无符号整数)与整数相同,因为它们存储 2 字节值。它们不存储负数,但只存储正值,产生的有用范围为 0 到 65,535 (2^16) - 1)。

Due 存储一个 4 字节(32 位)的值,范围从 0 到 4,294,967,295 (2^32 - 1)。

https://www.arduino.cc/en/Reference/UnsignedLong

无符号长变量是数字存储的扩展大小变量,存储 32 位(4 字节)。与标准 long 不同,无符号 long 不会存储负数,它们的范围为 0 到 4,294,967,295 (2^32 - 1)。

于 2017-06-19T10:43:48.027 回答
0

使用此代码:

void calibrateSensors(int16_t * accelOffsets){
  int16_t rawAccel[3];
  //  [...]
  accelOffsets[0] += rawAccel[0];

有一个明显的问题:您在这里添加了两个16 位有符号整数。16 位有符号整数的典型最大值是0x7fff十进制的(第一位将用作符号位)32767

给定您的前两个样本编号,17112 + 17116is 已经34228,所以您溢出了整数类型。

中溢出有符号整数是未定义的行为,因为不同的实现可能对负数使用不同的表示。对于具有未定义行为的程序,您不能期望任何特定的结果。一个很可能的结果是该值将“环绕”到负范围内。

由于您已经使用了来自stdint.h的类型,因此解决方案很简单:uint32_t用于求和,这种类型有足够的位来存储不超过 的值4294967295

作为一般规则:如果您从不需要负值,只需坚持使用无符号类型。我看不出你在这里使用的原因int16_t,只是使用uint16_t.

于 2017-06-19T11:02:13.467 回答