让大嘴鲈鱼玩具随音频起舞:分步制作指南
组件与物料
| 组件 | 说明 | 数量 |
|---|---|---|
| Arduino UNO | 主控板 | 1 |
| Adafruit 电机/步进/舵机扩展板 v2.3 | 电机驱动扩展板 | 1 |
| Amazon Alexa Echo Dot | 语音助手设备(任何音频源均可) | 1 |
项目简介

大约一个月前,艺术家 Brian Kane 发布了一段病毒视频,展示了一条大嘴鲈鱼玩具仿佛由 Amazon Alexa 语音驱动。视频在网络上引发热议,我也很好奇其实现原理,决定自制一个。
最初看到许多基于树莓派的 Alexa 项目,我以为 Brian 使用了树莓派驱动现有硬件。但在深思后,我认为最简单的方案是利用 49 美元 Echo Dot 的音频输出,通过 Arduino 驱动现有电机。
手头已有 Arduino 和电机扩展板(首次使用)。在 Amazon 订购了约 15 美元的二手鲈鱼玩具和新 Echo Dot。参考了两个教程:2012 年 sfool 的《Arduino 声控舵机》和 2013 年 Dotten 的《大嘴鲈鱼机械结构解析》。
了解到鲈鱼玩具(类似 Furby)由两个廉价 5V 直流玩具电机驱动,核心问题转化为:如何让电机随声音抽动。经过反复调试,找到了可行方案。代码尚不完美,还有许多功能待完善,但希望尽早分享供大家改进。
所需材料
- 大嘴鲈鱼唱歌玩具 (1)
- Arduino Uno (1)
- Arduino Uno 电源 (1)
- Adafruit 电机扩展板 v2 (1)
- 面板安装迷你插孔 (1)
- 多色绞线 (若干)
- Amazon Echo Dot(或任意音频源) (1)
- 小型充电音箱 (1)
- 3.5mm 音频线 (1)
- 3.5mm 分线器 (1)
所需工具
- 小螺丝刀
- 烙铁和焊锡
- 剥线钳
- 剪线钳
- 电钻和钻头
步骤 1:准备鱼体








购买的二手玩具到货即损坏,拆解毫无心理负担。拧开背部螺丝,轻压拔出线束,完全移除背板。为腾出空间,拧下并取出原电路板和压电蜂鸣器。
剩余一个 4 线线束:两根控制嘴部(延伸进鱼体内),两根控制头部或尾部(取决于电机转向)。剪四等长不同颜色导线,剥锡后插入线束四个插孔,稍后连接电机扩展板。
步骤 2:准备电机扩展板






仅需 4 处连接,其中 2 处需焊接。额外可接 2 根线实验头/尾电机。
先焊接音频输入:取两根等长不同色导线,一根焊接地线,一根焊接模拟引脚 0 (A0)。修剪多余导线。连接面板安装迷你插孔:模拟 0 连接插孔尖端触点,地线连接底座触点,形成单声道输入。
连接鱼体电机:嘴部电机线(黑、橙)接电机 1 端子块;可选将头/尾电机线(白、红)接电机 2 端子块(代码暂未使用)。我的线色对应:黑/橙(黄)为 M1 嘴部,白/红为 M2 头尾。
检查 VIN 跳线帽是否插好(我曾漏装导致供电失败)。将扩展板叠装在 Uno 上,上电应看到扩展板电源指示灯亮起。
步骤 3:烧录代码



代码整合了电机扩展板演示代码和 Cenk Özdemir (2012) 的《声音控制舵机》教程。当前版本暂未驱动头/尾电机,曾有版本实现但牺牲了嘴部响应速度。希望嘴部保持灵敏的同时头尾缓慢循环,但受限于编程能力,暂时搁置。欢迎大神改进。
步骤 4:组装调试





烧录代码并连接音频线后,用手机播放播客测试,鱼嘴应随声张合。正常则在鱼牌空处钻孔固定插孔。
实现 Alexa 通过鱼“说话”:音频线自由端接分线器,充电音箱接分线器另一端,分线器公头插入 Echo Dot 音频输出。确保音箱开启、Alexa 音量调大。唤醒 Alexa 提问(天气、笑话、新闻),音箱播放语音的同时鱼嘴同步张合。音箱越靠近鱼头效果越逼真。
最后需将音箱和 Arduino 装入鱼体内封装,这部分仍在摸索中。
步骤 5:后续改进方向


