伺服电机无法持续转动问题排查及代码优化需求
问题根源
原代码里的degrees数组是全局变量,但Move_motor函数接收的degree是传值参数——也就是说函数里修改的只是这个参数的副本,根本没更新全局的degrees数组。所以每次loop执行时,电机的度数还是初始的0,只能动一次5度,下一次循环又从0开始,看起来就像只转了瞬间就停了。另外,四次重复调用Move_motor完全可以用循环简化,避免冗余代码。
修复后的完整代码
#include <Adafruit_PWMServoDriver.h> #include <Wire.h> Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); const int MOTOR_COUNT = 4; int motors[] = {0, 1, 2, 3}; int degrees[] = {0, 0, 0, 0}; void setup() { Serial.begin(9600); pwm.begin(); pwm.setPWMFreq(50); pwm.setOscillatorFrequency(27000000); // 初始化所有16个通道到0度位置 for(int i=0; i<16; i++){ pwm.setPWM(i, 0, 150); } Serial.setTimeout(10); } // 单个电机的步进控制,直接操作全局degrees数组 void Move_motor(int motorIndex, int int_val){ int ¤tDegree = degrees[motorIndex]; // 引用全局数组的对应元素 int motorPin = motors[motorIndex]; if(int_val <= 1){ currentDegree += 5; if(currentDegree > 180) currentDegree = 180; int pul = map(currentDegree, 0, 180, 150, 600); pwm.setPWM(motorPin, 0, pul); } else if(int_val >= 4){ currentDegree -= 5; if(currentDegree < 0) currentDegree = 0; int pul = map(currentDegree, 0, 180, 150, 600); pwm.setPWM(motorPin, 0, pul); } // 中间值(int_val=2或3)对应操纵杆松开,电机停止 } void loop() { int analogPin[MOTOR_COUNT]; int int_Pin[MOTOR_COUNT]; // 批量读取操纵杆值并转换 for(int i=0; i<MOTOR_COUNT; i++){ analogPin[i] = analogRead(A0 + i); // 依次读取A0到A3引脚 int_Pin[i] = map(analogPin[i], 0, 1023, 0, 5); } // 循环控制所有电机,替代四次重复调用 for(int i=0; i<MOTOR_COUNT; i++){ Move_motor(i, int_Pin[i]); } // 打印调试信息 for(int j=0; j<MOTOR_COUNT; j++){ Serial.print(int_Pin[j]); Serial.print(" "); } Serial.println(""); // 可选:控制电机转动速度,可根据需求调整延迟时间 delay(50); }
关键修改说明
- 修复度数更新问题:让
Move_motor接收电机索引,直接引用全局的degrees数组元素,确保每次步进的度数能被保存,下次循环从当前度数继续转动。 - 简化冗余代码:用
MOTOR_COUNT常量统一管理电机数量,读取引脚、控制电机都用循环,避免重复写四次调用代码。 - 优化引脚读取逻辑:通过
A0 + i直接遍历A0到A3引脚,代码更简洁。 - 调整初始化通道数:原代码初始化15个通道,驱动板实际是16通道,修正为
i<16更准确。 - 增加速度控制:loop里的
delay(50)可以减缓电机步进速度,避免卡顿,可根据实际需求调整。
现在操纵杆保持拨动时,电机会持续步进转动直到极限位置;松开操纵杆时,电机停止在当前位置。
内容的提问来源于stack exchange,提问作者user16975087
相关产品推荐
相关产品推荐

