最近在 DF 创客商城入手了刚上架的Arduino UNO Q,开箱上手、调试编程的整个过程充满惊喜,不仅系统学习了 Linux 嵌入式、边缘 AI、双核心协同等前沿知识,还解锁了从传统单片机控制到智能视觉、语音识别的全新创作路径,无数创意点子在脑海里迸发。这块集经典兼容、Linux 系统、本地 AI、实时控制于一体的全能开发板,彻底打破了传统 Arduino 的性能边界,成为我手边又一件高效、好用、潜力无限的创客制作利器,未来的智能小车、环境监测站、交互装置、AI 小机器人都有了更强大的硬件底座!
【Arduino UNO Q 简介】
Arduino UNO Q是 Arduino 新一代高性能全能型开发板,专为创客、学生、开发者打造,既保留经典 UNO 的易用性,又搭载 “双大脑”,一步迈入 Linux 与边缘 AI 时代,是新手进阶、老玩家升级的首选主力板。
- 双核心 “神仙组合”
一边是STM32U585 实时单片机,精准控灯、舵机、传感器,延迟极低、稳如老狗;另一边是高通四核处理器,跑完整 Debian Linux,能跑 Python、跑 AI 模型、连 WiFi / 蓝牙,相当于把 “微型电脑 + 经典 Arduino” 焊在一块板上。 - 自带 Linux 系统,不用外接电脑也能开发
板载 2GB/4GB 内存 + 16GB/32GB 存储,预装 Linux 系统,可直接在板上运行 Arduino IDE、写代码、跑程序,接显示器鼠标就能当迷你开发机用,外出调试超方便。 - 原生支持边缘 AI,本地就能做人脸 / 物体识别
不用上云、不依赖服务器,本地直接跑目标检测、图像分类、关键词识别,做智能门禁、跟随机器人、语音交互装置门槛大幅降低。 - 完美兼容经典 UNO 生态
保留标准 UNO 接口尺寸,你手里现有的传感器、扩展板、模块直接插就能用,老项目无缝迁移,新项目直接起飞。 - 接口现代、联网齐全
标配USB-C(支持 PD 供电)、Qwiic 快连接口、高速 GPIO,自带WiFi 5 + 蓝牙 5.1,物联网、远程控制、无线传输一步到位。
它是能跑 Linux、能玩 AI、能精准控制硬件、兼容所有 UNO 配件的下一代 Arduino,从小白入门到高阶智能创作,一块板全覆盖,是当前最值得入手的创客全能神器。
【Arduino IDE】
Arduino UNO Q 兼容标准 Arduino IDE,可使用你熟悉的 Arduino 语言与生态系统对开发板进行编程。(Arduino UNO Q 搭载双处理器:Arduino IDE 只能编程其中的 STM32 微控制器;如果要开发高通处理器部分,可使用 Arduino App Lab 。)
测试:使用点阵屏播放“Bad Apple”
1.安装 UNO Q 开发板核心
手动添加安装包啦。操作步骤:打开「文件」>「首选项」,把下面这个链接粘贴到「附加开发板管理器网址」的输入框里:
- https://downloads.arduino.cc/packages/package_zephyr_index.json
复制代码 2.程序代码
使用UNO Q的”Arduino_LED_Matrix”——“video”示例 - #include "Arduino_LED_Matrix.h"
- #include "bad_apple.h"
-
- Arduino_LED_Matrix matrix;
-
- void setup() {
- matrix.begin();
- matrix.setGrayscaleBits(8);
- }
-
- void loop() {
- matrix.playVideo(bad_apple, bad_apple_len);
- }
复制代码
3.演示视频
【Arduino App Lab】
Arduino App Lab 是一款一站式开发工具,把咱们熟悉的 Arduino 玩法拓展到了高性能计算领域。用它可以把 Arduino 代码、Python 脚本和 Linux 容器应用完美融合,全程开发不用来回切换工具。
它自带「Bricks(代码积木)」、现成的 AI 模型,以及集成化的任务编排功能,能做出从简单小原型到高算力复杂应用的各种作品,新手也能轻松上手。
根据官网操作文档,下载Arduino App Lab,安装并连接UNO Q。
踩坑指南
1.Arduino App Lab卡在“检查更新”界面,这可能是由开发板固件版本过低引起的。
按照官方指南使用arduino-flasher-cli工具重刷最新固件。
2.准备硬件时需要用一个母对母跳线短接两个特定引脚,其目的是让UNO Q进入特殊的刷机模式(类似“下载模式”或“恢复模式”),以便后续连接电脑刷写固件。
【示例体验】
1.“UNO Q Pin Toggle”
你可通过简洁的交互式开发板可视化界面,在浏览器中控制 Arduino UNO Q 的每一个引脚。拨动开关即可切换引脚的通断状态,且所有状态变化会实时反馈显示。本示例展示了一套简洁易用的实时控制面板,你可在此基础上扩展为功能更丰富的监控仪表盘与自动化控制系统。
2.“Weather forecast on LED matrix”
修改示例ino文件,在原单一显示程序中指定的城市天气,实现通过按钮切换多个城市天气显示。
 - // SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL ([url]http://www.arduino.cc[/url])
