回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

小智语言+拍照控制ESP32 S3 WS2812RGB灯|极简MCP插件教程 简单

头像 rzyzzxw 2025.08.14 18 0

8.14

 

【目标任务】

这个帖子,记录用小智语音控制ESP32 S3开发板板载WS2812 RGB灯及外接WS2812灯带(灯环),初步计划颜色和亮度的控制,后续争取实现更多灯光效果。

【编程环境配置】

让小智语音控制ESP32 S3点灯|极简MCP插件教程- Makelog(造物记)

 

4a1dd5266b44a7e4508bb6262a6ea52.jpg
935660e0fa369aa00dd135e65ab299c.jpg

材料清单

  • K10小智 X1
  • ESP32 S3开发板 X1
  • WS2812 RGB灯环 X1
  • 锂电池 X

步骤1 安装Adafruit_NeoPixel库

编程环境配置:

让小智语音控制ESP32 S3点灯|极简MCP插件教程- Makelog(造物记)

工具--库管理,安装Adafruit_NeoPixel库。

image.png

然后做一个板载WS2812 RGB灯点(IO48)亮测试,红绿蓝三色变换。

fd77fe4f30ea9f2a01480aab7717ecc.jpg

代码
#include <Adafruit_NeoPixel.h>
#define LED_PIN    48   // RGB灯数据引脚[1](@ref)
#define LED_COUNT  1    // 灯珠数量(单颗)[1](@ref)

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();           // 初始化LED控制
  strip.setBrightness(50); // 设置亮度(0-255,建议≤50)[1,5](@ref)
  strip.show();            // 初始关闭灯珠
}

void loop() {
  // 红色 (R=255, G=0, B=0)
  strip.setPixelColor(0, strip.Color(255, 0, 0)); 
  strip.show();
  delay(1000);  // 持续1秒[1](@ref)

  // 绿色 (R=0, G=255, B=0)
  strip.setPixelColor(0, strip.Color(0, 255, 0));
  strip.show();
  delay(1000);

  // 蓝色 (R=0, G=0, B=255)
  strip.setPixelColor(0, strip.Color(0, 0, 255));
  strip.show();
  delay(1000);
}

步骤2 外接WS2812 RGB 32灯珠灯环基础测试

1.​​基础测试​​
colorWipe():实现​​红/绿/蓝三色顺序填充​​,验证灯珠焊接与信号传输。
每灯珠点亮间隔 50ms(可通过 wait参数调整速度)。

2.​​动态光效​​
​​剧场追逐​​:三灯一组移动白光,模拟跑马灯效果。

3.​​亮度安全​​
setBrightness(50):限制电流(32灯全亮时理论电流 ≈ 32× 20mA = 640mA)。

硬件连接注意事项
1.​​电源要求​​
​​必须外接 5V/2A 电源​​:32灯珠全白时峰值电流可达 1.92A(60mA × 32)。
接线顺序:先接 GND → 5V → 数据线(防浪涌冲击)。

2.​​信号传输​​
数据线串联 ​​330Ω电阻​​(防信号反射)。
灯环 ​​DI 端​​接 ESP32-S3 的 ​​GPIO5​​,​​DO 端​​留空或接下一灯环。

3.​​ESP32-S3 配置​​
若灯珠不亮,检查开发板是否启用 GPIO5(部分板型需跳线)。

de82d91ede5f173f39b9cceec414192.jpg

代码
#include <Adafruit_NeoPixel.h>
#define LED_PIN     5   // 数据引脚(ESP32-S3 的 GPIO5)
#define LED_COUNT   32   // 灯珠数量(外接 32 灯环)

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  Serial.begin(115200);
  strip.begin();           // 初始化灯带
  strip.setBrightness(50);  // 设置亮度(0-255,建议≤50防过流)
  strip.show();             // 关闭所有灯珠
  Serial.println("32灯环测试启动");
}

void loop() {
  // 1. 基础颜色测试(红→绿→蓝)
  colorWipe(strip.Color(255, 0, 0), 50);    // 红色填充
  colorWipe(strip.Color(0, 255, 0), 50);    // 绿色填充
  colorWipe(strip.Color(0, 0, 255), 50);    // 蓝色填充

  // 2. 彩虹渐变效果
  rainbow(10);                             // 全灯环彩虹流动

  // 3. 剧场追逐效果
  theaterChase(strip.Color(127, 127, 127), 50); // 白色追逐
}

// 逐点填充颜色
void colorWipe(uint32_t color, int wait) {
  for (int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, color);  // 设置当前灯珠颜色
    strip.show();                   // 更新硬件显示
    delay(wait);                    // 控制填充速度
  }
}

// 彩虹渐变(非阻塞优化版)
void rainbow(int wait) {
  static long firstPixelHue = 0;  // 色相起始值
  
  for (int i = 0; i < strip.numPixels(); i++) {
    int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
    strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
  }
  strip.show();
  delay(wait);
  firstPixelHue += 256;  // 色相步进(每帧移动1°)
  if (firstPixelHue >= 5 * 65536) firstPixelHue = 0; // 完成5次色环循环后复位
}

// 剧场追逐效果(3灯一组移动)
void theaterChase(uint32_t color, int wait) {
  for (int cycle = 0; cycle < 10; cycle++) {   // 重复10轮
    for (int phase = 0; phase < 3; phase++) {    // 3种相位
      strip.clear();                            // 清空灯带
      // 点亮当前相位灯珠(每隔3灯点亮1颗)
      for (int i = phase; i < strip.numPixels(); i += 3) {
        strip.setPixelColor(i, color);
      }
      strip.show();
      delay(wait);
    }
  }
}

