8浏览
查看: 8|回复: 8

[ESP8266/ESP32] 【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯

[复制链接]
原标题
《【花雕动手做】ESP32-S3 + MimiClaw 实战:通过飞书自然语言控制多色呼吸灯,打造炫酷嵌入式 AI 灯效》
——从单色点亮到多色呼吸,手把手教你扩展嵌入式 AI Agent 的“动态表情”


引言

在前面的实战中,我们已经实现了通过飞书发送“红”“绿”“蓝”等指令,让 ESP32‑S3 板载的 WS2812 RGB LED 瞬间切换颜色。然而,静态的常亮灯效终究缺少一点“灵气”。呼吸灯——那种平滑渐亮渐灭的效果,不仅能提供视觉反馈,更是嵌入式设备与人之间一种优雅的交互语言。

这里将详细介绍如何在 MimiClaw 框架下,为你的嵌入式 AI Agent 增加多色呼吸灯功能。你将看到:

- 如何设计一个支持任意 RGB 颜色的呼吸灯任务

- 如何将飞书自然语言指令(如“蓝色呼吸”“停止呼吸”)映射到对应的工具调用

- 如何通过预处理机制绕过 LLM,实现毫秒级响应的直接控制

- 完整的代码实现与扩展思路

本文假定你已经完成了开源项目迷你小龙虾 MimiClaw 的基础部署(包括Wi‑Fi、飞书、LLM 与搜索 API 配置等),并实现了基本的颜色控制。如未完成,请先参考前序文章。


【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图1

驴友花雕  高级技神
 楼主|

发表于 2 小时前

【花雕】ESP32-S3 + MimiClaw 实战:飞书控制多色呼吸灯

一、呼吸灯的原理与设计目标


1.1 呼吸灯效果

呼吸灯的核心是亮度按周期性规律变化。对于 WS2812 这类全彩 LED,我们可以保持色调不变(例如红色),仅改变亮度值;也可以让整个色环循环,实现彩虹呼吸。

本文实现的目标:

- 支持任意 RGB 颜色的呼吸效果

- 通过飞书自然语言启动/停止不同颜色的呼吸

- 呼吸过程中不阻塞其他任务(如飞书消息接收)

- 响应速度毫秒级,不依赖 LLM API


1.2 技术选型

- 硬件:ESP32‑S3 开发板 + 板载 WS2812(GPIO 48)

- 框架:MimiClaw(基于 ESP‑IDF 5.5)

- 驱动:ESP‑IDF 官方 led_strip 组件(基于 RMT 外设)

- 任务调度:FreeRTOS 独立任务实现呼吸循环,不阻塞主循环


回复

使用道具 举报

驴友花雕  高级技神
 楼主|

发表于 2 小时前

【花雕】ESP32-S3 + MimiClaw 实战:飞书控制多色呼吸灯

二、核心代码实现

2.1 呼吸灯任务的设计

呼吸灯需要一个独立的任务来不断更新 LED 亮度。为了支持任意颜色,任务中使用全局变量存储当前呼吸的目标 RGB 值,并实时计算当前亮度对应的 RGB 分量。

  1. static TaskHandle_t s_breathing_task = NULL;
  2. static bool s_breathing_enabled = false;
  3. static uint8_t s_breathing_r = 255;
  4. static uint8_t s_breathing_g = 0;
  5. static uint8_t s_breathing_b = 0;
  6. static void breathing_task(void *arg)
  7. {
  8.     int direction = 1;      // 1: 亮度递增,-1: 递减
  9.     int brightness = 0;     // 当前亮度 0-255
  10.     const int step = 5;     // 每次变化的步长
  11.     const int delay_ms = 20; // 每步延时 20ms,一个完整周期约 5 秒
  12.     while (s_breathing_enabled) {
  13.         brightness += direction * step;
  14.         if (brightness >= 255) {
  15.             brightness = 255;
  16.             direction = -1;
  17.         } else if (brightness <= 0) {
  18.             brightness = 0;
  19.             direction = 1;
  20.         }
  21.         // 根据目标颜色和当前亮度比例计算实际 RGB
  22.         uint8_t r = (s_breathing_r * brightness) / 255;
  23.         uint8_t g = (s_breathing_g * brightness) / 255;
  24.         uint8_t b = (s_breathing_b * brightness) / 255;
  25.         ws2812_set(r, g, b);
  26.         vTaskDelay(pdMS_TO_TICKS(delay_ms));
  27.     }
  28.     // 任务退出前关闭 LED
  29.     ws2812_set(0, 0, 0);
  30.     s_breathing_task = NULL;
  31.     vTaskDelete(NULL);
  32. }
复制代码

关键点:

- 亮度使用线性增减,简单有效。如需更平滑的曲线,可改为正弦或指数映射。

