Giant Animatronics Lego Minfig 操作游戏
组件和用品
![]() |
| × | 2 | |||
![]() |
| × | 1 | |||
| × | 6 | ||||
![]() |
| × | 2 | |||
![]() |
| × | 12 |
必要的工具和机器
| ||||
|
关于这个项目
该项目分4个阶段完成。我将快速介绍前 3 个阶段(不包含电子设备)并详细说明将 Frank 转换为操作游戏并添加音频和电子动画的第 4 个阶段。
第 1 阶段:建造 Megafigs
我从构建手开始。我认为这将是初始构建中最难的部分,它定义了需要制造的其余部分的比例。手由PVC管和玻璃纤维树脂制成,以填补内外手之间的空隙。

接下来是头部制造。它由PVC管(用于头部主要部分的大型管件)、MDF和树脂制成,以填充顶部小节的空隙。

megafigs 的主体由 MDF 和非常直接的盒子构造制成。附肢与躯干的连接采用PVC管件

腿由 MDF 和 PVC 制成,以定义上腿曲线。

手臂(最终成为最硬的部分)在前臂上用 PVC 管粗加工,上臂用 MDF 粗加工。花卉泡沫被用作空间填充物。 Bondo 被用来创建上臂的形状,大量的打磨和填充使其最终形状。




手臂和手部采用 Smoothcast 300 模制和铸造。

一切都是根据怪物猎人乐高套件绘制的。

第二阶段:头发
这个阶段包括制作科学家的头发。使用带锯将工具泡沫切割成发束的基本形状。发片的各个部分用环氧树脂胶粘在一起。

整个发片都覆盖着 Smoothcast 300,在泡沫上形成一个塑料外壳。然后用砂纸打磨和填充。


使用环氧树脂雕刻填充头发部分之间的所有接缝。


它被打底和涂漆。

阶段 3:弗兰克的床
第三阶段是根据疯狂科学家和他的怪物乐高套件建造弗兰克的床。这是一个简单的盒子,由 MDF 和 PVC 管制成,用于小块。

角落的细节是用 PVC 管夹着一个中密度纤维板制成的。

一切都经过打磨、底漆和油漆。

第 4 阶段:操作游戏和动作
这个项目的最后一部分(迄今为止)是将 Frank 转换成一个操作游戏,并为 Megafigs 添加音频和动作。我将详细说明构建的每个身体部分,而不是按照事情发生的时间顺序(所有事情都在同时进行)。
躯干:
躯干的关节处添加了 3D 打印支架,该支架固定 2 个旱冰轴承。它们充当手臂和头部的支点。

弗兰克的上半身有 2 个 3D 打印的糖果盘,顶部是经过研磨的铝制嘴唇,并覆盖着一个新的躯干板。铝制唇部充当操作游戏的开关。当钳子(已连接到 MP3 屏蔽罩上)接触铝时,它完成电路,激活程序。




头:
两个头部都经过修改以移动和固定扬声器。首先,在颈部添加了一个 3D 打印支架,以固定充当轴的 5/16 螺栓。


穿孔金属被用作绘制扬声器格栅孔的指南。这个过程我最紧张。任何错误都会毁了我脸上的油漆工作。孔被涂成与周围的颜色相匹配。




创建了一个 3D 打印支架,用于将扬声器固定在扬声器格栅后面。


腿:
新腿被 3D 打印成两半以及一个骨头形状的糖果盘。一块铝板像躯干一样被铣削。腿被粘合在一起,打磨,用bondo弄平并涂漆。




武器:
手臂的原始母版经过修改以接受 3D 打印支架,该支架为轴固定 5/16 粗体。然后对它们进行改造、铸造、清理和涂漆。




伺服:
伺服系统使用 3D 打印支架安装,并通过电线和连接 5/16 螺栓的铝制喇叭连接到附件。后来添加了弹簧以协助抬起手臂。



电子产品:
所有电子设备都安装在一块 MDF 上以创建原型测试台。这个设置让我和 Daniel 能够弄清楚编程、tweek 和解决故障。一切正常。
电子设备的工作方式是
1:MP3 屏蔽等待 3 个输入中的 1 个(夹在其中一块铝板上)
2:当铝板被激活时,MP3 Shield播放相应的MP3文件,并向伺服Arduino发送信号。
3:当舵机arduino收到MP3屏蔽的信号时,会运行舵机对应的代码。
两个 arduino 都安装在 Frank 的床底下,所有东西都重新接线。

