用N20减速电机自制舵机:从开环到闭环的电机控制实践

用N20减速电机自制舵机:从开环到闭环的电机控制实践 这次我们来看一个用N20减速电机自制舵机的项目。这个项目的核心不是要做一个性能多强的舵机而是展示如何用最基础的元件——一个普通的N20减速电机通过简单的电路和控制逻辑实现类似舵机的角度定位功能。对于想了解舵机工作原理、学习基础电机控制或者手头正好有N20电机想“废物利用”的硬件爱好者来说这是个非常直观的实践案例。从演示来看这个自制舵机已经能实现基本的转角动作但作者也提到了一个明显的遗憾电机轴太短限制了实际应用。这恰恰点出了DIY项目的精髓——在有限的条件下实现功能并清晰地认识到其局限性。本文将带你拆解这个项目的核心思路从硬件选型、电路设计到代码控制一步步复现其效果并探讨如何优化比如延长轴长、增加反馈以提高精度。如果你对Arduino、树莓派Pico控制舵机或者对减速电机、PWM控制原理感兴趣这篇文章会提供一个从理论到落地的完整参考。1. 核心能力速览能力项说明核心元件N20减速电机带减速箱的直流电机控制核心常见微控制器如Arduino、树莓派Pico等核心功能模拟舵机的角度定位控制反馈机制演示项目通常为开环控制无位置传感器控制信号标准PWM脉冲宽度调制信号供电需求根据N20电机电压确定常见3V-6V适合场景原理学习、教育演示、对精度要求不高的DIY项目主要局限无位置反馈导致精度和重复性差电机轴短负载能力有限2. 适用场景与使用边界这个自制舵机项目最适合以下几类人硬件入门学习者想弄明白舵机“黑盒子”里面到底是什么PWM信号如何控制电机转动。创客与DIY爱好者手头有一些闲置的N20电机想尝试将其改造成可定位的执行器用于小型模型、玩具或艺术装置。教育演示老师或培训者需要一个成本低廉、原理清晰的教具来讲解电机控制、减速比、PWM等概念。它能解决的问题直观展示舵机的基本工作原理用脉冲宽度对应目标角度。提供一套完整的、从硬件连接到软件编程的实践流程。在成本极低的前提下实现“有总比没有强”的角度控制功能。它不适合的场景高精度定位如机械臂关节、机器人云台、航模舵面等需要精确、稳定角度的场合。开环控制无法纠正误差。大扭矩负载N20电机本身扭矩小即使带减速箱其负载能力也远小于标准舵机。可靠性要求高的产品DIY项目在稳定性、一致性、寿命方面无法与工业级舵机相比。安全与合规边界电气安全注意电机工作电压避免超压烧毁。驱动电路如电机驱动模块需能承受电机堵转电流。机械安全自制结构强度有限避免用于可能产生人身伤害或财产损失的场景。高速旋转的电机轴需做好防护。版权与专利本项目为开源学习项目用于商业用途需注意相关驱动芯片、控制算法的知识产权问题。3. 环境准备与前置条件要复现或改进这个项目你需要准备以下硬件和软件环境。硬件清单N20减速电机这是核心。注意选择带有减速箱的型号减速比越大输出扭矩相对越大转速越慢。常见电压有3V、6V等。微控制器任选其一即可。Arduino Uno/Nano最普及资料最多。树莓派Pico性价比高双核处理器PWM资源丰富。ESP32自带Wi-Fi/蓝牙适合物联网项目。电机驱动模块因为微控制器IO口驱动能力不足以直接驱动电机必须使用驱动模块。L9110S / L298N 模块适用于驱动单个或两个直流电机。TB6612FNG 模块效率更高发热更小推荐使用。电源根据N20电机电压选择。如果电机是6V则需要一个6V左右的直流电源如电池盒或稳压模块同时要确保能为微控制器供电通常5V。杜邦线与面包板用于连接电路。(可选) 电位器或编码器如果你想升级为闭环控制需要增加角度传感器。(可选) 延长轴与联轴器解决原作者提到的“电机轴太短”问题。软件环境Arduino IDE如果使用Arduino或兼容Arduino的板子如ESP32。Thonny 或 Arduino IDE如果使用树莓派Pico。相应的板卡支持包Board Support Package。4. 电路连接与硬件搭建硬件连接是项目的基础。我们以最常见的Arduino Uno TB6612FNG驱动模块 N20电机为例。接线原理微控制器产生PWM信号和控制方向信号给驱动模块驱动模块根据信号控制电机的电压极性和大小从而控制电机的正反转和速度。具体接线步骤连接电源将外部电源如6V电池的正极VM和负极GND分别接到TB6612FNG模块的VM和GND引脚。将Arduino的5V和GND接到TB6612FNG模块的VCC和GND为驱动模块的逻辑部分供电。连接控制信号假设我们使用TB6612FNG的A通道驱动一个电机。将Arduino的某个PWM引脚如5连接到模块的PWMAA通道PWM输入。将Arduino的两个数字引脚如4和7连接到模块的AIN1和AIN2A通道输入控制。连接电机将N20电机的两根线分别接到TB6612FNG模块的A01和A02输出端。共地确保Arduino的GND、驱动模块的GND以及外部电源的GND连接在一起。接线表示例Arduino Uno 引脚TB6612FNG 模块引脚说明5VVCC为驱动芯片逻辑供电GNDGND共地D5PWMAA通道PWM速度控制D4AIN1A通道方向控制1D7AIN2A通道方向控制2-VM接外部电机电源正极如6V-GND接外部电机电源负极-A01接N20电机线1-A02接N20电机线2关于“电机轴太短”的解决方案如果原装轴太短无法安装舵盘或负载可以考虑使用联轴器购买孔径匹配的联轴器一端连接电机轴另一端连接一根更长的金属杆或轴。更换长轴电机直接购买轴更长的N20电机型号。DIY延长技术能力强的可以尝试焊接或粘接一段轴但需保证同心度否则抖动会非常严重。5. 控制原理与代码实现自制舵机的核心逻辑就是用程序模拟标准舵机的控制协议。标准舵机PWM信号周期通常为20ms50Hz脉冲高电平宽度在0.5ms到2.5ms之间对应舵机0度到180度或其他角度范围。自制开环舵机逻辑由于没有位置反馈我们无法知道电机实际转了多少度。因此这里的“角度”控制实际上是“时间”控制。概念映射假设给电机全速正转2.5秒它能从机械限位的一端转到另一端我们就把这2.5秒映射为180度。控制流程收到“转到90度”的指令 - 计算出需要转动的时间如 90/180 * 2.5s 1.25s- 控制电机正转1.25秒 - 停止。方向控制需要定义哪边是0度哪边是180度。通常通过改变电机转向来实现。显然这种方法误差很大电池电压变化、负载变化、摩擦变化都会影响转速但足以演示原理。Arduino 示例代码 (开环控制)// 引脚定义 const int PWMA 5; // PWM控制引脚 const int AIN1 4; // 方向控制引脚1 const int AIN2 7; // 方向控制引脚2 // 电机参数需要根据你的电机实测调整 const unsigned long fullRotationTime 2500; // 电机从一端转到另一端所需时间(毫秒) const int angleRange 180; // 角度范围 void setup() { pinMode(PWMA, OUTPUT); pinMode(AIN1, OUTPUT); pinMode(AIN2, OUTPUT); Serial.begin(9600); Serial.println(DIY Servo Ready. Send angle (0-180)); } void loop() { if (Serial.available() 0) { int targetAngle Serial.parseInt(); // 从串口读取目标角度 if (targetAngle 0 targetAngle angleRange) { moveToAngle(targetAngle); Serial.print(Moved to: ); Serial.println(targetAngle); } } } void moveToAngle(int angle) { // 1. 计算需要转动的时间 unsigned long runTime map(angle, 0, angleRange, 0, fullRotationTime); // 2. 控制电机正转假设从0度向180度转 digitalWrite(AIN1, HIGH); digitalWrite(AIN2, LOW); analogWrite(PWMA, 200); // 以一定速度运行PWM值0-255 // 3. 运行计算出的时间 delay(runTime); // 4. 停止电机 analogWrite(PWMA, 0); digitalWrite(AIN1, LOW); digitalWrite(AIN2, LOW); // 注意这是开环控制实际位置不准确 // 并且这里假设每次都是从0度开始转实际需要更复杂的逻辑记录“当前位置”。 }这段代码只是一个最基础的演示。它每次都是从“假设的0度”开始转到目标角度现实中没有复位功能多次运行后误差会累积得无法使用。6. 功能测试与效果验证按照上述步骤连接好硬件并上传代码后可以进行功能测试。测试1基础运动测试目的验证电机是否能被正确驱动正反转。操作修改代码不读取串口直接在setup里让电机正转2秒停止1秒反转2秒。预期结果电机能按照指令转动和停止。判断成功电机有明确的启停和转向变化。常见问题电机不转检查电源是否接好、驱动模块使能、控制引脚电平是否正确电机只振动不转可能是电源功率不足或驱动模块故障。测试2开环角度控制测试目的验证串口指令控制“角度”的功能。操作打开Arduino串口监视器设置波特率为9600。发送0回车。观察电机是否短时间运行后停止对应0度。发送90回车。观察电机运行时间是否约为发送0时的1.5倍假设180度对应2.5秒。发送180回车。观察电机是否长时间运行后停止。预期结果电机运行时间随发送的数值增大而变长。判断成功能观察到明显的运行时长差异说明“角度-时间”映射关系基本建立。核心局限验证重复发送90多次你会发现电机停止的位置每次都可能不一样。这就是开环控制的致命缺点——没有反馈无法纠偏。测试3负载与电压影响测试目的理解环境因素对开环控制精度的影响。操作在电机轴上粘一根指针作为位置参考。发送90记录指针停止的大致位置。用手指轻轻给电机轴施加一点阻力模拟负载增加再次发送90。或者稍微降低供电电压再次测试。预期结果在负载增加或电压降低后发送相同的角度指令电机停止的位置会偏离之前的位置。结论这个测试直观地说明了为什么真正的舵机必须要有位置反馈电位器或编码器。7. 进阶改进增加位置反馈实现闭环控制要让自制舵机变得实用必须增加位置传感器实现闭环控制。这里介绍两种常见方案。方案一电位器反馈模拟舵机方案这是最接近标准舵机的方案。硬件将一个单圈或多圈电位器与电机输出轴通过联轴器直接连接。电位器两端接Vcc和GND中间抽头接微控制器的模拟输入引脚如A0。原理电位器电压随轴的角度线性变化。单片机读取这个电压值就知道当前的实际角度。控制逻辑PID简化版读取目标角度和当前角度通过电位器电压换算。计算误差 目标角度 - 当前角度。如果误差为正则控制电机正转误差为负则反转。电机转速或PWM占空比可以与误差大小成比例比例控制P。当误差接近0时停止电机。Arduino 示例代码片段 (电位器反馈)#include PID_v1.h // 使用PID库简化控制 // 引脚定义 const int motorPWM 5; const int motorIN1 4; const int motorIN2 7; const int potPin A0; // 电位器连接引脚 // PID参数 double Setpoint, Input, Output; double Kp2.0, Ki5.0, Kd1.0; // 需要调试 PID myPID(Input, Output, Setpoint, Kp, Ki, Kd, DIRECT); void setup() { pinMode(motorPWM, OUTPUT); pinMode(motorIN1, OUTPUT); pinMode(motorIN2, OUTPUT); Serial.begin(9600); // 初始化PID Input analogRead(potPin); // 读取当前位置 Setpoint map(512, 0, 1023, 0, 180); // 初始目标设为中间位置 myPID.SetMode(AUTOMATIC); myPID.SetOutputLimits(-255, 255); // 输出限幅正负代表方向 } void loop() { if (Serial.available() 0) { Setpoint Serial.parseInt(); // 设置新目标角度 } // 1. 读取当前位置 int potValue analogRead(potPin); Input map(potValue, 0, 1023, 0, 180); // 转换为角度 // 2. 计算PID myPID.Compute(); // 3. 根据PID输出控制电机 int pwmVal abs(Output); pwmVal constrain(pwmVal, 0, 255); analogWrite(motorPWM, pwmVal); if (Output 0) { digitalWrite(motorIN1, HIGH); // 正转 digitalWrite(motorIN2, LOW); } else if (Output 0) { digitalWrite(motorIN1, LOW); // 反转 digitalWrite(motorIN2, HIGH); } else { analogWrite(motorPWM, 0); // 停止 } delay(10); // 控制周期 }方案二磁编码器反馈更高精度方案使用AS5600等磁编码器模块精度和寿命远高于电位器。硬件将一个小磁铁固定在电机输出轴上编码器模块靠近磁铁固定。模块通过I2C或模拟接口与单片机通信。优势非接触式无磨损分辨率高可测量多圈绝对位置。控制逻辑与电位器方案类似只是获取当前角度值的方式换成了读取编码器数据。增加反馈后你的自制舵机才能真正实现“指哪打哪”抗干扰能力如负载变化也大大增强。8. 资源占用与性能观察对于微控制器项目资源占用主要关注程序存储空间Flash、内存RAM以及CPU计算时间。开环程序非常节省资源Flash可能只用几KBRAM占用极少delay()函数会阻塞CPU。闭环PID程序引入了浮点运算和PID控制循环会占用更多的Flash和RAM。使用PID_v1.h库会增加一定体积。控制周期loop中delay(10)决定了响应速度周期越短CPU占用越高但控制更及时。编码器方案如果使用I2C编码器需要引入Wire库并处理I2C读取会进一步增加代码复杂度和周期时间。性能关键点控制频率PID计算和电机更新的频率建议在50-100Hz周期10-20ms以上太低会导致响应迟钝产生振荡。PWM频率Arduino默认PWM频率约490Hz或980Hz对于电机驱动足够。如果觉得电机声音太尖或振动大可以尝试调整PWM频率高级技巧。电源质量电机启停会造成电源电压波动可能影响单片机稳定工作和AD转换电位器读取精度。建议在电机电源端并联一个大电容如1000uF进行滤波。9. 常见问题与排查方法问题现象可能原因排查方式解决方案电机完全不转1. 电源未接通或电压不足2. 驱动模块未使能3. 控制信号线接错或未连接4. 电机本身损坏1. 用万用表测量电机两端电压2. 检查驱动模块的VCC供电3. 检查单片机到驱动模块的连线4. 直接给电机加电测试1. 确保电源开关打开电压匹配2. 检查并连接驱动模块使能引脚如有3. 对照接线图逐一检查4. 更换电机电机只振动不转1. 电源功率不足电流不够2. 驱动模块输出电流不足或损坏3. 电机堵转机械卡死1. 测量电机工作时的电源电压是否被拉低2. 尝试更换驱动模块3. 手动转动电机轴检查是否顺畅1. 更换功率更大的电源2. 更换驱动模块如TB66123. 排除机械障碍开环控制位置严重不准1.fullRotationTime参数不准确2. 电源电压波动3. 负载变化1. 实测电机空载从一端到另一端的时间2. 使用稳压电源3. 这是开环固有缺陷1. 重新校准时间参数2. 升级为带反馈的闭环控制闭环控制PID振荡严重1. PID参数Kp, Ki, Kd不合适2. 控制周期不稳定3. 传感器噪声大1. 观察角度变化曲线2. 检查loop中是否有不固定的长延时3. 读取传感器数值观察是否跳动1. 重新整定PID参数先调Kp再调Kd最后Ki2. 使用millis()进行定时避免delay()3. 对传感器读数进行软件滤波电位器反馈角度跳动1. 电位器接触不良或质量差2. 电源噪声干扰模拟信号3. AD转换参考电压不稳1. 测量电位器抽头电压是否平稳2. 在电位器供电端加滤波电容3. 使用analogRead()多次取平均1. 更换质量好的电位器或改用编码器2. 硬件上加电容0.1uF并联10uF3. 软件中实现滑动平均滤波通过串口发送指令无反应1. 串口波特率设置错误2. 代码中串口读取逻辑有误3. 串口监视器未发送回车符1. 检查代码和串口监视器的波特率是否一致2. 检查Serial.parseInt()的使用逻辑3. 确保串口监视器设置了“新行”或“回车”1. 统一改为9600等常用波特率2. 改用Serial.readStringUntil(\n)3. 在串口监视器中勾选“发送新行”10. 最佳实践与使用建议从简到繁务必先从开环控制开始理解最基本的电机驱动和PWM控制成功后再引入电位器实现闭环最后再挑战编码器。参数实测fullRotationTime、电位器电压与角度的映射关系等关键参数一定要在自己的硬件上实际测量不能照搬代码中的示例值。电源隔离强烈建议为电机驱动部分单独供电并与单片机电源共地。避免电机噪声干扰单片机。可以使用双路输出的电源模块或者两组电池。机械加固N20电机体积小固定不牢会导致整体晃动影响精度。使用热熔胶、螺丝或3D打印一个固定座来确保电机和传感器稳定。软件滤波无论是读取电位器还是编码器都建议加入简单的软件滤波如滑动平均可以平滑数据减少突变。PID整定方法先将Ki和Kd设为0。逐渐增大Kp直到系统开始出现等幅振荡。将此时的Kp值乘以0.6到0.8作为初步的Kp。逐渐增大Kd用于抑制超调和振荡。最后微调Ki用于消除静态误差如果存在。安全第一电机轴旋转时具有动能不要用手直接触碰。在测试时可以在轴上安装一个柔软的指针或轻质负载。这个用N20减速电机自制舵机的项目其价值不在于做出一个媲美商品舵机的东西而在于完整地揭示了一个自动化执行器从开环到闭环的控制原理演进过程。它让你亲自动手直面精度不足、负载影响等实际问题并通过增加传感器、引入PID算法来解决它们。最应该先验证的是电机的双向可控转动这是所有后续工作的基础。最容易踩的坑是电源功率不足和接线错误。当你成功加上电位器并调通PID让电机能稳定指向你设定的角度时你对舵机、对闭环控制的理解会上一个坚实的台阶。下一步你可以尝试用磁编码器获得更精确耐用的反馈或者用步进电机驱动器方案来获得更大的扭矩和开环精度步进电机本身可以开环控制但仍有丢步问题。你还可以把这个自制“舵机”集成到一个小型机械臂或云台上用多个这样的关节完成更复杂的动作。