ArduFarmBot 2부: 원격 IoT 제어 스테이션 구축하기
구성품 및 부품
| 부품 |
수량 |
비고 |
| Arduino Nano R3 |
1 |
|
| Espressif ESP8266 ESP-01 |
1 |
|
| DHT22 온습도 센서 |
1 |
|
| KY-018 광량 센서 모듈 |
1 |
|
| 토양 수분 센서 (하이드로미터) |
1 |
|
| 릴레이 모듈 (제네릭) |
2 |
|
| LCD 20x4 (I2C) |
1 |
|
| 푸시버튼 스위치 12mm |
3 |
|
| LED (제네릭) |
3 |
|
앱 및 온라인 서비스
프로젝트 소개
이 튜토리얼은 ArduFarmBot: 아두이노와 IoT로 토마토 홈 팜 제어하기의 연속입니다.
1부에서는 토마토 재배 환경(기온, 상대습도, 조도, 토양 수분) 데이터를 수집하는 로컬 제어 스테이션을 만들었습니다. 수집된 데이터를 바탕으로 ArduFarmBot이 자동으로 급수 시기와 양, 히터 작동을 결정했습니다. 로컬 스테이션에서는 운영자가 수동으로 펌프와 램프를 제어할 수도 있었습니다.
이번 2부에서는 이 '수동 개입'을 인터넷을 통해 원격으로도 가능하게 하는 IoT 접근법을 구현합니다. 블록 다이어그램과 같이 클라우드 스토리지(ThingSpeak.com)로 데이터를 전송하고, 전용 웹페이지('원격 제어 페이지')에서 실시간 모니터링과 펌프/램프 원격 제어를 수행합니다.
1단계: 자재 명세서 (BOM)
- Arduino Nano ($7.50)
- DHT22 또는 DHT11 온습도 센서 ($3.66)
- 조도 센서 AD-018 포토레지스터 모듈 ($0.71)
- 토양 수분 센서 ×2 ($1.99, DIY 가능)
- LCD I2C 20x4 ($13.99)
- LED ($0.20)
- ESP8266 ESP-01 와이파이 모듈 ($5.96)
- 액티브 부저 KY-12 ($0.60)
- 5V 릴레이 모듈 ×2 ($11.60)
- 점퍼 와이어, 각종 저항 (10k, 2.2k, 1k, 220Ω)
- Arduino Nano 쉴드 (Funduino) ($7.28)
- 멤브레인 키보드 4키 ($6.65)
- 플라스틱 박스
2단계: 하드웨어 완성
1부의 로컬 스테이션 기반으로 ESP8266만 추가하면 됩니다. 블록 다이어그램에 모든 핀 연결이 나와 있습니다. 주의할 점은 ESP8266이 3.3V 동작이라 나노 TX(D3)를 ESP8266 RX에 직접 연결하면 안 되고 전압 분배기로 레벨 변환해야 합니다.
ESP8266은 나노 핀 2(TX), 3(RX)에 SoftwareSerial로 연결. 하드웨어 시리얼(핀 0,1) 사용 시 업로드 때만 분리하면 됩니다.
부저는 핀 D17(A3)에 연결 (통신 에러 시 알림용, 최종 버전에선 하드웨어 제외했으나 코드는 대비).
ESP8266 테스트/설정용 코드: FC9DBPKIT682FY7.ino
3단계: ESP8266 연결
ESP8266으로 인터넷 연결. 먼저 CH-PD 핀에 리셋 펄스 적용:
void reset8266(void) {
pinMode(CH_PD, OUTPUT);
digitalWrite(CH_PD, LOW); delay(300);
digitalWrite(CH_PD, HIGH);
Serial.print("8266 reset OK");
lcd.clear(); lcd.println("8266 reset OK ");
}
자격 증명(USERNAME, PASSWORD)으로 로컬 네트워크 연결 후 STA 모드(CWMODE=1) 설정:
void connectWiFi(void) {
sendData("AT+RST\r\n", 2000, DEBUG);
sendData("AT+CWJAP=\"USERNAME\",\"PASSWORD\"\r\n", 2000, DEBUG);
delay(3000);
sendData("AT+CWMODE=1\r\n", 1000, DEBUG);
sendData("AT+CIFSR\r\n", 1000, DEBUG); // IP 주소 확인
lcd.clear(); lcd.print("8266 Connected");
Serial.println("8266 Connected");
}
AT 명령 전송 함수 sendData()로 위 함수들 호출. 정상 시 시리얼 모니터에 연결 메시지 출력.
4단계: 클라우드 데이터 저장 - ThingSpeak.com
모든 데이터를 무료 서비스 ThingSpeak.com에 업로드. loop()에서 readSensors() 후 updateDataThingSpeak() 호출:
void updateDataThingSpeak(void) {
startThingSpeakCmd();
cmd = msg;
cmd += "&field1=" + tempDHT; // 필드1: DHT 온도
cmd += "&field2=" + humDHT; // 필드2: DHT 습도
cmd += "&field3=" + lumen; // 필드3: 조도
cmd += "&field4=" + soilMoist; // 필드4: 토양 수분
cmd += "&field5=" + pumpStatus; // 필드5: 펌프 상태
cmd += "&field6=" + lampStatus; // 필드6: 램프 상태
cmd += "\r\n";
sendThingSpeakCmd();
}
ThingSpeak 통신 시작 startThingSpeakCmd(), 데이터 조립 후 sendThingSpeakCmd()로 채널 업로드. 위 함수들은 Michalis Vasilakis 튜토리얼 기반.
5단계: 웹에서 액추에이터 제어
데이터 업로드만으론 부족해 원격에서 펌프/램프 제어 기능 추가. ThingSpeak 채널에 명령용 필드 생성:
- 필드 7: 1=펌프 ON, 0=펌프 OFF
- 필드 8: 1=램프 ON, 0=램프 OFF
브라우저에서 api.thingspeak.com/update?key=YOUR_WRITE_KEY&field7=1로 테스트 가능.
로컬에서 명령 읽기: api.thingspeak.com/channels/CHANNEL_ID/fields/7/last로 최신 명령 조회.
int readLastDataField7() {
startThingSpeakCmd();
cmd = msgReadLastDataField7 + "\r\n";
String messageDown = sendThingSpeakCmd();
Serial.print("Command received: "); Serial.println(messageDown[7]);
return messageDown[7] - 48; // ASCII '0'/'1'을 정수로
}
수신한 명령으로 액추에이터 제어 (receiveCommands(), aplyCmd()). 로컬 버튼 조작 시에도 ThingSpeak 필드 7,8을 동기화해 로컬/원격 간 충돌 방지.
우선순위: 1) 루프마다 로컬 버튼 확인, 2) ~1분마다 ThingSpeak 풀링으로 원격 명령 확인, 3) ~10분마다 센서 읽기/자동 제어/데이터 업로드 (자동 제어가 최종 권한). 타이머 두 개로 구현.
6단계: 전용 웹페이지 구현
Byethost 무료 웹호스팅 사용. HTML5, CSS3, JavaScript로 반응형 웹 포트폴리오 구축 (Coursera 미시건대 강좌 활용).
이 페이지는 ArduFarmBot과 직접 통신하지 않고 ThingSpeak 채널과 상호작용:
- 필드 1~4: 센서 데이터 읽기
- 필드 5,6: 액추에이터 상태 읽기
- 필드 7,8: 제어 명령 쓰기
- 야후 날씨 API로 현지 날씨 표시 (부가 기능)
소스 코드: FQOK9ENIT653YX5.zip
7단계: 센서-액추에이터 매트릭스 접근법
1부에서 간단한 조건만 다뤘지만, 복잡한 상황엔 매트릭스 방식이 필요. 각 센서 조건별 액추에이터 출력을 정의한 엑셀 매트릭스(필터링/다중 선택 가능)를 코드로 변환.
18행 10열 배열로 매트릭스 복사 (토양: SL/SM/SH, 조도: LL/LH, 온도: TL/TM/TH → 펌프/램프):
boolean SDf[18][10] = {
{1,0,0, 0,1, 0,0,1, 1,0}, {1,0,0, 0,1, 0,1,0, 1,0}, {1,0,0, 0,1, 1,0,0, 1,1},
{1,0,0, 1,0, 0,0,1, 1,0}, {1,0,0, 1,0, 0,1,0, 1,0}, {1,0,0, 1,0, 1,0,0, 0,1},
{0,1,0, 0,1, 0,0,1, 0,0}, {0,1,0, 0,1, 0,1,0, 0,0}, {0,1,0, 0,1, 1,0,0, 0,1},
{0,1,0, 1,0, 0,0,1, 0,0}, {0,1,0, 1,0, 0,1,0, 0,1}, {0,1,0, 1,0, 1,0,0, 0,1},
{0,0,1, 0,1, 0,0,1, 0,0}, {0,0,1, 0,1, 0,1,0, 0,0}, {0,0,1, 0,1, 1,0,0, 0,1},
{0,0,1, 1,0, 0,0,1, 0,0}, {0,0,1, 1,0, 0,1,0, 0,1}, {0,0,1, 1,0, 1,0,0, 0,1}
};
defSensorStatus() 함수에서 각 행의 앞 8개 조건이 모두 TRUE면 뒤 2개(펌프/램프) 실행. 센서 상태 배열 snsSts[8]도 로그용으로 활용.
8단계: 코드 최적화
- 디스플레이: 기본 OFF, '센서 읽기' 버튼으로 토글 ON/OFF (표시용 읽기만 수행, 제어 로직엔 미영향)
- 초기 설정: 전원 ON 시 LCD에 설정값 표시(저온/건조/습한 토양/어두움 임계값, 펌프 ON 시간, 스캔 주기, SW 버전), '센서' 버튼 눌러야 시작
- 로그 기록: 매 읽기 주기마다
storeDataLogEEPROM() 실행, snsSts[] 비트시프트로 압축 저장 + 펌프/램프 상태
- 모듈화: 통신 관련
communication.ino, 인증 정보 stationCredentials.h 별도 파일로 분리
- 메모리 최적화: 상수 데이터를 SRAM 대신 플래시 메모리에 저장 (
PROGMEM 키워드, avr/pgmspace.h 포함), 디버그용 Serial.print() 주석 처리
전체 코드 파일들: FTUT5VIIT67U8ME.ino, FWMIPSSIT67U8MG.ino, FJPGZNKIT67U8MK.ino, FQH3X9VIT67U8NA.ino, F15MY4YIT67U8NB.ino, FVU64X1IT67U8NC.h, FZ057E3IT67U8P5.h
9단계: MJRovai 홈 팜
ArduFarmBot으로 제어한 첫 토마토 재배 연속 사진들 (씨앗 파종 ~ 수확 45일, 우수 6주 이식 과정 포함).
10단계: 결론
전자공학, IoT, 로봇공학의 흥미로운 세계로 여러분을 안내하는 데 도움이 되길 바랍니다! 곧 3부(유기농 토마토 소스 파스타 레시피 예상)도 공개 예정.
ArduFarmBot, the Book! 아마존에서도 구매 가능. 아두이노 나노 기반 로컬 버전 → ESP8266-01로 원격 제어/ThingSpeak 연동 → NodeMCU ESP8266-12E로 통합 + Blynk 플랫폼 탐색의 3부 구성. LCD/OLED, LED/버튼, 릴레이 구동, 각종 센서(DHT22, DS18B20, YL69, LDR) 다루는 법을 프리칭, 블록 다이어그램, 고해상도 사진, 프리칭 회로도, 깃허브 코드, 유튜브 영상으로 상세 문서화.
더 많은 프로젝트: MJRoBot.org
남반구에서 인사를 전하며, 다음 프로젝트에서 뵙겠습니다! 감사합니다. - Marcelo
코드
회로도
(Fritzing 회로도 파일: ardufarmbot_qpNcBDX6Jr.fzz)