드디어 완성된 모습.
모터고정이 불안정해서 다소 탁탁거리긴 하지만 뭐 작동엔 이상이 없다.
준비물
- 아두이노 UNO
- 모터쉴드
- HC-06 블루투스 모듈
—-아래는 옵션—-
- 16*2 LCD
- LCD 인터페이스 변환 어댑터, I2C로 전환 (원래 LCD는 포트낭비가 많은데 이걸 이용하면 4포트 밖에 안쓴다.)
간단히 모터쉴드와 블루투스 모듈만 있으면 되겠다. 모터쉴드는 꼭 저 모델아니더라도 모터 2개를 운용할 수 있으면 된다.
그리고 블루투스를 연결할 스마트폰 앱이 필요한데
안드로이드에는 BlueStick Control 이라는 잘 만들어진 앱이 있어서 이걸 사용했다.
다음은 소스.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x20 for a 16 chars and 2 line display
SoftwareSerial btSerial(11,12); // RX, TX of bluetooth
const int moter1_ctrl = 2;
const int moter1 = 3;
const int moter2_ctrl = 4;
const int moter2 = 5;
const int kCodeUp = 56;
const int kCodeDown = 50;
const int kCodeLeft = 52;
const int kCodeRight = 54;
const int kCodeGrab = 67;
const int kCodeRelease = 68;
const int kRotateL = 69;
const int kRotateR = 70;
const int kCodeBtnUp = 48;
int op_m1_run = LOW;
int op_m2_run = LOW;
int op_m1_direct = HIGH;
int op_m2_direct = HIGH;
int last_cmd = 0;
void setup()
{
Serial.begin(9600);
btSerial.begin(9600);
lcd.init();
lcd.backlight();
lcd.print("Remote Car");
pinMode(moter1, OUTPUT);
pinMode(moter1_ctrl, OUTPUT);
pinMode(moter2, OUTPUT);
pinMode(moter2_ctrl, OUTPUT);
digitalWrite(moter1_ctrl, HIGH);
digitalWrite(moter2_ctrl, HIGH);
}
String formatMotorStatus(String name, int run, int direct) {
String str;
str = name + ":";
str += run == HIGH ? " ON " : " OFF";
str += direct == HIGH ? " FWD" : " BWD";
return str;
}
void runCommand(int cmd) {
switch (cmd) {
case kCodeUp:
op_m1_run = HIGH;
op_m1_direct = HIGH;
break;
case kCodeDown:
op_m1_run = HIGH;
op_m1_direct = LOW;
break;
case kCodeLeft:
op_m2_run = HIGH;
op_m2_direct = HIGH;
break;
case kCodeRight:
op_m2_run = HIGH;
op_m2_direct = LOW;
break;
case kCodeGrab:
break;
case kCodeRelease:
break;
case kRotateL:
break;
case kRotateR:
break;
case kCodeBtnUp:
op_m1_run = LOW;
op_m2_run = LOW;
break;
}
digitalWrite(moter1, op_m1_run);
digitalWrite(moter2, op_m2_run);
digitalWrite(moter1_ctrl, op_m1_direct);
digitalWrite(moter2_ctrl, op_m2_direct);
}
void display() {
lcd.clear();
lcd.print(formatMotorStatus("M1", op_m1_run, op_m1_direct));
lcd.setCursor(0, 1);
lcd.print(formatMotorStatus("M2", op_m2_run, op_m2_direct));
}
void commandLoop(const String& line) {
int start = 0;
int end = 2;
while (end <= line.length()) {
// Split into each command
char buf[4] = {0,};
line.substring(start, end).toCharArray(buf, 4);
int cmd = atoi(buf);
// Avoid command duplicated
if (cmd != last_cmd) {
Serial.print(cmd);
runCommand(cmd);
display();
}
last_cmd = cmd;
start += 2;
end += 2;
}
}
void loop() {
String line;
if (!btSerial.available()) {
return;
}
line += btSerial.read();
commandLoop(line);
delay(50);
}
아래는 LCD 사용로직을 제거한 코드
#include <SoftwareSerial.h>
SoftwareSerial btSerial(11,12); // RX, TX of bluetooth
const int moter1_ctrl = 2;
const int moter1 = 3;
const int moter2_ctrl = 4;
const int moter2 = 5;
const int kCodeUp = 56;
const int kCodeDown = 50;
const int kCodeLeft = 52;
const int kCodeRight = 54;
const int kCodeGrab = 67;
const int kCodeRelease = 68;
const int kRotateL = 69;
const int kRotateR = 70;
const int kCodeBtnUp = 48;
int op_m1_run = LOW;
int op_m2_run = LOW;
int op_m1_direct = HIGH;
int op_m2_direct = HIGH;
int last_cmd = 0;
void setup()
{
Serial.begin(9600);
btSerial.begin(9600);
pinMode(moter1, OUTPUT);
pinMode(moter1_ctrl, OUTPUT);
pinMode(moter2, OUTPUT);
pinMode(moter2_ctrl, OUTPUT);
digitalWrite(moter1_ctrl, HIGH);
digitalWrite(moter2_ctrl, HIGH);
}
void runCommand(int cmd) {
switch (cmd) {
case kCodeUp:
op_m1_run = HIGH;
op_m1_direct = HIGH;
break;
case kCodeDown:
op_m1_run = HIGH;
op_m1_direct = LOW;
break;
case kCodeLeft:
op_m2_run = HIGH;
op_m2_direct = HIGH;
break;
case kCodeRight:
op_m2_run = HIGH;
op_m2_direct = LOW;
break;
case kCodeGrab:
break;
case kCodeRelease:
break;
case kRotateL:
break;
case kRotateR:
break;
case kCodeBtnUp:
op_m1_run = LOW;
op_m2_run = LOW;
break;
}
digitalWrite(moter1, op_m1_run);
digitalWrite(moter2, op_m2_run);
digitalWrite(moter1_ctrl, op_m1_direct);
digitalWrite(moter2_ctrl, op_m2_direct);
}
void commandLoop(const String& line) {
int start = 0;
int end = 2;
while (end <= line.length()) {
// Split into each command
char buf[4] = {0,};
line.substring(start, end).toCharArray(buf, 4);
int cmd = atoi(buf);
// Avoid command duplicated
if (cmd != last_cmd) {
Serial.print(cmd);
runCommand(cmd);
}
last_cmd = cmd;
start += 2;
end += 2;
}
}
void loop() {
String line;
if (!btSerial.available()) {
return;
}
line += btSerial.read();
commandLoop(line);
delay(50);
}
자 일단 처음 목표했던건 만들었고
다음은… 여기다 캠을 달아볼까?? ㅋㅋ
// 수정: 2015.05.30
두번째의 LCD가 제거된 코드에 블루투스 초기화 로직이 빠져있었다..ㄷㄷㄷ
첫번째 코드에는 있는 내용인데 LCD관련 코드 제거하면서 빠졌나보다.
그덕에 괜한 사람들이 삽질을…;