B38 – Sử dụng gia tốc kế điện tử ADXL345

Gia tốc kế điện tử có thể được sử dụng để đo góc nghiêng cũng như xác định hướng của vật thể trong không gian. Tùy từng loại gia tốc kế, chúng ta có thể đọc dữ liệu theo 1 chiều (trục), 2 chiều hoặc 3 chiều. Trong bài này, gia tốc kế ADXL345 cung cấp thông tin 3 trục xyz.

Đây là một máy đo gia tốc (gia tốc kế) 3 trục có thể đo cả lực tĩnh và lực động của gia tốc. Lực hấp dẫn của trái đất là một ví dụ điển hình của lực tĩnh, trong khi lực động có thể được gây ra bởi các dao động, chuyển động, v.v.

Đơn vị đo gia tốc là mét trên giây bình phương (m / s ^ 2). Tuy nhiên, cảm biến gia tốc kế thường biểu thị các phép đo bằng “g” hoặc trọng lực. Một “g” là giá trị của lực hấp dẫn trái đất bình phương bằng 9,8 m/s^2.

Chú ý giá trị lối ra 1g tương ứng với các vị trí đặc biệt

Vì vậy, nếu chúng ta có một gia tốc kế được đặt bằng phẳng, với trục Z của nó hướng lên trên, ngược chiều với lực hấp dẫn, thì đầu ra trục Z của cảm biến sẽ là 1g. Mặt khác, đầu ra X và Y sẽ bằng 0, vì lực hấp dẫn vuông góc với các trục này và hoàn toàn không ảnh hưởng đến chúng.

Nếu chúng ta lật ngược cảm biến, thì đầu ra trục Z sẽ là -1 g. Điều này có nghĩa là đầu ra của cảm biến do định hướng của nó đối với trọng lực có thể thay đổi từ -1g đến + 1g.

Cảm biến này sử dụng giao thức I2C để giao tiếp với Arduino, vì vậy chúng ta chỉ cần hai dây để kết nối nó, cộng với hai dây để cấp nguồn cho nó.

Chú ý điện trở treo cao cho SDA và SCL, chân CS có thể gấn 5V nếu mạch bị nhiễu

Mỗi thiết bị sử dụng giao tiếp I2C có một địa chỉ I2C duy nhất và địa chỉ này có thể được tìm thấy trong tài liệu của cảm biến. Vì vậy, chúng ta xác định địa chỉ và các biến cho ba đầu ra trong phần thiết lập. Trước tiên, chúng ta cần khởi tạo thư viện Wire và sau đó đặt gia tốc kế ở chế độ đo. Để làm được điều đó, chúng ta cần đặt bit D3 của thanh ghi POWER_CTL là HIGH.

D3 = 1 để gia tốc kế vào chế độ hoạt động

Dữ liệu cho mỗi trục được lưu trữ trong hai byte. Để đọc tất cả chúng, chúng ta bắt đầu với thanh ghi đầu tiên và sử dụng hàm requestFrom () yêu cầu đọc 6 thanh ghi. Sau đó, sử dụng hàm read (). Chúng ta đọc dữ liệu từ mỗi thanh ghi, và bởi vì đầu ra là hai phần bổ sung nên kết hợp chúng một cách thích hợp để có được các giá trị chính xác.

Các giá trị đầu ra từ cảm biến thực sự phụ thuộc vào độ nhạy đã chọn, có thể thay đổi từ +-2g đến +-16g. Độ nhạy mặc định là +-2g, đó là lý do tại sao chúng ta cần chia đầu ra cho 256 để nhận các giá trị từ -1 đến + 1g. 256 LSB / g có nghĩa là chúng ta có 256 số đếm trên mỗi g.

Tùy theo ứng dụng mà chúng ta có thể chọn độ nhạy phù hợp. Trong trường hợp này, đối với theo dõi định hướng , độ nhạy +-2g là tốt. Nhưng đối với ứng dụng mà chúng ta cần cảm nhận lực gia tốc cao hơn như chuyển động đột ngột, va chạm, v.v., chúng ta có thể chọn một số phạm vi độ nhạy khác bằng cách sử dụng thanh ghi DATA_FORMAT và các bit D1 và D0 của nó.

Minh họa định hướng (hình thiếu điện trở)

Sau khi đọc dữ liệu, chúng ta có thể chỉ cần in nó trên màn hình để kiểm tra xem các giá trị có như mong đợi hay không. Trong trường hợp các giá trị nhận được không chính xác như mong muốn, chúng ta cần hiệu chỉnh gia tốc kế bằng cách sử dụng 3 thanh ghi hiệu chuẩn bù đắp. Vì vậy, chúng ta cần đặt cảm biến bằng phẳng và in các giá trị RAW mà không chia chúng cho 256.

