using System; using MultiWheelC.Control.Abstractions; using MultiWheelC.Control.Common; namespace MultiWheelC.Control.Longitudinal { /// /// 将轨迹参考速度前馈与通用PID速度反馈组合为有符号底盘命令速度。 /// public sealed class PidLongitudinalController : ILongitudinalController { private const double ReferenceStopDeadbandMetersPerSecond = 1e-6; private readonly PidController _feedbackPid; /// /// 创建具有积分抗饱和和命令速度限幅的纵向速度外环。 /// public PidLongitudinalController( double proportionalGain, double integralGainPerSecond, double derivativeGainSeconds, double maximumIntegralCorrectionMetersPerSecond, double maximumCommandSpeedMetersPerSecond, double speedErrorDeadbandMetersPerSecond = 0.025) { EnsureFinitePositive( maximumCommandSpeedMetersPerSecond, nameof(maximumCommandSpeedMetersPerSecond)); EnsureFiniteNonNegative( speedErrorDeadbandMetersPerSecond, nameof(speedErrorDeadbandMetersPerSecond)); _feedbackPid = new PidController( proportionalGain, integralGainPerSecond, derivativeGainSeconds, maximumIntegralCorrectionMetersPerSecond, derivativeOnMeasurement: true); MaximumCommandSpeedMetersPerSecond = maximumCommandSpeedMetersPerSecond; SpeedErrorDeadbandMetersPerSecond = speedErrorDeadbandMetersPerSecond; } /// /// 获取负责计算速度误差修正量的通用PID控制器。 /// public PidController FeedbackPid => _feedbackPid; /// /// 获取底盘命令速度的最大绝对值,单位为m/s。 /// public double MaximumCommandSpeedMetersPerSecond { get; } /// /// 获取不触发纵向PID修正的速度误差死区,单位为m/s。 /// public double SpeedErrorDeadbandMetersPerSecond { get; } /// /// 获取最近一次有效控制周期的参考速度减实际速度,单位为m/s。 /// public double LastSpeedErrorMetersPerSecond => _feedbackPid.LastError; /// /// 获取最近一次比例项产生的速度修正,单位为m/s。 /// public double LastProportionalCorrectionMetersPerSecond => _feedbackPid.LastProportionalOutput; /// /// 获取最近一次积分项产生的速度修正,单位为m/s。 /// public double LastIntegralCorrectionMetersPerSecond => _feedbackPid.LastIntegralOutput; /// /// 获取最近一次微分项产生的速度修正,单位为m/s。 /// public double LastDerivativeCorrectionMetersPerSecond => _feedbackPid.LastDerivativeOutput; /// /// 根据轨迹参考速度和Detour实际纵向速度计算底盘命令速度。 /// public double ComputeSpeedMetersPerSecond( PathTrackingContext context) { var referenceSpeedMetersPerSecond = context.ReferenceSpeedMetersPerSecond; // 轨迹明确要求停车时直接输出零,防止速度反馈使车辆在终点反向纠偏。 if (Math.Abs(referenceSpeedMetersPerSecond) <= ReferenceStopDeadbandMetersPerSecond) { Reset(); return 0.0; } // 定位速度尚不可用时只透传参考速度,不使用无效反馈更新PID状态。 if (!context.HasValidVelocityEstimate) { Reset(); return LimitReferenceSpeed( referenceSpeedMetersPerSecond); } var speedErrorMetersPerSecond = referenceSpeedMetersPerSecond - context.ActualLongitudinalSpeedMetersPerSecond; // Detour差分速度在参考速度附近会有小幅波动;死区内只使用速度前馈, // 同时清除PID历史,避免噪声持续积累后产生突发修正。 if (Math.Abs(speedErrorMetersPerSecond) <= SpeedErrorDeadbandMetersPerSecond) { Reset(); return LimitReferenceSpeed( referenceSpeedMetersPerSecond); } GetCorrectionOutputRange( referenceSpeedMetersPerSecond, out var minimumCorrectionMetersPerSecond, out var maximumCorrectionMetersPerSecond); var correctionMetersPerSecond = _feedbackPid.Update( referenceSpeedMetersPerSecond, context .ActualLongitudinalSpeedMetersPerSecond, context.DeltaTimeSeconds, minimumCorrectionMetersPerSecond, maximumCorrectionMetersPerSecond); return referenceSpeedMetersPerSecond + correctionMetersPerSecond; } /// /// 清除纵向速度外环的积分、历史测量值和诊断输出。 /// public void Reset() { _feedbackPid.Reset(); } /// /// 根据参考行驶方向计算PID修正量允许使用的动态输出范围。 /// private void GetCorrectionOutputRange( double referenceSpeedMetersPerSecond, out double minimumCorrectionMetersPerSecond, out double maximumCorrectionMetersPerSecond) { if (referenceSpeedMetersPerSecond > 0.0) { minimumCorrectionMetersPerSecond = -referenceSpeedMetersPerSecond; maximumCorrectionMetersPerSecond = MaximumCommandSpeedMetersPerSecond - referenceSpeedMetersPerSecond; return; } minimumCorrectionMetersPerSecond = -MaximumCommandSpeedMetersPerSecond - referenceSpeedMetersPerSecond; maximumCorrectionMetersPerSecond = -referenceSpeedMetersPerSecond; } /// /// 在没有有效速度反馈时限制参考速度的绝对值。 /// private double LimitReferenceSpeed( double referenceSpeedMetersPerSecond) { return Math.Max( -MaximumCommandSpeedMetersPerSecond, Math.Min( MaximumCommandSpeedMetersPerSecond, referenceSpeedMetersPerSecond)); } /// /// 检查最大命令速度是否为正有限值。 /// private static void EnsureFinitePositive( double value, string parameterName) { if (double.IsNaN(value) || double.IsInfinity(value) || value <= 0.0) { throw new ArgumentOutOfRangeException( parameterName, "纵向控制器最大命令速度必须是正有限值。"); } } /// /// 检查速度误差死区是否为非负有限值。 /// private static void EnsureFiniteNonNegative( double value, string parameterName) { if (double.IsNaN(value) || double.IsInfinity(value) || value < 0.0) { throw new ArgumentOutOfRangeException( parameterName, "纵向控制器速度误差死区必须是非负有限值。"); } } } }