在这里插入图片描述

原标题
【花雕动手做】ESP32-S3 + MimiClaw 实战:为板载 WS2812 添加循环红绿蓝与彩虹灯效果
——从静态颜色到动态光效,让你的嵌入式 AI Agent 拥有更丰富的视觉反馈

概述

适用硬件:ESP32-S3 开发板(板载 WS2812 RGB LED)
依赖框架:MimiClaw 嵌入式 AI Agent 框架
核心功能:实现 WS2812 循环红绿蓝、平滑彩虹渐变两种动态灯效,支持飞书自然语言指令控制,毫秒级响应无 LLM 依赖
基本定位:实战开发指南,包含完整设计思路、代码实现、编译测试与扩展方案

引言

在前期教程中,我们已完成飞书控制 WS2812 静态常亮与多色呼吸灯功能。为进一步丰富嵌入式 AI Agent 的视觉反馈与交互体验,本实战将进阶实现两种炫酷动态灯效:
循环红绿蓝:红→绿→蓝顺序循环显示,固定间隔切换
彩虹灯:基于 HSV 色彩空间,实现全色环平滑渐变
这里基于 FreeRTOS 独立任务 实现灯效渲染,保证运行流畅不阻塞主流程;同时集成飞书自然语言指令控制,支持一键启动 / 停止,多灯效互斥避免硬件冲突。

在这里插入图片描述

一、动态灯效设计方案

1.1 核心灯效定义

在这里插入图片描述

1.2 系统集成设计
任务互斥机制:启动任意灯效时,自动停止其他动态效果(呼吸灯 / 循环灯 / 彩虹灯),避免多任务同时控制 WS2812 导致冲突
状态管理:通过全局标志位 + 任务句柄,精准控制灯效启动 / 停止
指令优化:在 agent_loop.c 实现指令硬匹配,绕过 LLM,实现毫秒级响应
退出逻辑:停止灯效后,LED 默认熄灭,释放硬件资源

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、核心代码实现
所有代码基于 MimiClaw 现有 WS2812 驱动扩展,无额外硬件依赖。
2.1 工具注册:tool_registry.c
该文件实现灯效任务创建、执行、停止逻辑,是核心功能模块。
2.1.1 全局变量声明
在文件头部(呼吸灯变量区域)新增动态灯效统一变量:

// ====================== 动态灯效:统一声明所有变量 ======================
// 呼吸灯原有变量
static TaskHandle_t s_breathing_task = NULL;
static bool s_breathing_enabled = false;
static uint8_t s_breathing_r = 255;
static uint8_t s_breathing_g = 0;
static uint8_t s_breathing_b = 0;

// 循环红绿蓝 任务变量
static TaskHandle_t s_cycle_task = NULL;
static bool s_cycle_enabled = false;

// 彩虹灯 任务变量
static TaskHandle_t s_rainbow_task = NULL;
static bool s_rainbow_enabled = false;

2.1.2 循环红绿蓝任务实现

/**
 * @brief 循环红绿蓝灯效任务
 */
static void cycle_rgb_task(void *arg)
{
    // 红、绿、蓝 三原色数组
    const int colors[3][3] = {{255,0,0}, {0,255,0}, {0,0,255}};
    int color_idx = 0;
    const int delay_ms = 1000;  // 每个颜色停留 1while (s_cycle_enabled) {
        // 设置当前颜色
        ws2812_set(colors[color_idx][0], colors[color_idx][1], colors[color_idx][2]);
        vTaskDelay(pdMS_TO_TICKS(delay_ms));
        // 循环切换索引
        color_idx = (color_idx + 1) % 3;
    }

    // 任务退出:熄灭 LED
    ws2812_set(0, 0, 0);
    s_cycle_task = NULL;
    vTaskDelete(NULL);
}

/**
 * @brief 启动循环红绿蓝工具
 */
static esp_err_t tool_cycle_rgb_start_execute(const char *in, char *out, size_t len)
{
    (void)in;
    // 停止所有其他动态效果,避免冲突
    if (s_breathing_task) {
        s_breathing_enabled = false;
        vTaskDelay(pdMS_TO_TICKS(100));
        s_breathing_task = NULL;
    }
    if (s_rainbow_task) {
        s_rainbow_enabled = false;
        vTaskDelay(pdMS_TO_TICKS(100));
        s_rainbow_task = NULL;
    }

    // 校验任务状态
    if (s_cycle_task) {
        snprintf(out, len, "Cycle RGB 已运行");
        return ESP_OK;
    }

    // 释放 LED 资源,避免 RMT 冲突
    ws2812_deinit();
    s_cycle_enabled = true;

    // 创建 FreeRTOS 任务
    BaseType_t ret = xTaskCreate(cycle_rgb_task, "cycle_rgb", 4096, NULL, 5, &s_cycle_task);
    if (ret == pdPASS) {
        snprintf(out, len, "循环红绿蓝已启动");
        return ESP_OK;
    } else {
        s_cycle_enabled = false;
        snprintf(out, len, "循环红绿蓝启动失败");
        return ESP_FAIL;
    }
}