Từ đây chúng ta có thể nhận thấy mức độ đầu ra bị lệch, trong trường hợp ví dụ đầu ra Z là khoảng 283. Đó là chênh lệch dương 27. Bây giờ chúng ta cần chia giá trị này cho 4 (27 / 4 = 7) và điều đó sẽ cho phép sử dụng số mà chúng ta cần ghi vào thanh ghi bù trục Z.

// Off-set Calibration
  //X-axis
  Wire.beginTransmission(ADXL345);
  Wire.write(0x1E);  // X-axis offset register
  Wire.write(1);
  Wire.endTransmission();
  delay(10);
  //Y-axis
  Wire.beginTransmission(ADXL345);
  Wire.write(0x1F); // Y-axis offset register
  Wire.write(-2);
  Wire.endTransmission();
  delay(10);
  
  //Z-axis
  Wire.beginTransmission(ADXL345);
  Wire.write(0x20); // Z-axis offset register
  Wire.write(-7);
  Wire.endTransmission();
  delay(10);

Nếu cần, chúng ta nên hiệu chỉnh trục khác bằng phương pháp tương tự. Và cần lưu ý rằng hiệu chuẩn này không được ghi vĩnh viễn vào các thanh ghi. Chúng ta cần ghi các giá trị này vào các thanh ghi ở mỗi lần khởi động cảm biến.

Sau khi hoàn tất việc hiệu chuẩn, cuối cùng chúng ta có thể tính toán Roll và Pitch, hoặc xoay quanh trục X và xoay quanh trục Y theo độ, bằng cách sử dụng hai công thức này.

// Calculate Roll and Pitch (rotation around X-axis, rotation around Y-axis)
  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;

Khi thể hiện kết quả trên màn hình, chúng ta có thể nhận thấy rằng giá trị không ổn định và đó là do gia tốc kế không chỉ nắm bắt được lực hấp dẫn mà còn cả các lực nhỏ do chuyển động của bàn tay chúng ta tạo ra. Để có được kết quả mượt mà hơn, chúng ta có thể sử dụng một bộ lọc Thông thấp đơn giản. Triển khai một bộ lọc như vậy trong mã Arduino, nó chiếm 94% trạng thái trước đó và thêm 6% trạng thái hoặc góc hiện tại.

// Low-pass filter
  rollF = 0.94 * rollF + 0.06 * roll;
  pitchF = 0.94 * pitchF + 0.06 * pitch;

Với bộ lọc này, chúng ta có thể nhận thấy rằng giá trị mượt mà hơn rất nhiều, nhưng cũng có một tác dụng phụ và đó là khả năng phản hồi chậm hơn. Chúng ta cũng có thể nhận thấy rằng đang thiếu Yaw, xoay quanh trục Z. Chỉ sử dụng dữ liệu gia tốc kế 3 trục, chúng ta không thể tính toán Yaw.

Chương trình ví dụ

/*
     Arduino & ADXL345 Accelerometer
     duannho.com
 */
 include <Wire.h>       // Wire library - used for I2C communication
 int ADXL345 = 0x53;       // The ADXL345 sensor I2C address
 float X_out, Y_out, Z_out;  
 void setup() 
 {
   pinMode(LED_BUILTIN, OUTPUT);
   Serial.begin(9600); 
   Wire.begin(); 
   // Set ADXL345 in measuring mode
   Wire.beginTransmission(ADXL345);  // Start communicating with the device 
   Wire.write(0x2D);                 // Access/ talk to POWER_CTL Register - 0x2D
   // Enable measurement
   Wire.write(8);                    // (8dec -> 0000 1000 binary) 
   Wire.endTransmission();
   delay(10);
 }
 void loop() 
 {
   Wire.beginTransmission(ADXL345);  // Start communicating with the device 
   Wire.write(0x2D);                 // Access/ talk to POWER_CTL Register - 0x2D
   // Enable measurement
   Wire.write(8);                    // (8dec -> 0000 1000 binary) 
   Wire.endTransmission();
   delay(10);
   //
   // Read acceleromter data 
   Wire.beginTransmission(ADXL345);
   Wire.write(0x32);                   // Start with register 0x32 (ACCEL_XOUT_H)
   Wire.endTransmission(false);
   Wire.requestFrom(ADXL345, 6, true); // Read 6 registers, each axis in 2 registers
   X_out = ( Wire.read()| Wire.read() << 8); // X-axis value
   X_out = X_out/256;          //For a range of +-2g, divide the raw values by 256     
   Y_out = ( Wire.read()| Wire.read() << 8); // Y-axis value
   Y_out = Y_out/256;
   Z_out = ( Wire.read()| Wire.read() << 8); // Z-axis value
   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);
 if (Z_out < 0.8)
   {
     digitalWrite(LED_BUILTIN, HIGH);
   }
   else
     digitalWrite(LED_BUILTIN, LOW);
 //
 }

Video minh họa

Leave a Reply

Your email address will not be published. Required fields are marked *