Arduino 步进电机驱动程序实现角度控制详解
该程序实现控制步进电机旋转角度的方法是通过将目标旋转角度转换为步数,然后调用 move 函数来启动移动。在 startMove 函数中,根据所选模式计算移动需要的步数,并根据时间计算速度和加速度。然后,根据计算得出的速度和加速度,计算出从 0 到目标速度需要的微步数和从巡航速度到完全停止需要的微步数。接下来,根据所选模式计算每个步骤的脉冲,设置方向引脚并开始移动。在移动过程中,nextAction 函数将计算下一个步骤的时间间隔,并等待该时间间隔。最后,在 rotate 函数中,通过调用 move 函数和 calcStepsForRotation 函数来启动旋转。
stepperMin(const T& a, const T& b)
{
return b < a ? b : a;
}
nextAction(void){
if (steps_remaining > 0){
delayMicros(next_action_interval, last_action_end);
/*
* DIR 引脚在上升 STEP 边沿上采样,因此首先设置它
*/
digitalWrite(dir_pin, dir_state);
digitalWrite(step_pin, HIGH);
unsigned m = micros();
unsigned long pulse = step_pulse; // 保存值,因为 calcStepPulse() 将覆盖它
calcStepPulse();
// 我们应该至少拉高 1-2us (step_high_min)
delayMicros(step_high_min);
digitalWrite(step_pin, LOW);
// 考虑到 calcStepPulse() 的执行时间; 设置较慢 MCU 的最大 rpm 的上限
last_action_end = micros();
m = last_action_end - m;
next_action_interval = (pulse > m) ? pulse - m : 1;
} else {
// 移动结束
last_action_end = 0;
next_action_interval = 0;
}
return next_action_interval;
}
startMove(long steps, long time){
float speed;
// 设置新移动
dir_state = (steps >= 0) ? HIGH : LOW;
last_action_end = 0;
steps_remaining = labs(steps);
step_count = 0;
rest = 0;
switch (profile.mode){
case LINEAR_SPEED:
// 速度以 [steps/s] 为单位
speed = rpm * motor_steps / 60;
if (time > 0){
// 计算新速度以在请求的时间内完成
float t = time / (1e+6); // 转换为秒
float d = steps_remaining / microsteps; // 转换为完整步骤
float a2 = 1.0 / profile.accel + 1.0 / profile.decel;
float sqrt_candidate = t*t - 2 * a2 * d; // 在√b^2-4ac 中
if (sqrt_candidate >= 0){
speed = stepperMin(speed, (t - (float)sqrt(sqrt_candidate)) / a2);
};
}
// 从 0 到目标速度需要多少微步
steps_to_cruise = microsteps * (speed * speed / (2 * profile.accel));
// 从巡航速度到完全停止需要多少微步
steps_to_brake = steps_to_cruise * profile.accel / profile.decel;
if (steps_remaining < steps_to_cruise + steps_to_brake){
// 无法达到最大速度,需要提前刹车
steps_to_cruise = steps_remaining * profile.decel / (profile.accel + profile.decel);
steps_to_brake = steps_remaining - steps_to_cruise;
}
// 初始脉冲 (c0),包括误差校正因子 0.676 [us]
step_pulse = (1e+6)*0.676*sqrt(2.0f/profile.accel/microsteps);
// 由于后面将不再有计算的目标速度,因此保存巡航时间
cruise_step_pulse = 1e+6 / speed / microsteps;
break;
case CONSTANT_SPEED:
default:
steps_to_cruise = 0;
steps_to_brake = 0;
step_pulse = cruise_step_pulse = STEP_PULSE(motor_steps, microsteps, rpm);
if (time > steps_remaining * step_pulse){
step_pulse = (float)time / steps_remaining;
}
}
}
long calcStepsForRotation(long deg){
return deg * motor_steps * (long)microsteps / 360;
}
move(long steps){
startMove(steps);
while (nextAction());
}
rotate(long deg){
move(calcStepsForRotation(deg));
}
原文地址: https://www.cveoy.top/t/topic/oQon 著作权归作者所有。请勿转载和采集!