24478浏览
查看: 24478|回复: 18

懒人养鱼之-自动鱼缸

[复制链接]
起因    一年前玩过一个小鱼缸,不过因为太小, 而且懒于换水, 没多久就放弃了; 后来一直想做点什么在家里可以玩儿的, 恰巧在DFRobot社区见到有人做了个懒人养鱼的换水系统(原文<爱小鱼又养不活?——懒人必试自动换水系统>), 于是下决心也整一个, 但不同的是这次准备玩儿大的, 整个大一点的鱼缸.
   鱼缸要大代价就高, 就不能随便整, 所以去泡了几天养鱼的坛子, 发现大鱼缸比小鱼缸复杂多了. 先是分淡水缸和海缸, 然后按过滤系统分: 上滤/侧滤/底滤.
   因好奇看了一下海缸, 不看不知道, 一看吓一跳! 海缸固然观赏价值极高(可以养珊瑚, 养海鱼, 想想都爽), 但其过程不但开缸极其复杂, 而且开缸成功后, 整个海水循环系统十分昂贵和复杂, 于是放弃.
   既然做不了海缸, 就淡水缸吧. 然后考虑过滤系统, 简单说一下其中两种过滤系统的优劣:

上部过滤:
    上部循环过滤是放在水族箱上面,整个过滤槽露在水族箱的外面,通过潜水泵将水抽出进入过滤槽,再由过滤槽底部的出水管流回到水族箱内,在过滤槽内可以放置过滤棉、活性炭、生化石等。上部过滤器的最大优点是清洗方便,在过滤材料污染时,可以很方便地取出进行清洗。最大的缺点是体积比较大,占的空间也相对要大。停电时滤材也不会因泡在水中而缺氧使菌群大量死亡.滤材内的硝化菌在停电后还可以存活很长的时间.
缺点:
    噪音 - 流水声更是必须忍受的
    过滤槽清洁较麻烦
    扬水马达及滴水区与下水口会有声音,有些马达比较吵,滴水声对于浅眠的人来说是一大困扰
    上部过滤所佔面积大,影响其他设备的摆放
    破坏美观

底部过滤 :
懒人养鱼之-自动鱼缸图1

(因本次采用的是底滤, 所以配上图说明, 借用养鱼坛子的一张图)
    适合大缸子,水草缸除外
    由沉/卧水马达在底下将水吸起利用水压力把水抽上去主缸,主缸水满了之后溢流回去底缸就这样一直循环一直循环,这种溢流设计可以将缸底下的排泄物给清除.通常都用木柜/铁架包门 - 底部看起来较为美观
    如设计上无误,换水也方便,拥有极为可观的滤材容量, 培养硝化菌极多,主缸整体看起来会很清爽
缺点:
    因需多个底滤缸,滤材,价格挺昂贵
    不适合铺底沙,如设计不当,会有流水噪音
    过滤槽难清洁整理


综合考虑, 既然搞大了, 那就直接整个美观大方的, 而且底滤系统因底部有柜子, 方便布置咱的智能设备, 只要把线和设备整理好, 鱼缸外观看起来观赏价值高.

先上两张鱼缸图
懒人养鱼之-自动鱼缸图2

懒人养鱼之-自动鱼缸图3



思路
    既然是懒人鱼缸, 所以需要的功能设计如下:
- 自动换水 (本设计的宗旨就是这货)
- 自动浇花 (排出的水不用就浪费了, 拿来浇花杠杠滴)
- 自动打氧 (全天24X7开启本人觉得没必要, 所以要改成定时开一阵子即可)
- 观赏LED灯,人来自动开, 人走演示自动关
    以上功能原本用一个普通的Arduino UNO就能做到, 不过后来考虑到联网及易于随时控制, 随时改程序, 随时在电脑上观察各种配件工作情况, 以及远程控制等等拓展功能, 于是采用了功能更为强大的树莓派.懒人养鱼之-自动鱼缸图13
(先上一张控制树莓派的装X图)

准备材料
- 1.2米大鱼缸一枚(带底滤系统)
- 树莓派 B+版
- 四路带光耦继电器
- 人体红外热释电运动传感器
- 鱼缸抽水泵X2 (1只注水, 1只排水)
- 鱼缸打氧机
- 鱼缸加热棒
- 家庭滴灌套装滴灌设备2100
- 注水用的储水罐(20升以上)一只
- 2-3孔插线板1只
- 小型开关电源(输入220V, 输出12V3A)
- 20P接线端子, 5孔电线连接器, 3孔电线连接器等
- PowerCube带USB魔方插座
- 多种Size的牛筋管若干
- 2芯0.5平线, 4芯0.3平线若干; 包线管若干
- 4分走线管及弯头/三通头若干
- 3D打印

