Отслеживание ориентации с Arduino и акселерометром ADXL345
Обзор
ADXL345 — 3-осевой акселерометр (I2C/SPI), измеряет статическое (гравитация) и динамическое ускорение. Используем для вычисления roll (крен) и pitch (тангаж) и 3D-визуализации в Processing.

Принцип работы
Единица измерения — g (9.8 м/с²). Датчик лежит горизонтально, Z вверх → Z=1g, X=Y=0. Перевернули → Z=-1g. Наклон меняет проекции g на оси: выходы варьируются от -1g до +1g. По тригонометрии вычисляем углы.



Подключение к Arduino (I2C)

- VCC → 3.3V/5V, GND → GND;
- SDA → A4, SCL → A5 (Uno/Nano);
- Адрес I2C: 0x53 (ALT ADDRESS заземлён).
Базовый код чтения данных
#include <Wire.h>
int ADXL345 = 0x53;
float X_out, Y_out, Z_out;
void setup() {
Serial.begin(9600);
Wire.begin();
// Режим измерения: бит D3 в POWER_CTL (0x2D) = 1
Wire.beginTransmission(ADXL345);
Wire.write(0x2D); Wire.write(8); // 0b00001000
Wire.endTransmission();
delay(10);
}
void loop() {
Wire.beginTransmission(ADXL345);
Wire.write(0x32); // ACCEL_XOUT_H
Wire.endTransmission(false);
Wire.requestFrom(ADXL345, 6, true);
X_out = (Wire.read() | Wire.read() << 8) / 256.0; // ±2g → 256 LSB/g
Y_out = (Wire.read() | Wire.read() << 8) / 256.0;
Z_out = (Wire.read() | Wire.read() << 8) / 256.0;
Serial.print("Xa= "); Serial.print(X_out);
Serial.print(" Ya= "); Serial.print(Y_out);
Serial.print(" Za= "); Serial.println(Z_out);
}




Калибровка смещения (Offset Calibration)
Сырые значения могут иметь ошибку (например, Z=283 вместо 256). Метод:
- Положите датчик идеально горизонтально.
- Выводите RAW значения (без деления на 256).
- Ошибка = (RAW - 256) / 4 → записываем в регистры смещения: 0x1E (X), 0x1F (Y), 0x20 (Z).
- Повторяем при каждом включении (не сохраняется в энергонезависимой памяти).
// В setup() после включения измерения:
Wire.beginTransmission(ADXL345); Wire.write(0x1E); Wire.write(1); Wire.endTransmission(); delay(10); // X
Wire.beginTransmission(ADXL345); Wire.write(0x1F); Wire.write(-2); Wire.endTransmission(); delay(10); // Y
Wire.beginTransmission(ADXL345); Wire.write(0x20); Wire.write(-9); Wire.endTransmission(); delay(10); // Z


Вычисление Roll и Pitch
roll = atan(Y_out / sqrt(X_out*X_out + Z_out*Z_out)) * 180/PI;
pitch = atan(-X_out / sqrt(Y_out*Y_out + Z_out*Z_out)) * 180/PI;
Формулы из аппноута Freescale (AN3461). Yaw (рыскание) акселерометром не измерить.
3D-визуализация в Processing
Arduino шлёт roll/pitch через Serial. Processing вращает коробку.
// Arduino: полный код с калибровкой и LPF
#include <Wire.h>
int ADXL345 = 0x53;
float X_out, Y_out, Z_out, roll, pitch, rollF=0, pitchF=0;
void setup() {
Serial.begin(9600); Wire.begin();
Wire.beginTransmission(ADXL345); Wire.write(0x2D); Wire.write(8); Wire.endTransmission(); delay(10);
// Калибровка (ваши значения!)
Wire.beginTransmission(ADXL345); Wire.write(0x1E); Wire.write(1); Wire.endTransmission(); delay(10);
Wire.beginTransmission(ADXL345); Wire.write(0x1F); Wire.write(-2); Wire.endTransmission(); delay(10);
Wire.beginTransmission(ADXL345); Wire.write(0x20); Wire.write(-9); Wire.endTransmission(); delay(10);
}
void loop() {
Wire.beginTransmission(ADXL345); Wire.write(0x32); Wire.endTransmission(false);
Wire.requestFrom(ADXL345, 6, true);
X_out = (Wire.read() | Wire.read() << 8) / 256.0;
Y_out = (Wire.read() | Wire.read() << 8) / 256.0;
Z_out = (Wire.read() | Wire.read() << 8) / 256.0;
roll = atan(Y_out / sqrt(X_out*X_out + Z_out*Z_out)) * 180/PI;
pitch = atan(-X_out / sqrt(Y_out*Y_out + Z_out*Z_out)) * 180/PI;
// Low-pass filter (сглаживание)
rollF = 0.94 * rollF + 0.06 * roll;
pitchF = 0.94 * pitchF + 0.06 * pitch;
Serial.print(rollF); Serial.print("/"); Serial.println(pitchF);
}
// Processing
import processing.serial.*;
Serial myPort; String data=""; float roll, pitch;
void setup() {
size(960, 640, P3D);
myPort = new Serial(this, "COM8", 9600); // Ваш порт
myPort.bufferUntil('\n');
}
void draw() {
translate(width/2, height/2, 0);
background(33);
textSize(22); text("Roll: " + int(roll) + " Pitch: " + int(pitch), -100, 265);
rotateX(radians(roll)); // Обратите знаки под вашу систему координат
rotateZ(radians(-pitch));
fill(0, 76, 153); box(386, 40, 200);
fill(255); textSize(25); text("www.HowToMechatronics.com", -183, 10, 101);
}
void serialEvent(Serial myPort) {
data = myPort.readStringUntil('\n');
if (data != null) {
data = trim(data);
String[] items = split(data, '/');
if (items.length > 1) { roll = float(items[0]); pitch = float(items[1]); }
}
}


LPF сглаживает дрожание (акселерометр улавливает вибрации руки), но добавляет задержку. Нет Yaw — нужен гироскоп (MPU6050).
Заключение
ADXL345 позволяет отслеживать крен и тангаж. Калибровка смещения критична для точности. LPF улучшает визуальную плавность. Для полной 3D-ориентации (включая yaw) нужен IMU с гироскопом (MPU6050) или фузия датчиков.
Производственный процесс
- Точное управление сервоприводом через MPU6050 (Arduino, SG90, MG996R)
- Модуль GPS u-blox LEA-6H 02: Интеграция с Arduino и Python
- Чтение температуры и влажности DHT11 через Blynk — пошаговый урок для Arduino
- Освоение распознавания и синтеза речи на Arduino Due
- Генерация музыкальных тонов на Arduino: полный спектр 88 клавиш пианино
- Подключение Arduino к NMEA-0183: пошаговое руководство
- Мастерство Modbus на Arduino: пошаговое руководство
- Умная кофемашина на Arduino с Bluetooth-управлением и мониторингом температуры
- Создание анимированной умной LED-ленты с управлением через Alexa на базе Arduino
- Голосовое управление светодиодами: Arduino Micro + BitVoicer Server для распознавания речи