我正在开发一个四轴飞行器平台,该平台将在明年扩展。该项目可以在Github上找到。当前,我们使用Arduino Uno R3作为飞行管理模块。

目前,我正在调整PID循环。 PID函数的实现方式如下:

int16_t pid_roll(int16_t roll)
{
    static int16_t roll_old = 0;
    int16_t result = 
    (KP_ROLL * roll) + 
    (KI_ROLL * (roll_old + roll)) +
    (KD_ROLL * (roll - roll_old))
    ;
    roll_old += roll;
    result = constrain(result, PID_MIN_ROLL, PID_MAX_ROLL);
    return -result;
}


我在解释有关改变常数的系统响应时遇到麻烦。我相信问题与以下问题有关。


PID控制器应该多久更新一次电机值?目前,我的更新时间约为100-110毫秒。
PID更新对电机推力的最大变化应该是多少?目前,我的最大限制约为推力范围的+ -15%。
应在什么推力范围或值下进行调整?最小值,升空或中档还是无关紧要?


评论

10Hz似乎很慢!我建议您在100Hz-1000Hz范围内进行调整。将其启动到最高可能的速度。

我不知道如何将时间缩短到20-40毫秒以下。

更快的微控制器?或者,询问问题“如何优化此PID代码?”。我在PIC18上运行了一个5kHz PID控制回路,该回路还处理CAN总线流量和EEPROM的同时写入。我敢肯定,我们可以采取一些措施来将您的循环时间缩短至少于10ms。

请参阅:robotics.stackexchange.com/questions/143/…

@Rocketmagnet在看到您的评论后,我遍历了源代码并检查了每个主要功能的执行时间。经过一些实验,时间缩短到45毫秒。同样,在45毫秒中,飞行员输入功能消耗了37 ms,这可能是由于pulseIn命令所致。除此之外,IMU正在占用7毫秒。那谢谢啦! 100 Hz也许可以实现。

#1 楼

1)我将尝试找出您的ESC可以更新的速度,并将其用作PID更新率。您当前的速率肯定太慢了(边缘性能至少需要50Hz)。

2)在最大变化量上设置阈值仅应用于处理紧急情况/意外情况。您不应该期望它是正常操作的一部分,如果在正常操作过程中出现尖峰,则意味着您需要在其他地方进行修复或降低增益。

3)随时随地调整PID需要最佳性能,这取决于您的应用程序。一种策略是针对不同情况使用不同的增益值集(例如单独的起飞增益),但是每组增益都需要分别进行调整,以增加工作量。

#2 楼

我自己编写了一个四边形,并学会了远离PulseIn函数。它基本上是在等待并不断读取该引脚。
我相信Arduino UNO有2个中断输入引脚,请尝试使用它们。对于某些接收器,如果一个接一个地发送脉冲,则可以使用OR端口,并且将脉冲组合成CPPM信号。中断处理程序不需要花费太多时间,您所需要做的就是启动并读取计时器。使用这种技术,我获得了超过200Hz的频率

#3 楼

它与电子速度控制器单元和BLDC电机的响应时间有关。在离散时间中,只有Ki和Kd具有时间变量。在稳定的系统中,如果更改采样率,则必须更改Ki和Kd才能放大它。因此,您可以反过来做。您可以仅更改Ki和Kd常数,而无需更改采样率。两者产生相同的效果。

您可以在此链接中找到PID与采样率之间的关系:http://support.motioneng.com/downloads-notes/tuning/scaling_pid_param.htm

评论


$ \ begingroup $
仅当系统可以使用当前时间步长进行控制时,才可以调整k值,对吗?例如,如果时间步长为2秒,则无法控制系统(飞行的物体)。
$ \ endgroup $
–GürkanÇetin
15年6月28日在13:03

$ \ begingroup $
不同的步长需要不同的常数。如果使用动态采样率,则可以与动态常数相乘。
$ \ endgroup $
– acs
15年6月28日在14:53

$ \ begingroup $
你是说增益常数可以是动态的吗?这不是违反直觉的吗?常量根据定义是常量,并且不会更改。或者,您是说在不同的条件下(如悬停和向前飞行),可以更改delta_t以使增益保持不变吗?您能否说说保持增益恒定并尝试提出动态delta_time有什么好处?我猜想调优是一样的,软件可能会变得更加复杂。
$ \ endgroup $
–GürkanÇetin
15年6月28日在15:30

$ \ begingroup $
PID只是一段代码。您可以在该代码中动态更改所有内容。如果系统更改了采样时间,则必须使用适当的常数进行更新。这意味着您可以响应采样时间的变化。
$ \ endgroup $
– acs
15年6月28日在17:08



$ \ begingroup $
是正确的,例如,您也可以更改Kd常数,实现相同结果的一种简单方法是将其与当前增量时间相乘。
$ \ endgroup $
–GürkanÇetin
15年6月28日在17:12



#4 楼

您的代码假定CPU以恒定时钟运行。但是,在现实生活中,它会发生变化,有时甚至会发生巨大变化!因此,需要在计算中将Delta时间(dt)因子插入KI和KD项。

ie

(KI_ROLL * (roll_old + roll) *dt) +
(KD_ROLL * (roll - roll_old) *dt)


( dt = time_now-time_previous)

顺便说一句,您的积分术语是错误的!就目前而言,这可能会破坏整个系统的稳定性。积分控制器应使用Integral_Roll_error变量,该变量是时间上的错误。例如:

Integral_Roll_error = Integral_Roll_error + roll - roll_old;


快速运行固然重要,但需要稳定的运行速度,尤其是如果您希望能够分析系统或进行测试,比较不同的控制逻辑,以添加导航算法或以后的有效载荷控制算法,等等。

回到问题:

"I am having trouble interpreting the system response on varying the constants."


详细说明遇到的有趣或遇到的困难将是有益的。在测试中添加一些响应图可能会给社区带来许多实际的帮助。

第二个问题是关于电机控制输出命令的速率限制。这在很大程度上取决于您期望的性能。该代码仅计算roll_command。如何将其转换为电动机命令是一个相关主题。通常,只要电动机加速度不造成损害,就可以使其尽可能快。

控制器的性能要求(将系统稳定地带入所需状态的速度,应该/可能超调的距离,应具有的阻尼程度)将得出所需的motor_rate_limit。例如,升空可能是性能要求之一。从站立到举起地面,如果需要30秒,是否可以接受?或如果车辆在2秒钟内倾斜60度(如果没有补偿,则升力将下降一半),您突然需要更大的升力。因此,车辆的角度敏捷性会间接影响车辆的提升敏捷性,进而影响马达的控制速度。

3) At what thrust range or values, should the tuning be performed? Minimum, lift off, or mid-range or is it irrelevant?


这很重要。在推力极限时,您将无法使已经处于最大转速的电动机加速。 (除非您永远不允许通过放弃某些性能而超出特定的total_Thrust,这是一种解决方法。)因此,必须最大程度地调节控制器的增益以及运行范围的其他一些点(向前飞行) ,悬停)。提醒:在正常飞行中,最大推力和类似的最小推力测试很难实现。

评论


$ \ begingroup $
导数项也不正确。我将更新答案。导数应乘以误差的导数,而不是误差的差。还应检查比例项。
$ \ endgroup $
–GürkanÇetin
15年6月28日在12:59

$ \ begingroup $
我刚刚找到了进一步检查的时间。只要未定义“滚动”,我对算法的理解就不完整。也许“滚动”已经是状态错误。我对正确性的评论假定“ roll”是状态变量。
$ \ endgroup $
–GürkanÇetin
15年6月28日在16:24