- 任务每次迭代都会重新计算 RGB,因此可以在呼吸过程中随时改变目标颜色(但本实现要求先停止再重新启动)。


2.2 启动与停止接口

为了便于外部调用,封装了 breathing_start 函数,并注册为工具:

  1. static esp_err_t breathing_start(uint8_t r, uint8_t g, uint8_t b, char *out, size_t len)
  2. {
  3.     if (s_breathing_task != NULL) {
  4.         snprintf(out, len, "Breathing already running, stop first");
  5.         return ESP_FAIL;
  6.     }
  7.     s_breathing_r = r;
  8.     s_breathing_g = g;
  9.     s_breathing_b = b;
  10.     s_breathing_enabled = true;
  11.     BaseType_t ret = xTaskCreate(breathing_task, "breathing", 2048, NULL, 5, &s_breathing_task);
  12.     if (ret == pdPASS) {
  13.         snprintf(out, len, "Breathing started (R=%d,G=%d,B=%d)", r, g, b);
  14.         return ESP_OK;
  15.     } else {
  16.         s_breathing_enabled = false;
  17.         snprintf(out, len, "Failed to start breathing task");
  18.         return ESP_FAIL;
  19.     }
  20. }
复制代码


停止函数则设置标志位,并等待任务自行退出:

  1. static esp_err_t tool_breathing_stop_execute(const char *in, char *out, size_t len)
  2. {
  3.     if (s_breathing_task == NULL) {
  4.         snprintf(out, len, "Breathing not running");
  5.         return ESP_OK;
  6.     }
  7.     s_breathing_enabled = false;
  8.     for (int i = 0; i < 50 && s_breathing_task != NULL; i++) {
  9.         vTaskDelay(pdMS_TO_TICKS(10));
  10.     }
  11.     snprintf(out, len, "Breathing stopped");
  12.     return ESP_OK;
  13. }
复制代码


2.3 注册工具到 MimiClaw

在 tool_registry.c 中注册两个工具:

  1. mimi_tool_t breath_start = {
  2.     .name = "breathing",
  3.     .description = "Start red breathing effect",
  4.     .input_schema_json = "{"type":"object","properties":{},"required":[]}",
  5.     .execute = tool_breathing_start_execute,
  6. };
  7. register_tool(&breath_start);
  8. mimi_tool_t breath_set = {
  9.     .name = "breathing_set",
  10.     .description = "Start breathing with specific RGB color",
  11.     .input_schema_json = "{"type":"object","properties":{"r":{"type":"integer"},"g":{"type":"integer"},"b":{"type":"integer"}},"required":["r","g","b"]}",
  12.     .execute = tool_breathing_set_execute,
  13. };
  14. register_tool(&breath_set);
  15. mimi_tool_t breath_stop = {
  16.     .name = "breathing_stop",
  17.     .description = "Stop breathing effect",
  18.     .input_schema_json = "{"type":"object","properties":{},"required":[]}",
  19.     .execute = tool_breathing_stop_execute,
  20. };
  21. register_tool(&breath_stop);
复制代码


其中 tool_breathing_set_execute 负责解析 JSON 参数并调用 breathing_start。

回复

使用道具 举报

驴友花雕  高级技神
 楼主|

发表于 2 小时前

【花雕】ESP32-S3 + MimiClaw 实战:飞书控制多色呼吸灯

三、自然语言指令预处理

为了提高响应速度并避免 LLM 理解偏差,我们在 agent_loop.c 中增加预处理函数,直接匹配飞书消息中的关键词,并调用对应的工具。

3.1 匹配规则设计

  1. static bool try_direct_command(const char *content, char *output, size_t output_size)
  2. {
  3.     // 去除首尾空白
  4.     // ...
  5.     // 匹配“蓝色呼吸”、“绿色呼吸”等
  6.     if (strstr(content, "蓝色呼吸") != NULL || (strstr(content, "蓝") && strstr(content, "呼吸"))) {
  7.         tool_registry_execute("breathing_set", "{"r":0,"g":0,"b":255}", output, output_size);
  8.         return true;
  9.     }
  10.     if (strstr(content, "绿色呼吸") != NULL || (strstr(content, "绿") && strstr(content, "呼吸"))) {
  11.         tool_registry_execute("breathing_set", "{"r":0,"g":255,"b":0}", output, output_size);
  12.         return true;
  13.     }
  14.     if (strstr(content, "红色呼吸") != NULL || (strstr(content, "红") && strstr(content, "呼吸"))) {
  15.         tool_registry_execute("breathing", "{}", output, output_size);  // 红色呼吸默认工具
  16.         return true;
  17.     }
  18.     // 纯“呼吸”默认为红色
  19.     if (strstr(content, "呼吸") != NULL && strstr(content, "停止") == NULL) {
  20.         tool_registry_execute("breathing", "{}", output, output_size);
  21.         return true;
  22.     }
  23.     // 停止呼吸
  24.     if (strstr(content, "停止呼吸") != NULL || strstr(content, "关呼吸") != NULL) {
  25.         tool_registry_execute("breathing_stop", "{}", output, output_size);
  26.         return true;
  27.     }
  28.     // ... 其他颜色指令(红、绿、蓝、灭等)
  29.     return false;
  30. }
