不用买屏幕、不用摄像头、不用云主机,用一部闲置的旧手机当交互终端,一块DFRobot FireBeetle 2 ESP32-C6做主控,再接入硅基流动大模型API(语音识别+大模型对话+语音合成),就能做出一台会说、会听、会按指令移动的语音控制小车。你只需对它说"先前进,再左转,再右转",小车就会依次完成三个动作;问它"今天天气怎么样",它会用稳定的音色回答你。整个网页就托管在C6的Flash里,手机打开浏览器即可使用,完全不需要电脑中转、不需要第三方物联网平台。

项目架构
旧手机(浏览器) --WiFi(2.4G)--> FireBeetle 2 ESP32-C6(HTTPS网页服务器)
| |
| 按住说话/自动听 | L298N 双H桥
v v
录音 -> 硅基流动 Qwen3-ASR --> 文字 --> 硅基流动 Qwen3-8B/32B 对话
|
播放 MOSS-TTSD 合成语音 <---------- 输出 actions:[FORWARD,LEFT,...]
|
+--------------+
v
C6 按顺序执行动作(前进2秒/转向1秒,自动停车)为什么手机要配C6,而不直接用手机控制电机?
浏览器受安全限制,不能直接驱动GPIO、不能发原始UDP,录音/摄像头还必须HTTPS。C6做"大脑+关节":提供HTTPS网页、解析指令、驱动电机,手机只负责"声音交互"。
材料清单
| 类别 | 名称 | 数量 | 说明 |
|---|---|---|---|
| 主控 | DFRobot FireBeetle 2 ESP32-C6 (DFR1075) | 1 | 板载LED(IO15)、支持Wi-Fi 6 |
| 驱动 | L298N双H桥电机驱动板 | 1 | 两路电机,PWM调速 |
| 电机 | 直流减速电机(带轮小车底盘) | 2 | 左右轮各一 |
| 电源 | 3.7V锂电池 | 1 | 进L298N 12V端子;C6用Type-C或电池供电 |
| 交互 | 闲置旧手机(安卓/iOS均可) | 1 | 与C6同连一路由器(2.4G) |
| 调试 | Type-C数据线 | 1 | 烧录+串口监视 |
| 服务 | 硅基流动(SiliconFlow) API | -- | 注册获得API Key,使用赠送额度即可 |
接线(L298N 与 C6)
务必共地:L298N的GND与C6的GND相连,否则信号不识别。
| C6引脚(GPIO) | 方向 | L298N端子 | 作用 |
|---|---|---|---|
| GPIO2 (M1_IN1) | --> | IN1(A通道) | 左轮方向1 |
| GPIO3 (M1_IN2) | --> | IN2(A通道) | 左轮方向2 |
| GPIO4 (M1_PWM) | --> | ENA | 左轮速度PWM |
| GPIO5 (M2_IN1) | --> | IN3(B通道) | 右轮方向1 |
| GPIO6 (M2_IN2) | --> | IN4(B通道) | 右轮方向2 |
| GPIO7 (M2_PWM) | --> | ENB | 右轮速度PWM |
| GND | <--> | GND | 共地(必须) |
| 电池3.7V | --> | 12V/VCC | 电机电源 |

引脚定义在主程序顶部,可按实际焊接修改;若转向相反,互换该轮两根IN线即可。
软件与模型
开发环境
Arduino IDE(2.x均可),安装Espressif ESP32板卡包(3.x)。开发板选择:DFRobot FireBeetle 2 ESP32-C6。工具中设置USB CDC On Boot = Enabled(否则串口在程序运行后会断开)。
硅基流动模型
| 用途 | 模型ID | 说明 |
|---|---|---|
| 语音识别ASR | Qwen/Qwen3-ASR-1.7B | 支持52种语言/方言,识别准、返回快 |
| 对话/动作决策 | Qwen/Qwen3-8B(默认) | 快;可换32B更强 |
| 语音合成TTS | fnlp/MOSS-TTSD-v0.5 | 音色fnlp/MOSS-TTSD-v0.5:alex,稳定 |
浏览器直连可行(CORS已放行),无需任何中转服务器。
程序结构
firebeetle2_voice_robot/
+-- firebeetle2_voice_robot.ino (C6主程序,HTTPS服务器+动作控制)
+-- page.h (网页HTML+JS全内嵌,放头文件防注入)
+-- certificates.h (自签名证书,DER二进制)C6侧核心逻辑
void processCommand(String cmd) {
cmd.trim(); cmd.toUpperCase();
Serial.print("[CMD] "); Serial.println(cmd);
if (cmd == "FORWARD") { startMotion("FORWARD", 2000); }
else if (cmd == "LEFT" || cmd == "RIGHT") { startMotion(cmd, 1000); }
else { stopMotionNow(); }
}两个网页服务:HTTP :80与HTTPS :443(mbedtls自签名)。动作执行后自动停车,等待新指令。
网页功能
| 功能 | 说明 |
|---|---|
| 按住说话 | 按住录音、松开识别(指针捕获,长按不选中文字) |
| 持续听(人声唤醒) | 听到人声自动录音->识别->对话;1.5秒PCM预卷不漏开头;播报自己声音自动忽略 |
| AI对话 | Qwen3-8B/32B,思考模式关闭,回复简短;可一次输出多个动作连续执行 |
| 语音播报 | MOSS-TTSD固定音色,失败自动重试保持音色;结尾杂音自动裁剪 |
| 左右轮调速 | 两个滑块独立调PWM(默认左240/右255) |

制作步骤
1. 烧录:用Arduino IDE打开主程序,选板卡"DFRobot FireBeetle 2 ESP32-C6",CDC On Boot=Enabled,上传。
2. 配置WiFi:改主程序顶部WIFI_SSID/WIFI_PASS(C6仅支持2.4GHz);默认静态IP可按路由器网段修改。
3. 配API Key:page.h顶部API_KEY换成你的硅基流动Key。
4. 串口监视器(115200)看到:WiFi已连接、HTTPS已启动,板载LED闪两下。
5. 手机:连同一WiFi,打开https://C6的IP(自签名证书 -> 高级 -> 继续访问)。
6. 先点"试听播报"验证链路,再按住说话或开启持续听。



技术难点与解决
1. 浏览器不能裸发UDP/录音必须HTTPS
C6用mbedtls做自签名HTTPS服务器,证书以DER二进制内嵌,手机浏览器"高级->继续访问"即可。
2. Arduino的"生成函数原型"会把#line注进HTML,毁掉页面JS
把网页HTML移进page.h头文件(原型生成器只处理.ino,不碰头文件)。这是"同一份代码有时页面白屏"类问题的根源。
3. 老手机浏览器不支持现代JS
页面JS用ES5兼容写法+拆成两个script块:第一块做极简启动自检,一眼判断是"浏览器不支持"还是"页面问题"。
4. 持续听漏掉开头几个字
用PCM预卷环(始终保留最近1.5秒音频),检测到人声即把预卷拼回录音,开头一字不丢。
5. TTS音色忽男忽女/结尾有杂音
固定音色,接口失败自动重试保持音色;播放前解码并按结尾静音裁剪,同时先停掉上次播放防重叠串音。
6. 一次说多个动作
对话里约定输出JSON格式包含reply和actions数组,网页解析后逐个发送并等上一个动作完成再下一个。
注意事项
API Key内嵌在网页里,仅限自家局域网使用,勿上传公开仓库;被其他人连到同一WiFi即可使用你的Key,注意额度。C6只支持2.4GHz WiFi;手机最好连2.4G段信号更稳。L298N必须与C6共地;电机单独由电池供电,不要从C6引脚取电。





ES5兼容写法照顾老手机浏览器,考虑周全
自签名HTTPS服务器这个方案实用,省了第三方平台
PCM预卷环防漏字的技巧学到了,之前做语音项目一直头疼这个问题
L298N和C6共地这个细节很重要,很多人会忘
旧手机再就业这个思路太赞了,ESP32-C6做主控成本也不高