锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

【物联网毕设】基于Arduino与树莓派的智能鱼缸【二】

时间:2022-12-04 08:30:00 电缸里的传感器

提示:文章完成后,目录可以自动生成,如何生成可以参考右边的帮助文档

文章目录

  • 前言
  • 一、Arduino通信树莓派
  • 2.树莓派将数据上传到服务器
    • 1.用于树莓派Django搭建服务器
    • 2.搭建树莓派MySQL数据库
    • 3.树莓派数据post到服务器上
  • 微信小程序通过服务器获取数据库的值
  • 总结


前言

本文主要讲的是智能鱼缸树莓派,也是我认为毕业设计最难的部分。

一、Arduino通信树莓派

看过我上一篇文章的朋友应该知道,现在我们已经实现了Arduino读取传感器的值,我们如何把它传给树莓派?(注:如果手里有全新的覆盆子派,需要安装镜像源,实现远程访问等准备工作。建议B站覆盆子派教程:https://www.bilibili.com/video/BV1bt411c7fC?share_source=copy_web只看前四节课ok)
参考链接:树莓派与Arduino通信

跟着这个帖子成功实现简单的通后(我用的是USB通讯),接下来要做的就是把我的Arduino传感器的数据传输到树莓派。
上代码!
在Arduino IDE写下面的代码,覆盖我上一篇文章Arduino IDE上面的代码(此代码添加到以前的基础上Arduino将数据发送给树莓的部分):
Arduino代码:

#include  #include   #define tempPin 2// 温度传感器数据输出脚接开发板数字引脚2 #define waterpower 7 ///水位传感器VCC引脚 #define waterpin A0 //水位传感器输出引脚 #define oxygenpin A1///溶解氧传感器输出引脚  OneWire oneWire(tempPin); DallasTemperature sensors(&oneWire);  int temp_relaypin=3;///温度传感器继电器1引脚3 int waterup_relaypin=4;///水位传感器继电器引脚4 int waterdown_relaypin=5;////水位传感器继电器引脚5 int oxygen_relaypin=9;///溶解氧传感器继电器引脚9  float temperature; int oxygen; int water_level; int val=0; int incomedate = 0;  void setup(void) { 
           Serial.begin(9600);///连接到计算机串口监视器   sensors.begin();   pinMode(temp_relaypin,OUTPUT);//设置继电器1为输出模式
  pinMode(tempPin,OUTPUT);//温度传感器输出模式
  pinMode(waterup_relaypin,OUTPUT);//继电器输出模式
  pinMode(waterdown_relaypin,OUTPUT);//继电器输出模式
  pinMode(waterpower,OUTPUT);//将水位传感器VCC引脚设置成输出模式
  pinMode(oxygen_relaypin,OUTPUT);//溶解氧继电器4输出模式 
  digitalWrite(waterpower,LOW);//先将水位传感器VCC引脚关闭
}

int readwatersensor()
{ 
        
  digitalWrite(waterpower,HIGH);//将水位传感器VCC电源打开给传感器供电
  delay(10);
  val=analogRead(waterpin);//读取水位传感器A0引脚的值
  digitalWrite(waterpower,LOW);//将水位传感器电源关闭
  return val;//返回val值
}

void loop(void)
{ 
         
  //温度
  sensors.requestTemperatures(); // 发送命令获取温度
  temperature=sensors.getTempCByIndex(0);
  
  //溶解氧
  int analog=analogRead(A1);//读取模拟输入值
  oxygen=map(analog,0,1023,0,10);//将模拟输入0~1023等比映射到0mg/L~10mg/L
  analogWrite(9,oxygen);
  
  //水位
  int level=readwatersensor();//让level=val
  water_level=readwatersensor();//让water_level=val

  if(Serial.available())
  { 
        
    incomedate = Serial.read();//获取串口接收到的数据
    if (incomedate == 't')
    { 
          
      Serial.println(temperature); //向树莓派发送信息
    }
    else if (incomedate == 'w')
    { 
          
      Serial.println(water_level); //向树莓派发送信息
    }
    else if (incomedate == 'o')
    { 
          
      Serial.println(oxygen); //向树莓派发送信息
    }
  }


  //继电器控制加热棒
  if(temperature<25)//如果温度小于25度
  { 
        
    digitalWrite(temp_relaypin, HIGH);//继电器1开,加热棒开
  }
  else
  { 
        
    digitalWrite(temp_relaypin,LOW);  //继电器1关,加热棒关; 
  }
  delay(500);
  
  //继电器控制水泵
  if(water_level<550)//如果水位在传感器1CM之下
  { 
        
    digitalWrite(waterup_relaypin, HIGH);//继电器2开,放水水泵开
  }
  else
  { 
        
    if(water_level>640)
    { 
        
       digitalWrite(waterdown_relaypin, HIGH);//继电器3开,抽水水泵开
    }
    else
    { 
        
      digitalWrite(waterup_relaypin, LOW);//继电器2关
      digitalWrite(waterdown_relaypin, LOW);//继电器3关
    }
  }
  
  //继电器控制增氧泵
  if(oxygen<5)
  { 
        
    digitalWrite(oxygen_relaypin, HIGH);//继电器4开,充氧泵开
  }
  else
  { 
        
    digitalWrite(oxygen_relaypin, LOW);//继电器4关,充氧泵开
  }
  delay(500);
}