步骤3 启动小智控制

系统架构

image.png

语音指令,例如下表

image.png

可以自然语言切换各种常见颜色和彩虹、各色呼吸、各色跑马灯。

代码
#include <WiFi.h>
#include <WebSocketMCP.h>
#include <Adafruit_NeoPixel.h>

#define LED_PIN 5        // WS2812数据引脚(GPIO5)
#define LED_COUNT 32     // 32灯珠灯环

// 初始化灯环
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

// 全局状态变量
enum Effects { OFF, SOLID, RAINBOW, BREATH, CHASE };
Effects currentEffect = OFF;
uint32_t effectColor = strip.Color(255, 255, 255); // 默认白色
uint16_t effectSpeed = 50; // 默认速度值

// WiFi配置
const char* ssid = "your-ssid";
const char* password = "your-password";
const char* mcpEndpoint = "ws://your-mcp-server:port/path";
WebSocketMCP mcpClient;

// 非阻塞灯光效果实现
void updateLEDEffects() {
  static unsigned long prevMillis = 0;
  static uint16_t rainbowCounter = 0;
  static uint8_t breathValue = 0;
  static bool breathDir = true;
  static uint8_t chasePos = 0;
  
  if (millis() - prevMillis < effectSpeed) return;
  prevMillis = millis();
  
  switch(currentEffect) {
    case OFF:
      strip.clear();
      strip.show();
      break;
      
    case SOLID:
      strip.fill(effectColor);
      strip.show();
      break;
      
    case RAINBOW:
      for(int i=0; i<LED_COUNT; i++) {
        strip.setPixelColor(i, strip.gamma32(strip.ColorHSV((i * 65536L / LED_COUNT) + rainbowCounter)));
      }
      strip.show();
      rainbowCounter += 256;
      break;
      
    case BREATH:
      strip.fill(strip.Color(breathValue * ((effectColor >> 16) & 0xFF) / 255, 
                          breathValue * ((effectColor >> 8) & 0xFF) / 255,
                          breathValue * (effectColor & 0xFF) / 255));
      strip.show();
      
      if(breathDir) {
        if(++breathValue >= 255) breathDir = false;
      } else {
        if(--breathValue <= 30) breathDir = true;
      }
      break;
      
    case CHASE:
      strip.clear();
      for(int i=0; i<3; i++) {
        int pos = (chasePos + i) % LED_COUNT;
        strip.setPixelColor(pos, effectColor);
      }
      strip.show();
      chasePos = (chasePos + 1) % LED_COUNT;
      break;
  }
}

// MCP工具注册(新增灯环控制)
void registerMcpTools() {  
  // RGB灯环控制工具
  mcpClient.registerTool(
    "rgb_control",
    "控制WS2812 RGB 小环 灯环",
    "{\"type\":\"object\",\"properties\":{"
    "\"command\":{\"type\":\"string\",\"enum\":[\"on\",\"off\",\"solid\",\"rainbow\",\"breath\",\"chase\"]},"
    "\"color\":{\"type\":\"string\",\"pattern\":\"^#[0-9a-fA-F]{6}$\"},"
    "\"speed\":{\"type\":\"integer\",\"minimum\":10,\"maximum\":500}}"
    "}",
    [](const String& args) {
      DynamicJsonDocument doc(512);
      deserializeJson(doc, args);
      
      String command = doc["command"].as<String>();
      
      // 解析颜色值 (#RRGGBB格式)
      if(doc.containsKey("color")) {
        String colorHex = doc["color"].as<String>();
        long colorNum = strtol(colorHex.substring(1).c_str(), NULL, 16);
        effectColor = strip.Color((colorNum >> 16) & 0xFF, 
                                 (colorNum >> 8) & 0xFF, 
                                 colorNum & 0xFF);
      }
      
      // 解析速度值
      if(doc.containsKey("speed")) {
        effectSpeed = doc["speed"];
      }
      
      // 执行指令
      if(command == "on" || command == "solid") {
        currentEffect = SOLID;
      } 
      else if(command == "off") {
        currentEffect = OFF;
      }
      else if(command == "rainbow") {
        currentEffect = RAINBOW;
      }
      else if(command == "breath") {
        currentEffect = BREATH;
      }
      else if(command == "chase") {
        currentEffect = CHASE;
      }
      
      return WebSocketMCP::ToolResponse("{\"status\":\"success\",\"effect\":\"" + command + "\"}");
    }
  );
}
void setup() {
  Serial.begin(115200);
  
  // 初始化RGB灯环
  strip.begin();
  strip.setBrightness(100); // 设置亮度(0-255)
  strip.show(); // 初始关闭
  
  // WiFi连接(保持不变)
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  
  // MCP客户端初始化
  mcpClient.begin(mcpEndpoint, [](bool connected) {
    if (connected) {
      Serial.println("[MCP] 已连接");
      registerMcpTools();
    }
  });
}
void loop() {
  mcpClient.loop();  // 处理WebSocket消息
  updateLEDEffects(); // 更新灯光效果(非阻塞)
}

image.png

上传,测试通过。

小智后台:

image.png

评论

user-avatar