项目介绍
本项目参与第四届2024年“寒假在家一起练”,对应平台4“搭配带屏12指神探的传感器扩展板”,该活动链接为:https://www.eetree.cn/activity/15 。本项目实现了以下任务:
该平台任务2“多功能感应及报警系统”,要求“人体经过或靠近检测”“可使用蜂鸣器发出警报、成功识别等状态音”“可在LCD上显示基本信息如开关状态、人体或物体是否经过、距离远近”,本项目程序已经实现。
链接:https://www.eetree.cn/vendorProject/preview/406
该平台任务1要求“至少使用一种自控算法控制,如PID等;可用按键或拨轮控制目标温度;可在LCD屏上显示目标温度及实时温度“。
链接:https://www.eetree.cn/vendorProject/preview/405
该平台任务3“颜色识别及校准功能”,“可识别至少五种颜色”“可在LCD上显示基本信息如当前识别颜色”“可在LCD上用色块显示识别的颜色并大致接近”。
链接:https://www.eetree.cn/vendorProject/preview/407
对任务4与任务5,本项目也设计了美观的UI界面,多种表盘,丰富仪表界面,还实现了“记录数据可上传至上位机”。
基于活动平台及任务要求,使用micropython语言,设计了一种自识别仪表盘与智能控制系统。完成了本平台要求的若干任务。
项目功能介绍
可以识别橙色、白色、黑色、蓝色、粉色5种颜色并自动切换不同的表盘,多种表盘自适应全局UI,同时展示识别结果的颜色,同时温度计地球底部部分,变为识别出的颜色。
本项目实现了基于PID的自控算法温度控制,用户可以使用拨轮设置目标温度“temperature_limit”,拨轮向左可以降低1摄氏度,拨轮向右可以升高1摄氏度。
LCD显示屏,实时显示当前设置的目标温度和NSHT30传感器输出的温湿度,显示颜色识别结果(文字与颜色展示),显示接近传感器报警状态。
基于PID算法,实现以下效果:当传感器温度低于目标温度,自动开启加热电阻(指示灯亮起);当传感器温度高于目标温度,自动关闭加热电阻(指示灯关闭)。
本项目还启用了接近传感器,该传感器基本实现了过近准确监测报警,并使用蜂鸣器发出报警,同时LCD屏幕上也有具体反馈(过近时温度计“水银”部分变为黄色,正常时温度计“水银”部分变为红色)。上位机可以收到传感器的距离数据,并持续绘图。
接近传感器该功能的实际意义为过近传感器报警,防止烫伤(因为温度传感器旁的加热电阻开启时温度过高)。
设计思路
本项目设计思路以多个任务为导向,在明确拓展板数据读取方案后,发现基于Micropython开发较为便捷,所以以本项目完成了若干任务内容,由于该板卡平台同时具备屏幕显示、传感器、蜂鸣器反馈等完备功能,因此完善地实现了该活动下的各个任务要求。具体任务实现方案可参考软件流程图。
软件流程图
硬件框图
以下为拓展板电路图。
以下为带屏RP2040电路图。
硬件介绍
带屏版的12指神探,它是在原板基础上,配备了一块240*240分辨率的LCD彩屏以及两个可程控按键和一个拨轮,丰富了人机交互功能,方便信息观察、界面切换等使用方式。此外还配备了白色外壳,精心设计的包装不仅使板卡日常使用时更加美观也便于板卡的站立以及使用安全。
这个模块是通过Type C的USB接口提供供电、下载以及通信的功能,板上有5V转3.3V,最高支持800mA的电压变换器,在12根引脚上也将5V和3.3V引出,方便对其它外设板供电。
主控芯片:采用树莓派Pico核心芯片RP2040。
扩展板搭载了几款常见传感器和功能模块,包括为初学者准备的麦克风、蜂鸣器、红外收发、霍尔效应开关、加热电阻,为进阶操作准备的温湿度传感器、六轴传感器、接近/环境光/IR传感器、颜色传感器。其中温湿度传感器、六轴传感器、接近传感器、颜色传感器可拆卸为单个模块,通过杜邦线等连接线延伸其使用的空间范围。
硬件还配置了加热电阻,电阻加热时指示灯自动亮起,注意加热电阻处高温烫伤,建议搭配温湿度传感器使用。
实现的功能及图片展示
程序启动时,先展示一张logo图片,拉起接近传感器、温湿度传感器:
然后初始化温度计,此时未进行颜色识别,或未识别到结果,展示颜色为NONE:
然后开始监测温度、湿度,获取了初始的目标温度为30摄氏度,将此类数据展示到屏幕。
开始识别颜色,放上白色卫生纸,识别颜色文字改为“WHITE”,刷新对应的白色表盘,另外,温度计下的地球,地球下部出现小球,展示为白色。
继续识别颜色,放上橙色手机支架,识别颜色文字改为“ORANGE”,刷新对应的橙色表盘,另外,温度计下的地球,地球下部出现小球,展示为橙色。
继续识别颜色,放上粉色的刀把手,识别颜色文字改为“PINK”,刷新对应的粉色表盘,另外,温度计下的地球,地球下部出现小球,展示为粉色。
继续识别颜色,放上反面为黑色的遥控器,识别颜色文字改为“BLACK”,刷新对应的黑表盘,另外,温度计下的地球,地球下部出现小球,展示为黑色。
继续识别颜色,放上蓝色的可折叠网线,识别颜色文字改为“BLUE”,刷新对应的蓝色雪山表盘,另外,温度计下的地球,地球下部出现小球,展示为蓝色。
上位机显示功能,实时绘制图像展示接近传感器收到的数据,距离过近导致蜂鸣器报警,具体可以看视频:
当距离过近,除了蜂鸣器报警外,表盘中温度计“水银”更新为黄色(过近时温度计“水银”部分变为黄色,正常时温度计“水银”部分变为红色)。接近传感器该功能的实际意义为过近传感器报警,防止烫伤(因为温度传感器旁的加热电阻开启时温度过高)。
用户可以使用拨轮设置目标温度“temperature_limit”,拨轮向左可以降低1摄氏度,拨轮向右可以升高1摄氏度。基于PID算法,实现以下效果:当传感器温度低于目标温度,自动开启加热电阻(指示灯亮起);当传感器温度高于目标温度,自动关闭加热电阻(指示灯关闭)。
使用扳机调节温度控制,目标温度大于实时温度,打开加热电阻,拓展版LED开启。
使用扳机调节温度控制,目标温度小于实时温度,关闭加热电阻,拓展版LED关闭。
主要代码片段及说明
颜色传感器判别
读取拓展版传感器信息,查数据手册可以得到。
# 颜色传感器判别
CS_DATA_RED=mma7660.readfrom_mem(0x53,0x13,3)
CS_DATA_GREEN = mma7660.readfrom_mem(0x53,0x0D,3)
CS_DATA_BLUE= mma7660.readfrom_mem(0x53,0x10,3)
X_DATA_RED = (CS_DATA_RED[2]<<16)|(CS_DATA_RED[1]<<8)|CS_DATA_RED[0]
X_DATA_GREEN=(CS_DATA_GREEN[2]<<16)|(CS_DATA_GREEN[1]<<8)|CS_DATA_GREEN[0]
X_DATA_BLUE=(CS_DATA_BLUE[2]<<16)|(CS_DATA_BLUE[1]<<8)|CS_DATA_BLUE[0]
根据颜色表盘切换
elif 20 <= X_DATA_RED <= 50 and 70 <= X_DATA_GREEN <= 130 and 40 <= X_DATA_BLUE <= 70:
MID_Color_now = 14
if MID_Color_now != MID_Color_last:
f_image = open(image_orange, 'rb')#以只读的形式打开墨鸢阁图片
for i in range(1,240):
buf=f_image.read(480)
display.blit_buffer(buf, 1, i, 240, 1)
# 生成温度计序列
tems_x = 0 # 温度计最小值
for i in range(13):
display.text(font1, str(tems_x), 145, 178-i*10)
tems_x=tems_x+10 # 间隔10生成
display.text(font2, "ORANGE" ,144,170) # 颜色,对应手机支架
颜色在屏幕展示与绘制
在每个识别循环中,均检测后设定温度计“水银”颜色。
elif 20 <= X_DATA_RED <= 40 and 70 <= X_DATA_GREEN <= 120 and 70 <= X_DATA_BLUE <= 120:
MID_Color_now = 23
if MID_Color_now != MID_Color_last:
colorREAD = st7789.BLUE #蓝色折叠网线
结束颜色识别后,设定底部识别球颜色。
display.fill_circle(120, 231, 9, colorREAD)#圆心的坐标(120,235),播放识别结果
PID代码
首先解读主函数中的PID代码,基础概念:
P(比例)控制是:输出量的大小与输入误差信号的大小成比例关系的一种控制。
I(积分)控制是:输出量的大小与输入误差信号的积分值成比例关系的一种控制,其主要作用是消除系统的残差
D(微分)控制是:输出量的大小与输入误差信号的微分值成比例关系的一种控制,其主要作用是:在系统平衡后,若存在干扰信号,D(微分)。
以下代码首先定义不同的PID参数,并初始化积分和误差存储值为0。在主循环中,每刷新一次,更新当前误差(实时温度与目标温度差值)、积分值(历史误差累积求和)、微分值(当前温度误差与上一个误差存储值差值),根据已经定义的PID参数,求解输出值。最后根据输出值,判断是否需要启动或关闭加热电阻。
# PID参数
kp = 1.0
ki = 0.1
kd = 0.01
integral = 0 # 积分
last_error = 0
while True:
# 控制加热电阻
error = temperature_limit - current_temperature
integral += error
derivative = error - last_error
output = kp * error + ki * integral + kd * derivative
if output > 0:
Heat_R(1)
display.text(font2,"Heat_R : Open",10,130)
else:
Heat_R(0)
display.text(font2,"Heat_R : Off ",10,130)
屏幕代码
以下代码初始化屏幕,并填充为黑色。使用了st7789PID的库。
# 屏幕
st7789_res = 0
st7789_dc = 1
disp_width = 240
disp_height = 240
spi_sck = Pin(2)
spi_tx = Pin(3)
spi0 = SPI(0, baudrate=4000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)
display = st7789.ST7789(spi0, disp_width, disp_height,
reset=machine.Pin(st7789_res, machine.Pin.OUT),
dc=machine.Pin(st7789_dc, machine.Pin.OUT),
xstart=0, ystart=0, rotation=0)
display.fill(st7789.BLACK)
温湿度传感器读取
以下代码基于数据手册给出的读取方法,首先预先定义传感器,然后在主循环获得传感器的温湿度数据,并不断刷新显示到屏幕以及作为PID控制的参考数据。
# 扫描I2C,初始化
sda = Pin(20)
scl = Pin(21)
mma7660 = machine.I2C(0, sda=sda, scl=scl, freq=400000)
print('I2C has already initialized.')
print(mma7660.scan())
# 温湿度传感器NST30
Read_CMD = bytearray(2)
Read_CMD[0] = 224
Read_CMD[1] = 0
# Periodic mode
Periodic_MODE = bytearray(2)
Periodic_MODE[0] = 39 # 0x27: 10mps
Periodic_MODE[1] = 33 # 0x21: Medium
mma7660.writeto(0x44, Periodic_MODE)
while True:
# 读取当前温度
mma7660.writeto(0x44, Read_CMD)
NST_READ = mma7660.readfrom(0x44, 6)
current_temperature = (NST_READ[0] << 8) | NST_READ[1]
# 显示温度
display.text(font1,"TEMPERATURE="+"%06d"%((NST_READ[0]<<8)|NST_READ[1]) + " C ",20,110)
display.text(font2,"Humidity="+"%06d" %((NST_READ[3]<<8)|NST_READ[4]),10,170)
其他工作
还对st7789库进行修改,该活动给出的文件可以显示“黑底白字”,为便于美观,符合本项目设置的表盘主题功能,所以修改文件,最终可以显示“白底黑字”。
另外,部分刷屏相关的函数,直接附加在st7789PID.py文件内,若感兴趣可以查询。
本项目所有文件已给出。
在st7789PID文件中,更新了若干颜色:
# 颜色定义RGB
ORANGE = const(0xfd20)
BLACK = const(0x0000)
PINK = const(0xf8b2)
NAVY = const(0x000F)
DGREEN = const(0x03E0)
DCYAN = const(0x03EF)
MAROON = const(0x7800)
PURPLE = const(0x780F)
OLIVE = const(0x7BE0)
LGRAY = const(0xC618)
DGRAY = const(0x7BEF)
BLUE = const(0x001F)
GREEN = const(0x07E0)
CYAN = const(0x07FF)
RED = const(0xF800)
MAGENTA = const(0xF81F)
YELLOW = const(0xFFE0)
WHITE = const(0xFFFF)
代码附件内容如下:
本项目表盘设计过程中,采用的霞鹜文楷字体,隶属于一个基于 SIL Open Font License 1.1 许可证发布的开源项目,可以商用。
遇到的主要难题及解决方法
RP2040芯片网络资源丰富、开源氛围浓厚,资源齐全,但是针对该平台硬件仍然有一定的陌生,基于硬禾 “搭配WiFi模块的树莓派RP2040游戏机“平台,快速对该类型固件以及 Micropython 编程下搭建项目进行熟悉,并对GUI的写作进行学习。最终具备了软件端写作的能力。
参考链接:https://www.eetree.cn/platform/1103
· GitHub - picospuch/eetree-mpy-lecture-code
PID端算法,参考了部分网络开源项目。
硬件传感器信息读取方面是主要难题,基于已有的数据手册以及该平台配套视频课程,初步实现了温湿度传感器数据读取。
未来的计划或建议
本项目由于屏幕面积有限,展示过于紧凑,后续可以考虑设计更加美观的仪表盘功能,特别是指针仪表盘的实现,另外,还可以更新触屏交互,比当前交互更加可靠便捷。
本文基于PID控制的算法具备充分的可靠性,但也是较为传统的解决方案,仅仅满足了该任务要求但创新性仍然有限。可以在硬件允许的情况下,选用其他控制算法实现该功能,例如引入一些其他的机器学习控制方案,或者借助于上位机,实现在线强化学习。
对颜色传感器,由于不同物体划过颜色传感器时,RGB数据是动态变化的,结合机器学习训练,可以实现基于颜色传感器的物体识别,如果耦合接近传感器或者其他光传感器,识别效果更为准确。