Files
linuxcncWebWASM/scripts/generate_rtcp_teaching_data.mjs

48 lines
3.1 KiB
JavaScript

import assert from 'node:assert/strict';
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { createHash } from 'node:crypto';
import createModule from '../build-wasm/linuxcnc-sim-core.js';
import { WasmXyzacKinematics } from '../web/worker/wasm-xyzac-kinematics.mjs';
const out = new URL('../docs/teaching/rtcp-five-axis/', import.meta.url);
await mkdir(new URL('assets/', out), { recursive: true });
const wasm = await readFile(new URL('../build-wasm/linuxcnc-sim-core.wasm', import.meta.url));
const core = await createModule({ wasmBinary: wasm });
const basePose = { x: 100, y: 0, z: 20, a: 0, b: 0, c: 0, u: 0, v: 0, w: 0 };
const cases = [];
const close = (a, b) => assert.ok(Math.abs(a - b) < 1e-9, `${a} != ${b}`);
for (const coordinates of ['XYZAC', 'XYZBC']) {
const k = new WasmXyzacKinematics(core, { coordinates, limits: Object.fromEntries([...coordinates.toLowerCase()].map((a) => [a, [-100000, 100000]])) });
const samples = [];
for (const [tilt, c] of [[0, 0], [0, 45], [0, 90], [30, 0], [30, 45], [30, 90]]) {
const p = { ...basePose, c, [coordinates[3].toLowerCase()]: tilt };
const ik = k.inverseMode(1, p); assert.equal(ik.status, 'verified');
k.selectPhysical(1, ik.joints);
const fk = k.forward(ik.joints); assert.equal(fk.status, 'verified');
for (const axis of ['x', 'y', 'z']) close(fk.pose[axis], p[axis]);
samples.push({ tilt, c, programmed: p, joints: ik.joints, forward: fk.pose });
}
close(samples[2].joints[0], 0); close(samples[2].joints[1], 100); close(samples[2].joints[2], 20);
const direction = k.inverseMode(1, { ...basePose, c: 45, x: 110 }).joints.map((v, i) => v - samples[1].joints[i]);
close(direction[0], 10 / Math.sqrt(2)); close(direction[1], 10 / Math.sqrt(2));
cases.push({ coordinates, samples, xw_increment_10_at_c45: direction });
k.destroy();
}
const offsets = { x_rot_point: -18, y_rot_point: 14, z_rot_point: 12, x_offset: 22, y_offset: 0, z_offset: -40, tool_offset: 0 };
const k = new WasmXyzacKinematics(core, { coordinates: 'XYZBC', ...offsets, limits: Object.fromEntries(['x', 'y', 'z', 'b', 'c'].map((a) => [a, [-100000, 100000]])) });
const physical = [0, 0, 44.5858, 4.8675, 179.88];
const tcp = k.selectPhysical(1, physical); const tcpPose = { ...tcp.pose };
const identity = k.selectPhysical(0, physical);
physical.forEach((value, i) => { close(tcp.joints[i], value); close(identity.joints[i], value); });
const report = {
report_id: 'rtcp-teaching-numerics-v1', status: 'verified',
wasm_sha256: createHash('sha256').update(wasm).digest('hex'),
convention: 'Native AC: Rx(A) Rz(C); BC: Ry(B) Rz(C). Main teaching examples P=D=tool_offset=0, mm/deg.',
cases,
switch_example: { offsets, physical, tcp_pose: tcpPose, identity_pose: identity.pose },
chord_midpoint: { compensated: [100 / Math.sqrt(2), 100 / Math.sqrt(2), 20], uncompensated_joint_interpolation: [50, 50, 20], distance: 100 - 50 * Math.sqrt(2) },
};
k.destroy();
await writeFile(new URL('numeric-evidence.json', out), JSON.stringify(report, null, 2) + '\n');
console.log(JSON.stringify({ report_id: report.report_id, status: report.status, poses: 12, fk_ik_roundtrips: 12, source: report.wasm_sha256 }));