过调处理,PID控制器,瞄准辅助MkIII

文中视频度盘:http://pan.baidu.com/s/1dE6mZuh
 
 
 
加入积分的term后,steady error问题解决,但是依然无法准确瞄准Predictor,下图所示,视频见:Unity 2016-03-24 19-04-12-41_加入积分后依然无法命中Predictor.avi
值得注意的是,虽然没有命中Predictor,但是误差已经小到物理模拟的子弹实际可以打到飞机了
不过现在这个误差在距离远了以后命中率依然很糟糕,必须解决
 
误差为下图红箭头
红色射线是射出的子弹射线判定
红色球是预期射线应该命中的HitBoxPredictor
 

为了解决这个误差,现在想到的方案有:
  • Error和ErrorD足够小时,直接作弊旋转飞机
  • Error和ErrorD足够小时,作弊扭枪
  • 让玩家自己输入来修正——模仿War Thunder,玩家可以通过输入修正瞄准辅助的目标瞄准位置。向输入方向是累加输入的delta,累加结果作为目标瞄准偏移,就像下图所示
 
玩家x轴方向输入0.5,此时按下开枪键,瞄准辅助选择了目标109K的左翼作为自动瞄准的目标部位,用红色叉子表示
因为刚刚按下,瞄准输入修正值为0
 
用户发现以这个结果来说overshoot了,于是将向右的输入降低到0.4。我们判定出来同上次输入相差 -0.1,于是将瞄准输入修正设为-0.1,此时瞄准辅助PID的目标瞄准位置为下图绿箭头所示
HUD上可以考虑把这个信息显示出来,以便供玩家调整和调试

 
 
关于累积错误的清零
但是没明白这里的delay time是什么意思
 
其他的参考文章:
 
 

3月31日。通过改为直接使用相差角度(pyMeToPredictor)作为Error,而不是idealInputVector后,强烈的ErrorD抖动已经解决,而且不是特别容易overshoot了

效果见视频:
 
Unity 2016-03-31 17-16-27-93_Lag_P0.45_D0.1_I0
Unity 2016-03-31 17-14-20-33_Lead_P0.45_D0.1_I0

现在有两个问题:
  • 接近目标后依然有轻微的ErrorD抖动,需要个Low-pass Filter处理下——Unity 2016-03-31 17-31-20-95_Shake_P0.45_D0.1_I0
  • 重战、滚转率低的飞机一直无法击中目标,因为它的滚转能力差,且没有I Term,导致始终无法追上目标——Unity 2016-03-31 17-44-32-41_Me410_P0.45_D0.1_I0
 

Low-pass Filter

这两面提到了两个值得注意的内容:
  • 一种叫做Set Point Filters的过滤方式
  • 对PV(Error)进行过滤会引发Overshoot(因为过滤意味着数据延迟)
 
另外找到的一个比较简单的方法:
 
一个复杂的方法:
 
关于PID信号过滤的更深入的讨论论文:
 
Butterwork Filter的源代码,同时这篇文章提到了3种常见Low-pass filter: Butterworth, Chebyshev, and elliptical
 
最后选择了这个RC low-pass filter的方法,不出意料的提升了overshoot的程度 囧

3月31日加入了低通滤波后成功减弱了抖动

Unity 2016-03-31 21-11-21-87_LowPassFilter_P0.45_D0.1_I0
 
调整了下参数,把P提升了下,让飞机能够贴的更近一点
Unity 2016-03-31 22-14-08-14_LagTooLong_P0.5_D0.15_I0
 
但是遗留个问题,需要明天处理——lag时追上去的速度太慢了,明天尝试加入I term
 
4月1日,发现可以不用I term也能解决steady error的问题
 
这里的资料提到,我们需要一个CObias的数值,如下文所示:

The P-Only Algorithm
The P-Only controller computes a CO action every loop sample time T as:

  CO = CObias + Kc∙e(t)

  Where:
CObias = controller bias or null value
Kc = controller gain, a tuning parameter
e(t) = controller error = SP – PV
SP = set point
PV = measured process variable


 
 
