산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

Arduino 및 ADXL345 가속도계로 방향을 추적하는 방법

<메인 클래스="사이트 메인" id="메인">

이 튜토리얼에서는 Arduino와 ADXL345 가속도계 센서를 사용하여 각도를 측정하고 방향을 추적하는 방법을 배웁니다. 자세한 내용은 다음 동영상을 보거나 아래에 작성된 튜토리얼을 참조하세요.

개요

먼저 센서의 작동 방식과 센서에서 데이터를 읽는 방법을 설명한 다음 Processing 개발 환경을 사용하여 가속도계 방향을 3D로 시각화하겠습니다.

ADXL345 가속도계 작동 방식

먼저 ADXL345 센서가 어떻게 작동하는지 살펴보겠습니다. 이것은 정적 및 동적 가속도를 모두 측정할 수 있는 3축 가속도계입니다. 지구 중력은 정적 힘의 전형적인 예이며 동적 힘은 진동, 움직임 등에 의해 발생할 수 있습니다.

가속도 측정 단위는 초당 미터 제곱(m/s^2)입니다. 그러나 가속도계 센서는 일반적으로 측정값을 "g" 또는 중력으로 표현합니다. 1 "g"는 초당 9.8미터의 제곱에 해당하는 지구 중력의 값입니다.

따라서 가속도계가 평평한 위치에 있고 Z축이 위쪽을 가리키고 중력과 반대인 경우 센서의 Z축 출력은 1g입니다. 반면에 X 및 Y 출력은 0이 됩니다. 중력은 이러한 축에 수직이고 전혀 영향을 미치지 않기 때문입니다.

센서를 거꾸로 뒤집으면 Z축 출력은 -1g이 됩니다. 이는 중력 방향으로 인한 센서 출력이 -1g에서 +1g까지 다양할 수 있음을 의미합니다.

따라서 이 데이터에 따라 일부 삼각법 수학을 사용하여 센서가 위치한 각도를 계산할 수 있습니다.

Arduino로 ADXL345 가속도계 데이터를 읽는 방법

이제 Arduino를 사용하여 ADXL345 가속도계 데이터를 읽는 방법을 살펴보겠습니다. 이 센서는 Arduino와의 통신을 위해 I2C 프로토콜을 사용하므로 연결을 위한 두 개의 와이어와 전원 공급을 위한 두 개의 와이어만 필요합니다.

아래 링크에서 이 Arduino 튜토리얼에 필요한 구성요소를 얻을 수 있습니다.

ADXL345 가속도계 Arduino 코드

다음은 ADXL345 가속도계 데이터를 읽기 위한 Arduino 코드입니다.

