// using System; // using System.Collections.Generic; // using System.Drawing; // using System.Numerics; // using ClumsyCore; // using ClumsyCore.DTools; // using ClumsyCore.Interfaces; // using ClumsyCore.Pilot; // using CommonUsage.Chassis; // using FundamentalLib; // using MDCSToolBox.Clumsy.Tracks; // using MDCSToolBox.Commons.Controllers; // using MyParking.Shared; // namespace MultiWheelC // { // // C层单车底盘:按照车轮里程行驶指定的相对距离。 // public class LineTracking : MovementDefinition // { // // 相对动作启动位置的行驶距离,单位mm。 // // 正数表示前进,负数表示后退。 // public float TargetDistance; // public float MaxSpeed = PilotDefinition.Conf.LineTrackMaxSpeed; // public float Kp = PilotDefinition.Conf.LineTrackKp; // public float Ki = PilotDefinition.Conf.LineTrackKi; // public float Kd = PilotDefinition.Conf.LineTrackKd; // public float DeadZone = PilotDefinition.Conf.LineTrackDeadZone; // public int SrcId = -1; // public int DstId = -1; // public Action LeaveSrcFunction; // // 接近目标后是否保留速度,交给下一个动作接管。 // public bool EnableHandover; // // 进入动作衔接的剩余距离,单位mm。 // public float HandoverDistance = 80f; // // HandoverSpeed小于0时,使用MaxSpeed的此比例。 // public float HandoverSpeedRatio = 0.5f; // // 大于等于0时,直接作为衔接速度,单位m/s。 // public float HandoverSpeed = -1f; // public float MinHandoverSpeed = 0.05f; // private PIDController _pid; // // 读取当前单车直线行驶里程,单位mm。 // private static float ReadPosition() // { // return // (PilotDefinition.Self.LFLActualPos + PilotDefinition.Self.LFRActualPos) / 2f; // } // // 根据动作启动位置和目标距离执行直线里程闭环。 // public override IEnumerable Get() // { // if (float.IsNaN(TargetDistance) || float.IsInfinity(TargetDistance)) // { // throw new ArgumentOutOfRangeException( // nameof(TargetDistance), // "目标行驶距离必须是有限值。"); // } // if (float.IsNaN(MaxSpeed) || float.IsInfinity(MaxSpeed) || MaxSpeed <= 0f) // { // throw new ArgumentOutOfRangeException( // nameof(MaxSpeed), // "最大速度必须是大于零的有限值。"); // } // var chassis = (MultiWheelChassis)PilotDefinition.Chassis; // // 每次启动动作时重新读取起始编码器位置。 // var startPosition = ReadPosition(); // // PID仍然控制绝对编码器位置,但绝对目标由动作自动计算。 // var targetPosition = startPosition + TargetDistance; // _pid = new PIDController(ReadPosition, Kp, Ki, Kd, 0, DeadZone, MaxSpeed) // { // SpeedAccPerSec = Math.Abs(MaxSpeed) / 2f // }; // var handoverRequested = false; // var keepHandoverSpeed = false; // DLog.Log( // $"直线里程动作:" + // $"起点={startPosition:F1}mm," + // $"距离={TargetDistance:F1}mm," + // $"目标={targetPosition:F1}mm", // "straight_line"); // try // { // while (true) // { // var currentPosition = ReadPosition(); // var remainingDistance = targetPosition - currentPosition; // // 接近目标后,保留一定速度交给后续动作。 // if (EnableHandover && Math.Abs(remainingDistance) <= Math.Max(1f, HandoverDistance)) // { // var direction = Math.Sign(remainingDistance); // if (direction == 0) // { // direction = Math.Sign(TargetDistance); // } // var requestedSpeed = HandoverSpeed >= 0f ? Math.Abs(HandoverSpeed) : Math.Abs(MaxSpeed) * HandoverSpeedRatio; // var maximumSpeed = Math.Abs(MaxSpeed); // var minimumSpeed = Math.Min(Math.Abs(MinHandoverSpeed), maximumSpeed); // var limitedSpeed = Math.Max(minimumSpeed, Math.Min(requestedSpeed, maximumSpeed)); // var handoverSpeed = limitedSpeed * direction; // chassis.SendXYThSpeed(handoverSpeed, 0f, 0f); // handoverRequested = true; // // 保持一个调度周期,让速度命令实际生效。 // yield return true; // break; // } // var speed = _pid.GetResponse(targetPosition); // chassis.SendXYThSpeed(speed, 0f, 0f); // if (_pid.IsArrived()) // { // break; // } // yield return true; // } // if (SrcId != -1 && // LeaveSrcFunction != null) // { // LeaveSrcFunction(SrcId); // DLog.Log($"释放放车点{SrcId}", "straight_line"); // } // // 只有正常完成动作衔接时才允许保留非零速度。 // keepHandoverSpeed = handoverRequested; // } // finally // { // // 普通完成、人工停止或异常退出时都必须停车。 // if (!keepHandoverSpeed) // { // chassis.SendXYThSpeed(0f, 0f, 0f); // } // } // yield return false; // } // } // //直线行走基于detour // public class LineTracking_based_detour : MovementDefinition // { // public float LineDistance = 1000f; // public int SrcId = -1; // public int DstId = -1; // public Action LeaveSrcFunction = null; // public Painter painter = UI.GetPainter("Line", false); // // C层单车轨迹:执行早期版本的两点直线跟踪动作。 // public override IEnumerable Get() // { // var curpose = DetourInterface.getCartLocation(); // Console.WriteLine($"curpose.th:{curpose.th}"); // var src = new Vector2((float)curpose.x, (float)curpose.y); // var headingRadians = // AngleMath.DegreesToRadians(curpose.th); // var dst = new Vector2( // (float)(curpose.x + // LineDistance * Math.Cos(headingRadians)), // (float)(curpose.y + // LineDistance * Math.Sin(headingRadians))); // // var dst = new Vector2((float)curpose.x + LineDistance * (float)Math.Cos(curpose.th), // // (float)curpose.y + LineDistance * (float)Math.Sin(curpose.th)); // Console.WriteLine($"src:{src.X} {src.Y}"); // Console.WriteLine($"dst:{dst.X} {dst.Y}"); // painter.DrawLine(Color.Green, src.X, src.Y, dst.X, dst.Y, width: 3); // var tracker = new ChassisController().Get(); // var linePath = new LineTrack(src, dst) { CarDirectionBias = LineDistance > 0 ? 0 : 180 }; // tracker.AddTrack(linePath); // var _dt = new DriveTask(tracker.Track()); // _dt.Wait(); // if (SrcId != -1 && LeaveSrcFunction != null) // { // LeaveSrcFunction(SrcId); // DLog.Log($"释放放车点{SrcId}", "straight_line"); // } // yield return false; // } // } // }