设计图
- 电图设计
懒人养鱼之-自动鱼缸图4


制作过程
    过程中用到3D打印的有几个地方:
   1. 人体红外热释电运动传感器, 因是唯一要放置在鱼缸外部的元件, 所以需要制作一个盒子来放它. 刚开始是用黑色材料打印,效果如下
懒人养鱼之-自动鱼缸图5


后来发现厚度设计有误, 修改了一下, 换了绿色打印, 效果如下,
懒人养鱼之-自动鱼缸图30
懒人养鱼之-自动鱼缸图6

装好后:
懒人养鱼之-自动鱼缸图7


    2. 树莓派和继电器放在底柜中, 需要有个盒子或支架放置, 初步设计为挂在底缸旁边
懒人养鱼之-自动鱼缸图31
懒人养鱼之-自动鱼缸图8

继电器底座
懒人养鱼之-自动鱼缸图9

固定支架(螺丝位设计了一些凹槽, 用于预防水从缸里渗出时, 从凹槽流走, 防止流到电路板上造成短路)

懒人养鱼之-自动鱼缸图10

安装好两层的效果图

懒人养鱼之-自动鱼缸图11
安装效果图


懒人养鱼之-自动鱼缸图12
安装到底缸实际效果.


    3. 设备接线(见前面的电路设计图)
      3.1 首先全部设备需经过20P的接线端子进入主线路, 使用接线端子是考虑到以后设备更换方便, 接线设计:
     1 - 220V(零线) 1号线(蓝) 220V共用零线(不知有没问题,请高人指点)
K3 2 - 220V(火线) 1号线(灰) 注水
K2 3 - 220V(火线) 2号线(蓝) 氧气
     4 - 220V(火线) 2号线(蓝) 热棒
K4 5 - 12V  (负极) 3号线(红) LED
K4 6 - 12V  (正极) 3号线(绿) LED
K1 7 - 220V  (零线) 3号线(黄) 排水
K1 8 - 220V  (火线) 3号线(黑) 排水
     9 - 5V    (负极) 4号线(黑)
     10 - 5V  (正极) 4号线(红)
     11 - Data 4号线(绿) 人体
     12 - Data 4号线(绿) 预留
     13 - Data 7号线(红) 预留
     14 - Data 7号线(绿) 预留
     15 - Data 7号线(黄) 预留
     16 - Data 7号线(黑) 预留
     17 - 220V(零线) 5号线(蓝) 预留
     18 - 220V(火线) 5号线(灰) 预留
     19 - 220V(火线) 6号线(蓝) 预留
     20 - 220V(火线) 6号线(灰) 预留

懒人养鱼之-自动鱼缸图14

(先接主线路, 主线路经过走线管, 这样看起来整洁些,也在一定程度上防水)

懒人养鱼之-自动鱼缸图15

再接外部设备, 从上到下按顺序依次是注水水泵,氧气,热棒,LED,排水水泵;再下来是5V(主线引到树莓派上)和人体红外传感器信号线), 12-20号脚预留(以后备用)

懒人养鱼之-自动鱼缸图16

20P接线完成后, 在底滤中部找个位置固定开关电源



懒人养鱼之-自动鱼缸图17

设置开关电源的背面还有空间, 用来固定220V电源(输入)插座, 并配了一个PowerCube魔方插座(4面有3脚插座,而且省空间),这里需要供电给:底滤水泵(24X7常开), 开关电源, 树莓派(USB)


懒人养鱼之-自动鱼缸图19

回过头继续接主线路的另一端, 220V的全部接上, 并从开关电源引出12V接给LED灯; 接在继电器上的设备主要是(注水水泵/排水水泵/打氧机/LED观赏灯), 这些通过4PIN的公母接头与继电器相连(不直接焊接是为了方便维修)

懒人养鱼之-自动鱼缸图18

与树莓派下方的继电器接上, 线上标识好继电器方便识别


排水->浇花(见后面的视频)

注水(从储水罐中抽水注入鱼缸中) (见后面的视频)


懒人养鱼之-自动鱼缸图22
懒人养鱼之-自动鱼缸图23

懒人养鱼之-自动鱼缸图20

懒人养鱼之-自动鱼缸图21
内部处理好后, 外部由排水泵引出水管接到滴灌设备上,这是滴灌时的效果. 还不错


    4.继电器与树莓派接线
