Files
ParkingRobot/MultiWheelC/Control/Longitudinal/PidLongitudinalController.cs
T

183 lines
6.4 KiB
C#

using System;
using MultiWheelC.Control.Abstractions;
using MultiWheelC.Control.Common;
namespace MultiWheelC.Control.Longitudinal
{
/// <summary>
/// 将轨迹参考速度前馈与通用PID速度反馈组合为有符号底盘命令速度。
/// </summary>
public sealed class PidLongitudinalController
: ILongitudinalController
{
private const double ReferenceStopDeadbandMetersPerSecond =
1e-6;
private readonly PidController _feedbackPid;
/// <summary>
/// 创建具有积分抗饱和和命令速度限幅的纵向速度外环。
/// </summary>
public PidLongitudinalController(
double proportionalGain,
double integralGainPerSecond,
double derivativeGainSeconds,
double maximumIntegralCorrectionMetersPerSecond,
double maximumCommandSpeedMetersPerSecond)
{
EnsureFinitePositive(
maximumCommandSpeedMetersPerSecond,
nameof(maximumCommandSpeedMetersPerSecond));
_feedbackPid = new PidController(
proportionalGain,
integralGainPerSecond,
derivativeGainSeconds,
maximumIntegralCorrectionMetersPerSecond,
derivativeOnMeasurement: true);
MaximumCommandSpeedMetersPerSecond =
maximumCommandSpeedMetersPerSecond;
}
/// <summary>
/// 获取负责计算速度误差修正量的通用PID控制器。
/// </summary>
public PidController FeedbackPid => _feedbackPid;
/// <summary>
/// 获取底盘命令速度的最大绝对值,单位为m/s。
/// </summary>
public double MaximumCommandSpeedMetersPerSecond { get; }
/// <summary>
/// 获取最近一次有效控制周期的参考速度减实际速度,单位为m/s。
/// </summary>
public double LastSpeedErrorMetersPerSecond =>
_feedbackPid.LastError;
/// <summary>
/// 获取最近一次比例项产生的速度修正,单位为m/s。
/// </summary>
public double LastProportionalCorrectionMetersPerSecond =>
_feedbackPid.LastProportionalOutput;
/// <summary>
/// 获取最近一次积分项产生的速度修正,单位为m/s。
/// </summary>
public double LastIntegralCorrectionMetersPerSecond =>
_feedbackPid.LastIntegralOutput;
/// <summary>
/// 获取最近一次微分项产生的速度修正,单位为m/s。
/// </summary>
public double LastDerivativeCorrectionMetersPerSecond =>
_feedbackPid.LastDerivativeOutput;
/// <summary>
/// 根据轨迹参考速度和Detour实际纵向速度计算底盘命令速度。
/// </summary>
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);
}
GetCorrectionOutputRange(
referenceSpeedMetersPerSecond,
out var minimumCorrectionMetersPerSecond,
out var maximumCorrectionMetersPerSecond);
var correctionMetersPerSecond =
_feedbackPid.Update(
referenceSpeedMetersPerSecond,
context
.ActualLongitudinalSpeedMetersPerSecond,
context.DeltaTimeSeconds,
minimumCorrectionMetersPerSecond,
maximumCorrectionMetersPerSecond);
return referenceSpeedMetersPerSecond +
correctionMetersPerSecond;
}
/// <summary>
/// 清除纵向速度外环的积分、历史测量值和诊断输出。
/// </summary>
public void Reset()
{
_feedbackPid.Reset();
}
/// <summary>
/// 根据参考行驶方向计算PID修正量允许使用的动态输出范围。
/// </summary>
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;
}
/// <summary>
/// 在没有有效速度反馈时限制参考速度的绝对值。
/// </summary>
private double LimitReferenceSpeed(
double referenceSpeedMetersPerSecond)
{
return Math.Max(
-MaximumCommandSpeedMetersPerSecond,
Math.Min(
MaximumCommandSpeedMetersPerSecond,
referenceSpeedMetersPerSecond));
}
/// <summary>
/// 检查最大命令速度是否为正有限值。
/// </summary>
private static void EnsureFinitePositive(
double value,
string parameterName)
{
if (double.IsNaN(value) ||
double.IsInfinity(value) ||
value <= 0.0)
{
throw new ArgumentOutOfRangeException(
parameterName,
"纵向控制器最大命令速度必须是正有限值。");
}
}
}
}