축산업을 하시는 아버지를 통해 한우 - 번식우의 경우 소의 발정을 탐지하는 것이 얼마나 개채수(두 수)를 빠른 시간에 늘리는가에 달렸다고 하였다.
그리하여, MPU-6050 가속도 센서와 RF-433MHz 센서를 활용한 무선 움직임 감지 센서 시스템을 만들어보려고 한다.
왕 초보로 개발해보는 나로서 많은 공부가 필요하지만, 기초 공부만 하다가 적용할 수 있는 시간을 놓치기 보다는 무작정 만들어보면서 수정/보완해나가는 것이 좋겠다고 판단하여 부끄럽지만 하나씩 만들어서 포스팅 하련다.
가칭은 '소 발정 탐지기'인데 뭔가 어감이 좋지 않아서 제목에는 '움직임 가지 센서'로 적어 봤다.
물론. 이번 포스팅으로 끝나지 않고 시스템이 구축될 때까지 시리즈로 포스팅 할 계획이다.
1. 준비물
(1) 가속도 센서 MPU-6050
https://link.coupang.com/a/m1hzc
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."
(2) RF-433MHz 통신 모듈 세트(송신부, 수신부)
https://link.coupang.com/a/m1hHz
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."
(3) 아두이노 우노 (호환 보드 사용) 2개 + 아두이노-컴퓨터 USB 연결 케이블
https://link.coupang.com/a/m1hOv
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."
(4) 점퍼케이블 (양쪽 Male / Male 모양 사용함)
https://link.coupang.com/a/m1hWw
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."
2. 구성
(1) RF433MHz 모듈-아두이노 연결 : 송신측 결선
(2) RF433MHz 모듈-아두이노 연결 : 수신측 결선
RF433MHz 모듈의 송수신부 결선 및 코드는 아래 링크를 참고하여 구성하였다.
(3) 가속도 센서 (MPU-6050) - 아두이노 결선
가속도 센서 (MPU-6050)의 참고 유튜브 링크는 아래와 같다.
나는 맥북을 사용하여 C포트 밖에 없어서 C-USB 허브를 사용하였다. 여러분도 필요하시다면 사용하시면 되겠고, 필요없으시다면 컴퓨터에 바로 연결하여 사용하시길.
3. 코드
나는 코딩 초보로서 예제를 보면서 기초 바탕은 구성하였고, 여기저기 웹사이트 돌아다니며, 주위 사람들에게 물어물어 작성하였으므로 결과는 본 포스팅의 결론에서 볼 수 있듯이 돌아가지만, 내용상 틀린 내용이 있을 수 있음.
혹시 틀린 내용을 발견하셔서 가르침을 주실 분은 댓글 달아주시면 정말 너무나 감사드리겠습니다^^
(1) 송신측 코드
(2) 송신측 코드
#include<Wire.h> //I2C통신을 위한 헤더
#include<RH_ASK.h> //무선통신을 위한 헤더
#include<SPI.h> //SPI통신용 헤더
#include<stdint.h> //비트단위 integer 변수 설정할때 사용
RH_ASK rf_driver;
const int MPU=0x68; //MPU 6050 의 I2C 기본 주소
//#define MPU 0x68 으로도 가능(변수 메모리할당 없음)
//int MPU=0x68 로 하면 메모리가 할당되어 메모리 잡아먹음
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; //16bit(=2byte)크기의 부호가 있는 정수형 변수
//-32768 ~ +32767까지 표현 가능
String str_AcX, str_AcY, str_AcZ;
String len_str_AcX, len_str_AcY, len_str_AcZ;
String out_str_Compose;
void setup(){
//Initialize ASK object
rf_driver.init();
Wire.begin(); //Wire 라이브러리 초기화
Wire.beginTransmission(MPU); //MPU로 데이터 전송 시작
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); //MPU-6050 시작 모드로
Wire.endTransmission(true);
Serial.begin(9600);
}
void loop(){
Wire.beginTransmission(MPU); //데이터 전송시작
Wire.write(0x3B); // register 0x3B (ACCEL_XOUT_H), 큐에 데이터 기록
Wire.endTransmission(false); //연결유지
Wire.requestFrom(MPU,14,true); //MPU에 데이터 요청
//데이터 한 바이트 씩 읽어서 반환
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)
Serial.print("AcX = "); Serial.println(AcX); //확인용
delay(200);
//Convert AcX to string
str_AcX = String(AcX);
str_AcY = String(AcY);
str_AcZ = String(AcZ);
str_Tmp = String(Tmp);
str_GyX = String(GyX);
str_GyY = String(GyY);
str_GyZ = String(GyZ);
len_str_AcX = str_AcX.length();
len_str_AcY = str_AcY.length();
len_str_AcZ = str_AcZ.length();
len_str_Tmp = str_Tmp.length();
len_str_GyX = str_GyX.length();
len_str_GyY = str_GyY.length();
len_str_GyZ = str_GyZ.length();
out_str_Compose = len_str_AcX + str_AcX
+ "," + len_str_AcY + str_AcY
+ "," + len_str_AcZ + str_AcZ;
static char *msg = out_str_Compose.c_str();
rf_driver.send((uint8_t *)msg, strlen(msg));
rf_driver.waitPacketSent();
Serial.print("Transmit check = "); Serial.println(msg); //확인용
}
(3) 수신측 코드
#include <RH_ASK.h>
#include <SPI.h>
RH_ASK rf_driver;
void setup() {
rf_driver.init();
Serial.begin(9600);
}
void loop() {
uint8_t buf[255];
uint8_t buflen = sizeof(buf);
if (rf_driver.recv(buf, &buflen))
{
String str_buf;
String len_AcX, len_AcY, len_AcZ;
String AcX, AcY, AcZ;
str_buf = buf; //들어온 데이터를 String으로 변환
int index_first;
int index_second;
long toint_len_AcX, toint_len_AcY, toint_len_AcZ; //int로 변환
index_first = str_buf.indexOf(',');
index_second = str_buf.indexOf(",",index_first+1);
len_AcX = str_buf.charAt(0); //AcX의 문자 길이
len_AcY = str_buf.charAt(index_first+1); //AcY의 문자 길이
len_AcZ = str_buf.charAt(index_second+1); //AcZ의 문자 길이
toint_len_AcX = len_AcX.toInt(); //integer로 변환
toint_len_AcY = len_AcY.toInt();
toint_len_AcZ = len_AcZ.toInt();
int cut_end = toint_len_AcX + toint_len_AcY + toint_len_AcZ + 5;
String str_cut = str_buf.substring(0,cut_end+1);
int cut_index_first = str_cut.indexOf(',');
int cut_index_second = str_cut.indexOf(',',cut_index_first+1);
AcX = str_cut.substring(1 , toint_len_AcX+1);
AcY = str_cut.substring(cut_index_first+2 , cut_index_first+2 + toint_len_AcY);
AcZ = str_cut.substring(cut_index_second+2 , cut_index_second+2+toint_len_AcZ);
Serial.print("AcX = "); Serial.println(AcX);
Serial.print("AcY = "); Serial.println(AcY);
Serial.print("AcZ = "); Serial.println(AcZ);
}
}
일단 위와같이 하면 데이터는 출력되고 넘어가긴한다.
하지만, 데이터가 유효한 데이터가 송신측에서 나오지 않고 당연히 유요한 데이터가 수신되지 않는다.
그러므로, 체크썸 코드를 넣어야겠다는 배움을 얻었지만, 아직 체크썸(Checksum)은 공부시간이 필요하므로,
다음포스팅에서 체크썸을 추가하여 해결 후 다시 코드를 올려보겠다.
도움이 되셨길 바라며, 혹시 가르침을 주실 분은 댓글 남겨주시면 감사드리겠습니다.^^
'임베디드 시스템' 카테고리의 다른 글
포트 포워딩: 공개 네트워크에서 사설 네트워크로의 문 / Port Forwarding: Accessing Private Networks from Public Networks (15) | 2023.02.28 |
---|---|
ESP32 CAM을 이용한 홈 CCTV 구성하기 / 축사 CCTV 구성 : Easy Guide to Setting up Home or Barn CCTV using ESP32 CAM (13) | 2023.02.27 |
[아두이노] 라이브러리 추가 방법 (0) | 2020.10.08 |
아두이노 프로그램(앱) 맥북에 설치하기 (3) | 2020.08.31 |