问题描述
我正在用 C++ 实现 PID 控制,以使差动驱动机器人转动准确的度数,但我遇到了很多问题。
由于循环运行速度快,提前退出控制循环
如果机器人测量其误差小于 0.5 度,它会退出控制循环并认为转弯“完成”(0.5 是一个随机值,我可能会在某个时候改变)。似乎控制回路运行得如此之快,以至于机器人可以以非常高的速度转动,超过设定点,并退出回路/切断电机功率,因为它是 em> 在设定点短暂停留。我知道这是 PID 控制的全部目的,即准确地达到设定值而不会超调,但是这个问题使得调整 PID 常数变得非常困难。例如,我试图找到一个 kp 值,使得有稳定的振荡,但永远不会有任何振荡,因为机器人一旦通过设定点就认为它已经“完成”了。为了解决这个问题,我实现了一个系统,机器人在退出之前必须处于设定点一段时间,这很有效,允许发生振荡,但提前退出循环的问题似乎不寻常问题,我的解决方案可能不正确。
D 项由于运行速度快而没有影响
一旦我仅使用 P 以受控方式使机器人摆动,我就尝试添加 D 以防止过冲。然而,这在大多数情况下都没有效果,因为控制循环运行得如此之快,以至于 20 个循环中有 19 个循环,误差变化率为 0:机器人没有移动或移动不够在那个时候被测量。我打印了每个循环的误差变化和导数项以确认这一点,我可以看到,在取一个合理的值之前,它们在大约 20 个循环周期中都是 0,然后在另外 20 个循环中回到 0。就像我说的那样,我认为这是因为循环周期太快了,以至于机器人实际上并没有移动到足够的位置来应对任何明显的错误变化。这是一个大问题,因为这意味着 D 项对机器人运动基本上没有影响,因为它几乎总是 0。为了解决这个问题,我尝试使用导数的最后一个非零值代替任何 0 值,但这并不奏效,如果最后一个导数不代表当前的误差变化率,机器人就会随机振荡。
注意:我还对静摩擦系数使用了一个小的前馈,我称这个前馈为“f”
我应该添加延迟吗?
我意识到我认为这两个问题的根源是循环运行得非常快,所以我想到的是在循环末尾添加一个等待语句。然而,有意减慢循环似乎是一个整体糟糕的解决方案。这是个好主意吗?
turnheading(double finalAngle,double kp,double ki,double kd,double f){
std::clock_t timer;
timer = std::clock();
double pastTime = 0;
double currentTime = ((std::clock() - timer) / (double)CLOCKS_PER_SEC);
const double initialheading = getheading();
finalAngle = angleWrapDeg(finalAngle);
const double initialAngleDiff = initialheading - finalAngle;
double error = angleDiff(getheading(),finalAngle);
double pastError = error;
double firstTimeAtSetpoint = 0;
double timeAtSetPoint = 0;
bool atSetpoint = false;
double integral = 0;
double derivative = 0;
double lastNonZeroD = 0;
while (timeAtSetPoint < .05)
{
updatePos(encoderL.read(),encoderR.read());
error = angleDiff(getheading(),finalAngle);
currentTime = ((std::clock() - timer) / (double)CLOCKS_PER_SEC);
double dt = currentTime - pastTime;
double proportional = error / fabs(initialAngleDiff);
integral += dt * ((error + pastError) / 2.0);
double derivative = (error - pastError) / dt;
//Failed METHOD OF USING LAST NON-0 VALUE OF DERIVATIVE
// if(epsilonEquals(derivative,0))
// {
// derivative = lastNonZeroD;
// }
// else
// {
// lastNonZeroD = derivative;
// }
double power = kp * proportional + ki * integral + kd * derivative;
if (power > 0)
{
setMotorPowers(-power - f,power + f);
}
else
{
setMotorPowers(-power + f,power - f);
}
if (fabs(error) < 2)
{
if (!atSetpoint)
{
atSetpoint = true;
firstTimeAtSetpoint = currentTime;
}
else //at setpoint
{
timeAtSetPoint = currentTime - firstTimeAtSetpoint;
}
}
else //no longer at setpoint
{
atSetpoint = false;
timeAtSetPoint = 0;
}
pastTime = currentTime;
pastError = error;
}
setMotorPowers(0,0);
}
turnheading(90,.37,.00004,.12);
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)