Главная » Arduino » Как отслеживать ориентацию с помощью Arduino и акселерометра ADXL345

Как отслеживать ориентацию с помощью Arduino и акселерометра ADXL345

В этой статье мы узнаем, как измерять угол и отслеживать ориентацию с помощью Arduino и датчика акселерометра ADXL345.

Как работает акселерометр ADXL345

ADXL345 — это 3-осевой акселерометр, который может измерять как статические, так и динамические силы ускорения. Сила земного притяжения является типичным примером статической силы, в то время как динамические силы могут быть вызваны вибрациями, движениями и так далее.

Как работает акселерометр ADXL345

 

Общеизвестная единица измерения ускорения — метр на секунду в квадрате (м/с2). Однако акселерометры обычно выдают значения в «g» или гравитационное ускорение. Один «g» — это величина ускорения придаваемое телу силой тяжести на поверхности земли и в среднем равна 9,8 м/с2.

Итак, если у нас акселерометр, расположенный горизонтально, с его осью Z, направленной вверх, (противоположной силе тяжести) выходной сигнал по оси Z будет равен 1g. Выходные сигналы по осям X и Y будут равны нулю, потому что гравитационная сила перпендикулярна к этим осям и никак на них не влияет.

акселерометр ADXL345 - 3 оси

Если перевернуть датчик вверх ногами, то выходной сигнал по оси Z будет -1g. Это означает, что выходные данные датчика из-за его ориентации под действием силы тяжести могут варьироваться от -1g до +1g.

Таким образом, на основании этих данных и используя некоторые тригонометрические формулы мы можем вычислить угол, под которым расположен датчик.

Как считать данные акселерометра ADXL345 с помощью Arduino

Хорошо, теперь давайте посмотрим, как мы можем прочитать данные акселерометра ADXL345 с помощью Arduino. Для связи с Arduino датчик ADXL345 использует I2C протокол. Следовательно, нам нужны только два провода для его подключения (линии данных) и два провода для его питания.

ADXL345 - схема подключения

Скетч для акселерометра ADXL345

Ниже приведен код для чтения данных акселерометра ADXL345:

#include <Wire.h>  // подключение библиотеки Wire
int ADXL345 = 0x53; // Адрес I2C датчика ADXL345
float X_out, Y_out, Z_out;  // Выходы

void setup() {
  Serial.begin(9600);
  Wire.begin(); // Инициализация библиотеки Wire 
  // Установите ADXL345 в режим измерения
  Wire.beginTransmission(ADXL345); // Начать общение с устройством 
  Wire.write(0x2D); // работа с регистром  POWER_CTL  - 0x2D
  // Включить измерение
  Wire.write(8); // (8dec -> 0000 1000 двоичный) Бит D3 High для разрешения измерения
  Wire.endTransmission();
  delay(10);
}

void loop() {
// === Считать данные акселерометра === //
  Wire.beginTransmission(ADXL345);
  Wire.write(0x32); // Начать с регистра 0x32 (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(ADXL345, 6, true); // Чтение всех 6 регистров, значение каждой оси сохраняется в 2 регистрах
  X_out = ( Wire.read()| Wire.read() << 8); // Значение по оси X
  X_out = X_out/256; //Для диапазона + -2g нам нужно разделить необработанные значения на 256 в соответствии с datasheet
  Y_out = ( Wire.read()| Wire.read() << 8); // Значение по оси Y
  Y_out = Y_out/256;
  Z_out = ( Wire.read()| Wire.read() << 8); // Значение по оси Z
  Z_out = Z_out/256;

  Serial.print("Xa= ");
  Serial.print(X_out);
  Serial.print("   Ya= ");
  Serial.print(Y_out);
  Serial.print("   Za= ");
  Serial.println(Z_out);
}

Описание: Итак, сначала нам нужно подключить библиотеку Wire.h, которая используется для связи по I2C. Каждое устройство, использующее I2C связь, имеет уникальный I2C адрес, и этот адрес можно найти в datasheet на ADXL345.

Итак, после того как мы определили адрес и переменные для трех выходов (X, Y, Z), в функции setup() нам нужно инициализировать библиотеку Wire, а затем перевести акселерометр в режим измерения. Для этого, если мы еще раз взглянем в datasheet, мы увидим, что нам нужно установить бит D3 в регистре POWER_CTL в HIGH.

 бит D3 в регистре POWER_CTL

Итак, с помощью функции beginTransmission() мы запускаем подключение, затем с помощью функции write() сообщаем, к какому регистру хотим получить доступ, и снова с помощью функции write() устанавливаем бит D3 в HIGH, записывая в регистр число 8 в десятичной системе счисления, которое соответствует установке высокого бита D3.