继电器                树莓派
5V                        5V
GND                        GND
K1                        GPIO_03                排水浇花水泵
K2                        GPIO_04                氧气
K3                        GPIO_05                LED观赏灯
K4                        GPIO_06                注水水泵



    5.树莓派准备工作
      - 准备系统(本例中采用的是原生的树莓派Linux系统)
        > 下载系统安装包>>>>GO
        > 具体安装方法
        > 第一次启动系统, 详细配置过程
      - 安装配置支持库
        > 安装Wiring Pi支持库
        > 同步时钟(用于定时器)
        > 安装pi4j java支持环境(让Java可以访问IO口)
      - 无线网络配置及准备
        > 此处如果希望树莓派能通过Wifi方式联网, 需要购置USB无线网卡,并配置; 否则用网线即可


程序(Java版本)
  1. /**
  2. * 智能鱼缸主程序
  3. * 功能设计要点:
  4. *                 - 人体红外传感器.                                GPIO_02
  5. *                 - 自动排水.水泵.1号继电器.                GPIO_03
  6. *                 - 氧气控制.3号继电器.                        GPIO_04
  7. *                 - LED控制.4号继电器(人来开灯).        GPIO_05
  8. *                 - 自动注水.水泵.2号继电器.                GPIO_06
  9. * @author Penny
  10. *
  11. */
  12. public class Fish {
  13.     private static boolean isAct = false;
  14.     private static long pin05_on_time = 0;
  15.    
  16.         public static void main(String[] args) throws InterruptedException{
  17.                 System.out.println("Fish program is running...");
  18.         final GpioController gpio = GpioFactory.getInstance();
  19.         final GpioPinDigitalInput hasPerson = gpio.provisionDigitalInputPin(RaspiPin.GPIO_02, PinPullResistance.PULL_DOWN);
  20.         final GpioPinDigitalOutput pin03 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_03, "MyRELAY_injection", PinState.HIGH);//排水,此继电器高电平表示OFF
  21.         pin03.setShutdownOptions(true, PinState.LOW);
  22.         final GpioPinDigitalOutput pin04 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_04, "MyRELAY_oxygen", PinState.HIGH);        //氧气
  23.         pin04.setShutdownOptions(true, PinState.LOW);
  24.         final GpioPinDigitalOutput pin05 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_05, "MyRELAY_led", PinState.HIGH);                //LED灯
  25.         pin05.setShutdownOptions(true, PinState.LOW);
  26.         final GpioPinDigitalOutput pin06 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_06, "MyRELAY_drain", PinState.HIGH);        //注水
  27.         pin06.setShutdownOptions(true, PinState.LOW);
  28.                
  29.         long pin06_on_time = 0;                //注水
  30.         long pin03_on_time = 0;
  31.         long pin04_on_time = 0;
  32.         String[] oxygenTimes = FishConfig._TRIGGE_G04_TIME.split(",");                //每日打氧气可设多个时间段,以","分隔
  33.         
  34.         hasPerson.addListener(new GpioPinListenerDigital() {
  35.             public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
  36.                     if(FishConfig._DEBUG)System.out.println(" --> GPIO PIN STATE CHANGE: " + event.getPin() + " = " + event.getState());
  37.                 if(event.getState().isHigh()){
  38.                         isAct=true;
  39.                         pin05_on_time=(new Date()).getTime();                //更新时间点
  40.                         if(FishConfig._DEBUG)System.out.println("update pin05_on_time.");
  41.                 }else{ isAct=false;}
  42.             }
  43.         });
  44.         
  45.                 while(true){
  46.                         String nowTime = new SimpleDateFormat("HH:mm").format(new Date());
  47.                 int t06 = DateCompare(nowTime, FishConfig._TRIGGE_G06_TIME, "HH:mm");
  48.                 int t03 = DateCompare(nowTime, FishConfig._TRIGGE_G03_TIME, "HH:mm");
  49.                
  50.                         //注水
  51.                         if(t06==0){
  52.                                 if(pin06.getState().isHigh()){
  53.                                         pin06.low();        //低电平接通
  54.                                         pin06_on_time=(new Date()).getTime();                //开启时间节点
  55.                                         System.out.println("--> in water: ON..."+pin06_on_time);
  56.                                         Common.recordLogs(new StringBuffer(new Date()+"--> in water: ON..."+pin06_on_time+"\r\n"), FishConfig.LOGFILE);
  57.                                 }System.out.print(".");
  58.                         }
  59.                         if((((new Date()).getTime()-pin06_on_time)/1000/60)>=FishConfig._TRIGGE_G06_TIME_DELAY){
  60.                                 if(pin06.getState().isLow()){
  61.                                         pin06.high();
  62.                                         System.out.println("--> in water: OFF...");
  63.                                         Common.recordLogs(new StringBuffer(new Date()+"--> in water: OFF..."+pin06_on_time+"\r\n"), FishConfig.LOGFILE);
  64.                                 }
  65.                 }
  66.                         //排水/浇花
  67.                         if(t03==0){
  68.                                 if(pin03.getState().isHigh()){
  69.                                         pin03.low();        //低电平接通
  70.                                         pin03_on_time=(new Date()).getTime();                //开启时间节点
  71.                                         System.out.println("--> out water: ON..."+pin03_on_time);
  72.                                         Common.recordLogs(new StringBuffer(new Date()+"--> out water: ON..."+pin03_on_time+"\r\n"), FishConfig.LOGFILE);
  73.                                 }if(FishConfig._DEBUG)System.out.print(".");
  74.                         }
  75.                         if((((new Date()).getTime()-pin03_on_time)/1000/60)>=FishConfig._TRIGGE_G03_TIME_DELAY){
  76.                                 if(pin03.getState().isLow()){
  77.                                         pin03.high();
  78.                                         System.out.println("--> out water: OFF...");
  79.                                         Common.recordLogs(new StringBuffer(new Date()+"--> out water: OFF..."+"\r\n"), FishConfig.LOGFILE);
  80.                                 }
  81.                 }
  82.                         
  83.                         //打氧气,维持1分钟
  84.                         boolean doOxygen = false;                //是否需要加氧气
  85.                         for(String g04time : oxygenTimes){
  86.                                 int t04 = DateCompare(nowTime, g04time, "HH:mm");
  87.                                 if(t04==0){doOxygen=true;break;}        //需要加氧气
  88.                         }
  89.                         if(doOxygen){
  90.                                 if(pin04.getState().isHigh()){
  91.                                         pin04.low();        //低电平接通
  92.                                         pin04_on_time=(new Date()).getTime();                //开启时间节点
  93.                                         System.out.println("--> oxygen: ON..."+pin04_on_time);
  94.                                         Common.recordLogs(new StringBuffer(new Date()+"--> oxygen: ON..."+pin04_on_time+"\r\n"), FishConfig.LOGFILE);
  95.                                 }if(FishConfig._DEBUG)System.out.print(".");
  96.                         }
  97.                         if((((new Date()).getTime()-pin04_on_time)/1000/60)>=FishConfig._TRIGGE_G04_TIME_DELAY){
  98.                                 if(pin04.getState().isLow()){
  99.                                         pin04.high();
  100.                                         System.out.println("--> oxygen: OFF...");
  101.                                         Common.recordLogs(new StringBuffer(new Date()+"--> oxygen: OFF..."+"\r\n"), FishConfig.LOGFILE);
  102.                                 }
  103.                 }
  104.                         //开LED,维持X分钟
  105.                         if(isAct){
  106.                                 if(pin05.getState().isHigh()){
  107.                                         pin05.low();        //低电平接通
  108.                                         pin05_on_time=(new Date()).getTime();                //开启时间节点
  109.                                         System.out.println("--> LED: ON..."+pin05_on_time);
  110.                                         Common.recordLogs(new StringBuffer(new Date()+"--> LED: ON..."+pin05_on_time+"\r\n"), FishConfig.LOGFILE);
  111.                                 }if(FishConfig._DEBUG)System.out.print(".");
  112.                         }
  113.                         if((((new Date()).getTime()-pin05_on_time)/1000/60)>=FishConfig._TRIGGE_G05_TIME_DELAY){
  114.                                 if(pin05.getState().isLow()){
  115.                                         pin05.high();
  116.                                         System.out.println("--> LED: OFF...");
  117.                                         Common.recordLogs(new StringBuffer(new Date()+"--> LED: OFF..."+"\r\n"), FishConfig.LOGFILE);
  118.                                 }
  119.                 }
  120.                         
  121.                 Thread.sleep(1000);
  122.                 }
  123.                
  124.                 //System.out.println("Fish program is end...");
  125.         }
  126.         
  127.         /**
  128.      * 根据时间类型比较时间大小
  129.      * @param source
  130.      * @param traget
  131.      * @param type "YYYY-MM-DD" "yyyyMMdd HH:mm:ss"  类型可自定义
  132.      * @param 传递时间的对比格式
  133.      * @return
  134.      *  0 :source和target时间相同   
  135.      *  1 :source比target时间大  
  136.      *  -1:source比target时间小
  137.      * @throws Exception
  138.      */
  139.     public static int DateCompare(String source, String target, String type) {
  140.             int ret = 2;
  141.             try{
  142.                     SimpleDateFormat format = new SimpleDateFormat(type);
  143.                     Date sourcedate = format.parse(source);
  144.                     Date tragetdate = format.parse(target);
  145.                     ret = sourcedate.compareTo(tragetdate);
  146.             }catch(Exception e){e.printStackTrace();}
  147.             return ret;
  148.     }
  149.         
  150. }
