산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

ArduFarmBot - 2부:IoT 구현과 원격 스테이션

구성품 및 소모품

Arduino Nano R3
× 1
Espressif ESP8266 ESP-01
× 1
DHT22 온도 센서
× 1
ky18
× 1
비중계
× 1
릴레이(일반)
× 2
LCD 4X20
× 1
SparkFun 푸시버튼 스위치 12mm
× 3
LED(일반)
× 3

앱 및 온라인 서비스

ThingSpeak API

이 프로젝트 정보

이 튜토리얼은 ArduFarmBot:Arduino 및 IoT를 사용하여 토마토 농장 제어하기

의 연속입니다.

첫 번째 부분에서 우리는 토마토 농장에서 온도, 상대 습도, 광도 및 토양 습도와 같은 정보를 캡처하는 로컬 제어 스테이션을 만듭니다. 이러한 데이터를 기반으로 ArduFarmBot은 농장이 열과 물을 받아야 하는 적절한 양(및 시기)을 자동으로 결정했습니다. Part 1에서 개발된 로컬 스테이션은 수도 펌프와 전등을 제어하기 위해 작업자의 수동 개입도 허용했습니다. 이 2부에서는 이 "수동 개입"이 인터넷을 통해 원격으로 가능할 경우 IoT 접근 방식을 구현합니다. 블록다이어그램은 이를 수행하는 방법을 보여줍니다.

캡처된 데이터는 "Cloud Storage 서비스"(이 경우 Thinkspeak.com)로 전송됩니다. 또한 전용 웹사이트인 "Remote Control Page"는 이러한 데이터를 거의 실시간으로 모니터링하고 표시합니다. 이 웹페이지는 또한 펌프와 램프의 원격 활성화를 허용합니다.

1단계:BOM

