自定义Arduino库中Servo对象导致舵机抖动的故障排查
首先,你的核心问题出在全局对象构造函数的执行时机上,这是Arduino开发中很容易踩的坑!
为什么会抖动?
Arduino的程序执行流程是这样的:
- 先初始化全局变量(包括你定义的
servo1、servo2这些ServoSweep对象) - 然后才会调用
setup()函数 - 最后进入
loop()
而你在ServoSweep的构造函数里直接调用了servo.attach()和servo.write()——这时候Arduino的硬件(比如定时器、引脚输出)还没完成初始化,Servo库根本没法正确生成稳定的PWM信号给舵机。这种情况下舵机收到的是混乱的脉冲,自然会出现严重抖动,哪怕你注释掉loop()里的代码也没用,因为构造函数已经在硬件就绪前搞砸了信号输出。
另外还有个小问题:你的timeToRun成员变量没有初始化,第一次调用sweep()时它是个随机值,可能会导致第一次位置更新的时机异常,不过这不是抖动的主因。
修复步骤
1. 添加begin()方法,延迟硬件初始化
给你的ServoSweep类加一个专门的初始化方法,把构造函数里的硬件操作移到这里,这样你可以在setup()里调用它——这时候硬件已经完全就绪了。
修改头文件,在public部分添加:
void begin();
修改源文件的构造函数,去掉attach和write相关代码:
ServoSweep::ServoSweep( byte _servoPin, byte _min, byte _max, byte _speed ) { servoPin = _servoPin ; servoSpeed = _speed ; servoMin = _min ; servoMax = _max ; middlePosition = ( (long)servoMax - (long)servoMin ) / (long)2 + (long)servoMin ; pos = middlePosition ; // 移除这两行:servo.write( pos ) ; servo.attach( servoPin ) ; relayPresent = 0; // 别忘了初始化这个变量! timeToRun = millis(); // 初始化时间变量 } ServoSweep::ServoSweep( byte _servoPin, byte _min, byte _max, byte _speed, byte _relayPin ) { servoPin = _servoPin ; servoSpeed = _speed ; servoMin = _min ; servoMax = _max ; middlePosition = ( (long)servoMax - (long)servoMin ) / (long)2 + (long)servoMin ; pos = middlePosition ; // 移除这两行:servo.write( pos ) ; servo.attach( servoPin ) ; relayPresent = 1; relayPin = _relayPin ; // 这里也别在构造函数里调用pinMode,移到begin() timeToRun = millis(); // 初始化时间变量 }
然后实现begin()方法:
void ServoSweep::begin() { servo.attach(servoPin); servo.write(pos); if (relayPresent == 1) { pinMode(relayPin, OUTPUT); // 初始化继电器状态 digitalWrite(relayPin, pos >= middlePosition ? HIGH : LOW); } }
2. 在测试代码的setup()里调用begin()
修改你的测试示例:
void setup() { pinMode( inputButton, INPUT_PULLUP ) ; // 在这里初始化舵机对象 servo1.begin(); servo2.begin(); }
3. 可选:检查引脚兼容性
确认你用的引脚在你的Arduino板上支持Servo库——比如Uno的数字2、3是没问题的,但如果是其他板(比如Mega),有些引脚的定时器可能被其他功能占用,导致Servo信号不稳定。不过从你的代码看,这个不是主要问题,但可以排查一下。
为什么这样改有用?
setup()是Arduino官方规定的硬件初始化入口,当执行到setup()时,所有底层硬件(定时器、GPIO、串口等)都已经完成初始化,这时候调用servo.attach()才能让Servo库正确配置PWM信号,输出稳定的脉冲给舵机,自然就不会抖动了。
内容的提问来源于stack exchange,提问作者bask185