这个CObias的作用是解决P only的控制器永远无法到达目标的问题,看下面文字中举的控制引擎速度的例子,和我们现在要追到目标,且维持角速度其实解决的是一个问题!
 

Understanding Controller Bias
Let’s suppose the P-Only control algorithm shown above is used for cruise control in an automobile and CO is the throttle signal adjusting the flow of fuel to the engine.

Let’s also suppose that the speed SP is 70 and the measured PV is also 70 (units can be mph or kph depending on where you live in the world). Since PV = SP, then e(t) = 0 and the algorithm reduces to:

  CO = CObias + Kc∙(0) = CObias

If CObias is zero, then when set point equals measurement, the above equation says that the throttle signal, CO, is also zero. This makes no sense. Clearly if the car is traveling 70 kph, then some baseline flow of fuel is going to the engine.

This baseline value of the CO is called the bias or null value. In this example, CObias is the flow of fuel that, in manual mode, causes the car to travel the design speed of 70 kph when on flat ground on a calm day.

Definition: CObias is the value of the CO that, in manual mode, causes the PV to steady at the DLO while the major disturbances are quiet and at their normal or expected values.

A P-Only controller bias (sometimes called null value) is assigned a value as part of the controller design and remains fixed once the controller is put in automatic.

CObias实现之后效果拔群,如下图和视频"Unity 2016-04-01 15-55-59-69_CObias_P0.45_D0.1_I0_RC0.1"中所示
  • OError(未经低通滤波的错误)始终维持在0.1以下,多数时间在0.01以下
 

发现了新问题:虽然error已经很低,但是机头依然没有对准HitBoxPredictor(可以看到上图计数中的FireAt仅为38)

从Scene视图可以看出,瞄准的位置靠前了(大约1帧?),说明给PID控制器传的参数不对
 
 
没错。。。可以看到用作弊方式恰好可以击中目标时,OError的值是0.7~1.0。。。感觉好像提前了一帧似得
 
想到问题了,因为现在的执行顺序是
  • FixedUpdate
    • 场景中的所有飞机更新位移,自机以外的所有飞机更新旋转
    • osPlayer._FixedUpdateAfterOSPlane——更新osPlaneController_Player._AimAssist的状态
  • LateUpdate
    • osPlaneController_Player.UpdateInput
      • osPlane.SetAimAssist
      • 读取自己和敌人飞机的空间信息,计算Error等Feedback数据
      • PID控制器根据Feedback数据计算Output
      • 自己的飞机根据Output更新旋转
    • osMachineGun
      • 子弹射出
 
设计成这个执行顺序原本目的是让瞄准辅助可以明确控制本帧开枪时机头的朝向,但是在换成PID控制器后引发了个问题:
  • 按照原本的设计,即使飞机每帧在射击时机头都对准了目标,Error也不应该为0。这是因为计算Error是发生在修正逻辑的前面
  • 但是PID控制器的特点是消除错误,所以就持续overshoot了。。。
那么改动的方法是:
 
  • FixedUpdate
    • 场景中的所有飞机更新位移,自机以外的所有飞机更新旋转
    • osPlayer._FixedUpdateAfterOSPlane——更新osPlaneController_Player._AimAssist的状态
  • LateUpdate
    • osPlaneController_Player.UpdateInput
      • osPlane.SetAimAssist
      • PID控制器根据Feedback数据计算Output
      • 自己的飞机根据Output更新旋转
      • 读取自己和敌人飞机的空间信息,计算Error等Feedback数据
    • osMachineGun
      • 子弹射出

4月6日,失速引起抖动,视频:Unity 2016-04-06 17-18-17-09_失速引起抖动

其他的视频:
Unity 2016-04-08 17-16-59-25_瞄准辅助开启关闭时抖动_第28帧瞄准辅助关闭时飞机少旋转了一帧_45帧多转了一些,怀疑是瞄准辅助和旋转共同起效
 