<울>
  • 아두이노 나노 - ($7.50)
  • <울>
  • 온도 및 습도 센서 DHT22 또는 DHT11 - ($3.66)
  • <울>
  • 광도 센서 - AD-018 포토 레지스터 모듈. 또는 이에 상응하는 것 - ($0.71)
  • <울>
  • 2X 토양 수분 센서 - ($1.99) (선택 사항, DIY 가능)
  • <울>
  • LCD I2C 20X4($13.99)
  • <울>
  • LED(1X)($0.20)
  • <울>
  • Esp8266 직렬 Wifi 무선 트랜시버 모듈 Esp-01 - ($5.96)
  • <울>
  • 활성 부저 - Ky-12 또는 이에 상응하는 것($0.60)
  • <울>
  • 2 X 5v 릴레이 모듈($11.60)
  • <울>
  • 점프 와이어(S1.00)
  • <울>
  • 10Kohms 저항 - ($0.03)
  • <울>
  • 2.2K 옴 저항 - ($0.03)
  • <울>
  • 1.0K 옴 저항 - ($0.03)
  • <울>
  • 220옴 저항 - ($0.03)
  • <울>
  • Arduino Nano Shield("Funduino") - ($7.28)
  • <울>
  • 멤브레인 키보드(4 키) - ($6.65)
  • <울>
  • 플라스틱 상자
  • 2단계:하드웨어 완성

    Part 1에서 개발한 Local Station부터 추가로 필요한 HW는 ESP8266뿐입니다. 위의 블록 다이어그램은 모든 Arduino 및 주요 구성 요소의 PIN 연결을 보여줍니다. 전압 레벨과 관련된 유일한 주의가 필요합니다. ESP8266은 3.3V로 동작하므로 Nano Tx Pin(D3)에 직접 연결하지 말아야 할 Rx Pin을 연결합니다. 전압 레벨을 사용해야 합니다. 우리의 경우 전압 레벨 변환기로 사용할 전압 분배기를 구축합니다. 위의 다이어그램은 ESP8266을 연결하는 방법을 자세히 보여줍니다. ESP8266에 대해 더 알고 싶으시면 제 튜토리얼을 참조하세요:

    <울>
  • ESP8266 파트 3 - Arduino LED 원격 트리거
  • <울>
  • ESP8266 파트 1 - Arduino용 직렬 WIFI 모듈
  • <울>
  • ESP8266 파트 2 - Arduino 웹 서버
  • SoftSerial 라이브러리를 사용하여 Nano Pin 2(Tx) 및 Pin 3(Rx)에 연결된 ESP8266을 사용하고 있습니다. 이러한 디지털 핀을 "해제"하려면 Nano 직렬 핀 0과 1을 교대로 사용할 수 있습니다. Nano에 코드를 업로드할 때 연결을 해제해야 한다는 점만 기억하십시오.

    참고:BUZZER를 연결하려면 핀 D17(핀 A3과 동일)에서 연결해야 합니다. 통신 오류가 났을 때 소리가 나는 것이 좋습니다. 테스트 단계에서 사용했고 최종 프로젝트에서 제외했습니다(hw, 하지만 코드는 이를 위해 준비되어 있습니다). 그것은 당신에게 달려 있습니다.

    ESP8266을 테스트 및/또는 설정하기 위해 다음 코드를 사용할 수 있습니다.

    FC9DBPKIT682FY7.ino

    3단계:ESP8266 연결

    ArduFarmBot을 인터넷에 연결하기 위해 간단하고 저렴하며 프로그래밍하기 쉬운 IoT 프로젝트용 모듈인 ESP8266을 사용할 것입니다. 모듈이 설치되면 가장 먼저 할 생각은 CH-PD 핀에 "리셋"을 적용하는 것입니다.

    <사전><코드>/************************************************ ********* 통신 수락을 위한 재설정 기능************************************ ****************/void reset8266(void){ pinMode(CH_PD, OUTPUT); 디지털 쓰기(CH_PD, LOW); 지연(300); 디지털 쓰기(CH_PD, HIGH); Serial.print("8266 재설정 OK"); lcd.clear(); lcd.println("8266 재설정 확인 ");}

    재설정한 후 자격 증명을 사용하여 로컬 네트워크에 연결하고(코드에서 변경:USERNAME 및 PASSWORD) "STA:스테이션 모드"(CWMODE =1)로 모듈을 시작합니다.

    <사전><코드>/************************************************ ********* WiFi 연결****************************************** *************/무효 connectWiFi(무효){ sendData("AT+RST\r\n", 2000, DEBUG); // 재설정 sendData("AT+CWJAP=\"USERNAME\",\"패스워드\"\r\n", 2000, DEBUG); //네트워크 연결 지연(3000); sendData("AT+CWMODE=1\r\n", 1000, 디버그); sendData("AT+CIFSR\r\n", 1000, 디버그); // IP 주소 표시 lcd.clear(); lcd.print("8266 연결됨"); Serial.println("8266 연결됨");}

    ESP8266에 데이터를 보내려면 sendData() 함수 사용됨:

    <사전><코드>/************************************************ ********* 모듈에 AT 명령 보내기************************************ ****************/String sendData(문자열 명령, const int 시간 초과, 부울 디버그){ 문자열 응답 =""; esp8266.print(명령어); 긴 int 시간 =millis(); while ( (time + timeout)> millis()) { while (esp8266.available()) { // esp에는 데이터가 있으므로 출력을 직렬 창에 표시합니다. char c =esp8266.read(); // 다음 문자를 읽습니다. 응답 +=c; } } if(디버그) { Serial.print(응답); } 반환 응답;}

    위의 함수는 코드의 "설정 단계"에서 호출됩니다. 모든 것이 올바르게 완료되면 직렬 모니터에서 위와 유사한 메시지를 볼 수 있습니다.

    4단계:클라우드 스토리지 데이터:ThinkSpeak.com

    ArduFarmBot에서 캡처한 모든 데이터는 "ThinkSpeak.com"의 무료 서비스를 사용하여 클라우드에 업로드됩니다.

    "Loop()" 함수에서(readSensors()로 데이터를 캡처한 후 ), 캡처된 데이터를 업로드하는 특정 함수를 호출합니다. updateDataThingSpeak();

    <사전><코드>/************************************************ ********* thingspeak.com으로 데이터 전송************************************** *****************/무효 updateDataThingSpeak(무효){ startThingSpeakCmd(); cmd =메시지; cmd +="&필드1="; //DHT 온도에 대한 필드 1 cmd +=tempDHT; cmd +="&필드2="; //DHT 습도에 대한 필드 2 cmd +=humDHT; cmd +="&필드3="; // LDR 광도에 대한 필드 3 cmd +=lumen; cmd +="&필드4="; // 토양 수분 데이터에 대한 필드 4 cmd +=흙수분; cmd +="&필드5="; // PUMP 상태에 대한 필드 5 cmd +=pumpStatus; cmd +="&필드6="; //램프 상태를 위한 필드 6 cmd +=lampStatus; cmd +="\r\n"; sendThingSpeakCmd();}

    이러한 데이터를 보내기 위해서는 먼저 ThingSpeak와 통신을 시작해야 합니다. startThingSpeakCmd(); 기능을 사용하여 이 작업을 수행합니다.

    <사전><코드>/************************************************ ********* ThingSpeak.com과의 커뮤니케이션 시작************************************** *****************/void startThingSpeakCmd(void){ cmd ="AT+CIPSTART=\"TCP\",\""; cmd +=IP; cmd +=" \",80"; esp8266.println(cmd); 지연(2000); if(esp8266.find("오류")) { Serial.println("ESP8266 시작 오류"); 반품; } Serial.println("Thinkspeak 통신 시작"); cmd ="";}

    채널이 ThingSpeak로 열리고 "cmd" 문자열이 데이터와 조합되면 다음 기능을 사용하여 ThingSpeak에 해당 채널을 모두 업로드해야 합니다. sendThingSpeakCmd();

    <사전><코드>/************************************************ ***** * 업데이트 채널 ThingSpeak.com************************************ ****************/문자열 sendThingSpeakCmd(무효){ esp8266.print("AT+CIPSEND="); esp8266.println(cmd.length()); if(esp8266.find(">")){ esp8266.print(cmd); Serial.println(""); Serial.println(""); 직렬.println(cmd); 지연(500); 문자열 messageBody =""; while (esp8266.available()) { 문자열 줄 =esp8266.readStringUntil('\n'); if (line.length() ==1) { //실제 내용은 빈 줄(길이가 1) 이후에 시작합니다. messageBody =esp8266.readStringUntil('\n'); Serial.print("수신된 메시지:"); Serial.println(messageBody); } } 반환 messageBody; } else{ esp8266.println("AT+CIPCLOSE"); Serial.println("ESP8266 CIPSEND 오류:재전송"); //재전송... error=1; "오류"를 반환합니다. }}

    위의 기능은 Michalis Vasilakis가 개발한 훌륭하고 상세한 튜토리얼을 기반으로 합니다. 자세한 내용은 그의 튜토리얼인 Arduino IOT:온도 및 습도(ESP8266 WiFi 포함)를 참조하세요.

    사진은 ThingSpeak.com의 ArduFarmBot 채널을 보여줍니다.

    5단계:웹에서 액추에이터 명령하기

    현재 수집된 모든 데이터를 업로드하여 클라우드에 저장하고 있습니다. 이것은 원격 모니터링에 매우 유용하고 유용하지만 이러한 데이터를 기반으로 로컬 자동 프로그램과 별도로 펌프 또는 램프도 켜고 싶다면 어떻게 될까요? 그렇게 하려면 클라우드에서 데이터를 "다운로드"하고 컨트롤러가 해당 명령에 따라 작동하도록 명령해야 합니다.

    액츄에이터에 명령을 내리기 위해 ThinkSpeak 채널에 특정 필드를 만들 것입니다.

    필드 7:

    <울>
  • 데이터 =1 ==> PUMP를 켜야 합니다.
  • <울>
  • 데이터 =0 ==> PUMP를 꺼야 합니다.
  • 필드 8:

    <울>
  • 데이터 =1 ==> 램프가 켜져 있어야 합니다.
  • <울>
  • 데이터 =0 ==> 램프를 꺼야 합니다.
  • 좋습니다. 하지만 ThingSpeak에서 직접 해당 필드를 설정하는 방법은 무엇입니까? 예를 들어 ThinksPeak에서 직접 "플러그인"을 작성하거나 외부 웹사이트를 사용하여 이를 수행할 수 있습니다(이것이 우리의 선택입니다). 어쨌든 두 경우 모두 다음과 같은 명령을 사용해야 합니다.

    api.thingspeak.com/update?key=YOUR_WRITE_KEY&field7=1 

    예를 들어 위의 명령을 사용하여(그리고 채널 쓰기 키를 사용하여) 필드 7에 "1"을 씁니다. 이는 PUMP가 켜져 있어야 함을 의미합니다. 브라우저에서 위의 명령줄을 작성하여 쉽게 테스트할 수 있습니다. 채널의 해당 필드가 변경됩니다. 반환으로 브라우저는 채널의 순차 데이터 항목에 해당하는 왼쪽 상단 모서리에 단일 숫자가 있는 흰색 페이지를 표시합니다.

    작업의 50%가 완료되었습니다. 이제 로컬 ArduFarmBot 스테이션에서 이 "명령"(현장 데이터)을 읽어야 합니다.

    이를 수행하는 명령은 다음과 같습니다. 특정 필드에 작성된 마지막 데이터를 가져옵니다(이 경우 "명령"이 됩니다.

    api.thingspeak.com/channels/CHANNEL_ID/fields/7/last 

    이전과 같은 방식으로 웹 브라우저를 사용하여 명령줄을 테스트할 수 있습니다. 이 경우 브라우저는 해당 특정 필드에 대한 데이터를 표시합니다. 위의 사진을 참조하십시오.

    "지구"로 돌아가서 이 "마지막 필드"를 읽을 함수를 작성해 보겠습니다.

    <사전><코드>/************************************************ ********* thingspeak.com의 field7에서 데이터 읽기************************************ *******************/int readLastDataField7(){ startThingSpeakCmd(); // "GET /channels/CHANNEL_ID/fields/7/last"; cmd =msgReadLastDataField7; cmd +="\r\n"; 문자열 messageDown =sendThingSpeakCmd(); Serial.print("명령 수신:"); Serial.println(messageDown[7]); int 명령 =messageDown[7]-48; 반환 명령;}

    위의 함수는 필드 7("1" 또는 "0")의 데이터를 반환합니다. 필드 8에 대해서도 유사한 함수를 작성해야 합니다.

    두 필드의 내용이 있으면 "수동 명령 기능"에서 했던 것과 유사하게 액추에이터를 명령하는 기능에서 이를 사용해야 합니다.

    <사전><코드>/************************************************ ********* thingSpeak.com에서 명령 수신************************************** *****************/void receiveCommands(){ field7Data =readLastDataField7(); if (field7Data ==1) { digitalWrite(PUMP_PIN, HIGH); 펌프 상태 =1; 쇼데이터LCD(); } if (field7Data ==0) { digitalWrite(PUMP_PIN, LOW); 펌프 상태 =0; 쇼데이터LCD(); } 지연(500); field8Data =readLastDataField8(); if (field8Data ==1) { digitalWrite(LAMP_PIN, HIGH); 램프 상태 =1; 쇼데이터LCD(); } if (field8Data ==0) { digitalWrite(LAMP_PIN, LOW); 램프 상태 =0; 쇼데이터LCD(); } 지연(500); }

    따라서 지금부터 브라우저의 명령줄을 사용하여 원격으로 펌프와 램프를 켜거나 끌 수 있습니다. 위의 사진은 수신된 명령이 시리얼 모니터에 어떻게 나타나는지 보여줍니다.

    또 다른 중요한 고려 사항은 로컬 및 원격 명령 간의 "조정"입니다. readLocalCmd() 함수 를 변경해야 합니다. 또한 펌프 및 램프 상태로 Thinkspeak Field 7 및 8을 각각 업데이트합니다(해당 "IF 문"에서. 이 튜토리얼의 끝에 있는 전체 코드 참조):

    field7Data =pumpStatus;field8Data =lampStatus; 

    이제 "filed7Data" 및 "field8Data"가 웹 페이지 명령과 동기화되며 버튼을 누를 때 로컬 명령 작업과도 동기화됩니다. 이제 aplyCmd()를 업데이트해 보겠습니다. 액츄에이터를 켜고 끄는 역할을 하는 기능입니다.

    <사전><코드>/************************************************ ********* 명령을 수신하고 액추에이터에서 작동************************************** *****************/void aplyCmd(){ if (field7Data ==1) digitalWrite(PUMP_PIN, HIGH); if (field7Data ==0) digitalWrite(PUMP_PIN, LOW); if (field8Data ==1) digitalWrite(LAMP_PIN, HIGH); if (field8Data ==0) digitalWrite(LAMP_PIN, LOW);}

    테스트를 시작하면 로컬에서 또는 웹을 통해 수동으로 수행하는 모든 명령이 autoControlPlantation() 함수에 의해 정의된 자동 작업에 의해 극복된다는 것을 알게 될 것입니다. ; 이 시점에서 마지막 말을 가진 "보스"가 누구인지 고려해야합니다! 여기서는 다음을 정의합니다.

    <울>
  • 거의 "항상"인 모든 루프 사이클에서 버튼이 눌렸는지 확인할 것입니다.
  • <울>
  • 매분마다 ThingSpeak에서 "풀링"을 수행하고 거기에서 주문을 받았는지 확인해야 합니다.
  • <울>
  • 약 10분마다 센서를 읽고 ThingSpeak의 데이터를 업데이트하며 더 중요한 것은 자동 작업을 수행합니다. 이러한 작업은 수동으로 선택한 작업과 독립적으로 수행되며 유지됩니다.
  • 원하는 방식으로 변경할 수 있습니다. 제어할 수 있는 프로그램 가능한 프로세서를 사용하는 것은 좋은 점입니다!

    따라서 이제 2개의 타이머가 사용됩니다. 하나는 원격 명령을 풀링하고 다른 하나는 센서를 읽기 위한 것입니다(이전에 사용한 것과 동일한 것:

    긴 sampleTimingSeconds =75; // ==> ******** 센서를 읽기 위한 샘플 시간(초) 정의 *********int reverseElapsedTimeSeconds =0;long startTiming =0;long elapsedTime =0;long poolingRemoteCmdSeconds =20; // ==> ******** 새로운 ThingSpeak 명령에 대한 풀링 시간을 초 단위로 정의 *********long startRemoteCmdTiming =0; 긴 경과된RemoteCmdTime =0; 

    따라서 loop() 함수는 이제 아래와 같이 다시 작성되어야 합니다.

    void loop() { elapsedRemoteCmdTime =millis()-startRemoteCmdTiming; // 원격 명령 풀링을 위한 시작 타이머 elapsedTime =millis()-startTiming; // 측정을 위한 타이머 시작 reverseElapsedTimeSeconds =round (sampleTimingSeconds - elapsedTime/1000); readLocalCmd(); //로컬 버튼 상태 읽기 showDataLCD(); if (elapsedRemoteCmdTime> (poolingRemoteCmdSeconds*1000)) { receiveCommands(); updateDataThingSpeak(); startRemoteCmdTiming =millis(); } if (elapsedTime> (sampleTimingSeconds*1000)) { readSensors(); autoControlPlantation(); updateDataThingSpeak(); 시작 타이밍 =밀리(); }} 

    6단계:전용 웹페이지 구현

    이 시점에서 ArduFarmBot이 작동 중이며 웹에서 제어할 수 있습니다. Thinkspeak 사이트에서 데이터를 모니터링하고 브라우저를 사용하여 명령을 보낼 수도 있지만 물론 이 "웹 솔루션"이 "우아한" 솔루션으로 간주될 수는 없습니다! 전체 IoT 솔루션을 구현하는 가장 좋은 방법은 모든 데이터를 표시하고 액추에이터를 활성화하는 버튼도 포함하는 완전한 웹페이지를 개발하는 것입니다.

    저는 귀하의 페이지를 매우 쉽고 간단하게 처리할 수 있는 무료 웹호스트인 Byethost를 선택했습니다. 또한 저는 Coursera/University of Michigan:Learn to Design and Create Websites(HTML5, CSS3, JavaScript를 사용하여 반응형 및 접근 가능한 웹 포트폴리오 구축 ).

    이러한 페이지를 개발하는 방법에 대해 자세히 설명하지 않겠습니다. 이것이 이 튜토리얼의 중심 목적이 아니기 때문에 여기에 HTML, CSS 및 JavaScript 소스 코드를 포함할 것입니다. 그리고 누군가 내가 어떻게 결과를 얻었는지에 관심을 갖게 되면 프로젝트가 끝날 때 의견 게시판을 사용하여 따로 논의할 수 있습니다.

    이 페이지가 ArduFarmBot 로컬 제어 스테이션과 직접 작동하지 않는다는 점을 강조하는 것이 중요합니다. 실제로 하는 일은 아래와 같이 ThinkSpeak 채널과 상호 작용하는 것입니다.

    <울>
  • 필드 1, 2, 3, 4의 센서 데이터 읽기
  • <울>
  • 필드 5 및 6에서 액추에이터 상태 읽기
  • <울>
  • 필드 7과 8에 데이터 쓰기
  • <울>
  • 야후 서비스에서 지역 날씨 데이터 읽기
  • 위의 항목 4는 프로젝트에 실제로 중요하지 않지만 토마토 농장에서 로컬에서 진행 중인 작업과 관계없이 원격 작업을 수행하려는 경우 항상 사용할 수 있는 추가 데이터입니다. 다른 고려 사항은 예를 들어 해당 데이터를 다른 ThingSpeak 채널에 저장하고 Arduino에 다운로드하여 날씨 데이터를 로컬 LCD 디스플레이에 표시할 수 있다는 것입니다(나는 잘 작동하는 다른 멋진 프로젝트에서 이것을 개발했습니다! 당신).

    FQOK9ENIT653YX5.zip

    7단계:뇌로 돌아갑니다. 센서-액추에이터 매트릭스 접근 방식:

    이 프로젝트의 첫 번째 부분에서 우리는 센서의 판독값에 따라 액추에이터가 어떻게 작동해야 하는지에 대한 몇 가지 예비 고려 사항을 정의했습니다. 우리는 단순한 선택만 했을 뿐인데, 상황이 더 복잡해지면 어떻게 될까요? 여러 가지 다른 조건? 우리가 개발할 것은 "센서 - 액츄에이터 매트릭스 접근"입니다.

    Matrix에서는 각 센서에 대해 그 상태와 액추에이터의 출력이 어떻게 되어야 하는지를 정의했습니다. 결과는 아래에 포함된 Excel 스프레드시트에서 볼 수 있습니다. Excel 파일에는 두 개의 스프레드시트가 있습니다. 필터와 버전이 있는 테이블은 여러 센서 조건을 선택하고 이 선택으로 인해 액추에이터가 어떻게 작동하는지 확인할 수 있었습니다.

    Matrix가 정의되면 이를 코드로 변환해야 합니다. Sensor-Actuator Matrix의 조건을 "복사"하기 위해 18줄과 10열의 어레이가 생성되었습니다.

     // +---SOIL----+-LIGHT-+---TEMP---+---ACTUAT----+ // SL SM SH LL LH TL TM TH 펌프 램프불 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 }, }; 

    Matrix로 작업하기 위해 defSensorStatus() 함수를 만듭니다. . 이 함수는 8개의 첫 번째 열의 조건이 TRUE인지 각 행에 대해 테스트합니다. 예인 경우 마지막 2열의 조건이 실행됩니다.

    예:

    if (1과 0과 0과 0과 1과 0과 0과 1) { pumpStatus =1; LampStatus =0}else if (1 및 0 및 0 및 0 및 1 및 0 및 1 및 0) { pumpStatus =1; 램프 상태 =0} 

    등등.

    위의 함수 내에서 각 센서 판독값의 상태와 함께 다른 어레이가 생성됩니다.

    부울 snsSts[8]={0, 0, 0, 0, 0, 0, 0, 0}; // SL, SM, SH, LL, LH, TL, TM, TH 

    이 변수 배열은 LOG 레지스터에도 사용됩니다.

    F2HWXBYITA8WIN1.xlsx

    8단계:코드 최적화

    ArduFarmBot을 개발하는 과정에서 원래 사양을 약간 변경해야 함을 깨달았습니다.

    디스플레이:

    LCD 디스플레이는 기본적으로 꺼져 있어야 하며 센서 판독이 필요할 때마다 수동으로 "켜짐"으로 설정할 수 있습니다. 이 조건은 코드에서 구현되었으며 "토글" 모드에서와 같이 "센서 읽기" 버튼을 사용하여 언제든지 LCD를 켜고/끄도록 해야 합니다. 디스플레이를 켜거나 끄면 표시할 센서 판독값이 업데이트되지만 ArduFarmBot이 일반 기능에서는 사용하지 않습니다.

    초기 설정:

    ArduFarmBot이 켜지면(또는 재설정되면) LCD에 "초기 설정"이 표시됩니다. 프로그램 실행을 시작하려면 "센서" 버튼을 눌러야 합니다. 표시된 초기 정보(위 사진 참조)는 다음과 같습니다.

    <울>
  • COLD 온도(예:12oC)
  • <울>
  • 건조 토양 습도(즉, 30%)
  • <울>
  • 습한 토양 습도(예:60%)
  • <울>
  • 어두운 조명(예:40%)
  • <울>
  • P_ON 펌프 시간 켜기(즉, 10초)
  • <울>
  • SCAN 센서를 읽는 데 걸리는 시간(예:600초)
  • <울>
  • SW_버전(예:4.1)
  • 로그 기록:

    감사 목적으로 ArduFarmBot의 판독값과 작동으로 LOG를 만들었습니다. 모든 읽기 주기에서 함수:storeDataLogEEPROM() 실행됩니다.

    <사전><코드>/************************************************ ********* Arduino EEPROM에 로그 데이터 저장********************************** ******************/void storeDataLogEEPROM(void){ for (int i =0; i<8; i++) { logData =logData + (snsSts[i])<<1; } EEPROM.write(memoAddr, logData); 메모주소++; 로그 데이터 =0; logData =logData + 펌프 상태; 로그 데이터 =로그 데이터 <<1; logData =logData + 램프 상태; EEPROM.write(memoAddr, logData); EEPROM.write(0, memoAddr+1); 로그 데이터 =0; if ((memoAddr+1) ==1023) memoAddr=1; else memoAddr++;}

    마지막 단계에서 언급했듯이 Arduino EEPROM에 저장되는 내용은 snsSts[] 배열의 비트입니다. 플러스 펌프 및 램프 상태. 위의 시리얼 모니터에서 LOG를 볼 수 있습니다.

    모든 ArduFarmBot 코드는 이해하기 쉽도록 다른 파일로 분할되었습니다. 이 두 번째 부분에 2개의 새 파일이 추가되었습니다.

    <울>
  • communication.ino (ThingSpeak 및 ESP8266 특정 기능)
  • <울>
  • stationCredentials.h (ThingSpeak 채널 ID 및 채널에 쓰기 위한 특정 키)
  • 마지막으로 코드가 적당한 크기로 끝나면 SRAM 대신 플래시(프로그램) 메모리에 상수 데이터를 저장하기로 결정했습니다. 이를 위해 변수 수정자인 PROGMEM 키워드를 사용합니다. 예를 들어 다음을 사용하는 대신:

    #DHTPIN 5 정의 

    우리는 다음을 사용했습니다:

    const PROGMEM 바이트 DHTPIN =5; 

    키워드 PROGMEN은 컴파일러에게 일반적으로 이동하는 SRAM 대신 "이 정보를 플래시 메모리에 넣습니다"라고 알려줍니다. 또한 코드의 기본 파일에 avr/pgmspace.h 라이브러리를 포함해야 합니다.

    SRAM 사용을 줄이는 또 다른 좋은 절차는 개발 중 디버깅에 사용한 모든 Serial.Print() 행에 주석을 달거나 삭제하는 것입니다. 예를 들어 직렬 모니터에서 LOG를 표시하는 데 사용되는 코드가 아래 파일에 주석으로 표시된다는 것을 알게 될 것입니다.

    아래에서 전체 ArduFarmBot Arduino 코드를 찾을 수 있습니다. 채널 ID 및 쓰기 키로 자격 증명.h의 더미 데이터를 변경하는 것을 잊지 마십시오. 또한 communication.ino에서 실제 사용자 이름과 암호를 사용하여 인터넷에서 ESP 8266을 연결합니다.

    FTUT5VIIT67U8ME.ino FWMIPSSIT67U8MG.ino FJPGZNKIT67U8MK.ino FQH3X9VIT67U8NA.ino F15MY4YIT67U8NB.ino FVU64X1IT67U8NC.h FZ057E3IT67U8P5.h

    9단계:MJRovai 홈 팜

    아래 사진은 첫 번째 토마토 농장을 제어하는 ​​ArduFarmBot의 순차 사진입니다.

    아래 사진 순서는 종자 파종부터 최고의 식물을 선택하는 시간(약 45일) 및 베스트 6 식물의 이식까지의 나의 2차 파종 진화를 보여줍니다.

    10단계:결론

    그게 다야! ...당분간!

    항상 그렇듯이 이 프로젝트가 다른 사람들이 전자, IoT 및 로봇 공학의 흥미진진한 세계에서 길을 찾는 데 도움이 되기를 바랍니다!

    곧 우리는 아마 유기농 토마토 소스 파스타의 아주 좋은 조리법이 되기를 바라는 우리 프로젝트의 세 번째이자 마지막 부분을 게시할 것입니다.

    그건 그렇고, 위의 사진에서 Mauricio의 농장에서 인생의 첫 한숨을 볼 수 있습니다! 그리고 가시기 전에 새로운 ArduFarmBot, 책!을 살펴보세요. 더 친숙한 형식으로 모든 프로젝트를 포장하는 곳:

    ArduFarmBot, the Book!

    "ArduFarmBot, the book" is also at Amazon.com! You can get it, by clicking hereThe book uses the electronic controller ArduFarmBot as a basis for teaching how to work in both HW and SW, with:

    <울>
  • LCD and OLED type displays;
  • <울>
  • LEDs and buttons;
  • <울>
  • Activation of pumps and lamps via relays and
  • <울>
  • Sensors such as:DHT22 (temperature and relative air humidity), DS18B20 (soil temperature), YL69 (soil moisture) and LDR (luminosity).
  • All key stages of the project are documented in detail through explanatory texts, block diagrams, high-resolution color photos, electrical diagrams using Fritzing application, complete codes stored in GitHub and YouTube 비디오.

    Two versions of the electronic controller ArduFarmBot are developed in detail in the book. From capture of data coming from a garden, such as air and soil temperature, relative humidity, soil moisture and luminosity, the ArduFarmBot helps to control when a crop should receive heat and water. Control will happen automatically, locally and remotely via internet. The book is divided into 3 parts. In the first part, the Arduino Nano is the starting point for development of a local version of ArduFarmBot , that can be controlled both, manually and automatically.

    In the second part, the book dives into automation design, introducing remote operation through the creation of a webpage. The ESP8266-01 is used for Wi-Fi connection, sending data to an important web service in the field of IoT, the ThingSpeak.com .

    In the third part, a second version of ArduFarmBot is developed, introducing the NodeMCU ESP8266-12E , a powerful and versatile IoT device, which replaces both the Arduino Nano and the ESP8266-01 , used in the earlier parts of the book.

    In this last part of the book, a new service platform of the IoT universe, the Blynk , is also explored.

    Download the book, give it a review and please use the message board here to give us any comment, suggestion or critic!

    For more projects, please visit my blog:MJRoBot.org

    Saludos from the south of the world!

    See you at my next project!

    Thank you

    마르셀로

    <섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

    코드

    <울>
  • 코드 스니펫 #1
  • 코드 스니펫 #2
  • 코드 스니펫 #3
  • 코드 스니펫 #4
  • 코드 스니펫 #5
  • Code snippet #6
  • Code snippet #9
  • Code snippet #10
  • 코드 스니펫 #11
  • Code snippet #12
  • Code snippet #13
  • Code snippet #14
  • Code snippet #15
  • 코드 스니펫 #1일반 텍스트
    /**************************************************** Reset funtion to accept communication****************************************************/void reset8266(void){ pinMode(CH_PD, OUTPUT); digitalWrite(CH_PD, LOW); 지연(300); digitalWrite(CH_PD, HIGH); Serial.print("8266 reset OK"); lcd.clear(); lcd.println("8266 reset OK ");}
    코드 스니펫 #2일반 텍스트
    /**************************************************** Connect WiFi****************************************************/void connectWiFi(void){ sendData("AT+RST\r\n", 2000, DEBUG); // reset sendData("AT+CWJAP=\"USERNAME\",\"PASSWORD\"\r\n", 2000, DEBUG); //Connect network delay(3000); sendData("AT+CWMODE=1\r\n", 1000, DEBUG); sendData("AT+CIFSR\r\n", 1000, DEBUG); // Show IP Adress lcd.clear(); lcd.print("8266 Connected"); Serial.println("8266 Connected");}
    코드 스니펫 #3일반 텍스트
    /**************************************************** Send AT commands to module****************************************************/String sendData(String command, const int timeout, boolean debug){ String response =""; esp8266.print(command); long int time =millis(); while ( (time + timeout)> millis()) { while (esp8266.available()) { // The esp has data so display its output to the serial window char c =esp8266.read(); // read the next character. response +=c; } } if (debug) { Serial.print(response); } return response;}
    코드 스니펫 #4일반 텍스트
    /**************************************************** Transmit data to thingspeak.com****************************************************/void updateDataThingSpeak(void){ startThingSpeakCmd (); cmd =msg; cmd +="&field1="; //field 1 for DHT temperature cmd +=tempDHT; cmd +="&field2="; //field 2 for DHT humidity cmd +=humDHT; cmd +="&field3="; //field 3 for LDR luminosity cmd +=lumen; cmd +="&field4="; //field 4 for Soil Moisture data cmd +=soilMoist; cmd +="&field5="; //field 5 for PUMP Status cmd +=pumpStatus; cmd +="&field6="; //field 6 for LAMP Status cmd +=lampStatus; cmd +="\r\n"; sendThingSpeakCmd();}
    코드 스니펫 #5일반 텍스트
    /**************************************************** Start communication with ThingSpeak.com****************************************************/void startThingSpeakCmd(void){ cmd ="AT+CIPSTART=\"TCP\",\""; cmd +=IP; cmd +="\",80"; esp8266.println(cmd); 지연(2000); if(esp8266.find("Error")) { Serial.println("ESP8266 START ERROR"); 반품; } Serial.println("Thinkspeak Comm Started"); cmd ="";}
    Code snippet #6Plain text
    /*************************************************** * Update channel ThingSpeak.com****************************************************/String sendThingSpeakCmd(void){ esp8266.print("AT+CIPSEND="); esp8266.println(cmd.length()); if(esp8266.find(">")){ esp8266.print(cmd); Serial.println(""); Serial.println(""); Serial.println(cmd); 지연(500); String messageBody =""; while (esp8266.available()) { String line =esp8266.readStringUntil('\n'); if (line.length() ==1) { //actual content starts after empty line (that has length 1) messageBody =esp8266.readStringUntil('\n'); Serial.print("Message received:"); Serial.println(messageBody); } } return messageBody; } else{ esp8266.println("AT+CIPCLOSE"); Serial.println("ESP8266 CIPSEND ERROR:RESENDING"); //Resend... error=1; return "error"; }}
    Code snippet #9Plain text
    /**************************************************** Read data from field7 of thingspeak.com****************************************************/int readLastDataField7(){ startThingSpeakCmd (); // "GET /channels/CHANNEL_ID/fields/7/last"; cmd =msgReadLastDataField7; cmd +="\r\n"; String messageDown =sendThingSpeakCmd(); Serial.print("Command received:"); Serial.println(messageDown[7]); int command =messageDown[7]-48; return command;}
    Code snippet #10Plain text
    /**************************************************** Receive Commands from thingSpeak.com****************************************************/void receiveCommands(){ field7Data =readLastDataField7(); if (field7Data ==1) { digitalWrite(PUMP_PIN, HIGH); pumpStatus =1; showDataLCD(); } if (field7Data ==0) { digitalWrite(PUMP_PIN, LOW); pumpStatus =0; showDataLCD(); } delay (500); field8Data =readLastDataField8(); if (field8Data ==1) { digitalWrite(LAMP_PIN, HIGH); lampStatus =1; showDataLCD(); } if (field8Data ==0) { digitalWrite(LAMP_PIN, LOW); lampStatus =0; showDataLCD(); } delay (500); }
    코드 스니펫 #11일반 텍스트
    /**************************************************** Receive Commands and act on actuators****************************************************/void aplyCmd(){ if (field7Data ==1) digitalWrite(PUMP_PIN, HIGH); if (field7Data ==0) digitalWrite(PUMP_PIN, LOW); if (field8Data ==1) digitalWrite(LAMP_PIN, HIGH); if (field8Data ==0) digitalWrite(LAMP_PIN, LOW);}
    Code snippet #12Plain text
    long sampleTimingSeconds =75; // ==> ******** Define Sample time in seconds to read sensores *********int reverseElapsedTimeSeconds =0;long startTiming =0;long elapsedTime =0;long poolingRemoteCmdSeconds =20; // ==> ******** Define Pooling time in seconds for new ThingSpeak commands *********long startRemoteCmdTiming =0; long elapsedRemoteCmdTime =0;
    Code snippet #13Plain text
    void loop() { elapsedRemoteCmdTime =millis()-startRemoteCmdTiming; // Start timer for pooling remote commands elapsedTime =millis()-startTiming; // Start timer for measurements reverseElapsedTimeSeconds =round (sampleTimingSeconds - elapsedTime/1000); readLocalCmd(); //Read local button status showDataLCD(); if (elapsedRemoteCmdTime> (poolingRemoteCmdSeconds*1000)) { receiveCommands(); updateDataThingSpeak(); startRemoteCmdTiming =millis(); } if (elapsedTime> (sampleTimingSeconds*1000)) { readSensors(); autoControlPlantation(); updateDataThingSpeak(); startTiming =millis(); }}
    Code snippet #14Plain text
     // +---SOIL----+-LIGHT-+---TEMP---+---ACTUAT----+ // SL SM SH LL LH TL TM TH Pump Lampboolean 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 }, };
    Code snippet #15Plain text
    /**************************************************** Storage of Log data at Arduino EEPROM****************************************************/void storeDataLogEEPROM(void){ for (int i =0; i<8; i++) { logData =logData + (snsSts[i])<<1; } EEPROM.write (memoAddr, logData); memoAddr++; logData =0; logData =logData + pumpStatus; logData =logData <<1; logData =logData + lampStatus; EEPROM.write (memoAddr, logData); EEPROM.write (0, memoAddr+1); logData =0; if ((memoAddr+1) ==1023) memoAddr=1; else memoAddr++;} 
    ArduFarmBot GitHub
    https://github.com/Mjrovai/ArduFarmBot

    회로도

    ardufarmbot_qpNcBDX6Jr.fzz

    제조공정

    1. IoT 구현 동향
    2. 6-Shooter:Arduino 음료 혼합 스테이션
    3. 다중 온도 센서
    4. 모션센스
    5. 3D 프린터 화재 안전
    6. Arduino, Yaler 및 IFTTT가 포함된 IoT 게이지
    7. Arduino 반발 전자기 부상
    8. 원격 제어 그리퍼 봇
    9. Arduino 기반 날씨 풍선 데이터 로거
    10. CoroFence - 열 감지기🖖