본문 바로가기

관리하지않음/라즈베리파이

라즈베리파이4 안드로이드 블루투스 통신하기

라즈베리파이4와 안드로이드 사이에 블루투스 연결을 시도했습니다. 라즈베리파이4에서 블루투스 통신을 하기 위한 코드는 파이썬으로 작성했습니다.

 

라즈베리파이, 안드로이드, 블루투스 통신 관련 포스팅은 많았지만 돌발변수가 많아서 대부분의 포스팅이 저에게 도움이 되질 않았습니다;ㅅ; 하지만 긴 삽질 끝에 겨우 custom 안드로이드 앱 개발까지 성공했습니다.. 어떤 문제가 있었는지, 어떻게 해결했는지를 간략하게 정리했습니다.

1. 필요한 라이브러리 설치

// 라즈베리파이 업데이트
Sudo apt-get update
Sudo apt-get upgrade

// 필요한 라이브러리 설치
Sudo apt-get install bluetooth blueman bluez
Sudo apt-get install python-bluetooth

// 재부팅
Sudo reboot

2. 블루투스 페어링

sudo bluetoothctl

아래와 같이 [bluetooth]# 으로 변경됩니다.

 

라즈베리파이 화면 캡쳐

scan on

scan on 명령어를 통해서 주변 블루투스 기기를 스캔합니다.

저의 스마트폰의 MAC 주소는 50:77:05:5F:37:5C였습니다.

 

라즈베리파이 화면 캡쳐

pair MAC주소
trust MAC주소

저는 연결을 위해서 "pair 50:77:05:5F:37:5C"을 터미널에 입력했습니다.

pair 명령어를 치면, 스마트폰에서는 블루투스 연결 요청이 뜹니다.

 

블루투스 연결 요청

확인을 눌러주셔야 블루투스 연결이 됩니다.

라즈베리파이에서도 Confirm passkey OOOOOO (yes/no): 하고 입력창이 뜹니다.

yes라고 타이핑해주셔야 블루투스 연결이 됩니다.

 

라즈베리파이 화면 캡쳐 - pair

여기까지 하면 라즈베리파이↔️안드로이드 블루투스 페어링이 설정되었습니다.

3. 데이터 송/수신

데이터 송/수신 테스트를 위해서 Blueterm 어플을 설치합니다.

 

구글 플레이스토어 캡쳐

라즈베리파이에서 데이터를 수신하기 위한 코드는 파이썬으로 작성했습니다. 저는 라즈베리파이에 기본으로 설치되어있는 Tonny Python IDE를 사용했습니다.

 

상단의 라즈비안 아이콘>Programming>Thonny Python IDE를 켜고 아래 코드를 복붙 해주세요. 파일 이름은 example.py 정도로 저장해주세요. 절대 bluetooth.py로 저장하시면 안 됩니다!

from bluetooth import *

server_socket= BluetoothSocket(RFCOMM)

port = 1
server_socket.bind(("", port))
server_socket.listen(1)

client_socket, address = server_socket.accept()
print("Accepted connection from ", address)

client_socket.send("bluetooth connected!")

while True:
    data = client_socket.recv(1024)
    print("Received: %s" %data)
    if(data=="q"):
        print("Quit")
        break

client_socket.close()
server_socket.close()

IDE에서 RUN 버튼을 눌러서 코드를 실행시킵니다.

 

라즈베리파이 화면 캡쳐 - Thonny Python IDE

그러고 나서 Blueterm에서 raspberrypi와 연결을 요청합니다.

 

blueterm 캡쳐 화면

연결에 성공하면 blueterm에서 "bluetooth connected!"가 출력됩니다.

 

화면 캡쳐

Python IDE의 쉘을 확인하면 제 스마트폰 MAC주소를 가진 기기와 연결이 되었다는 메시지가 출력됩니다. 이제 스마트폰에서 문자를 치면 한 글자씩 보내집니다.

 

라즈베리파이 화면 캡쳐 - 안드로이드 앱에서 데이터를 받아오는 모습

4. 이 짧은 포스팅을 위해 삽질한 것들

