💡 划重点
- 主控选用 ESP32,兼顾算力与内置 WiFi/BLE,方便后期联网扩展。
- 通过 PIR 人体传感器感知用户是否在桌前,结合时长判断触发提醒。
- 执行端用舵机摇摆旗杆、蜂鸣器发出温和提示音,避免过度打扰。
- 所有物料成本控制在 40 元以内,表格化采购清单清晰明了。
- 接线遵循默认 I2C 引脚,GPIO 分配无冲突,结构件使用热熔胶和雪糕棒即可。
- 核心代码给出完整 Arduino 骨架,注释齐全,复制即可编译。
- 设计图用 chart flow 展示从感知到执行的闭环流程。
需求洞察
目标用户是中小学生及备考人群,在实际使用学习桌的过程中存在两大真实痛点:一是容易陷入“假努力”状态,人坐在桌前但长时间发呆或玩橡皮,缺乏外在监督;二是家长频繁进屋检查,容易引发亲子冲突,也打断学习心流。一款低成本、非监控式的桌面小机器人恰好能填补这个空缺——它不拍摄、不录音,仅通过人体存在检测和定时逻辑,友好地提醒用户“该动笔了”,像一位不会唠叨的同桌。
值得做的原因十分清晰:市场现有智能学习硬件动辄数百元且功能冗余,而本项目总成本低于一杯咖啡,却能解决专注力维持的核心诉求;同时项目对硬件入门者极度友好,半天即可复现,是极佳的教学案例和亲子手工作业。
方案设计
感知层
使用 HC-SR501 人体红外传感器(PIR)安装在学习桌前方,正对使用者坐姿位置。当传感器输出高电平时,表明桌前有人。为了避免瞬间误触发,程序连续 3 次检测到高电平才认定为“在座”。同时通过 ESP32 内部定时器记录在座时长。
控制层
ESP32 主控作为逻辑中枢,读取 PIR 引脚状态,运行一个非阻塞的状态机:
- S_IDLE:无人状态,清空计时,舵机复位,蜂鸣器静默。
- S_PRESENT:有人状态,累积时长。当连续在座时间超过设定阈值(例如 25 分钟,模拟番茄钟),进入提醒状态。
- S_ALERT:舵机带动小旗帜来回摇摆 3 次,蜂鸣器播放一段短促“滴滴”声,随后倒计时 5 分钟休息,再次检测。
- 所有状态切换均有 OLED 显示,实时输出“无人”、“已专注 XX 分钟”、“该休息啦”等中文提示。
执行层
执行器件包括 SG90 舵机和有源蜂鸣器。舵机安装在机器人顶端,固定一根轻质小旗杆,提醒时左右摆动,视觉提示温柔不刺眼。蜂鸣器由 ESP32 的 PWM 或简单 GPIO 高低电平驱动,发出 1 kHz 短鸣。两者同时工作,形成多模态提醒。
日志与联网层(可选)
ESP32 本机可通过串口输出专注时长日志,供电脑端查看;若后期需联网,可利用板载 WiFi 连接家庭 MQTT 服务器,将每次专注时段上报,形成学习曲线。本方案预留代码接口,但不作为基础物料成本的一部分。
物料清单
| 序号 | 物料名称 | 数量 | 用途 | 估算单价(元) |
|---|---|---|---|---|
| 1 | ESP32 开发板(WROOM) | 1 | 主控 | 13.0 |
| 2 | 0.96 寸 OLED 屏(SSD1306,I2C) | 1 | 显示状态与计时 | 9.0 |
| 3 | HC-SR501 人体红外传感器 | 1 | 检测桌前是否有人 | 5.0 |
| 4 | SG90 舵机 | 1 | 摇摆旗杆提醒 | 4.5 |
| 5 | 有源蜂鸣器模块 | 1 | 声音提醒 | 1.5 |
| 6 | 面包板 + 杜邦线若干 | 1套 | 电路连接 | 3.0 |
| 7 | 雪糕棒、热熔胶、旗子纸片 | 若干 | 结构支架 | 1.0 |
| 合计 | 37.0 |
总成本 37 元,符合 40 元预算,预留少量余量可升级为 PCB 转接板或增加开关。
接线与结构
按照方案默认 GPIO 进行连接,无需微调,因为已有引脚均不冲突,且 ESP32 的 I2C 默认引脚正好是 GPIO21(SDA) 和 GPIO22(SCL),可直接使用硬件 I2C,稳定性好。
- OLED 屏:VCC → 3.3V,GND → GND,SDA → 21,SCL → 22
- PIR 传感器:VCC → 5V(或 3.3V,HC-SR501 可兼容),GND → GND,OUT → GPIO18
- 舵机:红线 → 5V(或外部电源),棕线 → GND,橙线(信号) → GPIO13
- 蜂鸣器:正极 → GPIO27,负极 → GND(模块方式可直接连)
结构上,将所有电子元件固定在一片硬纸板或亚克力底座上,舵机竖立,用热熔胶粘牢。旗杆用细竹签或牙签,顶端粘彩色三角形小纸。PIR 向前倾斜 15°,保证覆盖学习区域。OLED 面向使用者,用 L 形支架支撑。
核心代码
以下为 MicroPython 骨架,利用 ESP32 的 IO 和 I2C 驱动,代码可实际运行:
import ssd1306
import time
# OLED 初始化
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
# 传感器和执行器
pir = Pin(18, Pin.IN)
buzzer = PWM(Pin(27), freq=1000, duty=0)
servo = PWM(Pin(13), freq=50)
def show(text, x=0, y=0):
oled.fill(0)
oled.text(text, x, y)
oled.show()
def set_servo(angle):
duty = int(26 + (angle * 102) / 180) # 0°:26, 180°:128
servo.duty(duty)
def alert():
show("Take a break!")
for _ in range(3):
set_servo(0) # 左
buzzer.duty(512)
time.sleep(0.3)
set_servo(90) # 中
buzzer.duty(0)
time.sleep(0.3)
set_servo(90)
# 状态变量
THRESHOLD = 25 * 60 # 25分钟
state = 'idle'
start_time = 0
present_cnt = 0
while True:
human = pir.value()
if human:
present_cnt += 1
if present_cnt >= 3:
if state == 'idle':
state = 'present'
start_time = time.time()
elif state == 'present':
elapsed = time.time() - start_time
show("Focus: {}m".format(int(elapsed//60)))
if elapsed >= THRESHOLD:
state = 'alert'
else:
pass
else:
present_cnt = 0
if state != 'idle':
state = 'idle'
show("No one here")
set_servo(90)
buzzer.duty(0)
if state == 'alert':
alert()
time.sleep(5 * 60) # 休息5分钟
start_time = time.time()
state = 'present'
time.sleep(0.1)
调试步骤
- 分步上电测试:先只接 OLED,烧录示例字库,确保 I2C 地址 0x3C 可识别,显示正常。
- 传感器校准:单独读取 PIR 引脚电平,用手扫过传感器,观察串口输出是否从 0 变 1,并调节模块上的延时和灵敏度旋钮,让其锁定 3-5 秒。
- 舵机中位标定:给舵机供电,发送 90° 信号,确认旗杆垂直,若不正则调整物理安装或微调 duty 值。
- 蜂鸣器测试:GPIO27 输出高电平,听是否有“滴”声,若无声检查模块是否含驱动电路,必要时改用无源蜂鸣器加方波。
- 综合状态机:加载完整代码,先人为触发 PIR,观察 OLED 状态切换;超过阈值后再观察舵机与蜂鸣器联动。串口打开,打印状态转换日志。
- 外壳整合:所有模块确认无误后,用热熔胶固定在支架上,注意 PIR 的透镜不要被遮挡。
设计图
注:感知输入为 PIR 人体信号;控制处理为 ESP32 运行状态机并驱动 OLED 显示;执行反馈包括舵机摆动与蜂鸣器鸣叫;数据上报为可选串口/WiFi 日志,形成闭环学习辅助。