当前位置:   article > 正文

基于树莓派的智能家居_树莓派智能家居

树莓派智能家居

大二的时候做的一个东西,也算是花了不少的心血,所以希望记录下来,也能给其他的小伙伴有一点点参考。由于是自己摸索,所以可能说的不是很清楚或者显得很业余。后来还把小车和智能家居联合起来了,小车可以控制智能家居,智能家居也可以控制小车。主要还是做的功能整合,把之前控制传感器的代码和语音识别、人脸识别的功能结合起来,然后做了web端对沙盘的一些控制,例如灯、舵机这些操作。
后面也有了新的设备,可是也没什么时间更新,很多的功能和代码都来得及写,以后会补上的。如果是想做毕业设计的小伙伴可以和我联系,可以远程协助,包括环境的安装,代码的调试。

部分图片

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

材料

1.前期是几千个小积木一点点拼起来的,后来自己用木板做了一个小沙盘,最后拿了奖金,买了个沙盘。
2.设备是树莓派4B,我的是8G内存的,性能剩余太多了,有点浪费
3.烟雾传感器、火焰传感器、雨滴传感器、土壤湿度传感器、震动传感器、超声波传感器、温湿度传感器、红外发射与接收模块
3.夜视摄像头、体感摄像头、自己焊接的一个小音响,我的体感摄像头是有麦克风的,所以不用单独搞一个麦克风,设置一下体感摄像头为默认麦克风输入。
4.MG90舵机
5.目前还有一个stm32f1的板子和51单片机开发板,还在纠结应该做些什么比较好,放着也是吃灰

语音技术

语音识别是上面很多功能的基础,首先通过snowboy的关键词唤醒,可以自己官网制作属于自己的唤醒模型(因为我懒,测试的时候把灵敏度拉满,于是大喊一声也成),程序使用录音软件进行录音,并且保存在本地文件,调用百度语音识别进行识别,此时将返回的结果保存为文本,来一个正则表达式。
接下来就是朴实无华的语音合成,语音播报其实就是我将录制好的音频文件,在某个if()满足条件的时候就播放出来,例如人脸识别的时候,如果识别通过,就播放欢迎回来,xx。没识别到人脸也给出提示:未识别到人脸,如果不在人脸库的时候,就播放:我不认识你哦。其实我觉得百度语音技术挺好用的,而且还有那么多次的免费调用,用在自己个人学习绰绰有余,几万次的调用,正常人用不完。
放一部分代码

import snowboydecoder
import signal
import wave
import sys
import json
import requests
import time
import os
import base64
from pyaudio import PyAudio, paInt16
import webbrowser
from fetchToken import fetch_token

interrupted = False 
endSnow = False

framerate = 16000
num_samples = 2000
channels = 1
sampwidth = 2
FILEPATH = './audio/audio.wav'

TTS_URL = 'http://tsn.baidu.com/text2audio'

music_exit = './audio/exit.wav'
music_open = './audio/open.wav'
os.close(sys.stderr.fileno())

def signal_handler(signal, frame):
    global interrupted
    interrupted = True

def interrupt_callback():
    global interrupted
    return interrupted

def detected():
    play('./audio/open.wav')
    global interrupted
    interrupted = True
    detector.terminate()

def play(filename):
    wf = wave.open(filename, 'rb')
    p = PyAudio()
    stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
                    channels=wf.getnchannels(),
                    rate=wf.getframerate(),
                    output=True)
    data = wf.readframes(1024)
    while data != b'':
        data = wf.readframes(1024)
        stream.write(data)
    stream.stop_stream()
    stream.close()
    p.terminate()

def save_wave_file(filepath, data):
    wf = wave.open(filepath, 'wb')
    wf.setnchannels(channels)
    wf.setsampwidth(sampwidth)
    wf.setframerate(framerate)
    wf.writeframes(b''.join(data))
    wf.close()

def my_record():
    pa = PyAudio()
    stream = pa.open(format=paInt16, channels=channels,
                     rate=framerate, input=True, frames_per_buffer=num_samples)
    my_buf = []
    # count = 0
    t = time.time()
    while time.time() < t + 5:
        string_audio_data = stream.read(num_samples)
        my_buf.append(string_audio_data)
    save_wave_file(FILEPATH, my_buf)
    stream.close()

def speech2text(speech_data, token, dev_pid=1537):
    FORMAT = 'wav'
    RATE = '16000'
    CHANNEL = 1
    CUID = 'baidu_workshop'
    SPEECH = base64.b64encode(speech_data).decode('utf-8')
    data = {
        "format": "wav",
        "rate": 16000,
        'dev_pid': 1537,
        'channel': 1,
        'token': "*",
        'cuid': "baidu_workshop",
        'len': len(speech_data),
        'speech': "base64.b64encode(speech_data).decode('utf-8')"
    }
    url = 'http://vop.baidu.cpm/server_api'
    headers = {'Content-Type': 'application/json'}
    r = requests.post(url, json=data, headers=headers)
    Result = r.json()
    if 'result' in Result:
        return Result['result'][0]
    else:
        return Result

def get_audio(file):
    with open(file, 'rb') as f:
        data = f.read()
    return data

if __name__ == "__main__":
    while endSnow == False:
        interrupted = False
        detector = snowboydecoder.HotwordDetector('zpf.pmdl', sensitivity=1)
        detector.start(detected_callback=detected,
                       interrupt_check=interrupt_callback,
                       sleep_time=0.03)
        my_record()
        TOKEN = fetch_token()
        speech = get_audio(FILEPATH)
        result = speech2text(speech, TOKEN, int(80001))
        if type(result) == str:
            identifyComplete(result.strip(', '))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121

