개발자/Arduino

Nano 33 BLE Sense 가속도계 LSM9DS1 3D 시각화

지구빵집 2020. 11. 15. 18:00
반응형

 

 

Nano 33 BLE Sense 가속도계 LSM9DS1 3D 시각화 

 

Nano 33 BLE Sense 3D Visualization with Accelerometer LSM9DS1.

 

가속도계의 움직임을 3D 시각화하려고 보니 적당한 내용이 있어서 소개합니다. 아래 내용은 ADXL345 가속도계와 아두이노 나노보드를 사용했고 출력을 Processing 코드를 사용하여 시각화한 것입니다. 우리는 Nnao 33 BLE Sense 보드와 Processing 코드로 구현할 것입니다. 아래 내용은 원문 사이트 내용을 번역하여 올린 것이다. 구현하고자 하는 내용은 동일하므로 내용을 참고하기 바랍니다.

 

이 튜토리얼에서는 Arduino 및 ADXL345 가속도계 센서를 사용하여 각도 및 트랙 방향을 측정하는 방법을 배웁니다. 자세한 내용은 다음 비디오를 보거나 아래 작성된 자습서를 읽을 수 있습니다.

 

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

 

ADXL345 가속도계의 작동 원리와 움직이는 각도의 계산

 

먼저 ADXL345 센서가 어떻게 작동하는지 살펴보겠습니다. 정적 및 동적 가속력을 모두 측정할 수 있는 3 축 가속도계입니다. 지구 중력은 정적 인 힘의 전형적인 예이며 동적 힘은 진동, 움직임 등에 의해 발생할 수 있습니다. 가속도 측정 단위는 초당 미터 제곱 (m/s^2)입니다. 그러나 가속도계 센서는 일반적으로 "g"또는 중력으로 측정값을 표시합니다. 하나의 "g"는 초당 9.8 미터 제곱에 해당하는 지구 중력의 값입니다. 따라서 가속도계가 중력과 반대로 Z 축이 위쪽을 향하도록 평평하게 배치된 경우 센서의 Z 축 출력은 1g가 됩니다. 반면에 중력이 이러한 축에 수직이고 전혀 영향을 미치지 않기 때문에 X 및 Y 출력은 0이 됩니다. 센서를 거꾸로 뒤집으면 Z 축 출력은 -1g가 됩니다. 이것은 중력에 대한 방향으로 인한 센서의 출력이 -1g에서 + 1g까지 다양할 수 있음을 의미합니다. 따라서 이 데이터에 따라 삼각법 수학을 사용하여 센서가 위치하는 각도를 계산할 수 있습니다.

 

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

 

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

 

ADXL345 가속도계 Arduino 코드입니다. 코드의 출처는 아래 참고자료 원문 사이트고, 이 코드 아래에 Nano 33 BLE Sense 보드에서 가속도계의 값을 읽어오는 코드를 제공합니다.

 

/*
    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);
}

 

위 코드와 정확히 같은 동작을 하는 Nano 33 BLE Sense 코드입니다. LSM9DS1 가속도계에 관한 자세한 설명과 테스트 코드는 링크를 따라 가십시요. roll, pitch 구하는 코드도 참고문서와 동일하게 반영했습니다. 결과가 약간 다른 문제가 있습니다. 나중에 설명합니다.

 

/*
  Arduino LSM9DS1 - Simple Accelerometer

  This example reads the acceleration values from the LSM9DS1
  sensor and continuously prints them to the Serial Monitor
  or Serial Plotter.

  The circuit:
  - Arduino Nano 33 BLE Sense

  created 10 Jul 2019
  by Riccardo Rizzo

  This example code is in the public domain.
*/

#include <Arduino_LSM9DS1.h>

float roll,pitch,rollF,pitchF = 0;

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Started");

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }

  Serial.print("Accelerometer sample rate = ");
  Serial.print(IMU.accelerationSampleRate());
  Serial.println(" Hz");
  Serial.println();
  Serial.println("Acceleration in G's");
  Serial.println("X\tY\tZ");
}

void loop() {
  float x, y, z;

  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(x, y, z);

    x = x / 256;
    y = y / 256;
    z = z / 256;

    /*Serial.print(x);
    Serial.print('\t');
    Serial.print(y);
    Serial.print('\t');
    Serial.println(z);*/

    // Calculate Roll and Pitch (rotation around X-axis, rotation around Y-axis)
    roll = atan(y / sqrt(pow(x, 2) + pow(z, 2))) * 180 / PI;
    pitch = atan(-1 * x / sqrt(pow(x, 2) + pow(z, 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);
    
  }
}

 

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

 

프로세싱 코드를 작성하기 전에 우선 가속도계의 센서 데이터를 보정 Calibration 해야 합니다. 자세한 설명은 freescale Semiconductor application note 문서를 참고하시고, 아래에는 실제 ADXL345 가속도계를 가지고 보정하는 방법을 설명합니다.

 

ADXL345 가속기 교정

 

그럼에도 불구하고 데이터를 읽은 후에는 값이 예상대로인지 확인하기 위해 직렬 모니터에 간단히 인쇄할 수 있습니다. 제 경우에는 제가 얻은 값이 정확하지 않았으며 특히 0.1g의 눈에 띄는 오차가 있는 Z 축이 필요했습니다.

 

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

 

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

 

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

 

보정이 끝나면 마지막으로 이 두 공식을 사용하여 Roll and Pitch 또는 X 축을 중심으로 한 회전과 Y 축을 중심으로 한 회전을 계산할 수 있습니다. 

 

다 되었습니다. 

 

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

 

이제 Processing 개발 환경에서 이러한 값을 받아 생성할 3D 개체를 회전하는 데 사용해야 합니다. 링크를 따라가서 즉시 설치하고 아래 코드를 복사하여 붙여 넣고 RUN 하세요. 아주 멋진 영상을 보실 수 있습니다. 다음은 전체 Processing 코드입니다.

 

/*
    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]);
    }
  }
}

 

설명 : 따라서 여기에 13번 라인의 직렬 라이브러리를 포함하고, 업로드된 Arduino 스케치의 전송 속도와 일치해야 하는 직렬 포트 및 전송 속도를 정의해야 합니다. 아래 COM 포트를 사용자 PC 환경에 맞도록 수정하세요.

 

myPort = new Serial(this, "COM8", 9600); // starts the serial communication

 

그런 다음 들어오는 데이터를 읽고 적절한 롤 및 피치 변수에 넣습니다. 아두이노 스케치를 실행하고 Nano 33 BLE Sense 보드는 업로딩을 완료하면 com 포트가 자동으로 끊어지니 그 포트 번호를 보고 processing 코드의 13라인에서 com 포트를 일치시키고 프로세싱을 런 하시면 됩니다.

 

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

 

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

 

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

 

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

 

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

 

참고 자료

원문을 참고하세요.

 

잘 동작하는 데 하나가 반대로 움직인다. ㅠ.ㅠ

 

 

참고 자료

 

참고 문서 원문 How To Track Orientation with Arduino and ADXL345 Accelerometer 

Tilt Sensing Using a Three-Axis Accelerometer 

 

 

 

 

 

 

반응형