shock_detect.ino
7.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
// 전처리부
#include <SoftwareSerial.h> // 0,1번핀 제외하고 Serial 통신을 하기 위해 선언
#include "I2Cdev.h"
#include "MPU6050.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
#define mpu_add 0x68
#define Pin_Relay 13
#define rxPin 7
#define txPin 6
SoftwareSerial mySerial(6, 7);
MPU6050 mpu;
// 변수 및 상수부
long ac_x, ac_y, ac_z, gy_x, gy_y, gy_z; //acc, gyro data (acc, gyro 계산 수식)
double angle = 0, deg; // angle, deg data (각도계산)
double dgy_x; // double type acc data
long int normal_x, normal_y, normal_z, deltha_x[3], deltha_y[3], deltha_z[3], deltha; // 노말라이즈(정규화 데이터), 가속도 변화량 표시
long int angle_value;
const int mapping_value = 5000;
const int Emergency_value = 10000; // 충격상태로 판단하는 값
const int Emergency_angle = 25; // 충격상태로 판단하는 각도(기울기)
const int Emergency_value2 = 1200;// 충격상태로 판단하는 값
const int Emergency_angle2 = 9; // 충격상태로 판단하는 각도(기울기)
boolean State_Parameter = false; // 충격상태 판단
unsigned short int shock_level; // 충격정도 상,중,하 char로 받을 생각
const long int sum_count = 4; // 평균 내는 횟수
const long interval = 50; // 충격을 감지후 다음 충격을 감지하는 최소 간극 시간 (ms)
unsigned long previousMillis = 0; // 최초 시작시간
long shock_sum = 0; // 누적 충격값
/* 사용자지정함수부
*/
// 모듈초기화
void mpu6050_init(){
Wire.begin(); //I2C통신 시작
Wire.beginTransmission(mpu_add) ; // 0x68(주소) 찾아가기
Wire.write(0x6B) ; // 0x6B의 레지스트를 0으로 함으로써 Sleep에서 깨움
Wire.write(0); // set to ZERO(WAKE UP THE MPU6050)
Wire.endTransmission(true) ;
}
// 연산에 필요한 변수들을 초기화
void value_init(){
normal_x = 0;
normal_y = 0;
normal_z = 0;
for(int i = 0; i < 3; i++){
deltha_x[i] = 0;
deltha_y[i] = 0;
deltha_z[i] = 0;
angle = 0;
angle_value = 0;
}
}
// 가속도 연산 함수
void accel_calculate() {
ac_x = 0;
ac_y = 0;
ac_z = 0;
normal_x = 0;
normal_y = 0;
normal_z = 0;
Wire.beginTransmission(mpu_add) ; // 번지수 찾기
Wire.write(0x3B) ; // 가속도 데이터 보내달라고 컨트롤 신호 보내기
Wire.endTransmission(false) ; // 기달리고,
Wire.requestFrom(mpu_add, 6, true) ; // 데이터를 받아 처리
// Data SHIFT
ac_x = Wire.read() << 8 | Wire.read() ;
ac_y = Wire.read() << 8 | Wire.read() ;
ac_z = Wire.read() << 8 | Wire.read() ;
//맵핑화 시킨 것 - 즉 10000으로 맵핑시킴
normal_x = map(int(ac_x), -16384, 16384, -5000, mapping_value);
normal_y = map(int(ac_y), -16384, 16384, -5000, mapping_value);
normal_z = map(int(ac_z), -16384, 16384, -5000, mapping_value);
//normal_z = map(int(ac_z), -16384, 16384, -1000, mapping_value);
//각도계산 deg -> 각도
deg = atan2(ac_x, ac_z) * 180 / PI ; //rad to deg
dgy_x = gy_y / 131. ; //16-bit data to 250 deg/sec
angle = (0.95 * (angle + (dgy_x * 0.001))) + (0.05 * deg) ;
}
// 충격상태함수
void Emergency_state_(){
digitalWrite(Pin_Relay , HIGH); // 릴레이핀을 True값으로 바꿔 13번 핀의 LED를 ON시킨다.
Serial.print("SHOCK level : ");
Serial.println(shock_level); // Serial 모니터로 확인
Serial.print(" x: ");
Serial.print(deltha_x[0]);
Serial.print(" y: ");
Serial.print(deltha_y[0]);
Serial.print(" z: ");
Serial.println(deltha_z[0]);
/*Serial.print(" deltha_1 : "); Serial.print(deltha_x[1]);
Serial.print(" deltha_2 : "); Serial.println(deltha_x[2]);*/
}
void Shock_Sensing(){
State_Parameter = false; // 충격상태 초기화
shock_level = 0; // 충격정도 초기화
//첫번째 센싱
for (int i=0; i < sum_count; i++){
accel_calculate();
deltha_x[1] = deltha_x[1]+(normal_x);
deltha_y[1] = deltha_y[1]+(normal_y);
deltha_z[1] = deltha_z[1]+(normal_z);
angle_value = angle_value + angle;
}
deltha_x[1] = int(deltha_x[1]/sum_count);
deltha_y[1] = int(deltha_y[1]/sum_count);
deltha_z[1] = int(deltha_z[1]/sum_count);
//두번째 센싱
for (int i=0; i < sum_count; i++){
accel_calculate();
deltha_x[2] = deltha_x[2]+(normal_x);
deltha_y[2] = deltha_y[2]+(normal_y);
deltha_z[2] = deltha_z[2]+(normal_z);
angle_value = angle_value + angle;
}
deltha_x[2] = int(deltha_x[2]/sum_count);
deltha_y[2] = int(deltha_y[2]/sum_count);
deltha_z[2] = int(deltha_z[2]/sum_count);
//3축 변화량 비교 - 가속도 변화량, 각도 평균 값
deltha_x[0] = abs(deltha_x[1]-deltha_x[2]);
deltha_y[0] = abs(deltha_y[1]-deltha_y[2]);
deltha_z[0] = abs(deltha_z[1]-deltha_z[2]);
deltha = deltha_x[0] + deltha_y[0] + deltha_z[0];
angle_value = abs(int(angle_value/(sum_count)));
// deltha : 가속도 변화량
// angle_value : 각도 값(현재 각도 값)
if (deltha > Emergency_value){
State_Parameter=true;
}
shock_level = deltha; // 추후 수정 예정
/*
if(deltha > 하){
shock_level = 'a';
if(deltha > 중){
shock_level = 'b';
if(deltha > 상){
shock_level = 'c';
}
}
}
*/
/*if (angle_value > Emergency_angle){
State_Parameter=true;
}
if ((deltha > Emergency_value2)&&(angle_value > Emergency_angle2)){
State_Parameter=true;
}*/
// 충격상태체크
if( State_Parameter == true ){
Emergency_state_();
}
else {
digitalWrite(Pin_Relay , LOW);
}
}
// BLUETOOTH TRANSACTION
/*main 함수부*/
void setup() {
Serial.begin(9600); // 시리얼 속도 설정
mySerial.begin(9600); // 블루투스 통신 시작
Serial.println("Initializing I2C devices...");
// bluetooth.begin(9600); // 블루투스 속도 설정
Serial.println("Initializing Bluetooth devices...");
mpu6050_init(); // 가속도 센서 초기화
Serial.println("Testing device connections...");
Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
pinMode(Pin_Relay, OUTPUT); // 핀모드사용, led로 육안확인 가능하게끔
digitalWrite(Pin_Relay , LOW); // HIGH - LED on, LOW - LED off (DEFAULT : OFF)
}
char char_maker(long x){ // 백그라운드 앱에 전송할 충격을 구분해서 char값으로 반환하는 함수
if(x<=15000){
return 'L';
}
else if(x<=25000){
return 'M';
}
else{ // 세게치면 40000까지 누적값이 반환되는 일이 생기는데 흔하게 일어나지는 않음
return 'H';
}
}
void loop() {
value_init(); //가속도-각도 관련 초기값 선언
// softwareSerial.print("test");
//---------dump--------------------do not erase yet-
//unsigned long currentMillis = 0;
//previousMillis = currentMillis;
//if(currentMillis - previousMillis >= interval){
//if(currentMillis - previousMillis >= interval){
//--------------------------------------------------
Shock_Sensing();
if(State_Parameter == true){
shock_sum += deltha;
// currentMillis = millis();
}
if(State_Parameter == false && shock_sum != 0){
if (Serial.available()){ // 블루투스로 충격정도 전송 (shock_maker 라는 char 리턴함수를 통해 진동강도 전송)
mySerial.write(char(char_maker(shock_sum)));
Serial.println(char_maker(shock_sum));
Serial.println("send complete");
}
//bluetooth.write(char_maker(shock_sum));
Serial.print("누적 충격값 : ");
Serial.println(shock_sum); // 충격 누적값 전송
shock_sum = 0; // 충격의 지속이 끝났으니 원래값인 0으로 초기화
}
if (mySerial.available()){ // 안드로이드 쪽에서 값을 아두이노로 가져오는 코드, 필요없을거 같아서 주석처리
Serial.write(mySerial.read());
}
}