Arduino と ADXL345 加速度センサーで姿勢トラッキング:ステップバイステップガイド
このチュートリアルでは、Arduino と ADXL345 加速度センサーを使用して角度を測定し、姿勢をトラッキングする方法を学びます。以下の動画をご覧いただくか、詳細な書面チュートリアルをお読みください。 まず、センサーの仕組みとデータの読み取り方法を説明し、その後 Processing 開発環境を使用して加速度センサーの向きの 3D 可視化を行います。 まず、ADXL345 センサーの仕組みを見てみましょう。これは 3 軸加速度センサーで、静的および動的な加速度の両方を測定できます。地球の重力は静的力の典型的な例であり、動的力は振動、動きなどによって引き起こされます。 加速度の測定単位はメートル毎秒二乗(m/s²)です。しかし、加速度センサーは通常、測定値を「g」(重力加速度)で表します。1「g」は地球の重力の値で、9.8 メートル毎秒二乗に等しいです。 したがって、Z 軸が上向き、重力とは反対方向を向くように加速度センサーを平らに配置した場合、センサーの Z 軸出力は 1g になります。一方、X と Y の出力はゼロになります。重力がこれらの軸に垂直で、まったく影響しないためです。 センサーを逆さまにすると、Z 軸出力は -1g になります。これは、重力に対するセンサーの向きによって、センサーの出力が -1g から +1g の範囲で変化することを意味します。 このデータと三角関数の数学を使用して、センサーが配置されている角度を計算できます。 では、Arduino を使用して ADXL345 加速度センサーデータを読み取る方法を見てみましょう。このセンサーは Arduino との通信に I2C プロトコルを使用するため、電源用の 2 本に加えて、わずか 2 本のワイヤーで接続できます。 この Arduino チュートリアルに必要なコンポーネントは以下のリンクから入手できます: ADXL345 加速度センサーデータを読み取る Arduino コードです。 説明: まず、I2C 通信に使用される Wire.h ライブラリをインクルードします。I2C 通信の仕組みと Arduino での使用方法について詳しく知りたい場合は、私の他の詳細なチュートリアルをご覧ください。 I2C 通信を使用する各デバイスには固有の I2C アドレスがあり、このアドレスはセンサーのデータシート(ADXL345 データシート)で確認できます。アドレスと 3 つの出力用変数を定義したら、setup ではまず Wire ライブラリを初期化し、加速度センサーを測定モードに設定します。データシートを見ると、POWER_CTL レジスタのビット D3 をハイに設定する必要があることがわかります。 beginTransmission() 関数で通信を開始し、write() 関数でアクセスしたいレジスタを指定し、再び write() 関数で 10 進数の 8 を書き込んでビット D3 をハイに設定します。これはビット D3 をハイに設定することに対応します。 loop ではセンサーからデータを読み取ります。各軸のデータは 2 バイトまたはレジスタに格納されています。これらのレジスタのアドレスはデータシートから確認できます。 すべてを読み取るために、最初のレジスタから開始し、requestFrom() 関数を使用して 6 レジスタの読み取りを要求します。その後、read() 関数で各レジスタからデータを読み取り、出力が 2 の補数形式であるため、適切に組み合わせて正しい値を取得します。 センサーからの出力値は、選択された感度に依存し、±2g から ±16g の範囲で変化します。デフォルトの感度は ±2g なので、-1 から +1g の値を得るために出力を 256 で割る必要があります。256 LSB/g は、1g あたり 256 カウントがあることを意味します。 アプリケーションに応じて適切な感度を選択できます。この場合、姿勢トラッキングには ±2g 感度で十分ですが、急な動きや衝撃などのより高い加速度を検知するアプリケーションでは、DATA_FORMAT レジスタの D1 と D0 ビットを使用して他の感度範囲を選択できます。 それでも、データを読み取ったら、シリアルモニターに出力して値が期待通りか確認できます。私の場合、得られた値が正確ではありませんでした。特に Z 軸に 0.1g の顕著な誤差がありました。 この問題を解決するには、3 つのオフセットキャリブレーションレジスタを使用して加速度センサーをキャリブレーションする必要があります。その方法は以下の通りです。センサーを平らに置き、256 で割らない生の値を出力します。 ここで出力がどの程度ずれているか確認できます。私の場合、Z 出力は約 283 でした。正しい値 256 との差はプラス方向に 27 です。この値を 4 で割ると、Z 軸オフセットレジスタに書き込むべき数値が得られます。コードをアップロードすると、Z 軸出力は正確に 256、つまり正しい 1g になります。 必要に応じて同じ方法で他の軸もキャリブレーションしてください。なお、このキャリブレーションはレジスタに永続的に書き込まれるものではありません。センサーの電源投入ごとにこれらの値をレジスタに書き込む必要があります。 キャリブレーションが完了したら、以下の 2 つの式を使用して、ロールとピッチ、つまり X 軸周りの回転と Y 軸周りの回転を度単位で計算できます。 これらの式の仕組みの詳細については、Freescale Semiconductor のアプリケーションノートをご覧ください。 では、加速度センサーの 3D 可視化例を作成しましょう。 同じコードを使用して、ロールとピッチの値をシリアルポート経由で送信します。完全な Arduino コードは以下の通り: Processing 開発環境でこれらの値を受信し、作成する 3D オブジェクトの回転に使用します。完全な Processing コードは以下の通り: 説明: ここではシリアルライブラリをインクルードし、シリアルポートとボーレートを定義します。これはアップロードした Arduino スケッチのボーレートと一致させる必要があります。次に着信データを読み取り、適切なロールとピッチ変数に格納します。メインの draw ループでは、これらの値を使用して 3D オブジェクトを回転させます。この場合、特定の色とテキストを持つシンプルな箱です。 スケッチを実行すると、3D オブジェクトが現れ、加速度センサーの向きをトラッキングします。ここではオブジェクトが少し震えていることがわかります。これは加速度センサーが重力だけでなく、手の動きによって生じる小さな力も捉えているためです。より滑らかな結果を得るには、シンプルなローパスフィルターを使用できます。ここでは Arduino コードにそのようなフィルターを実装しました。これは前の状態の 94% を取り、現在の状態または角度の 6% を加算します。 このフィルターにより、オブジェクトの動きがかなり滑らかになりますが、副作用として反応速度が遅くなります。また、ヨー、つまり Z 軸周りの回転がないこともわかります。3 軸加速度センサーデータのみを使用してヨーを計算することはできません。 それを実現し、姿勢トラッキングセンサーの全体的な性能を向上させるには、ジャイロスコープという追加センサーを組み込み、そのデータを加速度センサーと融合する必要があります。 ADXL345 加速度センサーを何らかのジャイロスコープセンサーと組み合わせるか、または MPU6050 IMU を使用できます。これは 3 軸加速度センサーと 3 軸ジャイロスコープが単一チップに統合されています。このセンサーの詳細なチュートリアルは次の動画でご覧いただけます。 このチュートリアルを楽しんでいただき、新しいことを学んでいただけたなら幸いです。質問があれば下のコメント欄で自由にお尋ねください。また、私の Arduino プロジェクトコレクションもぜひチェックしてみてください。概要

