当前位置: 首页 > news >正文

基于Arduino与无源蜂鸣器的星战主题音乐盒DIY全攻略

1. 项目概述与设计思路

作为一个玩了十多年Arduino和各种嵌入式小玩意儿的老玩家,我一直觉得,把代码和电路塞进一个自己亲手做的壳子里,让它不仅能动、能响,还能成为桌上一件有故事的摆件,这才是DIY电子最大的乐趣。这次做的这个“星战主题音乐盒”,就是一个把这种乐趣发挥到极致的项目。它本质上是一个基于Arduino UNO的简易音乐播放器,但核心魅力在于,它完全复刻了老式点唱机(Jukebox)的交互形式,并且披上了《星球大战》中经典机器人R2-D2的外壳。你通过三个实体按钮来切歌、暂停,一块LCD屏幕会告诉你正在播放哪首经典旋律,而所有的声音,都来自于那个小小的、成本不到一块钱的被动式压电蜂鸣器。

为什么用压电蜂鸣器而不是MP3模块或喇叭?这恰恰是这个项目的精妙之处。对于《星球大战》这种拥有极具辨识度、旋律简单的主题音乐,用蜂鸣器来演绎,反而有一种复古的、8-bit游戏机般的独特风味,非常契合“手工制作”和“星战”这两个主题。它逼着你深入理解音乐的本质——频率和节奏。你需要将乐谱转换成一系列精确的频率值和延时,这个过程本身就是一次绝佳的数字信号处理入门课。同时,结合LCD显示和机械按钮,你又实践了经典的人机交互设计。从电路焊接、代码编写到外壳的测量、切割、粘贴,最后完成一个能看、能听、能互动的完整作品,这种全方位的成就感,是单纯买一个成品玩具无法比拟的。

这个项目非常适合有一定Arduino基础,想挑战综合性制作的朋友。你会用到数字输入(按钮)、模拟输入(电位器调节对比度)、数字输出(驱动蜂鸣器和LCD),并学习如何用状态机逻辑来管理播放列表。即使你是新手,只要跟着步骤一步步来,也能顺利完成。接下来,我就把自己从电路搭设、代码调试到外壳制作的全过程,包括中间踩过的坑和总结的技巧,毫无保留地分享给你。

2. 核心元件选型与电路解析

2.1 主控与发声单元:为什么是Arduino UNO与被动蜂鸣器?

项目的主控核心是Arduino UNO(或其兼容板如Elegoo UNO R3)。选择它理由很充分:首先,其ATmega328P芯片的16MHz主频和32KB闪存,对于处理几首用tone()函数生成的音乐代码绰绰有余;其次,UNO板拥有足够多的数字I/O口(14个)来驱动LCD和按钮,社区支持度极高,任何问题都能轻松找到答案;最后,其USB供电和编程的便利性,使得开发调试过程非常顺畅。

发声单元选用的是被动式压电蜂鸣器,这是本项目的声音灵魂。这里必须分清“有源”和“无源”蜂鸣器的区别:有源蜂鸣器内部自带振荡电路,给电就响,但只能发出固定频率的声音;而无源蜂鸣器内部没有振荡源,就像一个简单的扬声器,需要外部输入不同频率的方波才能发出不同音调。这正是我们需要的。Arduino的tone(pin, frequency)函数可以轻松地在指定引脚产生特定频率的方波,从而驱动无源蜂鸣器演奏旋律。它的优点是成本极低、驱动简单,且非常适合表现《星球大战》那种电子感强烈的音乐。

注意:购买时务必确认是“无源”或“被动式”蜂鸣器。有源蜂鸣器通常底部有密封的胶体或贴有标签,而无源的底部可以看到裸露的金属片和压电陶瓷片。用万用表电阻档测一下,电阻在8Ω或16Ω左右的通常是无源的。

2.2 人机交互界面:LCD1602与按钮的经典组合

显示部分采用最常见的LCD1602字符液晶屏(16列x2行)。它通过并行接口与Arduino通信,虽然需要连接较多的线(6条数据控制线+2条电源线),但库支持成熟,显示信息稳定可靠。为了调节屏幕对比度,我们使用了一个10kΩ的电位器。这是一个模拟输入应用,通过改变分压值来调整LCD_V0引脚的电压,从而控制显示深浅。

