SG90舵机与电位器联动控制:从模拟输入到PWM输出的完整实践
发布时间:2026/9/24 13:24:01 作者:尧图编辑部 阅读量:1,286

1. 项目缘起与整体设计思路1.1 为什么选择SG90加电位器这个组合SG90这颗微型舵机在创客圈里的地位大概相当于编程入门时的Hello World。它便宜、体积小、扭矩够用最关键的是驱动逻辑极其简单——一根PWM信号线就能控制角度。而电位器作为最基础的模拟输入器件输出的是一个连续变化的电压值正好可以映射成舵机的角度指令。两者凑在一起就构成了一个手动角度控制器的最小闭环系统。我最初做这个项目是为了给一个桌面机械臂做关节调试。机械臂上每个关节都用SG90但我不想每次都改代码来测试角度范围于是接了一个电位器上去转动旋钮就能实时看到舵机转到对应位置。这个思路后来被我用在了很多场景里云台方向微调、摄像头俯仰角控制、甚至给小朋友做的一个旋钮控制小旗子升降的玩具。从技术角度看这个项目的核心就两件事模拟信号的采集和PWM信号的生成。电位器负责前者单片机负责中间的计算和映射SG90负责执行。整个链路清晰、可调试、可扩展非常适合用来理解模拟输入到执行器输出的完整流程。1.2 系统架构与信号流拆解整个系统的信号流可以这样理解电位器的中间抽头输出一个0到VCC之间的电压单片机的ADC模块把这个电压转换成数字值比如0到1023或0到4095然后通过map()函数把这个范围映射到舵机的角度范围0到180度最后单片机用PWM模块输出对应占空比的方波SG90内部的比较电路解析这个方波驱动电机转到指定角度。这里有一个容易被忽略的细节SG90的PWM周期是20ms对应50Hz的频率。脉宽在0.5ms到2.5ms之间对应0到180度。也就是说1.5ms的脉宽对应90度中位。这个参数是SG90的行业通用标准但不同批次的舵机可能存在微小偏差后面我会详细讲怎么校准。从选型角度来说单片机可以用Arduino Uno、ESP32、STM32甚至树莓派Pico。Arduino Uno的优势是库生态成熟Servo.h库一行代码就能驱动ESP32的优势是ADC分辨率更高12位且自带WiFi可以做远程控制扩展。如果你手头只有STM32那就需要自己配置定时器输出PWM稍微麻烦一点但更灵活。注意SG90的工作电压标称是4.8V到6V但实际测试下来5V供电时扭矩表现最好。如果用3.3V供电舵机会出现抖动甚至无法转动的情况。这一点在ESP32项目里特别容易踩坑因为ESP32的GPIO是3.3V电平虽然信号线能识别但舵机电源必须单独接5V。2. 核心细节解析与实操要点2.1 SG90舵机的内部原理与驱动要求SG90内部结构其实不复杂一个直流电机、一组减速齿轮、一个电位器用来反馈当前角度、一块控制小板。控制小板上的芯片负责比较外部PWM信号和内部电位器的反馈电压然后驱动电机正转或反转直到两者一致。这就是为什么舵机能知道自己转到了哪里——它内部也有一个电位器在做闭环反馈。这个原理决定了几个实操要点。第一舵机上电时会有一个找中位的动作如果你在上电瞬间强行掰动舵机臂容易打坏齿轮。第二舵机的PWM信号不能中断太久否则内部电路会失去参考舵机会乱转。第三堵转是大忌当舵机被外力卡住时电机会持续大电流工作几分钟内就能烧毁。SG90的扭矩大约是1.8kg·cm5V供电时这个数值意味着它只能带动很轻的负载。我试过用它直接驱动一个塑料小手臂长度超过10cm时就已经很吃力了。所以如果你要做机械臂建议每个关节都加弹簧辅助或者用金属齿轮舵机替代。2.2 电位器的选型与接线细节电位器我推荐用10kΩ的线性电位器B型不要用对数型A型。线性电位器的阻值变化和旋转角度成正比映射到角度控制上更直观。对数型是给音频音量设计的用在角度控制上会出现前一半行程只控制10度后一半行程控制170度的尴尬情况。接线方面电位器的三个引脚分别是一端接VCC、一端接GND、中间抽头接单片机的ADC引脚。这里有个小技巧在中间抽头和GND之间并联一个0.1μF的电容可以滤掉旋转时的抖动噪声。我最早做的时候没加这个电容舵机会跟着手抖一起抖加了之后明显平稳很多。另外电位器的旋转角度通常是270度或300度而舵机只有180度。这意味着电位器的整个行程里只有一部分能对应到舵机的有效角度。你可以在代码里做映射也可以机械上限位。我一般选择在代码里映射因为这样更灵活换电位器时不用改结构。2.3 单片机ADC与PWM的资源分配以Arduino Uno为例ADC是10位分辨率也就是0到1023。PWM方面Servo.h库会占用一个定时器Uno上最多可以同时驱动12个舵机但实际项目中超过6个就会出现抖动因为定时器中断太频繁了。如果你用ESP32ADC是12位0到4095但要注意ESP32的ADC2在WiFi开启时不可用所以建议用ADC1的引脚GPIO32到GPIO39。PWM方面ESP32有LEDC模块可以独立配置频率和分辨率比Arduino灵活得多。STM32的话我一般用TIM2或TIM3的通道来输出PWM配置预分频器和自动重装载值来得到50Hz。具体计算如果系统时钟是72MHz预分频器设为72-1自动重装载值设为20000-1那么PWM频率就是72MHz / 72 / 20000 50Hz。然后改变比较寄存器的值就能改变脉宽。提示无论用哪个平台舵机电源和单片机电源最好分开供电。SG90在启动瞬间的电流可以达到500mA以上如果和单片机共用一路电源容易导致单片机复位。我通常用一块5V 2A的电源模块单独给舵机供电单片机的5V从USB取电两者共地即可。3. 完整实操过程与核心环节实现3.1 硬件清单与接线方案先列一下我这次用的硬件清单元件型号/规格数量备注单片机Arduino Uno R31也可以用ESP32或STM32舵机SG9019g微型舵机电位器10kΩ B型1线性电位器电容0.1μF1滤除ADC噪声电源模块5V 2A1单独给舵机供电面包板830孔1方便接线杜邦线公对公/公对母若干建议用不同颜色区分接线方案如下电位器左脚接5V右脚接GND中间脚接A0同时中间脚和GND之间接0.1μF电容。SG90棕色线接GND红色线接5V电源模块的正极橙色线接D9。电源模块输入端接外部电源输出端5V接舵机红线GND和Arduino的GND连在一起。这里要特别强调共地的问题。我见过太多人舵机不转最后发现是电源模块的GND没有和Arduino的GND连在一起。没有共地PWM信号就没有参考电平舵机自然不工作。3.2 代码实现与参数映射先上Arduino的完整代码#include Servo.h Servo myServo; const int potPin A0; const int servoPin 9; int potValue 0; int angle 0; void setup() { myServo.attach(servoPin); Serial.begin(9600); } void loop() { potValue analogRead(potPin); angle map(potValue, 0, 1023, 0, 180); myServo.write(angle); Serial.print(Pot: ); Serial.print(potValue); Serial.print( Angle: ); Serial.println(angle); delay(15); }这段代码的逻辑很直白读A0的值映射到0到180写给舵机。delay(15)是为了让舵机有时间转到位置同时也降低了循环频率避免PWM信号更新太快导致舵机抖动。但实际调试时你会发现一个问题电位器转到两端时舵机会发出滋滋的声音。这是因为映射后的角度超出了舵机的机械限位舵机在试图转到不存在的角度。解决办法是在代码里把映射范围缩小一点比如map(potValue, 0, 1023, 5, 175)给两端留一点余量。如果你用ESP32代码需要调整#include ESP32Servo.h Servo myServo; const int potPin 34; const int servoPin 18; void setup() { myServo.attach(servoPin, 500, 2500); Serial.begin(115200); } void loop() { int potValue analogRead(potPin); int angle map(potValue, 0, 4095, 0, 180); myServo.write(angle); Serial.printf(Pot: %d Angle: %d\n, potValue, angle); delay(15); }注意ESP32的attach()函数可以指定脉宽范围默认是500到2400微秒我改成500到2500是为了覆盖SG90的完整行程。另外ESP32的ADC引脚建议用34、35、36、39这几个它们是输入专用引脚不受其他功能干扰。3.3 校准与调试的实操记录第一次上电时不要急着把舵机臂装上去。先让舵机转到90度位置然后再把舵机臂对准机械结构的中间位置装上去。这样做的原因是舵机上电时的初始位置是随机的如果你先装好臂再上电舵机会强行转到中位可能带动机械结构卡死。校准的具体步骤上传代码但先不接舵机臂。打开串口监视器观察电位器读数和角度值。把电位器转到中间位置确认角度显示在90度左右。如果偏差超过5度调整代码里的映射范围。确认无误后断电装上舵机臂再上电测试。我在调试时还遇到过一个现象舵机在某个角度附近会快速抖动。排查后发现是电位器在那个位置接触不良输出电压跳变。换了一个质量好一点的电位器就解决了。所以如果你买的是几毛钱的电位器出现抖动时先怀疑电位器本身。注意调试时如果发现舵机发热严重立即断电。正常工作的SG90只有微微温热如果烫手说明堵转或PWM信号异常。4. 常见问题与排查技巧实录4.1 舵机不转或只往一个方向转这是最常见的问题我整理了一个排查表现象可能原因排查方法解决方案舵机完全不转电源未接或电压不足万用表测舵机红线电压确保5V供电电流能力≥1A舵机完全不转信号线接错引脚检查代码中的servoPin确认接的是PWM引脚舵机只往一个方向转电位器接线错误测中间脚电压是否随旋转变化重新接线确保VCC和GND正确舵机只往一个方向转映射范围错误串口打印角度值检查map()函数的参数舵机抖动不转PWM频率不对示波器测信号频率确保50Hz脉宽0.5-2.5ms舵机抖动不转电源干扰单独供电测试舵机电源和单片机电源分开我印象最深的一次是帮一个朋友排查他的舵机死活不转代码换了三遍都没用。最后发现是他把电位器的VCC和GND接反了导致中间脚电压一直是0V映射出来的角度一直是0度。所以接线这种基础工作一定要反复确认。4.2 角度控制不线性或跳变电位器是线性器件但实际使用中可能会出现转一点没反应再转一点跳很多的情况。原因通常有三个一是用了对数型电位器二是ADC参考电压不稳定三是电位器质量差导致接触电阻变化不均匀。解决办法首先确认电位器型号是B型。其次在代码里加一个滑动平均滤波连续读5次ADC值取平均可以有效平滑跳变。代码片段如下int readPotSmooth() { int sum 0; for (int i 0; i 5; i) { sum analogRead(potPin); delay(2); } return sum / 5; }这个滤波方法我用了很多年简单有效。代价是响应速度稍微慢一点但对于手动控制来说完全够用。4.3 舵机发出异响或发热异响通常来自两个地方一是齿轮打滑二是舵机在极限位置堵转。齿轮打滑的声音是咔咔的堵转的声音是嗡嗡的。如果是齿轮打滑检查舵机臂是否装得太紧或者负载太大。如果是堵转检查映射范围是否超出了0到180度。发热问题前面提过正常工作的SG90只有微温。如果烫手立即断电检查。我烧过两个SG90都是因为堵转没及时发现。后来我养成了一个习惯调试时用手轻轻摸着舵机外壳一旦感觉温度异常就断电。4.4 电源相关的隐蔽问题电源问题是最隐蔽的因为万用表测电压正常但舵机一动作就复位。这是因为万用表测的是平均电压而舵机启动瞬间的电流冲击会导致电压瞬间跌落。解决办法是用示波器看电压波形或者直接换一个电流能力更大的电源。我的经验是SG90的电源电流能力至少要是标称值的2倍。标称500mA那就用1A以上的电源。如果多个舵机同时工作每个舵机按500mA计算再留50%余量。比如3个舵机就需要3×500mA×1.52.25A选3A的电源比较稳妥。提示如果你用电池供电注意电池的内阻。9V方块电池的内阻很大驱动舵机会导致电压跌落不建议使用。我用过4节AA电池6V供电效果不错但续航只有几十分钟。5. 扩展玩法与进阶思路5.1 多舵机同步控制一个电位器控制一个舵机是最基础的玩法。如果你想用一个电位器控制多个舵机同步动作只需要在代码里多定义几个Servo对象然后写入相同的角度值即可。但要注意电源的电流能力以及PWM引脚的分配。Arduino Uno上Servo.h库会占用Timer1影响D9和D10的PWM输出。如果你同时用D9和D10接舵机会发现其中一个不工作。解决办法是换用其他引脚比如D3、D5、D6、D11。这个坑我踩过当时以为是舵机坏了换了好几个才找到原因。5.2 加入LCD显示当前角度给系统加一个1602 LCD或者OLED屏幕实时显示电位器读数和舵机角度调试起来会方便很多。我用的是0.96寸OLEDI2C接口只占两个引脚。代码里加几行显示逻辑就行这里不展开网上例程很多。5.3 用舵机做角度记录与回放如果你想记录一系列角度然后回放可以在代码里加一个按钮按下时把当前角度存入数组再按另一个按钮回放。这个玩法可以用来做简单的机械臂示教虽然精度不高但胜在简单直观。5.4 换成其他传感器电位器只是模拟输入的一种。你可以把电位器换成光敏电阻、热敏电阻、弯曲传感器甚至超声波测距模块把不同的物理量映射成角度。比如用超声波测距控制舵机转动距离越近角度越大就是一个简单的避障扫描头。我在实际项目中用过弯曲传感器做手势控制手指弯曲程度控制舵机角度效果挺有意思。但弯曲传感器的线性度不如电位器需要做分段校准。6. 个人实操心得与避坑清单做了这么多次SG90加电位器的项目我总结了几条血泪教训列出来供你参考先供电再信号接线时先接电源线确认电压正常后再接信号线。反过来容易在插拔过程中造成短路。共地是底线任何涉及外部电源的项目GND必须共地。我至少见过五次因为没共地导致的问题。映射留余量不要映射到0和180的极限值留5度余量舵机寿命会明显延长。滤波不能省ADC读数加滑动平均成本几乎为零效果立竿见影。调试先空载装上机械结构之前先空载测试舵机行程确认无误再装配。电源要独立舵机电源和单片机电源分开共地即可。这是最省心的方案。发热即断电舵机烫手说明有问题不要抱有侥幸心理继续跑。备件要充足SG90便宜多买几个备用。烧了直接换不耽误项目进度。最后分享一个我常用的调试技巧在代码里加一个串口命令输入角度值直接控制舵机不用转电位器。这样在校准机械结构时特别方便。代码很简单在loop()里加一段Serial.parseInt()的判断就行。这个项目虽然简单但它是理解模拟输入-数字处理-执行输出这条链路的最佳入口。把SG90和电位器玩透了后面换更复杂的传感器和执行器思路是一样的。我后来做机械臂、云台、机器人关节底层逻辑都没离开这个框架。