欢迎各位建议,计划近期发布 2.0 版本:
- 实现头尾动画:接线已就绪且能工作,但会降低嘴部响应速度(核心体验)
- 音箱由 Arduino 供电充电:原理简单但未实现
- 利用鲈鱼红按钮切换“语音模式”(侧重嘴部张合)和“音乐模式”(侧重身体随乐摆动)
- 代码重构清理:现有代码混合了多个示例,冗余较多
- 采用更小主控:Uno + 扩展板过剩,考虑 Adafruit Feather 及其双电机扩展板,甚至双 Feather 分别驱动嘴部和头尾
代码
SoundToDC (Arduino)
/* 随声音动作的直流电机控制 - 公共领域代码
Donald Bell, Maker Project Lab (2016) 创建
基于 Cenk Özdemir (2012) 的声音控制舵机
和 Adafruit 的 DCMotorTest 示例 */
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
// 创建默认 I2C 地址的电机扩展板对象
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
// 或指定不同地址(用于叠装)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61);
// 选择端口 M1-M4,本例 M1 控制嘴部,M2 控制头尾
Adafruit_DCMotor *myMotor = AFMS.getMotor(1);
Adafruit_DCMotor *myOtherMotor = AFMS.getMotor(2);
// 变量定义
int SoundInPin = A0;
int LedPin = 12; // 可选:嘴部动作时点亮 LED
void setup() {
Serial.begin(9600);
AFMS.begin(); // 默认频率 1.6KHz
// AFMS.begin(1000); // 可选 1KHz
myMotor->setSpeed(0);
myMotor->run(FORWARD);
myMotor->run(RELEASE);
pinMode(SoundInPin, INPUT);
pinMode(LedPin, OUTPUT);
myOtherMotor->setSpeed(0);
myOtherMotor->run(FORWARD);
myOtherMotor->run(RELEASE);
pinMode(SoundInPin, INPUT);
}
void loop() {
uint8_t i;
int sensorValue = analogRead(SoundInPin);
// 映射 LED 亮度 0-255
int LEDValue = map(sensorValue, 0, 512, 0, 255);
// 映射电机运动范围 0-180
sensorValue = map(sensorValue, 0, 512, 0, 180);
// 正常模拟读取上限 1023,此处改为 512 获取更好读数
int MoveDelayValue = map(sensorValue, 0, 255, 0, sensorValue);
if (sensorValue > 10) { // 过滤静态噪声
delay(1); // 平滑延时
myMotor->run(FORWARD);
for (i = 140; i < 255; i++) {
myMotor->setSpeed(i);
}
// 可选减速逻辑(注释掉)
// for (i = 200; i != 0; i--) {
// myMotor->setSpeed(i);
// delay(10);
// }
analogWrite(LedPin, sensorValue);
myMotor->run(RELEASE);
myOtherMotor->run(RELEASE);
delay(1);
}
analogWrite(LedPin, 0); // 关闭 LED
}
制造工艺
- K30 CO₂ 传感器:室内空气质量实时监测
- 基于 1Sheeld 与 Arduino 的盲聋人士沟通辅助系统
- 智能存钱罐:Arduino Nano 控制硬币识别器实现余额显示
- 改造大嘴鲈鱼玩具:Arduino + L293D + LM386 打造 Alexa 互动智能鱼
- Arduino 音频频率检测:基于 FFT 测量最响亮声音峰值
- Arduino + HC-05 蓝牙控制 LED:MIT App Inventor 手机 App 开发全攻略
- DFRobot 电容指纹传感器 (ID809) 接入 Arduino/ESP8266 完整教程
- 基于 Arduino Mega 与 Nextion 显示屏的交互式气象站
- Arduino UNO 与 DFPlayer Mini 播放音频完整指南
- Arduino Mega 驱动 Wii Nunchuk 控制 6 自由度机械臂
- Arduino UNO + 以太网盾板实现低成本太阳辐射测量仪(热电堆原理)
- 紧凑型Arduino雷达系统:HC-SR04超声波传感器配1.8英寸显示屏