交互方面,三个 tactile按钮 构成了完整的播放控制逻辑:“上一曲”、“下一曲”、“播放/暂停”。这是最直观的物理交互方式。按钮电路采用经典的下拉电阻设计。当按钮未按下时,通过一枚1kΩ电阻将信号引脚连接到GND,确保输入为稳定的低电平(0);按下按钮时,引脚连接到5V,输入变为高电平(1)。这种设计可以有效避免引脚悬空导致的电平漂移和误触发。

2.3 电路连接详解与避坑指南

整个电路的连接可以分成电源、按钮、蜂鸣器、LCD四个部分。下面是基于我实际搭建的详细接线表,并附上了关键原理说明:

表1:核心电路连接清单

元件引脚/端连接到 Arduino UNO说明与注意事项
电源总线5V5V引脚为整个电路供电。建议在面包板或PCB上建立清晰的5V和GND总线。
GNDGND引脚公共地线,所有元件的GND最终都要汇于此。
按钮1 (上一曲)一脚Pin 2信号输入引脚。
另一脚通过1kΩ电阻接GND下拉电阻,确保空闲时为低电平。
同一脚(按钮)5V按下时,将Pin 2上拉到5V。
按钮2 (下一曲)一脚Pin 3同上。
另一脚通过1kΩ电阻接GND同上。
同一脚(按钮)5V同上。
按钮3 (播放/暂停)一脚Pin 5同上。
另一脚通过1kΩ电阻接GND同上。
同一脚(按钮)5V同上。
无源蜂鸣器正极(+)Pin 12tone()函数输出引脚。
负极(-)GND
LCD1602VSS (Pin 1)GND电源地。
VDD (Pin 2)5V电源正。
VO (Pin 3)电位器中脚对比度调节,接电位器滑动端。
RS (Pin 4)Pin 8寄存器选择。
RW (Pin 5)GND直接接地,设置为写模式。
E (Pin 6)Pin 9使能信号。
D4 (Pin 11)Pin 44位数据线模式,我们只用高4位。
D5 (Pin 12)Pin 5注意:此Pin 5与按钮3的Pin 5冲突!必须修改其一。
D6 (Pin 13)Pin 6
D7 (Pin 14)Pin 7
A (LED+)通过220Ω电阻接5V背光正极,必须串电阻限流。
K (LED-)GND背光负极。
10kΩ电位器左引脚5V
中引脚LCD VO (Pin 3)输出可调电压。
右引脚GND

实操心得:引脚冲突的经典坑仔细看上面表格,你会发现一个重大冲突:LCD的D5数据线要求接Arduino的Pin 5,但我们的“播放/暂停”按钮也用了Pin 5。一个引脚不能同时作为输入(读按钮)和输出(向LCD写数据)。这是初学者最容易忽略的问题。解决方法很简单:将播放/暂停按钮改接到一个未被使用的数字引脚,例如Pin 11。在后续的代码中,我们也要相应修改。在动手接线前,务必在纸上或思维导图软件里规划好所有引脚用途,避免冲突。

LCD的接线看起来繁琐,但遵循“电源、控制、数据”的顺序就能理清。采用4位数据模式(只接D4-D7)而不是8位模式,可以节省4个I/O口。电位器连接时,如果发现屏幕全黑或全白,只需旋转旋钮即可调整出清晰的对比度。

3. 软件逻辑与核心代码实现

3.1 程序流程图与状态机思想

在写代码之前,理清逻辑至关重要。这个音乐盒的程序核心是一个简单的状态机。它主要有以下几个状态:停止、播放中、暂停。三个按钮作为事件触发器,驱动状态转换。

其工作流程可以概括为:

  1. 初始化:设置引脚模式,初始化LCD,显示欢迎信息或第一首歌名。
  2. 主循环: a. 持续扫描三个按钮的状态。 b. 如果“下一曲”被按下,则当前播放序号加一(循环列表),更新LCD显示歌曲名,如果当前状态是播放,则立即停止当前音调并开始播放新歌曲。 c. 如果“上一曲”被按下,处理逻辑类似,序号减一。 d. 如果“播放/暂停”被按下,这是一个翻转开关:如果当前是停止或暂停状态,则开始播放当前序号对应的歌曲;如果当前是播放状态,则暂停播放(停止发声)。
  3. 播放子程序:根据当前歌曲序号,调用对应的播放函数。该函数内部是一系列tone(pin, frequency)delay(duration)的组合,精确控制音高和节拍。

