Add AC/BC RTCP programs and 3D machine manager
This commit is contained in:
76
scripts/test_trt_switch_stationary_browser.mjs
Normal file
76
scripts/test_trt_switch_stationary_browser.mjs
Normal file
@@ -0,0 +1,76 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
const { chromium } = await import(pathToFileURL(process.env.PLAYWRIGHT_MODULE).href);
|
||||
const output = new URL('../coverage/glb-machine/switching/', import.meta.url);
|
||||
const browser = await chromium.launch({ executablePath: '/usr/bin/google-chrome', headless: true, args: ['--no-sandbox', '--use-angle=swiftshader', '--enable-unsafe-swiftshader'] });
|
||||
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
|
||||
const errors = []; page.on('pageerror', (e) => errors.push(e.message));
|
||||
const control = (id) => page.locator(`[data-axis-control="${id}"]`);
|
||||
const rendered = () => page.waitForFunction(() => { const e = document.querySelector('.xyzac-machine-view'); return e?.dataset.xyzacTick === e?.dataset.xyzacRenderedTick; });
|
||||
const sample = () => page.locator('.xyzac-machine-view').evaluate((e) => ({ joints: JSON.parse(e.dataset.xyzacJoints), tip: JSON.parse(e.dataset.xyzacToolTip), tick: Number(e.dataset.xyzacTick) }));
|
||||
const close = (a, b, label) => a.forEach((v, i) => assert.ok(Math.abs(v - b[i]) < 1e-8, `${label}[${i}] ${v} != ${b[i]}`));
|
||||
async function mdi(block) {
|
||||
await control('tab-mdi').click(); await control('mdi-command').fill(block); await control('mdi-submit').click();
|
||||
await page.waitForFunction(() => document.querySelector('.command-status')?.textContent?.includes('MDI_EXECUTE acknowledged'));
|
||||
}
|
||||
const report = { report_id: 'trt-stationary-switch-browser-v1', status: 'running', machines: [] };
|
||||
try {
|
||||
await page.goto('http://127.0.0.1:5174/');
|
||||
await page.waitForFunction(() => document.querySelector('main')?.dataset.axisProgramLoading === 'false');
|
||||
for (const id of ['ac', 'bc']) {
|
||||
await control('machine-glb-settings').click(); await control(`machine-glb-${id}`).click();
|
||||
await page.waitForFunction(() => document.querySelector('main')?.dataset.axisProgramLoading === 'false');
|
||||
await page.keyboard.press('Escape');
|
||||
await control('toolbar-power').click(); await control('tab-manual').click(); await control('manual-home-all').click();
|
||||
await page.waitForFunction(() => !document.querySelector('[data-axis-control="switchkins-1"]').disabled);
|
||||
const tilt = id[0].toUpperCase();
|
||||
await mdi(`G21 G90 G0 X0 Y0 Z44.5858 ${tilt}4.8675 C179.88`);
|
||||
await page.waitForFunction(() => Math.abs(JSON.parse(document.querySelector('.xyzac-machine-view').dataset.xyzacJoints)[4] - 179.88) < 1e-7);
|
||||
await control('tab-manual').click();
|
||||
await page.waitForFunction(() => !document.querySelector('[data-axis-control="switchkins-1"]').disabled);
|
||||
await rendered();
|
||||
const initial = await sample(), rows = [];
|
||||
await page.locator('.axis-preview-machine').screenshot({ path: new URL(`${id}-identity.png`, output).pathname });
|
||||
for (const type of [1, 0, 1, 0, 2, 1, 0]) {
|
||||
await control(`switchkins-${type}`).click();
|
||||
await page.waitForFunction((type) => document.querySelector(`[data-axis-control="switchkins-${type}"]`)?.getAttribute('aria-pressed') === 'true', type);
|
||||
await rendered(); const after = await sample(); close(after.joints, initial.joints, `${id} button joints`); close(after.tip, initial.tip, `${id} button tip`);
|
||||
await page.waitForTimeout(100); const idle = await sample(); close(idle.tip, initial.tip, `${id} idle tip`);
|
||||
rows.push({ type, after });
|
||||
if (type === 1) await page.locator('.axis-preview-machine').screenshot({ path: new URL(`${id}-tcp.png`, output).pathname });
|
||||
}
|
||||
for (const type of [1, 0, 1]) {
|
||||
await mdi(type === 1 ? 'M428' : 'M429'); await rendered();
|
||||
const after = await sample(); close(after.joints, initial.joints, `${id} MDI joints`); close(after.tip, initial.tip, `${id} MDI tip`);
|
||||
rows.push({ mdi: true, type, after });
|
||||
}
|
||||
// A subsequent rotary jog must still produce actual XYZ compensation.
|
||||
await control('tab-manual').click(); await control(`manual-axis-${id[0]}`).check();
|
||||
const beforeJog = await sample(), box = await control('manual-jog-positive').boundingBox();
|
||||
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2); await page.mouse.down();
|
||||
try { await page.waitForFunction((angle) => JSON.parse(document.querySelector('.xyzac-machine-view').dataset.xyzacJoints)[3] > angle + 1, beforeJog.joints[3]); }
|
||||
finally { await page.mouse.up(); }
|
||||
await page.waitForFunction(() => document.querySelector('.command-status')?.textContent?.includes('JOG_STOP acknowledged'));
|
||||
await rendered(); const afterJog = await sample();
|
||||
assert.ok(afterJog.joints.slice(0, 3).some((v, i) => Math.abs(v - beforeJog.joints[i]) > 1e-5));
|
||||
const compensation = await page.evaluate(async ({ id, beforeJog, afterJog }) => {
|
||||
const api = await import('/src/imported-machine.ts');
|
||||
const asset = await api.loadImportedMachine(await (await fetch(`/machines/demo-${id}-xyz-head.glb`)).arrayBuffer(), `${id}.glb`);
|
||||
const model = api.buildImportedMachine(asset), offsets = { ...asset.structure.offsets, tool_offset: 0 };
|
||||
model.update({ ...beforeJog, offsets });
|
||||
const target = model.workOrigin.worldToLocal(model.toolTip.getWorldPosition(model.toolTip.position.clone()));
|
||||
model.update({ ...afterJog, offsets });
|
||||
const tip = model.toolTip.getWorldPosition(target.clone()), point = model.workOrigin.localToWorld(target.clone());
|
||||
const error = point.distanceTo(tip); model.dispose(); api.disposeMachineScene(asset.scene); return error;
|
||||
}, { id, beforeJog, afterJog });
|
||||
assert.ok(compensation < 1e-8);
|
||||
await control('switchkins-0').click(); await rendered(); close((await sample()).joints, afterJog.joints, 'switch after jog');
|
||||
await control('toolbar-power').click();
|
||||
await page.waitForFunction(() => !document.querySelector('[data-axis-control="machine-glb-import"]').disabled);
|
||||
report.machines.push({ id, initial, rows, afterJog, tcp_jog_error: compensation });
|
||||
}
|
||||
assert.deepEqual(errors, []); report.status = 'verified';
|
||||
} catch (error) { report.status = 'failed'; report.error = String(error.stack ?? error); await page.screenshot({ path: new URL('failure.png', output).pathname }); throw error; }
|
||||
finally { report.browser_errors = errors; await writeFile(new URL('browser.report.json', output), JSON.stringify(report, null, 2) + '\n'); await browser.close(); }
|
||||
console.log(JSON.stringify({ report_id: report.report_id, status: report.status, switches: report.machines.reduce((n, m) => n + m.rows.length + 1, 0) }));
|
||||
Reference in New Issue
Block a user