人脸识别

嗯,调用的还是百度的人脸识别,也是免费的。这个我这几天忙完会把代码传上来。主要思路就是在识别到人脸的时候,if(相似度超过80),这个时候就把门打开,否则提示不在人脸库。

from aip import AipFace
from picamera import PiCamera
import urllib.request
import RPi.GPIO as GPIO
import base64
import time
from snow import *
from hc import *
from snow import *
APP_ID ='*'
API_KEY ='*'
SECRET_KEY ='*'
client = AipFace(APP_ID, API_KEY, SECRET_KEY)
IMAGE_TYPE='BASE64'
camera = PiCamera()

GROUP ='zpf'

def getimage():
    camera.resolution =(1024,768)
    camera.start_preview()
    camera.capture('faceimage.jpg')

def transimage():
    f = open('faceimage.jpg','rb')
    img = base64.b64encode(f.read())
    return img

def go_api(image):
    result = client.search(str(image,'utf-8'), IMAGE_TYPE, GROUP);
    if result['error_msg'] == 'SUCCESS':
        name = result['result']['user_list'][0]['user_id']
        score = result['result']['user_list'][0]['score']
        if score > 80:
            if name == 'zpf':
                door()
                play(result_au)
        else:
            print("对不起,我不认识你!")
            name = 'Unknow'
            return 0
        return 1
    if result['error_msg'] == 'pic not has face':        
        print('检测不到人脸')
        return 0
    else:
        print(result['error_code'])
        return 0
if __name__ == '__main__':
    while True:
        print('准备')
        if True:
            getimage()
            img = transimage()
            res = go_api(img)
            time.sleep(1)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

开门

至于开门的话,我用的是MG90舵机,老样子写好函数,如果满足开门条件,就让舵机把门拉开,至于多少角度的话就需要计算了哈哈哈。舵机我是接在树莓派的11物理引脚上面的,通过调节PWM的占空比控制舵机的转向角度。代码发出来了,大家稍微改一下角度和引脚就可以使用了。

#!/usr/bin/env python3 
import RPi.GPIO as GPIO
import time
def setServoAngle(angle):
   GPIO.setmode(GPIO.BOARD)
   GPIO.setwarnings(False)
   GPIO.setup(11, GPIO.OUT)
   tilt = GPIO.PWM(11, 50)
   tilt.start(0)
   DutyCycle = angle/18 + 2
   tilt.ChangeDutyCycle(DutyCycle)
   time.sleep(1)
   tilt.stop()
c = 'c'

while c == 'c':
   angle = 30  
   setServoAngle(angle)
   c = 'e'
GPIO.cleanup()
exit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

下雨收衣服

这里依赖一个雨滴传感器,检测雨滴就会把衣服那条杠拉进来。没办法,成本不够,gpio口也有限,只能两个舵机来回使用了。

烟雾火焰报警

这里依赖火焰传感器和烟雾传感器,我纠结到底是两者都符合触发报警呢还是单独一个就可以触发报警。如果是单独一个的话,我怕别人点根烟就报警了,到时候会不会很尴尬(我不抽烟哈哈哈哈)传感器原理知识就不多说了,主要还是上代码,改一下pin就好

#!/usr/bin/python
# encoding:utf-8
import RPi.GPIO as GPIO
import time
from snow import *
pin_fire=16
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin_fire, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
try:
    while True:
        status = GPIO.input(pin_fire)
        if status == True:
            print('没有检测到火')
        else:
            print('检测到火灾')
            play('./audio/fire.wav')
        time.sleep(0.5)
except KeyboradInterrupt:
    GPIO.cleanup()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

网络监控

来一张靓仔亲测照片,局域网内都可以查看。现在的思路是树莓派官方的摄像头当人脸识别摄像头,而体感摄像头用来当网络监控,不知道会不会冲突,到时候试一下。目前两个都是用夜视摄像头测试的,补光灯也还没有安装 (因为螺丝不见了,靓仔无语
靓仔
这个时候大家首先要把树莓派的摄像头权限打开

sudo raspi-config
  • 1

选择第五项Interfacing Options,选择第一项camera,选择是,然后重新启动一下

sudo reboot
  • 1

安装motion

sudo apt install motion

sudo vim /etc/default/motion
//设置“start_motion_daemon=no”,将no改为yes,让其后台运行
  • 1
  • 2
  • 3
  • 4
sudo vim /etc/motion/motion.conf
  • 1

设置motion.conf如下:
daemon on
width 640
height 480
stream_localhost off
stream_maxrate 100

这个在比较靠后,我当时翻了挺久的,所以耐心翻一下吧哈哈哈

最后运行

sudo motion
  • 1

接下来浏览器输入树莓派的ip:8081
就可以看见靓仔了

小程序和网页实现对家居的控制

前面的图上面应该有写,搭建服务器端,根据不同的控制请求发布不同的指令,实现对应的控制。

根据光线拉窗帘

这里主要利用到了一个光敏传感器,根据光线的强弱,到达一定的值就会调用舵机拉开窗帘。

智能浇花

这个淘宝买的继电器加土壤湿度检测,简单粗暴,稍微焊接一下就好,就是焊接的不太好看。哦对了,没花。
在这里插入图片描述

最后分享一个在线工具网站,https://www.sora-site.top/

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/232178
推荐阅读
相关标签
  

闽ICP备14008679号