BASIC4MCU | 질문게시판 | 아두이노 동시동작
페이지 정보
작성자 죠르디 작성일2022-06-19 20:19 조회642회 댓글7건본문
저번에 동시동작하는 거 답변해주신 거 많은 도움 되었습니다!! 하지만 온도센서는 제대로 동작하여 앱에 뜨는 것 같은데 자이로센서는 한번 일정값 이상이 되어 스피커에 부저가 울리면 그 값이 넘지 않아도 계속 울립니다. 이유를 모르겠어서 질문드려요 ! 도와주시면 정말 감사하겠습니다.
#include <Wire.h>
#include "DHT.h"
#include <SoftwareSerial.h>
#define DHTPIN 4 // SDA 핀의 설정
#define DHTTYPE DHT22 // DHT22 (AM2302) 센서종류 설정
DHT dht(DHTPIN, DHTTYPE);
SoftwareSerial BTserial(8,9); //블루투스 연결
//
const int MPU_ADDR = 0x68; // I2C통신을 위한 MPU6050의 주소
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ; // 가속도(Acceleration)와 자이로(Gyro)
double angleAcX, angleAcY, angleAcZ;
double angleGyX, angleGyY, angleGyZ;
double angleFiX, angleFiY, angleFiZ;
const double RADIAN_TO_DEGREE = 180/ 3.14159;
const double DEG_PER_SEC = 32767 / 250; // 1초에 회전하는 각도
const double ALPHA = 1 / (1 + 0.04);
// GyX, GyY, GyZ 값의 범위 : -32768 ~ +32767 (16비트 정수범위)
unsigned long now = 0; // 현재 시간 저장용 변수
unsigned long past = 0; // 이전 시간 저장용 변수
double dt = 0; // 한 사이클 동안 걸린 시간 변수
double averAcX, averAcY, averAcZ;
double averGyX, averGyY, averGyZ;
//
long t,t1;
//
void getData() {
Wire.beginTransmission(MPU_ADDR);
Wire.write(0x3B); // AcX 레지스터 위치(주소)를 지칭합니다
Wire.endTransmission(false);
Wire.requestFrom(MPU_ADDR, 14, true); // AcX 주소 이후의 14byte의 데이터를 요청
AcX = Wire.read() << 8 | Wire.read(); //두 개의 나뉘어진 바이트를 하나로 이어 붙여서 각 변수에 저장
AcY = Wire.read() << 8 | Wire.read();
AcZ = Wire.read() << 8 | Wire.read();
Tmp = Wire.read() << 8 | Wire.read();
GyX = Wire.read() << 8 | Wire.read();
GyY = Wire.read() << 8 | Wire.read();
GyZ = Wire.read() << 8 | Wire.read();
}
//
void getDT() {
now = millis();
dt = (now - past) / 1000.0;
past = now;
}
//
void caliSensor() {
double sumAcX = 0 , sumAcY = 0, sumAcZ = 0;
double sumGyX = 0 , sumGyY = 0, sumGyZ = 0;
getData();
for (int i=0;i<10;i++) {
getData();
sumAcX+=AcX; sumAcY+=AcY; sumAcZ+=AcZ;
sumGyX+=GyX; sumGyY+=GyY; sumGyZ+=GyZ;
delay(50);
}
averAcX=sumAcX/10; averAcY=sumAcY/10; averAcZ=sumAcY/10;
averGyX=sumGyX/10; averGyY=sumGyY/10; averGyZ=sumGyZ/10;
}
//
void setup() {
dht.begin();
initSensor();
BTserial.begin(9600);
Serial.begin(115200);
caliSensor(); // 초기 센서 캘리브레이션 함수 호출
past = millis(); // past에 현재 시간 저장
pinMode(13,OUTPUT);
}
//
void loop() {
getData();
getDT();
angleAcX = atan(AcY / sqrt(pow(AcX, 2) + pow(AcZ, 2)));
angleAcX *= RADIAN_TO_DEGREE;
angleAcY = atan(-AcX / sqrt(pow(AcY, 2) + pow(AcZ, 2)));
angleAcY *= RADIAN_TO_DEGREE;
// 가속도 센서로는 Z축 회전각 계산 불가함.
// 가속도 현재 값에서 초기평균값을 빼서 센서값에 대한 보정
angleGyX += ((GyX - averGyX) / DEG_PER_SEC) * dt; //각속도로 변환
angleGyY += ((GyY - averGyY) / DEG_PER_SEC) * dt;
angleGyZ += ((GyZ - averGyZ) / DEG_PER_SEC) * dt;
// 상보필터 처리를 위한 임시각도 저장
double angleTmpX = angleFiX + angleGyX * dt;
double angleTmpY = angleFiY + angleGyY * dt;
double angleTmpZ = angleFiZ + angleGyZ * dt;
// (상보필터 값 처리) 임시 각도에 0.96가속도 센서로 얻어진 각도 0.04의 비중을 두어 현재 각도를 구함.
angleFiX = ALPHA * angleTmpX + (1.0 - ALPHA) * angleAcX;
angleFiY = ALPHA * angleTmpY + (1.0 - ALPHA) * angleAcY;
if(abs(angleFiX) >= 50) {
tone(13,261.6,1000);}
angleFiZ = angleGyZ; // Z축은 자이로 센서만을 이용하열 구함(가속도센서 z축 회전 감지 불가)
//Serial.print("AngleAcX:"); Serial.print(angleAcX);
Serial.print("\t FilteredX:"); Serial.print(angleFiX);
//Serial.print("\t AngleAcY:"); Serial.print(angleAcY);
Serial.print("\t FilteredY:"); Serial.println(angleFiY);
//Serial.print("\t AngleGyZ:"); Serial.print(angleGyZ);
//Serial.print("\t FilteredZ:"); Serial.println(angleFiZ);
//Serial.print("Angle Gyro X:"); Serial.print(angleGyX);
//Serial.print("\t\t Angle Gyro y:"); Serial.print(angleGyY);
//Serial.print("\t\t Angle Gyro Z:"); Serial.println(angleGyZ);
//delay(20);
//----------------------
t=millis();
if(t-t1>=1000){ t1=t; // 매 1초마다
float t=dht.readTemperature();
float h=dht.readHumidity();
if(isnan(t) || isnan(h)){ Serial.println("Failed to read from DHT"); }
else{
Serial.print("Temperature: "); Serial.print(t); Serial.print(" ºC\t");
Serial.print("Humidity: "); Serial.print(h); Serial.println(" % rH");
}
BTserial.print(t); BTserial.println(" ºC");
BTserial.print(h); BTserial.println(" %");
if(t>=29 || h>=80){ BTserial.println("기저귀를 확인하세요."); }
else { BTserial.println("기저귀가 뽀송합니다."); }
}
}
//
void initSensor() {
Wire.begin();
Wire.beginTransmission(MPU_ADDR); // I2C 통신용 어드레스(주소)
Wire.write(0x6B); // MPU6050과 통신을 시작하기 위해서는 0x6B번지에
Wire.write(0);
Wire.endTransmission(true);
}
//
댓글 7
조회수 642죠르디님의 댓글
죠르디 작성일시리얼모니터에 자이로센서 값이 일정한 주기로 뚝뚝 끊어져서 나오는데 그래서 이러는 걸까요..?
master님의 댓글
master 작성일
angleFiX = ALPHA * angleTmpX + (1.0 - ALPHA) * angleAcX;
angleFiY = ALPHA * angleTmpY + (1.0 - ALPHA) * angleAcY;
if(abs(angleFiX) >= 50) {
Serial.print("test"); Serial.print(angleFiX); // <-- 추가해서 왜 if문이 실행 됬는지 체크하세요
tone(13,261.6,1000);}
죠르디님의 댓글
죠르디
확인해봤는데 기울일 때 잘 울리긴 하는데 이게 짧은 시간 기울어서 부저를 울렸다가 원위치 시키면 다시 부저가 안울리는데 좀 오래 옆으로 기울여서 부저를 울리면 다시 원위치 시켜도 부저가 안꺼지고 계속 울리더라구요..
master님의 댓글
master
좀 오래 옆으로 기울여서 부저를 울리면 다시 원위치 시켜도 부저가 안꺼지고 계속 울리더라구요.. <-- 이렇게 표현하면 안되는 이유가
if(abs(angleFiX) >= 50) {
tone(13,261.6,1000);}
if()문 조건에 부합하지 않는데도 부저가 울립니다. <-- 이렇게 보이기 때문입니다.
오래 기울이든 짧게 기울이든
if()문에 부합하지 않으면 부저가 울릴리가 없습니다.,
오래 기울이면 아래 if문이 왜 실행 되는지를 체크하세요
if(abs(angleFiX) >= 50) {
angleFiX 이 값을 시리얼모니터에 출력하고 있으니 쉽게 체크가 가능 할 겁니다.
죠르디님의 댓글
죠르디
저도 angleFiX값이 50을 넘지 않았는데도 부저가 울리는 이유를 모르겠습니다. 시리얼모니터의 값은 정확히 출력되는 듯하고 50이 넘을때만 체크해보라고 하신 test구문이 나오는데 부저는 한번 50이 넘으면 울리고 그 상태로 오래 지속되면 원위치시켜 값이 50이 넘지 않는 값이 시리얼모니터에 뜰때도 부저가 맘대로 울립니다,,
master님의 댓글
master
그 상태로 오래 지속되면 원위치시켜 값이 50이 넘지 않는 값이 시리얼모니터에 뜰때도 부저가 맘대로 울립니다,, <-- 이렇게 적지말고 시리얼모니터 캡쳐한 값을 올리세요
abs() 함수가 무엇인지 모르시는 듯
if()문이 엉터리로 동작하는 것을 40년이 넘도록 단 한 번도 본 적이 없습니다.
if()문은 기장 기초적인 문법으로, 모든 c 소스에서 사용합니다.
이렇게 흔하게 자주 사용하는 문법이 엉터리라면 그 컴파일러는 버전픽스 될리가 없습니다.
죠르디님의 댓글
죠르디
abs 함수는 절대값으로 알고 있는데 틀렸나요? 새로 글 올렸습니다.