1.引言
农业温室大棚作为现在农业发展的必要条件,将高新技术融入农业温室大棚也愈发的重要,对农业温室大棚数据的监控,将温室大棚智能化。本设计对温室大棚实现远程数据监控,自动化控制,对温室内的环境数据进行巡回检测,以4G技术为核心实现数据的远程传输,以适应设备适用于各种复杂偏远的环境。本设计基于ARM-Linux平台利用温湿度、光照强度、二氧化碳浓度等传感器和4G技术,实现数据的远程传输与设备远程控制,克服传统人工方法,节省了工作量,通过阈值设定与系统分析实时调节大棚温室环境,实现设备自动化和信息化。
2.方案设计
2.1系统需求分析
智能温室监控系统是整个温室的指挥中心,本系统基于Linux系统搭建了一个智能温室大棚,本系统基于ARMV7的I.MX6ULL+Linux操作系统的方案。采用NXP生产的I.MX6ULL微处理器,以及外围电路和温湿度、光照、CO2、土壤湿度传感器、4G模块构成智能监控系统。系统具有以下特点:
- 系统化设计:本系统采用系统化设计,根据实际调整传感器数量,以满足不同需求。
- 4G模块无线通信:以适应各种复杂环境,通过MQTT协议确保在3G、4G通信下实现数据传输。
- 远程监控:基于4G技术,使用MQTT协议与阿里云对接,实现数据远程监控。
2.2系统软件需求分析
嵌入式系统应用中,系统安全所需必须考虑的还有两个技术条件,一个前提是整个硬件系统本身要能够确保硬件稳定而可靠,一个先决条件是保证软件系统自身的系统稳定与可靠。并且要求软件的编写时要考虑与其它硬件最大限度地的有效配合。软件的编写通常具有一种较高度的系统复杂性,而Linux嵌入式系统则是指一个完全具有系统安全性、稳定性、实时性、高可并发、的嵌入式硬件系统,其功能结构完整清晰,可移植性高,并且开源。本系统设计主要采用下述四个技术层次上的软件系统设计优化方案:
用户交互层:用户通过移动端实时监控农业温室大棚。
系统内核层:这层是各类传感器设备驱动,将驱动程序与内核一起编译,通过温室大棚中的传感器对数据进行采集。
传输层:使用4G技术通过MQTT协议连入阿里云。
采集层:负责对温室大棚数据进行实时采集。
2.3监控方案设计
本系统采用嵌入式ARM+Linux来实现温室大棚的监控,使得系统更安全稳定,并通过4G技术实现移动端与设备端双向控制。具体方案如下图所示:
图2-1 监控方案设计
3.硬件设计
3.1核心硬件设计
3.1.1 I.MX6ULL简介
本系统选用了恩智浦i.MX6ULL 处理器处理器作为主控制器,I.MX6ULL是一种由NXP公司所生产研发的单核CPU,它同时具有着以下两个特点:性价比更高,在单核芯片范围内还集成了众多的功能及强大稳定的外围接口。I.MX6ULL是一种基于ARMV7指令集的处理器,具有性能极高的内存和处理逻辑单元,I.MX6ULL具有丰富多样的内部扩展设备,LCD、NAND闪存和Flash系统、USB数据接口、UART、传感器等接口。I.MX6ULL具有极高的性价比。
3.1.2储存模块
本套系统主要是采用带有一块512MB系统内存芯片的大容量的NAND闪存盘或高速FLASH卡等作为本系统的外部的主存储器,用来存放文件并可存放系统程序代码、用户数据资料等。Nand-flash的数据存储器容量要足够的大,适合用来进行大量的数据信息资料的实时存储,I.MX6ULL为存储器提供了接口,通过接口来向存储器外部数据传达信号,后面主要用NAND FLASH存储模块来存放根文件系统。
3.2数据采集模块设计
采集模块主要完成的任务是采集环境温湿度、CO2浓度、光照强度、土壤湿度等环境数据,对数据进行运算并传输至阿里云,考虑到尺寸及功耗,要选择合适的硬件设备。
3.2.1传感器
环境温湿度传感器:温湿度检测仪采用新型一体化的数字式温度传感器DHT11,可现场直接测量将温湿度模拟检测信号准确转化输出为数字信号,使用更加方便。技术参数更为准确。
光照传感器:光照传感器选用太阳能感应原件构成的光照传感器,该传感器能将0~65000LX的光照转化为电压信号。
土壤湿度传感器:土壤湿度传感器通过暴露的平行线的电导率测取土壤的湿度,通过A/D信号转换读取土壤湿度值。
CO2传感器:C02传感器采用SGP30,此传感器具有使用简单、高密集性的优点。
3.2.2 4G模块
4G模块采用移远EC20Mini,可以在3G与4G网络之间的无缝切换。在3G、4G网络的偏远地区也可正常工作。
4.功能效果图
4.1系统软件开发
由于目前温室开发的无线监控应用系统目前主要都实现到了监控数据实时自动无线采集与储存分析与实时智能报警处理控制及远程双向远程无线实时视频遥控通信。在我们完成了上述的硬件环境方面的一些基本软件设计及程序测试后我们接下来就将更主要和重点地是我们要去进行无线监控应用系统项目中需要的一些相关的软件环境的设计。软件系统的系统设计开发通常来说是在要实现基于的一个嵌入式开发系统的Linux开发运行的环境平台基础上进行所要求实现的工作目标的,在要完成一个嵌入式系统Linux环境平台中的开机与启动系统及文件系统数据库等的硬件设计系统建立设计好系统后,接着的将会就是进行相关的设备软件与驱动系统设计及进行相关的应用程序环境的编写。其中所有的设备驱动程序代码都是带有Linux内核标准接口功能,应是在对其的每个接口模块代码编写中也都会重新进行了编写。本系统设计文档中的设备驱动程序的设备驱动程序框架是由使用一个基于Linux平台的内核文件所提供出来的字符设备驱动框架代码所来编写及实现完成的,将其所重新编写好完成的字符设备的驱动框架代码才会与该内核文件在一起进行被编译。
4.1.1字符设备驱动框架
(1)模块的注册/注销
当驱动模块成功注册完毕后Linux系统内核将会开始为其模块分配响应的地址空间,注册模块完成配置后,使用midprobe命令来加载驱动模块,使用rmmod函数来自动卸载被加载后卸载的驱动模块,modprob使用到的命令是由module_的init()系统所调用,rmmod是使用由module_的exit()系统调用。驱动程序通过这两个函数来管理驱动模块的注册与卸载。
(2)申请设备号
在Linux系统中,每个设备都会对应由设备号,当编写驱动程序时都必须先要想内核申请设备号。
(3)添加字符设备
在Linux系统中一切皆文件,通过内核提供的cdev_add函数向 Linux 系统添加字符设备。将设备抽象化为文件。
(4)创建节点
Linux下一切皆文件,我们使用的设备都会被抽象成驱动文件也就是所谓的节点。首先要创建一个 class 类,通过函数class_create注册节点类,再通过device_create创建字符设备。
4.1.2系统调用
系统调用是用户态到内核态的转换,是用户通过系统提供的API函数访问内核的唯一方式,从而访问相应的系统资源,其关系可通过下图简单描述:
图4-1 系统调用
内核提供了一系列的服务、资源、支持一系列功能,应用程序通过调用系统调用 API 函数来使用内核提供的服务、资源以及各种各样的功能。
驱动程序中通过file_operations结构体成员来实现应用程序中C库函数的调用,具体描述如下:
图4-2 C库调用
4.2移动端应用软件开发
移动端作为应用软件时是本应用系统中的一重要技术组成的部分,通过采集的传感器数据信息经计算机处理后直接上传数据至数据库阿里云后再自动流转数据传输至移动端,移动端会将传感器数据信息解析并显示出来并同步更新到数据库,这样也实现了温室环境信息实时的动态保存,并且绘制曲线图。移动端也可进行远程的阈值设定以及设备操控,实现手动或自动化以便调节大棚环境。
4.2.1应用软件开发工具及平台
(1)编程工具远程监控软件的开发编程工具主要选用了Qt,基本应用的主要编程语言都为C++。Qt开发具有着以下显而易见的突出优点:首先,Qt中集成使用了大量的UI控件,支持了ADO数据库与ODBC、QSLITE数据库等高级数据库交互访问等技术;其次,其自身具有一套强大高效的互联机帮助和文档系统,可以快速很方便的来进行各种帮助或信息资源的快速查询,如搜索某一个关键词或调用API函数。
(2)数据库选用的数据库系统都是嵌入式设计的轻量级的qslite数据库,该系列数据库开源免费、精简、占用数据库的运行内存相对也小。
(3)在硬件部分所选用到的设备是移远通信公司研制的EC204G模块,使用好该通讯模块后可以自动实现服务器与远程上位机设备的点对点通讯连接及远程短消息数据包的批量发送传输及接收。
4.2.2远程监控软件结果展示
(1)主界面
远程监控软件可通过手机随时查看大棚环境数据,并远程控制设备调节大棚环境。远程监控软件采用模块化设计,用户可根据查看内容点击相应模块进入查看,主界面如图:
图4-3 主界面
(2)数据监测界面
数据监测实时监测大棚环境数据,采样时间为1秒,当设备开启自动化,大棚环境超出阈值设定,设备端向移动端返回设备状态,由云消息记录,如图:
图4-4 数据检测界面
(3)数据分析界面
数据分析界面通过绘制曲线图来记录每日24小时的数据变量,并统计每日最高和最低的温湿度、CO2浓度、光照强度,通过图表可直观观察。
图4-5 数据分析界面
(4)设备控制界面
设备控制界面通过点击相应的设备图标即可开启/关闭设备,若设备开启/关闭成功,设备端会向移动端返回设备状态,有云消息记录。如图:
图4-6 设备控制界面
(5)阈值设定界面
移动端可远程设置阈值并同步到设备端,通过数据库保存,开启自动化后设备将通过阈值管理来实现设备自动化。当阈值设置成功,设备端会返回消息给移动端。由云消息记录设定时间。
图4-7 阈值设定界面
(6)其他功能界面
值班人员和地块管理以及植物百科通过qslite数据库管理,作为辅助性的功能,对大棚进行更细致化的管理和监控。如图:
图4-8 其他功能界面
5.核心代码
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package org.kde.necessitas.ministro;
public interface IMinistro extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements org.kde.necessitas.ministro.IMinistro
{
private static final java.lang.String DESCRIPTOR = "org.kde.necessitas.ministro.IMinistro";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an org.kde.necessitas.ministro.IMinistro interface,
* generating a proxy if needed.
*/
public static org.kde.necessitas.ministro.IMinistro asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof org.kde.necessitas.ministro.IMinistro))) {
return ((org.kde.necessitas.ministro.IMinistro)iin);
}
return new org.kde.necessitas.ministro.IMinistro.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_requestLoader:
{
data.enforceInterface(descriptor);
org.kde.necessitas.ministro.IMinistroCallback _arg0;
_arg0 = org.kde.necessitas.ministro.IMinistroCallback.Stub.asInterface(data.readStrongBinder());
android.os.Bundle _arg1;
if ((0!=data.readInt())) {
_arg1 = android.os.Bundle.CREATOR.createFromParcel(data);
}
else {
_arg1 = null;
}
this.requestLoader(_arg0, _arg1);
reply.writeNoException();
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements org.kde.necessitas.ministro.IMinistro
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
/**
* Check/download required libs to run the application
*
* param callback - interface used by Minsitro service to notify the client when the loader is ready
* param parameters
* parameters fields:
* * Key Name Key type Explanations
* "sources" StringArray Sources list from where Ministro will download the libs. Make sure you are using ONLY secure locations.
* "repository" String Overwrites the default Ministro repository. Possible values: default, stable, testing and unstable
* "required.modules" StringArray Required modules by your application
* "application.title" String Application name, used to show more informations to user
* "qt.provider" String Qt libs provider, currently only "necessitas" is supported.
* "minimum.ministro.api" Integer Minimum Ministro API level, used to check if Ministro service compatible with your application. Current API Level is 3 !
* "minimum.qt.version" Integer Minimim Qt version (e.g. 0x040800, which means Qt 4.8.0, check http://qt-project.org/doc/qt-4.8/qtglobal.html#QT_VERSION)!
*/
@Override public void requestLoader(org.kde.necessitas.ministro.IMinistroCallback callback, android.os.Bundle parameters) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((callback!=null))?(callback.asBinder()):(null)));
if ((parameters!=null)) {
_data.writeInt(1);
parameters.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_requestLoader, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_requestLoader = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
/**
* Check/download required libs to run the application
*
* param callback - interface used by Minsitro service to notify the client when the loader is ready
* param parameters
* parameters fields:
* * Key Name Key type Explanations
* "sources" StringArray Sources list from where Ministro will download the libs. Make sure you are using ONLY secure locations.
* "repository" String Overwrites the default Ministro repository. Possible values: default, stable, testing and unstable
* "required.modules" StringArray Required modules by your application
* "application.title" String Application name, used to show more informations to user
* "qt.provider" String Qt libs provider, currently only "necessitas" is supported.
* "minimum.ministro.api" Integer Minimum Ministro API level, used to check if Ministro service compatible with your application. Current API Level is 3 !
* "minimum.qt.version" Integer Minimim Qt version (e.g. 0x040800, which means Qt 4.8.0, check http://qt-project.org/doc/qt-4.8/qtglobal.html#QT_VERSION)!
*/
public void requestLoader(org.kde.necessitas.ministro.IMinistroCallback callback, android.os.Bundle parameters) throws android.os.RemoteException;
}
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package org.qtproject.example.untitled;
public final class R {
public static final class array {
public static final int bundled_libs=0x7f010000;
public static final int load_local_libs=0x7f010001;
public static final int qt_libs=0x7f010002;
public static final int qt_sources=0x7f010003;
}
public static final class layout {
public static final int splash=0x7f020000;
}
public static final class string {
public static final int fatal_error_msg=0x7f030000;
public static final int ministro_needed_msg=0x7f030001;
public static final int ministro_not_found_msg=0x7f030002;
public static final int unsupported_android_version=0x7f030003;
}
}
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"android-build-debug.apk","fullName":"debug","baseName":"debug"},"path":"android-build-debug.apk","properties":{}}]
[{"outputType":{"type":"MERGED_MANIFESTS"},"apkData":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"android-build-debug.apk","fullName":"debug","baseName":"debug"},"path":"AndroidManifest.xml","properties":{"packageId":"org.qtproject.example.untitled","split":"","minSdkVersion":"21"}}]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.qtproject.example.untitled"
android:installLocation="auto"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="21"
android:targetSdkVersion="28" />
<!--
The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
Remove the comment if you do not require these default permissions.
-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--
The following comment will be replaced upon deployment with default features based on the dependencies of the application.
Remove the comment if you do not require these default features.
-->
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true" />
<application
android:name="org.qtproject.qt5.android.bindings.QtApplication"
android:debuggable="true"
android:extractNativeLibs="true"
android:hardwareAccelerated="true"
android:label="untitled" >
<activity
android:name="org.qtproject.qt5.android.bindings.QtActivity"
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
android:label="untitled"
android:launchMode="singleTop"
android:screenOrientation="unspecified" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Application arguments -->
<!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
<!-- Application arguments -->
<meta-data
android:name="android.app.lib_name"
android:value="untitled" />
<meta-data
android:name="android.app.qt_sources_resource_id"
android:resource="@array/qt_sources" />
<meta-data
android:name="android.app.repository"
android:value="default" />
<meta-data
android:name="android.app.qt_libs_resource_id"
android:resource="@array/qt_libs" />
<meta-data
android:name="android.app.bundled_libs_resource_id"
android:resource="@array/bundled_libs" />
<!-- Deploy Qt libs as part of package -->
<meta-data
android:name="android.app.bundle_local_qt_libs"
android:value="1" />
<!-- Run with local libs -->
<meta-data
android:name="android.app.use_local_qt_libs"
android:value="1" />
<meta-data
android:name="android.app.libs_prefix"
android:value="/data/local/tmp/qt/" />
<meta-data
android:name="android.app.load_local_libs_resource_id"
android:resource="@array/load_local_libs" />
<meta-data
android:name="android.app.load_local_jars"
android:value="jar/QtAndroid.jar:jar/QtAndroidBearer.jar" />
<meta-data
android:name="android.app.static_init_classes"
android:value="" />
<!-- Used to specify custom system library path to run with local system libs -->
<!-- <meta-data android:name="android.app.system_libs_prefix" android:value="/system/lib/"/> -->
<!-- Messages maps -->
<meta-data
android:name="android.app.ministro_not_found_msg"
android:value="@string/ministro_not_found_msg" />
<meta-data
android:name="android.app.ministro_needed_msg"
android:value="@string/ministro_needed_msg" />
<meta-data
android:name="android.app.fatal_error_msg"
android:value="@string/fatal_error_msg" />
<meta-data
android:name="android.app.unsupported_android_version"
android:value="@string/unsupported_android_version" />
<!-- Messages maps -->
<!-- Splash screen -->
<!--
Orientation-specific (portrait/landscape) data is checked first. If not available for current orientation,
then android.app.splash_screen_drawable. For best results, use together with splash_screen_sticky and
use hideSplashScreen() with a fade-out animation from Qt Android Extras to hide the splash screen when you
are done populating your window with content.
-->
<!-- meta-data android:name="android.app.splash_screen_drawable_portrait" android:resource="@drawable/logo_portrait" / -->
<!-- meta-data android:name="android.app.splash_screen_drawable_landscape" android:resource="@drawable/logo_landscape" / -->
<!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
<!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
<!-- Splash screen -->
<!-- Background running -->
<!--
Warning: changing this value to true may cause unexpected crashes if the
application still try to draw after
"applicationStateChanged(Qt::ApplicationSuspended)"
signal is sent!
-->
<meta-data
android:name="android.app.background_running"
android:value="false" />
<!-- Background running -->
<!-- auto screen scale factor -->
<meta-data
android:name="android.app.auto_screen_scale_factor"
android:value="false" />
<!-- auto screen scale factor -->
<!-- extract android style -->
<!--
available android:values :
* default - In most cases this will be the same as "full", but it can also be something else if needed, e.g., for compatibility reasons
* full - useful QWidget & Quick Controls 1 apps
* minimal - useful for Quick Controls 2 apps, it is much faster than "full"
* none - useful for apps that don't use any of the above Qt modules
-->
<meta-data
android:name="android.app.extract_android_style"
android:value="default" />
<!-- extract android style -->
</activity>
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
</application>
</manifest>
6.参考论文
目录
7.总结
随着优化设施农业大棚温室环境,智能温室系统监控设备及设备管理将是今后世界上其他很多相关国家共同的重点研究与热点。本项课题主要基于最新ARM微处理器和4G技术设计研发了新一代智能温室环境监控设备系统。该系统已经摆脱掉了过去传统的现场总线技术。采用上了当今先进的无线射频技术,更能够适合我国现代设施农业生产的新发展。而且通过4G技术,摆脱了设备应用于偏远山区和复杂环境的限制。
论文主要研究结果如下:
(1)本章详细讨论分析探讨了针对当前我国农业温室大棚系统的运行的实际监控应用情况,温室大棚控制系统的基本软硬件需求、功能指标选择以及控制系统总体功能设计特点等,通过对国际当前最为流行应用的嵌入式操作系统分析比较,选择了嵌入式或Linux等操作系统作为实现本应用系统目标的主流操作系统。
(2)软、硬件选型,软件方面包括u盘-boot、Linux系统内核和根目录文件系统、Qt移动端应用开发。硬件方面要选择一款适合无线监控设备使用的开发板,实现无线移动通信功能的4G模块以及传感器。
(3)成功搭建嵌入式开发平台,介绍u-boot的移植、内核的移植与启动过程、构建根文件系统。
(4)设备控制端通过使用Linux操作系统内核中提供的字符设备驱动框架来编写一套相应版本的字符设备驱动,为上层的应用程序提供一个接口函数,应用程序能够通过此接口函数自动读取传感器数据并可以通过4G技术直接将传感器数据自动上传至阿里云。
(5)移动端成功完成了对数据的远程监控,实现数据库的建立;实现远程手动或自动管理设备,实现对数据查询和曲线显示。
本系统实现了温室远程信息采集、查询、统计及图表、设备自动化控制等操作。更强大的功能还有待完善。
喜欢的点赞收藏加关注私信作者沟通交流