小智机器人

1.引言 最近有一个很火的开源项目小智机器人-xiaozhi-esp32。 类似于小度音箱和小爱音箱,你可以和小智进行语音沟通,但是小智的服务端对接了大模型(千问、DeepSeek等)。 所以它是一个智能体,可以和用户进行更丰富和有趣的对话。 2.特点 2.1 开源MIT协议,可以用于商用 2.2 支持语音唤醒 需要特定硬件 2.3 基于流式 ASR + LLM + TTS 架构的语音交互 2.4 OLED / LCD 显示屏,支持表情显示 2.5 设备端为ESP32-C3、ESP32-S3、ESP32-P4 芯片平台 价格低廉(最便宜大概50元左右,一般情况小于200元) 立创开发板 立创的这块开发板还带有摄像头,也就是说可以进行图像识别。爱动手的可以买元器件自己装,懒人可以直接在淘宝和京东上买成品。 2.6 后端也有开源实现 xinnan-tech/xiaozhi-esp32-server Python 服务器 joey-zhou/xiaozhi-esp32-server-java Java 服务器 AnimeAIChat/xiaozhi-server-go Golang 服务器 其实虾哥的版本,只开源了客户端和通讯协议,Server的实现都来自第三方 2.7 支持MCP扩展大模型能力 可以实现智能家居控制、PC桌面操作、知识搜索、邮件收发等 小智原生已经带有播放音乐、天气预报、新闻等功能 为了将MCP服务接入小智,萌叔开发了 vearne/xiaozhi-mcp-pipe,欢迎使用。 2.8 有记忆功能 参考 mem0 和 mem0-research 3. 原理&技术 3.1 原理 ESP32芯片的性能非常弱,几百MHz,<1MB的内存,因此几乎所有的功能都是在服务端实现的。 1)【Client】ESP32硬件通过麦克风采集原始音频数据,通过Websocket协议传到Server 2)【Server】对音频数据进行语音识别,转换为文字 3)【Server】使用文字与大模型进行交互,得到回答(文字),回答可能包含指令(控制与之连接的其他外围设备或IoT设备,例如智能灯泡、传感器等) 4)【Server】文字通过TTS转成音频数据,通过Websocket协议再发到ESP32硬件 5)【Client】ESP32硬件通过扬声器播放给用户 3.2 技术 以xinnan-tech/xiaozhi-esp32-server为例说明 LLM 语言模型 使用方式 支持平台 免费平台 openai 接口调用 阿里百炼、火山引擎豆包、深度求索、智谱ChatGLM、Gemini 智谱ChatGLM、Gemini ollama 接口调用 Ollama - dify 接口调用 Dify - fastgpt 接口调用 Fastgpt - coze 接口调用 Coze - 实际上,任何支持 openai 接口调用的 LLM 均可接入使用。 ...

August 13, 2025 · 1 min

玩转Arduino(4)-天气预报