从前面的流程图就可以看出,瞄准辅助的开启、关闭发生在osPlane.FixedUpdate后,所以瞄准辅助启动的本帧飞机已经进行过旋转更新,如果这帧就执行瞄准辅助逻辑,那就意味着多旋转了一帧
 
最后通过加入以下逻辑修正了这个BUG:
  • 瞄准辅助启动时多旋转:revision 36967,修改osPlaneController_Player.UpdateAimAssist方法,只有前一帧瞄准辅助是起效的,才执行瞄准辅助的物理模拟。
  • 瞄准辅助关闭时少旋转:revision 36991,在osPlaneController_Player.LateUpdate改成如果上帧苗猪辅助是启动状态,那么本帧依然执行UpdateAimAssist方法,以便让瞄准辅助的物理模拟起效
 
最终效果见视频:“Unity 2016-04-09 13-55-58-52_解决了瞄准辅助启动时多旋转的问题和关闭时少旋转的问题”

 

4月13日,加入延迟射击后,第一枪总是会先开出一枪

 
  • FixedUpdate
    • 场景中的所有飞机更新位移,自机以外的所有飞机更新旋转
    • osPlayer._FixedUpdateAfterOSPlane——更新osPlaneController_Player._AimAssist的状态
  • Update
    • osPlane.Update——将osPlaneController的开枪状态更新给osMachineGun
  • LateUpdate
    • osPlaneController.LateUpdate->osPlaneController_Player.UpdateInput
      • osPlane.SetAimAssist
      • PID控制器根据Feedback数据计算Output
      • 自己的飞机根据Output更新旋转
      • 读取自己和敌人飞机的空间信息,计算Error等Feedback数据
    • osMachineGun.LateUpdate
      • 子弹射出
 
现在问题是osPlayer._FixedUpdateAfterOSPlane启动瞄准辅助是在FixedUpdate中执行,而阻止开火的逻辑在osPlaneController_Player.UpdateInput中执行,所以不一定每次都能在武器发射子弹前阻止发射
 
osPlane.Update_Frame: 5180, m_Fire: NotFire, m_HoldFireByAimAssist: False, _AimAssistOn: False
Controller.UpdateInput_Frame: 5180, m_Fire: NotFire, m_HoldFireByAimAssist: False, _AimAssistOn: False
osPlane.Update_Frame: 5181, m_Fire: NotFire, m_HoldFireByAimAssist: False, _AimAssistOn: False
Controller.UpdateInput_Frame: 5181, m_Fire: FireAllGun, m_HoldFireByAimAssist: False, _AimAssistOn: False
osPlane.Update_Frame: 5182, m_Fire: FireAllGun, m_HoldFireByAimAssist: True, _AimAssistOn: True
Controller.UpdateInput_Frame: 5182, m_Fire: NotFire, m_HoldFireByAimAssist: True, _AimAssistOn: True
osPlane.Update_Frame: 5183, m_Fire: NotFire, m_HoldFireByAimAssist: True, _AimAssistOn: True
Controller.UpdateInput_Frame: 5183, m_Fire: NotFire, m_HoldFireByAimAssist: True, _AimAssistOn: True
 
 
改造后
 
  • FixedUpdate
    • 场景中的所有飞机更新位移,自机以外的所有飞机更新旋转
  • Update
    • osPlane.Update——将osPlaneController的开枪状态更新给osMachineGun
  • LateUpdate
    • osPlayer.LateUpdate——更新osPlaneController_Player._AimAssist的状态
    • osPlaneController.LateUpdate->osPlaneController_Player.UpdateInput
      • osPlane.SetAimAssist
      • PID控制器根据Feedback数据计算Output
      • 自己的飞机根据Output更新旋转
      • 读取自己和敌人飞机的空间信息,计算Error等Feedback数据
    • osMachineGun.LateUpdate
      • 子弹射出
 
 





附件列表

 

posted on 2016-12-17 16:23  MobileFish  阅读(887)  评论(0编辑  收藏  举报

导航