158 lines
4.5 KiB
TypeScript
158 lines
4.5 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { SemanticProgramIr } from "../../src/grl/ir/index.js";
|
|
import type { PathPlanRequest, PathPlanResult, TrajectoryPoint } from "../../src/kdl/types.js";
|
|
import { KdlRuntimeBridge, MotionQueue, type MotionPlanner } from "../../src/runtime/index.js";
|
|
|
|
const POSE = {
|
|
position: [0, 0, 0] as [number, number, number],
|
|
quaternion: [0, 0, 0, 1] as [number, number, number, number]
|
|
};
|
|
|
|
function point(index: number, time: number, joints: number[], segmentId: string): TrajectoryPoint {
|
|
return {
|
|
index,
|
|
time,
|
|
dt: index === 0 ? 0 : time,
|
|
s: time,
|
|
sd: 1,
|
|
sdd: 0,
|
|
joints,
|
|
jointVelocity: joints.map(() => 0),
|
|
jointAcceleration: joints.map(() => 0),
|
|
flange: POSE,
|
|
tcp: POSE,
|
|
motion: "MOVEJ",
|
|
segmentId,
|
|
diagnostics: []
|
|
};
|
|
}
|
|
|
|
function pathResult(request: PathPlanRequest): PathPlanResult {
|
|
return {
|
|
ok: true,
|
|
duration: 1,
|
|
segments: [],
|
|
points: [point(0, 0, request.startJoints, request.segments[0]?.id ?? "p0"), point(1, 1, [1], request.segments[0]?.id ?? "p0")],
|
|
diagnostics: []
|
|
};
|
|
}
|
|
|
|
function program(): SemanticProgramIr {
|
|
return {
|
|
moduleName: "Main",
|
|
symbols: [],
|
|
semanticChecks: [],
|
|
diagnostics: [],
|
|
sourceMap: [
|
|
{ kind: "path_point", id: "p0", pathId: "pick_path", pointId: "p0", sourceMap: { line: 10 } },
|
|
{ kind: "operation_action", id: "pick_op_start_action_0", operationId: "pick_op", sourceMap: { line: 20 } }
|
|
],
|
|
procedures: [
|
|
{
|
|
name: "main",
|
|
instructions: [
|
|
{ kind: "RUN_OPERATION", operationId: "pick_op", sourceMap: { line: 30 } }
|
|
]
|
|
}
|
|
],
|
|
paths: [
|
|
{
|
|
pathId: "pick_path",
|
|
request: {
|
|
pathId: "pick_path",
|
|
startJoints: [0],
|
|
sampleTime: 0.1,
|
|
segments: [
|
|
{
|
|
id: "p0",
|
|
motion: "MOVEJ",
|
|
target: { joints: [1] },
|
|
speed: { kind: "joint_abs", velocity: 1 },
|
|
zone: { kind: "fine" },
|
|
sourceMap: { line: 10 }
|
|
}
|
|
]
|
|
},
|
|
motions: [
|
|
{
|
|
kind: "MOVEJ",
|
|
id: "p0",
|
|
pathId: "pick_path",
|
|
pointId: "p0",
|
|
target: { joints: [1] },
|
|
speed: { kind: "joint_abs", velocity: 1 },
|
|
zone: { kind: "fine" },
|
|
sourceMap: { line: 10 },
|
|
source: { brand: { vendor: "ABB", file: "cell.mod", line: 42 } }
|
|
}
|
|
],
|
|
events: []
|
|
}
|
|
],
|
|
operations: [
|
|
{
|
|
operationId: "pick_op",
|
|
kind: "handling",
|
|
pathId: "pick_path",
|
|
process: {},
|
|
startActions: [
|
|
{
|
|
kind: "ACTION",
|
|
actionKind: "start_action",
|
|
operationId: "pick_op",
|
|
statement: "io.do[1] = true",
|
|
sourceMap: { line: 20 }
|
|
}
|
|
],
|
|
endActions: [
|
|
{
|
|
kind: "ACTION",
|
|
actionKind: "end_action",
|
|
operationId: "pick_op",
|
|
statement: "io.do[1] = false",
|
|
sourceMap: { line: 22 }
|
|
}
|
|
]
|
|
}
|
|
],
|
|
kdlBridge: {
|
|
motionRequests: [],
|
|
pathRequests: []
|
|
}
|
|
};
|
|
}
|
|
|
|
describe("motion queue and KDL runtime bridge", () => {
|
|
it("preserves operation/path/action sources and samples planned paths by virtual time", async () => {
|
|
const plannerCalls: PathPlanRequest[] = [];
|
|
const planner: MotionPlanner = {
|
|
planPath: (_handle, request) => {
|
|
plannerCalls.push(request);
|
|
return pathResult(request);
|
|
}
|
|
};
|
|
const queue = new MotionQueue({ startJoints: [0], sampleTime: 0.1, planner, robotHandle: 7 });
|
|
const ir = program();
|
|
const bridge = new KdlRuntimeBridge(ir, queue);
|
|
|
|
const items = bridge.enqueueInstruction(ir.procedures[0]!.instructions[0]!);
|
|
expect(items.map((item) => item.kind)).toEqual(["action", "path", "action"]);
|
|
expect(items[0]).toMatchObject({ source: { operationId: "pick_op", sourceMap: { line: 20 } } });
|
|
expect(items[1]).toMatchObject({ source: { pathId: "pick_path", operationId: "pick_op" } });
|
|
|
|
await queue.planAll();
|
|
expect(plannerCalls).toHaveLength(1);
|
|
expect(plannerCalls[0]).toMatchObject({ pathId: "pick_path", startJoints: [0] });
|
|
|
|
expect(queue.advance(0.5)).toMatchObject({
|
|
itemId: items[1]!.id,
|
|
localTime: 0.5,
|
|
point: { joints: [1] },
|
|
source: { pathId: "pick_path", operationId: "pick_op" }
|
|
});
|
|
expect(queue.snapshot().items[1]).toMatchObject({
|
|
planned: { ok: true, duration: 1 }
|
|
});
|
|
});
|
|
});
|