feat(*): 添加轨迹产物导出与规划速度倍率隔离

* 新增 FlyshotTrajectoryArtifactWriter,支持 saveTrajectory
  将规划结果导出到 Config/Data/name(JointTraj、CartTraj、
  ShotEvents 等)
* RobotConfig 新增 PlanningSpeedScale,区分规划阶段限速倍率
  与运行时 J519 下发倍率
* 轨迹缓存键纳入 planningSpeedScale,避免降速规划误用缓存
* 完善 FanucCommandClient 命令参数日志与状态通道重连
* 补充 RuntimeOrchestrationTests 覆盖产物导出与倍率隔离
* 更新 README 进度文档
This commit is contained in:
2026-04-30 13:52:09 +08:00
parent a6579f1e5b
commit 91c1494cde
20 changed files with 593 additions and 133 deletions

View File

@@ -1,5 +1,6 @@
using System.Text.Json;
using Flyshot.Core.Domain;
using Microsoft.Extensions.Logging;
namespace Flyshot.Core.Config;
@@ -17,7 +18,8 @@ public sealed class CompatibilityRobotSettings
int ioKeepCycles,
double accLimitScale,
double jerkLimitScale,
int adaptIcspTryNum)
int adaptIcspTryNum,
double planningSpeedScale = 1.0)
{
ArgumentNullException.ThrowIfNull(ioAddresses);
@@ -36,6 +38,11 @@ public sealed class CompatibilityRobotSettings
throw new ArgumentOutOfRangeException(nameof(jerkLimitScale), "Jerk 倍率必须大于 0。");
}
if (planningSpeedScale <= 0.0 || double.IsNaN(planningSpeedScale) || double.IsInfinity(planningSpeedScale))
{
throw new ArgumentOutOfRangeException(nameof(planningSpeedScale), "规划速度倍率必须是有限正数。");
}
if (adaptIcspTryNum < 0)
{
throw new ArgumentOutOfRangeException(nameof(adaptIcspTryNum), "补点尝试次数不能为负数。");
@@ -54,6 +61,7 @@ public sealed class CompatibilityRobotSettings
AccLimitScale = accLimitScale;
JerkLimitScale = jerkLimitScale;
AdaptIcspTryNum = adaptIcspTryNum;
PlanningSpeedScale = planningSpeedScale;
}
/// <summary>
@@ -81,6 +89,11 @@ public sealed class CompatibilityRobotSettings
/// </summary>
public double JerkLimitScale { get; }
/// <summary>
/// 获取规划阶段的全局速度倍率,只影响 JointTraj 基准时间,不等同于运行时 J519 下发速度倍率。
/// </summary>
public double PlanningSpeedScale { get; }
/// <summary>
/// 获取自适应补点最大尝试次数。
/// </summary>
@@ -131,6 +144,17 @@ public sealed class LoadedRobotConfig
/// </summary>
public sealed class RobotConfigLoader
{
private readonly ILogger<RobotConfigLoader>? _logger;
/// <summary>
/// 初始化 RobotConfigLoader。
/// </summary>
/// <param name="logger">日志记录器;允许 null。</param>
public RobotConfigLoader(ILogger<RobotConfigLoader>? logger = null)
{
_logger = logger;
}
/// <summary>
/// 加载一份旧版 RobotConfig.json。
/// </summary>
@@ -139,6 +163,8 @@ public sealed class RobotConfigLoader
/// <returns>规范化后的配置文档。</returns>
public LoadedRobotConfig Load(string configPath, string? repoRoot = null)
{
_logger?.LogInformation("RobotConfig 开始加载: configPath={ConfigPath}, repoRoot={RepoRoot}", configPath, repoRoot);
var resolvedRepoRoot = ResolveRepoRoot(repoRoot);
var resolvedConfigPath = PathCompatibility.ResolveConfigPath(configPath, resolvedRepoRoot);
@@ -153,7 +179,8 @@ public sealed class RobotConfigLoader
ioKeepCycles: ReadInt(robotElement, "io_keep_cycles", defaultValue: 0),
accLimitScale: ReadDouble(robotElement, "acc_limit", defaultValue: 1.0),
jerkLimitScale: ReadDouble(robotElement, "jerk_limit", defaultValue: 1.0),
adaptIcspTryNum: ReadInt(robotElement, "adapt_icsp_try_num", defaultValue: 0));
adaptIcspTryNum: ReadInt(robotElement, "adapt_icsp_try_num", defaultValue: 0),
planningSpeedScale: ReadDouble(robotElement, "planning_speed_scale", defaultValue: 1.0));
var programs = new Dictionary<string, FlyshotProgram>(StringComparer.Ordinal);
foreach (var programElement in flyingShotsElement.EnumerateObject())
@@ -163,6 +190,10 @@ public sealed class RobotConfigLoader
programs.Add(programName, program);
}
_logger?.LogInformation(
"RobotConfig 加载完成: resolvedPath={ResolvedPath}, useDo={UseDo}, ioKeepCycles={IoKeepCycles}, accLimit={AccLimit}, jerkLimit={JerkLimit}, planningSpeedScale={PlanningSpeedScale}, adaptIcspTryNum={AdaptIcspTryNum}, 程序数={ProgramCount}",
resolvedConfigPath, robot.UseDo, robot.IoKeepCycles, robot.AccLimitScale, robot.JerkLimitScale, robot.PlanningSpeedScale, robot.AdaptIcspTryNum, programs.Count);
return new LoadedRobotConfig(
sourcePath: resolvedConfigPath,
robot: robot,