- //
- // SPDX-License-Identifier: MPL-2.0
-
- #include <Arduino_LED_Matrix.h>
- #include <Arduino_RouterBridge.h>
-
- #include "weather_frames.h"
-
- // 1. 定义7个中国主要城市列表(拼音,适配open-meteo API)
- String cities[] = {"Zhangjiakou","Beijing", "Shanghai", "Guangzhou", "Shenzhen", "Chengdu", "Chongqing"};
- // 当前选中的城市索引(初始为0,对应张家口)
- int currentCityIndex = 0;
- // 城市总数
- const int cityCount = sizeof(cities) / sizeof(cities[0]);
-
- // 按钮相关定义
- const int BUTTON_PIN = 4; // 按钮接引脚4
- bool lastButtonState = LOW; // 上一次按钮状态(初始低电平)
- unsigned long lastDebounceTime = 0; // 消抖时间记录
- const unsigned long debounceDelay = 50; // 消抖延时(50ms)
-
- Arduino_LED_Matrix matrix;
-
- void setup() {
- // 初始化LED点阵屏
- matrix.begin();
- matrix.clear();
-
- // 初始化Bridge通信
- Bridge.begin();
-
- // 初始化按钮引脚(上拉输入模式,无需外接上拉电阻)
- pinMode(BUTTON_PIN, INPUT_PULLUP);
-
- // 启动时显示第一个城市(张家口)的天气
- updateWeatherForecast();
- }
-
- void loop() {
- // 检测按钮按下并切换城市
- checkButtonPress();
-
- // 持续播放当前城市的天气动画(无需频繁调用API,避免限流)
- matrix.playSequence();
- }
-
- // 检测按钮按下(带消抖),切换城市并更新天气
- void checkButtonPress() {
- // 读取当前按钮状态(INPUT_PULLUP模式下,按下为HIGH,松开为LOW)
复制代码

【马到成功】
新年“马上”就要到了,马年祝大家,事事顺意,马到成功。
1.“LED Matrix Painter”
LED 矩阵绘制器示例提供了一个基于网页的交互界面,可实时绘制、制作动画并控制 Arduino UNO Q 内置的 LED 点阵屏。该工具具备像素编辑功能(支持 3 位色深 / 0-7 级亮度调节)、设计方案的数据库存储功能,还内置代码生成器,可将你设计的帧动画导出为可直接使用的 C++ 代码。
该应用支持你直接在浏览器中为 8×13 LED 点阵屏设计视觉效果。它借助 web_ui 功能模块搭建了一个图形化编辑器,你可在其中绘制单个像素点、调节像素亮度,还能对图案执行翻转、旋转等变换操作。你在浏览器中做出的每一处修改,都会即时同步到物理开发板上呈现。
演示视频
2.修改示例,实现一键“平移动画生成器”
它会根据当前编辑的图案,自动生成从左到右移动的多帧动画。
1) 首先在 HTML 中添加按钮在 index.html 文件中的 animation-options 部分添加一个新按钮: - <button id="generate-horizontal" class="anim-option-btn" title="生成水平移动动画"> <img src="img/arrow-right.svg" alt="水平移动" style="width: 16px; height: 16px;">
- </button>
复制代码 2)在 CSS 中添加样式
在 style.css 中添加按钮样式: - /* 为生成动画按钮添加样式 */
- #generate-horizontal {
- border: 1px solid #C9D2D2;
- border-radius: 8px;
- padding: 6px;
- background-color: transparent;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
- color: #2C353A;
- }
-
- #generate-horizontal:hover {
- background-color: rgba(0, 129, 132, 0.08);
- }
-
- #generate-horizontal img {
- width: 16px;
- height: 16px;
- }
复制代码 3) 在 JavaScript 中实现核心功能 在 app.js 中添加以下代码: - // 获取生成水平移动动画的按钮
- const generateHorizontalBtn = document.getElementById('generate-horizontal');
-
- // 生成水平移动动画的函数
- async function generateHorizontalAnimation() {
- if (loadedFrameId === null) {
- showError('请先选择一个帧作为基础图案');
- setTimeout(hideError, 3000);
- return;
- }
-
- // 询问用户要生成多少帧
- const frameCountInput = prompt('请输入要生成的帧数(建议 13-39 帧,数字越大动画越流畅):', '26');
- if (!frameCountInput) return;
-
- const count = parseInt(frameCountInput, 10);
- if (isNaN(count) || count < 5) {
- showError('请输入至少 5 帧');
- setTimeout(hideError, 3000);
- return;
- }
-
- try {
- // 获取当前帧的图案
- const currentGrid = collectGridBrightness();
-
- // 计算动画参数
- // 图案宽度为 COLS (13列)
- // 为了让图案从左侧外出现到右侧外消失,总共需要移动 COLS + 当前帧宽度步数
- // 但实际上我们让图案从左侧外完全看不到,到完全进入,再到完全出去
- const patternWidth = COLS; // 图案宽度
- const totalMovement = patternWidth + COLS; // 完全进入 + 完全出去需要的步数
-
- // 创建保存所有新帧的数组
- const newFrames = [];
-
- // 生成每一帧
- for (let i = 0; i < count; i++) {
- // 计算当前帧的偏移量
- // 从完全在左侧外(-COLS)开始,到完全在右侧外(+COLS)结束
- const progress = i / (count - 1); // 0 到 1 的进度
- const offset = Math.floor(-COLS + progress * (2 * COLS));
-
- // 创建新帧的图案
- const newRows = [];
- for (let r = 0; r < ROWS; r++) {
- const newRow = [];
- for (let c = 0; c < COLS; c++) {
- // 计算图案中对应的列
- const sourceCol = c - offset;
-
- // 如果源列在图案范围内,则使用图案的值,否则为0
- if (sourceCol >= 0 && sourceCol < patternWidth) {
- newRow.push(currentGrid[r][sourceCol]);
- } else {
- newRow.push(0);
- }
- }
- newRows.push(newRow);
- }
-
- // 添加新帧到数组
- newFrames.push({
- rows: newRows,
- name: `水平移动 ${i + 1}/${count}`,
- duration_ms: Math.max(30, Math.floor(1000 / count)) // 根据帧数计算合适的时长
- });
- }
-
- // 批量保存所有新帧
- for (let i = 0; i < newFrames.length; i++) {
- const frame = newFrames[i];
- await fetchWithHandling('/persist_frame', {
- method: 'POST',
- headers: {'Content-Type': 'application/json'},
- body: JSON.stringify({
- rows: frame.rows,
- name: frame.name,
- duration_ms: frame.duration_ms,
- brightness_levels: BRIGHTNESS_LEVELS
- })
- }, 'json', `保存第 ${i + 1} 帧`);
- }
-
- // 刷新帧列表
- await refreshFrames();
-
- // 加载第一帧
- if (sessionFrames.length > 0) {
- // 找到最新创建的帧(最后保存的那个)
- const latestFrame = sessionFrames[sessionFrames.length - 1];
- // 但我们需要找到水平移动动画的第一帧
- const horizontalFrames = sessionFrames.filter(f => f.name.startsWith('水平移动'));
- if (horizontalFrames.length > 0) {
- await loadFrameIntoEditor(horizontalFrames[0].id);
- }
- }
-
- showError(`成功生成 ${count} 帧水平移动动画!`);
- setTimeout(hideError, 3000);
-
- } catch (error) {
- console.error('生成水平移动动画失败:', error);
- showError('生成动画失败: ' + error.message);
- setTimeout(hideError, 5000);
- }
- }
-
- // 为按钮添加事件***
- if (generateHorizontalBtn) {
- generateHorizontalBtn.addEventListener('click', generateHorizontalAnimation);
- }
复制代码
4)演示视频
|