135 lines
4.9 KiB
C#
135 lines
4.9 KiB
C#
|
||||
|
|
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using ClumsyCore.Interfaces;
|
|||
|
|
using ClumsyCore.Pilot;
|
|||
|
|
using CommonUsage.Chassis;
|
|||
|
|
using MDCSToolBox.Commons.Controllers;
|
|||
|
|
using MyParking.Shared;
|
|||
|
|
|
|||
|
|
namespace MultiWheelC
|
|||
|
|
{
|
|||
|
|
public class MultiWheelRotateInPlace : MovementDefinition
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 旋转目标角度
|
|||
|
|
/// </summary>
|
|||
|
|
public float AngleTarget;
|
|||
|
|
|
|||
|
|
public Func<float> ThetaReader = () => (float)DetourInterface.getCartLocation().th;
|
|||
|
|
|
|||
|
|
public MultiWheelChassis Chassis = (MultiWheelChassis)PilotDefinition.Chassis;
|
|||
|
|
|
|||
|
|
public Func<PIDParams> PidparamsRead = () => new PIDParams() { };
|
|||
|
|
|
|||
|
|
public PIDController thPid;
|
|||
|
|
|
|||
|
|
// 将本周期PID角速度输出提供给实验记录器,单位deg/s。
|
|||
|
|
public Action<float> CommandAngularSpeedObserver;
|
|||
|
|
|
|||
|
|
// 自转前舵轮实际角度允许误差,单位deg。
|
|||
|
|
public float WheelAlignmentToleranceDegrees = 2f;
|
|||
|
|
|
|||
|
|
// 自转舵轮连续保持到位的时间,单位s。
|
|||
|
|
public float WheelAlignmentStableSeconds = 0.3f;
|
|||
|
|
|
|||
|
|
// 自转舵轮准备超时时间,单位s。
|
|||
|
|
public float WheelAlignmentTimeoutSeconds = 10f;
|
|||
|
|
|
|||
|
|
// 先准备自转舵角,再通过安全版SendXYThSpeed闭环旋转到目标角度。
|
|||
|
|
public override IEnumerable<bool> Get()
|
|||
|
|
{
|
|||
|
|
if (Chassis == null)
|
|||
|
|
throw new InvalidOperationException(
|
|||
|
|
"当前底盘不是MultiWheelChassis,无法执行原地自转。");
|
|||
|
|
|
|||
|
|
var adapter = new MultiWheelChassisAdapter(
|
|||
|
|
Chassis,
|
|||
|
|
PilotDefinition.Self.CarNum);
|
|||
|
|
adapter.ResetToBodyFrame();
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var alignmentStarted = DateTime.Now;
|
|||
|
|
DateTime? alignedSince = null;
|
|||
|
|
while (true)
|
|||
|
|
{
|
|||
|
|
if (!adapter.PrepareSpin())
|
|||
|
|
throw new InvalidOperationException(
|
|||
|
|
"无法生成原地自转舵轮目标:" +
|
|||
|
|
adapter.LastFailureReason);
|
|||
|
|
|
|||
|
|
if (adapter.AreSpinWheelsAligned)
|
|||
|
|
{
|
|||
|
|
if (alignedSince == null)
|
|||
|
|
alignedSince = DateTime.Now;
|
|||
|
|
|
|||
|
|
if ((DateTime.Now - alignedSince.Value)
|
|||
|
|
.TotalSeconds >=
|
|||
|
|
WheelAlignmentStableSeconds)
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
alignedSince = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ((DateTime.Now - alignmentStarted)
|
|||
|
|
.TotalSeconds >
|
|||
|
|
WheelAlignmentTimeoutSeconds)
|
|||
|
|
throw new TimeoutException(
|
|||
|
|
"原地自转舵轮在限定时间内未稳定到位。");
|
|||
|
|
|
|||
|
|
yield return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var targetAngle =
|
|||
|
|
(float)AngleMath.NormalizeDegrees(AngleTarget);
|
|||
|
|
var p = PidparamsRead();
|
|||
|
|
thPid = new PIDController(ThetaReader, p.Kp);
|
|||
|
|
thPid.ChangeParameters(p.Kp, p.Ki, p.Kd, p.MaxI, p.DeadZone,
|
|||
|
|
p.OutputUpperThreshold, p.SpeedAccPerSec);
|
|||
|
|
var lastCommandTime = DateTime.Now;
|
|||
|
|
|
|||
|
|
while (true)
|
|||
|
|
{
|
|||
|
|
var s = thPid.GetResponse(targetAngle, true);
|
|||
|
|
Console.WriteLine($"s:{s} AngleTarget:{AngleTarget}");
|
|||
|
|
CommandAngularSpeedObserver?.Invoke(s);
|
|||
|
|
var now = DateTime.Now;
|
|||
|
|
var interval = now - lastCommandTime;
|
|||
|
|
lastCommandTime = now;
|
|||
|
|
|
|||
|
|
// PID输出s为deg/s,Shared命令统一使用rad/s。
|
|||
|
|
// adapter.Send最终调用普通安全版SendXYThSpeed。
|
|||
|
|
var omegaRadiansPerSecond =
|
|||
|
|
(float)AngleMath.DegreesToRadians(s);
|
|||
|
|
if (!adapter.Send(
|
|||
|
|
new ChassisCommand(
|
|||
|
|
PilotDefinition.Self.CarNum,
|
|||
|
|
new Twist2D(
|
|||
|
|
0.0,
|
|||
|
|
0.0,
|
|||
|
|
omegaRadiansPerSecond)),
|
|||
|
|
interval))
|
|||
|
|
{
|
|||
|
|
throw new InvalidOperationException(
|
|||
|
|
"安全XYTh原地旋转底盘解算失败:" +
|
|||
|
|
adapter.LastFailureReason);
|
|||
|
|
}
|
|||
|
|
if (thPid.IsArrived()) break;
|
|||
|
|
yield return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Console.WriteLine($"final rotate to {targetAngle}");
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
CommandAngularSpeedObserver?.Invoke(0f);
|
|||
|
|
adapter.StopImmediately();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|