Files
Mujoco_WASM/web_platform/e2e/lekiwi.fullCollision.spec.ts
T
chenlin 3ad29356c9
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
feat(lekiwi): release V0.10.1 初步集成 LeKiwi,优化碰撞模型
集成通用机器人数值接口、本机控制桥、LeRobot 插件和统一键盘遥操作。采用离线 CoACD 全臂碰撞配方 revision 4、局部装配区切分与结构自接触,限制直接关节位姿写入并保留安全看门狗。同步版本号、变更记录、来源许可证和兼容性验证。
2026-09-20 14:42:30 +08:00

92 lines
4.4 KiB
TypeScript

import { expect, test } from '@playwright/test';
import { resolve } from 'node:path';
import { writeFile } from 'node:fs/promises';
import type {} from '../physics/runner';
test('真实 WASM:相邻 Mirror/Square 连杆主体阻挡、反向脱离,机器人禁止 qpos 瞬移', async ({
page,
}, info) => {
const errors: string[] = [];
page.on('pageerror', (e) => errors.push(e.message));
await page.goto('/physics/runner.html');
await page.waitForFunction(() => Boolean(window.lekiwiPhysics));
await page.evaluate((path) => window.lekiwiPhysics.boot(path), `/@fs${resolve('build/lekiwi')}`);
try {
const result = await page.evaluate(() => window.lekiwiPhysics.adjacentArmChecks());
console.log('adjacent arm', JSON.stringify(result));
await writeFile(info.outputPath('adjacent-arm-contacts.json'), JSON.stringify(result, null, 2));
expect(result.teleportAccepted).toBe(false);
expect(result.jointResetError).toMatch(/profile.*瞬移/);
expect(result.editable).toBe(false);
expect(result.before).toEqual(result.after);
for (const sample of result.samples) {
expect(sample.neutral.contacts).toEqual([]);
expect(Math.abs(sample.neutral.panActual - sample.pan)).toBeLessThan(0.01);
expect(Math.abs(sample.neutral.actual)).toBeLessThan(0.015);
expect(sample.blocked.maxContacts).toBeGreaterThan(0);
expect(sample.blocked.contacts.length).toBeGreaterThan(0);
expect(sample.blocked.actual).toBeGreaterThan(sample.blocked.target + 0.5);
expect(sample.blocked.minContactRadius).toBeGreaterThan(0.04); // structural contact, NOT the bearing core
expect(sample.blocked.maxPenetration).toBeLessThan(0.002);
expect(sample.blocked.finite).toBe(true);
for (const c of sample.blocked.contacts) expect(c.distance).toBeGreaterThan(-0.0005);
expect(Math.abs(sample.released.actual - 0.3)).toBeLessThan(0.015);
expect(sample.released.contacts).toEqual([]);
}
expect(errors).toEqual([]);
} finally {
await page.evaluate(() => window.lekiwiPhysics.dispose());
}
});
test('真实 WASM:六关节双向有界目标扫掠,无整体穿入或数值重置', async ({ page }, info) => {
const errors: string[] = [];
page.on('pageerror', (e) => errors.push(e.message));
await page.goto('/physics/runner.html');
await page.waitForFunction(() => Boolean(window.lekiwiPhysics));
await page.evaluate((path) => window.lekiwiPhysics.boot(path), `/@fs${resolve('build/lekiwi')}`);
try {
const result = await page.evaluate(() => window.lekiwiPhysics.jointSweepChecks());
await writeFile(info.outputPath('joint-sweeps.json'), JSON.stringify(result, null, 2));
console.log('joint sweeps', JSON.stringify(result));
expect(result).toHaveLength(12);
for (const sample of result) {
expect(sample.finite, sample.joint).toBe(true);
expect(sample.elapsed).toBeCloseTo(sample.expectedTime, 6);
expect(sample.maxPenetration, sample.joint).toBeLessThan(0.002);
if (sample.joint === 'arm_shoulder_pan') {
expect(Math.abs(sample.actual - sample.target)).toBeLessThan(0.01);
expect(sample.maxContacts).toBe(0); // core/structural straddlers must not lock the bearing
}
if (Math.abs(sample.actual - sample.target) > 0.05)
expect(sample.maxContacts, sample.joint).toBeGreaterThan(0);
}
expect(errors).toEqual([]);
} finally {
await page.evaluate(() => window.lekiwiPhysics.dispose());
}
});
test('真实 WASM:从原始 STL 独立取六向极值,整臂 18 个视觉网格均有外部物体接触覆盖', async ({
page,
}, info) => {
const errors: string[] = [];
page.on('pageerror', (e) => errors.push(e.message));
await page.goto('/physics/runner.html');
await page.waitForFunction(() => Boolean(window.lekiwiPhysics));
await page.evaluate((path) => window.lekiwiPhysics.boot(path), `/@fs${resolve('build/lekiwi')}`);
try {
const result = await page.evaluate(() => window.lekiwiPhysics.visualCollisionCoverage());
await writeFile(info.outputPath('arm-visual-coverage.json'), JSON.stringify(result, null, 2));
expect(result).toHaveLength(18);
for (const sample of result) {
expect(sample.probes).toHaveLength(6);
for (const probe of sample.probes)
expect(probe.contacts.length, `${sample.visual}: ${probe.point}`).toBeGreaterThan(0);
}
expect(errors).toEqual([]);
} finally {
await page.evaluate(() => window.lekiwiPhysics.dispose());
}
});