Implement AXIS parity UI and execution baseline
This commit is contained in:
86
web/worker/test_authoritative_kinematics_s6_04.mjs
Normal file
86
web/worker/test_authoritative_kinematics_s6_04.mjs
Normal file
@@ -0,0 +1,86 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import createModule from "../../build-wasm/linuxcnc-sim-core.js";
|
||||
import { compareEndpoints, createEndpoint, endpointHash } from "./endpoint-replay.mjs";
|
||||
import { SimSession, CONTEXT_ID } from "./sim-session.mjs";
|
||||
|
||||
const wasmBinary = await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url));
|
||||
const TRIPOD_SAMPLE = [5.385164807, 9.433981132, 6.447715952];
|
||||
|
||||
async function runTripod(id, fast) {
|
||||
const core = await createModule({ wasmBinary });
|
||||
const session = new SimSession(core, { sessionId: id });
|
||||
const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: id };
|
||||
let seq = 0;
|
||||
const send = (kind, operation_id, payload = {}) => {
|
||||
seq += 1;
|
||||
const response = session.accept({ ...base, kind, seq, operation_id, payload });
|
||||
assert.notEqual(response.kind, "ERROR", `${id}:${kind}:${response.payload?.code ?? "error"}`);
|
||||
return response;
|
||||
};
|
||||
send("HELLO", "hello");
|
||||
send("SESSION_ATTACH", "attach");
|
||||
const loaded = send("LOAD_WORKSPACE", "workspace", { root_path: "/workspace", kinematics: "tripodkins" });
|
||||
assert.equal(loaded.payload.task.state, "READY");
|
||||
send("PROGRAM_LOAD", "program", { source: "G0 X2 Y3 Z4\nM2\n", path: "tripod.ngc" });
|
||||
send("PROGRAM_RUN", "run");
|
||||
if (fast) send("SIM_STEP", "fast", { cycles: 8 });
|
||||
else for (let index = 0; index < 8; index += 1) send("SIM_STEP", `step-${index}`, { cycles: 1 });
|
||||
const endpoint = createEndpoint({ session });
|
||||
assert.equal(endpoint.authoritative.kinematics.type, "tripod");
|
||||
assert.equal(endpoint.authoritative.kinematics.joint_count, 3);
|
||||
endpoint.authoritative.kinematics.joints.forEach((value, index) => assert.ok(Math.abs(value - TRIPOD_SAMPLE[index]) < 1e-9));
|
||||
assert.equal(endpoint.authoritative.kinematics.pose.x, 2);
|
||||
assert.equal(endpoint.authoritative.kinematics.pose.y, 3);
|
||||
assert.equal(endpoint.authoritative.kinematics.pose.z, 4);
|
||||
const checkpoint = session.createCheckpoint();
|
||||
send("SIM_STEP", "post-checkpoint", { cycles: 1 });
|
||||
const continuous = createEndpoint({ session });
|
||||
const recovery = session.restoreCheckpoint(checkpoint, session.timeline.export(), (operation) => operation);
|
||||
assert.equal(recovery.status, "recovered");
|
||||
const restored = createEndpoint({ session });
|
||||
const recoveryParity = compareEndpoints(continuous, restored);
|
||||
assert.equal(recoveryParity.equal, true, JSON.stringify(recoveryParity));
|
||||
return { endpoint, recoveryParity, checkpoint, kinematics: endpoint.authoritative.kinematics };
|
||||
}
|
||||
|
||||
async function unsupported(type, id) {
|
||||
const core = await createModule({ wasmBinary });
|
||||
const session = new SimSession(core, { sessionId: id });
|
||||
const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: id };
|
||||
session.accept({ ...base, kind: "HELLO", seq: 1, operation_id: "hello" });
|
||||
session.accept({ ...base, kind: "SESSION_ATTACH", seq: 2, operation_id: "attach" });
|
||||
const result = session.accept({ ...base, kind: "LOAD_WORKSPACE", seq: 3, operation_id: "unsupported", payload: { root_path: "/workspace", kinematics: type } });
|
||||
assert.equal(result.kind, "ERROR");
|
||||
assert.equal(result.payload.code, "authoritative_kinematics_unsupported");
|
||||
return { type, code: result.payload.code };
|
||||
}
|
||||
|
||||
const oneX = await runTripod("authoritative-tripod-1x", false);
|
||||
const fast = await runTripod("authoritative-tripod-fast", true);
|
||||
const modeParity = compareEndpoints(oneX.endpoint, fast.endpoint);
|
||||
assert.equal(modeParity.equal, true, JSON.stringify(modeParity));
|
||||
const unsupportedTrt = await unsupported("xyzac-trt", "authoritative-trt-queued");
|
||||
const unsupportedRobot = await unsupported("puma", "authoritative-robot-queued");
|
||||
|
||||
console.log(JSON.stringify({
|
||||
schema: "authoritative-kinematics-s6-04-sample.v1",
|
||||
status: "verified",
|
||||
context_id: CONTEXT_ID,
|
||||
supported: {
|
||||
type: "tripod",
|
||||
source_family: "tripodkins",
|
||||
pose: [2, 3, 4],
|
||||
joints: oneX.kinematics.joints,
|
||||
geometry: { base: [[0, 0], [10, 0], [5, 7.071]], joint_semantics: ["AD", "BD", "CD"] },
|
||||
endpoint_hash: endpointHash(oneX.endpoint),
|
||||
},
|
||||
parity: { mode: modeParity, recovery: oneX.recoveryParity },
|
||||
checkpoint_hash: oneX.checkpoint.checkpoint_hash,
|
||||
unsupported: [unsupportedTrt, unsupportedRobot],
|
||||
boundaries: [
|
||||
"TRT, serial robot, Delta, Hexapod, Pentapod and switch/user families remain queued for later slices",
|
||||
"official LinuxCNC kinematics oracle remains SOURCE_BLOCKED",
|
||||
"tripod native/WASM golden is implementation evidence, not official oracle evidence",
|
||||
],
|
||||
}));
|
||||
Reference in New Issue
Block a user