在树莓派上新建一个post.py文件,写入:
树莓派代码:

import RPi.GPIO as GPIO
import serial
import time
import json,requests
import datetime
ser = serial.Serial('/dev/ttyUSB0', 9600,timeout=1);   #open named port at 9600,1s timeot
#try and exceptstructure are exception handler
while 1:
    for i in range(2):
        send='t';
        ser.write(send.encode());#wrt a string to port
        time.sleep(2);
        temperature = ser.readline().decode();#read a string from port
        print(temperature);
        send='w';
        ser.write(send.encode());#wrt a string to port
        time.sleep(2);
        water_level= ser.readline().decode();#read a string from port
        print(water_level);
        send='o';
        ser.write(send.encode());#wrt a string to port
        time.sleep(2);
        oxygen = ser.readline().decode();#read a string from port
        print(oxygen);

注意树莓派代码第六行里的:/dev/ttyUSB0,还有人是/dev/ttyACM0,要知道你的是什么,把树莓派和Arduino用USB连接后,在树莓派终端输入: ls /dev/tty*查看两者连接端口的名字,多出哪个就是哪个。
for i in range(2): 的意思是让树莓派打印两次,因为经过实验,发现第一个值一直打不出来,咱也不知道为什么,硬件有时候就是玄学,所以就让这段代码循环两次,让树莓派和Arduino之间实现稳定的传值。
提醒一下之后post.py里还要写入一部分代码,也就是说目前上面的这段树莓派里的代码只是一部分,所以你试验的时候,可能会出现多余的头文件,然后树莓派的IDE报错,没事,暂时把没有用到的头文件注释掉就好了,后面会用得着的(我可真是太贴心了)。
运行结果:
在这里插入图片描述
注意这里是后期要放在论文里的截图,特意把第一个没有打出来的temperature盖住了(怕老师问我我答不上来),然后让程序循环了五次。

二、树莓派把数据上传到服务器

现在我们的树莓派已经得到了从Arduino上传过来的传感器数据了。接下来就是把数据上传到服务器,通过服务器写入到数据库了。首先,我们得有一个基于树莓派的服务器。其次,我们树莓派上得有一个MySQL数据库。然后,我们要把服务器和数据库连接起来。最后,把树莓派上的数据post到服务器。接下来我一部分一部分的细说。
参考链接:https://blog.csdn.net/weixin_52079689/article/details/109383872?spm=1001.2014.3001.5506

1.在树莓派上用Django搭建服务器

参考链接:https://blog.csdn.net/damanchen/article/details/85224686
跟着这个链接,我们可以在树莓派上下载好Django。需要注意的是,你的树莓派要有python,我的3B里python默认的是python2。为了之后方便操作,我需要将python2换成python3,这个视情况而定,你不一定非得改。如果你也想改,推荐链接:https://blog.csdn.net/ylzmm/article/details/107827065
好的。现在我们的树莓派上已经有Django了,可以正式开始创建一个服务器了。
输入:

django-admin.py startproject fish_tank2#生成网站
cd fish_tank2 
python manage.py startapp index2#生成app

创建好后的截图:

配置功能:
需要说明以下我的项目名都是fish_tank,app都叫index。上面的项目和app是我为了演示新建的。名字会有变化。
fish_tank/setting

这里是有关树莓派数据库的,要加这两句代码。

import pymysql
pymysql.install_as_MySQLdb()


[’*’]是为了让同一局域网下面不同ip都可以访问该服务器。