复制代码



下面是视频片段

感应观赏灯


命令行控制注水演示


命令行控制排水演示


滴灌效果特写

最后上几张鱼图
懒人养鱼之-自动鱼缸图24  懒人养鱼之-自动鱼缸图25

懒人养鱼之-自动鱼缸图26  懒人养鱼之-自动鱼缸图27

懒人养鱼之-自动鱼缸图28  懒人养鱼之-自动鱼缸图29


..........>>>>完











hnyzcj  版主

发表于 2016-1-11 10:10:05

今年流行占坑
回复

使用道具 举报

dsweiliang  初级技神

发表于 2016-1-11 10:13:00

今年流行占坑
回复

使用道具 举报

visionsl  初级技匠
 楼主|

发表于 2016-1-11 10:14:33

今年流行占坑
回复

使用道具 举报

Juice  高级技师

发表于 2016-1-11 11:32:53

这个可以远程控制么?单身狗出差半个月回来家里的花花草草可能都做天使去了~
回复

使用道具 举报

virtualwiz  中级技匠

发表于 2016-1-11 11:35:07

今年流行占坑
看起来,全数控鱼缸是大势所趋啊:lol
回复

使用道具 举报

visionsl  初级技匠
 楼主|

发表于 2016-1-11 11:36:10

Juice 发表于 2016-1-11 11:32
这个可以远程控制么?单身狗出差半个月回来家里的花花草草可能都做天使去了~ ...

