Files
ParkingRobot/MultiWheelC/Fleet/FleetController.cs
T

202 lines
7.0 KiB
C#

using System;
using MultiWheelC.Control.Abstractions;
using MultiWheelC.Control.Allocation;
using MultiWheelC.Control.Execution;
using MultiWheelC.Trajectory;
using MyParking.Shared;
namespace MultiWheelC.Fleet
{
// 表示车队中心单周期轨迹控制的计算结果,不包含通信发送结果。
public enum FleetControlCycleResult
{
Inactive = 0,
CommandGenerated = 1,
Completed = 2,
Faulted = 3
}
// 将公共轨迹核心生成的GCP命令转换为车队坐标系下的刚体速度命令。
public sealed class FleetController
{
private readonly PathTrackingCore _trackingCore;
// virtualControlPointRadiusMeters必须与横向控制器采用的虚拟车队GCP半径一致。
public FleetController(
ILateralController lateralController,
ILongitudinalController longitudinalController,
GcpCommandAllocator gcpAllocator,
double virtualControlPointRadiusMeters,
double finishDistanceMeters = 0.04,
double finishSpeedMetersPerSecond = 0.02,
double finishHeadingToleranceRadians =
3.0 * Math.PI / 180.0,
double maximumDistanceToTrajectoryMeters = 0.30,
double terminalBrakingPreviewMeters = 0.02,
double terminalApproachDistanceMeters = 0.10,
double terminalApproachGainPerSecond = 0.8,
double maximumTerminalApproachSpeedMetersPerSecond = 0.05,
double curvaturePreviewSeconds = 0.20,
double maximumCurvaturePreviewMeters = 0.12)
{
NumericGuard.EnsureFinitePositive(
virtualControlPointRadiusMeters,
nameof(virtualControlPointRadiusMeters));
VirtualControlPointRadiusMeters =
virtualControlPointRadiusMeters;
_trackingCore = new PathTrackingCore(
lateralController,
longitudinalController,
gcpAllocator,
finishDistanceMeters,
finishSpeedMetersPerSecond,
finishHeadingToleranceRadians,
maximumDistanceToTrajectoryMeters,
terminalBrakingPreviewMeters,
terminalApproachDistanceMeters,
terminalApproachGainPerSecond,
maximumTerminalApproachSpeedMetersPerSecond,
curvaturePreviewSeconds,
maximumCurvaturePreviewMeters);
}
// 虚拟车队中心到前、后GCP的距离,单位为m。
public double VirtualControlPointRadiusMeters { get; }
public double FinishDistanceMeters =>
_trackingCore.FinishDistanceMeters;
public double FinishSpeedMetersPerSecond =>
_trackingCore.FinishSpeedMetersPerSecond;
public double FinishHeadingToleranceRadians =>
_trackingCore.FinishHeadingToleranceRadians;
public double MaximumDistanceToTrajectoryMeters =>
_trackingCore.MaximumDistanceToTrajectoryMeters;
public double TerminalBrakingPreviewMeters =>
_trackingCore.TerminalBrakingPreviewMeters;
public double TerminalApproachDistanceMeters =>
_trackingCore.TerminalApproachDistanceMeters;
public double TerminalApproachGainPerSecond =>
_trackingCore.TerminalApproachGainPerSecond;
public double MaximumTerminalApproachSpeedMetersPerSecond =>
_trackingCore.MaximumTerminalApproachSpeedMetersPerSecond;
public double CurvaturePreviewSeconds =>
_trackingCore.CurvaturePreviewSeconds;
public double MaximumCurvaturePreviewMeters =>
_trackingCore.MaximumCurvaturePreviewMeters;
public bool IsActive => _trackingCore.IsActive;
public bool IsCompleted => _trackingCore.IsCompleted;
public string LastFailureReason =>
_trackingCore.LastFailureReason;
public Exception LastException =>
_trackingCore.LastException;
public FleetState? LastFleetState { get; private set; }
public TrajectoryProjection? LastProjection =>
_trackingCore.LastProjection;
public GcpMotionCommand? LastGcpCommand =>
_trackingCore.LastRequestedCommand;
public FleetMotionCommand? LastCommand { get; private set; }
// 重置公共核心,并从轨迹起点开始跟踪虚拟车队中心。
public void Start(Trajectory2D trajectory)
{
_trackingCore.Start(trajectory);
LastFleetState = null;
LastCommand = null;
}
// 计算一周期车队中心命令;非运行状态、完成或故障时返回停车命令。
public FleetControlCycleResult ComputeCommand(
FleetState fleetState,
double deltaTimeSeconds,
out FleetMotionCommand command)
{
NumericGuard.EnsureFinitePositive(
deltaTimeSeconds,
nameof(deltaTimeSeconds));
command = FleetMotionCommand.Stop();
if (!_trackingCore.IsActive)
{
return FleetControlCycleResult.Inactive;
}
LastFleetState = fleetState;
var output = _trackingCore.Compute(
fleetState.FleetPoseInWorld,
fleetState.TwistAtFleetOriginInFleet,
fleetState.HasValidVelocityEstimate,
deltaTimeSeconds);
if (output.Result ==
PathTrackingCycleResult.Completed)
{
LastCommand = command;
return FleetControlCycleResult.Completed;
}
if (output.Result ==
PathTrackingCycleResult.Faulted)
{
LastCommand = command;
return FleetControlCycleResult.Faulted;
}
if (output.Result !=
PathTrackingCycleResult.CommandGenerated ||
!output.Command.HasValue)
{
return FleetControlCycleResult.Inactive;
}
try
{
var twistAtFleetOrigin =
GcpKinematics.ToBodyTwist(
output.Command.Value,
VirtualControlPointRadiusMeters);
command = new FleetMotionCommand(
Point2D.Zero,
twistAtFleetOrigin);
LastCommand = command;
return FleetControlCycleResult.CommandGenerated;
}
catch (Exception exception)
{
_trackingCore.Fail(
"车队中心GCP命令转换异常:" +
exception.Message,
exception);
LastCommand = command;
return FleetControlCycleResult.Faulted;
}
}
// 取消当前轨迹并使后续周期只生成停车命令。
public void Cancel()
{
_trackingCore.Cancel();
LastFleetState = null;
LastCommand = null;
}
}
}