/*
    Arduino and ADXL345 Accelerometer Tutorial
     by Dejan, https://howtomechatronics.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;  // Outputs

void setup() {
  Serial.begin(9600); // Initiate serial communication for printing the results on the Serial monitor
  Wire.begin(); // Initiate the Wire library
  // 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) Bit D3 High for measuring enable 
  Wire.endTransmission();
  delay(10);
}

void loop() {
  // === 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 total, each axis value is stored in 2 registers
  X_out = ( Wire.read()| Wire.read() << 8); // X-axis value
  X_out = X_out/256; //For a range of +-2g, we need to divide the raw values by 256, according to the datasheet
  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);
}Code language: Arduino (arduino)

설명: 따라서 먼저 I2C 통신에 사용되는 Wire.h 라이브러리를 포함해야 합니다. I2C 통신이 작동하는 방식과 Arduino와 함께 사용하는 방법에 대한 자세한 내용은 제 다른 자세한 자습서를 참조하세요.

I2C 통신을 사용하는 각 장치에는 고유한 I2C 주소가 있으며 이 주소는 센서의 데이터시트(ADXL345 데이터시트)에서 찾을 수 있습니다. 따라서 설정 섹션에서 세 개의 출력에 대한 주소와 변수를 정의하면 먼저 와이어 라이브러리를 초기화한 다음 측정 모드에서 가속도계를 설정해야 합니다. 이를 위해 데이터시트를 다시 살펴보면 POWER_CTL 레지스터의 D3 비트를 HIGH로 설정해야 함을 알 수 있습니다.

<그림 클래스="aligncenter">

따라서 beginTransmission() 함수를 사용하여 통신을 시작한 다음 write() 함수를 사용하여 액세스하려는 레지스터를 말하고 다시 write() 함수를 사용하여 숫자 8을 작성하여 D3 비트를 HIGH로 설정합니다. 비트 D3 HIGH 설정에 해당하는 10진수.

// 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) Bit D3 High for measuring enable 
  Wire.endTransmission();Code language: Arduino (arduino)

이제 루프 섹션에서 센서의 데이터를 읽습니다. 각 축의 데이터는 2바이트 또는 레지스터에 저장됩니다. 데이터시트에서 이러한 레지스터의 주소를 볼 수 있습니다.

그것들을 모두 읽기 위해 우리는 첫 번째 레지스터부터 시작하고 requestionFrom() 함수를 사용하여 6개의 레지스터를 읽도록 요청합니다. 그런 다음 read() 함수를 사용하여 각 레지스터에서 데이터를 읽고 출력이 2의 보수이므로 올바른 값을 얻기 위해 적절하게 결합합니다.

// === 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 total, each axis value is stored in 2 registers
  X_out = ( Wire.read()| Wire.read() << 8); // X-axis value
  X_out = X_out/256; //For a range of +-2g, we need to divide the raw values by 256, according to the datasheet
  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;Code language: Arduino (arduino)

센서의 출력 값은 실제로 선택한 감도에 따라 달라지며, 이는 +-2g에서 +-16g까지 다양합니다. 기본 감도는 +-2g이므로 -1에서 +1g까지의 값을 얻으려면 출력을 256으로 나누어야 합니다. 256 LSB/g는 g당 256개의 카운트가 있음을 의미합니다.

애플리케이션에 따라 적절한 감도를 선택할 수 있습니다. 이 경우 추적 방향의 경우 +-2g 감도가 좋지만 급격한 움직임, 충격 등과 같이 더 높은 가속력을 감지해야 하는 응용 프로그램의 경우 DATA_FORMAT 레지스터를 사용하여 다른 감도 범위 중 일부를 선택할 수 있습니다. D1 및 D0 비트.

<그림 클래스="aligncenter">

ADXL345 가속도계 보정

그럼에도 불구하고 데이터를 읽은 후에는 직렬 모니터에 인쇄하여 값이 예상한 대로인지 확인할 수 있습니다. 제 경우에는 얻은 값이 정확히 정확히 일치하지 않았습니다. 특히 Z축에는 0.1g의 눈에 띄는 오류가 있었습니다.

이 문제를 해결하려면 3개의 오프셋 보정 레지스터를 사용하여 가속도계를 보정해야 합니다. 이를 수행하는 방법은 다음과 같습니다. 따라서 센서를 평평하게 배치하고 RAW 값을 256으로 나누지 않고 인쇄해야 합니다.

이제 여기에서 출력이 얼마나 꺼져 있는지 알 수 있습니다. 제 경우 Z 출력은 약 283이었습니다. 양수에서 27의 차이입니다. 이제 우리는 이 값을 4로 나누어야 합니다. 그러면 Z축 오프셋 레지스터에 쓰는 데 필요한 숫자가 사용됩니다. 지금 코드를 업로드하면 Z축 출력은 정확히 256 또는 1g가 되어야 합니다.

// This code goes in the SETUP section
// 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);Code language: Arduino (arduino)

필요한 경우 동일한 방법을 사용하여 다른 축을 보정해야 합니다. 그리고 이 보정이 레지스터에 영구적으로 기록되지 않는다는 점에 유의하십시오. 센서를 켤 때마다 이 값을 레지스터에 기록해야 합니다.

보정이 완료되면 이제 이 두 공식을 사용하여 롤 및 피치, 즉 X축을 중심으로 한 회전과 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;Code language: Arduino (arduino)

이러한 공식의 작동 방식에 대한 자세한 내용은 이 Freescale Semiconductor 애플리케이션 노트를 참조하십시오.

Arduino 및 ADXL345 가속도계 방향 추적 – 3D 시각화

자, 이제 가속도계 3D 시각화 예제를 만들어 보겠습니다.

따라서 직렬 포트를 통해 Roll 및 Pitch 값을 보내는 동일한 코드를 사용하고 있습니다. 전체 Arduino 코드는 다음과 같습니다.

/*
    Arduino and ADXL345 Accelerometer - 3D Visualization Example 
     by Dejan, https://howtomechatronics.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;  // Outputs
float roll,pitch,rollF,pitchF=0;

void setup() {
  Serial.begin(9600); // Initiate serial communication for printing the results on the Serial monitor
 
  Wire.begin(); // Initiate the Wire library
  // 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); // Bit D3 High for measuring enable (8dec -> 0000 1000 binary)
  Wire.endTransmission();
  delay(10);

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

  //Z-axis
  Wire.beginTransmission(ADXL345);
  Wire.write(0x20);
  Wire.write(-9);
  Wire.endTransmission();
  delay(10);
}

void loop() {
  // === 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 total, each axis value is stored in 2 registers
  X_out = ( Wire.read() | Wire.read() << 8); // X-axis value
  X_out = X_out / 256; //For a range of +-2g, we need to divide the raw values by 256, according to the datasheet
  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;

  // 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;

  // 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);
}Code language: Arduino (arduino)

이제 Processing 개발 환경에서 이러한 값을 수신하고 이를 사용하여 생성할 3D 개체를 회전해야 합니다. 전체 처리 코드는 다음과 같습니다.

/*
    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); // starts the serial communication
  myPort.bufferUntil('\n');
}

void draw() {
  translate(width/2, height/2, 0);
  background(33);
  textSize(22);
  text("Roll: " + int(roll) + "     Pitch: " + int(pitch), -100, 265);

  // Rotate the object
  rotateX(radians(roll));
  rotateZ(radians(-pitch));
  
  // 3D 0bject
  textSize(30);  
  fill(0, 76, 153);
  box (386, 40, 200); // Draw box
  textSize(25);
  fill(255, 255, 255);
  text("www.HowToMechatronics.com", -183, 10, 101);

  //delay(10);
  //println("ypr:\t" + angleX + "\t" + angleY); // Print the values to check whether we are getting proper values
}

// Read data from the Serial Port
void serialEvent (Serial myPort) { 
  // reads the data from the Serial Port up to the character '.' and puts it into the String variable "data".
  data = myPort.readStringUntil('\n');

  // if you got any bytes other than the linefeed:
  if (data != null) {
    data = trim(data);
    // split the string at "/"
    String items[] = split(data, '/');
    if (items.length > 1) {

      //--- Roll,Pitch in degrees
      roll = float(items[0]);
      pitch = float(items[1]);
    }
  }
}Code language: Arduino (arduino)

설명: 따라서 여기에 직렬 라이브러리를 포함하고 직렬 포트와 업로드된 Arduino 스케치의 전송 속도와 일치해야 하는 전송 속도를 정의해야 합니다. 그런 다음 들어오는 데이터를 읽고 적절한 롤 및 피치 변수에 넣습니다. 기본 그리기 루프에서 이 값을 사용하여 3D 개체를 회전합니다. 이 경우에는 특정 색상과 텍스트가 있는 단순한 상자입니다.

스케치를 실행하면 3D 개체가 나타나고 가속도계 센서의 방향을 추적합니다. 여기서 물체가 실제로 약간 흔들리고 있음을 알 수 있습니다. 이는 가속도계가 중력뿐만 아니라 손의 움직임에 의해 생성되는 작은 힘도 포착하기 때문입니다. 더 부드러운 결과를 얻기 위해 간단한 저역 통과 필터를 사용할 수 있습니다. 여기에서 Arduino 코드에서 이러한 필터를 구현했는데 이전 상태의 94%를 취하고 현재 상태 또는 각도의 6%를 추가합니다.

// Low-pass filter
  rollF = 0.94 * rollF + 0.06 * roll;
  pitchF = 0.94 * pitchF + 0.06 * pitch;Code language: Arduino (arduino)

이 필터를 사용하면 개체가 훨씬 더 부드럽게 움직이는 것을 알 수 있지만 부작용도 있고 응답 속도가 느려집니다. 또한 Yaw 또는 Z축을 중심으로 한 회전이 누락되었음을 알 수 있습니다. 3축 가속도계 데이터만 사용하여 Yaw를 계산할 수 없습니다.

이를 수행하고 방향 추적 센서의 전반적인 성능을 개선하려면 실제로 추가 센서인 자이로스코프를 포함하고 해당 데이터를 가속도계와 융합해야 합니다.

따라서 일부 자이로스코프 센서와 함께 ADXL345 가속도계를 사용하거나 단일 칩에 3축 가속도계와 3축 자이로스코프가 모두 통합된 MPU6050 IMU를 사용할 수 있습니다. 내 다음 비디오에서 이 센서에 대한 자세한 자습서를 찾을 수 있습니다.

이 튜토리얼을 즐기고 새로운 것을 배웠기를 바랍니다. 아래 댓글 섹션에서 언제든지 질문을 하고 내 Arduino 프로젝트 컬렉션을 확인하는 것을 잊지 마세요.


제조공정

  1. Arduino 및 MPU6050으로 서보 모터 제어
  2. U-blox LEA-6H 02 GPS 모듈(Arduino 및 Python 포함)
  3. DHT11로 Blynk에서 온도와 습도를 읽는 방법
  4. Arduino를 사용한 음성 인식 및 합성
  5. Arduino로 음악을 만드는 방법
  6. Arduino와 함께 NMEA-0183을 사용하는 방법
  7. Arduino에서 Modbus를 사용하는 방법
  8. Arduino 및 Bluetooth가 탑재된 스마트 커피 머신
  9. Alexa 및 Arduino를 사용한 애니메이션 스마트 조명
  10. Arduino 및 BitVoicer 서버로 음성 인식