728x90
상보필터 complementary filter
- 각 센서 데이터에 alpha 만큼의 가중치를 줘서 서로 보완하는 필터
- 예시 : 각 변화율 자이로 x에 가속도 x 값을 같이 반영해서 롤 각을 구함
raw mpu데이터로 roll, pitch, yaw를 출력하도록
상보 필터 예제를 찾다가
위 링크에서 예제와 잘 설명이 되어있더라
원본 소스에서 주석 처리되거나 필요없는 부분을 제거해서 돌려봤
으나..
생각보다 롤, 피치, 요가 잘 나오지 않는다.
#include <Wire.h>
#define MPU6050_AXOFFSET 158
#define MPU6050_AYOFFSET 9
#define MPU6050_AZOFFSET -91
#define MPU6050_GXOFFSET 19
#define MPU6050_GYOFFSET -42
#define MPU6050_GZOFFSET -26
long sampling_timer;
const int MPU_addr=0x68; // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; // Raw data of MPU6050
float GAcX, GAcY, GAcZ; // Convert accelerometer to gravity value
float Cal_GyX,Cal_GyY,Cal_GyZ; // Pitch, Roll & Yaw of Gyroscope applied time factor
float acc_pitch, acc_roll, acc_yaw; // Pitch, Roll & Yaw from Accelerometer
float angle_pitch, angle_roll, angle_yaw; // Angle of Pitch, Roll, & Yaw
float alpha = 0.96; // Complementary constant
void setup(){
Wire.begin();
init_MPU6050();
Serial.begin(9600);
}
void loop(){
// Read raw data of MPU6050
Wire.beginTransmission(MPU_addr);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr,14,true); // request a total of 14 registers
AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
Tmp=Wire.read()<<8|Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
GyX=Wire.read()<<8|Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
GyY=Wire.read()<<8|Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
GyZ=Wire.read()<<8|Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
// Raw data of accelerometer corrected by offset value
// AcX -= MPU6050_AXOFFSET;
// AcY -= MPU6050_AYOFFSET;
// AcZ -= MPU6050_AZOFFSET;
// Convert accelerometer to gravity value
GAcX = (float) AcX / 4096.0;
GAcY = (float) AcY / 4096.0;
GAcZ = (float) AcZ / 4096.0;
// Calculate Pitch, Roll & Yaw from Accelerometer value
// Reference are
// https://engineering.stackexchange.com/questions/3348/calculating-pitch-yaw-and-roll-from-mag-acc-and-gyro-data
// https://www.dfrobot.com/wiki/index.php/How_to_Use_a_Three-Axis_Accelerometer_for_Tilt_Sensing
acc_pitch = atan ((GAcY - (float)MPU6050_AYOFFSET/4096.0) / sqrt(GAcX * GAcX + GAcZ * GAcZ)) * 57.29577951; // 180 / PI = 57.29577951
acc_roll = - atan ((GAcX - (float)MPU6050_AXOFFSET/4096.0) / sqrt(GAcY * GAcY + GAcZ * GAcZ)) * 57.29577951;
acc_yaw = atan (sqrt(GAcX * GAcX + GAcZ * GAcZ) / (GAcZ - (float)MPU6050_AZOFFSET/4096.0)) * 57.29577951;
// Calculate Pitch, Roll & Yaw by Complementary Filter
// Reference is http://www.geekmomprojects.com/gyroscopes-and-accelerometers-on-a-chip/
// Filtered Angle = α × (Gyroscope Angle) + (1 − α) × (Accelerometer Angle)
// where α = τ/(τ + Δt) and (Gyroscope Angle) = (Last Measured Filtered Angle) + ω×Δt
// Δt = sampling rate, τ = time constant greater than timescale of typical accelerometer noise
angle_pitch = alpha * (((float)(GyX - MPU6050_GXOFFSET) * 0.000244140625) + angle_pitch) + (1 - alpha) * acc_pitch;
angle_roll = alpha * (((float)(GyY - MPU6050_GYOFFSET) * 0.000244140625) + angle_roll) + (1 - alpha) * acc_roll;
angle_yaw += (float)(GyZ - MPU6050_GZOFFSET) * 0.000244140625; // Accelerometer doesn't have yaw value
// Print value of Pitch, Roll & Yaw reflected Complementary Filter
Serial.print(" | angle_pitch = "); Serial.print(angle_pitch);
Serial.print(" | angle_roll = "); Serial.print(angle_roll);
Serial.print(" | angle_yaw = "); Serial.println(angle_yaw);
// Sampling Timer
while(micros() - sampling_timer < 4000);
sampling_timer = micros(); //Reset the sampling timer
}
void init_MPU6050(){
//MPU6050 Initializing & Reset
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
//MPU6050 Clock Type
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0x03); // Selection Clock 'PLL with Z axis gyroscope reference'
Wire.endTransmission(true);
//MPU6050 Gyroscope Configuration Setting
Wire.beginTransmission(MPU_addr);
Wire.write(0x1B); // Gyroscope Configuration register
Wire.write(0x18); // FS_SEL=3, Full Scale Range = +/- 2000 [degree/sec]
Wire.endTransmission(true);
//MPU6050 Accelerometer Configuration Setting
Wire.beginTransmission(MPU_addr);
Wire.write(0x1C); // Accelerometer Configuration register
Wire.write(0x10); // AFS_SEL=2, Full Scale Range = +/- 8 [g]
Wire.endTransmission(true);
//MPU6050 DLPF(Digital Low Pass Filter)
Wire.beginTransmission(MPU_addr);
Wire.write(0x1A); // DLPF_CFG register
Wire.write(0x00); // Accel BW 260Hz, Delay 0ms / Gyro BW 256Hz, Delay 0.98ms, Fs 8KHz
Wire.endTransmission(true);
}
//https://blog.naver.com/PostView.nhn?blogId=ysahn2k&logNo=221385063966&categoryNo=0&parentCategoryNo=0&viewDate=¤tPage=1&postListTopCurrentPage=1&from=postView
생각해보니 mpu6050에서 dmp 기능으로
오일러 각을 잘 출력해주는데 잊고있었다.
ref : https://www.teachmemicro.com/orientation-arduino-mpu6050/
그동안 써왔던 핀 연결에다가 인터럽트 핀도 D2에 연결하자
electrocats의 mpu6050 라이브러리를 다운받고
DMP 기능으로 오일러각 출력하는 예제가 있다.
중간에 이 줄을 남겨두면 키 입력받을때까지 동작을 안하니 지워주고
업로드하자
값은 yaw pitch roll 순으로 나온다
1. yaw
2. pitch
3. roll
300x250
'로봇 > 전기전자&메카' 카테고리의 다른 글
프로토타이핑 - 35. 아두이노 모터 사용하기 (0) | 2020.08.30 |
---|---|
프로토타이핑 - 34. 밸런싱 로봇 예제 살펴보기 (0) | 2020.08.30 |
프로토타이핑 - 32. MPU6050 동작과 값 변화 (0) | 2020.08.30 |
프로토타이핑 - 31. 라즈베리파이3 opencv 설치 및 영상 스트리밍 (0) | 2020.08.30 |
프로토타이핑 - 30. 파이에서 아두이노의 MPU6050 값 읽기 (0) | 2020.08.29 |