0과 1을 공부하다.

[Communication] 구형 건축물에서의 스마트홈 구축 프로젝트 - 블루투스 통신 본문

Project/Smart Home

[Communication] 구형 건축물에서의 스마트홈 구축 프로젝트 - 블루투스 통신

Developer_Jay 2022. 4. 1. 02:03
728x90
개요

 

 본 프로젝트의 기획단계에서 기기간의 연결성과 사용자와 상호작용을 위해 서버와 센서간 Bluetooth 통신을 계획했다. 이번 게시물은 스마트홈에 빌드하여 바로 적용하는 코드가 아닌 서버-센서간 통신을 위한 기초 예제이다. 본 예제는 향후 Sensor에서 다루는 내용에 기본적으로 포함되는 예제이므로 반드시 확인하고 넘어가야하는 항목 중 하나이다. 

 

 

Arduino

 

가. 환경구성

  •  앞서 2-1에서 Arduino IDE를 설치했다면 별도의 환경구성은 필요없다.
  •  본 예제에서 사용된 MCU와 센서는 Arduino UNO, HC-06)을 사용하였다. 

 

 

나. 회로연결

tinkercad를 이용하여 도식하였음.

 

  • 블루투스 모듈(HC-06)에 Arduino에서 5V를 인가한다. (5v, GUD 결선)
  • 소스코드에서 지정한 RX(수신) 아날로그 포트와 블루투스 모듈의 TX(송신) 포트 결선한다.
  • 소스코드에서 지정한 TX(송신) 아날로그 포트와 블루투스 모듈의 RX(수신) 포트 결선한다.

 

 

다. 소스코드

#include <SoftwareSerial.h>

// 송/수신 포트지정
int RX=7; // 아두이노 디지털 7번 핀과 BT 모듈 TX 연결
int TX=8; // 아두이노 디지털 8번 핀과 BT 모듈 RX 연결

SoftwareSerial bluetooth(RX, TX);

void setup(){
  Serial.begin(9600);
  bluetooth.begin(9600);
}
 
void loop(){
  // 데이터 수신
  if (bluetooth.available()) // 블루투스 시리얼에서 읽을 수 있는 바이트의 수가 0이 아니면
  {
    Serial.write(bluetooth.read());
  }
  // 데이터 송신
  if (Serial.available()) // 아두이노 시리얼에서 읽을 수 있는 바이트의 수가 0이 아니면
  {
    bluetooth.write(Serial.read()); 
  }
}

 

 

라. 코드 분석

 

  • 아날로그 송/수신 포트를 지정하고 아두이노의 RX(수신) TX(송신)를 블루투스의 RX(수신) TX(송신)와 크로스 연결(반대로)한다.  
// 송/수신 포트지정
int RX=7; // 아두이노 디지털 7번 핀과 BT 모듈 TX 연결
int TX=8; // 아두이노 디지털 8번 핀과 BT 모듈 RX 연결

 

  • 블루투스 객체 생성
SoftwareSerial bluetooth(RX, TX);

 

  • 각 기기의 시리얼 통신을 통해 입/출력된 데이터가 존재한다면 데이터 송신 및 출력  
// 데이터 수신
if (bluetooth.available()) {...} // 블루투스 시리얼에서 읽을 수 있는 바이트의 수가 0이 아니면

// 데이터 송신
if (Serial.available()) {...} // 아두이노 시리얼에서 읽을 수 있는 바이트의 수가 0이 아니면

 

 

마. Github  Link: Github

 

 

 

 

Raspberry PI

 

가. 환경 구성

  • Raspberry PI 내 Bluetooth 모듈 내장으로 별도의 회로 연결은 필요없다.
  • 2-1에서 공개한 쉘스크립트를 실행하면 별도의 라이브러리 설치는 불필요하다.
  • 2-1의 쉘스크립트에서 라이브러리를 설치하지 않았다면 아래의 라이브러리를 설치한다.
$ sudo apt-get install bluetooth blueman bluez
$ sudo apt-get install python-bluetooth
$ sudo apt-get install bluez libbluetooth-dev pi-bluetooth 
$ pip3 install pybluez

 

 

나. 블루투스 스캔/페어링

  • sudo 명령을 통해 블루투스 컨트롤(bluetoothctl)을 시작한다.
  • 전원을 켜고(power) 블루투스 검색(scan)을 한다.
  • 검색된 목록에서 자신이 연결하고자 하는 모듈을 찾는다.  (필자는 HC-06 모듈을 찾았다.) 
  • 찾은 모듈의 MAC주소를 메모장에 잠시 기입한다.
  • 찾은 모듈을 연결(pair)한다.  
  • 연결한 장치에 대한 신뢰(trust) 설정을 한다. 
  • 코드기입 방법은 아래의 코드를 참고한다. 
