Upload project files
This commit is contained in:
146
kdl-wasm/web/tests/olp/geometry.test.ts
Normal file
146
kdl-wasm/web/tests/olp/geometry.test.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
applyCalibrationRecords,
|
||||
commercialExtensionBoundaries,
|
||||
compareControllerLowSpeedRun,
|
||||
createResourceLibraryTemplate,
|
||||
detectBasicCollisions,
|
||||
generatePathFromGeometry,
|
||||
instantiateProcessTemplate,
|
||||
locateCollisionTime,
|
||||
sampleOlpProject,
|
||||
validateOlpProject
|
||||
} from "../../src/olp/index.js";
|
||||
|
||||
describe("OLP geometry, calibration, and multi-robot extensions", () => {
|
||||
it("generates path targets from points, edges, and curves", () => {
|
||||
const pointPath = generatePathFromGeometry(
|
||||
{ kind: "points", points: [[500, 0, 0], [600, 0, 0]] },
|
||||
{ pathId: "point_path", speedId: "v_linear", zoneId: "z10" }
|
||||
);
|
||||
const edgePath = generatePathFromGeometry(
|
||||
{ kind: "edge", start: [0, 0, 0], end: [100, 0, 0], samples: 3 },
|
||||
{ pathId: "edge_path" }
|
||||
);
|
||||
const curvePath = generatePathFromGeometry(
|
||||
{ kind: "curve", controlPoints: [[0, 0, 0], [50, 50, 0], [100, 0, 0]], samples: 3 },
|
||||
{ pathId: "curve_path", targetPrefix: "curve" }
|
||||
);
|
||||
|
||||
expect(pointPath.targets.map((target) => target.pose)).toEqual([
|
||||
[500, 0, 0, 0, 0, 0],
|
||||
[600, 0, 0, 0, 0, 0]
|
||||
]);
|
||||
expect(edgePath.targets.map((target) => target.pose?.[0])).toEqual([0, 50, 100]);
|
||||
expect(curvePath.targets.map((target) => target.name)).toEqual(["curve_00", "curve_01", "curve_02"]);
|
||||
expect(curvePath.path.points.map((point) => point.motion)).toEqual(["movej", "movel", "movel"]);
|
||||
});
|
||||
|
||||
it("detects primitive collisions and locates the first time point", () => {
|
||||
const project = sampleOlpProject();
|
||||
const report = detectBasicCollisions([
|
||||
{ time: 0, pointId: "p0", position: [100, 0, 0] },
|
||||
{ time: 1.25, pointId: "p1", position: [550, 0, -40] }
|
||||
], project.resources.collisionObjects);
|
||||
|
||||
expect(report.ok).toBe(false);
|
||||
expect(report.hits).toEqual([
|
||||
expect.objectContaining({
|
||||
objectId: "fixture_box",
|
||||
pointId: "p1",
|
||||
time: 1.25
|
||||
})
|
||||
]);
|
||||
expect(locateCollisionTime(report)).toBe(1.25);
|
||||
});
|
||||
|
||||
it("saves and applies TCP/frame/base/external-axis calibration records", () => {
|
||||
const project = sampleOlpProject();
|
||||
const calibrated = applyCalibrationRecords(project, [
|
||||
{
|
||||
id: "tcp_cal_2",
|
||||
name: "tcp_cal_2",
|
||||
kind: "tcp",
|
||||
targetResourceId: "tool_gripper",
|
||||
poseDelta: [1, 2, 3, 0, 0, 0]
|
||||
},
|
||||
{
|
||||
id: "fixture_cal_1",
|
||||
name: "fixture_cal_1",
|
||||
kind: "frame",
|
||||
targetResourceId: "frame_fixture",
|
||||
poseDelta: [10, 0, 0, 0, 0, 0]
|
||||
},
|
||||
{
|
||||
id: "track_cal_1",
|
||||
name: "track_cal_1",
|
||||
kind: "external_axis",
|
||||
targetResourceId: "track_1",
|
||||
axisOffset: 2.5
|
||||
}
|
||||
]);
|
||||
|
||||
expect(calibrated.resources.tools.find((tool) => tool.id === "tool_gripper")?.tcp).toEqual([1, 2, 103, 0, 0, 0]);
|
||||
expect(calibrated.resources.frames.find((frame) => frame.id === "frame_fixture")?.pose).toEqual([810, 0, 0, 0, 0, 0]);
|
||||
expect(calibrated.externalAxes[0]?.metadata).toEqual({ calibrationOffset: 2.5 });
|
||||
expect(validateOlpProject(calibrated).ok).toBe(true);
|
||||
});
|
||||
|
||||
it("creates resource library and process template delivery boundaries", () => {
|
||||
const project = sampleOlpProject();
|
||||
const library = createResourceLibraryTemplate(project);
|
||||
const template = instantiateProcessTemplate(project.processTemplates[0]!, "pick_op");
|
||||
const boundaries = commercialExtensionBoundaries();
|
||||
|
||||
expect(library).toMatchObject({
|
||||
robots: [{ id: "robot_1", brand: "abb", model: "IRB120" }],
|
||||
collisionObjects: [{ id: "fixture_box" }]
|
||||
});
|
||||
expect(template).toEqual({
|
||||
operationId: "pick_op",
|
||||
operationKind: "handling",
|
||||
defaults: { speedId: "v_linear", zoneId: "z10" },
|
||||
deliveryTags: ["source", "post", "report"]
|
||||
});
|
||||
expect(boundaries).toEqual(expect.arrayContaining([
|
||||
expect.objectContaining({ feature: "cad_kernel", mvp: false }),
|
||||
expect.objectContaining({ feature: "delivery_package", mvp: true })
|
||||
]));
|
||||
});
|
||||
|
||||
it("reports multi-robot/external-axis low-speed controller verification boundaries", () => {
|
||||
const project = sampleOlpProject();
|
||||
const report = compareControllerLowSpeedRun([
|
||||
{
|
||||
pointId: "p01",
|
||||
offline: [500, 0, 0, 0, 0, 0],
|
||||
measured: [501, 0, 0, 0.1, 0, 0],
|
||||
speedPercent: 10
|
||||
},
|
||||
{
|
||||
pointId: "p02",
|
||||
offline: [600, 0, 0, 0, 0, 0],
|
||||
measured: [604, 0, 0, 0.5, 0, 0],
|
||||
speedPercent: 10
|
||||
}
|
||||
], {
|
||||
positionMm: 5,
|
||||
orientationDeg: 1
|
||||
});
|
||||
|
||||
expect(project.motionGroups[0]).toMatchObject({
|
||||
robotIds: ["robot_1"],
|
||||
externalAxisIds: ["track_1"]
|
||||
});
|
||||
expect(report).toMatchObject({
|
||||
status: "pass",
|
||||
speedPercent: 10,
|
||||
maxPositionErrorMm: 4,
|
||||
maxOrientationErrorDeg: 0.5
|
||||
});
|
||||
expect(report.boundaries).toEqual(expect.arrayContaining([
|
||||
expect.stringContaining("does not open a live controller communication session"),
|
||||
expect.stringContaining("does not include a full CAD kernel")
|
||||
]));
|
||||
});
|
||||
});
|
||||
114
kdl-wasm/web/tests/olp/model.test.ts
Normal file
114
kdl-wasm/web/tests/olp/model.test.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { postProcessAllBrands } from "../../src/grl/post/index.js";
|
||||
import { parseGrl } from "../../src/grl/parser/index.js";
|
||||
import { compileSemanticProgram } from "../../src/grl/semantic/index.js";
|
||||
import {
|
||||
applyPatch,
|
||||
pathOperationToGrl,
|
||||
sampleOlpProject,
|
||||
validateOlpProject,
|
||||
type OlpProjectModel
|
||||
} from "../../src/olp/index.js";
|
||||
|
||||
describe("OLP project model", () => {
|
||||
it("creates a serializable station/resource/path/operation sample", () => {
|
||||
const project = sampleOlpProject();
|
||||
const restored = JSON.parse(JSON.stringify(project)) as OlpProjectModel;
|
||||
const report = validateOlpProject(restored);
|
||||
|
||||
expect(restored.schemaVersion).toBe("olp/0.1");
|
||||
expect(report).toEqual({ ok: true, issues: [] });
|
||||
expect(restored.resources.robots[0]).toMatchObject({
|
||||
id: "robot_1",
|
||||
kind: "robot",
|
||||
brand: "abb"
|
||||
});
|
||||
expect(restored.externalAxes[0]).toMatchObject({
|
||||
id: "track_1",
|
||||
axisKind: "linear"
|
||||
});
|
||||
expect(restored.motionGroups[0]).toMatchObject({
|
||||
robotIds: ["robot_1"],
|
||||
externalAxisIds: ["track_1"],
|
||||
coordination: "synchronized"
|
||||
});
|
||||
});
|
||||
|
||||
it("applies brand import style object patches and validates references", () => {
|
||||
const patched = applyPatch(sampleOlpProject(), [
|
||||
{
|
||||
op: "add",
|
||||
path: "/targets/-",
|
||||
value: {
|
||||
id: "inspect",
|
||||
name: "inspect",
|
||||
kind: "pose",
|
||||
robotId: "robot_1",
|
||||
pose: [650, 25, 0, 0, 0, 0],
|
||||
toolId: "tool_gripper",
|
||||
frameId: "frame_fixture"
|
||||
}
|
||||
},
|
||||
{
|
||||
op: "add",
|
||||
path: "/paths/0/points/-",
|
||||
value: {
|
||||
id: "p03",
|
||||
name: "p03",
|
||||
motion: "movel",
|
||||
targetId: "inspect",
|
||||
speedId: "v_linear",
|
||||
zoneId: "z10"
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
expect(validateOlpProject(patched).ok).toBe(true);
|
||||
expect(patched.paths[0]?.points.map((point) => point.name)).toEqual(["p00", "p01", "p02", "p03"]);
|
||||
});
|
||||
|
||||
it("generates stable parseable GRL from Path and Operation", () => {
|
||||
const result = pathOperationToGrl(sampleOlpProject(), "pick_op", {
|
||||
moduleName: "DemoCell",
|
||||
style: "expanded"
|
||||
});
|
||||
const ast = parseGrl(result.text);
|
||||
const ir = compileSemanticProgram(ast, {
|
||||
startJoints: [0, 0, 0, 0, 0, 0],
|
||||
sampleTime: 0.004
|
||||
});
|
||||
const post = postProcessAllBrands(ir);
|
||||
|
||||
expect(result.stableIds).toEqual({
|
||||
targets: ["home", "pick", "place"],
|
||||
points: ["p00", "p01", "p02"],
|
||||
path: "pick_path",
|
||||
operation: "pick_op"
|
||||
});
|
||||
expect(result.text).toContain("path pick_path");
|
||||
expect(result.text).toContain("operation pick_op");
|
||||
expect(result.program).toMatchObject({
|
||||
id: "pick_op_grl",
|
||||
language: "grl",
|
||||
entryOperationIds: ["pick_op"]
|
||||
});
|
||||
expect(ir.operations[0]).toMatchObject({
|
||||
operationId: "pick_op",
|
||||
kind: "handling",
|
||||
pathId: "pick_path"
|
||||
});
|
||||
expect(post.outputs.abb.text).toContain("MODULE DemoCell");
|
||||
expect(post.outputs.fanuc.text).toContain("/PROG MAIN");
|
||||
expect(post.outputs.kuka.text).toContain("DEF Main()");
|
||||
});
|
||||
|
||||
it("reports broken schema references with stable issue codes", () => {
|
||||
const project = sampleOlpProject();
|
||||
project.operations[0]!.pathId = "missing_path";
|
||||
|
||||
expect(validateOlpProject(project)).toMatchObject({
|
||||
ok: false,
|
||||
issues: [expect.objectContaining({ code: "OLP_REF_PATH_MISSING" })]
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user