电机推子 PID 控制

电器工程 Arduino 控制系统 电机控制器 pid控制器
2022-01-11 21:59:35

我正在尝试使用 Arduino 控制电动推子(线性滑动电位器)。
PID 控制为“跳跃”到特定目标位置提供了良好的结果,但跟踪斜坡是一个问题,它根本不平滑。无论我尝试什么,运动都非常生涩。

这是跟踪斜坡时参考位置、测量位置和电机输出的图: 跟踪坡道

这是同一测试的视频

在商业系统上,它似乎更流畅,请参阅this

详细信息
电动推子是Alps RSA0N11M9A0K为了驱动它,我使用的是ST L293D H 桥,由稳压 10 V 直流电源 ( XL6009 ) 供电。
在 Arduino UNO (ATmega328P) 上,我使用引脚 9 和 10,PWM 频率为 31.372 kHz 以使其听不见(预分频器为 1 的 Timer1,TCCR1B = (TCCR1B & 0b11111000) | 0b001)。
电位器连接在地和 5V 之间,抽头像往常一样连接到 ADC0。

控制器
我正在使用一个带有抗饱和的简单 PID 控制器,它以 1 kHz (Ts = 1e-3 s) 的速率更新:

float update(int16_t input) {
  int16_t error = setpoint - input;
  int16_t newIntegral = integral + error;
  float output = k_p * error 
               + k_i * newIntegral * Ts 
               + k_d * (input - previousInput) / Ts;

  if (output > maxOutput)
    output = maxOutput;
  else if (output < -maxOutput)
    output = -maxOutput;
  else
    integral = newIntegral;

  previousInput = input;
  return output;
}

控制器的输出是一个从 -127 到 127 的值。PWM 输出产生如下:

const int8_t knee = 48;

uint8_t activation(int8_t val) {
  if (val == 0)
    return 0;
  else {
    return map(val, 0, 127, 2 * knee, 255);
  }
}

void writeMotor(int8_t val) {
  if (val >= 0) {
    analogWrite(forward, activation(val));
    digitalWrite(backward, 0);
  } else {
    analogWrite(backward, activation(-val));
    digitalWrite(forward, 0);
  }
}

我将 48 添加到 7 位 PWM 信号,因为这是电机开始以 31 kHz 移动的地方,然后我将其放大到 8 位数字(因为这是analogWrite函数所期望的): PWM速度

我尝试过的:
我尝试将 EMA 滤波器添加到输入、控制信号、PID 控制器的微分组件,但无济于事。我还尝试降低模拟输入的分辨率,使用滞后来阻止它在静止时在两个值之间翻转。这似乎不影响任何事情。将时间步长增加到 10 毫秒似乎也无济于事。

我还尝试在 MATLAB 中进行系统识别,并尝试在 Simulink 中对其进行调整(按照此视频系列)。我得到了一个拟合度为 91% 的模型,但我不知道如何处理 MATLAB 模型的输入和输出非线性,它们如何影响 PID 调整,以及如何在 Arduino 上实现它。

我尝试的最后一件事是制作两种不同的控制器:一种用于参考位置的大跳跃,另一种用于跟踪斜坡时的小误差。这似乎有点帮助,因为这样我可以在跟踪时增加积分系数,而不会增加跳跃时的超调。
然而,通过增加积分(和比例)增益,电机现在总是在做一些事情,即使它应该是静止的并且参考值不会改变。(它并没有真正移动,但你可以感觉到它在振动。)
我几乎没有微分增益,因为将它增加到高于 1e-4 似乎会使它更加抖动,而且我并没有真正注意到 0 和1e-4。

我的猜测是它需要更多的动力来克服静摩擦,然后动摩擦就更少,所以它会过冲,所以它会向后驱动电机,导致它再次停止,然后它必须再次克服静摩擦,它再次向前冲, 等等。

商业控制器如何克服这个问题?

我的背景
我在电气工程专业的第三个学士年,我学习了控制理论、数字信号处理、LQR 控制等课程,所以我有一些理论背景,但我无法将所有这些理论应用于这个真实世界的系统。


编辑
我已经按照laptop2d 的建议测试了开环传感器测量值,我对结果感到非常惊讶:在高PWM 频率下,读数中有令人讨厌的峰值。在 490 Hz 时,没有。
这是在一个恒定的占空比下,所以我无法想象当电机快速反转方向时我会得到什么样的噪音。

在此处输入图像描述

所以在我再次开始使用控制器之前,我必须找到一种方法来过滤掉这些噪音。

编辑 2
使用指数移动平均滤波器不足以滤除噪声。

EMA

我尝试过使用 0.25、0.50 和 0.75 的极点。小极点影响不大,大极点增加了太多延迟,所以我不得不降低增益以保持稳定,导致整体性能更差。

我在电位器(雨刮器和地之间)添加了一个 0.1 µF 电容器,这似乎可以清理它。

目前,它运行良好。与此同时,我正在阅读Tim Wescott 发表的论文
感谢大家的帮助。

4个回答

控制系统与传感器一样好,运行传感器开环并移除控制输入。创建您自己的传感器输入并缓慢滑动它(或找到一种可靠地缓慢滑动它的方法),同时获取位置数据以确保它不是传感器。如果传感器有噪声,则通过获取新传感器或将其并联,或通过过滤传感器的输出来提高传感器的性能。您可能需要分辨率更高的传感器。

如果传感器没有噪音,那么您需要获得不同的控制回路。PID 是一阶系统,在速率控制方面并不出色。

您是正确的,问题出在摩擦,或者可能是摩擦和反弹的结合。您绘制的各种脉冲宽度的平均速度与占空比的关系图是具有摩擦的系统的特征。 本文解释了您所看到的内容,并提供了一份自古以来一直用于解决问题的解决方案概要。你不会在你的工程课程中看到它们,因为它们很难分析;您基本上必须根据具体情况摆弄它们才能使它们正常工作。

我不知道商业控制器做什么,虽然我怀疑那里有各种各样的解决方案。我过去做过这样的事情是,当来自我的 PID 控制器的电机驱动信号低于某个阈值(在你的情况下可能是 60 到 70 个计数)时,我开始在阈值处脉冲电机驱动,有责任使平均驱动等于 PID 输出的循环。我通常为此使用 sigma-delta-ish 调制器,因为它可以用很少的几行代码实现,但你可以选择适合你的任何东西。

似乎大部分噪声来自 PWM 驱动信号。

您是否尝试过将 ADC 捕获与 PWM 周期同步?大多数微控制器都有在定时器上触发 ADC 捕获的方法,因此您始终可以在周期的同一点触发。

为了获得最低的噪音,最佳的采样位置应该是在打开电机电源之前,因为这样任何尖峰都有最长的时间稳定下来。但无论在什么位置,同步捕获都会减少尖峰,因为偏移量在 PWM 周期的同一点将保持大致相同。

所以在我再次开始使用控制器之前,我必须找到一种方法来过滤掉这些噪音。

您可以使用以下代码过滤传感器噪声(或任何其他噪声测量/变量)(低通滤波):

$$S_{\text{filtered}}[k] = \alpha \cdot S_{\text{filtered}}[k-1] + (1-\alpha)\cdot S_{\text{raw}}[k ]$$

其中\$0<<\alpha \leq 1\$越接近 1,看起来越平滑,但它也会增加更多的延迟,例如,从值 0.9 开始,看看它的表现如何。