아두이노 4WD RC카 제작: 조이스틱 무선 제어 완벽 가이드
부품 및 소모품
| 부품 |
수량 |
| 아두이노 우노 |
2 |
| nRF24L01+ 트랜시버 (RP-SMA 안테나) |
2 |
| Funduino 조이스틱 쉴드 V1.A |
1 |
| L298N 듀얼 H-브리지 모터 드라이버 |
2 |
| 4WD 스마트 로봇 카 섀시 키트 |
1 |
| LED (일반) |
3 |
| 221Ω 저항 |
2 |
| 브레드보드 |
2 |
| 18650 배터리 |
2 |
| 파워뱅크 |
1 |
| 점퍼 와이어 |
1세트 |
필요 도구
소프트웨어
프로젝트 소개
개요
아날로그 조이스틱으로 아두이노 4WD 스마트카를 제어하는 프로젝트입니다. nRF24L01을 송수신기로 사용하며, 개방 공간에서 최대 1km 통신 거리를 가집니다. 제작이 매우 간단하고 쉽습니다.
1. 조이스틱 컨트롤러 (송신부)
조이스틱 쉴드를 아두이노 위에 장착하면 간단한 컨트롤러가 됩니다. 7개의 순간 버튼(큰 버튼 4개, 작은 버튼 2개, 조이스틱 셀렉트 버튼)과 2축 썸 조이스틱으로 기존 닌텐도 컨트롤러 수준의 기능을 제공합니다. 노키아 5110 LCD, nRF24L01, 블루투스, I2C 인터페이스도 갖추고 있습니다.
사용 모듈: BTE16-49 nRF24L01+RFX2401C +PA+LNA 안테나 실드형 (2.4GHz, 20dBm, 1000m)
조이스틱 쉴드 핀 구성
- 큰 버튼 4개 + 작은 버튼 2개 + 조이스틱 셀렉트 버튼
- 2축 썸 조이스틱 (X축 0~1023, Y축 0~1023)
- 버튼 매핑: 위(부저/경적), 오른쪽(전조등), 왼쪽(후미등), 나머지 미사용
2. 아두이노 4WD RC카 (수신부)
배선도대로 연결하세요. 중요: 코드 업로드 전 아두이노 우노의 0, 1번 핀(RX/TX)에서 점퍼 와이어를 제거해야 합니다.
전원 연결 후 조이스틱으로 전진/후진, 좌/우 회전 제어가 가능합니다.
소스 코드
자동차 측 수신 코드 (Car_nRF24.ino)
/* nRF24L01 연결:
1-GND, 2-VCC 3.3V(절대 5V 안됨), 3-CE→D6, 4-CSN→D8
5-SCK→D13, 6-MOSI→D11, 7-MISO→D12, 8-미사용 */
#include
#include
#include
#define CE_PIN 6
#define CSN_PIN 8
const uint64_t pipe = 0xE8E8F0F0E1LL;
#define LIGHT_FRONT A4 // 전조등
#define LIGHT_BACK A5 // 후미등
#define HORN_BUZZ 7 // 경적
// 모터 드라이버 1 (우측 바퀴)
#define ENA_M1 3
#define ENB_M1 5
#define IN_11 0
#define IN_12 1
#define IN_13 2
#define IN_14 4
// 모터 드라이버 2 (좌측 바퀴)
#define ENA_M2 9
#define ENB_M2 10
#define IN_21 14
#define IN_22 15
#define IN_23 16
#define IN_24 17
RF24 radio(CE_PIN, CSN_PIN);
int joystick[6];
int speedRight = 0, speedLeft = 0;
int xAxis, yAxis;
void setup() {
// 핀 모드 설정
pinMode(LIGHT_FRONT, OUTPUT);
pinMode(LIGHT_BACK, OUTPUT);
pinMode(HORN_BUZZ, OUTPUT);
pinMode(ENA_M1, OUTPUT); pinMode(ENB_M1, OUTPUT);
pinMode(ENA_M2, OUTPUT); pinMode(ENB_M2, OUTPUT);
pinMode(IN_11, OUTPUT); pinMode(IN_12, OUTPUT);
pinMode(IN_13, OUTPUT); pinMode(IN_14, OUTPUT);
pinMode(IN_21, OUTPUT); pinMode(IN_22, OUTPUT);
pinMode(IN_23, OUTPUT); pinMode(IN_24, OUTPUT);
radio.begin();
radio.openReadingPipe(1, pipe);
radio.startListening();
}
void loop() {
if (radio.available()) {
radio.read(joystick, sizeof(joystick));
xAxis = joystick[0];
yAxis = joystick[1];
int buttonUp = joystick[2];
int buttonRight = joystick[3];
int buttonDown = joystick[4];
int buttonLeft = joystick[5];
// 버튼 제어 (액티브 로우)
digitalWrite(HORN_BUZZ, buttonUp == HIGH ? LOW : HIGH);
digitalWrite(LIGHT_FRONT, buttonRight == HIGH ? LOW : HIGH);
digitalWrite(LIGHT_BACK, buttonLeft == HIGH ? LOW : HIGH);
// Y축: 전진/후진
if (yAxis < 470) { // 후진
// 우측 모터 후진
digitalWrite(IN_11, LOW); digitalWrite(IN_12, HIGH);
digitalWrite(IN_13, HIGH); digitalWrite(IN_14, LOW);
// 좌측 모터 후진
digitalWrite(IN_21, HIGH); digitalWrite(IN_22, LOW);
digitalWrite(IN_23, LOW); digitalWrite(IN_24, HIGH);
speedRight = map(yAxis, 470, 0, 0, 255);
speedLeft = map(yAxis, 470, 0, 0, 255);
} else if (yAxis > 550) { // 전진
// 우측 모터 전진
digitalWrite(IN_11, HIGH); digitalWrite(IN_12, LOW);
digitalWrite(IN_13, LOW); digitalWrite(IN_14, HIGH);
// 좌측 모터 전진
digitalWrite(IN_21, LOW); digitalWrite(IN_22, HIGH);
digitalWrite(IN_23, HIGH); digitalWrite(IN_24, LOW);
speedRight = map(yAxis, 550, 1023, 0, 255);
speedLeft = map(yAxis, 550, 1023, 0, 255);
} else { // 정지
speedRight = 0; speedLeft = 0;
}
// X축: 좌/우 회전
if (xAxis < 470) { // 좌회전
int xMapped = map(xAxis, 470, 0, 0, 255);
speedLeft -= xMapped;
speedRight += xMapped;
speedLeft = max(speedLeft, 0);
speedRight = min(speedRight, 255);
}
if (xAxis > 550) { // 우회전
int xMapped = map(xAxis, 550, 1023, 0, 255);
speedLeft += xMapped;
speedRight -= xMapped;
speedLeft = min(speedLeft, 255);
speedRight = max(speedRight, 0);
}
// 저속 버징 방지 (모터에 따라 조정, 여기선 70 미만 차단)
if (speedLeft < 70) speedLeft = 0;
if (speedRight < 70) speedRight = 0;
analogWrite(ENA_M1, speedRight);
analogWrite(ENB_M1, speedRight);
analogWrite(ENA_M2, speedLeft);
analogWrite(ENB_M2, speedLeft);
}
}
조이스틱 컨트롤러 송신 코드 (Joystick_nRF24.ino)
/* nRF24L01 연결:
1-GND, 2-VCC 3.3V, 3-CE→D9, 4-CSN→D10
5-SCK→D13, 6-MOSI→D11, 7-MISO→D12 */
#include
#include
#include
#define CE_PIN 9
#define CSN_PIN 10
#define X_AXIS A0
#define Y_AXIS A1
const uint64_t pipe = 0xE8E8F0F0E1LL;
RF24 radio(CE_PIN, CSN_PIN);
int joystick[6];
int buttonUp = 2, buttonRight = 3, buttonDown = 4, buttonLeft = 5;
void setup() {
Serial.begin(9600);
radio.begin();
radio.openWritingPipe(pipe);
radio.stopListening();
pinMode(buttonUp, INPUT_PULLUP);
pinMode(buttonRight, INPUT_PULLUP);
pinMode(buttonDown, INPUT_PULLUP);
pinMode(buttonLeft, INPUT_PULLUP);
}
void loop() {
joystick[0] = analogRead(X_AXIS);
joystick[1] = analogRead(Y_AXIS);
joystick[2] = digitalRead(buttonUp);
joystick[3] = digitalRead(buttonRight);
joystick[4] = digitalRead(buttonDown);
joystick[5] = digitalRead(buttonLeft);
radio.write(joystick, sizeof(joystick));
delay(20);
// 시리얼 모니터 디버깅용
Serial.print("X="); Serial.print(joystick[0]);
Serial.print(" Y="); Serial.print(joystick[1]);
Serial.print(" Up="); Serial.print(joystick[2]);
Serial.print(" R="); Serial.print(joystick[3]);
Serial.print(" D="); Serial.print(joystick[4]);
Serial.print(" L="); Serial.println(joystick[5]);
}
회로도
프리칭(Fritzing) 회로도 파일(rc_car_tp3A7JlpYw.fzz)과 배선도 이미지가 제공됩니다.