feat(flyshot): 引入飞拍执行侧最终发送队列构建与校验机制

* 新增 FlyshotExecutionSendSequenceBuilder,负责在运行时前构建最终 8ms 发送队列,并进行离散限幅校验。
* 引入 FlyshotPreparedExecution 类,封装最终发送结果及相关诊断信息。
* 调整 ControllerClientCompatService 和 FanucControllerRuntime,确保运行时直接使用预生成的发送队列,避免临场重采样。
* 更新 TrajectoryResult 和 PlannedExecutionBundle,支持准备好的执行队列。
* 增加单元测试,验证非 1 倍 speedRatio 下的执行行为与预生成队列的使用。
This commit is contained in:
2026-05-09 19:06:49 +08:00
parent f7e2bb0e7b
commit 74761bb5da
11 changed files with 1185 additions and 75 deletions

View File

@@ -1,5 +1,6 @@
using Flyshot.Core.Config;
using Flyshot.Core.Domain;
using Flyshot.Core.Planning.Sampling;
using Flyshot.Runtime.Common;
using Microsoft.Extensions.Logging;
@@ -492,6 +493,7 @@ public sealed class ControllerClientCompatService : IControllerClientCompatServi
// 已上传飞拍轨迹必须按调用方指定 method 生成 shot timeline 后再交给运行时。
var settings = RequireRobotSettings();
var bundle = _trajectoryOrchestrator.PlanUploadedFlyshot(robot, trajectory, options, settings, settings.PlanningSpeedScale);
bundle = PrepareFlyshotExecutionBundle(robot, bundle, _runtime.GetSnapshot().SpeedRatio);
ExportFlyshotArtifactsIfRequested(name, options.SaveTrajectory, robot, bundle);
_logger?.LogInformation(
"ExecuteTrajectoryByName 规划完成: name={Name}, method={Method}, 时长={Duration}s, 触发事件数={TriggerCount}, 使用缓存={UsedCache}, planningSpeedScale={PlanningSpeedScale}",
@@ -621,6 +623,7 @@ public sealed class ControllerClientCompatService : IControllerClientCompatServi
new FlyshotExecutionOptions(useCache:false,saveTrajectory: true, method: method),
planningSettings,
planningSettings.PlanningSpeedScale);
bundle = PrepareFlyshotExecutionBundle(robot, bundle, _runtime.GetSnapshot().SpeedRatio);
_logger?.LogInformation("SaveTrajectoryInfo 规划完成记录到本地");
ExportFlyshotArtifactsIfRequested(name, saveTrajectory: true, robot, bundle);
@@ -658,6 +661,7 @@ public sealed class ControllerClientCompatService : IControllerClientCompatServi
new FlyshotExecutionOptions(method: method, saveTrajectory: saveTrajectory),
planningSettings,
planningSettings.PlanningSpeedScale);
bundle = PrepareFlyshotExecutionBundle(robot, bundle, _runtime.GetSnapshot().SpeedRatio);
ExportFlyshotArtifactsIfRequested(name, saveTrajectory, robot, bundle);
duration = bundle.Result.Duration;
@@ -794,6 +798,37 @@ public sealed class ControllerClientCompatService : IControllerClientCompatServi
_artifactWriter.WriteUploadedFlyshot(name, robot, bundle, speedRatio);
}
/// <summary>
/// 为飞拍链路预先构建最终发送队列,确保运行时只消费已经离散校验通过的 8ms 点列。
/// </summary>
private static PlannedExecutionBundle PrepareFlyshotExecutionBundle(
RobotProfile robot,
PlannedExecutionBundle bundle,
double speedRatio)
{
var preparedExecution = FlyshotExecutionSendSequenceBuilder.Build(
robot,
bundle.Result,
robot.ServoPeriod.TotalSeconds,
speedRatio);
var preparedResult = new TrajectoryResult(
programName: bundle.Result.ProgramName,
method: bundle.Result.Method,
isValid: bundle.Result.IsValid,
duration: bundle.Result.Duration,
shotEvents: bundle.Result.ShotEvents,
triggerTimeline: bundle.Result.TriggerTimeline,
artifacts: bundle.Result.Artifacts,
failureReason: bundle.Result.FailureReason,
usedCache: bundle.Result.UsedCache,
originalWaypointCount: bundle.Result.OriginalWaypointCount,
plannedWaypointCount: bundle.Result.PlannedWaypointCount,
triggerSampleIndexOffsetCycles: bundle.Result.TriggerSampleIndexOffsetCycles,
denseJointTrajectory: bundle.Result.DenseJointTrajectory,
preparedFlyshotExecution: preparedExecution);
return new PlannedExecutionBundle(bundle.PlannedTrajectory, bundle.ShotTimeline, preparedResult, preparedExecution);
}
/// <summary>
/// 尝试从配置根目录加载 RobotConfig.json 获取机器人配置;失败时返回 null。
/// </summary>