적외선(Infrared ray, IR ray)은 이름에서도 알 수 있듯이 적색 가시광 바깥에 있는 빛이다. 다시 말해 가시광보다 파장이 긴 전자기파이다(가시광 영역에서 파장이 길 수록 붉은색 빛을 띠므로). 적외선은 우리 생활에서 쉽게 찾을 수 있다. TV나 에어컨 등 가전을 조작하기 위한 리모컨은 대부분 적외선을 이용하고, 온도를 측정하는 체온계나, 어두운 환경에서도 볼 수 있는 감시 장비로도 사용된다.
이번 시간에는 적외선 센서를 통해, 실제 리모컨에서 어떤 적외선 신호가 나오며, 해당 적외선 신호를 방출했을 때, 리모컨과 같은 기능을 할 수 있는지 알아볼 것이다.
NodeMCU와 시중에서 쉽게 구할 수 있는 IR Receiver와 Transmitter를 이용했다.
회로도와 코드를 살펴보기 전에, MCU로 NodeMCU를 이용할 것이기 때문에, Command + Shift + I를 눌러 Library를 추가해야 한다. Library Manager에서 IRremoteESP8266를 입력하고 David Conran, Sebastine Warin, Mark Szabo, Ken Shirriff에 의해 만들어진 라이브러리를 추가하면 사전 준비는 끝이 난다.
먼저 적외선 수신을 살펴보자. 너무 간단해서 설명은 필요 없고, 센서의 Data 핀이 D1에 위치시켰다. (아래 이미지 참고)
NodeMCU의 핀 맵에 대해서는 이전 포스팅(taeminator1.tistory.com/15)에서 잠깐 설명을 했는데, GPIO 핀이 다수 있어, 확장성이 괜찮은 편이다. 하지만 주의할 점은, GPIO 핀 중에서 몇몇 핀은 다른 용도로 이미 할당되어 있어 사용하기가 쉽지 않다. Google에 "NodeMCU available GPIO pins"를 검색하거나, 각각의 GPIO 핀을 연결해 Serial Monitor를 확인해 봐도 된다. (처음에 GPIO 핀을 연결해도 아무 반응이 없어, 후자로 모든 핀을 테스트했다. 쉬운 전자의 길을 놔두고..)
그리고, 아두이노에서 방금 다운로드한 Library의 Examples에서 IRrecvDumpV2를 열어 핀 맵만 바꿔주면 된다. 참고로 예제에서는 D5핀에 적외선 센서의 데이터 핀을 연결해 주었다.
Upload 후, Serial Monitor를 킨 상태에서, 집에 굴러다니는 아무 리모컨을 붙잡고 적외선 수신부를 향해 버튼을 눌러주면 된다. 그럼 아래 이미지와 같이 텍스트가 출력된다.
두 개의 리모컨에 대해서 해봤다. 첫 번째는 선풍기 리모컨이고, 두 번째는 에어컨 리모컨이다.
Serial Monitor를 보면,
선풍기 리모컨의 경우, NEC라는 프로토콜을 사용하고, 그 아래로 적외선 신호를 출력해 준다.
에어컨 리모컨의 경우, 친절하게 SAMSUNG_AC라고 프로토콜도 명시해 주고, 적외선 신호를 출력해 준다.
이제 IR Transmitter로 실제 해당 적외선 신호로 단말기를 제어할 수 있는지 확인해보자. 회로 구성은 다음과 같다. Transmitter의 Data 핀은 D2에 연결한 것만 주의하면 된다.
다음은 아두이노이다. 수신과 달리 약간 수정이 필요하다. 우선 Example의 IRsendDemo를 살펴보자.
IRsendDemo.ino
...
// Example Samsung A/C state captured from IRrecvDumpV2.ino
uint8_t samsungState[kSamsungAcStateLength] = {
0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0};
...
void loop() {
Serial.println("NEC");
irsend.sendNEC(0x00FFE01FUL);
delay(2000);
Serial.println("Sony");
irsend.sendSony(0xa90, 12, 2); // 12 bits & 2 repeats
delay(2000);
Serial.println("a rawData capture from IRrecvDumpV2");
irsend.sendRaw(rawData, 67, 38); // Send a raw data capture at 38kHz.
delay(2000);
Serial.println("a Samsung A/C state from IRrecvDumpV2");
irsend.sendSamsungAC(samsungState);
delay(2000);
}
loop() 함수를 보면, protocol의 종류에 따라 사용 가능한 함수가 정해져 있는 모양이다.
나의 리모컨의 프로토콜은 NEC와 SAMSUNG_AC이므로 각각 irsend.snedNEC와 irsend.sendSamsungAC함수가 필요하다.
NEC의 경우 sendNEC함수의 파라미터로 방금 전 Serial Monitor로 수신한 data를 입력해주면 된다.
SAMSUNG_AC의 경우, On/Off시에는 21byte의 데이터가 전송되고, On 이후에 리모컨 조작 시 14byte의 데이터가 전송된다.
아래 그림을 참고하면, 이해가 될 것이다. 첫 번째 데이터가 리모컨의 On을 누른 것이고, 두 번째 데이터가 리모컨의 온도 +를 누른 것이다. 그리고 마지막 데이터가 리모컨의 Off를 누른 것이다.
각각 state의 개수가 21, 14, 21개로 상이한 것을 알 수 있다. 그런데 IRSendDemo.ino에서 상수 kSamsungAcStateLength의 값은 14여서 에어컨을 끌 수가 없었다. 다시 말해, 아래 그림의 14byte 데이터는 Power On을 포함하고 있어, 켜는 것은 가능했지만, 21byte의 데이터를 전송할 수가 없어서, 에어컨을 끌 수가 없었다. 한참을 헤매다가 irsend.sendRaw함수를 사용하면 될까 싶어서, 해보니까 다행히 잘 되었다.
그래서 에어컨을 켤 때는 14byte의 데이터를 전송하고, 끌 때는 rawData를 전송했다.
MutatedIRsendDemo.ino
// IR Transmitter with NodeMCU
// Modified IRremoteESP8255/IRsendDemo
#include <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message.
// Mesg Desc.: Power: Off, Mode: 0 (Auto), Temp: 25C, Fan: 6 (Auto), Swing: Off, Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, Light: On, Ion: Off
const uint16_t rawData[349] = {630, ..., 560};
// Mesg Desc.: Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 5 (High), Swing: Off, Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, Light: On, Ion: Off
const uint8_t state[1][14] = {
{ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x01, 0xC2, 0xFE, 0x71, 0x40, 0x1B, 0xF0 }
};
void setup() {
irsend.begin();
#if ESP8266
Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
#else // ESP8266
Serial.begin(115200, SERIAL_8N1);
#endif // ESP8266
}
void loop() {
Serial.println("a Samsung A/C rawData from IRrecvDumpV2");
Serial.println("turn on the Samsung A/C");
irsend.sendSamsungAC(state[0]);
delay(1000);
Serial.println("a Samsung A/C rawData from IRrecvDumpV2");
Serial.println("turn off the Samsung A/C");
irsend.sendRaw(rawData, 349, 38);
delay(1000);
}
추가적으로 집에 있는 TV 리모컨이나 셋탑박스 리모컨에 대해서도 잘 동작했다.
그런데, 에어컨 리모컨은 여러 방향에서 잘 동작하는데, 내가 만든 건 그렇지 못하다. (에어컨을 향해 정방향으로 노아야 동작을 한다. )
이건 왜 그런 걸까.. 단순히 센서의 질 차이인지.. 다음에 에어컨 리모컨을 분해해봐야겠다.
'아두이노' 카테고리의 다른 글
NodeMCU를 이용한 Stepper motor & Driver 제어 (0) | 2020.08.29 |
---|---|
NodeMCU를 이용한 Limit Switch 제어 (0) | 2020.08.29 |
NodeMCU를 통한 Web Scraping (0) | 2020.08.17 |