Files
cnc_wams/web-rtcp-5axis-xyzbc-trt-sim-plan/tests/node/verify_linuxcnc_kinematics_runtime.mjs
2026-07-02 08:01:34 -04:00

127 lines
4.8 KiB
JavaScript

import assert from "node:assert/strict";
import { getFiveAxisProfile } from "../../app/src/profiles/index.js";
import { createLinuxCncKinematicsRuntime } from "../../app/src/runtime/linuxcnc-kinematics-runtime.js";
import { buildRtcpFrame } from "../../app/src/runtime/rtcp-frame.js";
const DEG_TO_RAD = Math.PI / 180;
const cases = [
{
moduleId: "xyzac-trt",
wasmFile: "linuxcnc_xyzac_trt_kinematics.wasm",
joints: [10, 20, 30, 25, 40],
fourthAxis: "A",
fourthKey: "a",
axisPose: { x: 10, y: 20, z: 30, a: 25, b: 0, c: 40 },
kinsType: "tcp-xyzac",
expectedToolAxis: xyzacToolAxis(25, 40),
},
{
moduleId: "xyzbc-trt",
wasmFile: "linuxcnc_xyzbc_trt_kinematics.wasm",
joints: [10, 20, 30, 35, 40],
fourthAxis: "B",
fourthKey: "b",
axisPose: { x: 10, y: 20, z: 30, a: 0, b: 35, c: 40 },
kinsType: "tcp-xyzbc",
expectedToolAxis: xyzbcToolAxis(35, 40),
},
];
for (const testCase of cases) {
const runtime = await createLinuxCncKinematicsRuntime({
moduleId: testCase.moduleId,
switchkinsType: 1,
});
const readiness = runtime.readiness();
assert.equal(runtime.apiName, "web-rtcp-5axis-linuxcnc-kinematics-runtime");
assert.equal(runtime.moduleId, testCase.moduleId);
assert.equal(runtime.loaded, true);
assert.equal(runtime.sourceMode, "source-derived-kinematics-wasm");
assert.equal(runtime.semanticBoundary, "linuxcnc_kinematics_wasm_c_abi");
assert.equal(runtime.executionContext, "direct");
assert.equal(runtime.wasmFile, testCase.wasmFile);
assert.equal(runtime.switchkinsType, 1);
assert.equal(readiness.loaded, true);
assert.equal(readiness.executionContext, "direct");
assert.equal(readiness.supportedModules.includes("xyzac-trt"), true);
assert.equal(readiness.supportedModules.includes("xyzbc-trt"), true);
assert.equal(runtime.switchRc, 0);
const linuxCncKinematicsResult = runtime.frameForJoints(testCase.joints);
assert.equal(linuxCncKinematicsResult.moduleId, testCase.moduleId);
assert.equal(linuxCncKinematicsResult.switchkinsType, 1);
assert.equal(linuxCncKinematicsResult.forward.rc, 0);
assert.equal(linuxCncKinematicsResult.inverse.rc, 0);
assert.deepEqual(roundJoints(linuxCncKinematicsResult.inverse.joints), testCase.joints);
const frame = buildRtcpFrame({
axisPose: testCase.axisPose,
activeLine: 777,
kinsType: testCase.kinsType,
rtcpEnabled: true,
profile: getFiveAxisProfile(testCase.moduleId),
linuxCncKinematicsResult,
});
assert.equal(frame.sourceMode, "source-derived-kinematics-wasm");
assert.equal(frame.semanticBoundary, "linuxcnc_kinematics_wasm_c_abi");
assert.equal(frame.readiness.linuxCncKinematicsReady, true);
assert.equal(frame.readiness.promotionAllowed, true);
assert.equal(frame.readiness.fullLinuxCncProgramExecutionReady, false);
assert.equal(frame.profileId, testCase.moduleId);
assert.equal(frame.kinematicsModuleId, testCase.moduleId);
assert.equal(frame.kinematicsSwitchkinsType, 1);
assert.equal(frame.kinematicsForwardRc, 0);
assert.equal(frame.kinematicsInverseRc, 0);
assert.equal(frame.jointPose[3].axis, testCase.fourthAxis);
assert.equal(frame.jointPose[3].value, testCase.joints[3]);
assert.equal(frame.jointPose[4].axis, "C");
assert.equal(frame.jointPose[4].value, testCase.joints[4]);
assert.equal(frame.tcpPose.x, linuxCncKinematicsResult.forward.pose.x);
assert.equal(frame.tcpPose.y, linuxCncKinematicsResult.forward.pose.y);
assert.equal(frame.tcpPose.z, linuxCncKinematicsResult.forward.pose.z);
assert.equal(frame.tcpPose.a, linuxCncKinematicsResult.forward.pose.a);
assert.equal(frame.tcpPose.b, linuxCncKinematicsResult.forward.pose.b);
assert.equal(frame.tcpPose.c, linuxCncKinematicsResult.forward.pose.c);
assert.equal(frame.tcpPose[testCase.fourthKey], testCase.axisPose[testCase.fourthKey]);
assertVectorNear(frame.toolAxisVector, testCase.expectedToolAxis);
console.log(`${testCase.moduleId.replace(/-/g, "_")}_kinematics_runtime=ok`);
}
console.log("linuxcnc_kinematics_runtime_smoke=ok");
console.log("xyzbc_b_axis_tcp_pose_preserved=1");
function roundJoints(joints) {
return joints.map((value) => Math.round(value * 1e6) / 1e6);
}
function xyzacToolAxis(aDegrees, cDegrees) {
const tilt = aDegrees * DEG_TO_RAD;
const c = cDegrees * DEG_TO_RAD;
return {
x: Math.sin(tilt) * Math.sin(c),
y: -Math.sin(tilt) * Math.cos(c),
z: Math.cos(tilt),
};
}
function xyzbcToolAxis(bDegrees, cDegrees) {
const tilt = bDegrees * DEG_TO_RAD;
const c = cDegrees * DEG_TO_RAD;
return {
x: Math.sin(tilt) * Math.cos(c),
y: Math.sin(tilt) * Math.sin(c),
z: Math.cos(tilt),
};
}
function assertVectorNear(actual, expected, tolerance = 1e-12) {
assert.ok(Math.abs(actual.x - expected.x) < tolerance);
assert.ok(Math.abs(actual.y - expected.y) < tolerance);
assert.ok(Math.abs(actual.z - expected.z) < tolerance);
}