- 项目介绍及市场应用介绍
市面上现有的窗帘控制器大多体积巨大而且价格昂贵。说实话我自己觉得拉动窗帘而已,并不需要那么大功率的电机,整体体积应该可以缩小。因此就有了这个项目。
- 项目设计思路
电机拉动窗帘时确实需要一定的扭矩,但是对速度的要求却并不高,因此我们可以使用合适比例的减速机,来实现低功率小体积也可以正常驱动窗帘。
- 项目原理图解释
原理图及后面的PCB使用Kicad进行绘制。先看一下原理图:
设计分为两部分,第一个是ESP32-C3最小系统,这个在官网上就有开发板的原理图可以参考,官方也提供了硬件设计手册,照着画就行难度不大。另外一个是步进电机驱动部分,就是右边这一块。由于使用了现成的A4988模块,因此外围也非常简单,参考一些开源的3D打印机控制板,就可以轻松绘制。
具体的原理图在阶段一中已经进行了非常详细的介绍,这里只是在Kicad中重新抄了一遍而已,并没有做任何改动。想要了解的小伙伴直接看阶段一就好,这边就不再重复了。
- 设计中用到规定厂商的元器件介绍
1,乐鑫ESP32-C3 MINI 模块:
- 集成 ESP32-C3 芯片,RISC-V 32 位单核处理器,时钟频率高达 160 MHz
- 行业领先的低功耗性能和射频性能
- 内置 400 KB SRAM、384 KB ROM 存储空间,并支持多个外部 SPI、Dual SPI、Quad SPI、QPI flash
- 完善的安全机制:基于 RSA-3072 算法的安全启动、基于 AES-128-XTS 算法的 flash 加密、创新的数字签名和 HMAC 模块、支持加密算法的硬件加速器
- 丰富的通信接口及 GPIO 管脚,可支持多种场景及复杂的应用
- 通过 RF 认证以及软件协议认证
2,Onsemi安森美NCP114ASN330T1G:
NCP114是一种300毫安线性稳压器,为工程师提供了非常稳定、精确、噪声低的电压,适用于空间受限、噪声敏感的应用。为了优化电池供电的便携式应用性能,NCP114采用动态静态电流调节技术,在无负载时具有非常低的待机电流消耗。主要性能参数如下:
• 工作输入电压范围:1.7 V至5.5 V
• 可选固定电压选项:0.75 V至3.6 V。其他电压选项请联系工厂。
• 待机电流极低,典型值为50 A。
• 待机电流消耗:典型值为0.1 A。
• 很小的压差:在300 mA时典型值为135 mV。
• 室温下的精度为±1%。
• 高功率供应纹波抑制:在1 kHz时为75 dB。
• 具有热关断和电流限制保护功能。
• 与1uF陶瓷输出电容稳定。
• 提供UDFN和TSOP封装。
• 无铅器件。
- PCB绘制打板介绍及遇到的问题和解决方法
按照原理图绘制好的PCB如下:
绘制PCB的时候要注意,USB信号速度相对较快,不要拉线拉的太长,以免影响信号质量。另一个就是旁路电容尽可能靠近电源引脚,别的就没有什么要注意的了。由于PCB是手焊,因此元件之间的距离不要太过于紧凑,会给焊接带来很多不必要的麻烦。
- 关键代码及说明
这个项目我使用了两种控制方式,一种是手动控制,通过手机进行远程操纵窗帘的开关;另一种是自动控制,会自动在天亮时开启,天黑后关闭,可以每天在自然光的沐浴下醒来。
首先介绍一下手动控制代码,代码是用Micropython实现的:
speed = 0.001
distance = 2000
ssid = 'SSID'
password = 'PWD'
from machine import Pin, ADC
from time import sleep
import network
import socket
adc = ADC(Pin(1))
stp = Pin(3, Pin.OUT)
en = Pin(8, Pin.OUT)
dr = Pin(2, Pin.OUT)
en.value(1)
dr.value(0)
def move(_dr):
dr.value(_dr)
en.value(0)
for i in range (distance):
stp.value(1)
sleep(speed)
stp.value(0)
sleep(speed)
en.value(1)
station = network.WLAN(network.STA_IF)
station.active(True)
try:
station.connect(ssid, password)
except:
pass
while station.isconnected() == False:
pass
print('Connection successful')
print(station.ifconfig())
代码很短,这里简单说明一下。一开始是一些必要参数的配置。电机的速度和步数在这里设置。由于使用步进电机,因此不需要反馈传感器,也可以精确控制转动的速度和角度。下面就是WIFI的接入点和密码设置。完成这个后大家就可以直接运行程序测试了。
下面是步进电机驱动的引脚配置,引脚配置好后将步进电机控制封装成一个单独的方法,方便下面进行调用。接下来是WIFI相关的配置,完成这部分后,我们就可以开始功能代码的编写。
manual = 0
def web_page():
if manual == 1:
window_state="ON"
else:
window_state="OFF"
html = """<html><head> <title>ESP Web Server</title> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,"> <style>html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;}.button{display: inline-block; background-color: #e7bd3b; border: none;
border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}
.button2{background-color: #4286f4;}</style></head><body> <h1>ESP Web Server</h1>
<p>Window State: <strong>""" + window_state + """</strong></p><p><a href="/?led=on"><button class="button">ON</button></a></p>
<p><a href="/?led=off"><button class="button button2">OFF</button></a></p></body></html>"""
return html
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 80))
s.listen(5)
在这里我做了个非常简易的HTML界面,整个HTML代码也就短短几行。HTML做好后,开始主循环部分,这里实现的功能就是当我们点击打开按键时,驱动电机完成以预先配置好的速度及步数进行正转;如果点击关闭按钮,进行相对应的反转。
while True:
conn, addr = s.accept()
print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
request = str(request)
print('Content = %s' % request)
led_on = request.find('/?led=on')
led_off = request.find('/?led=off')
if led_on == 6:
print('Window ON')
manual = 1
move(True)
if led_off == 6:
print('Window OFF')
manual = 0
move(False)
response = web_page()
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.sendall(response)
conn.close()
通过WEB进行手动控制的代码到这里就结束了。下面是自动控制的代码。代码的前半部分配置是和上面完全一样的,只是删去了联网的部分,并增加了一个传感器接口:
speed = 0.001
distance = 2000
from machine import Pin, ADC
from time import sleep
adc = ADC(Pin(1))
stp = Pin(3, Pin.OUT)
en = Pin(8, Pin.OUT)
dr = Pin(2, Pin.OUT)
en.value(1)
dr.value(0)
def move(_dr):
dr.value(_dr)
en.value(0)
for i in range (distance):
stp.value(1)
sleep(speed)
stp.value(0)
sleep(speed)
en.value(1)
自动控制的话需要一个光敏电阻传感器来进行光强度感应,我们把它接在Pin1。由于这是个模拟量传感器,因此我们需要在代码中给定一个阈值,来区分亮和暗。在主循环中,当光从暗转变为亮时,驱动电机正转;反之则驱动电机反转:
old = False
state = False
while 1:
val = adc.read_u16() # read a raw analog value in the range 0-65535
if val < 40000:
state = True
else:
state = False
if state != old:
move(state)
old = state
- 功能展示及说明
由于电路板是双面板,且焊接难度不大,因此特别选用了一些平时不会用的特殊颜色:
电路板焊接完成后,并安装上A4988模块后,成品是这个样子:
步进电机按照阶段一的计划,使用的是自带减速机的电机。但问题是这个电机是五线电机,与常规的42步进电机出线不一样,所使用的驱动也不一样。但好在可以比较简单的将五线四相电机改为四线两相电机,只需要打开盖,去除中间的抽头,并且切短两组相线圈之间的连接即可。
做好这一切后,把电机插上控制板,整个系统就完成啦。
为了演示方便,我用寄来的快递箱切了一个小房子,上面开个口作为窗户,用餐巾纸做窗帘。电机实际的扭矩完全可以拉动重得多的东西,在这里我使用的是5V USB电压给步进电机驱动供电。而实际上A4988可以耐受非常高的电压,我实测24V都不在话下。如果负载变大,或者需要电机以更高的速度运行,我们只需要外接独立供电给A4988模块即可。
- 对本活动的心得体会(包括意见或建议),及整个设计过程中遇到的难点和解决方法
通过这次项目,学到了很多东西,但也确实留下了一些遗憾,没有想好要如何去处理。比如说我将自动控制和手动控制作为两套独立的功能进行开发,并没有合并。相当于说如果是商品的话,那么就得区分为两个版本,要么是自动版,要么是联网手动版。我在写代码的时候曾经尝试将两者合并,但发现这会带来新的问题,比如说当两个控制同步产生时,要如何界定优先级?当一个控制渠道已经进行了控制,如何避免另一个渠道重复进行动作?这一定可以通过一系列的二元变量进行状态的判断来实现,但是我能力有限,绕了半天把自己都绕晕了也没绕出来。那最后的这个问题就留给大佬们来发挥吧。