复制代码


3.2 集成到主循环

在 agent_loop_task 中,消息入队后首先调用 try_direct_command,如果匹配成功则直接回复并跳过 LLM 调用:

  1. if (try_direct_command(msg.content, direct_response, sizeof(direct_response))) {
  2. ESP_LOGI(TAG, "Direct command matched, executing tool and responding");
  3. // 构造回复消息并推送
  4. continue;
  5. }
  6. // 否则走正常 LLM 流程
复制代码


这种设计让固定指令获得毫秒级响应,同时保留了 LLM 处理复杂自然语言的能力。


回复

使用道具 举报

驴友花雕  高级技神
 楼主|

发表于 2 小时前

【花雕】ESP32-S3 + MimiClaw 实战:飞书控制多色呼吸灯

四、测试与效果

【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图1
回复

使用道具 举报

驴友花雕  高级技神
 楼主|

发表于 1 小时前

【花雕】ESP32-S3 + MimiClaw 实战:飞书控制多色呼吸灯

五、实验结果记录:手机飞书通信截图与ESP32S3开发板板载WS2812的点灯情况(视频)

【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图1

【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图2

【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图3

【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图4

【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图7

【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图6

【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图8

【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图5

【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图9
回复

使用道具 举报

驴友花雕  高级技神
 楼主|

发表于 1 小时前

【花雕】ESP32-S3 + MimiClaw 实战:飞书控制多色呼吸灯

本帖最后由 驴友花雕 于 2026-4-7 05:36 编辑

实验动图与视频

【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图2
【花雕】ESP32-S3 + MimiClaw 实战:手机飞书控制多色呼吸灯图1


实验视频记录
【【花雕动手做】ESP32-S3 + MimiClaw 实战:通过飞书自然语言控制多色呼吸灯,打造炫酷嵌入式 AI 灯效——从单色点亮到多色呼吸的跨越】

https://www.bilibili.com/video/BV1kBDbB2ELZ/?share_source=copy_web&vd_source=371a292a55e5ca9be994cbb4a86cc987





回复

使用道具 举报

驴友花雕  高级技神
 楼主|

发表于 1 小时前

【花雕】ESP32-S3 + MimiClaw 实战:飞书控制多色呼吸灯

六、扩展与优化方向

1、呼吸速度调节

可在 breathing_set 工具中增加 speed 参数,动态调整 delay_ms。

2、彩虹呼吸

编写一个任务让 HSV 色相随时间线性增加,实现七彩渐变呼吸。

3、传感器联动

例如温度高于 30°C 时自动启动红色呼吸报警,低于 20°C 启动蓝色呼吸。

4、多灯珠级联

如果你的 WS2812 灯带有多个灯珠,可以扩展 max_leds 参数,并实现流水呼吸效果。

5、Web 控制面板

注:经测试,MimiClaw 自带的 Web 门户(http://192.168.4.1)当前出现“invalid link”报错,暂时无法正常访问。后续可排查网络配置或固件问题,修复后可在 Web 门户增加呼吸灯控制按钮,提供图形化操作。

6、定时呼吸

利用 cron_add 工具,设置“每天 19:00 启动橙色呼吸,22:00 停止”,实现智能氛围灯。

回复

使用道具 举报

驴友花雕  高级技神
 楼主|

发表于 1 小时前

【花雕】ESP32-S3 + MimiClaw 实战:飞书控制多色呼吸灯

六、总结

本文详细介绍了如何在 MimiClaw 嵌入式 AI Agent 框架上实现多色呼吸灯功能。通过 FreeRTOS 独立任务、工具注册和自然语言预处理,这里实现了:

- 任意 RGB 颜色的呼吸效果

- 飞书自然语言直接控制(支持中英文、混合词)

- 毫秒级响应,不消耗 LLM API

- 清晰的模块化代码,易于扩展

呼吸灯只是一个开始。同样的模式可以用于控制舵机、步进电机、显示屏等任何硬件外设。当你能够通过飞书聊天框让硬件“活”起来时,你已经掌握了嵌入式 AI Agent 的精髓——让 AI 不再局限于屏幕,而是真正融入物理世界。


项目源码:基于 MimiClaw 二次开发,欢迎 fork 和贡献。

如果你在实现过程中遇到任何问题,欢迎在评论区留言交流。


本文为“花雕学编程”与“花雕动手做”系列博客之一,聚焦嵌入式 AI Agent 、物联网与各种开源硬件落地控制的交叉实践。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2026 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail