废旧光驱改造成旋转编码器:无刷电机霍尔信号实现角度与转速测量 📅 2026/8/26 3:42:20 老规矩先把这个项目的定位说清楚这篇文章要做的不是教你怎么把旧光驱拆了当废铁卖而是把里面那颗无刷主轴电机连同它自带的3颗霍尔传感器改造成一个能实时输出“转了多少度、转速多快”的旋转编码器。没错就是那种你在工业设备、机器人关节上常见的位置传感器只不过这次咱们用废旧驱动器来做成本几乎为零项目难度也控制在两周内能下班。这个方案适合谁如果你手头正好有一堆废旧光驱、硬盘又需要给手头项目加一个转速反馈、角度检测、限位归零之类功能那它绝对比你在电商平台花几十上百块买编码器实在得多。就算你是刚入门的创客只要会用电烙铁、写过Arduino例程这个项目基本就稳了。1. 项目思路旧驱动器里到底有什么能改编码器很多人一听到“旋转编码器”第一反应是工业设备里那种带光栅码盘、输出A/B相脉冲的高精度传感器觉得DIY搞不定。但实际上编码器的本质就是“感知旋转位置和速度”而旧光驱里的无刷主轴电机天生就带着3颗霍尔传感器。每转一圈这3颗霍尔会按一定规律输出高低电平组合只要处理器去读取这些状态就能还原出转子当前转到哪了、转速大概多少。所以这个项目的核心逻辑就是把“电机驱动里用于换相的位置检测信号”改造成“给外部控制器用的旋转位置信号”。电机和编码器的角色在电路层面其实是相通的只是我们换了个角度看问题。顺带说说旧驱动器里值得拆的东西光驱主轴电机3相无刷直流电机扁平结构自带3颗霍尔这是本文主角。光驱滑动步进电机激光头移动用的丝杆步进电机脉冲驱动适合改CNC滑块或小型直线平台。光驱托盘电机小直流电机只能做玩具风扇之类精度不高。硬盘主轴电机也是3相无刷电机超薄高转速但大多数型号没有内置霍尔没有反电动势反馈很难驱动改编码器不太划算。附带的一堆精密齿轮、丝杆、导轨、光电微动开关都是好东西。我一开始也想过从硬盘里拆了一个主轴电机来改后来发现它不带霍尔而且12V下转速动辄数千转控制难度大最后老老实实回归光驱电机。这也是想给各位提个醒不要因为标题里有“Disk Drives”就把所有盘片驱动器都当同一类光驱和硬盘在电机方案上差别非常大。有了准确的材料来源下一步关键问题就是为什么用霍尔信号而不是光学码盘我最早也踩过这个坑觉得光驱里明明有透明码盘和红外对管直接搬过来不就更像工业编码器结果试了才发现光驱码盘是给伺服寻道用的线性刻度不是标准的正交码盘读取电路和信号相位都对不上硬改成本高收益低。相比之下霍尔信号已经在电机内部经过整定读取电路极其简单分辨率虽然在绝对角度上不够漂亮但作为低成本方案非常稳。2. 原理拆解为什么电机本身就能当编码器2.1 旋转编码器的两类工作方式工业旋转编码器大致分增量式和绝对式两种。增量式编码器输出一组脉冲通常为A/B两相相位差90度通过数脉冲个数来推算旋转的相对角度通过A/B相先后顺序判断方向。它不知道当前绝对位置除非上电后先做一次归零动作。绝对式编码器则直接输出当前角度的数字量常见的有二进制格雷码、SSI串行协议或PWM占空比编码停电再上电也不会丢位置。我们拿光驱无刷电机的霍尔信号来做天然属于“增量式”。每次霍尔状态变化相当于编码器输出一个最小的位置步进处理器内部维护一个计数器即可知道相对角度。如果你想做绝对位置也好办在轴上加一个遮光片或磁铁配一个光电开关/霍尔开关作为零点上电后先转一圈找零后续就全部基于这个零点累加。2.2 霍尔传感器与无刷电机的天生联系无刷直流电机BLDC的转子是永磁体定子上有多组线圈。为了让控制器知道什么时候该给哪相线圈通电必须在电机内部放置位置传感器。绝大多数光驱主轴电机用的是3颗开关型霍尔传感器在圆周上按120度电角度分布。这里有个概念要理清机械角度和电角度。如果电机转子有4对极那么转子每转一圈磁场方向会周期变化4次对应4个360度电角度周期。霍尔传感器检测的是磁场方向变化所以它输出的状态转换频率是机械转数乘以极对数。对改造有用的结论霍尔输出是数字电平可以直接被单片机读取。3颗霍尔共产生2^38种组合其中6种是有效的另外两种通常不会出现。每出现一次有效的状态变化就代表转子转过了一个固定的“最小电角度步长”。电机极对数越多每转的状态总数越多分辨率越高。我们以常见的光驱主轴电机为例它通常是4对极8极转子或4极2对极。如果是4对极机械转一圈对应4个电角度周期每个周期有6个状态所以每圈总共能得到4×624个状态变化。这个分辨率确实不高但足以胜任转速测量和粗略角度判断。后文我会专门讲怎么用ADC把分辨率再往上提。2.3 霍尔状态与转子位置的对应关系三颗霍尔A、B、C在空间上相差120度电角度所以转子转动时会依次输出六组状态。把它们排出来是这样的霍尔A霍尔B霍尔C电角度区间度1000~6011060~120010120~180011180~240001240~300101300~360这个状态表非常重要后文写代码时我就是靠它判断方向并累加位置的。只要你顺着这个顺序读到状态变化就能确定转子是正转反过来就是反转。还有一个细节霍尔元件输出的是集电极开路信号直接读出来可能是悬空的必须接上拉电阻。有些Arduino的IO口内置上拉电阻可以省事但为了信号稳定我建议还是外接4.7kΩ到10kΩ的上拉后文接线部分会再强调。2.4 为什么不适合直接套用硬盘主轴电机开头说了硬盘主轴电机不带霍尔这里再展开聊聊免得大家走弯路。硬盘主轴电机几乎都是“传感器less”的3相无刷电机靠反电动势BEMF来判断转子位置。它的运行逻辑是给两相通电等第三相上感应出零点交叉信号再换相。这种结构在硬盘内部有专用控制芯片配合一旦离开原控制板你想读取位置信号就没有现成引脚可用了。而且硬盘主轴电机转速极高5400~7200转是常态轴承又做得很薄拆机后轴很容易变形直接拿来做编码器机械稳定性也存疑。所以这个项目里我只推荐从光驱拆主轴电机。光驱主轴电机的工作转速在几百到几千转之间同样是无刷但有霍尔有3根清晰的信号输出线接线难度完全不在一个数量级。3. 实战准备材料清单、工具与拆解步骤3.1 材料与工具清单这个项目对工具要求不高普通家庭工具柜基本都能凑齐。我列一张表按必需程度排一下材料/工具规格/用途必需程度废旧光驱CD/DVD-ROM或DVD刻录机品牌不限必需废旧硬盘备用拆轴承/铝盘做惯性负载可选Arduino Nano/Uno读取霍尔信号计算角度/转速必需4.7kΩ电阻 x3霍尔引脚上拉必需面包板跳线快速搭建测试电路必需万用表识别电机引脚、确认霍尔供电必需螺丝刀套装十字/一字/内六角都要有必需电烙铁焊锡焊接引线和电路板必需3D打印机打印电机固定支架、联轴器可选示波器/逻辑分析仪看霍尔波形、验证信号质量推荐如果你手头没有示波器也不用慌用Arduino读串口打印状态也能排错。示波器只是让问题暴露得更痛快一些属于锦上添花。3.2 拆解光驱的完整步骤与注意事项拆光驱这件事看着简单但细节决定成败。我每次拆都会提醒自己以下几点分享给各位第一步拆金属外壳。光驱外壳一般由4颗螺丝固定底部标签下面可能还藏着螺丝得把标签撕开或戳个洞才能拧到。有些品牌会用卡扣螺丝拆完直接撬四角就能打开。第二步拆面板和支架。前面板是卡扣结构小心别掰断卡扣。光驱内部电路板也就是那块带主控芯片的绿板先不急着拔线因为排线插头非常脆直接扯断就只能扔了。建议用镊子或指甲撬起排线压盖再轻轻抽出FPC排线。第三步找主轴电机。主轴电机在光盘托盘的正中心通常由3~4颗小螺丝固定在一块金属托板上。它的外观是一个扁平圆柱体直径大概25~40mm厚度10mm左右底部引出一组针脚或一条细线束。第四步拆步进电机。激光头支架上那个带丝杆的小电机是双极步进电机做直线驱动用的。如果你想顺便改造一台小型CNC滑块它值得一并拆出来。不过本文只用到主轴电机。第五步拆主轴电机连线。这里要特别注意很多光驱的电机驱动芯片和霍尔信号都在同一块驱动板上前置处理过你要找的是电机本体引脚而不是主控芯片引脚。拿万用表电阻档测一下绕组之间电阻通常是几欧姆到十几欧姆霍尔供电和信号引脚对地电阻则是几kΩ量级区分起来不难。第六步处理引线。电机引脚短的话直接焊一段30cm左右的硅胶线上去后期接面包板方便。务必将颜色标记清楚我习惯用红/黑/白/绿/黄五色定义红霍尔供电黑GND白霍尔A绿霍尔B黄霍尔C。三相绕组用蓝/橙/棕标记不参与信号读取但最好也引出方便以后做驱动测试。这里说一个我拆机时踩过的坑很多光驱主轴电机的霍尔信号不是直接裸引线出来而是先经过驱动板上的排线插座。如果你只拆到排线插座的电脑端那可能读到的是经过芯片缓冲的信号方向反了或电平不对。更稳的办法是直接从电机本体的引脚处取信号绕开驱动板保证我们读到的是原始霍尔信号。拆完后把电机固定在桌面上拿手搓转一下轴用万用表量霍尔输出你会看到电压在0和VCC之间跳变。到了这一步项目就成功一大半了。4. 硬件接线与信号处理4.1 识别电机与霍尔引脚拿到电机后先不要急着接Arduino。用万用表做一次完整测量把引脚定义摸清楚。这是我每次DIY都会强制执行的动作能省去后面无数排错时间。我在项目里测试的是从LG和三星两个品牌光驱里拆出来的电机引脚分布略有差异但底层规律一致绕组相线任意两根之间的电阻为1~20Ω具体看电机功率等级。霍尔供电VCC和GND供电脚对地电阻一般在几百Ω到几kΩ之间且不随转子位置变化。霍尔输出A/B/C任意两个霍尔输出之间或对地之间阻值通常较大转轴转动时电压会跳变。如果你能搜到对应电机型号的datasheet那最好搜不到就用万用表导通档加拨动转轴的办法来找。我通常先把找到的供电脚接上5V然后转动电机轴观察剩余3个引脚对GND的电压变化。哪个脚在转的时候有0~5V跳变哪个就是霍尔输出。这个方法非常朴素但百分之百有效。接线方案如下信号颜色约定接到说明霍尔供电红Arduino 5V霍尔IC工作电压GND黑Arduino GND公共地霍尔A白Arduino D2外部中断0霍尔B绿Arduino D3外部中断1霍尔C黄Arduino D4也可以做中断或普通IO绕组相线蓝/橙/棕不接悬空处理关于霍尔供电电压我实测过老光驱里大多是5V供电的霍尔IC但也有3.3V的。如果你不确定先看电机标签没有标签就先接5V再测信号电平如果信号电平始终接近VCC或0V且不跳变再降为3.3V试。Arduino Uno和Nano的5V和3.3V引脚都能提供小电流足够霍尔IC使用。4.2 信号整形与上拉电路霍尔IC的常见型号是AH276、OH41、SS41之类输出结构是集电极开路或推挽式。集电极开路输出必须接上拉电阻否则输出只能拉低不能拉高Arduino读到的是一路奇怪的浮动电平。建议每个霍尔输出引脚对VCC接一颗4.7kΩ电阻这是常规节点做法。Arduino内部的INPUT_PULLUP也能用但内部上拉电阻标称20~50kΩ抗干扰能力偏弱引线长了容易误触发。我实测手搓电机时内 Pullup还能勉强用一旦把电机和Arduino放在同一个工作台上干扰明显增多所以最终方案还是外接电阻。如果信号抖动严重可以在每个霍尔输出到GND之间并联一个0.1μF电容形成低通滤波把毛刺吸收掉。这个电容要尽量靠近Arduino引脚放置效果才明显。我前面提到过示波器能快速定位问题这里给一个判断标准接好上拉和电源后手拧电机轴示波器上应该看到三个占空比约50%的方波相位依次错开120度。如果看到的是正弦波或严重畸变的波形多半是霍尔供电脚接错了或者霍尔IC已经损坏。如果没有示波器就用Arduino读数字电平串口里连续打印三路状态手动慢转电机看状态是否按6组顺序轮换。这一步做完硬件就稳了下面进入软件。5. 代码实现角度、方向与转速计算5.1 Arduino接线与中断读取思路其实很清晰霍尔A、B、C任意一路发生变化就去读取当前三路霍尔电平得到一个状态编码再和上一次状态编码做比较。根据状态变化的方向正向跳变还是反向跳变就知道电机是正转还是反转然后累加或减少位置计数。放在Arduino里最合适的机制就是外部中断。把三路霍尔信号接到D2、D3、D4其中D2和D3是支持中断的引脚。由于每次状态变化都可能发生在任何一路霍尔上所以我选择在三路信号上全部挂中断只是D4不支持外部中断那就把它当普通IO在D2或D3的中断里读取D4的状态也可行。为了稳定我建议将三个霍尔都接到支持外部中断的引脚上比如Arduino Uno的D2/D3以及D2和D3之外的引脚不行那就用D2/D3加轮询D4的方案前提是电机转速不能太高。如果你用的是Arduino Due或ESP32这类有多路中断的板子那就三个引脚全挂中断代码会简单很多。5.2 核心代码与完整逻辑下面这段代码是我在Arduino Nano上实测过的功能包括读取霍尔状态维护相对位置计数器根据状态变化判断旋转方向计算实时转速并串口输出每200毫秒打印一次位置、角度换算值和转速// 旧光驱主轴电机 - 旋转编码器 Demo // 引脚定义 #define HALL_A 2 #define HALL_B 3 #define HALL_C 4 volatile int lastState 0; volatile long position 0; // 相对位置计数 volatile int stateCount 0; // 本次换相以来累计状态变化数 volatile unsigned long lastMicros 0; volatile float rpm 0.0f; // 霍尔状态 - 扇区索引建立状态表查找 const int sectorTable[8] {-1, 0, 1, -1, 3, 2, -1, 4}; int readSector() { int a digitalRead(HALL_A); int b digitalRead(HALL_B); int c digitalRead(HALL_C); return a | (b 1) | (c 2); } void onHallChange() { int current readSector(); int sector sectorTable[current]; if (sector 0) { lastState current; return; } // 判断方向扇区正向递增为正转反向递减为反转 // 由于霍尔间隔120度扇区变化方向可以直接确定转子转向 int delta sector - lastState; if (delta 1 || delta -5) { position; } else if (delta -1 || delta 5) { position--; } lastState sector; // 计算转速每变化一次代表转过一个扇区 // 一圈总扇区数 极对数 * 6这里假设4对极每圈24扇区 unsigned long now micros(); if (now lastMicros) { unsigned long dt now - lastMicros; if (dt 200) { // 转速(rpm) 60 / (扇区数 * 单扇区时间) // 单扇区时间 dt us一圈扇区数 24 rpm 60000000.0f / (24.0f * (float)dt); lastMicros now; } } } void setup() { pinMode(HALL_A, INPUT); pinMode(HALL_B, INPUT); pinMode(HALL_C, INPUT); // 开启外部中断三路霍尔变化都触发 attachInterrupt(digitalPinToInterrupt(HALL_A), onHallChange, CHANGE); attachInterrupt(digitalPinToInterrupt(HALL_B), onHallChange, CHANGE); attachInterrupt(digitalPinToInterrupt(HALL_C), onHallChange, CHANGE); Serial.begin(115200); delay(100); lastState sectorTable[readSector()]; lastMicros micros(); } void loop() { static unsigned long lastPrint 0; if (millis() - lastPrint 200) { // 位置计数换算角度。每圈24个扇区每扇区15度 float angle (position % 24) * 15.0f; if (angle 0) angle 360.0f; Serial.print(Position: ); Serial.print(position); Serial.print( Angle: ); Serial.print(angle); Serial.print( deg RPM: ); Serial.println(rpm); lastPrint millis(); } // 程序主循环可以干别的事 }这段代码有几个关键点需要解释第一个是lastState的初始化。上电时我先把当前霍尔状态对应的扇区读出来之后的中断都在这个基准状态上做增量避免开机瞬间误动作。第二个是方向判断。霍尔状态表是按顺序排列的正向旋转时扇区索引会增加到达最大值后回绕到0所以delta 1 || delta -5代表正向走了一格反向则是delta -1 || delta 5。写这种判断时最容易搞错建议你对照前面的状态表把逻辑在草稿纸上画一遍。第三个是转速计算。我假设电机每转一圈共24个扇区也就是极对数为4扇区数极对数×624。如果你的电机极对数不同这个24要改成实际值。怎么确认极对数把电机完全拆开数转子上的磁铁数量除以2就是极对数。如果不拆也可以用手慢慢转轴同时数霍尔状态变化次数转一圈一共变了多少次那就是每圈的扇区总数。这个实测值最可靠直接代进代码里的常量即可。5.3 精度估算与分辨率提升思路上面这套方案的分辨率其实很有限。一个典型的4对极光驱主轴电机一圈24个扇区换算成角度分辨率只有15度。如果你只是测转速、找零位、做限位这完全够用。但如果你想让它驱动一个云台头或机械臂这颗粒度就太粗了转起来会有明显的步进感。提升分辨率主要有三条路第一条路把开关量霍尔升级为模拟量读取。霍尔IC在磁场强度变化时输出电压并不只是0和VCC两个值在状态切换的中间区间输出会有一段线性过渡区域。用Arduino的ADC去采样霍尔模拟电压再做一个线性插值可以在一个电气周期里得到更多细分。实测下来把分辨率从24提升到100左右是可行的但前提是霍尔输出必须是线性霍尔而不是开关型霍尔。普通光驱电机里的霍尔IC大多是开关型在这个项目上走不通除非你换线性霍尔。第二条路在电机转轴上粘一块径向充磁的小磁铁然后用AS5600这类磁角度传感器读取。AS5600内部集成了霍尔阵列和ADC直接输出12位角度也就是每圈4096步。这个方案不依赖原电机霍尔属于“借用电机机械结构外挂传感器”也是我实际用下来最推荐的高分辨率改法。第三条路在轴上粘贴一个自制光栅码盘配合红外对管读取。可以用打印的黑白条纹盘但这对安装精度要求极高普通手搓条件下很难保证条纹间距均匀容易发生码盘偏心导致读数错误。如果你的目标是做低速高精度定位我更推荐第二条路电机机械结构不变把霍尔信号当成粗定位AS5600当精定位两者互补。这套双模方案在DIY机械臂上表现相当不错。6. 常见问题与调试实录这个项目我踩过不少坑有些问题看起来是软件问题实际是硬件接错有些正好相反。我整理了一张速查表按频率排序方便你遇到问题直接对照。现象可能原因解决办法串口霍尔状态一直不变霍尔供电接反或引脚识别错误用万用表复核供电脚和地直接量引脚电压转速数值忽高忽低信号抖动或转速计算方式有误检查上拉电阻加0.1μF滤波电容方向判断偶发反向霍尔A/B/C顺序接错交换任意两路霍尔输出重新测试位置计数长期漂移中断里漏掉状态变化确认三路霍尔都接中断或降低电机转速高速旋转时计数乱飞中断响应不及时换主频更高的板子或精简中断里的代码霍尔输出一直高/低霍尔IC损坏换电机或单独给霍尔IC供电测试其中最常见的是第2条转速忽高忽低。很多人一开始觉得是算法问题但真正原因是霍尔信号在临界点附近来回跳动导致中断被重复触发单扇区时间被误判为极短。解决方案分两步第一步接上拉电阻和滤波电容把信号整形干净第二步在代码里加一个去抖逻辑也就是两次中断间隔小于某个阈值比如50微秒就忽略这次变化。工业编码器里的硬件滤波器也是同样的思路。还有一个细节我在测试时发现如果把霍尔信号线走了太长平行线和电机绕组线绑在一起信号会串入不少噪声。因为三相绕组虽然没有通电但电机转动时线圈会感应出微弱的反电动势如果这个电动势耦合到霍尔线上就会造成误触发。建议霍尔信号线远离绕组线或者用双绞线传输。这一点在工业现场布线里是常识但DIY时很容易忽略。如果转速很低比如用手慢慢转电机轴转速计算也会不准。此时单扇区时间可能长达几百毫秒中断频率很低插值出来的瞬时转速波动很大。更好的做法是记录最后6个扇区的时间戳用滑窗平均来估算转速。这个思路和工业编码器M/T测速法类似有兴趣的可以在代码里实现。7. 应用场景与进一步扩展最后聊一聊这个改造出来的“旋转编码器”实际能干什么以及我个人的一些体会。第一个应用是给手写DIY的小型转台或云台做角度限位。比如你做一个遥控云台底座需要左右各转90度在电机轴侧装一个霍尔编码器代码里设定软件限位到角度就停止输出。这个用不上高精度24扇区足矣。第二个应用是测转速。把光驱电机本身当作一个发电机用外力带动它旋转霍尔信号就能实时输出转速。这个方案在物理实验、转速测控演示中非常直观成本几乎为零而且响应速度足够快。第三个应用是归零和定位。给电机轴加一个遮光片配合一个光电开关做零点上电后让电机以已知方向转到光电开关输出沿然后把位置计数器清零。之后不论手动转到哪个角度都能读出相对零点的位置。这是我最常做的事用来配合3D打印机的行程开关做半自动调平效果还不错。如果你想让这个项目更有挑战性可以试试把代码移植到ESP32上加一个OLED屏幕实时显示转速和角度曲线甚至通过WiFi把数据上报到手机。这些扩展都不难但会让整个项目从一个“拆机小玩具”变成一个“带物联网测控性质的仪表原型”。我个人做了多次这个项目后最深的一个体会是任何拆机改造第一优先级永远是搞清接口定义第二优先级才是琢磨算法和代码。很多朋友一上来就写转速算法结果霍尔引脚都没找对自然跑不通。花20分钟用万用表把引脚全理清楚后面会顺很多。最后再分享一个小技巧拆下来的光驱主轴电机如果你不着急用可以在轴上点一滴轻质润滑油我用的是缝纫机油让它静置一晚再通电测试。旧电机放置多年后轴承干涩你一上来就高速运转会加剧磨损转速读数也不稳定。润滑完你会发现手轻轻一拨轴就能顺畅转好几圈霍尔信号也干净得多。这个细节别省。