(1) 한번 페어링이 되고 나면, scan on을 했을 때 스캔되지 않는 문제

스마트폰 설정> 블루투스에서 페어링 된 기기를 삭제하고 나면, 다시 스캔이 되었습니다.

 

화면 캡쳐

(2) Blueterm 말고 되는 다른 어플

라즈베리파이↔️안드로이드 블루투스 연결 관련 포스팅은 모두 Blueterm을 사용하라는 말 뿐이었습니다. Blueterm은 마지막 업데이트가 2013년인 어플입니다. 더 좋은 어플을 찾기 위해서 구글 플레이에 존재하는 대부분의 블루투스 어플을 깔아본 것 같습니다.

 

화면 캡쳐

결론부터 말씀드리자면 더 좋은 어플 찾는 건 실패했습니다. 이 많은 어플 중에서 Blueterm과 Pi3 Bluetooth Manager만 라즈베리파이와 블루투스 연결이 되었습니다. 이전에 제가 만든 안드로이드 블루투스 어플도 연결에 실패했습니다.

(3) 안드로이드 Custom 앱 코드

제가 만든 어플리케이션에서 코드를 계속 수정해서 확인한 결과, 

read failed, socket might closed or timeout, read ret: -1

에러가 나면서 블루투스 연결에 실패하더라구요.

 

이 문제의 해결방법은 StackOverflow에서 자세한 해결방법을 찾을 수 있었는데요, 행운인지 아닌지 Blueterm의 코드가 깃헙에 올라와있었습니다.

 

깃헙의 코드를 참고해서, 제가 만든 안드로이드 블루투스 어의 MainActivity.java의 160번째 줄부터 시작하는 create&connect socket부분 코드를 다음과 같이 수정했습니다.

// create & connect socket
try {
	btSocket = createBluetoothSocket(device);
} catch (IOException e) {
	flag = false;
    textStatus.setText("socket creation failed!");
    e.printStackTrace();
}

/* 주석처리
try {
	btSocket.connect();
} catch (IOException e) {
	flag = false;
    textStatus.setText("connection failed!");
    e.printStackTrace();
}

// start bluetooth communication
if(flag){
	textStatus.setText("connected to "+name);
    connectedThread = new ConnectedThread(btSocket);
    connectedThread.start();
}
*/

// Make a connection to the BluetoothSocket
try {
	btSocket.connect();
} catch (IOException e) {
// Close the socket
	try {
		btSocket.close();
	} catch (IOException e2) {
		Log.e(TAG, "unable to close() socket during connection failure", e2);
	}
}

connectedThread = new ConnectedThread(btSocket);
textStatus.setText("connected to "+name);
connectedThread.start();

기존의 connect는 주석 처리하고 blueterm의 코드를 가져왔습니다.

소켓과 connect 하는 코드를 변경하니까 라즈베리파이와 연결에 성공했습니다.

 

스마트폰 화면 캡쳐

connect가 성공하면 SEND A버튼을 눌렀을 때, 라즈베리파이에 a가 전송됩니다.

 

긴 삽질을 하고 나니까 소켓 connect와 관련된 공부를 하고 나니까 왜 블루투스 연결이 되는 어플이 있고, 아닌 어플이 있는지 알게 되었습니다..

(4) 안드로이드→라즈베리파이로 보낸 데이터 형식

안드로이드에서 라즈베리파이로 데이터를 보내는 것에는 성공했지만, 문제는 문자열 a만 보내도 라즈베리파이에서 b'a'로 읽어졌습니다. 이 문제는 아직까지 해결을 못했습니다. 그래서 q를 보내도 python의 while문 탈출이 안됩니다. b'q'로 변경해도 마찬가지로 안됐습니다.

 

저는 안드로이드 앱 custom이 제일 급해서 이 문제는 뒷전이었는데요, 나중에 해결방법을 찾으면 공유하겠습니다.

 


잘못된 내용이 있다면 언제든지 댓글이나 메일로 알려주시면 감사하겠습니다.

이 포스팅이 도움이 되었다면 공감 부탁드립니다.

궁금한 점은 언제든지 댓글 남겨주시면 답변해드리겠습니다:D