2.1.3 彩虹灯任务实现(HSV→RGB 转换)

/**
 * @brief 彩虹渐变灯效任务(HSV 转 RGB)
 */
static void rainbow_task(void *arg)
{
    int hue = 0;  // 色相值 0~360
    const int delay_ms = 20;  // 刷新间隔,越小速度越快

    while (s_rainbow_enabled) {
        uint8_t r, g, b;
        uint8_t h = hue / 60;
        uint8_t s = 255;   // 饱和度 100%
        uint8_t v = 255;   // 亮度 100%
        uint8_t f = hue % 60;
        uint8_t pv = (v * (255 - s)) / 255;
        uint8_t qv = (v * (255 - (s * f) / 60)) / 255;
        uint8_t tv = (v * (255 - (s * (60 - f)) / 60)) / 255;

        // HSV 转 RGB 核心逻辑
        switch (h) {
            case 0: r = v; g = tv; b = pv; break;
            case 1: r = qv; g = v; b = pv; break;
            case 2: r = pv; g = v; b = tv; break;
            case 3: r = pv; g = qv; b = v; break;
            case 4: r = tv; g = pv; b = v; break;
            default: r = v; g = pv; b = qv; break;
        }

        ws2812_set(r, g, b);
        vTaskDelay(pdMS_TO_TICKS(delay_ms));

        // 循环色相
        hue++;
        if (hue >= 360) hue = 0;
    }

    // 任务退出:熄灭 LED
    ws2812_set(0, 0, 0);
    s_rainbow_task = NULL;
    vTaskDelete(NULL);
}

/**
 * @brief 启动彩虹灯工具
 */
static esp_err_t tool_rainbow_start_execute(const char *in, char *out, size_t len)
{
    (void)in;
    // 停止所有其他动态效果
    if (s_breathing_task) {
        s_breathing_enabled = false;
        vTaskDelay(pdMS_TO_TICKS(100));
        s_breathing_task = NULL;
    }
    if (s_cycle_task) {
        s_cycle_enabled = false;
        vTaskDelay(pdMS_TO_TICKS(100));
        s_cycle_task = NULL;
    }

    if (s_rainbow_task) {
        snprintf(out, len, "彩虹灯已运行");
        return ESP_OK;
    }

    ws2812_deinit();
    s_rainbow_enabled = true;

    BaseType_t ret = xTaskCreate(rainbow_task, "rainbow", 4096, NULL, 5, &s_rainbow_task);
    if (ret == pdPASS) {
        snprintf(out, len, "彩虹灯已启动");
        return ESP_OK;
    } else {
        s_rainbow_enabled = false;
        snprintf(out, len, "彩虹灯启动失败");
        return ESP_FAIL;
    }
}

2.1.4 统一停止工具实现

/**
 * @brief 停止所有动态灯效
 */
static void stop_all_dynamic_effects(void)
{
    // 停止呼吸灯
    if (s_breathing_task) {
        s_breathing_enabled = false;
        vTaskDelay(pdMS_TO_TICKS(100));
        s_breathing_task = NULL;
    }
    // 停止循环红绿蓝
    if (s_cycle_task) {
        s_cycle_enabled = false;
        vTaskDelay(pdMS_TO_TICKS(100));
        s_cycle_task = NULL;
    }
    // 停止彩虹灯
    if (s_rainbow_task) {
        s_rainbow_enabled = false;
        vTaskDelay(pdMS_TO_TICKS(100));
        s_rainbow_task = NULL;
    }

    // 释放资源,熄灭 LED
    ws2812_deinit();
    ws2812_set(0, 0, 0);
}

/**
 * @brief 停止所有效果工具
 */
static esp_err_t tool_stop_effect_execute(const char *in, char *out, size_t len)
{
    (void)in;
    stop_all_dynamic_effects();
    snprintf(out, len, "所有灯效已停止");
    return ESP_OK;
}

2.1.5 工具注册
在 tool_registry_init 函数中添加以下代码,完成工具注册:

// 1. 注册循环红绿蓝工具
mimi_tool_t cycle_tool = {
    .name = "cycle_rgb",
    .description = "启动红绿蓝循环灯效",
    .input_schema_json = "{\"type\":\"object\",\"properties\":{},\"required\":[]}",
    .execute = tool_cycle_rgb_start_execute,
};
register_tool(&cycle_tool);

