본문 바로가기

임베디드 시스템

[아두이노] 소의 움직임 감지 센서 만들기 - 1탄 (MPU6050와 RF433MHz 센서를 이용한 무선 움직임 감지 시스템 만들기)

반응형
SMALL
축산업을 하시는 아버지를 통해 한우 - 번식우의 경우 소의 발정을 탐지하는 것이 얼마나 개채수(두 수)를 빠른 시간에 늘리는가에 달렸다고 하였다.
그리하여, MPU-6050 가속도 센서와 RF-433MHz 센서를 활용한 무선 움직임 감지 센서 시스템을 만들어보려고 한다.
왕 초보로 개발해보는 나로서 많은 공부가 필요하지만, 기초 공부만 하다가 적용할 수 있는 시간을 놓치기 보다는 무작정 만들어보면서 수정/보완해나가는 것이 좋겠다고 판단하여 부끄럽지만 하나씩 만들어서 포스팅 하련다.
가칭은 '소 발정 탐지기'인데 뭔가 어감이 좋지 않아서 제목에는 '움직임 가지 센서'로 적어 봤다.
물론. 이번 포스팅으로 끝나지 않고 시스템이 구축될 때까지 시리즈로 포스팅 할 계획이다. 

1. 준비물

 (1) 가속도 센서 MPU-6050

 

MPU-6050 6축 자이로 가속도 센서 모듈 GY-521 [SZH-EK007]

MPU-6050 칩을 사용한 센서 모듈 입니다. 게임 및 가상 현실 입력 장치, GPS 네비게이션, 로봇 시스템 등에 유용합니다.

www.devicemart.co.kr

 (2) RF-433MHz 통신 모듈 세트(송신부, 수신부)

 

[11번가] DM2146 아두이노 433MHz RF 무선 송수신 모듈 세트

카테고리: PC액세서리 기타, 가격 : 1,100

www.11st.co.kr

 (3) 아두이노 우노 (호환 보드 사용) 2개 + 아두이노-컴퓨터 USB 연결 케이블

 

아두이노 우노 R3 호환보드 [SZH-EK002]

아두이노우노 호환보드! Arduino Uno (R3)의 기능을 그대로 재현한 고품질 호환보드,1.5m USB 케이블이 포함되어 있습니다. (※해외 수입 상품으로 재고 소진 시 5일 이상 소요 될 수 있습니다.)

www.devicemart.co.kr

 (4) 점퍼케이블 (양쪽 Male / Male 모양 사용함)

 

테스트[CH254] 소켓 점퍼 케이블 40P (칼라) (M/M) 20cm

40핀 테스트 소켓 점퍼 케이블 / F-F 타입 / 2.54mm 커넥터 / 길이 : 20cm

www.devicemart.co.kr

2. 구성

 (1) RF433MHz 모듈-아두이노 연결 : 송신측 결선

송신측 결선

 (2) RF433MHz 모듈-아두이노 연결 : 수신측 결선

수신측 결선

RF433MHz 모듈의 송수신부 결선 및 코드는 아래 링크를 참고하여 구성하였다.

*출처 : https://www.youtube.com/watch?v=b5C9SPVlU4U&t=869s

 

 (3) 가속도 센서 (MPU-6050) - 아두이노 결선

MPU-6050 결선

가속도 센서 (MPU-6050)의 참고 유튜브 링크는 아래와 같다.

*출처 : https://www.youtube.com/watch?v=aFD4TMw4oJQ&t=205s

결선한 결과 사진

나는 맥북을 사용하여 C포트 밖에 없어서 C-USB 허브를 사용하였다. 여러분도 필요하시다면 사용하시면 되겠고, 필요없으시다면 컴퓨터에 바로 연결하여 사용하시길.

 

3. 코드

나는 코딩 초보로서 예제를 보면서  기초 바탕은 구성하였고, 여기저기 웹사이트 돌아다니며, 주위 사람들에게 물어물어 작성하였으므로 결과는 본 포스팅의 결론에서 볼 수 있듯이 돌아가지만, 내용상 틀린 내용이 있을 수 있음.

혹시 틀린 내용을 발견하셔서 가르침을 주실 분은 댓글 달아주시면 정말 너무나 감사드리겠습니다^^

 

(1) 송신측 코드

 

[아두이노] 라이브러리 추가 방법

아두이노로 스케치에서 코딩을 하다보면 라이브러리를 추가해야 할 때가 나온다. 그 때 당황하지 않고 라이브러릴 추가하기 위해 방법을 올려본다. 한가지 알아둘 점은 나는 Mac OS 유저라는 것!

jin-t.tistory.com

(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)은 공부시간이 필요하므로, 

다음포스팅에서 체크썸을 추가하여 해결 후 다시 코드를 올려보겠다.

도움이 되셨길 바라며, 혹시 가르침을 주실 분은 댓글 남겨주시면 감사드리겠습니다.^^

반응형
LIST