✨ feat(fanuc): 统一 speedRatio 执行倍率语义
* 将 speedRatio 前移到规划/准备阶段,运行时只消费已生成的 8ms 队列 * 区分旧格式规划导出与 ActualSend 实发诊断工件 * 补充普通轨迹、MoveJoint、飞拍队列和严格限幅回归测试
This commit is contained in:
@@ -67,7 +67,7 @@ public sealed class PlanningCompatibilityTests
|
||||
{
|
||||
var workspaceRoot = GetWorkspaceRoot();
|
||||
var configPath = Path.Combine(workspaceRoot, "Rvbust", "EOL9 EAU 90", "eol9_eau_90.json");
|
||||
var modelPath = Path.Combine(workspaceRoot, "flyshot-replacement", "Config", "LR_Mate_200iD_7L.json");
|
||||
var modelPath = Path.Combine(workspaceRoot, "flyshot-replacement", "Config", "Models", "LR_Mate_200iD_7L.json");
|
||||
|
||||
var config = new RobotConfigLoader().Load(configPath);
|
||||
var baseProfile = new RobotModelLoader().LoadProfile(modelPath, config.Robot.AccLimitScale, config.Robot.JerkLimitScale);
|
||||
@@ -269,6 +269,144 @@ public sealed class PlanningCompatibilityTests
|
||||
validateJerk: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证飞拍最终 J519 队列的 jerk 硬约束使用严格限值,不再沿用历史上放大 4 倍的宽容口径。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void TrajectoryLimitValidator_ThrowsForJ519Jerk_WhenStrictFinalQueueValidationIsEnabled()
|
||||
{
|
||||
var robot = CreateRobotProfile([100.0], [1000.0], [100.0]);
|
||||
var samples = new[]
|
||||
{
|
||||
new J519SendSample(0, 0.000, 0.000, 1.0, [0.0]),
|
||||
new J519SendSample(1, 0.008, 0.008, 1.0, [0.0]),
|
||||
new J519SendSample(2, 0.016, 0.016, 1.0, [0.003754]),
|
||||
new J519SendSample(3, 0.024, 0.024, 1.0, [0.007508])
|
||||
};
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() =>
|
||||
TrajectoryLimitValidator.ValidateJ519SendSamples(
|
||||
robot,
|
||||
samples,
|
||||
trajectoryName: "strict-final-j519",
|
||||
validateJerk: true));
|
||||
|
||||
Assert.Contains("Jerk", exception.Message);
|
||||
Assert.Contains("strict-final-j519", exception.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证飞拍最终发送队列在请求倍率下严格 jerk 超限时直接拒绝执行,而不是自动改写 speed_ratio。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void FlyshotExecutionSendSequenceBuilder_ThrowsInsteadOfRewritingRequestedSpeedRatio()
|
||||
{
|
||||
var robot = CreateRobotProfile([100.0], [10000.0], [800.0]);
|
||||
var program = CreateProgram(
|
||||
[
|
||||
[0.0],
|
||||
[0.001]
|
||||
]);
|
||||
var trajectory = new PlannedTrajectory(
|
||||
robot: robot,
|
||||
originalProgram: program,
|
||||
plannedWaypoints: program.Waypoints,
|
||||
waypointTimes: [0.0, 0.024],
|
||||
segmentDurations: [0.024],
|
||||
segmentScales: [1.0],
|
||||
method: PlanningMethod.Icsp,
|
||||
iterations: 1,
|
||||
threshold: 0.0);
|
||||
var result = new TrajectoryResult(
|
||||
programName: "strict-builder",
|
||||
method: PlanningMethod.Icsp,
|
||||
isValid: true,
|
||||
duration: TimeSpan.FromSeconds(0.024),
|
||||
shotEvents: Array.Empty<ShotEvent>(),
|
||||
triggerTimeline: Array.Empty<TrajectoryDoEvent>(),
|
||||
artifacts: Array.Empty<TrajectoryArtifact>(),
|
||||
failureReason: null,
|
||||
usedCache: false,
|
||||
originalWaypointCount: 2,
|
||||
plannedWaypointCount: 2);
|
||||
var initialSamples = J519SendTrajectorySampler.SamplePlannedTrajectory(
|
||||
trajectory,
|
||||
servoPeriodSeconds: 0.008,
|
||||
speedRatio: 1.0);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
TrajectoryLimitValidator.ValidateJ519SendSamples(
|
||||
robot,
|
||||
initialSamples,
|
||||
trajectoryName: "strict-builder-initial",
|
||||
validateJerk: true));
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() =>
|
||||
FlyshotExecutionSendSequenceBuilder.Build(
|
||||
robot,
|
||||
trajectory,
|
||||
result,
|
||||
servoPeriodSeconds: 0.008,
|
||||
requestedSpeedRatio: 1.0));
|
||||
|
||||
Assert.Contains("speed_ratio=1.000000", exception.Message);
|
||||
Assert.Contains("planning_speed_scale", exception.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证飞拍最终发送队列通过严格校验时,请求 speed_ratio 会原样成为最终倍率。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void FlyshotExecutionSendSequenceBuilder_KeepsRequestedSpeedRatioWhenQueuePasses()
|
||||
{
|
||||
var robot = CreateRobotProfile([100.0], [10000.0], [10000.0]);
|
||||
var program = CreateProgram(
|
||||
[
|
||||
[0.0],
|
||||
[0.001]
|
||||
]);
|
||||
var trajectory = new PlannedTrajectory(
|
||||
robot: robot,
|
||||
originalProgram: program,
|
||||
plannedWaypoints: program.Waypoints,
|
||||
waypointTimes: [0.0, 0.024],
|
||||
segmentDurations: [0.024],
|
||||
segmentScales: [1.0],
|
||||
method: PlanningMethod.Icsp,
|
||||
iterations: 1,
|
||||
threshold: 0.0);
|
||||
var result = new TrajectoryResult(
|
||||
programName: "rewrite-speedratio-builder",
|
||||
method: PlanningMethod.Icsp,
|
||||
isValid: true,
|
||||
duration: TimeSpan.FromSeconds(0.024),
|
||||
shotEvents: Array.Empty<ShotEvent>(),
|
||||
triggerTimeline: Array.Empty<TrajectoryDoEvent>(),
|
||||
artifacts: Array.Empty<TrajectoryArtifact>(),
|
||||
failureReason: null,
|
||||
usedCache: false,
|
||||
originalWaypointCount: 2,
|
||||
plannedWaypointCount: 2);
|
||||
|
||||
var prepared = FlyshotExecutionSendSequenceBuilder.Build(
|
||||
robot,
|
||||
trajectory,
|
||||
result,
|
||||
servoPeriodSeconds: 0.008,
|
||||
requestedSpeedRatio: 0.8);
|
||||
|
||||
Assert.Equal(0.8, prepared.RequestSpeedRatio, precision: 6);
|
||||
Assert.Equal(0.8, prepared.FinalSpeedRatio, precision: 6);
|
||||
Assert.Equal(0, prepared.StretchIterationCount);
|
||||
Assert.All(prepared.Samples, sample => Assert.Equal(0.8, sample.SpeedRatio, precision: 6));
|
||||
Assert.All(prepared.TimingRows, row =>
|
||||
{
|
||||
Assert.Equal(0.8, row[3], precision: 6);
|
||||
Assert.Equal(0.8, row[4], precision: 6);
|
||||
Assert.Equal(0.0, row[5], precision: 6);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个最小 RobotProfile,便于规划层单元测试聚焦在时间轴逻辑上。
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user