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,6 +1,7 @@
using System.Text;
using System.Text.Json;
using Flyshot.Core.Domain;
using Microsoft.Extensions.Logging;
namespace Flyshot.Core.Config;
@@ -10,6 +11,16 @@ namespace Flyshot.Core.Config;
public sealed class RobotModelLoader
{
private const uint JsonChunkType = 0x4E4F534A;
private readonly ILogger<RobotModelLoader>? _logger;
/// <summary>
/// 初始化 RobotModelLoader。
/// </summary>
/// <param name="logger">日志记录器;允许 null。</param>
public RobotModelLoader(ILogger<RobotModelLoader>? logger = null)
{
_logger = logger;
}
/// <summary>
/// 加载 .robot 文件并生成规划侧可直接消费的 RobotProfile。
@@ -35,6 +46,8 @@ public sealed class RobotModelLoader
throw new ArgumentOutOfRangeException(nameof(jerkLimitScale), "Jerk 倍率必须大于 0。");
}
_logger?.LogInformation("RobotModel 开始加载: modelPath={ModelPath}, accLimitScale={AccLimitScale}, jerkLimitScale={JerkLimitScale}", modelPath, accLimitScale, jerkLimitScale);
var resolvedModelPath = Path.GetFullPath(modelPath);
var jsonText = ReadJsonChunk(resolvedModelPath);
using var document = JsonDocument.Parse(jsonText);
@@ -76,6 +89,10 @@ public sealed class RobotModelLoader
}
}
_logger?.LogInformation(
"RobotModel 加载完成: profileName={ProfileName}, dof={Dof}, 关节限制数={JointLimitCount}, couple数={CouplingCount}, resolvedPath={ResolvedPath}",
profileName, jointLimits.Count, jointLimits.Count, jointCouplings.Count, resolvedModelPath);
return new RobotProfile(
name: profileName,
modelPath: resolvedModelPath,
@@ -156,6 +173,8 @@ public sealed class RobotModelLoader
throw new ArgumentException(".robot 路径不能为空。", nameof(modelPath));
}
_logger?.LogInformation("RobotKinematicsModel 开始加载: modelPath={ModelPath}", modelPath);
var resolvedModelPath = Path.GetFullPath(modelPath);
var jsonText = ReadJsonChunk(resolvedModelPath);
using var document = JsonDocument.Parse(jsonText);
@@ -203,6 +222,8 @@ public sealed class RobotModelLoader
coupleOffset: coupleOffset));
}
_logger?.LogInformation("RobotKinematicsModel 加载完成: profileName={ProfileName}, 关节数={JointCount}", profileName, joints.Count);
return new RobotKinematicsModel(name: profileName, joints: joints);
}