오랜만에 ICbanQ의 무상체험단에 당첨되었다.
이번 체험 제품은…
DFRobot사의 Beginner Kit For Arduino v3.0 ^^;
해당 제품은 다음의 링크에서 확인할 수 있습니다.
http://www.icbanq.com/shop/product_detail.asp?prod_code=P005605397
[Beginner Kit For Arduino v3.0 개봉기]
블로그 원본글 : http://www.beanbox.co.kr/wordpress/?p=1057
icbanq 카페글 : http://cafe.naver.com/icbanq/1663
————————————————————————-
IR Remote는 적외선 리모콘이다.
TV 리모콘과 같은 방식이다.
보이는 곳에서만 가능한 단점이 있지만 저전력에 다양한 메세지도 쉽게 담을 수 있어서 많이 이용된다.
이번에는 이것을 이용해서 Servo 모터를 제어해 보도록 하자.
소형 서보이다.
먼저 기본 구동은 아래와 같이 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include <Servo.h> Servo myservo; int pos=0; void setup() { myservo.attach(9); } void loop() { // myservo.write(90); for (pos=0;pos<180;pos+=1) { myservo.write(pos); delay(15); } for (pos=180;pos>=1;pos-=1) { myservo.write(pos); delay(15); } } |
자세한 소스 설명은 생략하도록 하겠다.
원하는 각도를 입력하면 해당 각도로 서보가 움직인다.
위소스는 0~180도 사이를 왔다 갔다 하는 소스이다.
리모콘과 적외선 수신부이다.
미니 브레드보드에 꽂여 있는 발세개 짜리 검은 녀석이 적외선 수신부이다.
보통 리모콘과 쌍으로 사용되어진다.
IRremote.h 가 없다면 아래에서 다운하면 된다.
https://github.com/shirriff/Arduino-IRremote
그리고 아두이노 실행파일 아래에 [libraries] 폴더 안에 넣어두고 아두이노를 실행한다.
IR Remote의 기본 구동은 아래와 같이 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#include <IRremote.h> int RECV_PIN = 11; int ledPin = 13; boolean ledState = LOW; IRrecv irrecv(RECV_PIN); decode_results results; void setup() { Serial.begin(9600); irrecv.enableIRIn(); pinMode(ledPin,OUTPUT); } void loop() { if (irrecv.decode(&results)) { Serial.println(results.value, HEX); if(results.value == 0xFD00FF) { ledState = !ledState; digitalWrite(ledPin,ledState); } irrecv.resume(); } } |
적외선 입력을 받으면 그 값에 따라서 원하는 동작을 한다.
예제에서는 Power 버튼 하나만 있지만 다른 버튼들의 값을 읽어서 이용할 수 있다.
시리얼 모니터를 통해 각 버튼들의 값을 확인해 볼 수 있다.
심볼 | 코드 |
전원 | FD00FF |
Vol+ | FD807F |
Func/stop | FD40BF |
◀◀ | FD20DF |
▶ | FDA05F |
▶▶ | FD609F |
▼ | FD10EF |
Vol- | FD906F |
▲ | FD50AF |
0 | FD30CF |
EQ | FDB04F |
ST/REPT | FD708F |
1 | FD08F7 |
2 | FD8877 |
3 | FD48B7 |
4 | FD28D7 |
5 | FDA857 |
6 | FD6897 |
7 | FD18E7 |
8 | FD9867 |
9 | FD58A7 |
시리얼 모니터를 통해 읽은 값들이다.
해당 값에따라 적절한 동작을 구현할 수 았다.
[IR Remote + Servo]
두개의 하드웨어는 겹치는게 없음으로 그냥 합쳐도 된다.
물론 필요에 의해서 핀번호들은 변경 가능하다. (나는 LED를 13번 핀을 이용했다.)
심볼 | 코드 | 시리얼출력 | 기능 |
전원 | FD00FF | Power | 전원 On/Off |
Vol+ | FD807F | Vol+ | 1증가 |
Func/stop | FD40BF | Func/stop | 자동 정지 |
◀◀ | FD20DF | Prev | 0까지 자동 |
▶ | FDA05F | Start | 자동 시작 |
▶▶ | FD609F | Next | 180까지 자동 |
▼ | FD10EF | Down | 20씩 감소 |
Vol- | FD906F | Vol- | 1감소 |
▲ | FD50AF | Up | 20씩 증가 |
0 | FD30CF | Num 0 | 0도 |
EQ | FDB04F | EQ | 좌우로 왔다 갔다 |
ST/REPT | FD708F | ST/REPT | 자동 방향 반전 |
1 | FD08F7 | Num 1 | 20도 |
2 | FD8877 | Num 2 | 40도 |
3 | FD48B7 | Num 3 | 60도 |
4 | FD28D7 | Num 4 | 80도 |
5 | FDA857 | Num 5 | 100도 |
6 | FD6897 | Num 6 | 120도 |
7 | FD18E7 | Num 7 | 140도 |
8 | FD9867 | Num 8 | 160도 |
9 | FD58A7 | Num 9 | 180도 |
리모콘 버튼에 따라서 서보를 위와 같이 동작시켜 보자.
크게는 자동과 수동 모드가 있다.
전원
Power On/Off 를 한다.
On되는걸 알리기 위해 0~180까지 움직이고 초기값 또는 이전 설정값으로 바로 이동한다.
수동1
Vol+/-로 각도를 1씩 변화시킨다.
수동2
▲/▼버튼은 각도를 20도씩 변화시킨다.
수동3
각각의 숫자버튼은 특정 각도로 바로 이동한다.
자동1
▶/Func/stop 버튼으로 0~180 사이를 증가 또는 감소한다.
ST/REPT 버튼으로 증가 감소를 선택한다.(이동 방향 선택)
증가시에는 180이 되면 0으로 바로 돌아온다.
마찬가지로 감소시에는 0이 되면 180으로 바로 돌아온다.
자동2
EQ 버튼으로 0과 180을 계속 왔다 갔다 한다.
반자동1
▶▶/◀◀ 현재값에서 0 또는 180으로 이동하고 멈춘다.
90도 확인
90도 일때 LED를 On한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
#include <IRremote.h> #include <Servo.h> int RECV_PIN = 11; int ledPin = 13; boolean ledState = LOW; IRrecv irrecv(RECV_PIN); decode_results results; Servo myservo; boolean powerOnOff = LOW; int pos=0; // 서보 각도값 int pos_p=0; // 서보 이전값 int servoAutoState = 0; // 자동이동 여부. 0:자동이동 안함, 1:자동(한방향)(Start/Stop), 2:반자동(Prev/Next), 3:자동(양방향)(EQ) boolean servoDirection = LOW; // 방향 int temp=0; // 임시 void setup() { Serial.begin(9600); irrecv.enableIRIn(); pinMode(ledPin,OUTPUT); myservo.attach(9); // 9번핀 활용 myservo.write(pos); // 초기는 0 } void loop() { if (irrecv.decode(&results)) { //Serial.println(results.value, HEX); if (results.value==0xFD00FF) { powerOnOff = !powerOnOff; if (powerOnOff) { Serial.println("Power On"); myservo.write(0); delay(200); for (int i=0;i<180;i++) { myservo.write(i); delay(10); } delay(200); myservo.write(pos); } else { Serial.println("Power Off"); servoAutoState = 0; // 자동일경우 정지. 어차피 상관없나? 밑에서 Power On 일때만 동작하도록 했으니... 만약 자동일때 Power Off 했다면 Power On 시 자동으로 움직인다.(장비의 안전을 위해서 이런 일은 방지하도록 하자) } } if (powerOnOff) // Power On 일때만 신호를 읽도록 { switch (results.value) { case 0xFD00FF: //Serial.println("Power"); //pos=90; break; case 0xFD807F: Serial.println("Vol+"); servoAutoState = 0; // 수동버튼 입력시 자동으로 수동 전환 pos++; if (pos>180) { pos=180; } break; case 0xFD40BF: Serial.println("Func/stop"); servoAutoState = 0; // 자동이동 정지 break; case 0xFD20DF: Serial.println("Prev"); servoAutoState = 2; // 반자동이동 시작 servoDirection = LOW; // 반자동이동의 방향. 감소 break; case 0xFDA05F: Serial.println("Start"); servoAutoState = 1; // 자동이동 시작 break; case 0xFD609F: Serial.println("Next"); servoAutoState = 2; // 반자동이동 시작 servoDirection = HIGH; // 반자동이동의 방향. 증가 break; case 0xFD10EF: Serial.println("Down"); servoAutoState = 0; temp=pos % 20; // 20의 배수가 되기 위해 필요한 값 if (temp==0) // 만약 현재의 값이 20의 배수이면 { temp=20; } pos = pos - temp; if (pos<0) { pos=0; } break; case 0xFD906F: Serial.println("Vol-"); servoAutoState = 0; pos--; if (pos<0) { pos=0; } break; case 0xFD50AF: Serial.println("Up"); servoAutoState = 0; // 지금 pos에서 20단위로 증가를 해야 한다 // 혹시 19이면 20이 되어야 한다 temp=20 - (pos % 20); // 20의 배수가 되기 위해 필요한 값 if (temp==0) // 만약 현재의 값이 20의 배수이면 { temp=20; } pos = pos + temp; if (pos>180) { pos=180; } break; case 0xFD30CF: Serial.println("Num 0"); servoAutoState = 0; pos=0; break; case 0xFDB04F: Serial.println("EQ"); servoAutoState = 3; // 자동(양방향) break; case 0xFD708F: Serial.println("ST/REPT"); servoDirection = !servoDirection; // 방향 전환 break; case 0xFD08F7: Serial.println("Num 1"); servoAutoState = 0; pos=20; break; case 0xFD8877: Serial.println("Num 2"); servoAutoState = 0; pos=40; break; case 0xFD48B7: Serial.println("Num 3"); servoAutoState = 0; pos=60; break; case 0xFD28D7: Serial.println("Num 4"); servoAutoState = 0; pos=80; break; case 0xFDA857: Serial.println("Num 5"); servoAutoState = 0; pos=100; break; case 0xFD6897: Serial.println("Num 6"); servoAutoState = 0; pos=120; break; case 0xFD18E7: Serial.println("Num 7"); servoAutoState = 0; pos=140; break; case 0xFD9867: Serial.println("Num 8"); servoAutoState = 0; pos=160; break; case 0xFD58A7: Serial.println("Num 9"); servoAutoState = 0; pos=180; break; } } /* if(results.value == 0xFD00FF) { ledState = !ledState; digitalWrite(ledPin,ledState); } */ irrecv.resume(); } if (powerOnOff) // Power On 일떄만 동작 { if (servoAutoState==1) // 자동이동이 활성화 되어 있으면 { if (servoDirection) // 방향이 HIGH이면 증가 { pos++; if (pos>180) // 처음으로 돌아간다 { pos=0; } } else // 방향이 LOW이면 감소 { pos--; if (pos<0) // 마지막으로 돌아간다 { pos=180; } } } else if (servoAutoState==2) // 반자동이 활성화 되어 있으면 { if (servoDirection) // 방향이 HIGH이면 증가 { pos++; if (pos>180) // 180까지만 { pos=180; } } else // 방향이 LOW이면 감소 { pos--; if (pos<0) // 0까지만 { pos=0; } } } else if (servoAutoState==3) // 자동 양방향 { if (servoDirection) // 방향이 HIGH이면 증가 { pos++; if (pos>180) // 방향전환 { pos-=2; // 이미 181인 상태임으로 -2를 해서 179로 servoDirection = !servoDirection; // 방향전환 } } else // 방향이 LOW이면 감소 { pos--; if (pos<0) // 방향전환 { pos+=2; // 이미 -1인 상태임으로 +2를 해서 1로 servoDirection = !servoDirection; // 방향전환 } } } if (pos_p!=pos) // 값이 변경되었을시만 적용. 가만히 있어도 찍찍찍 거리는 것 때문에 넣어봄 { //Serial.println(pos); /* Serial.print("pos : "); Serial.print(pos); Serial.print(", pos_p : "); Serial.println(pos_p); */ myservo.write(pos); if (servoAutoState>0) // 자동/반자동 일때는 delay를 주어 천천히 움직인다 { delay(15); } pos_p=pos; } } if (pos==90) { digitalWrite(ledPin,HIGH); } else { digitalWrite(ledPin,LOW); } } |
리모콘으로 받은 값을 switch문으로 값을 확인하고 그에 맞는 동작을 하도록 한다.
수동,자동,반자동에 따라 동작을 하고
각도값이 이전값과 다를 대만 서보를 동작 시킨다.
아래는 동작하는 모습이다.
첫 개봉기에서는 과녁맞추기 게임이라고 했는데…
생각해보니 IR 이녀석은 아니다…^^
CDS와 레이져를 해야지 사격이 되겠다.
IR은 대충 방향만 맞아도… ^^
본 서보(SG90)를 개조해서 RC를 만들까 하고 있다.
아두이노 프로미니에 블루투스(혹은 IR), 서보 두개, 보조배터리…
헌데 과연 이 서보가 저 무게들을 다 견딜 수 있을까?
고민이다.
느린건 괜찮은데…(어차피 아들이 가지고 놀 녀석임으로… ^^)
안되면 일반 모터와 모터 드라이버 등을 사용하거나 좀 더 힘 좋은 서보를 사용해야 하거나…
최대한 단순하게 가고싶은데… ㅠㅜ
암튼…
샘플코드 만들어 보고 동작 구현 시켜보고 하는 것도 쉽진 않지만…
글 쓰는게 제일로 어려운것 같다. ^^;
※ 본 제품은 아이씨뱅큐 무상체험단 21기 활동의 일환으로 체험 제품을 제공받아 작성되었습니다. http://www.icbanq.com