拓冰建站拓冰建站
首页 / 资讯中心 / 正文

N20减速电机自制舵机:PID闭环控制与AS5600磁编码器实战

1. 背景与核心概念在机器人、航模和自动化项目中舵机是实现精确角度控制的核心执行器。然而标准舵机往往体积较大、价格偏高且其内部结构电机减速箱电位器相对固定在一些需要定制化尺寸或特殊安装方式的应用中显得不够灵活。这时一个极具性价比和创造性的方案就出现了使用N20减速电机配合简单的控制电路和程序自制一个“舵机”。本文将围绕“使用N20减速电机自制舵机”这一主题为你完整拆解从原理分析、硬件选型、电路设计到代码编写的全流程。无论你是正在学习Arduino或树莓派Pico的电子爱好者还是希望为小型机械臂、智能小车寻找更优驱动方案的开发者都能从本文中获得一套可直接复用的实战方案。我们将重点解决自制舵机中的核心难题——如何实现闭环位置控制并最终让电机轴像真舵机一样精准地转动到我们指定的角度。核心概念区分标准舵机一个封装好的模块内部包含直流电机、减速齿轮组、位置反馈电位器和控制电路。接收PWM信号自动完成位置闭环控制输出轴角度通常为0-180度。自制舵机本文方案我们使用N20减速电机作为动力和减速部分通过外部的磁编码器或其它角度传感器实现位置反馈并由主控板如Arduino、树莓派Pico运行PID控制算法来模拟标准舵机的功能。其优势在于尺寸、减速比、输出轴长度可灵活定制成本可控。2. 环境准备与版本说明在开始动手之前我们需要准备好所有硬件和软件。版本信息以常见且稳定的组合为例你可以根据手头现有的物料进行调整。2.1 硬件清单N20减速电机建议选择带减速箱的型号例如6V电压减速比在100:1到298:1之间。减速比越大输出扭矩越大但转速越慢可根据需求选择。电机驱动模块用于驱动电机正反转。最常用的是DRV8833或TB6612FNG双H桥驱动模块。它们比普通的L298N体积更小、效率更高。角度传感器关键部件方案A推荐磁编码器如AS5600。它通过检测磁铁角度来提供高精度的绝对位置信息非接触式寿命长安装灵活。方案B电位器。需选择线性好的精密电位器并将其轴与电机输出轴耦合。这是最接近标准舵机的方案但存在磨损问题。主控板任选其一。Arduino Uno/Nano生态成熟资料丰富。树莓派PicoRP2040性能更强双核价格便宜非常适合此类项目。电源根据电机电压选择如6V电机可使用2节18650电池串联供电。务必确保驱动模块和主控板的逻辑电压通常5V或3.3V得到满足。连接线与杜邦线若干。结构件用于固定电机、传感器和主控板的亚克力板、3D打印件或乐高积木。(可选) 磁铁如果使用AS5600磁编码器需要一个小型径向磁化磁铁安装在电机轴上。2.2 软件环境Arduino IDE版本1.8.x或2.0均可用于编写和上传代码到Arduino或树莓派Pico。必要的库对于DRV8833/TB6612电机驱动通常不需要专用库直接控制引脚电平即可。对于AS5600磁编码器需要在Arduino IDE的库管理中搜索并安装“AS5600”库。对于PID控制Arduino IDE自带“PID”库非常方便。2.3 电路连接原理图思路在焊接或接线前理解连接关系至关重要。下图展示了核心部件的连接逻辑[主控板] ---PWM/数字IO--- [电机驱动模块] ---电力--- [N20减速电机] | | |---I2C/模拟引脚--- [角度传感器 (如AS5600)] | | |---GND VCC--- [传感器供电]接线详解以Arduino Uno DRV8833 AS5600为例电机驱动(DRV8833)AIN1,AIN2连接 Arduino 数字引脚D5,D6用于控制电机A。BIN1,BIN2悬空或控制另一个电机。VM接电机电源正极如6V。GND接电机电源负极和 Arduino GND。VCC接 Arduino5V为驱动逻辑供电。AOUT1,AOUT2连接 N20 电机的两根线。磁编码器(AS5600)VDD接 Arduino3.3V注意AS5600工作电压为3.3V。GND接 ArduinoGND。SDA接 ArduinoA4(或标有SDA的引脚)。SCL接 ArduinoA5(或标有SCL的引脚)。电源确保所有GND共地。电机的大电流电源与Arduino的5V逻辑电源最好分开供电但共地。3. 核心原理PWM控制与PID闭环自制舵机的核心在于用软件和电路实现标准舵机硬件的功能。3.1 PWM控制电机速度与方向我们无法直接让电机停在一个精确位置。首先需要控制它转动。通过电机驱动模块我们可以向控制引脚输入PWM信号。AIN1HIGH, AIN2LOW电机正转。PWM值控制转速。AIN1LOW, AIN2HIGH电机反转。AIN1AIN2电机刹车停止。在代码中我们使用analogWrite(pin, value)来产生PWM信号value范围0-255。3.2 位置反馈与PID控制算法仅有开环控制电机无法精准停在目标位置。我们需要感知当前位置通过AS5600读取电机轴的实际角度currentAngle。计算误差误差 目标角度 - 当前角度。PID控制器计算输出根据误差的比例(P)、积分(I)、微分(D)项计算出一个控制量output。这个output将转换为PWM值驱动电机向减小误差的方向转动。闭环调节不断重复步骤1-3直到误差趋近于零电机轴稳定在目标位置。PID参数通俗理解P比例误差越大电机转动力量越大。太大容易震荡太小则响应慢。I积分消除静态误差。如果始终有微小偏差积分项会累积并加大输出最终消除偏差。D微分抑制震荡。当误差快速减小时微分项产生一个反向力防止冲过头使系统更稳定。Arduino的PID库帮我们完成了复杂的计算我们只需设定目标值、反馈值并获取输出值。4. 完整实战案例基于Arduino的自制舵机让我们从零开始构建一个完整的自制舵机系统。4.1 创建项目与接线首先按照第2.3节的接线图将硬件连接好。确保所有连接牢固特别是电机驱动部分的电源线接触不良会导致驱动芯片损坏。4.2 编写核心代码在Arduino IDE中创建一个新项目并安装必要的库AS5600, PID。// 文件DIY_Servo_with_AS5600_PID.ino // 依赖库AS5600, PID #include Wire.h #include AS5600.h #include PID_v1.h // 电机驱动引脚定义 (连接DRV8833) #define MOTOR_AIN1 5 #define MOTOR_AIN2 6 // PID参数及变量定义 double Setpoint, Input, Output; // 目标角度输入角度PID输出 double Kp 2.0, Ki 5.0, Kd 0.1; // PID增益需要根据实际调试 PID myPID(Input, Output, Setpoint, Kp, Ki, Kd, DIRECT); // AS5600对象 AS5600 encoder; // 角度范围映射根据你的机械安装调整 const long RAW_MIN 0; // AS5600原始值最小值 const long RAW_MAX 4095; // AS5600原始值最大值 (12位分辨率) const float ANGLE_MIN 0.0; // 对应最小原始值的角度(度) const float ANGLE_MAX 360.0; // 对应最大原始值的角度(度)我们做连续旋转 void setup() { Serial.begin(115200); Wire.begin(); // 初始化电机驱动引脚 pinMode(MOTOR_AIN1, OUTPUT); pinMode(MOTOR_AIN2, OUTPUT); brakeMotor(); // 初始状态刹车 // 初始化AS5600 if (!encoder.begin()) { Serial.println(AS5600 not found!); while (1); } encoder.setDirection(AS5600_CLOCK_WISE); // 设置方向 // 初始化PID myPID.SetMode(AUTOMATIC); myPID.SetOutputLimits(-255, 255); // 输出限制对应PWM范围负值表示反转 myPID.SetSampleTime(10); // PID计算周期(ms) // 设置初始目标角度为当前位置 Input getCurrentAngle(); Setpoint Input; Serial.println(System Initialized. Current Angle: String(Input)); } void loop() { // 1. 读取当前角度 Input getCurrentAngle(); // 2. 计算PID myPID.Compute(); // 3. 根据PID输出驱动电机 driveMotor(Output); // 4. 演示每3秒切换一个目标角度 static unsigned long lastChange 0; if (millis() - lastChange 3000) { lastChange millis(); Setpoint (Setpoint 90.0) ? 180.0 : 90.0; // 在90度和180度之间切换 Serial.print(New Setpoint: ); Serial.println(Setpoint); } // 5. 打印调试信息可选频繁打印可能影响PID性能 static unsigned long lastPrint 0; if (millis() - lastPrint 100) { lastPrint millis(); Serial.print(Set: ); Serial.print(Setpoint); Serial.print( | Cur: ); Serial.print(Input); Serial.print( | Out: ); Serial.println(Output); } } // 函数获取当前角度度 float getCurrentAngle() { long rawAngle encoder.readAngle(); // 读取原始值 (0-4095) // 将原始值映射到角度范围 float angle map(rawAngle, RAW_MIN, RAW_MAX, ANGLE_MIN * 100, ANGLE_MAX * 100) / 100.0; return angle; } // 函数根据PID输出值驱动电机 void driveMotor(int pwm) { if (pwm 5) { // 正转死区避免微震 analogWrite(MOTOR_AIN1, pwm); digitalWrite(MOTOR_AIN2, LOW); } else if (pwm -5) { // 反转死区 digitalWrite(MOTOR_AIN1, LOW); analogWrite(MOTOR_AIN2, -pwm); // pwm为负取反 } else { brakeMotor(); // 停止 } } // 函数电机刹车停止 void brakeMotor() { digitalWrite(MOTOR_AIN1, LOW); digitalWrite(MOTOR_AIN2, LOW); }4.3 代码详解与调试角度映射getCurrentAngle()函数将AS5600的原始读数0-4095映射到你需要的角度范围如0-360度。这是校准的关键步骤确保读取的角度和实际机械角度一致。PID调参Kp, Ki, Kd是核心参数。上传代码后打开串口监视器观察“Cur”值是否跟随“Set”值。先调P将Ki和Kd设为0逐渐增大Kp直到电机开始快速震荡然后取这个值的50%-70%作为初始P。再调D增加Kd可以抑制震荡使响应更平滑。最后调I如果电机始终无法到达目标点存在静差缓慢增加Ki。调试技巧一次只调一个参数微调0.1的量级变化观察一段时间。死区设置driveMotor()函数中的5和-5是死区阈值。因为电机有启动电压当PID输出很小时不足以驱动电机反而可能引起高频噪音。设置死区可以避免这个问题。4.4 运行与验证上传代码到Arduino。打开串口监视器波特率115200。你应该看到初始化信息然后角度数据开始滚动。每隔3秒目标角度会在90和180之间切换。观察电机轴是否能够平稳、准确地转动到这两个位置并保持。用手轻轻阻挡电机轴模拟负载它应该会努力抵抗并试图回到目标位置这就是闭环控制的威力。4.5 实现“舵机”控制接口为了让我们的自制模块像标准舵机一样使用我们可以封装一个函数接收0-180度的角度指令。// 在loop()函数中替换掉定时切换目标角度的演示代码 void loop() { Input getCurrentAngle(); myPID.Compute(); driveMotor(Output); // 从串口读取指令例如 “90\n” if (Serial.available() 0) { String command Serial.readStringUntil(\n); command.trim(); float targetAngle command.toFloat(); if (targetAngle 0 targetAngle 180) { Setpoint targetAngle; Serial.println(Moving to: String(Setpoint)); } } }现在你可以在串口监视器中输入“45”、“90”、“135”等数字并回车电机轴就会像舵机一样转到对应角度。5. 常见问题与排查思路在制作过程中你可能会遇到以下问题问题现象可能原因排查思路与解决方案电机完全不动1. 电源未接通或电压不足。2. 电机驱动模块接线错误或损坏。3. 主控板未供电或程序未上传。1. 用万用表检查电机驱动模块VM和GND间电压。2. 检查AIN1/AIN2到Arduino的连线尝试用代码直接设置digitalWrite看电机是否转动。3. 检查Arduino电源指示灯。电机只朝一个方向转1. 电机驱动的一个控制通道损坏。2. PID输出限幅只为正或只为负。3. 角度反馈方向与电机转动方向不匹配。1. 交换AIN1和AIN2的接线测试。2. 检查myPID.SetOutputLimits(-255, 255)。3. 检查encoder.setDirection()或尝试在角度计算中乘以-1。电机剧烈震荡1. PID参数P值过大。2. 机械结构松动反馈不稳定。3. 电源功率不足导致供电波动。1.大幅降低P值这是最常见原因。2. 紧固所有机械连接特别是传感器与电机轴的耦合。3. 使用更大容量或更稳定的电源电机电源与逻辑电源分开。到达目标位置后有轻微抖动或嗡嗡声1. PID死区设置过小。2. I值过大导致积分饱和后的微小振荡。3. 电机驱动芯片或PWM频率不合适。1. 适当增大driveMotor()函数中的死区阈值如从5调到10。2. 稍微降低Ki值。3. 尝试改变Arduino的PWM频率高级技巧需查资料。AS5600读数不准或跳动1. 磁铁距离传感器太远或太近。2. 磁铁未对准传感器中心。3. I2C上拉电阻未启用或干扰。1. 确保磁铁与AS5600芯片表面的距离在推荐范围内通常0.5-2mm。2. 尽量使磁铁中心正对芯片中心旋转。3. Arduino的I2C引脚A4, A5内部有上拉如果线较长可外接4.7kΩ上拉电阻到3.3V。角度范围不是0-360度机械安装导致磁铁旋转范围受限。修改getCurrentAngle()函数中的RAW_MIN和RAW_MAX。用手转动电机轴到两个极限位置从串口打印encoder.readAngle()的原始值用这两个值替换RAW_MIN和RAW_MAX。6. 进阶优化与工程建议一个稳定的自制舵机系统除了能动还需要考虑可靠性、精度和易用性。6.1 提高控制精度与稳定性传感器选择AS5600是12位分辨率4096步对于360度范围理论精度约0.088度。如果需更高精度可选用14位或16位的编码器。PID采样时间myPID.SetSampleTime()不宜过短否则会引入高频噪声也不宜过长否则响应迟钝。10-50ms是常用范围。加入低通滤波对Input反馈角度进行软件滤波可以平滑读数减少突变对PID的干扰。float filteredAngle 0.9 * filteredAngle 0.1 * getCurrentAngle(); // 一阶低通滤波 Input filteredAngle;非线性死区补偿电机在低速时存在非线性。可以建立一个PWM-速度查找表使PID输出更线性。6.2 关于“电机轴能再长点就好了”这是原项目标题中的痛点也是自制舵机的优势所在方案A替换轴一些N20电机允许你拧下输出轴螺丝更换为更长的自制轴需车床加工。方案B联轴器保留原短轴使用一个小型联轴器如梅花联轴器连接一根更长的金属杆。这是最常用、最灵活的方法。方案C定制电机直接采购输出轴更长的N20电机型号。注意事项加长轴后如果末端负载较重可能增加轴承受的弯矩影响寿命。对于重负载应考虑增加轴承支撑。6.3 结构设计与安装建议刚性固定电机、编码器、延长轴必须被牢固地安装在同一个基座上任何晃动都会导致反馈失真和控制震荡。同轴度磁铁与AS5600传感器必须保持良好同轴联轴器连接也要保证两端轴的对中性否则会产生周期性误差。走线规范电机线大电流与信号线I2C、PWM尽量分开走避免干扰。可以将线缆捆扎固定。6.4 扩展应用树莓派Pico与MicroPython如果你使用树莓派Pico思路完全一致只是编程语言和库不同。MicroPython代码更简洁。# 文件main.py (用于树莓派Pico) from machine import Pin, PWM, I2C import utime from as5600 import AS5600 from pid import PID # 初始化I2C和AS5600 i2c I2C(0, sclPin(5), sdaPin(4), freq400000) encoder AS5600(i2c) # 初始化电机驱动引脚 (以两个PWM引脚模拟H桥) ain1 PWM(Pin(6)) ain2 PWM(Pin(7)) ain1.freq(1000) ain2.freq(1000) # PID初始化 pid PID(2.0, 5.0, 0.1, setpoint0.0) pid.output_limits (-65535, 65535) # Pico的PWM范围是0-65535 def drive_motor(output): if output 500: ain1.duty_u16(int(output)) ain2.duty_u16(0) elif output -500: ain1.duty_u16(0) ain2.duty_u16(int(-output)) else: ain1.duty_u16(0) ain2.duty_u16(0) while True: current_angle encoder.read_angle() # 假设返回0-360度 pid.setpoint 90.0 # 示例目标角度 control pid(current_angle) drive_motor(control) utime.sleep_ms(10)注意需要将as5600.py和pid.py的MicroPython库文件上传到Pico。7. 总结通过本文的详细拆解我们完成了一个从硬件到软件、从开环到闭环的“N20减速电机自制舵机”项目。我们不仅实现了用PWM和PID控制电机定位还深入探讨了角度反馈、参数调试、常见故障排查以及工程化优化建议。关键收获硬件是基础正确的N20电机、驱动模块和高精度角度传感器如AS5600是成功的前提。PID是灵魂理解P、I、D三个参数的作用并掌握“先P后D再I”的调试方法是让系统稳定工作的关键。系统化思维自制舵机是一个典型的机电一体化系统需要统筹考虑机械结构、电路连接、控制算法和软件实现。下一步可以探索多轴控制用多个自制舵机构建一个3D打印的机械臂。无线控制加入蓝牙如HC-05或Wi-Fi模块用手机或电脑远程控制舵机角度。轨迹规划不仅控制终点还能让舵机以指定的速度曲线平滑运动。扭矩保护通过监测电机电流在堵转时停止输出保护电机和齿轮。自制舵机的过程比直接使用成品更能让你理解伺服控制的精髓。它给予了你极大的定制自由——无论是超长的输出轴、特殊的安装尺寸还是个性化的性能参数都可以由你亲手定义。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门