这是连接数据库。后面会讲到树莓派上搭建数据库,这里就是将数据库与服务器连接起来的代码。
fish_tank/urls.py

from django.conf.urls import url
from django.urls import path, include


urlpatterns = [
    #path('admin/', admin.site.urls),
    url(r'^sensor/', include('index.urls')),
]

fish_tank/index/admin.py

from django.contrib import admin

# Register your models here.
from .models import *


class SensorAdmin(admin.ModelAdmin):
    list_display = ('id', 'time', 'temperature','water_level','oxygen')


admin.site.register(Sensors, SensorAdmin)

fish_tank/index/app.py

from django.apps import AppConfig


class IndexConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'index'

fish_tank/index/models.py

from django.db import models


# Create your models here.
class Sensors(models.Model):
    time = models.DateTimeField(auto_now_add=False)
    temperature = models.CharField(max_length=10)
    water_level= models.CharField(max_length=10)
    oxygen = models.CharField(max_length=10)

    def __str__(self):
        return self.time

fish_tank/index/serializers.py(没有的文件就右键新建)

from rest_framework import serializers
from index.models import Sensors
class SensorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Sensors
        fields = ['time', 'temperature','water_level','oxygen']


fish_tank/index/urls.py

from django.conf.urls import url
from index import views

urlpatterns = [
    url(r'^post', views.Sensors_api.as_view(),name='sensor.Sensors_api'),
    url(r'^get', views.SensorView.as_view(),name='sensor.Sensors_api'),
]

这里新建了两个网址,post用来接收树莓派上传的数据,得到的是所有的数据;get用来显示最新的数据,因为我们只需要当前的数据。为什么要写成两个网址呢?是因为post用的接口和get不一样,get用的那个接口可以显示最新值,但是post的那个接口我没有找到如何显示最新的值的方法,所以就写了两个网址,一个用来接收数据,一个用来显示最新数据到服务器上,后续小程序也方便get到最新数据。
fish_tank/index/views.py

from rest_framework.response import Response
from rest_framework.views import APIView

from index.models import Sensors
from index.serializers import SensorSerializer
from rest_framework import generics

# Create your views here.
class Sensors_api(generics.ListCreateAPIView):
    #queryset = Sensors.objects.last()
    queryset = Sensors.objects.all()
    serializer_class = SensorSerializer


class SensorView(APIView):
    def get(self, request, *args, **kwargs):
        sensor = Sensors.objects.last()
        obj = SensorSerializer(sensor)
        return Response(obj.data)

这里就可以看出来,我post用的是ListCreateAPIView这个接口,get用的是APIView这个接口。
到此,树莓派上成功搭建起了一个web服务器。

2.在树莓派上搭建MySQL数据库

在树莓派上设置安装MySQL,设置用户名密码,推荐链接:点我
注意这里设置的用户名密码要和setting里连接的一样。
建议在pc端下载Navicate,连接树莓派上的数据库,这样有了图形化界面,建表看着也舒心。
然后执行给数据库建表的两句代码:
参考链接:点我

python manage.py makemigrations
python manage.py migrate

Navicate与树莓派数据库连接成功:

到此,数据库和服务器全都创建成功,并且进行了连接。

3.树莓派把数据post到服务器上

在刚才树莓派post.py后面加上此代码:

# Post Data to webpage
    
    rqs_headers={ 
        'Content-Type': 'application/json'}
    requrl ='http://192.168.43.121:8000/sensor/post/'
    new_data = { 
        
        "time": datetime.datetime.now(),
        "temperature": temperature,
        "water_level": water_level,
        "oxygen": oxygen
    }

    class ComplexEncoder(json.JSONEncoder):
        def default(self, obj):
            if isinstance(obj, datetime.datetime):
                return obj.strftime('%Y-%m-%d %H:%M:%S')
            elif isinstance(obj, datetime.date):
                return obj.strftime('%Y-%m-%d')
            else:
                return json.JSONEncoder.default(self, obj)
        
    test_data = json.dumps(new_data, cls=ComplexEncoder)

    response = requests.post(url=requrl, headers=rqs_headers, data=test_data)
    time.sleep(50);

运行服务器:
记得要先进入项目的文件夹在文件夹在运行哦

运行:

python manage.py runserver 0.0.0.0:8000

在浏览器上输入:192.168.43.121:8000/sensor/post/和192.168.43.121:8000/sensor/get/
192.168.43.121是我树莓派的ip地址,你们输网址的时候要改成自己的ip地址。

