一点点摸索总结资料出来,所以希望记录下来,也能给其他的小伙伴有一点点参考。由于是自己摸索,所以可能说的不是很清楚或者显得很业余。后来还把小车和智能家居联合起来了,小车可以控制智能家居,智能家居也可以控制小车。主要还是做的功能整合,把之前控制传感器的代码和语音识别、人脸识别的功能结合起来,然后做了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': "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=RGTHMghX5okVN2UVCakjnmEg&client_secret=0rDSjzQ20XUj5itV6WRtznPQSzr5pVw2&",
'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(', '))
嗯,调用的还是百度的人脸识别,也是免费的。这个我这几天忙完会把代码传上来。主要思路就是在识别到人脸的时候,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)
至于开门的话,我用的是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()
这里依赖一个雨滴传感器,检测雨滴就会把衣服那条杠拉进来。没办法,成本不够,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()
来一张靓仔亲测照片,局域网内都可以查看。现在的思路是树莓派官方的摄像头当人脸识别摄像头,而体感摄像头用来当网络监控,不知道会不会冲突,到时候试一下。目前两个都是用夜视摄像头测试的,补光灯也还没有安装 (因为螺丝不见了,靓仔无语 )
这个时候大家首先要把树莓派的摄像头权限打开
sudo raspi-config
选择第五项Interfacing Options,选择第一项camera,选择是,然后重新启动一下
sudo reboot
安装motion
sudo apt install motion
sudo vim /etc/default/motion
//设置“start_motion_daemon=no”,将no改为yes,让其后台运行
sudo vim /etc/motion/motion.conf
设置motion.conf如下:
daemon on
width 640
height 480
stream_localhost off
stream_maxrate 100
这个在比较靠后,我当时翻了挺久的,所以耐心翻一下吧哈哈哈
最后运行
sudo motion
接下来浏览器输入树莓派的ip:8081
就可以看见靓仔了
前面的图上面应该有写,搭建服务器端,根据不同的控制请求发布不同的指令,实现对应的控制。
这里主要利用到了一个光敏传感器,根据光线的强弱,到达一定的值就会调用舵机拉开窗帘。
这个淘宝买的继电器加土壤湿度检测,简单粗暴,稍微焊接一下就好,就是焊接的不太好看。哦对了,没花。