@holoscript/robotics-plugin 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/index.d.ts +9 -9
- package/dist/index.js +13 -12
- package/dist/parser.d.ts +2 -2
- package/dist/parser.js +1 -1
- package/dist/runtime.d.ts +5 -0
- package/dist/runtime.js +6 -0
- package/dist/traits/ROS2HardwareLoopTrait.d.ts +1 -1
- package/dist/traits/ROS2HardwareLoopTrait.js +20 -5
- package/dist/usd-codegen.d.ts +1 -1
- package/dist/usd-codegen.js +2 -1
- package/package.json +18 -10
- package/plugin.manifest.json +10 -0
- package/CHANGELOG.md +0 -14
- package/examples/isaac-lab-sim-to-real-bridge.holo +0 -63
- package/examples/isaac-lab-sim-to-real.holo +0 -127
- package/python/isaac_lab_bridge.py +0 -157
- package/src/__tests__/isaac-lab-interop.test.ts +0 -207
- package/src/ast.ts +0 -75
- package/src/index.ts +0 -553
- package/src/lexer.ts +0 -307
- package/src/parser.ts +0 -461
- package/src/traits/ROS2HardwareLoopTrait.ts +0 -69
- package/src/traits/types.ts +0 -4
- package/src/usd-codegen.ts +0 -622
- package/tsconfig.json +0 -10
- package/vitest.config.ts +0 -11
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Isaac Lab Sim-to-Real Interop Tests (Path A)
|
|
3
|
-
*
|
|
4
|
-
* Covers the smallest HoloScript -> Isaac Lab asset/export path:
|
|
5
|
-
* - PhysX/OpenUSD schema wiring for drives and per-axis friction
|
|
6
|
-
* - HoloScript radians -> USD degrees conversion for angular joints
|
|
7
|
-
* - Domain randomization and delayed actuator metadata
|
|
8
|
-
* - Fixture parse/generate validation
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { readFileSync } from 'node:fs';
|
|
12
|
-
import { join } from 'node:path';
|
|
13
|
-
import { describe, expect, it } from 'vitest';
|
|
14
|
-
import { Lexer } from '../lexer';
|
|
15
|
-
import { Parser } from '../parser';
|
|
16
|
-
import { USDCodeGen } from '../usd-codegen';
|
|
17
|
-
import type { CompositionNode } from '../ast';
|
|
18
|
-
|
|
19
|
-
const testHoloScript = `
|
|
20
|
-
composition "TestArm" {
|
|
21
|
-
domain_randomization: {
|
|
22
|
-
physics: {
|
|
23
|
-
massScale: [0.8, 1.2]
|
|
24
|
-
frictionRange: [0.3, 0.7]
|
|
25
|
-
}
|
|
26
|
-
actuator: {
|
|
27
|
-
kpNoise: 0.1
|
|
28
|
-
kdNoise: 0.05
|
|
29
|
-
}
|
|
30
|
-
initialState: {
|
|
31
|
-
jointPosRange: {
|
|
32
|
-
joint1: [-0.1, 0.1]
|
|
33
|
-
}
|
|
34
|
-
rootPoseRange: [-0.5, 0.5, -0.5, 0.5, 0.0, 1.0]
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
object "base" @static {
|
|
39
|
-
geometry: "box"
|
|
40
|
-
dimensions: [0.1, 0.1, 0.05]
|
|
41
|
-
mass: 1.0
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
object "joint1" {
|
|
45
|
-
@joint_revolute
|
|
46
|
-
joint_parent: "base"
|
|
47
|
-
joint_axis: [0, 0, 1]
|
|
48
|
-
joint_limits: [-3.141592653589793, 3.141592653589793]
|
|
49
|
-
joint_effort: 50
|
|
50
|
-
max_velocity: 3.141592653589793
|
|
51
|
-
kp: 100.0
|
|
52
|
-
kd: 10.0
|
|
53
|
-
joint_friction: 0.05
|
|
54
|
-
joint_viscous_friction: 0.01
|
|
55
|
-
armature: 0.001
|
|
56
|
-
actuator_latency: 0.005
|
|
57
|
-
actuator_group: {
|
|
58
|
-
name: "arm_group"
|
|
59
|
-
type: "DelayedPDActuator"
|
|
60
|
-
joints: ["joint1", "joint2", "joint3"]
|
|
61
|
-
stiffness: 100
|
|
62
|
-
damping: 10
|
|
63
|
-
friction: 0.05
|
|
64
|
-
latency: 0.005
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
object "link1" {
|
|
69
|
-
geometry: "cylinder"
|
|
70
|
-
radius: 0.05
|
|
71
|
-
length: 0.3
|
|
72
|
-
mass: 1.0
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
`;
|
|
76
|
-
|
|
77
|
-
function parseHoloScript(source = testHoloScript): CompositionNode {
|
|
78
|
-
const lexer = new Lexer(source);
|
|
79
|
-
const tokens = lexer.tokenize();
|
|
80
|
-
const parser = new Parser(tokens);
|
|
81
|
-
return parser.parse();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
describe('Isaac Lab Interop (Path A)', () => {
|
|
85
|
-
describe('Parser', () => {
|
|
86
|
-
it('parses composition-level domain_randomization blocks', () => {
|
|
87
|
-
const ast = parseHoloScript();
|
|
88
|
-
|
|
89
|
-
expect(ast.domainRandomization?.physics?.massScale).toEqual([0.8, 1.2]);
|
|
90
|
-
expect(ast.domainRandomization?.physics?.frictionRange).toEqual([0.3, 0.7]);
|
|
91
|
-
expect(ast.domainRandomization?.actuator?.kpNoise).toBe(0.1);
|
|
92
|
-
expect(ast.domainRandomization?.actuator?.kdNoise).toBe(0.05);
|
|
93
|
-
expect(ast.domainRandomization?.initialState?.jointPosRange?.joint1).toEqual([-0.1, 0.1]);
|
|
94
|
-
expect(ast.domainRandomization?.initialState?.rootPoseRange).toEqual([
|
|
95
|
-
-0.5,
|
|
96
|
-
0.5,
|
|
97
|
-
-0.5,
|
|
98
|
-
0.5,
|
|
99
|
-
0,
|
|
100
|
-
1,
|
|
101
|
-
]);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('accepts traits before and inside object bodies', () => {
|
|
105
|
-
const ast = parseHoloScript();
|
|
106
|
-
const base = ast.objects.find((object) => object.name === 'base');
|
|
107
|
-
const joint1 = ast.objects.find((object) => object.name === 'joint1');
|
|
108
|
-
|
|
109
|
-
expect(base?.traits).toContain('static');
|
|
110
|
-
expect(joint1?.traits).toContain('joint_revolute');
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('parses drive, friction, latency, and actuator group properties', () => {
|
|
114
|
-
const ast = parseHoloScript();
|
|
115
|
-
const joint1 = ast.objects.find((object) => object.name === 'joint1');
|
|
116
|
-
const group = joint1?.actuatorGroups?.[0];
|
|
117
|
-
|
|
118
|
-
expect(joint1?.properties.kp).toBe(100);
|
|
119
|
-
expect(joint1?.properties.kd).toBe(10);
|
|
120
|
-
expect(joint1?.properties.joint_friction).toBe(0.05);
|
|
121
|
-
expect(joint1?.properties.actuator_latency).toBe(0.005);
|
|
122
|
-
expect(group?.name).toBe('arm_group');
|
|
123
|
-
expect(group?.type).toBe('DelayedPDActuator');
|
|
124
|
-
expect(group?.jointNames).toEqual(['joint1', 'joint2', 'joint3']);
|
|
125
|
-
expect(group?.latency).toBe(0.005);
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
describe('USD Codegen', () => {
|
|
130
|
-
it('emits stage units and PhysX root schema assumptions', () => {
|
|
131
|
-
const usd = new USDCodeGen({ isaacLabVersion: '2.3' }).generate(parseHoloScript());
|
|
132
|
-
|
|
133
|
-
expect(usd).toContain('# Generated for Isaac Lab 2.3');
|
|
134
|
-
expect(usd).toContain('metersPerUnit = 1.0');
|
|
135
|
-
expect(usd).toContain('kilogramsPerMass = 1.0');
|
|
136
|
-
expect(usd).toContain('# Units: meters, kilograms, seconds; HoloScript angular inputs are radians.');
|
|
137
|
-
expect(usd).toContain('prepend apiSchemas = ["PhysicsArticulationRootAPI", "PhysxArticulationAPI"]');
|
|
138
|
-
expect(usd).toContain('bool physxArticulation:articulationEnabled = true');
|
|
139
|
-
expect(usd).not.toContain('physxArticulation:jointFriction');
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('emits applied DriveAPI and PhysxJointAxisAPI schemas on actuated joints', () => {
|
|
143
|
-
const usd = new USDCodeGen().generate(parseHoloScript());
|
|
144
|
-
|
|
145
|
-
expect(usd).toContain('prepend apiSchemas = ["PhysicsDriveAPI:angular", "PhysxJointAxisAPI:angular"]');
|
|
146
|
-
expect(usd).toContain('float drive:angular:physics:stiffness = 100');
|
|
147
|
-
expect(usd).toContain('float drive:angular:physics:damping = 10');
|
|
148
|
-
expect(usd).toContain('float drive:angular:physics:maxForce = 50');
|
|
149
|
-
expect(usd).toContain('uniform token drive:angular:physics:type = "force"');
|
|
150
|
-
expect(usd).toContain('float physxJointAxis:angular:staticFrictionEffort = 0.05');
|
|
151
|
-
expect(usd).toContain('float physxJointAxis:angular:dynamicFrictionEffort = 0.05');
|
|
152
|
-
expect(usd).toContain('float physxJointAxis:angular:viscousFrictionCoefficient = 0.01');
|
|
153
|
-
expect(usd).toContain('float physxJointAxis:angular:armature = 0.001');
|
|
154
|
-
expect(usd).not.toContain('drive:angular:physics:friction');
|
|
155
|
-
expect(usd).not.toContain('drive:angular:physics:latency');
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('exports angular limits and velocity in USD degrees', () => {
|
|
159
|
-
const usd = new USDCodeGen().generate(parseHoloScript());
|
|
160
|
-
|
|
161
|
-
expect(usd).toContain('float physics:lowerLimit = -180');
|
|
162
|
-
expect(usd).toContain('float physics:upperLimit = 180');
|
|
163
|
-
expect(usd).toContain('float physics:maxVelocity = 180');
|
|
164
|
-
expect(usd).toContain('float physxJointAxis:angular:maxJointVelocity = 180');
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
it('emits domain randomization and delayed actuator metadata without pretending they are USD schemas', () => {
|
|
168
|
-
const usd = new USDCodeGen().generate(parseHoloScript());
|
|
169
|
-
|
|
170
|
-
expect(usd).toContain('# Domain Randomization Configuration');
|
|
171
|
-
expect(usd).toContain('# massScale: [0.8, 1.2]');
|
|
172
|
-
expect(usd).toContain('# frictionRange: [0.3, 0.7]');
|
|
173
|
-
expect(usd).toContain('# kpNoise: 0.1');
|
|
174
|
-
expect(usd).toContain('# kdNoise: 0.05');
|
|
175
|
-
expect(usd).toContain('custom float holoscript:isaacLab:actuatorLatencySeconds = 0.005');
|
|
176
|
-
expect(usd).toContain('# arm_group: type=DelayedPDActuator joints=[joint1, joint2, joint3]');
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it('disables DriveAPI and PhysX joint-axis output when configured off', () => {
|
|
180
|
-
const usd = new USDCodeGen({
|
|
181
|
-
enableDriveAttributes: false,
|
|
182
|
-
enableJointFriction: false,
|
|
183
|
-
}).generate(parseHoloScript());
|
|
184
|
-
|
|
185
|
-
expect(usd).toContain('prepend apiSchemas = ["PhysicsArticulationRootAPI"]');
|
|
186
|
-
expect(usd).not.toContain('PhysxArticulationAPI');
|
|
187
|
-
expect(usd).not.toContain('PhysicsDriveAPI:angular');
|
|
188
|
-
expect(usd).not.toContain('PhysxJointAxisAPI:angular');
|
|
189
|
-
expect(usd).not.toContain('drive:angular:physics:');
|
|
190
|
-
expect(usd).not.toContain('physxJointAxis:angular:');
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('parses and generates the checked-in Isaac Lab fixture', () => {
|
|
194
|
-
const fixturePath = join(__dirname, '../../examples/isaac-lab-sim-to-real.holo');
|
|
195
|
-
const fixtureSource = readFileSync(fixturePath, 'utf8');
|
|
196
|
-
const usd = new USDCodeGen().generate(parseHoloScript(fixtureSource));
|
|
197
|
-
|
|
198
|
-
expect(usd).toContain('def Xform "TwoLinkArm_IsaacLab"');
|
|
199
|
-
expect(usd).toContain('metersPerUnit = 1.0');
|
|
200
|
-
expect(usd).toContain('kilogramsPerMass = 1.0');
|
|
201
|
-
expect(usd).toContain('PhysicsDriveAPI:angular');
|
|
202
|
-
expect(usd).toContain('PhysxJointAxisAPI:angular');
|
|
203
|
-
expect(usd).toContain('custom float holoscript:isaacLab:actuatorLatencySeconds = 0.005');
|
|
204
|
-
expect(usd).toContain('# Domain Randomization Configuration');
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
});
|
package/src/ast.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Abstract Syntax Tree (AST) node types for HoloScript robotics
|
|
3
|
-
*
|
|
4
|
-
* Extended for Isaac Lab sim-to-real interop (Path A):
|
|
5
|
-
* - Domain randomization blocks
|
|
6
|
-
* - Actuator group configurations
|
|
7
|
-
* - Delayed actuator export hints
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
export type PropertyValue = string | number | boolean | number[] | PropertyValue[];
|
|
11
|
-
|
|
12
|
-
export interface DomainRandomizationConfig {
|
|
13
|
-
/** Physics randomization: mass, friction, damping */
|
|
14
|
-
physics?: {
|
|
15
|
-
massScale?: [number, number]; // [min, max]
|
|
16
|
-
frictionRange?: [number, number];
|
|
17
|
-
dampingRange?: [number, number];
|
|
18
|
-
armatureRange?: [number, number];
|
|
19
|
-
};
|
|
20
|
-
/** Actuator randomization */
|
|
21
|
-
actuator?: {
|
|
22
|
-
kpNoise?: number;
|
|
23
|
-
kdNoise?: number;
|
|
24
|
-
latencyNoise?: number;
|
|
25
|
-
};
|
|
26
|
-
/** Observation noise */
|
|
27
|
-
observation?: {
|
|
28
|
-
jointPosNoise?: number;
|
|
29
|
-
jointVelNoise?: number;
|
|
30
|
-
imuNoise?: number;
|
|
31
|
-
};
|
|
32
|
-
/** Initial state randomization */
|
|
33
|
-
initialState?: {
|
|
34
|
-
jointPosRange?: Record<string, [number, number]>;
|
|
35
|
-
rootPoseRange?: [number, number, number, number, number, number]; // [x_min, x_max, y_min, ...]
|
|
36
|
-
};
|
|
37
|
-
/** Disturbance forces */
|
|
38
|
-
disturbance?: {
|
|
39
|
-
forceRange?: [number, number];
|
|
40
|
-
intervalRange?: [number, number];
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface ActuatorGroupConfig {
|
|
45
|
-
name: string;
|
|
46
|
-
type: 'IdealPDActuator' | 'DCMotorActuator' | 'DelayedPDActuator' | 'RemotizedPDActuator' | 'ImplicitActuator';
|
|
47
|
-
jointNames: string[];
|
|
48
|
-
stiffness?: number;
|
|
49
|
-
damping?: number;
|
|
50
|
-
friction?: number;
|
|
51
|
-
latency?: number; // seconds, converted by Isaac Lab task config to delay steps.
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface ObjectNode {
|
|
55
|
-
type: 'object';
|
|
56
|
-
name: string;
|
|
57
|
-
traits: string[];
|
|
58
|
-
properties: Record<string, PropertyValue>;
|
|
59
|
-
domainRandomization?: DomainRandomizationConfig;
|
|
60
|
-
actuatorGroups?: ActuatorGroupConfig[];
|
|
61
|
-
template?: string;
|
|
62
|
-
line?: number;
|
|
63
|
-
column?: number;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface CompositionNode {
|
|
67
|
-
type: 'composition';
|
|
68
|
-
name: string;
|
|
69
|
-
objects: ObjectNode[];
|
|
70
|
-
domainRandomization?: DomainRandomizationConfig;
|
|
71
|
-
line?: number;
|
|
72
|
-
column?: number;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export type ASTNode = CompositionNode | ObjectNode;
|