我正在尝试创建一个函数来查找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]) ;
知道我哪里错了吗?
答案 0 :(得分: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字节)。与标准长号未签名不同 多头不会存储负数,使其范围从0到 4,294,967,295(2 ^ 32 - 1)。
答案 1 :(得分:0)
使用此代码:
void calibrateSensors(int16_t * accelOffsets){
int16_t rawAccel[3];
// [...]
accelOffsets[0] += rawAccel[0];
有一个明显的问题:你在这里添加两个 16bit有符号整数。 16位有符号整数的典型最大值为0x7fff
(第一位将用作符号位),十进制32767
。
鉴于前两个样本号,17112 + 17116
已经34228
,因此您的整数类型溢出。
在c中溢出有符号整数是未定义的行为,因为不同的实现可以对负数使用不同的表示。对于具有未定义行为的程序,您不能期望任何特定结果。一个非常可能的结果是价值将会回绕&#34;进入负面范围。
由于您已使用stdint.h
中的类型,因此解决方案很简单:使用uint32_t
作为总和,此类型的值最多可达4294967295
。
作为一般规则:如果您从不需要负值,只需坚持使用无符号类型即可。我在这里没有看到您使用int16_t
的原因,只需使用uint16_t
。