낡은 RC카를 아두이노와 엑스박스 컨트롤러로 조종하는 차량으로 개조하기
필요한 부품 및 소모품
| 부품 |
수량 |
비고 |
| 아두이노 우노 |
1 |
메인 컨트롤러 |
| 아두이노 USB 호스트 쉴드 |
1 |
무선 리시버 연결용 |
| 엑스박스 360 무선 컨트롤러 |
1 |
조작용 |
| 엑스박스 360 무선 리시버 |
1 |
USB 호스트 쉴드에 연결 |
| L293D 모터 드라이버 (또는 SN754410) |
2개 |
각 모터당 1개 (H-브리지) |
| 7812 전압 레귤레이터 |
1 |
로직 전원용 12V 출력 |
| 78S12 고전류 전압 레귤레이터 |
1 |
모터 구동용 12V 출력 (2A 이상) |
| 스위치 |
1 |
전원 온/오프 |
| 방열판 |
1세트 |
레귤레이터 발열 해소용 |
| 전원 플러그 및 배터리 커넥터 |
각 1 |
AA 배터리 8~12개 직렬 연결용 |
프로젝트 개요
낡은 RC카의 기존 제어 회로를 제거하고 아두이노 + USB 호스트 쉴드 + 엑스박스 360 무선 리시버 조합으로 무선 조종이 가능하게 개조합니다. L293D 드라이버 2개로 구동 모터(전진/후진)와 조향 모터(좌/우)를 각각 제어하며, 배터리 전압을 7812/78S12로 강압해 아두이노와 모터에 공급합니다.
단계별 제작 과정
1. RC카 분해
구형 RC카(몬스터 트럭 권장)에서 기존 제어 기판을 모두 제거하고 구동 모터 2개와 조향 모터 1개의 선만 남깁니다.
2. 아두이노 + USB 호스트 쉴드 장착
아두이노 우노 위에 USB 호스트 쉴드를 적층하고 차체 빈 공간에 고정합니다. 기존 기판 고정 홀을 활용하면 편리합니다.
3. 회로 구성 (브레드보드 또는 퍼프보드)
전원부: AA 1.5V 배터리 10~12개 직렬(15~18V) → 78S12(모터용 12V, 대용량) / 7812(로직용 12V) → 각 레귤레이터 출력을 모터 드라이버 VCC2, 아두이노 VIN 등에 분배. 방열판 필수.
모터 드라이버부: L293D 2개 사용. 각 드라이버의 입력 핀을 아두이노 PWM 핀(5, 6번: 구동 / 4, 7번: 조향)에 연결. 인에이블 핀은 PWM으로 속도 제어.
4. 차체에 회로 장착 및 배선
구동 모터 2개는 병렬로 첫 번째 L293D에, 조향 모터는 두 번째 L293D에 연결. 무선 리시버를 USB 호스트 쉴드에 꽂습니다.
소스 코드 (핵심 로직)
Kristian Lauszus의 USB Host Shield 2.0 라이브러리의 Xbox 예제를 기반으로 수정했습니다.
주요 핀 매핑
#define motorPinOne 5 // 구동 모터 PWM 1
#define motorPinTwo 6 // 구동 모터 PWM 2
#define motor2PinOne 4 // 조향 모터 제어 1
#define motor2PinTwo 7 // 조향 모터 제어 2
#define BRAKE 2 // 브레이크 제어 핀
컨트롤러 매핑
- L2 트리거: 후진 (아날로그 값으로 속도 제어)
- R2 트리거: 전진 (아날로그 값으로 속도 제어)
- 왼쪽 아날로그 스틱 X축: 좌/우 조향 (데드존 ±7500, 임계값 ±26000)
- B 버튼: 급브레이크 (후진/전진 방향 반대 방향으로 순간 출력)
- Y 버튼: 모터 정지
- XBOX 버튼: 컨트롤러 LED 회전 모드
핵심 함수
clockwise() / counterClockwise(): 구동 모터 정/역회전 (PWM 속도 제어)
turn_left() / turn_right() / center(): 조향 모터 제어
motors_stop(): 전체 모터 정지
전체 코드
/* Xbox Wireless Receiver 라이브러리 예제 기반 수정 */
#include <XBOXRECV.h>
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
USB Usb;
XBOXRECV Xbox(&Usb);
#define motorPinOne 5
#define motorPinTwo 6
#define motor2PinOne 4
#define motor2PinTwo 7
#define BRAKE 2
int pulse = 0;
int forward = 0;
int brake_on = 0;
void setup() {
TCCR1B = TCCR1B & 0b11111000 | 0x02; // PWM 주파수 조정
Serial.begin(115200);
if (Usb.Init() == -1) {
Serial.print(F("\r\nOSC did not start"));
while(1); // halt
}
Serial.print(F("\r\nXbox Wireless Receiver Library Started"));
pinMode(motorPinOne, OUTPUT);
pinMode(motorPinTwo, OUTPUT);
pinMode(motor2PinOne, OUTPUT);
pinMode(motor2PinTwo, OUTPUT);
pinMode(BRAKE, OUTPUT);
digitalWrite(BRAKE, LOW);
motors_stop();
center();
}
void loop() {
Usb.Task();
if (Xbox.XboxReceiverConnected) {
for (uint8_t i = 0; i < 4; i++) {
// L2: 후진
if (Xbox.getButtonPress(L2, i)) {
pulse = Xbox.getButtonPress(L2, i);
forward = 0;
clockwise();
}
// R2: 전진
if (Xbox.getButtonPress(R2, i)) {
pulse = Xbox.getButtonPress(R2, i);
forward = 1;
counterClockwise();
}
// 아날로그 스틱: 조향
if (abs(Xbox.getAnalogHat(LeftHatX, i)) > 7500 ||
abs(Xbox.getAnalogHat(LeftHatY, i)) > 7500 ||
abs(Xbox.getAnalogHat(RightHatX, i)) > 7500 ||
abs(Xbox.getAnalogHat(RightHatY, i)) > 7500) {
if (Xbox.getAnalogHat(LeftHatX, i) > 7500) {
if (Xbox.getAnalogHat(LeftHatX, i) > 26000) turn_right();
else center();
}
if (Xbox.getAnalogHat(LeftHatX, i) < -7500) {
if (Xbox.getAnalogHat(LeftHatX, i) < -26000) turn_left();
else center();
}
}
// 버튼들
if (Xbox.getButtonClick(B, i)) { // 급브레이크
digitalWrite(BRAKE, HIGH);
brake_on = 1;
pulse = 100;
if (forward) clockwise(); else counterClockwise();
}
if (Xbox.getButtonClick(Y, i)) motors_stop(); // 정지
if (Xbox.getButtonClick(XBOX, i)) {
Xbox.setLedMode(ROTATING, i);
}
// 기타 버튼(UP, DOWN, A, X 등)은 시리얼 출력만
}
}
delay(1);
}
void clockwise() { // 전진
analogWrite(motorPinOne, pulse);
analogWrite(motorPinTwo, 0);
if (brake_on) { delay(600); digitalWrite(BRAKE, LOW); brake_on = 0; pulse = 0; }
}
void counterClockwise() { // 후진
analogWrite(motorPinOne, 0);
analogWrite(motorPinTwo, pulse);
if (brake_on) { delay(600); digitalWrite(BRAKE, LOW); brake_on = 0; pulse = 0; }
}
void turn_left() { digitalWrite(motor2PinOne, HIGH); digitalWrite(motor2PinTwo, LOW); }
void turn_right() { digitalWrite(motor2PinOne, LOW); digitalWrite(motor2PinTwo, HIGH); }
void motors_stop() { analogWrite(motorPinOne, 0); analogWrite(motorPinTwo, 0); pulse = 0; }
void center() { digitalWrite(motor2PinOne, LOW); digitalWrite(motor2PinTwo, LOW); }
라이브러리 및 참고 자료