이 튜토리얼에서는 이전 영상에서 만든 아두이노 로봇카를 무선으로 제어하는 방법을 배웁니다. HC-05 블루투스 모듈, NRF24L01 트랜시버 모듈, HC-12 장거리 무선 모듈 세 가지 무선 제어 방법과 스마트폰 및 커스텀 제작 안드로이드 앱을 이용한 제어법을 보여드리겠습니다. 더 자세한 내용은 아래 비디오를 시청하거나 작성된 튜토리얼을 읽어보세요.
각 모듈의 아두이노 연결 및 사용법 튜토리얼은 이미 따로 있으니 자세한 내용은 글 아래 링크를 참고하세요.
HC-05 블루투스 모듈을 이용한 아두이노 로봇카 제어
블루투스 통신부터 시작합니다. 이를 위해 HC-05 블루투스 모듈 두 개가 필요하며, 이를 마스터와 슬레이브 기기로 설정해야 합니다.
AT 명령어로 쉽게 설정할 수 있습니다. 조이스틱을 마스터로, 아두이노 로봇카를 슬레이브로 설정했습니다. 이 예제의 전체 회로도는 다음과 같습니다.
이 예제에 필요한 구성품은 아래 링크에서 구할 수 있습니다:
HC-05 블루투스 모듈
조이스틱 모듈
18650 배터리
18650 배터리 충전기
L298N 드라이버
12V 고토크 DC 모터
아두이노 보드
소스 코드
이전 튜토리얼에서 조이스틱으로 직접 로봇카를 제어하던 코드를 기반으로 약간 수정하겠습니다.
HC-05 마스터 코드:
/* 아두이노 로봇카 무선 제어 - HC-05 블루투스 사용 == 마스터 기기 - 조이스틱 == by Dejan Nedelkovski, www.HowToMechatronics.com */
int xAxis, yAxis;
void setup() {
Serial.begin(38400); // 블루투스 모듈 기본 통신 속도
}
void loop() {
xAxis = analogRead(A0); // 조이스틱 X축 읽기
yAxis = analogRead(A1); // 조이스틱 Y축 읽기
// 시리얼 포트로 슬레이브 HC-05 블루투스 기기에 값 전송
Serial.write(xAxis/4); // 0-1023을 0-255(1바이트) 범위로 변환
Serial.write(yAxis/4);
delay(20);
}
마스터 기기(조이스틱) 코드는 매우 간단합니다. 조이스틱의 X, Y 값(모터 속도 조절)을 읽어 시리얼 포트로 슬레이브 HC-05 블루투스 기기에 전송합니다. 조이스틱 아날로그 값(0~1023)을 4로 나누어 0~255 범위로 변환합니다.
이 범위(0~255)는 블루투스 기기를 통해 1바이트로 전송하기 쉽고, 반대편(아두이노 로봇카)에서 받기도 쉽습니다.
시리얼에서 2바이트(X, Y 값)를 수신하면 Serial.read() 함수로 둘 다 읽습니다.
// 아두이노 로봇카 코드에서
// 조이스틱(마스터 블루투스 기기)에서 수신 데이터 읽기
while (Serial.available() >= 2) {
x = Serial.read();
delay(10);
y = Serial.read();
}
이제 모터 제어 코드에 적합한 0~1023 범위로 다시 변환합니다. 이 코드는 이전 영상에서 이미 설명했습니다.
// 아두이노 로봇카 코드에서
// 0-255 범위를 0-1023으로 다시 변환
xAxis = x*4;
yAxis = y*4;
코드 업로드 시 아두이노 보드의 RX, TX 핀을 분리해야 합니다.
완전한 HC-05 슬레이브 코드:
/* 아두이노 로봇카 무선 제어 - HC-05 블루투스 사용 == 슬레이브 기기 - 아두이노 로봇카 == by Dejan Nedelkovski, www.HowToMechatronics.com */
#define enA 9
#define in1 4
#define in2 5
#define enB 10
#define in3 6
#define in4 7
int xAxis, yAxis;
unsigned int x = 0;
unsigned int y = 0;
int motorSpeedA = 0;
int motorSpeedB = 0;
void setup() {
pinMode(enA, OUTPUT);
pinMode(enB, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);
Serial.begin(38400); // 블루투스 모듈 기본 통신 속도
}
void loop() {
// 조이스틱이 중앙에 있을 때 기본값 - 움직임 없음
x = 510 / 4;
y = 510 / 4;
// 조이스틱(마스터 블루투스 기기)에서 수신 데이터 읽기
while (Serial.available() >= 2) {
x = Serial.read();
delay(10);
y = Serial.read();
}
delay(10);
// 0-255 범위를 0-1023으로 다시 변환
xAxis = x*4;
yAxis = y*4;
// Y축으로 전진/후진 제어
if (yAxis < 470) {
// 모터 A 후진
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
// 모터 B 후진
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
// 후진용 Y축 감소값(470~0)을 PWM 신호용 0~255 값으로 변환
motorSpeedA = map(yAxis, 470, 0, 0, 255);
motorSpeedB = map(yAxis, 470, 0, 0, 255);
}
else if (yAxis > 550) {
// 모터 A 전진
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
// 모터 B 전진
digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);
// 전진용 Y축 증가값(550~1023)을 PWM 신호용 0~255 값으로 변환
motorSpeedA = map(yAxis, 550, 1023, 0, 255);
motorSpeedB = map(yAxis, 550, 1023, 0, 255);
}
// 조이스틱이 중앙에 있으면 모터 정지
else {
motorSpeedA = 0;
motorSpeedB = 0;
}
// X축으로 좌/우 제어
if (xAxis < 470) {
// X축 감소값(470~0)을 증가하는 0~255 값으로 변환
int xMapped = map(xAxis, 470, 0, 0, 255);
// 좌회전 - 좌측 모터 속도 감소, 우측 모터 속도 증가
motorSpeedA = motorSpeedA - xMapped;
motorSpeedB = motorSpeedB + xMapped;
// 0~255 범위로 제한
if (motorSpeedA < 0) { motorSpeedA = 0; }
if (motorSpeedB > 255) { motorSpeedB = 255; }
}
if (xAxis > 550) {
// X축 증가값(550~1023)을 0~255 값으로 변환
int xMapped = map(xAxis, 550, 1023, 0, 255);
// 우회전 - 우측 모터 속도 감소, 좌측 모터 속도 증가
motorSpeedA = motorSpeedA + xMapped;
motorSpeedB = motorSpeedB - xMapped;
// 0~255 범위로 제한
if (motorSpeedA > 255) { motorSpeedA = 255; }
if (motorSpeedB < 0) { motorSpeedB = 0; }
}
// 저속에서 버징 방지 (모터에 맞게 조정. 내 모터는 PWM 값이 70 미만이면 움직이지 않음)
if (motorSpeedA < 70) { motorSpeedA = 0; }
if (motorSpeedB < 70) { motorSpeedB = 0; }
analogWrite(enA, motorSpeedA); // 모터 A에 PWM 신호 전송
analogWrite(enB, motorSpeedB); // 모터 B에 PWM 신호 전송
}
스마트폰과 커스텀 안드로이드 앱으로 아두이노 로봇카 제어하기
이제 커스텀 제작 안드로이드 앱으로 아두이노 로봇카를 제어하는 방법을 보겠습니다. 로봇카 회로도는 이전 예제와 정확히 동일하며 HC-05 블루투스 모듈이 슬레이브 모드로 설정됩니다.
MIT 앱 인벤터 온라인 애플리케이션으로 우리만의 안드로이드 앱을 만들며, 앱은 다음과 같습니다.
기본적으로 앱이 조이스틱을 시뮬레이션하며, 모양은 두 개의 이미지(이미지 스프라이트)로 구성됩니다.
앱 블록을 보면 조이스틱 스프라이트를 드래그할 때 조이스틱 공 이미지가 손가락 현재 위치로 이동하고, 동시에 X, Y 값을 블루투스로 아두이노 카에 전송합니다.
이 값들은 이전 예제와 같은 방식으로 Serial.read 함수로 아두이노에서 수신합니다.
// 스마트폰 안드로이드 앱에서 수신 데이터 읽기
while (Serial.available() >= 2) {
x = Serial.read();
delay(10);
y = Serial.read();
}
여기에 추가로 스마트폰에서 수신한 X, Y 값을 모터 제어 코드에 적합한 0~1023 범위로 변환해야 합니다. 이 값들은 캔버스 크기에 따라 달라지며, 내 앱에서 얻는 X, Y 값은 60~220 범위였으므로 map() 함수로 쉽게 변환했습니다.
// 올바른 값 수신 확인
if (x > 60 & x < 220) {
xAxis = map(x, 220, 60, 1023, 0); // 스마트폰 X, Y 값을 0-1023 범위로 변환
}
if (y > 60 & y < 220) {
yAxis = map(y, 220, 60, 0, 1023);
}
앱 블록에서 이미지 스프라이트 터치가 끝나면 조이스틱 공이 캔버스 중앙으로 돌아가고 차를 멈추게 하는 적절한 값이 전송됩니다. 웹사이트 기사에서 이 앱과 조이스틱용 두 이미지를 다운로드해 직접 만들거나 수정할 수 있습니다.
아래에서 안드로이드 앱과 조이스틱용 두 이미지를 다운로드할 수 있습니다:
Arduino_Robot_Car_Joystick_App.apk
1 file(s) 1.62 MB Download
Arduino_Robot_Car_Joystick_App_aia_file
1 file(s) 171.20 KB Download
Joystick App Images
1 file(s) 44.36 KB Download
완전한 아두이노 코드:
/* 아두이노 로봇카 무선 제어 - HC-05 블루투스 및 커스텀 안드로이드 앱 사용 == 슬레이브 기기 - 아두이노 로봇카 == by Dejan Nedelkovski, www.HowToMechatronics.com */
#define enA 9
#define in1 4
#define in2 5
#define enB 10
#define in3 6
#define in4 7
int xAxis, yAxis;
int x = 0;
int y = 0;
int motorSpeedA = 0;
int motorSpeedB = 0;
void setup() {
pinMode(enA, OUTPUT);
pinMode(enB, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);
Serial.begin(38400); // 블루투스 모듈 기본 통신 속도
}
void loop() {
// 조이스틱이 중앙에 있을 때 기본값 - 움직임 없음
xAxis = 510;
yAxis = 510;
// 스마트폰 안드로이드 앱에서 수신 데이터 읽기
while (Serial.available() >= 2) {
x = Serial.read();
delay(10);
y = Serial.read();
}
delay(10);
// 올바른 값 수신 확인
if (x > 60 & x < 220) {
xAxis = map(x, 220, 60, 1023, 0);
}
if (y > 60 & y < 220) {
yAxis = map(y, 220, 60, 0, 1023);
}
// Y축으로 전진/후진 제어
if (yAxis < 470) {
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
motorSpeedA = map(yAxis, 470, 0, 0, 255);
motorSpeedB = map(yAxis, 470, 0, 0, 255);
}
else if (yAxis > 550) {
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);
motorSpeedA = map(yAxis, 550, 1023, 0, 255);
motorSpeedB = map(yAxis, 550, 1023, 0, 255);
}
else {
motorSpeedA = 0;
motorSpeedB = 0;
}
// X축으로 좌/우 제어
if (xAxis < 470) {
int xMapped = map(xAxis, 470, 0, 0, 255);
motorSpeedA = motorSpeedA - xMapped;
motorSpeedB = motorSpeedB + xMapped;
if (motorSpeedA < 0) { motorSpeedA = 0; }
if (motorSpeedB > 255) { motorSpeedB = 255; }
}
if (xAxis > 550) {
int xMapped = map(xAxis, 550, 1023, 0, 255);
motorSpeedA = motorSpeedA + xMapped;
motorSpeedB = motorSpeedB - xMapped;
if (motorSpeedA > 255) { motorSpeedA = 255; }
if (motorSpeedB < 0) { motorSpeedB = 0; }
}
// 저속에서 버징 방지
if (motorSpeedA < 70) { motorSpeedA = 0; }
if (motorSpeedB < 70) { motorSpeedB = 0; }
analogWrite(enA, motorSpeedA);
analogWrite(enB, motorSpeedB);
}
NRF24L01 트랜시버 모듈을 이용한 아두이노 로봇카 무선 제어
이제 NRF24L01 트랜시버 모듈을 사용한 아두이노 로봇카 무선 제어 방법으로 넘어갑니다.
회로도입니다. 이 모듈들은 SPI 통신을 사용하므로 이전 예제와 달리 L298N 드라이버의 Enable A, Enable B 핀을 아두이노 2, 3번 핀으로 옮겼습니다. NRF24L01 모듈은 다음 아마존 링크에서 구할 수 있습니다.
소스 코드
이 예제에는 RF24 라이브러리 설치가 필요합니다. 이전 예제와 비슷하게 핀을 정의하고 모듈을 송신기로 설정한 후 조이스틱의 X, Y 값을 읽어 아두이노 로봇카의 다른 NRF24L01 모듈로 전송합니다.
아날로그 읽기 값은 문자열(String)이며, string.toCharArray() 함수로 문자 배열에 넣습니다. 그런 다음 radio.write() 함수로 그 문자 배열 데이터를 다른 모듈로 전송합니다.
수신 측(아두이노 로봇카)에서는 모듈을 수신기로 정의한 후 radio.read() 함수로 데이터를 수신합니다. atoi() 함수로 수신된 데이터(조이스틱의 X, Y 값)를 정수 값으로 변환해 모터 제어 코드에 사용합니다.
// 아두이노 로봇카 코드 - NRF24L01 예제
if (radio.available()) {
radio.read(&receivedData, sizeof(receivedData)); // 데이터 읽어 문자 배열에 저장
xAxis = atoi(&receivedData[0]); // 수신된 X 값을 문자 배열에서 정수로 변환
delay(10);
radio.read(&receivedData, sizeof(receivedData));
yAxis = atoi(&receivedData[0]);
delay(10);
}