이번에는 블루투스 모듈을 이용해서 원격으로 자동차를 조종할 수 있는 방법에 대해서 다뤄보겠습니다!
자율주행차량까지는 아직이지만, 원격으로 조종할 수 있다면 RC카와 비슷하게는 만들어졌다고 생각합니다.
재미있는 부분이라고 생각합니다.
아두이노 및 라즈베리파이에는 HC-06이라는 블루투스 모듈이 존재합니다.
블루투스는 1994년에 최초로 개발 된 근거리 무선 통신을 위한 산업 표준입니다.
HC-06이라는 모듈은 시리얼 통신을 통해서 데이터를 주고 받을 수 있게 해줍니다.
가용 거리는 10미터 정도 된다고 합니다.
라즈베리 버튼 > Preference > Raspberry Pi Configuration에 들어갑니다.
블루투스 모듈의 시리얼 통신을 사용하기 위해서 Serial Port라는 부분을 Enable해줍니다.
블루투스 모듈은 RXD, TXD, Ground, Vcc의 4개의 핀이 존재합니다.
RX, TX는 각 GPIO핀 14, 15에 연결했고, 나머지 Ground, Vcc는 맞는 곳에 연결시켜 주었습니다.
이렇게 블루투스 모듈에 빨간불이 번쩍번쩍 깜빡이면, 연결이 되었습니다.
블루투스 모듈이 연결되었으면, 시리얼 통신을 해봅시다!
블루투스 모듈의 TXD, RXD핀이 시리얼 통신으로 할당이 되어있는데, 라즈비안에서는 이를 /dev/serial0으로 부릅니다.
라즈비안의 터미널창으로 가서
ls -l /dev/serial0 |
위 명령어를 실행해보면, serial0이 연결된 이름을 찾을 수 있는데요.
ttyS0으로 연결되었음을 확인할 수 있었습니다.
이 이름은 이후 블루투스 모듈을 사용할 코드를 짤 때, serial0에 접속시킬 이름입니다!
import serial #시리얼을 불러온다. BlSerial = serial.Serial("/dev/ttyS0", baudrate=9600, timeout=1.0) #dev/ttyS0을 시리얼통신핀으로 사용한다. 9600의 통신속도를 가지고, 1초이상 데이터가 들어오지않으면 timeout된다. try: while True: sendData = "nice to meet you! \r\n" #nice to meet you!라는 메세지. 즉 데이터를 보낸다. BlSerial.write(sendData.encode()) #write를 이용해서 위의 메세지를 시리얼 데이터로 전송한다. data = BlSerial.readline() #한줄씩 값을 받는다. data = data.decode() #decode로 시리얼통신의 bytes 타입을 문자열 타입으로 변경한다. print(data) #data를 출력한다. except KeyboardInterrupt: #키보드에서 Ctrl+c가 눌려지면 종료합니다. pass BlSerial.close() |
위의 코드를 준비합니다.
nice to meet you라는 데이터를 보내서, 라즈베리파이 > 스마트폰 으로 데이터가 가는지 테스트합니다.
decode의 경우는, bytes타입으로 되어있기 때문에 hello같은 문자를 주고받기 위해서 문자열 타입으로 변경해줍니다.
그리고 받은 데이터를 확인해보기위해 data를 print를 해봅니다.
플레이스토어에 가서 위의 앱을 다운받아주세요!
블루투스의 serial 통신을 위해 필요합니다.
그리고 왼쪽의 목록에서 Devices를 들어가줍니다.
Bluetooth LE에서 이름을 바꾸지 않았다면, BT05라는 Device를 찾을 수 있습니다.
만약 나타나지 않는다면, 오른쪽 위의 SCAN버튼을 눌러주세요!
그렇게 BT05를 클릭하면 이렇게 연결이 될겁니다.
그럼 위의 코드를 실행시키면...!
nice to meet you!라는 메세지가 들어와집니다!
그러면 저도 hello를 보내보겠습니다.
이렇게 shell을 보면, hello라는 데이터를 받는 것을 확인했습니다!
그러면 이제 블루투스가 정상적으로 동작한다는 테스트를 마쳤으니,
본격적으로 자동차를 움직여보겠습니다!
BluetoothCarMotor.py
import serial #시리얼 사용! import threading #쓰레드기능을 사용하기 위해 사용 import time #time기능을 위해 사용 import RPi.GPIO as GPIO #GPIO핀을 사용하기 위해 사용 BlSerial = serial.Serial("/dev/ttyS0", baudrate=9600, timeout=1.0) #dev/ttyS0을 시리얼통신핀으로 사용한다. 9600의 통신속도를 가지고, 1초이상 데이터가 들어오지않으면 timeout된다. gData = "" #gData의 변수를 생성하고 빈 문자열로 초기화한다. #이전에 실행했던 모터와 스위치를 선언해준다. PWMA = 18 AIN2 = 27 AIN1 = 22 PWMB = 23 BIN2 = 24 BIN1 = 25 SW_F = 5 SW_B = 19 SW_R = 6 SW_L = 13 GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.setup(PWMA, GPIO.OUT) GPIO.setup(AIN1, GPIO.OUT) GPIO.setup(AIN2, GPIO.OUT) GPIO.setup(PWMB, GPIO.OUT) GPIO.setup(BIN1, GPIO.OUT) GPIO.setup(BIN2, GPIO.OUT) GPIO.setup(SW_R,GPIO.IN,pull_up_down=GPIO.PUD_DOWN) GPIO.setup(SW_F,GPIO.IN,pull_up_down=GPIO.PUD_DOWN) GPIO.setup(SW_B,GPIO.IN,pull_up_down=GPIO.PUD_DOWN) GPIO.setup(SW_L,GPIO.IN,pull_up_down=GPIO.PUD_DOWN) L_Motor = GPIO.PWM(PWMA, 500) L_Motor.start(0) R_Motor = GPIO.PWM(PWMB, 500) R_Motor.start(0) #LED들의 이름을 지어 핀들을 연결해주었다. LED_FR = 16 LED_FL = 26 LED_BR = 21 LED_BL = 20 #사용할 LED를 출력설정을 해준다. GPIO.setup(LED_FR, GPIO.OUT) GPIO.setup(LED_FL, GPIO.OUT) GPIO.setup(LED_BR, GPIO.OUT) GPIO.setup(LED_BL, GPIO.OUT) #앞,뒤,옆으로 움직이는 부분, 그리고 LED의 동작을 사용하기 쉽게 함수로 선언해주었다. def moving_Front(speed): GPIO.output(AIN1,0) GPIO.output(AIN2,1) L_Motor.ChangeDutyCycle(speed) GPIO.output(BIN1,0) GPIO.output(BIN2,1) R_Motor.ChangeDutyCycle(speed) def moving_Back(speed): GPIO.output(AIN1,1) GPIO.output(AIN2,0) L_Motor.ChangeDutyCycle(speed) GPIO.output(BIN1,1) GPIO.output(BIN2,0) R_Motor.ChangeDutyCycle(speed) def moving_Left(speed): GPIO.output(AIN1,1) GPIO.output(AIN2,0) L_Motor.ChangeDutyCycle(speed) GPIO.output(BIN1,0) GPIO.output(BIN2,1) R_Motor.ChangeDutyCycle(speed) def moving_Right(speed): GPIO.output(AIN1,0) GPIO.output(AIN2,1) L_Motor.ChangeDutyCycle(speed) GPIO.output(BIN1,1) GPIO.output(BIN2,0) R_Motor.ChangeDutyCycle(speed) def moving_Stop(): GPIO.output(AIN1,0) GPIO.output(AIN2,1) L_Motor.ChangeDutyCycle(0) GPIO.output(BIN1,0) GPIO.output(BIN2,1) R_Motor.ChangeDutyCycle(0) def OUT_LED_GO(): GPIO.output(LED_FR,GPIO.HIGH) GPIO.output(LED_FL,GPIO.HIGH) GPIO.output(LED_BR,GPIO.LOW) GPIO.output(LED_BL,GPIO.LOW) def OUT_LED_BACK(): GPIO.output(LED_FR,GPIO.LOW) GPIO.output(LED_FL,GPIO.LOW) GPIO.output(LED_BR,GPIO.HIGH) GPIO.output(LED_BL,GPIO.HIGH) def OUT_LED_LEFT(): GPIO.output(LED_FR,GPIO.LOW) GPIO.output(LED_FL,GPIO.HIGH) GPIO.output(LED_BR,GPIO.LOW) GPIO.output(LED_BL,GPIO.HIGH) def OUT_LED_RIGHT(): GPIO.output(LED_FR,GPIO.HIGH) GPIO.output(LED_FL,GPIO.LOW) GPIO.output(LED_BR,GPIO.HIGH) GPIO.output(LED_BL,GPIO.LOW) def OUT_LED_STOP(): GPIO.output(LED_FR,GPIO.LOW) GPIO.output(LED_FL,GPIO.LOW) GPIO.output(LED_BR,GPIO.LOW) GPIO.output(LED_BL,GPIO.LOW) def serial_thread(): #쓰레드로 동작하는 함수. 시리얼 통신으로 데이터를 받는다. global gData #serial_tread라는 함수안에서 gData를 사용하기위해 선언해준다. while True: data = BlSerial.readline() #한줄씩 값을 받는다. data = data.decode() #decode로 시리얼통신의 bytes 타입을 문자열 타입으로 변경한다. gData = data #받은 데이터를 gData에 대입해준다. def main(): global gData #gData를 사용하기 위해 선언해준다. try: while True: if gData.find("go") >= 0: #find를 통해서 go라는 값을 찾는다. 찾는다면 조건을 실행한다. gData = "" #gData를 비어둔다. 비어두지 않으면 gData는 계속 go로 항상 참이되게된다. print("ok go") #go가 들어온것을 확인하기 위해서 ok go라는 대사를 출력해준다. moving_Front(50) #앞의 함수를 이용해서 50%의 속도로 진행한다. OUT_LED_GO() #LED도 앞의 함수를 이용해 출력한다. elif gData.find("back") >= 0: #나머지 또한 같다 :) gData = "" print("ok back") moving_Back(50) OUT_LED_BACK() elif gData.find("left") >= 0: gData = "" print("ok left") moving_Left(50) OUT_LED_LEFT() elif gData.find("right") >= 0: gData = "" print("ok right") moving_Right(50) OUT_LED_RIGHT() elif gData.find("stop") >= 0: gData = "" print("ok stop") moving_Stop() OUT_LED_STOP() if GPIO.input(SW_F) == 1 : #비상멈춤 버튼이다. Front스위치를 누르면 멈추게한다. moving_Stop() OUT_LED_STOP() except KeyboardInterrupt: #Ctrl+C 사용 시 종료한다. pass if __name__ == '__main__': #name의 값이 main이면 참이 된다. task1 = threading.Thread(target = serial_thread) #task1을 이름으로 쓰레드를 생성한다. task1.start() #쓰레드를 시작한다. main() #main함수를 실행한다. BlSerial.close() #main함수가 끝나면 반환한다. GPIO.cleanup() |
위의 코드를 준비해준다!
자세한 내용은 주석으로 다 달아놓았습니다.
요약하자면, 스마트폰에서 go, back같은 데이터를 보내면! data를 gData로 받아들여
이를 이용해서 앞뒤옆으로 움직이도록 통신을 하게될 것입니다!
Bluetooth.Serial앱을 처음 사용하시면, 하단의 버튼들이 M1~M7 이런식으로 되어있을 텐데요,
우리는 조종을 위해서 go, back을 계속 칠 필요없이 이 하단의 버튼들을 이용해서 편하게 통신을 할 수 있습니다.
아래의 버튼들을 꾹 눌러서 이름과 보내고싶은 데이터, 즉 Value를 go 같은 식으로 위와같이 설정해줍니다.
그러면 버튼을 누를때마다 go, back과 같은 데이터값을 보내주어 조이스틱같이 조종할 수 있습니다.
그럼 위의 코드를 실행하고 다시 스마트폰으로 돌아와서 버튼들을 눌러서 데이터를 보내보면!
정상적으로 스마트폰으로 잘 움직입니다!
파일을 20MB까지 업로드 할 수 있어서 프레임이 떨어지지만..ㅠ
같이 하는 친구가 있었다면 장애물 경주 같은 것도 할 수 있겠네요.. ㅋㅋㅋ ...ㅠ
아까 코드에서 데이터를 받거나 보낼때의 확인으로 ok 텍스트를 출력시켜놓았는데,
Shell에서도 정상적으로 반응하는 것을 볼 수 있었습니다! 야호!
생각보다 내용이 길었습니다..! 휴...
다음시간에는 라즈베리 카메라를 이용해서 다양한 기능들을 익혀봅시다!
다음에 봐요!
AI 인공지능 자율주행 자동차
#해당 프로젝트는 앤써북의 'AI 인공지능 자율주행 자동차' 를 참고하고 있습니다!
https://book.naver.com/bookdb/book_detail.naver?bid=20861845
'AutoDriving > AutoDriving RC_Car' 카테고리의 다른 글
라즈베리파이 자율주행 자동차 - (7) OpenCV를 이용한 카메라 사용 2 [이미지처리] (0) | 2022.05.18 |
---|---|
라즈베리파이 자율주행 자동차 - (6) OpenCV를 이용한 카메라 사용 1 (0) | 2022.04.30 |
라즈베리파이 자율주행 자동차 - (4) 부저와 모터를 움직여보자! (0) | 2022.03.08 |
라즈베리파이 자율주행 자동차 - (3) LED, 버튼 테스트 (0) | 2022.03.06 |
라즈베리파이 자율주행 자동차 - (2) 필요 소프트웨어 설치! (1) | 2022.03.06 |