起因 一年前玩过一个小鱼缸,不过因为太小, 而且懒于换水, 没多久就放弃了; 后来一直想做点什么在家里可以玩儿的, 恰巧在DFRobot社区见到有人做了个懒人养鱼的换水系统(原文<爱小鱼又养不活?——懒人必试自动换水系统>), 于是下决心也整一个, 但不同的是这次准备玩儿大的, 整个大一点的鱼缸.
鱼缸要大代价就高, 就不能随便整, 所以去泡了几天养鱼的坛子, 发现大鱼缸比小鱼缸复杂多了. 先是分淡水缸和海缸, 然后按过滤系统分: 上滤/侧滤/底滤.
因好奇看了一下海缸, 不看不知道, 一看吓一跳! 海缸固然观赏价值极高(可以养珊瑚, 养海鱼, 想想都爽), 但其过程不但开缸极其复杂, 而且开缸成功后, 整个海水循环系统十分昂贵和复杂, 于是放弃.
既然做不了海缸, 就淡水缸吧. 然后考虑过滤系统, 简单说一下其中两种过滤系统的优劣:
上部过滤:
上部循环过滤是放在水族箱上面,整个过滤槽露在水族箱的外面,通过潜水泵将水抽出进入过滤槽,再由过滤槽底部的出水管流回到水族箱内,在过滤槽内可以放置过滤棉、活性炭、生化石等。上部过滤器的最大优点是清洗方便,在过滤材料污染时,可以很方便地取出进行清洗。最大的缺点是体积比较大,占的空间也相对要大。停电时滤材也不会因泡在水中而缺氧使菌群大量死亡.滤材内的硝化菌在停电后还可以存活很长的时间.
缺点:
噪音 - 流水声更是必须忍受的
过滤槽清洁较麻烦
扬水马达及滴水区与下水口会有声音,有些马达比较吵,滴水声对于浅眠的人来说是一大困扰
上部过滤所佔面积大,影响其他设备的摆放
破坏美观
底部过滤 :
(因本次采用的是底滤, 所以配上图说明, 借用养鱼坛子的一张图)
适合大缸子,水草缸除外
由沉/卧水马达在底下将水吸起利用水压力把水抽上去主缸,主缸水满了之后溢流回去底缸就这样一直循环一直循环,这种溢流设计可以将缸底下的排泄物给清除.通常都用木柜/铁架包门 - 底部看起来较为美观
如设计上无误,换水也方便,拥有极为可观的滤材容量, 培养硝化菌极多,主缸整体看起来会很清爽
缺点:
因需多个底滤缸,滤材,价格挺昂贵
不适合铺底沙,如设计不当,会有流水噪音
过滤槽难清洁整理
综合考虑, 既然搞大了, 那就直接整个美观大方的, 而且底滤系统因底部有柜子, 方便布置咱的智能设备, 只要把线和设备整理好, 鱼缸外观看起来观赏价值高.
先上两张鱼缸图
思路
既然是懒人鱼缸, 所以需要的功能设计如下:
- 自动换水 (本设计的宗旨就是这货)
- 自动浇花 (排出的水不用就浪费了, 拿来浇花杠杠滴)
- 自动打氧 (全天24X7开启本人觉得没必要, 所以要改成定时开一阵子即可)
- 观赏LED灯,人来自动开, 人走演示自动关
以上功能原本用一个普通的Arduino UNO就能做到, 不过后来考虑到联网及易于随时控制, 随时改程序, 随时在电脑上观察各种配件工作情况, 以及远程控制等等拓展功能, 于是采用了功能更为强大的树莓派.
(先上一张控制树莓派的装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打印
设计图
- 电图设计
制作过程
过程中用到3D打印的有几个地方:
1. 人体红外热释电运动传感器, 因是唯一要放置在鱼缸外部的元件, 所以需要制作一个盒子来放它. 刚开始是用黑色材料打印,效果如下
后来发现厚度设计有误, 修改了一下, 换了绿色打印, 效果如下,
装好后:
2. 树莓派和继电器放在底柜中, 需要有个盒子或支架放置, 初步设计为挂在底缸旁边
继电器底座
固定支架(螺丝位设计了一些凹槽, 用于预防水从缸里渗出时, 从凹槽流走, 防止流到电路板上造成短路)
安装好两层的效果图
安装效果图
安装到底缸实际效果.
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号线(灰) 预留
(先接主线路, 主线路经过走线管, 这样看起来整洁些,也在一定程度上防水)
再接外部设备, 从上到下按顺序依次是注水水泵,氧气,热棒,LED,排水水泵;再下来是5V(主线引到树莓派上)和人体红外传感器信号线), 12-20号脚预留(以后备用)
20P接线完成后, 在底滤中部找个位置固定开关电源
设置开关电源的背面还有空间, 用来固定220V电源(输入)插座, 并配了一个PowerCube魔方插座(4面有3脚插座,而且省空间),这里需要供电给:底滤水泵(24X7常开), 开关电源, 树莓派(USB)
回过头继续接主线路的另一端, 220V的全部接上, 并从开关电源引出12V接给LED灯; 接在继电器上的设备主要是(注水水泵/排水水泵/打氧机/LED观赏灯), 这些通过4PIN的公母接头与继电器相连(不直接焊接是为了方便维修)
与树莓派下方的继电器接上, 线上标识好继电器方便识别
排水->浇花(见后面的视频)
注水(从储水罐中抽水注入鱼缸中) (见后面的视频)
内部处理好后, 外部由排水泵引出水管接到滴灌设备上,这是滴灌时的效果. 还不错
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版本)
- /**
- * 智能鱼缸主程序
- * 功能设计要点:
- * - 人体红外传感器. GPIO_02
- * - 自动排水.水泵.1号继电器. GPIO_03
- * - 氧气控制.3号继电器. GPIO_04
- * - LED控制.4号继电器(人来开灯). GPIO_05
- * - 自动注水.水泵.2号继电器. GPIO_06
- * @author Penny
- *
- */
- public class Fish {
-
- private static boolean isAct = false;
- private static long pin05_on_time = 0;
-
- public static void main(String[] args) throws InterruptedException{
- System.out.println("Fish program is running...");
-
- final GpioController gpio = GpioFactory.getInstance();
- final GpioPinDigitalInput hasPerson = gpio.provisionDigitalInputPin(RaspiPin.GPIO_02, PinPullResistance.PULL_DOWN);
- final GpioPinDigitalOutput pin03 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_03, "MyRELAY_injection", PinState.HIGH);//排水,此继电器高电平表示OFF
- pin03.setShutdownOptions(true, PinState.LOW);
- final GpioPinDigitalOutput pin04 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_04, "MyRELAY_oxygen", PinState.HIGH); //氧气
- pin04.setShutdownOptions(true, PinState.LOW);
- final GpioPinDigitalOutput pin05 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_05, "MyRELAY_led", PinState.HIGH); //LED灯
- pin05.setShutdownOptions(true, PinState.LOW);
- final GpioPinDigitalOutput pin06 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_06, "MyRELAY_drain", PinState.HIGH); //注水
- pin06.setShutdownOptions(true, PinState.LOW);
-
- long pin06_on_time = 0; //注水
- long pin03_on_time = 0;
- long pin04_on_time = 0;
- String[] oxygenTimes = FishConfig._TRIGGE_G04_TIME.split(","); //每日打氧气可设多个时间段,以","分隔
-
- hasPerson.addListener(new GpioPinListenerDigital() {
- public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
- if(FishConfig._DEBUG)System.out.println(" --> GPIO PIN STATE CHANGE: " + event.getPin() + " = " + event.getState());
- if(event.getState().isHigh()){
- isAct=true;
- pin05_on_time=(new Date()).getTime(); //更新时间点
- if(FishConfig._DEBUG)System.out.println("update pin05_on_time.");
- }else{ isAct=false;}
- }
- });
-
- while(true){
- String nowTime = new SimpleDateFormat("HH:mm").format(new Date());
- int t06 = DateCompare(nowTime, FishConfig._TRIGGE_G06_TIME, "HH:mm");
- int t03 = DateCompare(nowTime, FishConfig._TRIGGE_G03_TIME, "HH:mm");
-
- //注水
- if(t06==0){
- if(pin06.getState().isHigh()){
- pin06.low(); //低电平接通
- pin06_on_time=(new Date()).getTime(); //开启时间节点
- System.out.println("--> in water: ON..."+pin06_on_time);
- Common.recordLogs(new StringBuffer(new Date()+"--> in water: ON..."+pin06_on_time+"\r\n"), FishConfig.LOGFILE);
- }System.out.print(".");
- }
- if((((new Date()).getTime()-pin06_on_time)/1000/60)>=FishConfig._TRIGGE_G06_TIME_DELAY){
- if(pin06.getState().isLow()){
- pin06.high();
- System.out.println("--> in water: OFF...");
- Common.recordLogs(new StringBuffer(new Date()+"--> in water: OFF..."+pin06_on_time+"\r\n"), FishConfig.LOGFILE);
- }
- }
-
- //排水/浇花
- if(t03==0){
- if(pin03.getState().isHigh()){
- pin03.low(); //低电平接通
- pin03_on_time=(new Date()).getTime(); //开启时间节点
- System.out.println("--> out water: ON..."+pin03_on_time);
- Common.recordLogs(new StringBuffer(new Date()+"--> out water: ON..."+pin03_on_time+"\r\n"), FishConfig.LOGFILE);
- }if(FishConfig._DEBUG)System.out.print(".");
- }
- if((((new Date()).getTime()-pin03_on_time)/1000/60)>=FishConfig._TRIGGE_G03_TIME_DELAY){
- if(pin03.getState().isLow()){
- pin03.high();
- System.out.println("--> out water: OFF...");
- Common.recordLogs(new StringBuffer(new Date()+"--> out water: OFF..."+"\r\n"), FishConfig.LOGFILE);
- }
- }
-
- //打氧气,维持1分钟
- boolean doOxygen = false; //是否需要加氧气
- for(String g04time : oxygenTimes){
- int t04 = DateCompare(nowTime, g04time, "HH:mm");
- if(t04==0){doOxygen=true;break;} //需要加氧气
- }
- if(doOxygen){
- if(pin04.getState().isHigh()){
- pin04.low(); //低电平接通
- pin04_on_time=(new Date()).getTime(); //开启时间节点
- System.out.println("--> oxygen: ON..."+pin04_on_time);
- Common.recordLogs(new StringBuffer(new Date()+"--> oxygen: ON..."+pin04_on_time+"\r\n"), FishConfig.LOGFILE);
- }if(FishConfig._DEBUG)System.out.print(".");
- }
- if((((new Date()).getTime()-pin04_on_time)/1000/60)>=FishConfig._TRIGGE_G04_TIME_DELAY){
- if(pin04.getState().isLow()){
- pin04.high();
- System.out.println("--> oxygen: OFF...");
- Common.recordLogs(new StringBuffer(new Date()+"--> oxygen: OFF..."+"\r\n"), FishConfig.LOGFILE);
- }
- }
-
- //开LED,维持X分钟
- if(isAct){
- if(pin05.getState().isHigh()){
- pin05.low(); //低电平接通
- pin05_on_time=(new Date()).getTime(); //开启时间节点
- System.out.println("--> LED: ON..."+pin05_on_time);
- Common.recordLogs(new StringBuffer(new Date()+"--> LED: ON..."+pin05_on_time+"\r\n"), FishConfig.LOGFILE);
- }if(FishConfig._DEBUG)System.out.print(".");
- }
- if((((new Date()).getTime()-pin05_on_time)/1000/60)>=FishConfig._TRIGGE_G05_TIME_DELAY){
- if(pin05.getState().isLow()){
- pin05.high();
- System.out.println("--> LED: OFF...");
- Common.recordLogs(new StringBuffer(new Date()+"--> LED: OFF..."+"\r\n"), FishConfig.LOGFILE);
- }
- }
-
- Thread.sleep(1000);
- }
-
- //System.out.println("Fish program is end...");
- }
-
- /**
- * 根据时间类型比较时间大小
- * @param source
- * @param traget
- * @param type "YYYY-MM-DD" "yyyyMMdd HH:mm:ss" 类型可自定义
- * @param 传递时间的对比格式
- * @return
- * 0 :source和target时间相同
- * 1 :source比target时间大
- * -1:source比target时间小
- * @throws Exception
- */
- public static int DateCompare(String source, String target, String type) {
- int ret = 2;
- try{
- SimpleDateFormat format = new SimpleDateFormat(type);
- Date sourcedate = format.parse(source);
- Date tragetdate = format.parse(target);
- ret = sourcedate.compareTo(tragetdate);
- }catch(Exception e){e.printStackTrace();}
- return ret;
- }
-
- }
复制代码
下面是视频片段
感应观赏灯
命令行控制注水演示
命令行控制排水演示
滴灌效果特写
最后上几张鱼图
..........>>>>完
|
|