硬件 ESP32 开发板 0.96寸OLED 128*64 思路 ESP32 开发板自带WIFI和蓝牙 Step1 使用开发板连接家里的WIFI热点 注意修改代码中的WIFI SSID和password Step2 使用和风天气API,获取天气信息 和风天气的API默认访问https://devapi.qweather.com 需要使用SSL,对单片机开发非常麻烦,我重新封装代理了对应接口,简化了调用过程。 可使用 http://qweather.vearne.com/v7/weather/3d?location=101010100&amp;lang=en&amp;key=xxx 访问和风天气API,注意修改秘钥key 代码库为vearne/simpleQweather Step3 解析Response,将天气信息显示在OLED显示屏幕上 代码 完整代码 weather #include &lt;WiFi.h&gt; #include &lt;HTTPClient.h&gt; #include &lt;Arduino.h&gt; #include &lt;Arduino_JSON.h&gt; #include &lt;SPI.h&gt; #include &lt;Wire.h&gt; #include &lt;Adafruit_GFX.h&gt; #include &lt;Adafruit_SSD1306.h&gt; #include &quot;BitmapData.h&quot; #define LOGO_HEIGHT 16 #define LOGO_WIDTH 16 #define WEATHER_X 50 const char *ssid = &quot;vearne-Guest&quot;; // Change this to your WiFi SSID const char *password = &quot;xxxx&quot;; // Change this to your WiFi password // Change key to your api key // https://dev.qweather.com/docs/configuration/project-and-key/ const char *url = &quot;http://qweather.vearne.com/v7/weather/3d?location=101010100&amp;lang=en&amp;key=xxx&quot;; #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &amp;Wire, OLED_RESET); void setup() { Serial.begin(115200); while (!Serial) { delay(100); } // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println(F(&quot;SSD1306 allocation failed&quot;)); for (;;) ; // Don&#039;t proceed, loop forever } // We start by connecting to a WiFi network Serial.println(); Serial.println(&quot;******************************************************&quot;); Serial.print(&quot;Connecting to &quot;); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print(&quot;.&quot;); } Serial.println(&quot;&quot;); Serial.println(&quot;WiFi connected&quot;); Serial.println(&quot;IP address: &quot;); Serial.println(WiFi.localIP()); } void loop() { if (WiFi.status() == WL_CONNECTED) { HTTPClient http; // 开始请求 // http.addHeader(const String &amp;name, const String &amp;value) http.begin(url); // 发送 GET 请求 int httpCode = http.GET(); // 如果请求成功 if (httpCode &gt; 0) { // 读取响应 String payload = http.getString(); Serial.println(&quot;响应内容:&quot;); Serial.println(payload); // 结束请求 http.end(); JSONVar weatherData = JSON.parse(payload); if (JSON.typeof(weatherData) == &quot;undefined&quot;) { Serial.println(&quot;Parsing input failed!&quot;); return; } // 获取第一天的天气信息 JSONVar firstDay = weatherData[&quot;daily&quot;][0]; String tempMax = (const char *)firstDay[&quot;tempMax&quot;]; String tempMin = (const char *)firstDay[&quot;tempMin&quot;]; String windScale = (const char *)firstDay[&quot;windScaleDay&quot;]; String fxDate = (const char *)firstDay[&quot;fxDate&quot;]; String iconDay = (const char *)firstDay[&quot;iconDay&quot;]; switch (iconDay.toInt()) { case 100: drawOLED(sun, fxDate, tempMin, tempMax, windScale); break; case 101: drawOLED(cloudy, fxDate, tempMin, tempMax, windScale); break; case 102: drawOLED(cloud, fxDate, tempMin, tempMax, windScale); default: drawOLED(rain, fxDate, tempMin, tempMax, windScale); break; } } else { Serial.println(&quot;WiFi 未连接&quot;); } delay(1000 * 300); // 等待 5min } } void drawOLED(const uint8_t *bitmap, String dateStr, String tempMin, String tempMax, String windScale) { display.clearDisplay(); // weather icon display.drawBitmap( 10, 10, bitmap, LOGO_WIDTH, LOGO_HEIGHT, 1); // temp &amp; wind display.setTextSize(1); // Normal 1:1 pixel scale display.setTextColor(WHITE); // Draw white text display.setCursor(WEATHER_X, 10); display.print(&quot;temp: &quot;); String s = &quot;&quot;; s.concat(tempMin); s.concat(&quot;~&quot;); s.concat(tempMax); display.println(s); display.setCursor(WEATHER_X, 25); display.print(&quot;wind: &quot;); display.println(windScale); // line display.drawLine(0, 45, display.width() - 1, 45, WHITE); // date display.setTextSize(2); // Normal 1:1 pixel scale display.setTextColor(WHITE); // Draw white text display.setCursor(5, 50); // Start at top-left corner display.println(dateStr); display.display(); delay(1000); } 库依赖 1.Adafruit_SSD1306 2.Arduino_JSON 3.ArduinoHttpClient 4.WiFi ...