# 블루투스 컨트롤 시작
$ sudo bluetoothctl

# 블루투스 전원 on 
> power on

# 블루투스 검색(스캔)
> scan on

# 블루투스 페어링
> pair Bluetooth_Mac주소 # ex) pair 98:DA:D0:00:56:A2

# 장치 신뢰 설정
> trust Bluetooth_Mac주소 # ex) trust 98:DA:D0:00:56:A2

 

 

다. 소스코드

import threading
from bluetooth import *
import sys

socket = BluetoothSocket(RFCOMM)

#socket.connect((sys.argv[1], 1)) # 대상 디바이스의 맥주소를 실행시 인자값으로 받음

mac_add = "98:DA:D0:00:56:A2"

try:
    socket.connect((mac_add, 1)) # 대상 디바이스 맥주소 입력
except:
    print("Con't Connect Bluetooth Pair.")
    socket.close(s)
    exit()

print("Bluetooth connected!")

# Arduino to Python  Data 수신 함수
def data_receive():
    while True:
        data = socket.recv(1024)
        decode_data = data.decode() # 문자열 형태임
        decode_data = decode_data.strip() # 문자열 끝 개행제거 
        
        if (decode_data.isdigit()==True):
            result = int(decode_data)
        else:
            result = decode_data
        
        print()
        print("receive message :", result)

# Python to Arduino Data 송신 함수 
def data_send():
    msg = input("send message : ")
    socket.send(msg)


# 메세지를 받는 쓰레드 생성
receive_t = threading.Thread(target=data_receive, args=())
receive_t.start()


while True:
    data_send()
    
socket.close()

 

 

라. 코드 분석

  • bluetooth소켓 생성 및 연결
    • bluetooth 소켓을 생성하고 연결한다. 
    • connect()에 MAC주소를 전달 할 때 실행 인자값으로 전달하거나 직접 입력하거나 본인의 선택에 따라 입력한다. 
    • try-except를 통해 connect에 대한 예외처리를 한다. 
socket = BluetoothSocket(RFCOMM)

socket.connect((sys.argv[1], 1)) # 대상 디바이스의 맥주소를 실행시 인자값으로 받음
socket.connect(("98:DA:D0:00:56:A2", 1)) # 직접 입력


  • 데이터 송/수신
    • 생성한 소켓에서 데이터를 송/수신한다. 
    • recv()를 통해 라즈베리로부터 데이터를 수신한다. 인자로 수신할 바이트의 크기를 지정한다. 
    • send()를 통해 아두이노로 데이터를 송신한다. 송신할 데이터를 인지로 전달한다.  
socket.recv(1024)

socket.send("안녕")

 

  • 병렬처리
    • 데이터 송/수신을 동시에 진행하려면 병렬처리가 필요하다. 그 이유는 라즈베리파이에서 데이터 송신을 위해 사용자 입력을 대기(wait)하고 있는 상태에서는 다른 코드를 실행하지 않기 때문이다. 
    • 멀티쓰레드를 통해 데이터 송/수신을 동시적으로 구현한다. 
    • threading 모듈을 import한다. 
    • 데이터를 수신받는 함수를 구현하고 쓰레드를 생성(Thread)한다.
    • 쓰레드를 시작(start)한다. 
import threading

receive_t = threading.Thread(target=data_receive, args=())
receive_t.start()

 

 

마. GitHub Link: Github

 

 

 

 

실행결과

 

  위 아두이노 스케치 파일을 보드에 업로드하고 라즈베리파이에서 Python으로 실행한다. 

 

실행하고 라즈베리파이에서 아두이노로 메세지를 보내면 아두이노의 시리얼 모니터에서 정상적으로 출력함을 확인할 수 있다.

 

 

이어서 아두이노 시리얼 모니터에서 메세지를 보내면 라즈베리파이에서 정상적으로 메세지를 출력함을 확인할 수 있다. 

 

 

 

 

 

참고문헌

 

[1] arduino

 

[2] Raspberry PI

 

[3] ETC

 

 

 

※ 본 게시글의 정보가 잘못 되었거나 부족한 부분에 대한 피드백을 환영합니다.

※ 본 프로젝트는 오픈소스 프로젝트로 인용 /수정 /사용을 허용합니다. 

 

 

* CopyRight 2022. Jay Park All rights reserved.

728x90
Comments