随着智能农业的发展,越来越多的小型设备被应用于农业领域。农业的发展正处于从传统农业向现代农业过渡的过程中,迫切需要具备现代物质条件,用现代科学技术进行转型。物联网(IoT)设备在现代农业中发挥着重要作用。在这个农业监测设备中,我重点监测环境温度和湿度,土壤湿度和水位。我使用了一个小而稳定的传感器,并使用LoRaWAN协议将相关数据上传到The Things Network(TTN)。
物联网(IoT)的快速发展将为农业的发展提供一个新的平台,也将在促进传统产业转型升级方面发挥巨大作用。这些物联网设备具有高效、低成本、自动化等优点,为农业的发展提供了技术支持。湿度控制在农业中非常重要。与肉眼可以观察到的光强不同,大范围农田的环境湿度和水位变化难以观察到,因此需要对电子元件进行监测。我使用了DHT11传感器、水位传感器、土壤湿度传感器和转向引擎,这是一种低成本、高度稳定的组件,适用于各种农业环境。
一. 元器件介绍
1.水位传感器
水位传感器是一款简单易用、性价比较高的水位/水滴识别检测传感器,其是通过具有一系列的暴露的平行导线线迹测量其水滴/水量大小从而判断水位。轻松完成水量到模拟信号的转换,输出的模拟值可以直接被Arduino开发板读取,达到水位报警的功效。
水位传感器能够监测水位。该模块主要是利用三极管的电流放大原理:当液位高度使三极管的基极与电源正极导通的时候,在三极管的基极和发射极之间就会产生一定大小的电流,此时在三极管的集电极和发射极之间就会产生一个一定放大倍数的电流,该电流经过发射极的电阻产生特点电压,被AD转换器采集。
2.DHT11温湿度传感器
数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。
传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式储存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。
单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选则。产品为 4 针单排引脚封装。连接方便,特殊封装形式可根据用户需求而提供。
3.土壤湿度传感器(XH-M214)
我只需要将叉形导电探针粘在土壤上,因为探针有两个暴露的导电板,它们将充当可变电阻器 ,其电阻会根据土壤中的含水量而变化。
探头的这个电阻与设备的土壤湿度成反比。土壤中的水越多,导电性就越好,这将导致电阻降低。土壤中的水越少,导电性越差,这意味着电阻越高。该传感器根据电阻产生输出电压,通过测量我们可以确定水分含量。
4.舵机
收到各个传感器监测到的数值之后,我通过控制舵机进行反馈。舵机模拟的是智能农业系统中的灌溉或者抽水设备。
通过向舵机的信号信号线发送PWM信号来控制舵机的输出量;一般来说,PWM的周期以及占空比,我们是可控的,所以PWM脉冲的占空比直接决定了输出轴的位置。
二.功能实现
本设计采用了Arduino MKR WAN 1300,它是一款功能强大的主板,结合了MKR Zero和LoRa连接的功能。对于希望设计物联网项目的制造商而言,它是理想的解决方案,而且在具有低功耗方面具备自己独特的优势,使用Arduino来开发和测试,也减少了对专业人员的技术需求。开发板上两个主要器件:一个是Atmel SAMD21,另一个是Murata CMWX1ZZABZ LoRa模块。前者让我们体验Arduino,后者让我们体验LoRa,二者结合起来能够实现很多功能。我采用5V的电源为各个元器件供电,并且为各个传感器分配了不同的引脚,确保数据的准确上传。在使用土壤湿度传感器时,我额外接了一个红色LED灯来提示。
土壤湿度传感器依赖于电压,因此将使用模拟引脚,并给出0-1,023的数值。例如,在一个3.3V的板子上,如果传感器返回的是3.3V,返回的值将是1,023。如果返回的电压是1.65V,返回的值将是511。
经过我用我的桌面植物反复测试,当土壤比较干旱时,数值输出为300。所以我将300作为临界值,在这种情况下,如果sensorValue大于该限制,那么一个LED将会亮起。
水位传感器没有插入到水中时,输出值为0,随着水位传感器逐渐没入水中,模拟引脚的值越来越大,当完全没入水中时,输出值最大为670左右。然后逐渐拔出水位传感器,模拟引脚的值随之减小。但是当水位传感器完全拔出来后,输出值没有为0,个人认为是这时水位传感器的表面还有水,会影响模拟引脚的输出值。用干纸巾擦干水位传感器的表面后,模拟引脚的输出值变为0。
同时我也用DHT11温湿度传感器和水位传感器获取了环境温湿度和水位情况。我将所有数据都上传到服务器端,这些数据可以存储在服务器上,以便相关专家研究。在现场我也用arduino对数据进行及时的反应,当湿度低于30%或水位低于三厘米或土壤湿度的值大于400时,控制舵机转动,模拟水泵泵水。串口输出情况如下:
三.数据传输
LoRaWAN协议定义了使用LoRa的MAC层规范,处在协议应用层与物理层中间的实现规范。LoRa没有开放的规范化物理层协议,而LoRa物理模块的接口上很多参数都可以进行配置,LoRaWAN同时对一些数据发送格式做了相应的限制。
我通过LoRaWAN协议将数据传到服务器上,实现TTN服务器与终端节点的通信。结果如下:
四.代码部分
#include "DHT.h"
#define DHTPIN 2 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT11 // DHT 11
DHT dht(DHTPIN, DHTTYPE);
int sensorPin = A0;
int sensorValue;
int limit = 400;
#include <Servo.h>
Servo myservo; // 定义Servo对象来控制
int pos = 0; // 角度存储变量
double temp,data;
#include <MKRWAN.h>
LoRaModem modem;
// Uncomment if using the Murata chip as a module
// LoRaModem modem(Serial1);
#include "arduino_secrets.h"
// Please enter your sensitive data in the Secret tab or arduino_secrets.h
String appEui = SECRET_APP_EUI;
String appKey = SECRET_APP_KEY;
void setup() {
Serial.begin(9600);
Serial.println(F("DHTxx test!"));
dht.begin();
Serial.begin(9600);
pinMode(13, OUTPUT);
myservo.attach(9); // 控制线连接数字9
// put your setup code here, to run once:
Serial.begin(115200);
while (!Serial);
// change this to your regional band (eg. US915, AS923, ...)
if (!modem.begin(EU868)) {
Serial.println("Failed to start module");
while (1) {}
};
Serial.print("Your module version is: ");
Serial.println(modem.version());
Serial.print("Your device EUI is: ");
Serial.println(modem.deviceEUI());
int connected = modem.joinOTAA(appEui, appKey);
if (!connected) {
Serial.println("Something went wrong; are you indoor? Move near a window and retry");
while (1) {}
}
// Set poll interval to 60 secs.
modem.minPollInterval(60);
}
void loop() {
delay(2000);
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
Serial.print(F("Humidity: "));
Serial.print(h);
Serial.print(F("% Temperature: "));
Serial.print(t);
Serial.println(F("C "));
sensorValue = analogRead(sensorPin);
Serial.println("Analog Value : ");
Serial.println(sensorValue);
if (sensorValue<limit) {
digitalWrite(13, HIGH);
}
else {
digitalWrite(13, LOW);
}
delay(1000);
temp=(long)analogRead(1);
data=(temp/650)*4;
Serial.print("the depth is:");
Serial.print(data);
Serial.println("cm");
delay(1000);
if (h<30 || sensorValue < 400 || data < 2){
for (pos = 0; pos <= 180; pos ++) { // 0° to 180°
// in steps of 1 degree
myservo.write(pos);
delay(10);
}
for (pos = 180; pos >= 0; pos --) { // 从180° to 0°
myservo.write(pos);
delay(10);
}
}
Serial.println();
Serial.println("Enter a message to send to network");
Serial.println("(make sure that end-of-line 'NL' is enabled)");
while (!Serial.available());
String msg = String( h );
Serial.println();
Serial.print("Sending: " + msg + " - ");
for (unsigned int i = 0; i < msg.length(); i++) {
Serial.print(msg[i] >> 4, HEX);
Serial.print(msg[i] & 0xF, HEX);
Serial.print(" ");
}
Serial.println();
int err;
modem.beginPacket();
modem.print(msg);
err = modem.endPacket(true);
if (err > 0) {
Serial.println("Message sent correctly!");
} else {
Serial.println("Error sending message :(");
Serial.println("(you may send a limited amount of messages per minute, depending on the signal strength");
Serial.println("it may vary from 1 message every couple of seconds to 1 message every minute)");
}
delay(1000);
if (!modem.available()) {
Serial.println("No downlink message received at this time.");
return;
}
char rcv[64];
int i = 0;
while (modem.available()) {
rcv[i++] = (char)modem.read();
}
Serial.print("Received: ");
for (unsigned int j = 0; j < i; j++) {
Serial.print(rcv[j] >> 4, HEX);
Serial.print(rcv[j] & 0xF, HEX);
Serial.print(" ");
}
Serial.println();
}