Qi 무선충전 Wi-Fi RC카 만들기: 아두이노 MKR1000 기반 무선 조종 자동차 키트
부품 및 소모품
| 부품 |
수량 |
| IDT Qi 5W 송신기 프로토타입 키트 |
1 |
| IDT Qi 5W 수신기 프로토타입 키트 |
1 |
| 아두이노 MKR1000 |
1 |
| 2WD 로봇 자동차 섀시 (아두이노용) |
1 |
| L293DNE 모터 드라이버 |
1 |
| CN6009 승압 컨버터 모듈 |
1 |
| 3.7V 리포 배터리 |
1 |
| 1N4007 고전압 다이오드 |
8 |
| LED (일반) |
1 |
| 221옴 저항 |
1 |
| 타이 랩 |
5 |
| 브레드보드 (선택) |
1 |
필요 도구
앱 및 온라인 서비스
프로젝트 소개
이 프로젝트로 무엇을 만들까요?
주차 시 자동으로 무선 충전되는 Wi-Fi 조종 RC카를 단계별로 제작합니다.
작동 원리
두뇌는 아두이노 MKR1000으로, 모바일 기기와 Wi-Fi로 연결됩니다. 3.7V 리포 배터리로 구동되며, 모터 제어용 L293DNE 드라이버는 최소 4.5V가 필요합니다. CN6009 승압 컨버터로 3.7V를 5V로 올려 모터 드라이버에 공급합니다.
배터리 충전은 MKR1000의 내장 리포 충전 기능을 활용합니다. 외부 5V 전원(IDT Qi 5W 수신기)이 연결되면 배터리가 충전됩니다. 차량이 충전 스테이션(IDT Qi 5W 송신기) 위에 주차하면 무선 충전이 시작됩니다.
제어 시스템은 빠른/느린 두 가지 속도 모드를 제공합니다.
하드웨어 제작
- 납땜: 모터 극성과 IDT 수신기 보드(OUT 핀=빨강, GND=검정)에 전선 납땜 (납땜 인두, 전선 6개 필요)
- 회로 구성: 브레드보드나 납땜으로 회로도대로 연결
- ⚠ 주의: 3.7V 리포 배터리는 최소 700mAh 이상 용량 필수! 미만 시 과열/폭발 위험
- CN6009 조정: 드라이버로 출력 전압 5V로 조정 (전압계로 OUT+/OUT- 확인)
- IDT 수신기 장착: 플라스틱 카드 등으로 차량 바닥 베이스 제작, 실리콘으로 수신기 고정. 빨강 선을 아두이노 VIN, 검정 선을 GND에 연결
- 차량 고정: 타이 랩으로 배터리와 브레드보드를 섀시에 고정
소프트웨어 - Wi-Fi 연결
코드 12~13번째 줄에 본인 네트워크 SSID와 비밀번호 입력. WPA/WPA2 기본 설정. WEP/개방형 네트워크는 코드 주석(34~37줄) 참고해 수정.
사용 방법
1단계: 아두이노 MKR1000 연결
두 가지 방법:
1) 모바일 핫스팟 켜고 보드 연결 (라우터 없이 제어 가능, 권장)
2) 모바일과 보드를 같은 Wi-Fi 라우터에 연결 (코드에 라우터 SSID/비번 입력 필요)
2단계: 아두이노 IP 주소 확인
- 핫스팟 사용 시: 모바일 핫스팟 설정에서 보드 IP 확인 (예: 192.168.1.1)
- 라우터 사용 시: 라우터 설정에서 확인
차량 LED 켜지면 네트워크 연결 및 서버 활성화 완료.
3단계: 아두이노 웹서버 접속
브라우저 주소창에 아두이노 IP 입력
4단계: 충전 베이스 연결
IDT Qi 5W 송신기를 5V DC 어댑터로 콘센트 연결
5단계: 즐기기!
충전 테스트 및 주행 테스트 진행. PCB 거버 파일 제공.
코드
Arduino_IDT_Wi-Fi_Car.ino (아두이노)
#include <SPI.h>
#include <WiFi101.h>
const int motor1Control = 2; // 우측 모터
const int motor2Control = 3; // 좌측 모터
const int motor1Input1 = 4;
const int motor1Input2 = 5;
const int motor2Input1 = 8;
const int motor2Input2 = 9;
const int wifiLed = 10;
char ssid[] = "example"; // 네트워크 SSID 입력
char pass[] = "password"; // 네트워크 비밀번호 입력
int keyIndex = 0; // WEP용 키 인덱스 (선택)
int status = WL_IDLE_STATUS;
String readString;
WiFiServer server(80);
String speedMode = "fast";
void setup() {
pinMode(motor1Control, OUTPUT);
pinMode(motor2Control, OUTPUT);
pinMode(motor1Input1, OUTPUT);
pinMode(motor1Input2, OUTPUT);
pinMode(motor2Input1, OUTPUT);
pinMode(motor2Input2, OUTPUT);
pinMode(wifiLed, OUTPUT);
while (status != WL_CONNECTED) {
status = WiFi.begin(ssid, pass); // WPA/WPA2
// WEP: status = WiFi.begin(ssid, keyIndex, pass);
// 개방형: status = WiFi.begin(ssid);
delay(10000);
}
server.begin();
digitalWrite(wifiLed, HIGH);
}
void loop() {
WiFiClient client = server.available();
if (client) {
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (readString.length() < 100) readString += c;
if (c == '\n') {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
client.println("");
client.println("");
// 전진 버튼
client.println("FORWARDS
");
// 좌회전, 정지, 우회전
client.println("LEFT");
client.println("STOP");
client.println("RIGHT
");
// 후진
client.println("BACKWARDS
");
// 속도 모드
client.println("SPEED MODES
");
client.println("FAST");
client.println("SLOW");
client.println("");
break;
}
// 버튼 클릭 처리
if (readString.indexOf("?fast") > 0) { speedMode = "fast"; readString = ""; }
if (readString.indexOf("?slow") > 0) { speedMode = "slow"; readString = ""; }
if (speedMode == "fast") {
if (readString.indexOf("?moveForwards") > 0) { moveForwards(); readString = ""; }
if (readString.indexOf("?moveBackwards") > 0) { moveBackwards(); readString = ""; }
} else {
if (readString.indexOf("?moveForwards") > 0) { moveForwardsSlow(); readString = ""; }
if (readString.indexOf("?moveBackwards") > 0) { moveBackwardsSlow(); readString = ""; }
}
if (readString.indexOf("?turnLeft") > 0) { turnLeft(); readString = ""; }
if (readString.indexOf("?turnRight") > 0) { turnRight(); readString = ""; }
if (readString.indexOf("?stopMoving") > 0) { stopMoving(); readString = ""; }
}
}
delay(1);
client.stop();
}
}
void moveForwards() {
digitalWrite(motor1Control, HIGH); digitalWrite(motor2Control, HIGH);
digitalWrite(motor1Input1, LOW); digitalWrite(motor1Input2, HIGH);
digitalWrite(motor2Input1, LOW); digitalWrite(motor2Input2, HIGH);
}
void moveBackwards() {
digitalWrite(motor1Control, HIGH); digitalWrite(motor2Control, HIGH);
digitalWrite(motor1Input1, HIGH); digitalWrite(motor1Input2, LOW);
digitalWrite(motor2Input1, HIGH); digitalWrite(motor2Input2, LOW);
}
void turnRight() {
analogWrite(motor1Control, 0); analogWrite(motor2Control, 200);
digitalWrite(motor1Input1, HIGH); digitalWrite(motor1Input2, LOW);
digitalWrite(motor2Input1, LOW); digitalWrite(motor2Input2, HIGH);
}
void turnLeft() {
analogWrite(motor1Control, 200); analogWrite(motor2Control, 0);
digitalWrite(motor1Input1, LOW); digitalWrite(motor1Input2, HIGH);
digitalWrite(motor2Input1, HIGH); digitalWrite(motor2Input2, LOW);
}
void stopMoving() {
digitalWrite(motor1Control, LOW); digitalWrite(motor2Control, LOW);
digitalWrite(motor1Input1, LOW); digitalWrite(motor1Input2, LOW);
digitalWrite(motor2Input1, LOW); digitalWrite(motor2Input2, LOW);
}
void moveForwardsSlow() {
analogWrite(motor1Control, 200); analogWrite(motor2Control, 200);
digitalWrite(motor1Input1, LOW); digitalWrite(motor1Input2, HIGH);
digitalWrite(motor2Input1, LOW); digitalWrite(motor2Input2, HIGH);
}
void moveBackwardsSlow() {
analogWrite(motor1Control, 200); analogWrite(motor2Control, 200);
digitalWrite(motor1Input1, HIGH); digitalWrite(motor1Input2, LOW);
digitalWrite(motor2Input1, HIGH); digitalWrite(motor2Input2, LOW);
}