💡 划重点

  • 主控:ESP32 低功耗双核芯片,板载 Wi‑Fi 方便后期升级联网提醒。 感知:PIR 人体传感器判断桌前是否有人,避免无人时误报。 执行:舵机带动小旗帜升降或轻敲桌面,蜂鸣器发出语音级提示音,OLED 显示作业项与倒计时。 逻辑:以番茄钟为核,作业 25 分钟提醒休息,休息 5 分钟提醒归位;人离开超时自动暂停计时。 **

需求洞察

目标用户:8~15 岁中小学生,尤其是自主管理能力较弱、需要家长远程提醒的孩子。

真实痛点:孩子一坐桌前就容易发呆、磨蹭,家长口头催促容易引起逆反。普通计时器只有声音,孩子离开书桌后仍在空跑,失去提醒意义。家长上班时无法了解孩子是否真正坐在书桌前。

为什么值得做

  1. 把“被动催促”变成“机器提醒”,降低亲子摩擦。
  2. 结合人体感应与番茄钟,离开即暂停,更贴合真实作业情景。
  3. ESP32 可后续通过 MQTT 将桌前人状态发给家长手机,实现轻量远程陪伴。
  4. 硬件门槛低,小学生也能在家长协助下焊接完成,兼具教育属性。

方案设计

感知层

控制层

执行层

日志/联网层(选配)

物料清单

序号 物料 数量 用途 估算单价(元)
1 ESP32‑WROOM‑32E 开发板 1 主控与供电 15
2 0.96 寸 OLED SSD1306 (I²C) 1 显示任务与时间 8
3 HC‑SR501 PIR 人体传感器 1 桌前人体检测 5
4 SG90 微型舵机 1 物理动作提醒 4
5 有源蜂鸣器模块 3.3~5V 1 声音提醒 2
6 轻触按键 + 10kΩ 电阻 3 模式切换/确认 1
7 5V 1A Micro USB 电源线 1 供电 2
8 排针、杜邦线、洞洞板、小旗帜、热缩管 若干 连接与结构 2
合计 39 元

总价 39 元,略低于 40 元预算,剩余 1 元作为胶水扎带备用。

接线与结构

结构安装:将全部模块焊接或用扎带固定在 50×70mm 洞洞板上。PIR 镜头朝前方稍向下,舵机安装在一个 L 型铝片上,带动纸质小旗。OLED 用尼龙柱垫高,方便阅读。底座用亚克力边角料或木块配重,避免倾倒。

核心代码

以下为 Arduino 骨架,可直接编译上传。省略非关键防抖与部分常量。


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ESP32Servo.h>

#define PIR_PIN 18
#define SERVO_PIN 13
#define BUZZER_PIN 27
#define BTN_NEXT 32
#define BTN_OK 33
#define BTN_PAUSE 25

Adafruit_SSD1306 oled(128, 64, &Wire;);
Servo flagServo;

enum State {IDLE, WORK, REST};
State state = IDLE;
unsigned long startTime = 0;
unsigned long pauseTime = 0;
bool paused = false;
int workSec = 25 * 60;
int restSec = 5 * 60;
int currentTimeLeft = workSec;
const char* tasks[] = {"语文", "数学", "英语", "科学"};
int taskIdx = 0;

void setup() {
  pinMode(PIR_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(BTN_OK, INPUT_PULLUP);
  flagServo.attach(SERVO_PIN);
  flagServo.write(0);
  Wire.begin(21, 22);
  Serial.begin(115200);
}

void loop() {
  bool person = digitalRead(PIR_PIN);
  handleButtons();
  if (state == IDLE) {
    if (person && !digitalRead(BTN_OK)) {
      startTimer(WORK);
    }
  } else {
    if (!person) {
      if (!paused) {
        paused = true;
        pauseTime = millis();
      }
      if (millis() - pauseTime > 20000) { // 离开超20秒暂停任务
        state = IDLE;
        paused = false;
      }
    } else {
      if (paused) {
        paused = false;
      }
      updateTimer();
    }
  }
  updateDisplay();
  delay(200);
}

void startTimer(State s) {
  state = s;
  startTime = millis();
  currentTimeLeft = (s == WORK) ? workSec : restSec;
  paused = false;
}

void updateTimer() {
  unsigned long elapsed = (millis() - startTime) / 1000;
  if (elapsed >= currentTimeLeft) {
    triggerAlarm();
    if (state == WORK) startTimer(REST);
    else state = IDLE;
  }
}

void triggerAlarm() {
  for (int i = 0; i < 5; i++) {
  }
}

void handleButtons() {
  if (!digitalRead(BTN_NEXT)) {
    taskIdx = (taskIdx + 1) % 4;
    delay(300);
  }
  if (!digitalRead(BTN_PAUSE)) {
    paused = !paused; delay(300);
  }
}

void updateDisplay() {
  oled.clearDisplay();
  oled.setTextSize(2);
  oled.setCursor(0,0);
  oled.print(tasks[taskIdx]);
  oled.setCursor(70,0);
  oled.print(state==WORK?"工":"停");
  oled.setTextSize(1);
  oled.setCursor(0,30);
  oled.print("剩余:");
  long remain = currentTimeLeft - ((millis()-startTime)/1000);
  oled.print(remain/60); oled.print("分");
  oled.print(remain%60); oled.print("秒");
  oled.setCursor(0,50);
  oled.print(digitalRead(PIR_PIN)?"有人":"无人");
  oled.display();
}

调试步骤

  1. 空板测试:先不安装舵机和蜂鸣器,上传代码后通过串口监视器查看 PIR 状态,手在传感器前晃动,确认 GPIO18 电平变化。
  2. OLED 显示检查:确认 I²C 地址为 0x3C,如果屏幕无显示,运行 I²C Scanner 脚本检查接线。
  3. 舵机角度校准:将 flagServo.write(80) 逐步调整为适合旗帜抬起的角度,确保不卡住结构。
  4. 蜂鸣器响度:若太吵,可在回路中串接 100Ω 电阻或通过 PWM 降低占空比。
  5. 离开暂停机制:设定 pauseTime 阈值为 5 秒进行快速测试,确认人走开 OLED 显示“停”且计时归零。
  6. 完整流程:从 IDLE 按下确认键 → 25 分钟作业 → 触发提醒 → 自动进入 5 分钟休息 → 休息结束归零。多次循环观察有无计时溢出。

设计图

桌面作业提醒机器人结构flow
1
感知输入 (PIR人体检测 | 按键输入)
2
控制处理 (ESP32 番茄钟逻辑 | 任务队列)
3
执行反馈 (OLED显示 | 舵机动作 | 蜂鸣器提示)
4
数据上报 (可选Wi-Fi MQTT 上报桌前状态)