这种状态机的设计,使得程序逻辑清晰,易于扩展(比如未来增加音量调节、播放模式等)。

3.2 核心代码拆解与tone()函数应用

首先,必须包含LCD库并定义引脚。注意,这里我们已经将播放/暂停按钮改为了Pin 11。

#include <LiquidCrystal.h> // 包含LCD库 // 初始化LCD引脚连接 (RS, E, D4, D5, D6, D7) LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // 定义按钮引脚 const int buttonPrev = 2; const int buttonNext = 3; const int buttonPlayPause = 11; // 已从Pin 5修改 const int buzzerPin = 12; // 定义歌曲数组和状态变量 String songs[] = {"Star Wars Intro", "Imperial March", "Cantina Band"}; int totalSongs = 3; int currentSongIndex = 0; bool isPlaying = false;

setup()函数中,进行初始化和引脚模式设置。

void setup() { pinMode(buttonPrev, INPUT); pinMode(buttonNext, INPUT); pinMode(buttonPlayPause, INPUT); pinMode(buzzerPin, OUTPUT); lcd.begin(16, 2); // 初始化LCD为16列2行 lcd.print("R2-D2 Jukebox"); // 第一行显示标题 lcd.setCursor(0, 1); lcd.print(songs[currentSongIndex]); // 第二行显示当前歌曲名 }

loop()函数是状态机的核心,负责检测按钮并更新状态。

void loop() { // 检测“下一曲”按钮 if (digitalRead(buttonNext) == HIGH) { noTone(buzzerPin); // 立即停止当前发声 currentSongIndex = (currentSongIndex + 1) % totalSongs; // 循环递增 updateDisplay(); if (isPlaying) { playCurrentSong(); // 如果原本在播放,则播放新歌 } delay(300); // 简单防抖 } // 检测“上一曲”按钮 if (digitalRead(buttonPrev) == HIGH) { noTone(buzzerPin); currentSongIndex = (currentSongIndex - 1 + totalSongs) % totalSongs; // 循环递减 updateDisplay(); if (isPlaying) { playCurrentSong(); } delay(300); } // 检测“播放/暂停”按钮 if (digitalRead(buttonPlayPause) == HIGH) { isPlaying = !isPlaying; // 状态翻转 if (isPlaying) { playCurrentSong(); } else { noTone(buzzerPin); // 暂停就是停止发声 lcd.setCursor(0, 1); lcd.print("[Paused] "); // 显示暂停状态 } delay(300); } } // 更新LCD显示 void updateDisplay() { lcd.setCursor(0, 1); lcd.print(" "); // 清空第二行 lcd.setCursor(0, 1); lcd.print(songs[currentSongIndex]); }

3.3 音乐编程:将乐谱转换为代码

这是本项目最有趣也最具挑战的部分。我们需要把《星球大战》主题曲的乐谱,转换成频率和时长的序列。以《帝国进行曲》的开头几个音为例:

首先,要知道每个音符对应的频率。中央C上的G音是392Hz,C音是523Hz,等等。你可以在网上找到完整的音符-频率对照表。

其次,定义节拍。我们可以设定一个基准时长,比如四分音符为300毫秒,八分音符就是150毫秒。

下面是一个极度简化的《帝国进行曲》开头片段示例,演示如何组织音乐数据:

void playImperialMarch() { // 定义音符和时长数组 // 音符部分: G, G, G, C, G, C, G (对应频率) int melody[] = {392, 392, 392, 523, 392, 523, 392}; // 节拍部分: 4分, 4分, 4分, 4分, 4分, 4分, 2分 (2分音符时长是4分的两倍) int noteDurations[] = {4, 4, 4, 4, 4, 4, 2}; int tempo = 300; // 四分音符基准时长300ms for (int i = 0; i < 7; i++) { int noteDuration = tempo / noteDurations[i]; // 计算实际持续时间 tone(buzzerPin, melody[i], noteDuration); // 播放音符 int pauseBetweenNotes = noteDuration * 1.05; // 音符间短暂停顿,使节奏更清晰 delay(pauseBetweenNotes); noTone(buzzerPin); // 停止当前音符 // 这里可以加入按钮状态检查,实现播放中切歌 if (checkButtonInterrupt()) return; } } // 在播放循环中检查按钮的函数 bool checkButtonInterrupt() { if (digitalRead(buttonNext) == HIGH || digitalRead(buttonPrev) == HIGH || digitalRead(buttonPlayPause) == HIGH) { noTone(buzzerPin); return true; // 如果检测到按钮,中断播放 } return false; }

playCurrentSong()函数中,根据currentSongIndex调用不同的歌曲函数即可。

注意事项:音乐编程的细节

  1. tone()函数的限制tone()函数在播放时,会占用一个内部定时器,这可能会干扰某些需要用到同一定时器的库(如Servo库的某些版本)。在本项目中,由于只使用tone()和LCD库,没有冲突。
  2. 阻塞与非阻塞:上面示例使用delay(),是“阻塞式”的,在播放一个音期间程序无法做其他事(比如快速响应按钮)。对于更流畅的体验,可以使用非阻塞的编程方式,用millis()来管理时间,但这会大幅增加代码复杂度。对于初学者,阻塞式代码更直观易懂。
  3. 音色与音量:压电蜂鸣器的音色单薄,音量不大。可以通过外接一个三极管驱动小喇叭来增大音量,但音色改变不大。这是其物理特性决定的。

4. 外壳设计与制作:赋予项目灵魂

电路和代码是项目的“内脏”,而一个精美的外壳则是它的“皮囊”和“灵魂”。我选择制作R2-D2风格的点唱机外壳,这需要一些手工技巧。

4.1 材料选择与结构设计

我主要使用了PVC发泡板白色卡纸。PVC板质地轻盈,易于切割和粘合,强度足够支撑电子元件,是制作模型外壳的理想材料。卡纸则用于制作弧形曲面和装饰贴皮。

结构设计上,我参考了经典点唱机的轮廓:一个长方形的机身,顶部有一个弧形穹顶。同时,融入了R2-D2的标志性元素:机身中下部的“传感器”圆环(我用红色和蓝色卡纸模拟),以及底部的三个“支撑脚”(我用PVC板裁切出梯形块来模拟)。

关键尺寸规划:我的设计尺寸大约是高20cm,宽12cm,深10cm。你需要根据自己实际的面包板、Arduino板和电池尺寸来调整内部空间。务必在切割材料前,用尺子笔在板上画好所有部件的展开图,包括前面板开孔(用于LCD和按钮)、后面板开孔(用于电源线)以及内部支架的位置。

4.2 切割、组装与表面处理

  1. 切割主体:使用美工刀和钢尺,沿着画好的线仔细切割PVC板。对于弧形顶部,可以先切出一个长方形,然后在背面用刀划出密集的、平行的浅痕(不要切断),这样就能轻松地弯折出平滑的���线。这是制作纸模的经典技法。
  2. 开孔:这是精细活。将LCD和按钮模块实际放在面板内侧,用铅笔描出轮廓。开孔时,宁小勿大,可以用小锉刀或砂纸慢慢打磨扩大,直到元件能严丝合缝地卡进去。我的经验是,按钮孔比按钮杆直径大0.5mm左右最合适,既能按压又不会晃动。
  3. 内部支架:我切割了两块小PVC板作为“楼板”,用热熔胶将它们垂直粘在机箱内壁,形成两层结构。下层放置9V电池和变压器,上层放置面包板和Arduino。这样布局清晰,便于维护。
  4. 组装:使用热熔胶枪进行粘合。热熔胶固化快,粘接力强,非常适合这种多材料粘接。按顺序粘合背面、侧面、前面板,最后粘顶部弧面。在内部接缝处可以额外打胶加固。
  5. 上色与装饰:主体使用哑光灰色喷漆,这是R2-D2机身的颜色。喷漆前确保表面清洁无尘,在通风处薄薄地喷多层,每层间隔10分钟,比一次性喷厚效果要好得多。待油漆完全干透后,用红色、蓝色、黑色的卡纸或丙烯颜料,画出R2-D2的细节。我用银色油漆笔勾勒了面板边缘,增加了金属质感。

实操心得:外壳制作的几个坑

  • 热熔胶的温度:粘接PVC板时,胶的温度不宜过高,否则会使薄PVC板轻微变形。可以先在不显眼处测试。
  • 电子元件的可维护性:不要用胶把面包板或Arduino死死粘住。我用的是尼龙扎带将Arduino板固定在支架上,面包板则靠其背面的不干胶粘贴,这样未来升级或维修时可以轻松取下。
  • 散热与通风:虽然本项目功耗极低,但考虑到长期运行,我在外壳背面隐蔽处钻了几个小孔,用于空气流通和走线。
  • 先测试,后封装绝对重要的步骤!在完全封闭外壳之前,必须将整个电路系统通电,测试所有功能:按钮是否灵敏,LCD显示是否正常,歌曲播放是否流畅。确认一切OK后,再最后固定内部线材并合盖。

5. 系统调试、问题排查与优化

即使按照教程一步步做,也难免会遇到问题。下面是我在制作和教学过程中总结的常见问题及解决方法。

5.1 常见问题速查表

现象可能原因排查步骤与解决方案
LCD屏幕无显示1. 电源未接通或接反。
2. 对比度电位器调节不当。
3. 引脚连接错误,特别是E、RS引脚。
4. 代码中LCD初始化引脚定义错误。
1. 用万用表检查LCD的VDD和VSS之间是否有5V电压。
2. 缓慢旋转电位器,观察屏幕是否有变化。
3.逐根检查LCD到Arduino的连线,确保与代码中LiquidCrystal lcd(8,9,4,5,6,7);的顺序一致。
4. 运行一个最简单的LCD显示例程(如“Hello World”)来隔离问题。
按钮按下无反应1. 下拉电阻未接或接错(接成了上拉)。
2. 引脚定义与代码不符。
3. 按钮本身损坏或接触不良。
1. 确认按钮电路是“引脚->按钮->5V”和“引脚->1k电阻->GND”。
2. 检查代码pinMode是否设置为INPUT,以及digitalRead的引脚号是否正确。
3. 用万用表通断档测试按钮按下时是否导通。
蜂鸣器不响或声音小1. 蜂鸣器是有源的,而非无源的。
2. 正负极接反(对无源蜂鸣器影响不大,但最好接对)。
3.tone()函数引脚号错误。
4. 歌曲函数未被调用或频率值全为0。
1.再次确认蜂鸣器类型,这是最常见错误。
2. 交换蜂鸣器两根线试试。
3. 用tone(buzzerPin, 1000, 1000);测试单音是否正常。
4. 在playCurrentSong()函数开始加个Serial.println(“Playing…”);,看是否执行。
播放歌曲时按钮响应迟钝代码中使用delay()进行音符延时,造成程序阻塞。这是预期行为。可采用非阻塞编程(用millis()记录时间)重写播放逻辑,但这属于进阶优化。对于简单项目,可以接受。或者,在playCurrentSong()的每个delay()后插入一个简短的按钮检查(如上面代码示例中的checkButtonInterrupt())。
切歌时声音有爆音或卡顿切歌时,没有先停止当前正在播放的音符。在切换歌曲索引(currentSongIndex)后,立即调用noTone(buzzerPin);,然后再开始播放新歌。我的代码示例中已经体现了这一点。

5.2 进阶优化建议

当基础功能实现后,你可以考虑以下优化,让音乐盒更完美:

  1. 增加音量调节:虽然蜂鸣器本身音量固定,但可以通过在蜂鸣器回路中串联一个电位器来分压,实现简单的音量调节。注意,这可能会影响音质。
  2. 添加LED光效:在机壳内部或R2-D2的“传感器”位置安装RGB LED,编写代码让灯光随着音乐节奏闪烁,效果会非常炫酷。可以使用NeoPixel灯带,用Arduino的另一个引脚控制。
  3. 使用SD卡模块存储更多歌曲:当前音乐代码直接写在程序里,占用大量内存且不易更改。可以加入SD卡模块,将编码好的音符频率和时长存入文本文件,程序从SD卡读取播放,这样就能轻松更换或增加歌曲。
  4. 制作更精致的交互:将机械按钮换成触摸传感器,甚至加入一个旋钮编码器来选歌,会让操作体验更上一层楼。
  5. 电源管理:使用一块大容量的锂电池配合充电模块,让音乐盒彻底摆脱电线束缚。

完成这个项目后,你收获的不仅仅是一个酷炫的星战主题音乐盒,更是一整套从电路设计、嵌入式编程到手工制作的综合技能。最重要的是,你亲手将一个想法变成了现实。当《帝国进行曲》从那小小的蜂鸣器中响起,LCD屏幕亮起歌名,你按下自己制作的按钮进行切歌时,那种满足感是无与伦比的。希望这个详细的教程能帮你少走弯路,享受创造的乐趣。如果遇到任何问题,不妨回头检查一下电路连接和代码逻辑,电子制作的大部分乐趣,其实就藏在解决问题的过程里。

http://www.rkmt.cn/news/1460343.html

相关文章:

  • 基于树莓派与Home Assistant的DIY泳池自动化系统搭建指南
  • 从Chemex到CAT:一个开源IT运维项目的重构实战与选型思考
  • 2026最新诚信优选 茂名全域金银铂金彩金回收实地甄选优质门店TOP6榜单+联系方式汇总推荐 - 余生黄金回收
  • 重庆市格力空调维修师傅电话|各区金牌师傅,靠谱选欧米到家 - 欧米到家
  • 霞浦 3 天 2 晚网约私家团,一站打卡沙滩灯塔与滨海风光 - 奔跑123
  • 2026 年 6 月丹阳市防水维修甄选指南:卫生间免砸砖、屋顶阳台外墙地下室漏水检修避坑全攻略 - 吉修匠
  • .NET Win32设置只读未对齐,导致NTFS文件系统识别异常
  • 杭州市天加中央空调维修师傅电话|各区金牌师傅,靠谱选欧米到家 - 欧米到家
  • 2026年工业防护包装厂家选购指南:航空箱、铝箱、卡扣箱、出口木箱、航空托盘厂家选择指南,产能、工艺、品控三维度客观解析 - 海棠依旧大
  • 从考试失利到实战通关:手把手教你用Python实现遗传算法中的轮盘赌选择
  • 2026 年 6 月如皋市防水维修甄选指南:卫生间免砸砖、屋顶阳台外墙地下室漏水检修避坑全攻略 - 吉修匠
  • 别再死记硬背了!深入理解X-Forwarded-For和Referer:从CTF题到真实网络代理场景
  • 2026最新诚信优选 茂名粤西片区黄金铂金白银彩金回收合规商家TOP6排行榜+联系方式整理推荐 - 余生黄金回收
  • 如何快速解决Dell G15散热问题:开源温度控制中心TCC-G15完全指南
  • 2026 年 6 月东台市防水维修甄选指南:卫生间免砸砖、屋顶阳台外墙地下室漏水检修避坑全攻略 - 吉修匠
  • 《我的世界》红石TNT轰炸机:从原理到实战的工程建造指南
  • 2026最新诚信优选 日照全市黄金回收白银回收铂金回收彩金回收靠谱门店TOP6排行榜+联系方式推荐 - 余生黄金回收
  • 列表list-常用方法
  • 杭州市特灵中央空调维修师傅电话|各区金牌师傅,靠谱选欧米到家 - 欧米到家
  • TMSpeech:3个步骤解决Windows实时语音转文字的所有痛点
  • 2026 年 6 月武夷山市防水维修甄选指南:卫生间免砸砖、屋顶阳台外墙地下室漏水检修避坑全攻略 - 吉修匠
  • 2026年6月天津高端黄金变现指南974元一克的高位窗口期 - 润富黄金回收
  • 鸿蒙 Flutter 项目里的平台能力层应该怎么命名和封装
  • 标题:2026行业实测优选 淄博市黄金白银铂金彩金回收放心门店TOP名录+实体门店地址电话推荐 - 余生黄金回收
  • 2026重庆GEO优化公司TOP5权威推荐:抢占AI搜索时代,这家企业独占全生态 - kio888
  • 2026 驻马店防水修缮|西部丘陵山体裂隙渗水 + 东部黄淮平原汛期地下水抬升返潮 + 宿鸭湖环湖高湿渗漏 + 老城预制板冬夏冻融漏水|天诚修缮全域免费仪器测漏 - 苏易修缮
  • 如何轻松实现Blender与3D打印的无缝对接:3MF插件完整指南
  • 保姆级教程:在Ubuntu 20.04 ROS Noetic下,用MoveIt让ABB YuMi双臂机器人跳个舞(附轨迹拼接代码)
  • Tkinter实现桌面悬浮歌词或弹幕效果:固定位置+局部透明的窗口叠加实战
  • 如何5分钟部署属于自己的免费气象API:Open-Meteo开源天气服务终极指南