9332| 12
|
Intel IoT 物联网大赛 - Zoo团队- 智能灌溉系统 |
hi,Everybody,不好意思,来晚了,但是今天还没有过去不是?就当做一个睡前的故事看看吧。 我们这次组团参加了蘑菇云与Innospace还有intel一起举办的一场基于Edison开发板的物联网大赛,结局是没有得到奖,不过没有关系,还是很开心的,兔子(队长),MKK(孙坚,主力外形设计师和实施工程师,土木工程师还有机械电子工程师,还有杨栋,正觉,skip,金立彦,box,王工,我们的队伍阵营还是很强大的,就是大家第一天都不知道做什么好,大家商量了好久。。。直到第二天上午早饭后,我们决定做一个智能灌溉系统。 智能灌溉系统???WTF? 我从来没有种过花花草草,你让我做灌溉系统?农业系统?期初我的内心是纠结的,是无奈的,可惜我看到那些SEEED套件的传感器后,觉得能做花花草草的灌溉系统已经是很奢侈的事情了。幸亏有DFrobot的套件撑场面。。。好吧,这不是广告。 无意中看了一眼时钟,23:34了,距离今天过去还有二十几分钟了,还是进入主题吧。 智能灌溉系统主要是想解决有的同志在家养花养草,忘记浇水导致花儿就这么早谢了。。;P。又TM跑题了,言归正传! 这个灌溉系统分为这么几个部分: 1. 数据采集传感器: 土壤干湿度传感器(DF套件里有) 2. 继电器(MKK的拿手绝活) 继电器,我们称之为Relay,就是允许通过低电平的电平信号来控制的开关模块,例如,你想用Arduino控制家里的点灯,arduino的引脚是低电平的,而家里是220V的致死电压,那么用继电器就很安全了。。。 3. 不知道怎么称呼:水泵? 蠕动泵?离心泵? 反正是一个马达带着转,能够泵水的装置,建议用养鱼的潜水泵,更加静音,这个泵跑起来和你的小赛车的噪音差不多。。。 4. 最后的大杀(keng)器(die)出现了! 就是Edison 开发板。说实话,很多人说edison是个坑爹货,说Yocto linux发行版各种坑,我觉得,其实也不是那么坑,其实基于linux内核的发行版里面,Edison的这块板子还是很不错的,至少wifi的稳定性,还有系统本身的稳定性都还是可圈可点的,比起香蕉派(bananaPi)这个坑爹板来说,好了不知道多少倍了! 另外,我太喜欢Edison上面跑OpenCV了,速度稳定而暴力,各种稳定没得说,好吧,最后还是觉得我的树莓派更好! 5.一个盛水的饭盒。。。饭盒。。。饭盒。。。我的队友们,你TMD在逗我?这么牛逼的比赛你给我带两个乐扣乐扣盒子做产品????我也是醉了。。。当我看到乐扣盒子的时候,我就知道我们肯定败了。。。因为评委里面有个搞艺术的Rex啊!你们~~哎。。。。 6. 还有一个非常非常关键的部件: 就是DF的I/O扩展板,没有它,基本啥都做不了了,有了这块扩展板,接驳设备也就15秒。 是不是已经看不下去了?哈哈,干货在此! 我们的创意思路是: 土壤干湿度传感器在花盆里面感受湿度的变化,据MKK的不完全统计,这个值的变化区间是在0~3000之间发生变化,当0出现的时候,就是水漫金山了,许仙哥你今天湿了没有?当3000的时候,干燥的土壤就开始”要你命三千了“,然后不是说要上云端么?不上云端怎么体现物联网?联网?联网? 好的,联网传什么数据呢? 当然在颜值统治世界的今天,自拍图片才是王道。所以就有了如下的技术硬植入: 1. Smartnode 对接微信端控制(1小时速成) 网址:www.smartnode.io 你值得拥有。 2. 阿里云端的一个存储照片的地方,这里是我的个人博客的后台,也是用wordpress搭建的一个小站。存储照片的后端用python的tornado模块实现了图片上传。地址:www.yoyojacky.com:9002 3. OpenCV 拍照并通过Edison本地的第一个shell脚本上传代码到我的个人博客后台的一个storage目录,并通过html页面展示出来,就这么简单。 上一张调试过程中的图片: 这里在测试照片的效果。 然后,我们开放了源码: 代码虽然很多bug,但是相信你们可以改得更好。。。 Github地址: https://github.com/yoyojacky/Edisoniot 上面的内容为smartnode上面的拖拽连线图,很像mind+的那种方式,非常简单方便。推荐初学者用起来,很赞! 首先,你得有一盆不怕水的植物,这个是兔子不知道从哪里找来的不怕水的水草,因为无数测试,它早已湿透。。 结构非常简单,两个乐扣饭盒,一块压合板,然后几根螺丝钉,加上一个土壤传感器,一个离心泵,两根4mm水管,一个Edison开发板,一个DF I/O扩展板,接上电源,然后就可以进行浇花行动了。基本上,一般的小白喜欢看的就是我上面写的这些,大牛工程师们可能要看细节了。好吧,先展示一下我们队友给你们看看。然后上代码。 ——++——————+++——+++——————+++————————+++——————————————+++—————————— 代码开始: C语言Opencv抓图代码: [mw_shl_code=cpp,true]#include <stdio.h> #include <iostream> #include "opencv2/opencv.hpp" #include "opencv2/core/core.hpp" #include "opencv2/video/background_segm.hpp" #include "opencv2/imgproc/imgproc_c.h" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/legacy/legacy.hpp" #include "opencv2/video/tracking.hpp" #include "opencv2/photo/photo.hpp" using namespace std; extern "C" void take_photo(char *str); void take_photo(char *str) { IplImage *frame = NULL; int num = 0; int key; CvCapture *input_camera = cvCaptureFromCAM(0); frame = cvQueryFrame(input_camera); while(frame != NULL) { num++; / frame = cvQueryFrame(input_camera); if(num == 20) { cvSaveImage(str,frame); break; } } cvReleaseCapture(&input_camera); }[/mw_shl_code] +++++++++++++++++++++++++++++++++++ 然后是main.c [mw_shl_code=c,true]#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <mraa/gpio.h> int sensor_state = 0; void *take_photo_thread (void *args){ for(;;){ if(sensor_state >= 500 ){ char str[25]; sprintf(str,"%d.jpg",(int) time((time_t*)NULL)); take_photo(str); sleep (1); char command[100]; sprintf (command, "upload.sh %s", str); system (command); } sleep(1); } } int main(int argc, char** argv) { mraa_gpio_context sensor_gpio = NULL; sensor_gpio = mraa_gpio_init(5); if (sensor_gpio == NULL) { fprintf(stdout, "Could not initilaize sensor_gpio\n"); return 1; } mraa_gpio_dir(sensor_gpio, MRAA_GPIO_IN); pthread_t t; pthread_create(&t,NULL,take_photo_thread,NULL); for (;;) { if( sensor_state != mraa_gpio_read(sensor_gpio)) { sensor_state = !sensor_state; printf("%d\n",sensor_state); sleep(1); } } return 0; }[/mw_shl_code] 代码非常简单,基本都是例程,大牛不要吐槽哈!下面是Makefile,随意取用。☺️ [mw_shl_code=c,true]GCC_MRAA_FLAG=-lmraa -lpthread GXX_OPENCV_FLAG=-lopencv_core -lopencv_highgui -lopencv_video -lopencv_calib3d -lopencv_contrib -lopencv_stitching -lopencv_superres -lopencv_legacy -lopencv_nonfree -lopencv_videostab -lopencv_gpu -lopencv_photo -lopencv_flann -lopencv_features2d -lopencv_ml -lopencv_imgproc -lopencv_objdetect build: main.o mycam.o gcc main.o mycam.o -lstdc++ $(GXX_OPENCV_FLAG) $(GCC_MRAA_FLAG) -o main run: build ./main main.o: main.c gcc -c $(GCC_MRAA_FLAG) main.c mycam.o: mycam.cpp g++ -c $(GXX_OPENCV_FLAG) mycam.cpp clean: -rm main *~ *.o *.png[/mw_shl_code] 往服务器上上传的代码: [mw_shl_code=bash,true] #!/bin/bash for i in `ls *.png |xargs` do curl -sT $i http://www.yoyojacky.com:9001 sleep 1 if [ $? -eq 0 ];then rm -rf $i else echo "upload failue." fi done[/mw_shl_code] 简单粗暴~~~哈哈 然后服务器端的配置,就要安装改centos的源,然后安装nginx,然后安装python 的pip,更新pip,然后安装python进程管理工具supervisor还有web框架tornado,tornado的东西可以问问夏力维,小伙子python还是很牛逼的。哈哈 另外,这里发放一个干货,就是陈昊兄弟在开放夜问的问题,如何在Edison上让程序开机自动运行。 这里说一下linux启动过程,以下内容来自:http://blog.chinaunix.net/uid-26495963-id-3066282.html ,chinaUnix,学习linux或者unix在这里没错。 启动第一步--加载BIOS 当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它。这是因为BIOS中包含了CPU的相关信息、设备启动顺序信息、硬盘信息、内存信息、时钟信息、PnP特性等等。在此之后,计算机心里就有谱了,知道应该去读取哪个硬件设备了。 启动第二步--读取MBR 众所周知,硬盘上第0磁道第一个扇区被称为MBR,也就是Master Boot Record,即主引导记录,它的大小是512字节,别看地方不大,可里面却存放了预启动信息、分区表信息。 系统找到BIOS所指定的硬盘的MBR后,就会将其复制到0×7c00地址所在的物理内存中。其实被复制到物理内存的内容就是Boot Loader,而具体到你的电脑,那就是lilo或者grub了。 启动第三步--Boot Loader Boot Loader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核做好一切准备。 Boot Loader有若干种,其中Grub、Lilo和spfdisk是常见的Loader。 我们以Grub为例来讲解吧,毕竟用lilo和spfdisk的人并不多。 系统读取内存中的grub配置信息(一般为menu.lst或grub.lst),并依照此配置信息来启动不同的操作系统。 启动第四步--加载内核 根据grub设定的内核映像所在路径,系统读取内存映像,并进行解压缩操作。此时,屏幕一般会输出“Uncompressing Linux”的提示。当解压缩内核完成后,屏幕输出“OK, booting the kernel”。 系统将解压后的内核放置在内存之中,并调用start_kernel()函数来启动一系列的初始化函数并初始化各种设备,完成Linux核心环境的建立。至此,Linux内核已经建立起来了,基于Linux的程序应该可以正常运行了。 启动第五步--用户层init依据inittab文件来设定运行等级 内核被加载后,第一个运行的程序便是/sbin/init,该文件会读取/etc/inittab文件,并依据此文件来进行初始化工作。 其实/etc/inittab文件最主要的作用就是设定Linux的运行等级,其设定形式是“:id:5:initdefault:”,这就表明Linux需要运行在等级5上。Linux的运行等级设定如下: 0:关机 1:单用户模式 2:无网络支持的多用户模式 3:有网络支持的多用户模式 4:保留,未使用 5:有网络支持有X-Window支持的多用户模式 6:重新引导系统,即重启 关于/etc/inittab文件的学问,其实还有很多 启动第六步--init进程执行rc.sysinit 在设定了运行等级后,Linux系统执行的第一个用户层文件就是/etc/rc.d/rc.sysinit脚本程序,它做的工作非常多,包括设定PATH、设定网络配置(/etc/sysconfig/network)、启动swap分区、设定/proc等等。如果你有兴趣,可以到/etc/rc.d中查看一下rc.sysinit文件,里面的脚本够你看几天的 启动第七步--启动内核模块 具体是依据/etc/modules.conf文件或/etc/modules.d目录下的文件来装载内核模块。 启动第八步--执行不同运行级别的脚本程序 根据运行级别的不同,系统会运行rc0.d到rc6.d中的相应的脚本程序,来完成相应的初始化工作和启动相应的服务。 启动第九步--执行/etc/rc.d/rc.local 你如果打开了此文件,里面有一句话,读过之后,你就会对此命令的作用一目了然: # This script will be executed *after* all the other init scripts. # You can put your own initialization stuff in here if you don’t # want to do the full Sys V style init stuff. rc.local就是在一切初始化工作后,Linux留给用户进行个性化的地方。你可以把你想设置和启动的东西放到这里。 启动第十步--执行/bin/login程序,进入登录状态 此时,系统已经进入到了等待用户输入username和password的时候了,你已经可以用自己的帐号登入系统了。:) === 漫长的启动过程结束了,一切都清静了… ==================== 好,轮到我来了,那么到这里,大家已经应该知道了kernel加载完成后,启动系统调用的第一个程序就是init,也就是为什么我们linux上关机可以用init 0, 重启可以用init 6 如果你用C写了一个二进制文件,或者用shell,python等脚本语言写了脚本,那么就放在/etc/init.d/目录下面,命名成你想要的名称即可,我的upload.sh 我可以放入/etc/init.d/upload 这里不用加后缀也可以,因为在linux环境下,后缀名称就是为了方便照顾windows用户的习惯,我们其实可以不用扩展名的。 这里注意,注意,注意一下,你们说的Edison的坑来了。 先前的edison 的yocto版本1.6 里面,在/etc 里没有init.d 文件夹,自己创建一个就好,用mkdir -p /etc/init.d ,而最新的yocto 版本 1.6.1里面是含有 init.d 文件的,不知道的就找不到了吧?) :Q 我的upload中的内容: [mw_shl_code=bash,true]#!/bin/bash for i in `ls *.png |xargs` do curl -sT $i http://www.yoyojacky.com:9001 sleep 1 if [ $? -eq 0 ];then rm -rf $i else echo "upload failue." fi done[/mw_shl_code] 记住要赋予可执行的权限 chmod +x /etc/init.d/upload 在 /etc/init.d 文件夹下执行 update-rc.d upload defaults 95 (启动顺序95) 然后开机就会自动启动了。是不是非常简单? 然后要删除开机自动启动就执行: update-rc.d -f upload remove +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 好了,到此我的帖子也结束了,我是骑驴玩儿漂移,一个专注技术和开源硬件的胖纸,欢迎大家拍砖灌水! 有机会去蘑菇云分享树莓派的心得,谢谢大家! 感谢蘑菇云提供我这个机会在此絮叨我们的项目,也感谢我的团队伙伴们,没有因为我的技术low,代码烂而抛弃我,义无反顾的收留了我。 感谢CCTV,一直没有给我称为网红的机会,感谢@juice,@ash 以及所有创客朋友们给我带来的启发和激励~ :lol 个人技术博客: http://www.yoyojacky.com/ 欢迎互粉哈!晚安~ |
© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed