ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

50元自制AI桌面助手:ESP32-S3实现语音、鼠标与手机远程控制

50元自制AI桌面助手:ESP32-S3实现语音、鼠标与手机远程控制 最近在折腾桌面自动化工具时发现市面上的成品要么功能单一要么价格昂贵。于是萌生了一个想法能否用极低的成本自己动手做一个功能全面的桌面机器人它最好能听懂指令、能对话、能控制鼠标键盘还能用手机远程操作。经过一番研究和实践我发现用几十块钱的硬件加上开源软件完全可以实现这个目标。本文将分享一套完整的制作方案从硬件选型、固件烧录到软件配置、功能集成手把手带你打造一个集AI对话、AI控制、鼠标控制、手机控制、语音控制于一体的智能桌面助手。无论你是嵌入式新手还是对桌面自动化感兴趣的开发者都能跟着教程一步步实现。1. 项目核心概念与硬件选型1.1 什么是桌面机器人桌面机器人并非指一个在桌面上行走的实体机器人而是一个运行在电脑上的智能代理程序。它通过监听用户的指令语音、文本或手机指令自动执行一系列桌面操作例如打开应用、搜索信息、控制鼠标键盘、进行智能对话等。其核心价值在于将重复、繁琐的桌面操作自动化并通过AI能力增强交互的智能性。本项目实现的桌面机器人其“大脑”是运行在电脑上的主控程序“四肢”和“感官”则由一个廉价的微控制器MCU扩展实现。MCU负责模拟键盘鼠标HID设备、接收语音指令并与电脑上的主控程序通信共同完成复杂任务。1.2 硬件清单与成本分析实现本项目的核心是选择一个合适的MCU开发板。它需要具备USB HID人机接口设备功能以模拟键盘鼠标最好有麦克风接口或I2S接口以支持语音输入同时需要足够的GPIO和计算资源。推荐方案ESP32-S3 开发板经过对比ESP32-S3是一款性价比极高的选择。它双核处理器、Wi-Fi/蓝牙、USB OTG、丰富的IO口并且原生支持USB HID和I2S。市面上常见的ESP32-S3开发板如ESP32-S3-DevKitC-1价格仅在30-50元人民币。完整硬件清单组件型号/规格预估成本元作用主控MCUESP32-S3 开发板35核心控制器运行固件模拟HID设备麦克风模块INMP441 (I2S接口)8采集语音信号用于语音控制杜邦线母对母2连接开发板与麦克风模块USB数据线Type-C5供电及与电脑通信合计约 50为什么选择ESP32-S3成本极低核心板仅需几十元。功能强大集成USB OTG可轻松模拟键盘、鼠标、游戏手柄等HID设备无需额外芯片。生态完善Arduino、ESP-IDF等开发框架支持良好有丰富的库和社区资源。扩展性强双核240MHz支持Wi-Fi和蓝牙为未来增加网络控制、蓝牙遥控等功能留有余地。如果手头有ESP32-S2、RP2040如Raspberry Pi Pico等同样支持USB HID的开发板也可以作为备选但ESP32-S3在性能和接口上更为均衡。2. 开发环境搭建与固件准备2.1 软件环境准备在开始编写和烧录固件前需要在你的电脑上搭建开发环境。1. 安装 Arduino IDEArduino IDE 是入门最简单的方式它集成了代码编辑、编译和烧录功能。访问 Arduino 官网下载并安装最新版 Arduino IDE。安装后打开文件-首选项在“附加开发板管理器网址”中添加以下网址https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json然后打开工具-开发板-开发板管理器搜索esp32找到并安装Espressif Systems提供的esp32开发板包。2. 安装 CP210x/USB转串口驱动ESP32开发板通常通过USB转串口芯片如CP2102、CH340与电脑通信。请根据你的开发板型号安装对应的驱动程序以便电脑识别出串口。3. 安装必要的库本项目需要用到以下Arduino库可通过项目-加载库-管理库进行搜索安装USBHID(通常已内置)WiFi(用于后续网络功能)HTTPClient(用于后续网络功能)ArduinoJson(用于处理JSON数据与AI服务通信时使用)2.2 固件源码结构与获取本项目的固件主要包含以下几个核心模块HID设备模拟让电脑将ESP32识别为一个键盘和鼠标。语音采集与识别通过I2S麦克风采集音频并发送到电脑端或云端进行识别。串口通信协议定义ESP32与电脑主控程序之间的指令格式。网络服务可选提供HTTP API供手机App或网页控制。由于固件代码较长我将分模块讲解核心逻辑。你可以通过文末提示的方式获取完整的、可编译的工程源码。核心固件功能预览// 示例模拟鼠标移动的核心函数 #include USBHID.h USBHID HID; void moveMouseRelative(int8_t x, int8_t y) { uint8_t report[4] {0}; report[0] 0; // 按钮状态 report[1] constrain(x, -127, 127); // X轴位移 report[2] constrain(y, -127, 127); // Y轴位移 report[3] 0; // 滚轮 HID.SendReport(2, report, 4); // 发送鼠标报告 } // 示例模拟键盘按键 void pressKey(uint8_t keycode) { uint8_t report[8] {0}; report[2] keycode; // 将按键码放入报告的第3个字节标准HID键盘报告描述符 HID.SendReport(1, report, 8); delay(50); report[2] 0; // 释放按键 HID.SendReport(1, report, 8); }3. 固件开发详解从HID模拟到语音采集3.1 USB HID设备模拟实现要让ESP32-S3被电脑识别为键盘鼠标我们需要在固件中正确配置USB HID报告描述符。这是最核心的一步。1. 配置HID报告描述符在Arduino项目中我们通常通过USBHID库的配置来实现。以下是一个简化的键盘和鼠标复合设备的描述符配置示例#include USBHID.h static const uint8_t report_descriptor[] { // 鼠标报告描述符 (用法页通用桌面用法鼠标) 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x02, // Usage (Mouse) 0xA1, 0x01, // Collection (Application) // ... 省略详细字节定义XY位移和按钮 // 键盘报告描述符 (用法页键盘/键区) 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x06, // Usage (Keyboard) 0xA1, 0x01, // Collection (Application) // ... 省略详细字节定义按键码 }; USBHID HID(report_descriptor, sizeof(report_descriptor), 1, 100, false); // 创建HID实例 void setup() { HID.begin(); Serial.begin(115200); }关键点完整的报告描述符比较复杂它定义了设备类型、数据格式和长度。在提供的完整源码中会包含一个经过测试的、完整的描述符确保能被Windows、macOS、Linux系统正确识别。2. 实现基础控制函数基于配置好的HID实例我们可以封装常用的控制函数。// 鼠标控制类 class DesktopMouse { public: void move(int16_t dx, int16_t dy) { // 处理超出单次报告范围-127~127的移动 while(dx ! 0 || dy ! 0) { int8_t reportX (dx 127) ? 127 : (dx -127) ? -127 : dx; int8_t reportY (dy 127) ? 127 : (dy -127) ? -127 : dy; sendMouseReport(0, reportX, reportY, 0); dx - reportX; dy - reportY; } } void click(uint8_t button MOUSE_LEFT) { sendMouseReport(button, 0, 0, 0); delay(10); sendMouseReport(0, 0, 0, 0); } void scroll(int8_t value) { sendMouseReport(0, 0, 0, value); } private: void sendMouseReport(uint8_t buttons, int8_t x, int8_t y, int8_t wheel) { uint8_t report[4] {buttons, (uint8_t)x, (uint8_t)y, (uint8_t)wheel}; HID.SendReport(2, report, 4); // 假设鼠标报告ID是2 } }; // 键盘控制类 class DesktopKeyboard { public: void press(String keys) { // 简化示例实际需要将字符串映射为HID键码并处理组合键 // 例如实现 press(KEY_LEFT_CTRL, c) 进行复制 } void write(String text) { // 模拟逐字输入 for (char c : text) { pressKey(charToHidKey(c)); } } };3.2 I2S麦克风语音采集语音控制是本项目的亮点之一。我们使用INMP441这类数字麦克风通过I2S接口将音频数据实时发送到电脑由电脑上性能更强的AI服务进行语音识别ASR。1. 硬件连接将INMP441模块与ESP32-S3连接INMP441 L/R-GND(选择左声道)INMP441 DOUT-ESP32-S3 GPIO33(I2S数据线)INMP441 BCLK-ESP32-S3 GPIO17(位时钟)INMP441 LRCL-ESP32-S3 GPIO16(左右声道时钟)INMP441 VDD-3.3VINMP441 GND-GND2. 固件中的音频采集代码#include driver/i2s.h #define I2S_SAMPLE_RATE 16000 // 16kHz采样率满足语音识别需求 #define I2S_BUFFER_SIZE 1024 void setupI2S() { i2s_config_t i2s_config { .mode (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX), .sample_rate I2S_SAMPLE_RATE, .bits_per_sample I2S_BITS_PER_SAMPLE_32BIT, .channel_format I2S_CHANNEL_FMT_ONLY_LEFT, .communication_format I2S_COMM_FORMAT_STAND_I2S, .intr_alloc_flags ESP_INTR_FLAG_LEVEL1, .dma_buf_count 4, .dma_buf_len I2S_BUFFER_SIZE, .use_apll false, .tx_desc_auto_clear false, .fixed_mclk 0 }; i2s_pin_config_t pin_config { .bck_io_num 17, .ws_io_num 16, .data_out_num I2S_PIN_NO_CHANGE, .data_in_num 33 }; i2s_driver_install(I2S_NUM_0, i2s_config, 0, NULL); i2s_set_pin(I2S_NUM_0, pin_config); } void audioTask(void *parameter) { int32_t audio_buffer[I2S_BUFFER_SIZE]; size_t bytes_read; while(1) { // 从I2S读取音频数据 i2s_read(I2S_NUM_0, audio_buffer, sizeof(audio_buffer), bytes_read, portMAX_DELAY); // 此处可以将audio_buffer通过串口或Wi-Fi发送给电脑 // 例如Serial.write((uint8_t*)audio_buffer, bytes_read); // 注意直接串口发送原始音频数据量很大实际项目中需要压缩或分帧。 } } void setup() { Serial.begin(115200); setupI2S(); xTaskCreatePinnedToCore(audioTask, Audio Task, 4096, NULL, 1, NULL, 1); }重要提示在原型阶段可以通过串口将音频原始数据发送到电脑但速率可能成为瓶颈。更成熟的方案是在ESP32上先进行压缩如ADPCM或通过Wi-Fi UDP流式传输。3.3 串口通信协议设计ESP32与电脑主控程序之间需要通过串口进行双向通信。我们需要定义一个简单高效的文本协议。协议格式示例电脑 - ESP32 (控制指令)CMD:MOVE, X:100, Y:-50\n// 移动鼠标CMD:CLICK, BTN:LEFT\n// 点击左键CMD:TYPE, TEXT:Hello World\n// 输入文本ESP32 - 电脑 (状态/数据上报)EVENT:VOICE_START\n// 开始拾音DATA:AUDIO, LEN:1024\n// 音频数据头后跟二进制数据STATUS:READY\n// 设备就绪固件端协议解析示例String serialBuffer ; void loop() { // 读取串口指令 while (Serial.available()) { char c Serial.read(); if (c \n) { parseCommand(serialBuffer); serialBuffer ; } else { serialBuffer c; } } // ... 其他任务 } void parseCommand(String cmd) { cmd.trim(); if (cmd.startsWith(CMD:MOVE)) { // 解析参数例如使用字符串查找“X:”和“Y:” int xStart cmd.indexOf(X:) 2; int xEnd cmd.indexOf(,, xStart); int yStart cmd.indexOf(Y:) 2; int yEnd cmd.length(); int x cmd.substring(xStart, xEnd).toInt(); int y cmd.substring(yStart).toInt(); mouse.move(x, y); Serial.println(ACK:MOVE_OK); } else if (cmd.startsWith(CMD:CLICK)) { // 解析点击类型 mouse.click(); Serial.println(ACK:CLICK_OK); } // ... 解析其他指令 }4. 电脑端主控程序开发Python示例桌面机器人的“大脑”是运行在电脑上的主控程序。它负责接收来自各方的指令串口、网络、语音调用AI服务并最终通过串口向ESP32发送HID控制命令。这里以Python为例因为它跨平台且开发效率高。4.1 环境准备与项目结构安装必要的Python库pip install pyserial # 串口通信 pip install requests # 网络请求用于调用AI API pip install pyautogui # 备用桌面控制可选 pip install SpeechRecognition pyaudio # 语音识别本地备用项目目录结构desktop_robot/ ├── main.py # 主程序入口 ├── serial_controller.py # 串口通信封装 ├── ai_client.py # AI对话与控制逻辑 ├── voice_engine.py # 语音识别引擎 ├── web_api.py # 手机控制HTTP API └── config.yaml # 配置文件4.2 串口通信模块这个模块负责与ESP32固件通信。# serial_controller.py import serial import serial.tools.list_ports import threading import time import logging class RobotSerialController: def __init__(self, portNone, baudrate115200): self.ser None self.port port self.baudrate baudrate self.is_connected False self._find_and_connect() def _find_and_connect(self): 自动查找并连接ESP32设备 if self.port: ports [self.port] else: ports [p.device for p in serial.tools.list_ports.comports()] # 可以加入更智能的筛选例如通过USB PID/VID ports [p for p in ports if USB in p or ACM in p] for port in ports: try: self.ser serial.Serial(port, self.baudrate, timeout1) time.sleep(2) # 等待设备初始化 self.ser.write(b\n) # 发送测试指令 response self.ser.readline().decode().strip() if READY in response or response : self.is_connected True self.port port logging.info(fConnected to robot at {port}) # 启动接收线程 threading.Thread(targetself._read_loop, daemonTrue).start() return else: self.ser.close() except Exception as e: logging.warning(fFailed to connect {port}: {e}) logging.error(Could not find or connect to robot.) def _read_loop(self): 持续读取串口数据如音频流、状态上报 while self.is_connected and self.ser: try: if self.ser.in_waiting: line self.ser.readline().decode().strip() if line: self._handle_incoming_data(line) except Exception as e: logging.error(fError reading serial: {e}) break def _handle_incoming_data(self, data): 处理从设备上报的数据 if data.startswith(DATA:AUDIO): # 处理音频数据头准备接收二进制音频帧 pass elif data.startswith(EVENT:): event data.split(:)[1] logging.info(fDevice event: {event}) else: logging.debug(fFrom device: {data}) def send_command(self, cmd_type, **kwargs): 发送指令到设备 if not self.is_connected: logging.error(Not connected to device.) return False # 构建协议字符串例如 CMD:MOVE, X:100, Y:50 if cmd_type MOVE: cmd_str fCMD:MOVE, X:{kwargs[x]}, Y:{kwargs[y]}\n elif cmd_type CLICK: btn kwargs.get(button, LEFT) cmd_str fCMD:CLICK, BTN:{btn}\n elif cmd_type TYPE: text kwargs[text].replace(\n, \\n) cmd_str fCMD:TYPE, TEXT:{text}\n else: logging.error(fUnknown command type: {cmd_type}) return False try: self.ser.write(cmd_str.encode()) return True except Exception as e: logging.error(fFailed to send command: {e}) self.is_connected False return False def disconnect(self): self.is_connected False if self.ser: self.ser.close()4.3 AI对话与控制逻辑集成这是项目的智能核心。我们可以接入大语言模型LLM的API让机器人不仅能对话还能理解自然语言指令并转化为桌面操作。1. 调用AI API以 OpenAI ChatGPT 格式为例# ai_client.py import requests import json import logging from typing import List, Dict, Any class AIClient: def __init__(self, api_key: str, base_url: str https://api.openai.com/v1): self.api_key api_key self.base_url base_url self.headers { Authorization: fBearer {api_key}, Content-Type: application/json } # 定义系统提示词告诉AI它的角色和能力 self.system_prompt 你是一个桌面助手机器人可以控制鼠标、键盘并执行电脑操作。 用户可能会用自然语言描述任务你需要将其解析为明确的指令。 可用的指令类型有 - MOVE [x] [y]: 将鼠标移动到相对当前位置的(x, y)像素点。x, y为整数。 - CLICK [button]: 点击鼠标按钮。button可以是 LEFT, RIGHT, MIDDLE。 - DOUBLE_CLICK: 双击左键。 - SCROLL [amount]: 滚动滚轮。amount为正数向上负数向下。 - TYPE [text]: 输入文本。 - PRESS [key1, key2...]: 按下组合键如 [ctrl, c]。 - OPEN [app_name]: 打开应用程序需要预设映射。 - SEARCH [query]: 在浏览器中搜索。 请根据用户请求只输出一个JSON数组每个元素是一个指令对象。例如 用户说“选中所有文字并复制” 你输出[{action: PRESS, args: [ctrl, a]}, {action: PRESS, args: [ctrl, c]}] 用户说“把鼠标往右移动100像素然后点击” 你输出[{action: MOVE, args: [100, 0]}, {action: CLICK, args: [LEFT]}] 如果只是普通对话不涉及控制则输出空数组 []。 def chat_with_instruction(self, user_message: str) - (str, List[Dict]): 与AI对话并尝试解析出控制指令。 返回(AI的回复文本, 指令列表) messages [ {role: system, content: self.system_prompt}, {role: user, content: user_message} ] try: resp requests.post( f{self.base_url}/chat/completions, headersself.headers, json{ model: gpt-3.5-turbo, messages: messages, temperature: 0.2, max_tokens: 500 }, timeout30 ) resp.raise_for_status() result resp.json() ai_response_text result[choices][0][message][content].strip() # 尝试从回复中提取JSON数组 instructions [] # 简单查找JSON数组的开始和结束 start ai_response_text.find([) end ai_response_text.rfind(]) 1 if start ! -1 and end ! 0: try: instructions json.loads(ai_response_text[start:end]) except json.JSONDecodeError: logging.warning(Failed to parse instructions from AI response.) # 返回纯文本回复和指令列表 return ai_response_text, instructions except requests.exceptions.RequestException as e: logging.error(fAI API request failed: {e}) return 抱歉AI服务暂时不可用。, []2. 指令执行器# command_executor.py import logging from serial_controller import RobotSerialController class CommandExecutor: def __init__(self, serial_controller: RobotSerialController): self.sc serial_controller def execute_instructions(self, instructions: List[Dict]): 执行AI解析出来的指令列表 for instr in instructions: action instr.get(action) args instr.get(args, []) try: if action MOVE: self.sc.send_command(MOVE, xargs[0], yargs[1]) elif action CLICK: self.sc.send_command(CLICK, buttonargs[0].upper()) elif action TYPE: self.sc.send_command(TYPE, text .join(args)) elif action PRESS: # 将组合键转换为一系列按键操作需在固件端实现组合键逻辑 # 简化处理假设固件支持组合键指令 CMD:PRESS, KEYS:ctrl,c key_str ,.join(args).lower() self.sc.send_command(PRESS, keyskey_str) # ... 处理其他指令类型 logging.info(fExecuted: {action} {args}) except Exception as e: logging.error(fFailed to execute {action} {args}: {e})4.4 语音识别集成我们可以使用离线的SpeechRecognition库配合pyaudio或在线API如百度、科大讯飞来实现语音转文本。使用离线识别需安装pyaudio和SpeechRecognition# voice_engine.py import speech_recognition as sr import logging import threading class VoiceEngine: def __init__(self, serial_controller, ai_client, command_executor): self.recognizer sr.Recognizer() self.microphone sr.Microphone() self.sc serial_controller self.ai_client ai_client self.executor command_executor self.is_listening False def start_listening(self): 开始后台语音监听线程 self.is_listening True thread threading.Thread(targetself._listen_loop, daemonTrue) thread.start() logging.info(Voice engine started.) def _listen_loop(self): with self.microphone as source: self.recognizer.adjust_for_ambient_noise(source, duration1) while self.is_listening: try: logging.debug(Listening...) audio self.recognizer.listen(source, timeout3, phrase_time_limit5) text self.recognizer.recognize_google(audio, languagezh-CN) logging.info(fRecognized: {text}) # 将识别文本交给AI处理 ai_response, instructions self.ai_client.chat_with_instruction(text) logging.info(fAI says: {ai_response}) if instructions: self.executor.execute_instructions(instructions) except sr.WaitTimeoutError: continue except sr.UnknownValueError: logging.debug(Could not understand audio.) except sr.RequestError as e: logging.error(fSpeech recognition error: {e}) except Exception as e: logging.error(fUnexpected error in listen loop: {e}) def stop_listening(self): self.is_listening False4.5 手机控制HTTP API通过一个简单的HTTP服务器我们可以用手机浏览器或专用App发送控制指令。# web_api.py from flask import Flask, request, jsonify import threading import logging class WebControlAPI: def __init__(self, serial_controller, command_executor, host0.0.0.0, port5000): self.sc serial_controller self.executor command_executor self.app Flask(__name__) self.host host self.port port self._setup_routes() def _setup_routes(self): self.app.route(/api/control, methods[POST]) def control(): data request.json action data.get(action) args data.get(args, []) if action move: self.sc.send_command(MOVE, xargs[0], yargs[1]) elif action click: self.sc.send_command(CLICK, buttonargs[0]) elif action type: self.sc.send_command(TYPE, textargs[0]) # ... 其他指令映射 return jsonify({status: ok}) self.app.route(/api/ai_chat, methods[POST]) def ai_chat(): text request.json.get(text) # 这里需要接入ai_client为简化示例直接返回 return jsonify({reply: fReceived: {text}}) self.app.route(/) def index(): return htmlbody h1Desktop Robot Control/h1 button onclickmove(0, -50)Up/buttonbr button onclickmove(-50,0)Left/button button onclickclick()Click/button button onclickmove(50,0)Right/buttonbr button onclickmove(0,50)Down/button script function move(x,y){fetch(/api/control,{method:POST,headers:{Content-Type:application/json},body:JSON.stringify({action:move,args:[x,y]})});} function click(){fetch(/api/control,{method:POST,headers:{Content-Type:application/json},body:JSON.stringify({action:click,args:[LEFT]})});} /script /body/html def run(self): 在独立线程中运行Flask服务器 thread threading.Thread(targetself.app.run, kwargs{host: self.host, port: self.port, debug: False, use_reloader: False}) thread.daemon True thread.start() logging.info(fWeb control API started at http://{self.host}:{self.port})4.6 主程序整合最后我们将所有模块整合到一个主程序中。# main.py import logging import time from serial_controller import RobotSerialController from ai_client import AIClient from command_executor import CommandExecutor from voice_engine import VoiceEngine from web_api import WebControlAPI logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s) def main(): # 1. 初始化串口控制器连接ESP32 sc RobotSerialController() # 自动查找端口 if not sc.is_connected: logging.error(Failed to connect to robot hardware. Exiting.) return # 2. 初始化AI客户端需要配置你的API Key ai AIClient(api_keyyour_openai_api_key_here) # 请替换为实际Key # 3. 初始化指令执行器 executor CommandExecutor(sc) # 4. 初始化语音引擎可选 voice_engine VoiceEngine(sc, ai, executor) # voice_engine.start_listening() # 如需语音控制取消注释 # 5. 初始化Web API手机控制 web_api WebControlAPI(sc, executor, host0.0.0.0, port5000) web_api.run() logging.info(Desktop Robot started successfully!) logging.info(Control via: 1. Serial Command 2. Voice 3. Web UI http://your_ip:5000) # 主循环保持程序运行 try: while True: # 这里可以添加其他轮询任务例如从GUI读取指令 time.sleep(1) except KeyboardInterrupt: logging.info(Shutting down...) sc.disconnect() if __name__ __main__: main()5. 完整部署与使用流程5.1 硬件组装与固件烧录硬件连接使用杜邦线将INMP441麦克风模块按照前述引脚定义连接到ESP32-S3开发板。固件烧录在Arduino IDE中选择开发板ESP32S3 Dev Module。选择正确的端口Port。将完整的固件代码包含HID描述符、I2S配置、串口协议解析上传到开发板。上传成功后打开串口监视器波特率设置为115200应看到[INFO] Robot Ready之类的启动日志。5.2 电脑端环境配置与运行安装依赖在电脑上安装Python及上述列出的库 (pyserial,requests等)。配置参数在main.py中将AIClient的api_key替换为你自己的OpenAI API Key或其他兼容API的Key和URL。检查serial_controller.py中的波特率是否与固件设置一致默认115200。运行主程序在项目根目录下执行python main.py。验证连接程序应自动找到ESP32设备并连接打印成功日志。5.3 功能测试基础控制测试在程序运行后你可以在Python交互环境或修改main.py临时添加测试代码发送指令# 临时测试 sc.send_command(MOVE, x100, y100) sc.send_command(CLICK, buttonLEFT)观察鼠标是否相应移动和点击。AI对话测试修改main.py在初始化后直接调用AIreply, instr ai.chat_with_instruction(帮我打开记事本) print(fAI回复: {reply}) print(f解析指令: {instr}) executor.execute_instructions(instr)观察AI是否解析出正确的操作指令如打开记事本可能需要预设应用映射。语音控制测试取消main.py中voice_engine.start_listening()的注释对着麦克风说“向上移动鼠标”观察鼠标是否移动。手机控制测试确保电脑和手机在同一局域网。在电脑上运行ipconfig(Windows) 或ifconfig(Linux/macOS) 查看本机IP。在手机浏览器输入http://电脑IP:5000打开控制页面点击按钮测试控制是否生效。6. 常见问题与排查思路在制作和运行过程中你可能会遇到以下问题问题现象可能原因排查思路与解决方案电脑无法识别ESP32为HID设备1. 固件中HID报告描述符错误。2. USB数据线仅供电不支持数据传输。3. 驱动问题。1. 检查并确保使用了正确的、完整的HID报告描述符。2. 更换一根已知良好的数据线。3. 在设备管理器中查看是否有未知设备尝试重新安装ESP32-S3的USB驱动。串口连接失败1. 端口被占用。2. 波特率不匹配。3. 驱动未安装。1. 关闭其他可能占用串口的软件如Arduino IDE串口监视器。2. 确认固件和电脑端程序使用相同的波特率如115200。3. 安装CP210x或CH340驱动。语音识别无反应或错误率高1. 麦克风连接错误或损坏。2. 环境噪音太大。3. 离线识别库不支持中文或精度低。1. 用万用表检查麦克风供电或用示波器/逻辑分析仪检查I2S信号。2. 在安静环境下测试或增加软件降噪。3. 考虑换用在线语音识别API如百度、讯飞精度更高。AI指令解析不准确1. 系统提示词System Prompt描述不清晰。2. AI模型理解偏差。3. 指令映射规则不完善。1. 优化系统提示词更详细地定义指令格式和示例。2. 尝试让AI在回复中先复述理解的任务再输出指令。3. 在command_executor.py中增加更多指令类型和容错处理。手机网页无法访问控制界面1. 电脑防火墙阻止了5000端口。2. 手机和电脑不在同一网络。3. Flask服务未成功启动。1. 在电脑防火墙设置中允许5000端口的入站连接。2. 确保手机连接的是同一个Wi-Fi。3. 检查程序日志确认Web control API started日志已打印。鼠标移动不流畅或跳跃1. 串口指令发送频率过高或过低。2. 单次移动位移过大超出HID报告范围。1. 在固件和电脑端代码中加入适当的延时如time.sleep(0.01)。2. 确保move函数正确处理了超出-127~127范围的移动将其拆分为多次小移动。程序占用CPU或内存过高1. 语音识别或AI API调用循环阻塞。2. 线程未正确管理。1. 为语音识别和网络请求等IO密集型操作使用异步asyncio或线程池。2. 检查是否有死循环或资源未释放。使用logging监控各线程状态。7. 优化方向与进阶玩法完成基础版本后你可以从以下几个方面进行优化和扩展让你的桌面机器人更强大、更实用固件优化低功耗模式当无操作时让ESP32进入轻睡眠通过USB或特定串口指令唤醒。本地简单指令识别在ESP32上集成TinyML框架如TensorFlow Lite Micro实现本地关键词唤醒如“你好机器人”减少对电脑的依赖。增加状态反馈添加RGB LED或蜂鸣器用不同灯光或声音表示“正在聆听”、“执行成功”、“错误”等状态。电脑端功能增强图形化界面GUI使用PyQt或Tkinter制作一个控制面板集成语音开关、指令录制回放、自定义宏等功能。指令录制与宏实现“录制”功能记录一系列鼠标键盘操作并保存为可重复执行的脚本。应用场景化预设针对不同应用如Photoshop、代码编辑器、游戏的专用指令集和AI提示词。多AI模型支持除了OpenAI可以接入本地部署的Ollama、通义千问、文心一言等API提供更多选择。网络与远程控制强化内网穿透使用frp或ngrok将本地Web API暴露到公网实现真正的远程控制。安全加固为Web API添加简单的Token认证防止被他人随意访问。开发手机App用Flutter或React Native开发一个专用App提供比网页更流畅的控制体验和手势操作。AI能力深化视觉能力集成使用电脑摄像头或额外USB摄像头通过OpenCV和视觉AI模型让机器人具备“看到”屏幕并理解内容的能力如自动识别按钮位置。上下文记忆让AI记住之前的对话和操作实现多轮交互和更复杂的任务规划。这个项目最大的乐趣在于其可扩展性。几十元的硬件成本只是一个起点通过软件和AI的赋能它可以演化成高度个性化的生产力工具。你可以根据自己的需求不断为其添加新的技能模块。
返回列表