// 2. 注册彩虹灯工具
mimi_tool_t rainbow_tool = {
    .name = "rainbow",
    .description = "启动彩虹渐变灯效",
    .input_schema_json = "{\"type\":\"object\",\"properties\":{},\"required\":[]}",
    .execute = tool_rainbow_start_execute,
};
register_tool(&rainbow_tool);

// 3. 注册停止所有效果工具
mimi_tool_t stop_tool = {
    .name = "stop_effect",
    .description = "停止所有动态灯效",
    .input_schema_json = "{\"type\":\"object\",\"properties\":{},\"required\":[]}",
    .execute = tool_stop_effect_execute,
};
register_tool(&stop_tool);

2.2 指令硬匹配:agent_loop.c
打开 main/agent_loop.c,在 try_direct_command 函数中添加指令匹配规则,实现毫秒级响应:

// ====================== 动态灯效指令匹配 ======================
// 匹配:循环红绿蓝 / cycle rgb / 红绿蓝循环
if (strstr(content, "循环红绿蓝") != NULL || strstr(content, "cycle rgb") != NULL ||
    strstr(content, "红绿蓝循环") != NULL) {
    tool_registry_execute("cycle_rgb", "{}", output, output_size);
    return true;
}

// 匹配:彩虹灯 / 彩虹 / rainbow
if (strstr(content, "彩虹灯") != NULL || strstr(content, "彩虹") != NULL ||
    strstr(content, "rainbow") != NULL) {
    tool_registry_execute("rainbow", "{}", output, output_size);
    return true;
}

// 匹配:停止效果 / 停止所有效果 / stop effect
if (strstr(content, "停止效果") != NULL || strstr(content, "停止所有效果") != NULL ||
    strstr(content, "stop effect") != NULL) {
    tool_registry_execute("stop_effect", "{}", output, output_size);
    return true;
}

三、编译、烧录与测试

3.1 编译与烧录
执行以下命令完成清理、编译、烧录(替换为你的实际串口):

idf.py fullclean
idf.py build
idf.py -p COM12 flash monitor

3.2 串口手动测试
在 mimi> 命令行执行以下指令:

mimi> tool_exec cycle_rgb "{}"      # 启动红绿蓝循环
mimi> tool_exec rainbow "{}"        # 启动彩虹渐变
mimi> tool_exec stop_effect "{}"    # 停止所有灯效

3.3 飞书自然语言控制
直接在飞书发送以下指令,设备立即响应:

循环红绿蓝 → 启动三原色循环
彩虹灯 → 启动平滑彩虹渐变
停止效果 → 熄灭 LED,停止所有动态灯效

四、效果说明与注意事项

4.1 灯效效果
循环红绿蓝:LED 按红→绿→蓝顺序切换,每个颜色停留 1 秒,无限循环
彩虹灯:平滑遍历红→橙→黄→绿→青→蓝→紫,全程无断层,约 7 秒完成一圈

4.2 关键注意事项
任务互斥:启动任意动态灯效,会自动停止其他效果,杜绝硬件冲突
资源释放:停止灯效后自动调用 ws2812_deinit,释放 RMT 硬件资源
内存占用:单任务栈 4096 字节,ESP32-S3 充足,无内存压力
兼容性:不影响静态颜色指令(如红色、绿色),可自由切换

4.3 功能扩展建议
可调速度:新增参数配置,支持 cycle_rgb {“speed”:500} 自定义切换速度
多灯珠扩展:适配 WS2812 灯带,实现流水灯、跑马灯效果
状态联动:将灯效与设备状态绑定(联网→蓝色呼吸、异常→红色闪烁)
音乐律动:结合麦克风,实现灯效随音量 / 节奏变化

五、实验场景图与记录视频

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

【【花雕动手做】ESP32-S3 + MimiClaw 实战:为板载 WS2812 添加循环红绿蓝与彩虹灯效果让你的嵌入式 AI Agent 拥有更丰富视觉反馈】

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

MimiClaw实战:WS2812 添加循环红绿蓝与彩虹灯效

六、总结

本实战基于 ESP32-S3 + MimiClaw 框架,通过 FreeRTOS 任务实现了两种高性能 WS2812 动态灯效:
轻量化设计:无额外硬件,纯软件扩展,资源占用极低
极致响应:指令硬匹配绕过 LLM,控制延迟<10ms
稳定可靠:任务互斥 + 资源自动释放,长期运行无冲突
易于扩展:代码模块化,可快速新增更多灯效
完成开发后,你的嵌入式 AI Agent 不仅能听懂指令,更能通过炫酷灯效实现可视化交互,大幅提升产品体验。

附录
所属系列:花雕学编程・花雕动手做・MimiClaw 嵌入式实战
代码仓库:MimiClaw GitHub 官方仓库 https://github.com/memovai/mimiclaw
官方文档:https://mimiclaw.io
适配平台:ESP32-S3 全系列开发板

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