230 lines
11 KiB
JavaScript
230 lines
11 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
|
|
import { createMemorySessionStorage } from "../../app/src/runtime/five-axis-session.js";
|
|
import { parseLinuxCncIni } from "../../app/src/runtime/linuxcnc-ini-runtime.js";
|
|
import {
|
|
createMachineFileStagingPlan,
|
|
selectMachineFileProgram,
|
|
stageProfileMachineFiles,
|
|
} from "../../app/src/runtime/linuxcnc-machine-file-staging.js";
|
|
import { createLinuxCncInterpreterRuntime } from "../../app/src/runtime/linuxcnc-interpreter-runtime.js";
|
|
import {
|
|
buildTaskHalProgramMotionPlan,
|
|
buildTaskHalSessionFromMachineFiles,
|
|
wrapTaskHalSdk,
|
|
} from "../../app/src/runtime/linuxcnc-task-hal-runtime.js";
|
|
import { getFiveAxisProfile } from "../../app/src/profiles/index.js";
|
|
import { createSimulationStore } from "../../app/src/state/store.js";
|
|
import { createLinuxCncTaskHalSdk } from "../../../wasm-port/runtime/sdk/src/linuxcnc-task-hal.js";
|
|
import { buildVismachModelState, XYZBC_TRT_VISMACH_PINS } from "../../app/src/runtime/vismach-model-state.js";
|
|
import {
|
|
applyToolCommandSequence,
|
|
createToolRuntimeState,
|
|
} from "../../app/src/runtime/tool-db-simulation.js";
|
|
|
|
const profile = getFiveAxisProfile();
|
|
|
|
assert.equal(profile.id, "xyzbc-trt");
|
|
assert.equal(profile.machineName, "sim-xyzbc-trt-kins (switchkins)");
|
|
assert.equal(profile.traj.coordinates, "XYZBC");
|
|
assert.deepEqual(profile.coordinates, ["X", "Y", "Z", "B", "C"]);
|
|
assert.equal(profile.kinematics, "xyzbc-trt-kins");
|
|
assert.equal(profile.kinematicsModuleId, "xyzbc-trt");
|
|
assert.equal(profile.machineFileStaging.defaultProgramFilename, "xyzbc_switchkins.ngc");
|
|
assert.equal(profile.panelSchema.id, "xyzbc-trt-switchkins-pyvcp");
|
|
assert.ok(profile.halPins.includes("xyzbc-trt-kins.x-offset"));
|
|
assert.ok(profile.halPins.includes("motion.switchkins-type"));
|
|
assert.deepEqual(profile.hal.halcmd.feedbackNets.map((net) => net.signal), [
|
|
"table-x",
|
|
"saddle-y",
|
|
"spindle-z",
|
|
"tilt-b",
|
|
"rotate-c",
|
|
]);
|
|
assert.deepEqual(profile.hal.halcmd.offsetNets.map((net) => net.target), [
|
|
"xyzbc-trt-kins.tool-offset",
|
|
"xyzbc-trt-gui.tool-offset",
|
|
"xyzbc-trt-gui.x-offset",
|
|
"xyzbc-trt-gui.z-offset",
|
|
]);
|
|
assert.deepEqual(profile.samplePrograms, [
|
|
"configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc",
|
|
"configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzbc.ngc",
|
|
]);
|
|
assert.ok(profile.remaps.some((remap) => remap.code === "M428" && remap.switchkinsType === 1));
|
|
assert.ok(profile.remaps.some((remap) => remap.code === "M429" && remap.switchkinsType === 0));
|
|
assert.ok(profile.remaps.some((remap) => remap.code === "M430" && remap.switchkinsType === 2));
|
|
|
|
const iniText = await readFile(
|
|
new URL("../../../wasm-port/vendor/linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini", import.meta.url),
|
|
"utf8",
|
|
);
|
|
const ini = parseLinuxCncIni(iniText, {
|
|
path: profile.iniPath,
|
|
profileId: profile.id,
|
|
});
|
|
|
|
assert.equal(ini.validation.ready, true);
|
|
assert.equal(ini.machineName, "sim-xyzbc-trt-kins (switchkins)");
|
|
assert.equal(ini.kinematics.name, "xyzbc-trt-kins");
|
|
assert.equal(ini.kinematicsModuleId, "xyzbc-trt");
|
|
assert.equal(ini.traj.coordinates, "XYZBC");
|
|
assert.equal(ini.rs274ngc.halPinVars, true);
|
|
assert.equal(ini.rs274ngc.parameterFile, "xyzbc.var");
|
|
assert.equal(ini.emcio.toolTable, "xyzbc-trt.tbl");
|
|
assert.equal(ini.jointConfig[3].axis, "B");
|
|
assert.equal(ini.jointConfig[4].axis, "C");
|
|
assert.deepEqual(ini.halui.mdiCommands, ["M429", "M428", "M430"]);
|
|
|
|
const storage = createMemorySessionStorage();
|
|
const staged = await stageProfileMachineFiles(profile, { storage });
|
|
|
|
assert.equal(staged.plan.profileId, "xyzbc-trt");
|
|
assert.equal(staged.plan.wasmDir, "/work/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt");
|
|
assert.equal(staged.save.status, "saved");
|
|
assert.equal(staged.save.storageMode, "memory");
|
|
assert.ok(staged.save.opfsRoot.endsWith("/xyzbc-trt"));
|
|
assert.ok(staged.save.files.every((file) => file.opfsPath.startsWith("web-rtcp-5axis-xyzbc-trt-sim-plan/machines/xyzbc-trt/")));
|
|
assert.ok(staged.save.files.some((file) => file.sourceRel.endsWith("xyzbc-trt.ini") && file.kind === "ini"));
|
|
assert.ok(staged.save.files.some((file) => file.sourceRel.endsWith("xyzbc-trt.xml") && file.kind === "pyvcp"));
|
|
assert.ok(staged.save.files.some((file) => file.sourceRel.endsWith("xyzbc-trt.tbl") && file.kind === "toolTable"));
|
|
assert.ok(staged.save.files.some((file) => file.sourceRel.endsWith("remap_subs/428remap.ngc") && file.kind === "remap"));
|
|
assert.ok(staged.save.files.some((file) => file.sourceRel.endsWith("remap_subs/429remap.ngc") && file.kind === "remap"));
|
|
assert.ok(staged.save.files.some((file) => file.sourceRel.endsWith("remap_subs/430remap.ngc") && file.kind === "remap"));
|
|
assert.ok(staged.save.files.some((file) => file.sourceRel.endsWith("remap_subs/xyzbc_switchkins_sub.ngc") && file.kind === "remap"));
|
|
assert.ok(staged.save.files.some((file) => file.sourceRel.endsWith("remap_subs/centering.ngc") && file.kind === "remap"));
|
|
assert.ok(staged.save.files.some((file) => file.sourceRel.endsWith("remap_subs/helix_bc.ngc") && file.kind === "remap"));
|
|
assert.ok(staged.save.gcodeSources.some((source) => source.filename === "xyzbc_switchkins.ngc"));
|
|
assert.ok(staged.save.gcodeSources.some((source) => source.filename === "boat-xyzbc.ngc"));
|
|
assert.equal(staged.save.files.some((file) => file.sourceRel.endsWith("xyzbc.var") && file.kind === "parameters"), true);
|
|
assert.equal(staged.save.files.find((file) => file.sourceRel.endsWith("xyzbc-trt.tbl")).text.includes("T2 P2 Z10 D8"), true);
|
|
|
|
const selectedPlan = selectMachineFileProgram(
|
|
staged.plan,
|
|
staged.save,
|
|
"configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc",
|
|
);
|
|
assert.equal(selectedPlan.selectedProgramFilename, "xyzbc_switchkins.ngc");
|
|
assert.ok(selectedPlan.wasmProgramPath.endsWith("/demos/xyzbc_switchkins.ngc"));
|
|
|
|
const interpreter = await createLinuxCncInterpreterRuntime();
|
|
const execution = interpreter.runMachineFileProgram({
|
|
plan: selectedPlan,
|
|
files: staged.save.files,
|
|
executionMode: "fiveAxisRemap",
|
|
});
|
|
assert.equal(execution.summary.machineFileExecutionReady, true);
|
|
assert.equal(execution.plannerTiming.plannerRuntimeReady, true);
|
|
assert.equal(execution.plannerTiming.samples.length > 0, true);
|
|
|
|
const taskHalWasm = await readFile(
|
|
new URL("../../../wasm-port/build/wasm/task-hal/linuxcnc_task_hal.wasm", import.meta.url),
|
|
);
|
|
const taskHal = wrapTaskHalSdk(await createLinuxCncTaskHalSdk({
|
|
wasmBinary: taskHalWasm,
|
|
print() {},
|
|
printErr() {},
|
|
}));
|
|
const taskHalSession = buildTaskHalSessionFromMachineFiles({
|
|
profile,
|
|
plan: selectedPlan,
|
|
save: staged.save,
|
|
selectedProgramRel: selectedPlan.selectedProgramSourceRel,
|
|
});
|
|
taskHal.initSession(taskHalSession);
|
|
taskHal.stageFiles(taskHalSession.files);
|
|
taskHal.openProgram(taskHalSession.programPath);
|
|
taskHal.loadProgramMotionPlan(buildTaskHalProgramMotionPlan({
|
|
programPath: taskHalSession.programPath,
|
|
motion: execution.motion,
|
|
timing: execution.plannerTiming,
|
|
linearUnits: execution.plannerTiming.linearUnits || "mm",
|
|
programLines: staged.save.files
|
|
.find((file) => (file.wasmPath || file.path) === taskHalSession.programPath)
|
|
?.text.split(/\r?\n/) || [],
|
|
}));
|
|
taskHal.sendCommand({ type: "EMC_TASK_SET_STATE", state: "ON" });
|
|
taskHal.sendCommand({ type: "EMC_TASK_SET_MODE", mode: "AUTO" });
|
|
taskHal.sendCommand({ type: "EMC_TASK_PLAN_RUN", line: 0 });
|
|
taskHal.runCycles({ taskPeriodNs: 20000000, servoPeriodNs: 1000000, taskCycles: 3 });
|
|
const taskHalStatus = taskHal.readStatus();
|
|
assert.equal(taskHalStatus.summary.taskRuntimeReady, true);
|
|
assert.equal(taskHalStatus.summary.halSyncReady, true);
|
|
assert.equal(taskHalStatus.ui.activeLine >= 1, true);
|
|
assert.equal(Number.isFinite(taskHalStatus.motionStatus.axis.x), true);
|
|
assert.equal(Number.isFinite(taskHalStatus.motionStatus.axis.y), true);
|
|
assert.equal(Number.isFinite(taskHalStatus.motionStatus.axis.z), true);
|
|
|
|
const store = createSimulationStore();
|
|
const state = store.getState();
|
|
assert.equal(state.machineProfile, "xyzbc-trt");
|
|
assert.equal(state.profile.id, "xyzbc-trt");
|
|
assert.equal(state.sessionName, "xyzbc-trt-web-session");
|
|
assert.equal(state.kinematicsRuntimeReadiness, null);
|
|
|
|
const storeStage = await store.stageMachineFiles({ storage: createMemorySessionStorage() });
|
|
const toolOffsetDb = applyToolCommandSequence(store.getState().toolDbSimulation, [
|
|
{ code: "T", toolNumber: 2 },
|
|
{ code: "M6" },
|
|
{ code: "G43", h: 2 },
|
|
]);
|
|
const toolRuntimeState = createToolRuntimeState(toolOffsetDb, {
|
|
fallbackToolLength: state.toolPreview.length,
|
|
});
|
|
assert.equal(toolRuntimeState.ready, true);
|
|
assert.equal(toolRuntimeState.activeOffsetApplied, true);
|
|
assert.equal(toolRuntimeState.activeToolNumber, 2);
|
|
assert.equal(toolRuntimeState.activePocket, 2);
|
|
assert.equal(toolRuntimeState.currentTool.offset.z, 10);
|
|
assert.equal(toolRuntimeState.currentTool.diameter, 8);
|
|
assert.equal(toolRuntimeState.kinematics.toolOffsetZ, 10);
|
|
assert.equal(toolRuntimeState.kinematics.halPin, "motion.tooloffset.z");
|
|
assert.deepEqual(toolRuntimeState.kinematics.downstreamPins, [
|
|
"xyzbc-trt-kins.tool-offset",
|
|
"xyzbc-trt-gui.tool-offset",
|
|
]);
|
|
assert.equal(toolRuntimeState.pathTool.id, 2);
|
|
assert.equal(toolRuntimeState.pathTool.pocket, 2);
|
|
assert.equal(toolRuntimeState.pathTool.length, 10);
|
|
assert.equal(toolRuntimeState.pathTool.diameter, 8);
|
|
assert.equal(toolRuntimeState.vismach.toolOffset, 10);
|
|
|
|
const vismachState = buildVismachModelState({
|
|
...state,
|
|
axisPose: { x: 12.5, y: -6.25, z: 3.75, b: 35, c: -90 },
|
|
toolPreview: { ...state.toolPreview, length: 84.019 },
|
|
toolRuntimeState,
|
|
});
|
|
assert.deepEqual(Object.keys(vismachState.pins), XYZBC_TRT_VISMACH_PINS);
|
|
assert.equal(vismachState.pins["table-x"], 12.5);
|
|
assert.equal(vismachState.pins["saddle-y"], -6.25);
|
|
assert.equal(vismachState.pins["spindle-z"], 3.75);
|
|
assert.equal(vismachState.pins["tilt-b"], 35);
|
|
assert.equal(vismachState.pins["rotate-c"], -90);
|
|
assert.equal(vismachState.pins["x-offset"], -20);
|
|
assert.equal(vismachState.pins["z-offset"], -15);
|
|
assert.equal(vismachState.pins["tool-offset"], 10);
|
|
assert.deepEqual(vismachState.transforms.table.sourcePins, ["table-x"]);
|
|
assert.deepEqual(vismachState.transforms.saddle.sourcePins, ["saddle-y"]);
|
|
assert.deepEqual(vismachState.transforms.spindle.sourcePins, ["spindle-z"]);
|
|
assert.deepEqual(vismachState.transforms.tilt.sourcePins, ["tilt-b"]);
|
|
assert.deepEqual(vismachState.transforms.rotary.sourcePins, ["rotate-c"]);
|
|
assert.deepEqual(vismachState.transforms.tool.sourcePins, ["tool-offset", "x-offset", "z-offset"]);
|
|
assert.equal(vismachState.transforms.tool.translate.x, -20);
|
|
assert.equal(vismachState.transforms.tool.translate.z, -25);
|
|
assert.equal(vismachState.halNets.length, 9);
|
|
assert.equal(vismachState.semanticBoundary, "web_threejs_vismach_equivalent_driven_by_xyzbc_trt_hal_pins");
|
|
|
|
const stagedState = store.getState();
|
|
assert.equal(storeStage.save.profileId, "xyzbc-trt");
|
|
assert.equal(stagedState.machineFileStaging.profileId, "xyzbc-trt");
|
|
assert.ok(stagedState.machineProject.projectRoot.startsWith("web-rtcp-5axis-xyzbc-trt-sim-plan/machines/xyzbc-trt"));
|
|
assert.ok(stagedState.machineFileStaging.gcodeSources.some((source) => source.filename === "xyzbc_switchkins.ngc"));
|
|
|
|
const stagingPlan = await createMachineFileStagingPlan({ profile });
|
|
assert.equal(stagingPlan.summary.remapFileCount >= 3, true);
|
|
assert.equal(stagingPlan.files.some((file) => file.sourceRel.endsWith("xyzbc.var")), true);
|
|
|
|
console.log("xyzbc_trt_web_app_smoke=ok");
|