* 新增 FlyshotTrajectoryArtifactWriter,支持 saveTrajectory 将规划结果导出到 Config/Data/name(JointTraj、CartTraj、 ShotEvents 等) * RobotConfig 新增 PlanningSpeedScale,区分规划阶段限速倍率 与运行时 J519 下发倍率 * 轨迹缓存键纳入 planningSpeedScale,避免降速规划误用缓存 * 完善 FanucCommandClient 命令参数日志与状态通道重连 * 补充 RuntimeOrchestrationTests 覆盖产物导出与倍率隔离 * 更新 README 进度文档
150 lines
5.4 KiB
C#
150 lines
5.4 KiB
C#
using Flyshot.ControllerClientCompat;
|
||
using Flyshot.Core.Config;
|
||
|
||
namespace Flyshot.Core.Tests;
|
||
|
||
/// <summary>
|
||
/// 验证 ControllerClient 兼容层默认围绕运行目录 Config 读写配置和轨迹文件。
|
||
/// </summary>
|
||
public sealed class ControllerClientCompatConfigRootTests
|
||
{
|
||
/// <summary>
|
||
/// 验证路径兼容层优先命中运行目录 Config 下的 RobotConfig.json,而不是旧仓库根目录候选。
|
||
/// </summary>
|
||
[Fact]
|
||
public void PathCompatibility_ResolvesRuntimeConfigBeforeLegacyCandidates()
|
||
{
|
||
var runtimeRoot = CreateTempDirectory();
|
||
try
|
||
{
|
||
var configPath = Path.Combine(runtimeRoot, "Config", "RobotConfig.json");
|
||
var legacyPath = Path.Combine(runtimeRoot, "RobotConfig.json");
|
||
Directory.CreateDirectory(Path.GetDirectoryName(configPath)!);
|
||
File.WriteAllText(configPath, "{}");
|
||
File.WriteAllText(legacyPath, "{}");
|
||
|
||
var resolved = PathCompatibility.ResolveConfigPath("RobotConfig.json", runtimeRoot);
|
||
|
||
Assert.Equal(configPath, resolved);
|
||
}
|
||
finally
|
||
{
|
||
Directory.Delete(runtimeRoot, recursive: true);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证机器人目录优先从显式 ConfigRoot/Models 加载 .robot 文件。
|
||
/// </summary>
|
||
[Fact]
|
||
public void ControllerClientCompatRobotCatalog_LoadsModelFromConfigRootModels()
|
||
{
|
||
var configRoot = CreateTempConfigRoot();
|
||
try
|
||
{
|
||
CopySampleRobotModel(configRoot);
|
||
var options = new ControllerClientCompatOptions { ConfigRoot = configRoot };
|
||
var catalog = new ControllerClientCompatRobotCatalog(options, new RobotModelLoader());
|
||
|
||
var profile = catalog.LoadProfile("FANUC_LR_Mate_200iD");
|
||
|
||
Assert.Equal(Path.Combine(configRoot, "Models", "LR_Mate_200iD_7L.robot"), profile.ModelPath);
|
||
}
|
||
finally
|
||
{
|
||
Directory.Delete(configRoot, recursive: true);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证 JSON 轨迹存储保存、加载和删除都落在 ConfigRoot/RobotConfig.json。
|
||
/// </summary>
|
||
[Fact]
|
||
public void JsonFlyshotTrajectoryStore_PersistsTrajectoriesInRobotConfigJson()
|
||
{
|
||
var configRoot = CreateTempConfigRoot();
|
||
try
|
||
{
|
||
var options = new ControllerClientCompatOptions { ConfigRoot = configRoot };
|
||
var store = new JsonFlyshotTrajectoryStore(options, new RobotConfigLoader());
|
||
var settings = new CompatibilityRobotSettings(
|
||
useDo: true,
|
||
ioAddresses: [7, 8],
|
||
ioKeepCycles: 2,
|
||
accLimitScale: 1.0,
|
||
jerkLimitScale: 1.0,
|
||
adaptIcspTryNum: 5);
|
||
var trajectory = TestRobotFactory.CreateUploadedTrajectoryWithSingleShot();
|
||
|
||
store.Save("FANUC_LR_Mate_200iD", settings, trajectory);
|
||
var expectedPath = Path.Combine(configRoot, "RobotConfig.json");
|
||
|
||
Assert.True(File.Exists(expectedPath), $"应在运行目录 Config 下创建统一配置文件: {expectedPath}");
|
||
Assert.False(Directory.Exists(Path.Combine(configRoot, "TrajectoryStore")), "不应再创建独立轨迹存储目录。");
|
||
var loaded = store.LoadAll("FANUC_LR_Mate_200iD", out var loadedSettings);
|
||
Assert.NotNull(loadedSettings);
|
||
Assert.Contains(trajectory.Name, loaded);
|
||
|
||
store.Delete("FANUC_LR_Mate_200iD", trajectory.Name);
|
||
|
||
var afterDelete = store.LoadAll("FANUC_LR_Mate_200iD", out _);
|
||
Assert.Empty(afterDelete);
|
||
}
|
||
finally
|
||
{
|
||
Directory.Delete(configRoot, recursive: true);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建测试专用的运行目录 Config 根,避免污染真实输出目录。
|
||
/// </summary>
|
||
private static string CreateTempConfigRoot()
|
||
{
|
||
var root = Path.Combine(Path.GetTempPath(), "flyshot-config-root-tests", Guid.NewGuid().ToString("N"), "Config");
|
||
Directory.CreateDirectory(root);
|
||
return root;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建测试专用的临时目录。
|
||
/// </summary>
|
||
private static string CreateTempDirectory()
|
||
{
|
||
var root = Path.Combine(Path.GetTempPath(), "flyshot-config-root-tests", Guid.NewGuid().ToString("N"));
|
||
Directory.CreateDirectory(root);
|
||
return root;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 复制仓库内已固化的现场机器人模型到临时 Config/Models 目录。
|
||
/// </summary>
|
||
private static void CopySampleRobotModel(string configRoot)
|
||
{
|
||
var modelDir = Path.Combine(configRoot, "Models");
|
||
Directory.CreateDirectory(modelDir);
|
||
File.Copy(
|
||
Path.Combine(GetReplacementRoot(), "Config", "Models", "LR_Mate_200iD_7L.robot"),
|
||
Path.Combine(modelDir, "LR_Mate_200iD_7L.robot"));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 定位 replacement 仓库根目录,供测试读取仓库内固化样本。
|
||
/// </summary>
|
||
private static string GetReplacementRoot()
|
||
{
|
||
var current = new DirectoryInfo(AppContext.BaseDirectory);
|
||
while (current is not null)
|
||
{
|
||
if (File.Exists(Path.Combine(current.FullName, "FlyshotReplacement.sln")))
|
||
{
|
||
return current.FullName;
|
||
}
|
||
|
||
current = current.Parent;
|
||
}
|
||
|
||
throw new DirectoryNotFoundException("Unable to locate the flyshot replacement root.");
|
||
}
|
||
}
|