已使用智能门锁的,可以忽略本文
老式防盗门锁
当时使用小米的微信小程序拍照判断是否可以安装智能门锁,结果是不符合
中间遇到过一次出门丢个垃圾,刚出门关门发现钥匙忘记带了,没有放备用钥匙在门外,只好等朋友带备用钥匙过来(没有叫二房东帮忙,是因为二房东神出鬼没,等愿意带钥匙过来,天都黑了)
钥匙忘记带,手机一般不会忘
本文使用ESP32+MicroPython设置蓝牙控制舵机,达到开门的目的
完整老式门锁开门需要以下物品
-
一个ESP32开发板(成本25元左右,后期可换为12元左右的ESP8266)
-
一个SG90舵机(其他舵机也行,能操作转动就行)(成本8元左右)
-
程序开发辅助用品:USB数据线,杜邦线(默认随开发板配送)
-
门锁设置辅助用品:无痕双面胶,缝衣线(总计10元左右,如已有,则忽略成本)
接线
-
红色电源线接5v5(5v)
-
灰色线接电源(GND)
-
橙色线接引脚GPIO13(本文代码设置的为P13)
当门锁关闭时,舵机固定机翼在起始位置,也就是贴近门锁
只有当收到角度数据时,循环指定角度如180度,带动线的拉动,达成开锁条件,开锁后几秒自动返回初始位置,避免因为电机阻力,一直处理开锁状态,无法手动关闭
先放入依赖库到ESP32
文件名
servo.py
from machine import PWM
import math
# originally by Radomir Dopieralski http://sheep.art.pl
# from https://bitbucket.org/thesheep/micropython-servo
class Servo:
"""
A simple class for controlling hobby servos.
Args:
pin (machine.Pin): The pin where servo is connected. Must support PWM.
freq (int): The frequency of the signal, in hertz.
min_us (int): The minimum signal length supported by the servo.
max_us (int): The maximum signal length supported by the servo.
angle (int): The angle between the minimum and maximum positions.
"""
def __init__(self, pin, freq=50, min_us=600, max_us=2400, angle=180):
self.min_us = min_us
self.max_us = max_us
self.us = 0
self.freq = freq
self.angle = angle
self.pwm = PWM(pin, freq=freq, duty=0)
def write_us(self, us):
"""Set the signal to be ``us`` microseconds long. Zero disables it."""
if us == 0:
self.pwm.duty(0)
return
us = min(self.max_us, max(self.min_us, us))
duty = us * 1024 * self.freq // 1000000
self.pwm.duty(duty)
def write_angle(self, degrees=None, radians=None):
"""Move to the specified angle in ``degrees`` or ``radians``."""
if degrees is None:
degrees = math.degrees(radians)
degrees = degrees % 360
total_range = self.max_us - self.min_us
us = self.min_us + total_range * degrees // self.angle
self.write_us(us)
然后设置默认执行文件main.py
参考代码,可以将角度180,设置为自己需要的角度,随时变换0-180
from machine import Pin
from servo import Servo
# 定义舵机控制对象
my_servo = Servo(Pin(13), max_us=2500)
# 设置舵机转到指定角度
my_servo.write_angle(180)
用无痕双面胶把舵机固定在可以开锁的位置
使用缝衣线一端勾住门把手,一端穿过舵机机翼的小孔并打结固定
注意
选定固定位置前,先实际通电测试开锁的最佳位置并做好标记,然后贴上无痕双面胶
本期所有的操作都从简单的来
之前写过ESP32蓝牙通信,并且已经写微信调试小程序
参考文章
《ESP32使用MicroPython设置低功耗蓝牙广播,通过Chrome Web蓝牙通信》
《ESP32使用MicroPython设置低功耗蓝牙广播,通过微信小程序蓝牙通信》
通过以下步骤
-
设置ESP32蓝牙广播
-
设置监听蓝牙广播收到字符前缀为deg时,执行字符过滤角度数据,并设置对应舵机转动
-
使用已写好的微信小程序DIY硬件 直接手动发送字符测试和开门(后期再优化更为方便的可视化操作)
在蓝牙接收字符的交互中添加判断
# 如果接收到字符为deg前缀,就操作舵机
if message.startswith('deg'):
# 打印要转动的角度
print('deg',message,message[3:])
# 获取要转动的角度(数字)
deg_num=int(message[3:])
# 转动舵机
my_servo.write_angle(deg_num)
# 蓝牙返回数据
ble.send(message)
完整代码
import time
from machine import Pin
from servo import Servo
# 引入依赖
import ubluetooth
# 定义舵机控制对象
my_servo = Servo(Pin(13), max_us=2500)
# 实例化蓝牙
class BLE():
def __init__(self, name):
# 蓝牙名称
self.name = name
# 创建蓝牙实例
self.ble = ubluetooth.BLE()
# 开启蓝牙
self.ble.active(True)
# 蓝牙事件回调
# 参考文档
# https://docs.micropython.org/en/latest/library/bluetooth.html?highlight=irq
self.ble.irq(self.ble_irq)
# 配置蓝牙UUID
self.register()
# 特征和描述符的默认最大大小为 20 个字节,修改允许为100个字节(蓝牙数据的发送和接收字节大小限制)
self.ble.gatts_write(self.rx, bytes(100))
# 蓝牙广播
self.advertiser()
print("已开启蓝牙广播")
# 蓝牙连接成功后回调
def connected(self):
print("connected")
# 蓝牙断开连接后回调
def disconnected(self):
print("disconnected")
# 蓝牙事件回调函数
def ble_irq(self, event, data):
#蓝牙已连接
if event == 1:
print("蓝牙已连接")
# 连接后的执行函数
self.connected()
#蓝牙已断开连接
elif event == 2:
print("蓝牙已断开连接")
# 断开连接后的执行函数
self.advertiser()
self.disconnected()
#蓝牙已发送数据
elif event == 3 :
print("蓝牙已接收到数据")
# 读取二进制数据
buffer = self.ble.gatts_read(self.rx)
# 使用UTF-8格式把二进制数据转为字符串
message = buffer.decode('UTF-8').strip()
# 打印收到的字符数据
print("message",message)
# 对指定的数据做处理并蓝牙返回数据
if message == 'test':
print('test')
ble.send('test')
if message == 'str':
print('str')
ble.send('str')
if message.startswith('deg'):
print('deg',message,message[3:])
deg_num=int(message[3:])
my_servo.write_angle(deg_num)
ble.send(message)
# 注册蓝牙UUID
def register(self):
# 自定义UUID
# 蓝牙服务UUID service_uuid(后续蓝牙建议连接会用到)
NUS_UUID = 'AE25A5C4-4601-143C-12BB-8BC45A18749C'
# 蓝牙接收特征UUId receive_uuid
RX_UUID = 'AE25A5C5-4601-143C-12BB-8BC45A18749C'
# 蓝牙发送特征UUId transmit_uuid
TX_UUID = 'AE25A5C6-4601-143C-12BB-8BC45A18749C'
# UUID组合(一个包含UUID和特征列表的二元元组)
BLE_NUS = ubluetooth.UUID(NUS_UUID)
BLE_RX = (ubluetooth.UUID(RX_UUID), ubluetooth.FLAG_WRITE)
BLE_TX = (ubluetooth.UUID(TX_UUID), ubluetooth.FLAG_NOTIFY)
BLE_UART = (BLE_NUS, (BLE_TX, BLE_RX,))
SERVICES = (BLE_UART, )
# 使用指定的服务配置外围设备
# 文档地址:
# https://docs.micropython.org/en/latest/library/bluetooth.html?highlight=irq#peripheral-role
((self.tx, self.rx,), ) = self.ble.gatts_register_services(SERVICES)
# 发送数据
def send(self, data):
# 向连接的客户端发送通知请求
# 文档地址:
# https://docs.micropython.org/en/latest/library/bluetooth.html?highlight=irq#gatt-client
self.ble.gatts_notify(0, self.tx, data + '\n')
# 蓝牙广播配置
def advertiser(self):
name = bytes(self.name, 'UTF-8')
# 以指定的时间间隔(以微秒为单位)开始广播
# 文档地址
# https://docs.micropython.org/en/latest/library/bluetooth.html?highlight=irq#broadcaster-role-advertiser
self.ble.gap_advertise(100, bytearray('\x02\x01\x02') + bytearray((len(name) + 1, 0x09)) + name)
# 创建一个名为ESP32的蓝牙广播
ble = BLE("Door")
本文有需要可以优化的地方
一.使用伸缩/直轴/往复马达电机
二.使用除了缝衣线以外的其他质量好的线,橡皮筋,尼龙线等
三.设置专用微信小程序,app,web网页等,一键开门,无需填写deg角度参数
四.电池盒,锂电池等外置电源
无需时刻插座通电,只需要加电池,不用时设置睡眠模式,使用时唤醒,保持可持续时间三个月甚至半年以上使用,不用在门附近走线,直接和模块贴在门上
掉电检测器被触发
错误提示信息:
Brownout detector was triggered
这个是在操作舵机转动一次后,就一定会报这个错
可能的原因
-
USB 电缆质量差或太长。
-
您计算机的 USB 端口无法为开发板提供足够的电力。
-
ESP32Cam 有缺陷
-
电路中的其他组件未正确接线,影响电源
本文先试减少了杜邦线的长度,确保线路尽可能短,但是无用
其次更换了USB数据线,更短和质量更好的,但是无用
最后把USB电源从电脑的USB改为了充电宝或者插座上的USB,就可以了,所以本文是供电不足或者电压电流问题
如果遇到上述问题,可尝试更换电源
END.