绝对,必须可以远程!
出差半个月的话, 储水罐需要备个40升的(有自来水管的可以无视)
然后你的花花草草会比你在家还长得好:lol
回复

使用道具 举报

visionsl  初级技匠
 楼主|

发表于 2016-1-11 11:36:59

因为用的是滴灌方式浇花, 所以40升水应该可以用超过半个月
回复

使用道具 举报

heinau  高级技匠

发表于 2016-1-11 14:35:24

visionsl 发表于 2016-1-11 11:36
绝对,必须可以远程!
出差半个月的话, 储水罐需要备个40升的(有自来水管的可以无视)
然后你的花花草草会比 ...

好棒哦!
然而比我在家还要长得好。。感觉自己的存在好没用的样子
回复

使用道具 举报

大连林海  初级技神

发表于 2016-1-11 19:57:54

太牛掰的项目了 模
回复

使用道具 举报

visionsl  初级技匠
 楼主|

发表于 2016-1-11 22:09:40

大连林海 发表于 2016-1-11 19:57
太牛掰的项目了 模

谢谢大牛支持
回复

使用道具 举报

wangsh  见习技师

发表于 2016-1-12 17:02:07

这个必须顶!
回复

使用道具 举报

大连林海  初级技神

发表于 2016-1-12 19:54:11


我是小白 来学习
回复

使用道具 举报

visionsl  初级技匠
 楼主|

发表于 2016-1-18 11:55:19

补: 实际使用效果中, 发现人体红外有时会误报, 后来增加了些功能, 在半夜时段, 不管是否有人都不开LED灯, 以免鱼儿受到惊吓
回复

使用道具 举报

MoonShine  高级技匠

发表于 2016-1-27 17:23:29

楼主真是好人哪!连链接都有,先谢谢了,我再想想优化优化
回复

使用道具 举报

visionsl  初级技匠
 楼主|

发表于 2016-1-29 11:54:42

MoonShine 发表于 2016-1-27 17:23
楼主真是好人哪!连链接都有,先谢谢了,我再想想优化优化

有好想法也Share一下, 共同进步!:handshake
回复

使用道具 举报

guoguode  见习技师

发表于 2021-11-15 21:25:54

厉害!下来慢慢研究、
回复

使用道具 举报

派大星ym  初级技匠

发表于 2022-8-11 08:27:02

酷酷酷酷
回复

使用道具 举报

派大星ym  初级技匠

发表于 2022-8-11 08:29:09

,,,,,
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail