Код Arduino неправильно добавляет цифры

Я пытаюсь создать функцию для нахождения среднего значения датчика на 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), инт
хранит 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 байта). В отличие от стандартных длинных без знака
longs не будет хранить отрицательные числа, делая их диапазон от 0 до
4,294,967,295 (2 ^ 32 — 1).

1

Другие решения

С этим кодом:

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

Существует очевидная проблема: вы добавляете два 16-битные целые числа со знаком Вот. Типичное максимальное значение для 16-битного целого числа со знаком 0x7fff (первый бит будет использоваться как знаковый бит), в десятичном виде 32767,

Учитывая ваши первые два номера образцов, 17112 + 17116 уже 34228, так что вы переполняете свой целочисленный тип.

Переполнение целого числа со знаком неопределенное поведение в , потому что разные реализации могут использовать разные представления для отрицательных чисел. Для программы с неопределенное поведение, ты не можешь ожидать любой конкретный результат. Весьма вероятный результат состоит в том, что значение «обернется» в отрицательный диапазон.

Как вы уже используете типы из stdint.h, решение простое: использовать uint32_t для ваших сумм этот тип имеет достаточно битов для значений до 4294967295,

Как правило: если вам никогда не нужно отрицательное значение, просто придерживайтесь беззнакового типа. Я не вижу причины, по которой вы используете int16_t здесь, просто используйте uint16_t,

0

По вопросам рекламы [email protected]