// Установите ADXL345 в режим измерения
Wire.beginTransmission(ADXL345); // Начать общение с устройством 
Wire.write(0x2D); // работа с регистром  POWER_CTL  - 0x2D
// Включить измерение
Wire.write(8); // (8dec -> 0000 1000 двоичный) Бит D3 High для разрешения измерения
Wire.endTransmission();

Теперь в функции loop() мы читаем данные с датчика. Данные для каждой оси хранятся в двух байтах или регистрах. Адреса этих регистров можно также посмотреть в datasheet:

Данные для каждой оси хранятся в двух байтах

Чтобы прочитать их все, начинаем с первого регистра, а при использовании функции RequestionFrom() мы считываем все 6 регистров. Затем, используя функцию read(), мы выбираем данные из каждого регистра по отдельности. Поскольку данные для каждой оси состоят из старшего и младшего байта, то для получения правильного значения мы объединяем их.

// === Считать данные акселерометра === //
  Wire.beginTransmission(ADXL345);
  Wire.write(0x32); // Начать с регистра 0x32 (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(ADXL345, 6, true); // Чтение всех 6 регистров, значение каждой оси сохраняется в 2 регистрах
  X_out = ( Wire.read()| Wire.read() << 8); // Значение по оси X
  X_out = X_out/256; //Для диапазона + -2g нам нужно разделить необработанные значения на 256 в соответствии с datasheet
  Y_out = ( Wire.read()| Wire.read() << 8); // Значение по оси Y
  Y_out = Y_out/256;
  Z_out = ( Wire.read()| Wire.read() << 8); // Значение по оси Z
  Z_out = Z_out/256;

Выходные данные датчика фактически зависят от выбранной чувствительности, которая может варьироваться от + -2g до + -16g. Чувствительность по умолчанию составляет + -2g, поэтому нам нужно разделить результат на 256, чтобы получить значения от -1 до + 1g. 256 LSB/g означает, что у нас 256 отсчетов на 1g.

Чувствительность по умолчанию составляет + -2g

В зависимости от нашей потребности мы можем выбрать подходящую чувствительность. В случае для слежения ориентации вполне подойдет чувствительность + -2g, но для приложений, где нам нужно фиксировать более высокую силу ускорения, например, от внезапных движений, ударов и т. д., мы можем выбрать другие диапазоны чувствительности, используя регистр DATA_FORMAT и его биты D1 и D0.

регистр DATA_FORMAT и его биты D1 и D0

Калибровка акселерометра ADXL345

После того как мы прочитали данные, мы можем просто вывести их в мониторе последовательного порта, чтобы проверить, соответствуют ли значения ожидаемым. В нашем случае значения, которые мы получили, были не совсем такими, какими они должны быть, особенно по оси Z, которая имела заметную ошибку в 0,1g.

Калибровка акселерометра ADXL345

Чтобы решить эту проблему, нам нужно откалибровать акселерометр, используя 3 регистра калибровки смещения, и вот как мы можем это сделать. Итак, нам нужно расположить датчик ровно и распечатать значения RAW, не деля их на 256.

нужно откалибровать акселерометр

Здесь мы можем видеть отклонение от нормы, в нашем случае значение по оси Z было около 283. Это положительная разница в 27. Теперь нам нужно разделить это значение на 4, и это даст нам число, которое нам нужно записать в регистр смещения оси Z. Если после этого мы загрузим скетч, то значение по оси Z будет ровно 256, или 1g, как и должно быть.

// Этот код должен находится в разделе setup()
// Калибровка смещения
   // ось X
  Wire.beginTransmission(ADXL345);
  Wire.write(0x1E);  // Регистр смещения оси X
  Wire.write(1);
  Wire.endTransmission();
  delay(10);
  // ось Y
  Wire.beginTransmission(ADXL345);
  Wire.write(0x1F); //Регистр смещения оси Y
  Wire.write(-2);
  Wire.endTransmission();
  delay(10);
  
  // ось Z
  Wire.beginTransmission(ADXL345);
  Wire.write(0x20); // Регистр смещения оси Z
  Wire.write(-7);
  Wire.endTransmission();
  delay(10);

При необходимости нам следует откалибровать и другие оси, используя тот же метод. И сразу заметим, что эта калибровка не записывается в регистры постоянно. Нам нужно записывать эти значения в регистры при каждом включении датчика.

После того, как мы завершили калибровку, мы наконец можем вычислить крен и тангаж, используя две формулы:

// Расчет крена и тангажа (вращение вокруг оси X, вращение вокруг оси Y)
  roll = atan(Y_out / sqrt(pow(X_out, 2) + pow(Z_out, 2))) * 180 / PI;
  pitch = atan(-1 * X_out / sqrt(pow(Y_out, 2) + pow(Z_out, 2))) * 180 / PI;

Источник




Добавить комментарий


.