基于伺服电机与3D打印的万向节时钟:机电一体化与视觉错觉的实践

发布时间:2026/5/30 1:58:04

基于伺服电机与3D打印的万向节时钟:机电一体化与视觉错觉的实践 1. 项目概述一个会“变脸”的时钟如果你对传统的LED点阵时钟或者数码管时钟已经审美疲劳想在家里或者工作台上放一个既酷炫又能体现技术含量的时间显示装置那么这个基于伺服电机和3D打印的万向节时钟绝对值得你花时间研究一下。我叫它“变脸时钟”因为它本质上是一个利用视觉错觉来显示时间的机械装置。几个看似普通的方块通过内部伺服电机的驱动在不同的角度下会呈现出不同的数字组合起来就能告诉你现在是几点几分。这个项目的核心价值远不止是“看时间”那么简单。它是一次非常典型的“机电一体化”微型实践完美融合了机械结构设计万向节、嵌入式系统开发Arduino/PWM控制、3D打印快速原型以及一点点艺术创意。你不仅能学到如何用代码精确控制多个伺服电机协同工作更能深入理解如何将抽象的电子信号转化为直观、有趣的物理运动。对于嵌入式爱好者、创客或者任何想动手做个“镇桌之宝”的朋友来说这是一个从想法到实物的绝佳练手项目。2. 核心设计思路与机械原理拆解2.1 视觉错觉的数学与几何基础这个时钟最吸引人的地方无疑是它的显示原理。它并非像屏幕一样发光而是利用了“立体数字的投影错觉”。简单来说就是在一个立方体或长方体的多个面上雕刻出不同数字的立体凸起。当你从特定角度比如正面观察时由于透视和光影只有某个数字的轮廓是清晰可见的其他角度的凸起则融合在背景中或形成干扰图案。原作者提到的“dual letter illusion”双字母错觉是这一原理的经典应用。想象一个方柱从正面看它的横截面是一个正方形。如果你在这个方柱的正面雕刻或拉伸凸出一个数字“1”然后把这个方柱旋转90度在它的新“正面”再雕刻一个数字“2”。那么当你从0度方向看你看到的是“1”从90度方向看你看到的是“2”。关键在于这两个数字的凸起部分在三维空间中是交错、共存的。将这个原理扩展到时钟我们需要显示0-9这十个数字以及可能的“”分隔符。如果为每一位数字例如分钟的个位都单独分配一个方块并通过旋转让它只显示当前需要的数字那么我们就需要设计一种机构能让这个方块至少旋转到10个不同的、可清晰识别数字的位置。这显然对机械结构和控制提出了极高要求。2.2 万向节机构的简化与取舍原作者的聪明之处在于做了关键的简化。他并没有追求一个方块显示所有数字而是采用了“组合分配”和“冗余隐藏”的策略。时间数字分配他将时间拆解为“十位小时”、“个位小时”、“十位分钟”、“个位分钟”四部分。但通过分析发现“十位小时”只能是0, 1, 224小时制。“十位分钟”只能是0, 1, 2, 3, 4, 5。“个位小时”和“个位分钟”都是0-9。 因此他决定用1个数字块来显示“十位小时”0,1,2。用2个数字块来显示“十位分钟”0-5分配到两个块上例如一个管0-2一个管3-5。用3个数字块来显示“个位小时”0-9分配到三个块上。用3个数字块来显示“个位分钟”0-9分配到三个块上。 总共使用了9个数字块但通过组合覆盖了所有需要的数字。双轴万向节与隐藏机制每个数字块被安装在一个由两个伺服电机驱动的万向节支架上。这意味着每个方块可以绕两个互相垂直的轴例如水平轴X和垂直轴Y旋转。显示状态通过协调两个电机的角度将方块旋转到某个预设位置使得从观察者视角看目标数字清晰呈现。隐藏状态当这个方块在当前时间不需要显示数字时就将其旋转到一个“无效”角度比如原作者提到的45°。在这个角度下方块上所有数字的凸起都无法形成清晰的轮廓看起来就像一个带有杂乱纹理的装饰块从而实现了“隐藏”。伺服电机的角度约束标准180°旋转的舵机限制了旋转范围。为了将数字排布得更紧凑原作者甚至将其中一个轴的旋转范围进一步限制在90°内。这就要求在CAD设计阶段必须精确计算每个数字对应的两个舵机角度值确保在有限的运动空间内每个数字都能被正确“播放”到观察窗口。注意这种设计意味着大量的“角度对”需要标定。每个数字块对于它需要显示的每一个数字都有一组唯一的水平角度垂直角度坐标。这是软件部分最繁琐但至关重要的准备工作。2.3 电子系统架构选型整个系统的电子部分遵循了经典的分层控制架构特点是稳定、可靠且易于扩展。主控单元大脑Wemos D1 mini。这本质上是一个基于ESP8266的开发板。选择它而非更基础的Arduino Uno主要看中其内置的Wi-Fi功能。这使得时钟可以联网从NTP网络时间协议服务器自动获取精确时间实现“免调校”。这是物联网(IoT)的一个典型应用。执行器驱动单元神经中枢PCA9685 PWM驱动板。这是项目的关键组件。一个Wemos D1 mini的GPIO通用输入输出口和PWM脉冲宽度调制输出能力有限无法直接驱动多达13个伺服电机9个数字块 * 2个轴 18个电机等一下实际是13个说明部分块可能共享轴或设计有优化。PCA9685是一个16通道的I2C接口PWM控制器。你可以通过两根线SDA, SCL与主控通信然后由它同时产生多达16路独立的、精度很高的PWM信号来控制伺服电机。这解决了主控IO口不足的问题并且通过I2C总线简化了布线。执行器肌肉MG90s微型伺服电机。这是一种经济实惠、性能足够的金属齿轮舵机。它的180°旋转范围正好符合项目需求。选择金属齿轮是因为数字块虽然不重但长期、频繁的启停和保持位置对齿轮的耐用性有要求塑料齿轮容易磨损导致角度漂移。供电考虑伺服电机尤其是多个同时运动时瞬时电流可能很大。Wemos D1 mini和PCA9685的逻辑部分可以用5V或3.3V供电但伺服电机必须由独立的、电流充足的5V电源供电例如2A以上的USB适配器或专用的DC电源并通过PCA9685的V端口接入避免因电机动作导致主控板复位。3. 从零开始硬件制作与机械组装3.1 3D打印模型的设计与处理机械部分是整个项目的基础其精度直接影响最终显示效果。数字块设计这是最核心的CAD工作。你需要一个“等宽等高的字体”确保所有数字拉伸为立体模型后其基底大小一致才能放入统一的安装座。在三维软件如Fusion 360中你需要创建基础立方体。在每个需要“刻”数字的面上绘制数字草图。使用“拉伸”命令让数字部分凸出立方体表面一定高度例如2mm。关键点在于对于同一个方块上的不同数字它们是在立方体不同的面上被拉伸出来的。通过旋转立方体让不同的面朝向观察者。仔细检查不同数字的凸起部分在空间上是否干涉。例如数字“1”的凸起部分是否会影响从侧面看数字“2”的轮廓需要进行大量的视角预览和调整。结构件设计万向节支架需要设计两个互相嵌套的U型或框架结构分别连接水平轴电机和垂直轴电机。轴承部分可以直接利用伺服电机自带的输出轴和固定耳设计对应的卡槽和螺丝孔。底座与外壳需要容纳所有电路板、电机和走线。设计时应考虑散热、布线通道、USB口访问便利性。像原作者一样将外壳分成两半打印是解决打印床尺寸限制的常用方法。文件管理与支撑将所有零件导出为STL格式时务必确认单位毫米。在切片软件如Cura, PrusaSlicer中对于有悬空结构的数字块和万向节支架必须生成支撑否则打印会失败。支撑类型可以选择“树状支撑”相对容易拆除且节省材料。打印实践材料PLA是最佳选择它易于打印、强度足够、无异味、后期处理简单。层高与填充为了获得光滑的数字表面建议使用0.15mm或0.12mm的层高。填充率15%-20%即可强度主要靠外壳通常2-3层壁厚。颜色方案像原作者一样使用双色如黑橙打印数字块可以极大地增强视觉对比度和科技感。这需要在打印过程中暂停并更换耗材。3.2 机械组装步骤详解组装顺序很重要混乱的组装可能导致无法安装或损坏零件。准备伺服电机将每个MG90s舵机的舵盘舵机自带的塑料圆盘更换为适合你设计的连接件。通常你需要打印一个小的“联轴器”一端连接舵机轴另一端连接数字块的转轴或万向节支架。组装万向节首先将“水平轴”伺服电机固定到底座支架上。这个支架最终是固定在外壳底板上的。然后将“垂直轴”伺服电机固定到活动支架内框架上。这个活动支架将通过轴承或直接与水平轴舵机的舵盘相连。最后将数字块固定到垂直轴舵机的舵盘上。确保数字块的“初始面”朝向一个你定义好的方向比如正前方以便后续校准。整体集成先将所有组装好的万向节模块通过底座支架用螺丝固定到主底板上。将PCA9685驱动板用铜柱或螺丝固定在底板上合适位置。将Wemos D1 mini用热熔胶或尼龙柱固定。热熔胶的好处是可逆方便后期维修。布线管理这是保持项目整洁可靠的关键。使用扎带将伺服电机的三根线电源、电源-、信号捆扎整齐并沿着底板预设的线槽走线最后汇总连接到PCA9685板。混乱的线缆不仅难看还可能影响电机运动甚至造成短路。3.3 电路连接与焊接电路连接相对简单但务必仔细接错可能烧毁设备。主控与驱动板连接Wemos D1 mini - PCA9685 --------------------------- D1 (GPIO5) - SCL D2 (GPIO4) - SDA 5V - V (注意这是给舵机供电的主电源输入) 3.3V - Vcc (这是给PCA9685芯片本身供电的逻辑电压) GND - GND重要提示务必确保Wemos D1 mini和PCA9685的“地”GND连接在一起这是电路正常工作的基础。V输入的5V电源必须能提供足够电流建议至少2.5A。伺服电机连接将13个伺服电机的信号线通常是黄线或白线依次连接到PCA9685的通道0至通道15根据设计会空出几个通道。强烈建议你画一张连接表记录每个通道对应的是哪个时间单位的哪个轴水平/垂直。例如PCA9685通道控制对象对应舵机功能CH0十位小时块水平轴CH1-CH3个位小时块1-3水平轴.........CH12十位小时块垂直轴CH13个位小时块1垂直轴.........4. 嵌入式软件让时钟“活”起来硬件是躯体软件是灵魂。这里的代码不仅要实现功能更要处理多电机协同和网络对时。4.1 开发环境与核心库搭建安装Arduino IDE从官网下载并安装。添加ESP8266开发板支持在“文件-首选项”的附加开发板管理器网址中添加http://arduino.esp8266.com/stable/package_esp8266com_index.json。然后在“工具-开发板-开发板管理器”中搜索安装“esp8266”。安装必要库Adafruit PWM Servo Driver Library用于控制PCA9685。在库管理器中搜索“Adafruit PWM Servo Driver”并安装。NTPClient和WiFiManager用于网络对时和Wi-Fi配置。同样在库管理器中搜索安装。ESP8266WiFi通常随开发板包一起安装。4.2 核心代码逻辑剖析代码主要分为几个模块伺服控制、角度标定、时间获取与解析、状态机显示。#include Wire.h #include Adafruit_PWMServoDriver.h #include ESP8266WiFi.h #include WiFiManager.h #include NTPClient.h #include WiFiUdp.h // 初始化PCA9685对象 Adafruit_PWMServoDriver pwm Adafruit_PWMServoDriver(); // 定义每个伺服电机对应的通道号根据你的接线表修改 const int servoHoursTenH 0; // 十位小时水平轴 // ... 定义其他通道 // 定义每个数字块显示每个数字时两个舵机的脉冲宽度需要标定 // 这是一个示例结构实际你需要一个更复杂的数据结构如二维数组或结构体数组 // 例如posTable[blockIndex][digit][axis] pulseWidth; int posTable[9][10][2]; // 假设9个块每个块最多对应10个数字每个数字有2个轴的角度 // NTP客户端设置 WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, pool.ntp.org, 8*3600); // 东八区 void setup() { Serial.begin(115200); pwm.begin(); pwm.setPWMFreq(50); // 伺服电机标准频率50Hz // 1. 连接Wi-Fi使用WiFiManager首次启动会进入配网模式 WiFiManager wm; bool res wm.autoConnect(GimbalClockAP); // 创建热点 if(!res) { Serial.println(Failed to connect); // 可以考虑在这里让时钟进入错误显示模式 } else { Serial.println(Connected to WiFi); } // 2. 初始化NTP客户端并获取时间 timeClient.begin(); while(!timeClient.update()) { timeClient.forceUpdate(); delay(500); } // 3. 运行一次标定模式通常通过串口指令触发这里简化 // calibrateServos(); } void loop() { // 每60秒更新一次时间对于时钟来说足够了 static unsigned long lastUpdate 0; if (millis() - lastUpdate 60000) { timeClient.update(); int currentHour timeClient.getHours(); int currentMinute timeClient.getMinutes(); // 分解时间数字 int hourTen currentHour / 10; int hourOne currentHour % 10; int minuteTen currentMinute / 10; int minuteOne currentMinute % 10; // 根据分解的数字查找预设的角度值并设置对应的伺服电机 displayTime(hourTen, hourOne, minuteTen, minuteOne); lastUpdate millis(); } // 主循环可以处理其他任务如响应串口指令等 delay(100); } void displayTime(int hT, int hO, int mT, int mO) { // 这是一个伪代码逻辑你需要根据你的数字块分配方案来实现 // 例如对于“十位小时”块它只需要显示0,1,2 setBlockAngle(block_hour_ten, hT); // 设置该块到显示数字 hT 的位置 // 对于“个位小时”可能需要判断当前数字由哪个块显示并隐藏其他块 for (int i0; i3; i) { // 假设有3个块负责个位小时 if (blockAssignment_hour_one[i] hO) { setBlockAngle(block_hour_one[i], hO); // 显示 } else { setBlockAngle(block_hour_one[i], HIDE_ANGLE); // 隐藏转到45° } } // ... 同理处理分钟 } void setBlockAngle(int blockId, int digit) { int pulseH posTable[blockId][digit][0]; int pulseV posTable[blockId][digit][1]; pwm.setPWM(horizontalChannel[blockId], 0, pulseH); pwm.setPWM(verticalChannel[blockId], 0, pulseV); }4.3 最关键的步骤伺服电机角度标定这是项目中最耗时但也最决定性的环节。你需要编写一个简单的“标定模式”程序。创建标定程序在setup()里调用一个calibrateServos()函数或者通过串口发送特定字符进入标定模式。手动标定流程程序依次控制每个数字块的两个舵机使其缓慢地遍历可能的运动范围。你通过串口监视器发送指令如‘H’增加水平角度‘h’减少水平角度‘V’增加垂直角度‘v’减少垂直角度。当数字块旋转到某个位置使得从你的主视角看目标数字最清晰、最正时记录下此时两个舵机对应的脉冲宽度值pwm.setPWM(channel, 0, pulse)中的pulse通常在150-600之间。为每个数字块的每一个需要显示的数字重复这个过程记录下对应的pulseH, pulseV值。数据固化将记录的所有角度值以数组或结构体的形式保存在一个单独的servo_positions.h头文件中并在主程序中引用。这样主程序displayTime()函数只需要查表即可。实操心得标定时一定要将时钟外壳安装好并在最终摆放的位置和视角下进行。视角的微小变化都会影响数字识别的“正”感。可以两个人配合一个人操作键盘一个人观察并喊停。5. 调试、优化与问题排查即使组装和编程都完成了第一次上电也很大概率不会成功。以下是常见问题及解决方法。5.1 机械与硬件问题问题现象可能原因排查与解决某个舵机不转或抖动1. 电源功率不足。2. 信号线接触不良或接错。3. 舵机卡死机械干涉。1. 使用万用表测量供电电压确保在5V左右且加载时不掉压太多。换用电流更大的电源。2. 检查PCA9685上该通道的接线确认信号线未松脱。用示波器或逻辑分析仪检查该通道是否有PWM信号输出。3. 断开舵机与负载的连接空载测试是否转动。检查万向节是否有零件干涉导致堵转。所有舵机都不动1. I2C通信失败。2. 主电源未接通。1. 检查Wemos D1 mini与PCA9685之间的SDA、SCL连接。确认代码中I2C地址正确默认0x40。2. 检查给PCA9685的V和GND是否接入强电5V。数字显示歪斜、不清晰1. 标定角度不准确。2. 舵机存在回差或漂移。3. 3D打印件有变形或安装不牢。1. 重新进行精细标定。2. 这是廉价舵机的通病。在代码中可尝试加入“微调”偏移量。对于要求高的项目可考虑使用数字舵机并启用位置反馈模式。3. 检查数字块与舵机轴的连接是否紧固。打印件是否因冷却不均而翘曲。运动时噪音大、晃动1. 结构刚性不足。2. 舵机速度过快产生冲击。3. 重心不平衡。1. 增加关键连接部位的壁厚或添加加强筋。2. 在代码中不要让舵机瞬间跳到目标角度而是编写一个平滑移动函数让其缓慢过渡。3. 在数字块背面非显示面粘贴配重块使其重心靠近旋转中心。5.2 软件与网络问题问题现象可能原因排查与解决无法连接到Wi-Fi1. WiFiManager配置问题。2. 路由器设置问题如MAC过滤。1. 确保手机或电脑连接了时钟发出的“GimbalClockAP”热点进行配置。检查输入的密码是否正确。2. 查看路由器后台确认未屏蔽ESP8266的MAC地址。时间获取失败1. NTP服务器地址不可达。2. 时区设置错误。3. 网络不稳定。1. 尝试更换NTP服务器如cn.pool.ntp.org或time.apple.com。2. 检查timeClient初始化时的时区偏移参数秒数。3. 在代码中加入重试机制和错误处理获取失败时使用上次成功的时间并累加。显示错乱数字不对应1. 伺服电机通道映射错误。2. 角度查表数据错误或数组越界。3. 时间数字分解逻辑错误。1. 再次核对接线表与代码中的通道定义。2. 检查posTable数组的索引是否正确对应块和数字。添加串口打印输出当前时间、分解后的数字以及查询到的脉冲值。3. 仔细检查displayTime函数中的分配逻辑特别是“个位”由多个块负责时的判断条件。5.3 显示效果优化建议增强数字识别度正如原项目评论中指出的数字“9”可能难以辨认。可以在CAD阶段优化数字字体使用更粗、更方正的字体。或者在打印完成后用黑色哑光颜料涂装数字凸起部分背景用亮色增强对比。增加动态指示原作者提到用LED指示当前活跃的数字块。这是一个绝妙的想法。可以在每个数字块内部嵌入一个微型LED如0402封装的通过光导纤维或使用半透明PLA材料打印数字块让数字在激活时从内部发光科技感倍增。提升结构稳定性使用更大扭矩的舵机如MG996R或核心电机编码器的方案可以显著减少晃动。此外优化万向节轴承结构使用更紧密的配合或添加微型轴承也能减少虚位。加入交互功能利用Wemos D1 mini的Wi-Fi和Web服务器功能可以做一个简单的配置页面允许用户通过浏览器设置时区、调整亮度如果加了LED、甚至切换显示模式如12/24小时制。这个项目从构思到实现充满了工程上的权衡与乐趣。它不要求你有顶尖的机械或电子功底但需要你耐心地完成设计、打印、组装、编程和调试每一个环节。当最后所有方块齐刷刷地转动清晰地呈现出当前时间的那一刻所有的努力都会得到回报。它不仅是一个时钟更是一个展示了如何用简单技术组合创造出奇妙效果的立体教科书。

相关新闻