November 23, 2024 · 3 min

试玩单片机的进展和感想

警告:本文仅用于萌叔自己总结之用,对其它人而言可能毫无营养,没有阅读价值。 1.总结 自2024年10月接触Arduino Uno电子平台以来, 萌叔购买了2块开发板和一系列的配件,尝试使用这些配件,并完成了若干小实验。具体如下 1.玩转Arduino(1)-自制温度湿度计 2.玩转Arduino(2)-按钮控制小灯 3.玩转Arduino(3)-感应式垃圾桶 4.玩转Arduino(4)-天气预报 2. 感想 其实感想才是萌叔想重点说的 2.1 单片机的自动化控制相对软件开发要简单很多 生活中大部分的单片机使用的场景都非常简单,比如停车场的自动升降杆、感应式垃圾桶。对应的代码开发量非常的少。相对而言,现在的软件开发非常的复杂,一个普通工程师需要掌握多种开发语言,好几种框架云原生等等卷的飞起。 2.2 整个单片机开发过程,犹如搭建积木 每种配件厂商几乎都有完善且对应的驱动包,特别典型的是步进电机。每种配件相当于一块积木,普通开发者通常只需要使用配件对应的驱动,就可以构建出非常炫酷的功能。最终达到的效果是1 + 1 > 2 的。 2.3 配件和开发板之间也有标准协议进行通讯 类似 I2C和 SPI。 2.4 配件底层涉及多学科知识 笔者在2.1 提到的单片机的自动化控制相对软件开发简单,指的是不涉及配件底层知识,单纯调用驱动的接口的情况。 一旦涉及底层,情况就复杂的多。 比如 RF433MHZ 涉及电磁波和电谐振 步进电机涉及电和磁力的转换 2.5 单片机的配套硬件和软件情况 单片机的硬件非常的弱,比如Arduino UNO的MCU ATmega328 运行内存只有2 KB。 以至于很多库(类似JSON和HTTP库)必须重新定制 软件方面是发现了FreeRTOS, FreeRTOS是有进程(Task)调度的。 单片机的场景,硬件性能弱,对应的软件也就简单,反而觉得更适合初学者学习了,萌叔推荐本科教育应该从单片机入手。 2.6 行业壁垒相比过去大幅降低了 这次尝试玩硬件,纯粹是一时兴起,然后萌叔发现上手几乎毫无难度。 这当然要感谢十几年的软件开发经历,但更多的还是要感谢时代的进步。 2.6.1 工业克鲁苏 中国的硬件制造商把开发板的价格卷到只要几十块,配件的价格卷到只有几块。 以前配件和开发板相连,往往还需要电烙铁焊接,现在一般都有对应扩展板,直接插端子就行。 2.6.2 Arduino平台 类似Arduino这种开源平台,使得开发板和配件驱动安装变得非常简单,代码开发调试也非常方便 2.6.1 开源精神 互联网(包含github)提供了完整的驱动和教程 2.6.2 AI 编程中遇到的很多问题多亏了chatGPT,不然我的开发速度要慢很多 3.开发板 ESP32 Arduino Uno 4.配件 编号 硬件设备 是否使用 备注 1 湿度温度传感器 是 2 LCD1602 是 3 按钮 是 4 LED小灯 是 5 舵机 是 6 单路马达 是 7 红外线接收器 是 8 超声波传感器 是 9 实时时钟模块 是 10 红外线传感器 是 11 RFID射频感应模块 否 12 步进电机 是 只能朝一个方向转? 13 OLED显示屏 是 14 旋转电位器 是 范围是0 ~ 978 15 继电器 是 收到高电平后,NO与COM形成通路 16 声音传感器 否 17 小喇叭 否 18 RF433MHZ 否 作者: vearne 文章标题: 试玩单片机的进展和感想 发表时间: 2024年11月22日 文章链接: https://vearne.cc/archives/40207 版权说明: CC BY-NC-ND 4.0 DEED ...

November 22, 2024 · 1 min