系统烧录
下载树莓派系统镜像:https://www.raspberrypi.org/downloads/raspbian/,下载后解压得到.img后缀的文件
对树莓派的SD卡进行格式化。
将SD卡通过转接器插入电脑USB口,Windows10下<对计算机图标右键-管理>,在左侧列表选择存储-磁盘管理,在界面中找到SD卡对应的磁盘(别找错了把自己电脑硬盘清空了),SD卡可能有标蓝的已有分区与标黑的未分配空间。
对所有标蓝的已有分区<右键-删除卷>,直到SD卡对应的磁盘显示为一个标黑的未分配空间。接着在标黑的未分配空间上<右键-新建简单卷>,无脑下一步,此时SD卡对应的磁盘变为了一个标蓝的分区。记录SD卡的卷号,譬如H或者I等。
树莓派操作系统的烧录。
下载软件Win32Diskmager:https://sourceforge.net/projects/win32diskimager/
在Win32Diskmager中,映像文件选择之前下载的.img文件,设备中选择SD卡的卷号,点击写入,等待镜像写完。写完以后计算机里可能只看得到一个几百MB的boot分区,另一个分区识别不到,因为另一个分区被制作成了Windows不识别的ext4文件系统。电脑会提示你格式化这个盘,不要理他!
最后将SD卡插入树莓派打开树莓派即可,此时树莓派已经可以运行SD卡中的操作系统。拔SD卡的时候需要先关树莓派再拔。
树莓派连显示器
直接把树莓派和显示器接上即可。如果用的是嵌入式显示器,USB供电注意不能接树莓派,要接电脑或者手机充电器等等,树莓派的USB供电能力较差。一开始供电接了树莓派结果点不亮显示器以为系统没烧好,结果用万用表一测5v的VCC只有0.63v。
↑↑↑我也不知道这是怎么回事,power口接树莓派点不亮接充电器能点亮,但是触摸屏信号传输口接树莓派不仅触摸信息能传输了供电也没问题可以直接把power口悬空???这是什么操作反正我是没看懂。
![](https://cdn.nlark.com/yuque/0/2020/jpeg/1333618/1591102800980-65874371-512e-4ca3-b2ca-922bc681a15b.jpeg#align=left&display=inline&height=228&margin=%5Bobject%20Object%5D&originHeight=302&originWidth=378&size=0&status=done&style=none&width=286)
如果还点不亮显示器的话,把SD卡拔下来插进电脑,在SD卡那个几百MB大的boot分区里有个config.txt,先存一个副本防止改坏,然后在config.txt末尾加上:
hdmi_force_hotplug=1
config_hdmi_boost=4
hdmi_group=2
hdmi_mode=9
hdmi_drive=2
hdmi_ignore_edid=0xa5000080
disable_overscan=1
config.txt里还有很多其它能用于配置的参数,没仔细展开研究。
更改屏幕分辨率:https://jingyan.baidu.com/article/02027811d749395bcd9ce52f.html
屏幕截图:https://blog.csdn.net/u014755255/article/details/52777253
树莓派与电脑的连接
开启SSH
参考:树莓派开启SSH的N种方法
树莓派默认是禁止ssh远程登录的,需要首先在树莓派上打开ssh,推荐链接里的方法二方法三比较方便。打开后重启树莓派。
ssh登录树莓派linux和Windows均可,ssh首先需要知道树莓派的ip地址,譬如192.168.60.144,在电脑端命令行中输入“ssh pi@192.168.60.144”即可,其中pi为默认用户名,默认密码为“raspberry”。
获取树莓派ip
- 找个显示器,接上,运行命令行(点击UI上面的命令行标志或者快捷键ctrl+alt+T),输入ifconfig
- 找一个能连无线网又有有线网口(或者用网口转接器)的电脑,wifi正常连网,有线网口用网线连接树莓派。
打开“网络和internet设置”-更改适配器设置-WLAN上右键-属性-共享里打钩:
然后有两种方法。
第一种:在Windows端打开cmd命令行,输入“ping raspberrupi.local”,就可以看到树莓派的ip地址。
第二种:在Windows端打开cmd命令行,输入“arp -a”,在192.168.137.1这个共享接口下查找ip地址(192.168开头的那个)
![](https://cdn.nlark.com/yuque/0/2020/png/1333618/1590743814651-19a0934e-930f-42cb-8c15-7c7f71a07f66.png#align=left&display=inline&height=78&margin=%5Bobject%20Object%5D&originHeight=78&originWidth=413&size=0&status=done&style=none&width=413)
- 大神,我既连不了无线也连不上显示器只有一根网线,怎么连电脑?救救孩子吧大神,救救孩子!
答:梦里什么都有
静态ip设置
懒的搞搁置
参考:https://www.jianshu.com/p/ac9d784f112b
树莓派基础操作
文件系统
cd:进入某个文件夹(cd ../返回上一级)
ls:列出当前目录下所有的文件、文件夹
vi
mkdir:创建一个文件夹
rm:删除文件(rm -rf递归地删除文件夹及其包含的所有文件)
mv:移动文件(剪切+粘贴)
cp:拷贝文件(复制+粘贴)
与Windows互传文件
scp C:\Users\LouZhenyu\Desktop\PythonPro\test.py pi@192.168.137.236:/home/pi
scp pi@192.168.137.236:/home/pi/test.py C:\
传文件夹:scp -r
需要在Windows端装软件但不需要敲命令的方法:
https://blog.csdn.net/midle110/article/details/46474607
vim
i:进入插入模式
esc:退出插入模式,再输入冒号输入命令
w filename:保存或重命名当前文件
wq:保存退出
saveas
e
q:在未做修改的情况下退出
q!:不保存退出
PyQt5
第一个程序
Windows端用PyQt5编写的程序可以直接移植至树莓派,就很方便。
需要保证Windows端和树莓派端的python版本一样(比如都是python3)
(以下命令区分大小写,务必完全一致)
Windows:pip install PyQt5
树莓派:sudo apt-get upgrade
sudo apt-get install python3-pyqt5
(我也不知道为什么树莓派装完以后不论pip list还是python -m pydoc modules都不显示这个包)
第一个PyQt程序, 该程序显示了一个250*150的窗口:
import sys
from PyQt5.QtWidgets import QApplication, QWidget
if __name__ == '__main__':
app = QApplication(sys.argv) # 创建一个application对象
w = QWidget() # Qwidget组件是PyQt5中所有用户界面类的基础类
w.resize(250, 150) # 调整窗口大小为250*150
w.move(300, 300) # 移动到x=300,y=300处
w.setWindowTitle('Simple') # 设置窗体标题
w.show() # 显示窗体
sys.exit(app.exec_()) # 安全退出
Windows端运行结果:
树莓派端运行结果(由于是ssh上去的,没任何显示输错,但已经能用了):
按钮、窗体、信号
![1.png](https://cdn.nlark.com/yuque/0/2020/png/1333618/1591014355387-6bf2d743-43f5-4d7a-9b0f-d3138934ae99.png#align=left&display=inline&height=336&margin=%5Bobject%20Object%5D&name=1.png&originHeight=423&originWidth=674&size=13685&status=done&style=none&width=536)
import sys
import time
import PyQt5
from PyQt5.QtWidgets import QWidget,QToolTip,QPushButton,QMessageBox,QApplication,QDesktopWidget
from PyQt5.QtGui import QFont
from PyQt5.QtCore import QCoreApplication
w_width = 480
w_height = 320
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
QToolTip.setFont(QFont('SansSerif', 10)) # 设置提示框的字体和字大小
btn = QPushButton('Boom', self)
btn.clicked.connect(self.close) # 将self.close作为信号接收方,close会调用closeEvent
btn.setToolTip('This is a <b>QPushButton</b> widget') # 按钮提示框<b></b>控制粗体
btn.resize(150, 80)
# btn.move((w_width - btn.width()) // 2, (w_height - btn.height()) // 2)
#####################以下代码负责窗体居中####################
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
###########################################################
self.setGeometry(0, 0, w_width, w_height)
self.setWindowTitle('BoomShakalaka!')
self.show()
def closeEvent(self, event): # 退出事件函数的overload,命名必须一致
reply = QMessageBox.question(self, 'Message', "Are you sure to boom the computer?",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
如果要让窗口全屏,将35行的self.show()改成self.showFullScreen()
加载图片
![1.png](https://cdn.nlark.com/yuque/0/2020/png/1333618/1591014433029-07b9df93-0525-4519-9170-157d1f158b56.png#align=left&display=inline&height=314&margin=%5Bobject%20Object%5D&name=1.png&originHeight=353&originWidth=483&size=14717&status=done&style=none&width=430)
from PyQt5.Qt import *
from PyQt5.QtWidgets import QWidget, QToolTip, QLabel, QMessageBox, QDesktopWidget, QApplication
from PyQt5.QtGui import QPixmap
w_width = 480
w_height = 320
class UI(QWidget):
def __init__(self):
super().__init__()
self.w = w_width
self.h = w_height
self.initUI()
def initUI(self):
lb_bg = self._create_label_from_picture('picture/A_bg.png', fullscreen=True)
self._lb_fullscreen(lb_bg)
lb_clock = self._create_label_from_picture('picture/A_clock.png', scale=1.0)
self._lb_center(lb_clock)
self.setWindowTitle('BoomShakalaka!')
self.setGeometry(0, 0, self.w, self.h)
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
self.show()
def _create_label_from_picture(self, path, fullscreen=False, scale=1.0):
import os
if not os.path.exists(path):
raise ValueError('\"{}\" is missing.', path)
pix = QPixmap(path)
if fullscreen:
pix = pix.scaled(QSize(self.w, self.h))
else:
pix = pix.scaled(QSize(int(pix.width() * scale), int(pix.height() * scale)))
label = QLabel(self)
label.resize(pix.size())
label.setPixmap(pix)
return label
实时刷新与定时器
获取系统时间参见https://www.cnblogs.com/xiaoxiaoweng/p/10966220.html
遗留问题:如何获取drawText后的文字渲染图的长宽?获取不到每次都只能把绘制的rect区域写死很蠢……
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
w_width = 480
w_height = 320
class UI(QWidget):
def __init__(self):
super().__init__()
self.w = w_width
self.h = w_height
self.draw_timer = QBasicTimer() # 定义一个定时器
self.initUI()
def initUI(self):
self.pix_bgA = self._create_label_from_picture('picture/A_bg.png', fullscreen=True)
self.draw_timer.start(20, self) # 20ms触发一次定时器
self.setWindowTitle('BoomShakalaka!')
self.setGeometry(0, 0, self.w, self.h)
self.show()
def timerEvent(self, event): # 重载定时器event处理函数,名字必须完全一样
if event.timerId() == self.draw_timer.timerId():
self.update() # self.update函数会触发paintEvent进行画面更新
else:
super(UI, self).timerEvent(event)
def paintEvent(self, event):
import datetime
painter = QPainter(self)
font = QFont('SansSerif', int(28 * self.scale)) # 设置渲染字符串时的字体和大小
painter.setFont(font)
painter.setPen(QColor(96, 52, 24)) # 设置颜色
painter.drawPixmap(self.pix_bgA.rect(), self.pix_bgA) # 绘制背景
now = datetime.datetime.now().strftime('%H:%M') # 获取系统时间并实时显示
painter.drawText(QRect(188, 141, 300, 300), 0, now) # drawText可以直接传字符串进去
def _create_label_from_picture(self, path, fullscreen=False, scale=1.0):
import os
if not os.path.exists(path):
raise ValueError('\"{}\" is missing.', path)
pix = QPixmap(path)
if fullscreen:
pix = pix.scaled(QSize(self.w, self.h))
else:
pix = pix.scaled(QSize(int(pix.width() * scale), int(pix.height() * scale)))
label = QLabel(self)
label.resize(pix.size())
label.setPixmap(pix)
return label
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
骂人
这个库是真的垃圾啊,竟然没有任何报错信息,一出错就直接给你崩溃退程序,没有报错信息也没有traceback。
PyAudio
Windows端直接pip install pyaudio
树莓派端需要先
实时检测输入音量程序示例:
import pyaudio
import numpy as np
import math
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 16000
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
while True:
str_data = stream.read(CHUNK)
audio_data = np.fromstring(str_data, dtype=np.short)
# db = 20 * math.log10(np.sum(audio_data ** 2) / CHUNK / (32768 ** 2) + 1e-9)
db = 20 * math.log10(np.average((audio_data / 32768.0) ** 2) + 1e-9)
print(db)
stream.close()
p.terminate()
踩了个坑,用第21行的代码算db的时候,short类型求平方和默认会被放在short类型中发生了溢出,所以把除32768移到前面防止溢出并将类型转成float。
在Windows上跑时没问题,在树莓派上跑有一百万个报错,但是意外的根本没关系。
硬件与驱动
开发板中文手册:http://docs.16302.com/1228882
这是一整个模块竟然只用来当麦克风。。。真的有点浪费。。。
硬件连接方面,模块板的引脚是母口,可以直接插到树莓派的公口引脚上。别接反!别接反!别接反!接反了会爆炸,一定要看清楚。
DSP
使用了谐波显著度和算法,参考:宋黎明《谐波显著度的基频提取方法》
*参考http://www.doc88.com/p-1778502117278.html
安装scipy包,树莓派上sudo apt-get install python3-scipy
虽然dsp部分单独开了一个进程执行(python的多线程是调用同一个cpu核心的,只能用多进程编程以利用多核cpu)一开始写的程序在x86上跑没问题,在树莓派上跑发现dsp进程直接挂了只剩下ui进程然后得不到任何麦克风的输入信息。
调试的时候发现,在AMD Ryzen r7 3700x @4.15GHz下,进行一次dsp耗时70ms(这还是numpy有Intel的mkl加成而amd很不友好的情况下),而树莓派端ARM A72 @1.5GHz下,进行一次dsp耗时750ms,然后采样率为16000,帧长1024,dsp的速度远远跟不上麦克风输入的速度导致用于存放麦克风输入的buffer爆栈。
最开始的dsp方法要对所有频域的点计算谐波显著度和Q,后来改成基于幅值的候选点计算Q,限制计算Q的点数不大于60才勉强在树莓派上算的动。改成这种方法以后意外的效果并没有变差多少。
开机自启动
参考:https://www.cnblogs.com/in-dreams/p/7597619.html
sudo su (进入root模式)
sudo vim /etc/rc.local
在exit 0 之前添加执行命令 sudo python /xx/xx/xx.py
exit (退出root模式)
重启
↑↑↑↑↑说是这么说的可是不知道为啥没用,有说法说是没权限,但是加了777权限也没用