运行post.py文件,可以看到post页面获取到了所有的值,get页面获取到了最新值,Navicat中可以看到数据库里更新了值。
post页面:

get页面:

Navicat连接数据库页面:

如果你不想手动点击post.py,而是想让它自动每60秒执行一次,可以:

sudo -i
crontab -e 
*/1 * * * * python /home/pi/Desktop/post.py #把这个命令加到最后一行,我设定的是每分钟运行一次,用的时候把注释去掉就好了。
sudo /etc/init.d/cron restart

这个时候post.py里的while 1 就可以去掉了。我把自动执行的放到post2.py里,手动执行的放在post.py里,手动的方便调试,自动的最后使用。
至此,由arduino获取传感器数值,并传给树莓派,树莓派上传到服务器,通过服务器写入到数据库就完成了。

三、微信小程序通过服务器获取数据库的值

最后一步!!终于快写完了!!
我们要开发一个微信小程序,让小程序通过服务器获取到传感器的数值。
微信小程序课程推荐的B站链接:
下载微信开发者工具
注册账号,获取到appid

其实不用做那么复杂,只需要改两段代码,其他的默认就行:
index.wxml

<!--index.wxml-->
<view class="container">
  <view class="userinfo">
    <block wx:if="{ 
        {canIUseOpenData}}">
      <view class="userinfo-avatar" bindtap="bindViewTap">
        <open-data type="userAvatarUrl"></open-data>
      </view>
      <open-data type="userNickName"></open-data>
    </block>
    <button type="primary" bindtap="get_message">获取传感器数值</button>
    <view>时间:{ 
        { 
        message.time}}</view>
    <view>温度:{ 
        { 
        message.temperature}}</view>
    <view>水位:{ 
        { 
        message.water_level}}</view>
    <view>溶解氧:{ 
        { 
        message.oxygen}}</view>
    <view>加热棒:{ 
        { 
        message.temperature >25 ? '关': '开'}}</view>
    <view>充氧泵:{ 
        { 
        message.oxygen >5 ? '关': '开'}}</view>
    <view>加水水泵:{ 
        { 
        message.water_level <550 ? '开': '关'}}</view>
    <view>抽水水泵:{ 
        { 
        message.water_level >640 ? '开': '关'}}</view>
  </view>
</view>

这里只加了一个按钮
index.js

// index.js
// 获取应用实例
const app = getApp()

Page({ 
        
  data: { 
        
    message:[],
    motto: 'Hello World',
    userInfo: { 
        },
    hasUserInfo: false,
    canIUse: wx.canIUse('button.open-type.getUserInfo'),
    canIUseGetUserProfile: false,
    canIUseOpenData: wx.canIUse('open-data.type.userAvatarUrl') && wx.canIUse('open-data.type.userNickName') // 如需尝试获取用户信息可改为false
  },
  // 事件处理函数
  bindViewTap() { 
        
    wx.navigateTo({ 
        
      url: '../logs/logs'
    })
  },
  onLoad() { 
        
    if (wx.getUserProfile) { 
        
      this.setData({ 
        
        canIUseGetUserProfile: true
      })
    }
  },
  getUserProfile(e) { 
        
    // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
    wx.getUserProfile({ 
        
      desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
      success: (res) => { 
        
        console.log(res)
        this.setData({ 
        
          userInfo: res.userInfo,
          hasUserInfo: true
        })
      }
    })
  },
  getUserInfo(e) { 
        
    // 不推荐使用getUserInfo获取用户信息,预计自2021年4月13日起,getUserInfo将不再弹出弹窗,并直接返回匿名的用户个人信息
    console.log(e)
    this.setData({ 
        
      userInfo: e.detail.userInfo,
      hasUserInfo: true
    })
  },
  get_message(){ 
        
    var that = this;
    wx.request({ 
        
      url: 'http://192.168.43.121:8000/sensor/get',
      success(data){ 
        
        console.log(data.data)
        that.setData({ 
        message:data.data})
      }
    })
  },
})

这里get数据。
在手机上运行的结果:(我点击按钮会出来传感器数值)

总结

终于写完了,最后再整体捋一遍
1、arduino获取传感器数值
2、arduino与树莓派进行通讯,树莓派获取传感器数值
3、树莓派将数值上传到服务器上,通过服务器写入数据库,服务器用Django写,然后与树莓派上数据库进行连接。
4、微信小

相关文章