我在线遇到了一些代码,其中为arduino实现了PID。我对实施感到困惑。我对PID的工作原理有基本的了解,但是我的困惑是为什么十六进制用于m_prevError?值0x80000000L代表什么?为什么在计算速度时右移10?
// ServoLoop Constructor
ServoLoop::ServoLoop(int32_t proportionalGain, int32_t derivativeGain)
{
m_pos = RCS_CENTER_POS;
m_proportionalGain = proportionalGain;
m_derivativeGain = derivativeGain;
m_prevError = 0x80000000L;
}
// ServoLoop Update
// Calculates new output based on the measured
// error and the current state.
void ServoLoop::update(int32_t error)
{
long int velocity;
char buf[32];
if (m_prevError!=0x80000000)
{
velocity = (error*m_proportionalGain + (error - m_prevError)*m_derivativeGain)>>10;
m_pos += velocity;
if (m_pos>RCS_MAX_POS)
{
m_pos = RCS_MAX_POS;
}
else if (m_pos<RCS_MIN_POS)
{
m_pos = RCS_MIN_POS;
}
}
m_prevError = error;
}
答案 0 :(得分:0)
将二进制数右移1表示将其对应的十进制值乘以2。此处,将10移位表示乘以2 ^ 10(即1024)。作为任何基本控制回路,它可以是速度的增益,返回值将转换为适合通过任何其他方法重复使用的值。
这里L
的{{1}}将该值声明为0x80000000L
。因此,该值long
可能是error的初始值。另外,您需要修改整个程序,以查看工作原理以及为0x80000000
之类的东西分配什么值。
答案 1 :(得分:0)
与其他答案相反,向右移动具有除以2的幂的作用,在这种情况下,>> 10
将除以1024。但是,真实的除法会更好,更清晰和最优化反正由编译器移动。所以我发现这种转变很丑。
目的是在不实际使用浮点数的情况下实现一些浮点数学运算-这是一种定点计算,其中小数部分约为10位。要理解,假设简化导数系数= 0,将m_proportionalGain设置为1024将意味着1,而如果将其设置为512将意味着0.5。实际上,在比例= 1024且误差= 100的情况下,公式将给出
100*1024 / 1024 = 100
(gain = 1),而比例= 512会给出
100*512 / 1024 = 50
(增益= 0.5)。
至于先前的错误m_prevError
设置为0x80000000,它只是一个特殊值,在循环中检查该值以查看“是否已经”存在先前的错误。如果不是,即prevError具有特殊值,则整个循环将被跳过一次;否则,整个循环将被跳过。换句话说,其目的是在创建对象之后跳过第一次更新。我想不是很聪明,我宁愿简单地将先前的错误设置为0并完全跳过:: update()中的检查。使用特殊值作为标志存在一个问题,即有时计算会导致特殊值本身-这将是一个大错误。如果绝对需要,最好使用true标志。
总的来说,我认为这是一个较差的PID算法,因为它完全缺少集成部分。似乎变量m_pos
是出于此综合目的而考虑的,它是通过这种方式进行管理的,但从未使用过-仅设置。尽管如此,该算法仍然可以工作,但都取决于目标系统和所需的性能:在大多数情况下,该算法会留下残余错误。