Тема перекочевала отсюда.
В моем приводе это вопрос позиционирования встал ребром. По началу я не считал эту задачу сложной, но теперь понял, что все не так просто...
Застабилизировать скорость, когда вал должен просто вращаться, оказалось делом не сложным. PI регулятор работает.
Но вот вопрос позиционирования раскусить не могу... то, что смог реализовать работает с затухающими колебаниями относительно точки, в которую приводу нужно уйти.
Привожу код, который сможет пояснить суть алгоритма. Но общий принцип такой: берется рассогласованиее по координатам, которое домножается на некоторой коэффициент posTolPGain (пропорциональная часть), получаем скорость, на которой приказываем приводу двигаться. По мере приближения к заданной точке, рассогласование будет уменьшаться, пока не достигнет того минимума, при котором привод останавливается. Остается некоторая ошибка. Эта ошибка (ее величина определяется переменной posTolerance), компенсируется следующей ступенью пропорционального регулятора, у которого коэффициент posTolPGain1, который много больше, чем posTolPGain, в силу малости ошибки. Перввая ступень регулятора работает великолепно, но всегда остается ошибка. Вторая ступень дает колебания. Будут ли они затухающими, или нет, зависит от posTolPGain1, но они есть всегда... Мне не приходит идея, что делать? Использовать еще и интегральную составляющую для устранения ошибки позиционирования? Но это уже будет целых два ПИ-регулятора со своими коэффициентами... многовато их получается... Есть ли какие-нибудь идей у уважаемых профессионалов? Спасибо!
Да, датчик обратной связи - энкодер. Больше ничего нет..., и добалять нельзя. Привода аппаратно готов и какой бы ущербный он не был, придется придумывать, как реализовать позиционирование на энкодере.
Код
/*
This function must be called every 5 ms in Position Mode
IN:
pos - desired position
OUT:
servo result codes
*/
uint8_t TServoControl::positionModeProcess(int16_t pos)
{
int32_t pos_tolerance = pos - getPosition();
int32_t dp = pos_tolerance;
if(dp < 0)
dp*= -1L;
if(dp > posTolerance)
{
int32_t vel = ((pos - getPosition()) * posTolPGain) / 128L;
if(vel > 0)
{
if(vel > velocityLimit)
vel = velocityLimit;
}
else
if(vel < 0)
{
if(vel < -velocityLimit)
vel = -velocityLimit;
}
velocityModeProcess(vel);
}
else
{
int16_t s_pwm = pos_tolerance * posTolPGain1 / 128L;
if(s_pwm > 0)
setServoMode(SERVO_POS_VELOCITY_MODE);
else
if(s_pwm < 0)
{
setServoMode(SERVO_NEG_VELOCITY_MODE);
s_pwm*= -1;
}
if(s_pwm > 250L)
s_pwm = 250;
if(s_pwm)
setPWM((uint8_t)s_pwm);
else
setServoMode(SERVO_FAST_STOP_MODE);
}
return SERVO_OK_RESULT;
}
This function must be called every 5 ms in Position Mode
IN:
pos - desired position
OUT:
servo result codes
*/
uint8_t TServoControl::positionModeProcess(int16_t pos)
{
int32_t pos_tolerance = pos - getPosition();
int32_t dp = pos_tolerance;
if(dp < 0)
dp*= -1L;
if(dp > posTolerance)
{
int32_t vel = ((pos - getPosition()) * posTolPGain) / 128L;
if(vel > 0)
{
if(vel > velocityLimit)
vel = velocityLimit;
}
else
if(vel < 0)
{
if(vel < -velocityLimit)
vel = -velocityLimit;
}
velocityModeProcess(vel);
}
else
{
int16_t s_pwm = pos_tolerance * posTolPGain1 / 128L;
if(s_pwm > 0)
setServoMode(SERVO_POS_VELOCITY_MODE);
else
if(s_pwm < 0)
{
setServoMode(SERVO_NEG_VELOCITY_MODE);
s_pwm*= -1;
}
if(s_pwm > 250L)
s_pwm = 250;
if(s_pwm)
setPWM((uint8_t)s_pwm);
else
setServoMode(SERVO_FAST_STOP_MODE);
}
return SERVO_OK_RESULT;
}
Требования не высокие: нужно просто перемещаться из текущей точки в заданную. Ускорение и максимальная скорость, до которой разгоняемя - задаются. Погрешность допустима.. ну сколько, даже не знаю как выразить. Ну вал двигателя может провернуться или не довернуться процентов на 20 - 40 от того значения, которое соответсвует заданной координате. Извините за доморощенные термины. Ну вот, пока вроде все.