准备好不给糖就捣蛋:
一切都非常好,并忍受了一整夜的虐待。



有关更详细的构建日志,请访问 ... http://www.therpf.com/showthread.php?t=195101。在那里我详细说明了我制作的每一步。
代码
- 伺服
- 音效
伺服Arduino
此代码加载到控制所有 6 个伺服电机的 Arduino uno 上。基本上它等待从 MP3 屏蔽接收 3 个信号之一。收到信号后,舵机Arduino Uno运行相应的舵机动作。/******************************** Targus -操作-舵机********************************//******注意事项*******// / 数字引脚 0 和 1 通常用于从计算机上传和监控 Arduino 时的串行通信。// 如果 Arduino 未连接到计算机,则数字引脚 0 和 1 可用于伺服。// 如果数字引脚 0和 1 用于伺服系统,注释掉所有以“Serial”开头的行。在这个文件中。// 确保这个 Arduino 在另一个 Arduino 之前通电,因为这个 Arduino 将接收 5V 信号。// 确保这个 Arduino 上的 GND 线连接到另一个 Arduino 上的 GND。/**** ***** 包含**********/#include/********** 变量************/Servoservo5;伺服伺服6;伺服伺服7;伺服伺服8;伺服伺服9;伺服伺服10;伺服伺服11;int pin2 =2;int pin3 =3;int pin4 =4;/**************** Arduino设置***************/void setup() { Serial.begin(9600); // 为开发和故障排除启用串行通信 Serial.println("Targus - Operation - Servos\n"); /***************************************** 连接舵机并设置初始位置** ********************************************/servo5.attach(5); // 数字引脚 5 伺服5.write(90); //移动到90度servo6.attach(6); // 数字引脚 6 伺服6.write(90);伺服7.附加(7); // 数字引脚 7 伺服7.write(90);伺服8.附加(8); // 数字引脚 8 伺服8.write(90);伺服9.附加(9); // 数字引脚 9 伺服9.write(80);伺服10.附加(10); // 数字引脚 10 伺服10.write(90);伺服11.附加(11); // 数字引脚 11 伺服11.write(80); /************************* 设置数字输入引脚 ******************** ******/ // 设置输入引脚,以便带有音效的 Arduino 可以告诉我们何时激活伺服系统。 pinMode(pin2, INPUT_PULLUP); pinMode(pin3, INPUT_PULLUP); pinMode(pin4, INPUT_PULLUP);}/************* Arduino Loop**************/void loop() { if (digitalRead(pin2) ==高) { zap2(); } else if (digitalRead(pin3) ==HIGH) { zap3(); } else if (digitalRead(pin4) ==HIGH) { zap4(); } delay(300);}/********** 函数***********/int moveServo(Servo &servo, int degreeStart, int degreeEnd, unsigned long timeEnd, unsigned long timeStart , float (*easing)(float), unsigned long timeNow) { // 如果还有工作要做,这个函数将返回一个数字 1 timeEnd +=timeStart; // 添加任何延迟到结束时间 if (timeNow timeEnd) { // 舵机运动阶段完成,无事可做 return 0; } // 如果我们走到这一步,准备移动一个舵机 float percentToMove =float(timeNow - timeStart) / float(timeEnd - timeStart); percentToMove =缓动(percentToMove); // 将 SG-92R 的度数范围从 0-180 映射到微秒范围 500-2400 http://www.servodatabase.com/servo/towerpro/sg92r degreeStart =map(degreeStart, 0, 180, 500, 2400); degreeEnd =map(degreeEnd, 0, 180, 500, 2400);浮动伺服=0; if (degreeEnd> degreeStart) { // 逆时针旋转servoTo =((degreeEnd - degreeStart) * percentToMove) + degreeStart; } else { // 顺时针旋转 percentToMove =1 - percentToMove; // 倒数百分比,所以像 0.8 这样的值变成了 0.2servoTo =((degreeStart - degreeEnd) * percentToMove) + degreeEnd; } 伺服.writeMicroseconds(servoTo); // Serial.print("将映射到:"); Serial.println(servoTo); // Serial.print("degreeStart:"); Serial.println(degreeStart); // Serial.print("degreeEnd:"); Serial.println(degreeEnd); // Serial.print("timeEnd:"); Serial.println(timeEnd); // Serial.print("timeStart:"); Serial.println(timeStart); // Serial.print("timeNow:"); Serial.println(timeNow); // Serial.print("percentToMove:"); Serial.println(percentToMove); // Serial.print("servoTo:"); Serial.println(servoTo); // Serial.print("\n"); return 1;}/****************** 函数:缓动*******************////缓动函数来自 https://github.com/warrenm/AHEasing/blob/master/AHEasing/easing.c 重命名以匹配 http://easings.net/ 以便于预览。float easeInBack(float pos) { // 在过冲之后建模立方 y =x^3-x*sin(x*pi) return pos * pos * pos - pos * sin(pos * M_PI);}float easeOutBack(float pos) { // 超调后建模立方 y =1-( (1-x)^3-(1-x)*sin((1-x)*pi)) 浮点 f =(1 - pos); return 1 - (f * f * f - f * sin(f * M_PI));}float easeInOutBack(float pos) { // 在分段超调三次函数之后建模: // y =(1/2)*(( 2x)^3-(2x)*sin(2*x*pi)); [0, 0.5) // y =(1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1); [0.5, 1] if (pos <0.5) { float f =2 * pos;返回 0.5 * (f * f * f - f * sin(f * M_PI)); } else { float f =(1 - (2 * pos - 1));返回 0.5 * (1 - (f * f * f - f * sin(f * M_PI))) + 0.5; }}浮动easeInBounce(浮动位置){返回1-easeOutBounce(1-位置);}浮动easeOutBounce(浮动位置){如果(位置<4/11.0){返回(121*位置*位置)/16.0; } else if (pos <8 / 11.0) { return (363 / 40.0 * pos * pos) - (99 / 10.0 * pos) + 17 / 5.0; } else if (pos <9 / 10.0) { return (4356 / 361.0 * pos * pos) - (35442 / 1805.0 * pos) + 16061 / 1805.0; } else { return (54 / 5.0 * pos * pos) - (513 / 25.0 * pos) + 268 / 25.0; }}浮动easeInOutBounce(浮动pos){如果(pos<0.5){返回0.5*easeInBounce(pos*2); } else { 返回 0.5 * easeOutBounce(pos * 2 - 1) + 0.5; }}float easyInCirc(float pos) { // 在单位圆的移动象限 IV 之后建模 return 1 - sqrt(1 - (pos * pos));}float easeOutCirc(float pos) { // 在单位圆的移动象限 II 之后建模circle return sqrt((2 - pos) * pos);}float easeInOutCirc(float pos) { // 以分段循环函数为模型 // y =(1/2)(1 - sqrt(1 - 4x^2)); [0, 0.5) // y =(1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1); [0.5, 1] if (pos <0.5) { return 0.5 * (1 - sqrt(1 - 4 * (pos * pos))); } else { return 0.5 * (sqrt(-((2 * pos) - 3) * ((2 * pos) - 1)) + 1); }}float easeInCubic(float pos) { // 仿照三次 y =x^3 return pos * pos * pos;}float easeOutCubic(float pos) { // 仿照三次 y =(x - 1)^3 + 1 浮点 f =(pos - 1); return f * f * f + 1;}float easeInOutCubic(float pos) { // 以分段三次为模型 // y =(1/2)((2x)^3); [0, 0.5) // y =(1/2)((2x-2)^3 + 2); [0.5, 1] if (pos <0.5) { return 4 * pos * pos * pos; } else { float f =((2 * pos) - 2);返回 0.5 * f * f * f + 1; }}float easyInElastic(float pos) { // 以阻尼正弦波为模型 y =sin(13pi/2*x)*pow(2, 10 * (x - 1)) return sin(13 * M_PI_2 * pos) * pow(2, 10 * (pos - 1));}float easeOutElastic(float pos) { // 在阻尼正弦波之后建模 y =sin(-13pi/2*(x + 1))*pow(2, - 10x) + 1 return sin(-13 * M_PI_2 * (pos + 1)) * pow(2, -10 * pos) + 1;}float easyInOutElastic(float pos) { // 以分段指数阻尼正弦波为模型:// y =(1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)); [0,0.5) // y =(1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2 ); [0.5, 1] if (pos <0.5) { return 0.5 * sin(13 * M_PI_2 * (2 * pos)) * pow(2, 10 * ((2 * pos) - 1)); } else { return 0.5 * (sin(-13 * M_PI_2 * ((2 * pos - 1) + 1)) * pow(2, -10 * (2 * pos - 1)) + 2); }}float easeInExpo(float pos) { // 模仿指数函数 y =2^(10(x - 1)) return (pos ==0.0) ? pos :pow(2, 10 * (pos - 1));}float easeOutExpo(float pos) { // 模仿指数函数 y =-2^(-10x) + 1 return (pos ==1.0) ? pos :1 - pow(2, -10 * pos);}float easeInOutExpo(float pos) { // 以分段指数为模型 // y =(1/2)2^(10(2x - 1)); [0,0.5) // y =-(1/2)*2^(-10(2x - 1))) + 1; [0.5,1] if (pos ==0.0 || pos ==1.0) return pos; if (pos <0.5) { return 0.5 * pow(2, (20 * pos) - 10); } else { return -0.5 * pow(2, (-20 * pos) + 10) + 1; }}float linear(float pos) { return pos;}float easyInQuad(float pos) { // 以抛物线为模型 y =x^2 return pos * pos;}float easeOutQuad(float pos) { // 以抛物线为模型y =-x^2 + 2x return -(pos * (pos - 2));}float easeInOutQuad(float pos) { // 在分段二次之后建模 // y =(1/2)((2x)^2 ); [0, 0.5) // y =-(1/2)((2x-1)*(2x-3) - 1); [0.5, 1] if (pos <0.5) { return 2 * pos * pos; } else { return (-2 * pos * pos) + (4 * pos) - 1; }}float easyInQuart(float pos) { // 在四次 x^4 之后建模 return pos * pos * pos * pos;}float easeOutQuart(float pos) { // 在四次之后建模 y =1 - (x - 1) ^4 浮点 f =(pos - 1); return f * f * f * (1 - pos) + 1;}float easeInOutQuart(float pos) { // 在分段四次之后建模 // y =(1/2)((2x)^4); [0, 0.5) // y =-(1/2)((2x-2)^4 - 2); [0.5, 1] if (pos <0.5) { return 8 * pos * pos * pos * pos; } else { float f =(pos - 1);返回-8 * f * f * f * f + 1; }}float easeInQuint(float pos) { // 在五次之后建模 y =x^5 return pos * pos * pos * pos * pos;}float easyOutQuint(float pos) { // 在五次之后建模 y =(x - 1)^5 + 1 浮点数 f =(pos - 1); return f * f * f * f * f + 1;}float easeInOutQuint(float pos) { // 在分段五次之后建模 // y =(1/2)((2x)^5); [0, 0.5) // y =(1/2)((2x-2)^5 + 2); [0.5, 1] if (pos <0.5) { return 16 * pos * pos * pos * pos * pos; } else { float f =((2 * pos) - 2);返回 0.5 * f * f * f * f * f + 1; }}floateaseInSine(float pos) { // 以正弦波的四分之一周期为模型 return sin((pos - 1) * M_PI_2) + 1;}float easeOutSine(float pos) { // 以正弦波的四分之一周期为模型波(不同相位) return sin(pos * M_PI_2);}float easeInOutSine(float pos) { // 仿照半正弦波返回 0.5 * (1 - cos(pos * M_PI));}/****** ********* 函数: Zap****************//****** Zap 2*******/void zap2() { Serial.println("ZAP 2 被调用!"); //骨骼无符号long timeStart =millis(); int todo; do { unsigned long timeNow =millis() - timeStart;待办事项 =0; // M 腿踢 //todo +=moveServo(servo5, 90, 50, 100, 0, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 5 从 90 度移动到 180 度 1 秒 // todo +=moveServo(servo5, 50, 90, 500, 500, easeOutBounce, timeNow); // 延迟 1 秒后将伺服 5 从 180 度移动到 90 度 1 秒 // M 头侧到侧 todo +=moveServo(servo7, 90, 110, 500,0, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 7 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo7, 110, 70, 500, 500, easeInOutCubic, timeNow); // 延迟 1 秒后将伺服 7 从 180 度移动到 90 度 1 秒 todo +=moveServo(servo7, 70, 110, 500, 1000, easeInOutCubic, timeNow); todo +=moveServo(servo7, 110, 70, 500, 1500, easeInOutCubic, timeNow); todo +=moveServo(servo7, 70, 110, 500, 2000, easeInOutCubic, timeNow); todo +=moveServo(servo7, 110, 70, 500, 2500, easeInOutCubic, timeNow); todo +=moveServo(servo7, 70, 90, 500, 3000, easeInOutCubic, timeNow); // M 左臂上下 todo +=moveServo(servo8, 90, 170, 1000, 0, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 8 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo8, 170, 90, 1000, 4000, easeOutBounce, timeNow); // 延迟 1 秒后将伺服 8 从 180 度移动到 90 度 1 秒 // M 右臂上下 todo +=moveServo(servo6, 90, 130, 1000, 1500, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 8 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo6, 130, 90, 1000, 5000, easeOutBounce, timeNow); // 延迟 1 秒后,将伺服 8 从 180 度移动到 90 度 1 秒 // S Head side to side todo +=moveServo(servo10, 90, 40, 1000, 500, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 7 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo10, 40, 105, 1000, 2000, easeInOutCubic, timeNow); // 延迟 1 秒后将伺服 7 从 180 度移动到 90 度 1 秒 todo +=moveServo(servo10, 105, 90, 1000, 6000, easeInOutCubic, timeNow); // S 左臂上下 todo +=moveServo(servo11, 80, 160, 1000, 2000, easeInOutCubic, timeNow); // 在 0 秒延迟后将servo8 从90 度移动到180 度1 秒 todo +=moveServo(servo11, 160, 80, 1000, 5000, easeInOutCubic, timeNow); // 延迟 1 秒后将伺服 8 从 180 度移动到 90 度 1 秒 // S 右臂上下 todo +=moveServo(servo9, 80, 20, 1000, 1000, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 8 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo9, 20, 80, 1000, 2000, easeInOutCubic, timeNow); // 在 1 秒延迟延迟 (20) 后,将伺服 8 从 180 度移动到 90 度 1 秒; } while (todo> 0);}/****** Zap 3*******/void zap3() { Serial.println("ZAP 3 调用!"); unsigned long timeStart =millis(); int todo; do { unsigned long timeNow =millis() - timeStart;待办事项 =0; // M 并排 todo +=moveServo(servo7, 90, 130, 1000, 0, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 7 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo7, 130, 90, 1000, 5000, easeInOutCubic, timeNow); // 延迟 1 秒后将伺服 7 从 180 度移动到 90 度 1 秒 // M 左臂上下 todo +=moveServo(servo8, 90, 170, 1000, 0, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 8 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo8, 170, 90, 1000, 4000, easeOutBounce, timeNow); // 延迟 1 秒后将伺服 8 从 180 度移动到 90 度 1 秒 // M 右臂上下 todo +=moveServo(servo6, 90, 130, 1000, 1500, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 8 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo6, 130, 90, 1000, 5000, easeOutBounce, timeNow); // 延迟 1 秒后,将伺服 8 从 180 度移动到 90 度 1 秒 // S Head side to side todo +=moveServo(servo10, 90, 40, 1000, 500, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 7 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo10, 40, 105, 1000, 2000, easeInOutCubic, timeNow); // 延迟 1 秒后将伺服 7 从 180 度移动到 90 度 1 秒 todo +=moveServo(servo10, 105, 90, 1000, 6000, easeInOutCubic, timeNow); // S 左臂上下 todo +=moveServo(servo11, 80, 160, 1000, 0, easeInOutCubic, timeNow); // 在 0 秒延迟后将servo8 从90 度移动到180 度1 秒 todo +=moveServo(servo11, 160, 80, 1000, 5000, easeInOutCubic, timeNow); // 延迟 1 秒后将伺服 8 从 180 度移动到 90 度 1 秒 // S 右臂上下 todo +=moveServo(servo9, 80, 20, 1000, 1000, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 8 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo9, 20, 80, 1000, 6000, easeInOutCubic, timeNow); // 在 1 秒延迟延迟 (10) 后,将伺服 8 从 180 度移动到 90 度 1 秒; } while (todo> 0);}/****** Zap 4*******/void zap4() { Serial.println("ZAP 4 调用!"); unsigned long timeStart =millis(); int todo; do { unsigned long timeNow =millis() - timeStart;待办事项 =0; // M 并排 todo +=moveServo(servo7, 90, 130, 1000, 0, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 7 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo7, 130, 90, 1000, 5000, easeInOutCubic, timeNow); // 延迟 1 秒后将伺服 7 从 180 度移动到 90 度 1 秒 // M 左臂上下 todo +=moveServo(servo8, 90, 170, 1000, 0, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 8 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo8, 170, 90, 1000, 4000, easeOutBounce, timeNow); // 延迟 1 秒后将伺服 8 从 180 度移动到 90 度 1 秒 // M 右臂上下 todo +=moveServo(servo6, 90, 130, 1000, 1500, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 8 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo6, 130, 90, 1000, 5000, easeOutBounce, timeNow); // 延迟 1 秒后,将伺服 8 从 180 度移动到 90 度 1 秒 // S Head side to side todo +=moveServo(servo10, 90, 40, 1000, 500, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 7 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo10, 40, 105, 1000, 2000, easeInOutCubic, timeNow); // 延迟 1 秒后将伺服 7 从 180 度移动到 90 度 1 秒 todo +=moveServo(servo10, 105, 90, 1000, 6000, easeInOutCubic, timeNow); // S 左臂上下 todo +=moveServo(servo11, 80, 160, 1000, 2000, easeInOutCubic, timeNow); // 在 0 秒延迟后将servo8 从90 度移动到180 度1 秒 todo +=moveServo(servo11, 160, 80, 1000, 5000, easeInOutCubic, timeNow); // 延迟 1 秒后将伺服 8 从 180 度移动到 90 度 1 秒 // S 右臂上下 todo +=moveServo(servo9, 80, 20, 1000, 1000, easeInOutCubic, timeNow); // 在 0 秒延迟后将伺服 8 从 90 度移动到 180 度 1 秒 todo +=moveServo(servo9, 20, 80, 1000, 2000, easeInOutCubic, timeNow); // 在 1 秒延迟延迟 (10) 后,将伺服 8 从 180 度移动到 90 度 1 秒; } while (todo> 0);}
音效Arduino
此代码加载到 Arduino Uno 上,并安装了 MP3 扩展板。 Basically it receives a signal from one of three switches, plays the corresponding audio file and send a signal the Arduino Uno controlling the servos. Two buttons can also be mounted to it to control volume./*********************************** Targus - Operation - Sound Effects************************************//****** Notes*******/// Digital Pins 0 and 1 are normally used for serial commucation when uploading and monitoring an Arduino from a computer.// Digital Pins 3, 4, 6, 7, 11, 12, and 13 are used by the Adafruit Music Maker Shield.// This Arduino should be powered on after the servos Arduino since this Arduino will be sending 5V signals.// Make sure a GND wire on this Arduino is connected to GND on the other Arduino./********* Includes**********/#include#include #include /********** Variables***********/int relayPin5 =5;int relayPin8 =8;int relayPin9 =9;int pinVolDown =14; // aka Analog In 0int pinVolUp =15; // aka Analog In 1int volume =50; // this is the default volume which can be changed later by the volDown() and volUp() functions/******************************************************************** Adafruit Music Maker Shield - https://www.adafruit.com/product/1788*********************************************************************/// Adafruit Music Maker Shield Pins#define SHIELD_RESET -1 // VS1053 reset pin (unused!)#define DREQ 3 // VS1053 Data request, ideally an Interrupt pin. See http://arduino.cc/en/Reference/attachInterrupt for more info.#define CARDCS 4 // Card chip select pin#define SHIELD_DCS 6 // VS1053 Data/command select pin (output)#define SHIELD_CS 7 // VS1053 chip select pin (output)// the most important thing on the line below is the variable 'musicPlayer' which we will use to play music laterAdafruit_VS1053_FilePlayer musicPlayer =Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);/************** Arduino Setup***************/void setup() { Serial.begin(9600); // enable serial communication for development and troubleshooting Serial.println("Targus - Operation - Sound Effects\n"); if (! musicPlayer.begin()) { // initialise the music player Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));而 (1); // loop forever since we could not connect to the Adafruit Music Maker Shield } SD.begin(CARDCS); // initialise the SD card // Set volumes for the left and right channels. musicPlayer.setVolume(volume,volume); // 0-255 with 0 being crazy loud // If DREQ is on an interrupt pin (on uno, #2 or #3) we can do background audio playing musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT); // DREQ int // Specify which GPIO pins to use for input. musicPlayer.GPIO_pinMode(2, OUTPUT); // switch for ... musicPlayer.GPIO_pinMode(3, OUTPUT); // switch for ... musicPlayer.GPIO_pinMode(4, OUTPUT); // switch for ... // Specify which digital pins we will use for volume control pinMode(pinVolDown, INPUT_PULLUP); pinMode(pinVolUp, INPUT_PULLUP); // Specify which digital pins we will use to communicate with the other Arduino (aka the Arduino with all the servos). pinMode(relayPin5, OUTPUT); pinMode(relayPin8, OUTPUT); pinMode(relayPin9, OUTPUT);}/************* Arduino Loop**************/void loop() { int gpio2 =musicPlayer.GPIO_digitalRead(2); int gpio3 =musicPlayer.GPIO_digitalRead(3); int gpio4 =musicPlayer.GPIO_digitalRead(4); int ioDown =digitalRead(pinVolDown); // volume down int ioUp =digitalRead(pinVolUp); // volume up// Serial.println(ioDown);// Serial.println(ioUp);// Serial.println(gpio2); if (gpio2 ==1) { Serial.println("GPIO 2 triggered.\n"); zap2(); } else if (gpio3 ==1) { Serial.println("GPIO 3 triggered.\n"); zap3(); } else if (gpio4 ==1) { Serial.println("GPIO 4 triggered.\n"); zap4(); } else if (ioDown ==LOW) { Serial.println("Analog 0 triggered.\n"); volDown(); } else if (ioUp ==LOW) { Serial.println("Analog 1 triggered.\n"); volUp(); } delay(2); // this delay may need to be reduced or removed depending on how responsive hitting the tongs to the side of a container feels}/********** Functions***********/void audioPlay(String file) { Serial.println("Playing " + file); musicPlayer.startPlayingFile(file.c_str());延迟(500); // wait half a second before returning so the audio can get going}void audioStop(String file) { musicPlayer.stopPlaying(); Serial.println("Done playing " + file);}void activate(int pin) { digitalWrite(pin, HIGH); delay(300); // delay as long as needed for the other Arduino to notice an event digitalWrite(pin, LOW);}void volDown() { volume =volume + 1; if (volume> 255) { volume =255; } // Set volumes for the left and right channels. musicPlayer.setVolume(volume,volume); // 0-255 with 0 being crazy loud Serial.print("Volume set to "); Serial.println(volume);}void volUp() { volume =volume - 1; if (volume <0) { volume =0; } // Set volumes for the left and right channels. musicPlayer.setVolume(volume,volume); // 0-255 with 0 being crazy loud Serial.print("Volume set to "); Serial.println(volume);}/*************** Functions:Zap****************/ /****** Zap 2 *******/ void zap2() { // Audio and Servo(s) triggered by GPIO 2 String file ="02.mp3"; // this file should exist on the SD card /*********** Play Audio ************/ audioPlay(file); /************************************* Tell other Arduino to Animate Servos **************************************/ activate(relayPin5); delay(6000); // Customize delay to match end of servo movements, go by feel vs. accurate math since this Arduino's clock may not sync with the other Arduino. /*********** Stop Audio ************/ audioStop(file); } /****** Zap 3 *******/ void zap3() { // Audio and Servo(s) triggered by GPIO 3 String file ="03.mp3"; // this file should exist on the SD card /*********** Play Audio ************/ audioPlay(file); /************************************* Tell other Arduino to Animate Servos **************************************/ activate(relayPin8); delay(6000); // Customize delay to match end of servo movements, go by feel vs. accurate math since this Arduino's clock may not sync with the other Arduino. /*********** Stop Audio ************/ audioStop(file); } /****** Zap 4 *******/ void zap4() { // Audio and Servo(s) triggered by GPIO 4 String file ="04.mp3"; // this file should exist on the SD card /*********** Play Audio ************/ audioPlay(file); /************************************* Tell other Arduino to Animate Servos **************************************/ activate(relayPin9); delay(6000); // Customize delay to match end of servo movements, go by feel vs. accurate math since this Arduino's clock may not sync with the other Arduino. /*********** Stop Audio ************/ audioStop(file); }
定制零件和外壳
3D grown Parts
CAD file on thingiverse.com示意图
Connect GPIO 2, 3, 4 of the MP3 shield to the aluminum Plates.Connect 3v of the MP3 shield to the tongs.
Connect pins 5, 8, 9 of the MP3 shiled to pins 2, 3, 4 of the servo Arduino.
Connect pins 6, 7, 8, 9, 10, 11 of the servo Arduino to the servos.
Wire the positive and negative of the servos to a 5v plug.
Wire the graounds of both the servo Arduino and the MP3 shield to the 5v plug.
Wire up both speaker inputs.

制造工艺