ADXL345 加速度センサーの仕組み



Arduino で ADXL345 加速度センサーデータを読み取る方法

ADXL345 加速度センサー Arduino コード
/* Arduino and ADXL345 Accelerometer Tutorial by Dejan, https://howtomechatronics.com */
#include <Wire.h> // Wire ライブラリ - I2C 通信に使用
int ADXL345 = 0x53; // ADXL345 センサーの I2C アドレス
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 binary) ビット D3 をハイにして測定有効化
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 で割る
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);
}
// ADXL345 を測定モードに設定
Wire.beginTransmission(ADXL345); // デバイスとの通信開始
Wire.write(0x2D); // POWER_CTL レジスタにアクセス - 0x2D
// 測定を有効化
Wire.write(8); // (8dec -> 0000 1000 binary) ビット D3 をハイにして測定有効化
Wire.endTransmission();
// === 加速度センサーデータの読み取り ===
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 で割る
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;

ADXL345 加速度センサーのキャリブレーション


// このコードは 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;Arduino と ADXL345 加速度センサー姿勢トラッキング – 3D 可視化

/* Arduino and ADXL345 Accelerometer - 3D Visualization Example by Dejan, https://howtomechatronics.com */
#include <Wire.h> // Wire ライブラリ - I2C 通信に使用
int ADXL345 = 0x53; // ADXL345 センサーの I2C アドレス
float X_out, Y_out, Z_out; // 出力値
float roll, pitch, rollF, pitchF = 0;
void setup() {
Serial.begin(9600); // 結果をシリアルモニターに表示するためシリアル通信を開始
Wire.begin(); // Wire ライブラリを初期化
// ADXL345 を測定モードに設定
Wire.beginTransmission(ADXL345); // デバイスとの通信開始
Wire.write(0x2D); // POWER_CTL レジスタにアクセス - 0x2D
// 測定を有効化
Wire.write(8); // ビット D3 をハイにして測定有効化 (8dec -> 0000 1000 binary)
Wire.endTransmission();
delay(10);
// オフセットキャリブレーション
// X 軸
Wire.beginTransmission(ADXL345);
Wire.write(0x1E);
Wire.write(1);
Wire.endTransmission();
delay(10);
// Y 軸
Wire.beginTransmission(ADXL345);
Wire.write(0x1F);
Wire.write(-2);
Wire.endTransmission();
delay(10);
// Z 軸
Wire.beginTransmission(ADXL345);
Wire.write(0x20);
Wire.write(-9);
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 で割る
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;
// ロールとピッチを計算(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;
// ローパスフィルター
rollF = 0.94 * rollF + 0.06 * roll;
pitchF = 0.94 * pitchF + 0.06 * pitch;
Serial.print(rollF);
Serial.print("/");
Serial.println(pitchF);
}/* Arduino and ADXL345 Accelerometer - 3D Visualization Example by Dejan, https://howtomechatronics.com */
import processing.serial.*;
import java.awt.event.KeyEvent;
import java.io.IOException;
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));
// 3D オブジェクト
textSize(30);
fill(0, 76, 153);
box(386, 40, 200); // 箱を描画
textSize(25);
fill(255, 255, 255);
text("www.HowToMechatronics.com", -183, 10, 101);
// delay(10);
// println("ypr:\t" + angleX + "\t" + angleY); // 適切な値が取得できているか確認
}
// シリアルポートからデータを読み取り
void serialEvent(Serial myPort) {
// シリアルポートから改行文字 '\n' までデータを読み取り、文字列変数 "data" に格納
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]);
}
}
}// ローパスフィルター
rollF = 0.94 * rollF + 0.06 * roll;
pitchF = 0.94 * pitchF + 0.06 * pitch;
製造プロセス
- Arduino & MPU6050:SG90 & MG996Rサーボの精密制御
- u-blox LEA-6H 02 GPSモジュール: Arduino & Python 統合ガイド
- DHT11 と Blynk で温湿度をリアルタイム監視する Arduino チュートリアル
- Arduino Dueでマスターする音声認識と音声合成
- Arduinoで楽器演奏:音階生成のステップバイステップガイド
- ArduinoをNMEA-0183に接続するステップバイステップガイド
- ArduinoでModbusをマスターする:ステップバイステップガイド
- Arduino Nanoで作るBluetooth対応スマートコーヒーメーカー 〜温度グラフ表示と自動開始機能付き〜
- ArduinoとAlexaで制御するアニメーション対応スマートLEDストリップの作り方
- 音声制御LEDプロジェクト:Arduino Micro + BitVoicer Serverで音声認識
- ArduinoとPythonで作るAIアシスタントロボット「ジャウndice」