news 2026/9/24 13:23:52

SG90舵机与电位器联动控制:从模拟输入到PWM输出的完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SG90舵机与电位器联动控制:从模拟输入到PWM输出的完整实践

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·cm(5V供电时),这个数值意味着它只能带动很轻的负载。我试过用它直接驱动一个塑料小手臂,长度超过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个就会出现抖动,因为定时器中断太频繁了。

如果你用ESP32,ADC是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度位置,然后再把舵机臂对准机械结构的中间位置装上去。这样做的原因是:舵机上电时的初始位置是随机的,如果你先装好臂再上电,舵机会强行转到中位,可能带动机械结构卡死。

校准的具体步骤:

  1. 上传代码,但先不接舵机臂。
  2. 打开串口监视器,观察电位器读数和角度值。
  3. 把电位器转到中间位置,确认角度显示在90度左右。
  4. 如果偏差超过5度,调整代码里的映射范围。
  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.5=2.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寸OLED,I2C接口,只占两个引脚。代码里加几行显示逻辑就行,这里不展开,网上例程很多。

5.3 用舵机做角度记录与回放

如果你想记录一系列角度然后回放,可以在代码里加一个按钮,按下时把当前角度存入数组,再按另一个按钮回放。这个玩法可以用来做简单的机械臂示教,虽然精度不高,但胜在简单直观。

5.4 换成其他传感器

电位器只是模拟输入的一种。你可以把电位器换成光敏电阻、热敏电阻、弯曲传感器,甚至超声波测距模块,把不同的物理量映射成角度。比如用超声波测距控制舵机转动,距离越近角度越大,就是一个简单的避障扫描头。

我在实际项目中用过弯曲传感器做手势控制,手指弯曲程度控制舵机角度,效果挺有意思。但弯曲传感器的线性度不如电位器,需要做分段校准。

6. 个人实操心得与避坑清单

做了这么多次SG90加电位器的项目,我总结了几条"血泪教训",列出来供你参考:

  • 先供电,再信号:接线时先接电源线,确认电压正常后再接信号线。反过来容易在插拔过程中造成短路。
  • 共地是底线:任何涉及外部电源的项目,GND必须共地。我至少见过五次因为没共地导致的问题。
  • 映射留余量:不要映射到0和180的极限值,留5度余量,舵机寿命会明显延长。
  • 滤波不能省:ADC读数加滑动平均,成本几乎为零,效果立竿见影。
  • 调试先空载:装上机械结构之前,先空载测试舵机行程,确认无误再装配。
  • 电源要独立:舵机电源和单片机电源分开,共地即可。这是最省心的方案。
  • 发热即断电:舵机烫手说明有问题,不要抱有侥幸心理继续跑。
  • 备件要充足:SG90便宜,多买几个备用。烧了直接换,不耽误项目进度。

最后分享一个我常用的调试技巧:在代码里加一个串口命令,输入角度值直接控制舵机,不用转电位器。这样在校准机械结构时特别方便。代码很简单,在loop()里加一段Serial.parseInt()的判断就行。

这个项目虽然简单,但它是理解"模拟输入-数字处理-执行输出"这条链路的最佳入口。把SG90和电位器玩透了,后面换更复杂的传感器和执行器,思路是一样的。我后来做机械臂、云台、机器人关节,底层逻辑都没离开这个框架。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 13:21:44

FlutterFlow上架App Store完全指南:从代码导出到审核通过

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/24 13:21:39

DIC的精度到底能到什么水平

精度是选购DIC系统时问得最多的问题&#xff0c;但这个问题本身需要拆开来看。DIC测量涉及多个环节的精度&#xff1a;空间分辨率&#xff08;能分辨多小的变形区域&#xff09;、位移测量精度&#xff08;测量位移值的准确度&#xff09;、应变测量精度&#xff08;应变值与真…

作者头像 李华
网站建设 2026/9/24 13:21:30

晶振选型实战:负载电容、温漂与老化三重精度控制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/24 13:21:22

主板驱动必须从官网下载的底层逻辑与实操指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/24 13:18:40

零极点如何影响频响:从s平面到实测曲线的工程直觉

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/24 13:16:59

B站音画不同步全解析:从解码到投屏的排查与解决

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华