@holoscript/robotics-plugin 2.0.1 → 2.0.2

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/dist/index.d.ts DELETED
@@ -1,127 +0,0 @@
1
- /**
2
- * @holoscript/robotics-plugin v1.0.0
3
- * Complete robotics solution: Compile-time (USD/URDF) + Runtime (ROS2/Gazebo)
4
- *
5
- * Features:
6
- * - USD codegen for NVIDIA Isaac Sim (from holoscript-compiler)
7
- * - Isaac Lab sim-to-real interop (Path A)
8
- * - PhysicsDriveAPI for PD actuator control
9
- * - PhysxJointAxisAPI for per-axis friction assumptions
10
- * - Domain randomization configuration blocks
11
- * - URDF/SDF export for ROS2/Gazebo
12
- * - ROS2 runtime integration (roslibjs)
13
- * - VR teleoperation and digital twins
14
- *
15
- * @packageDocumentation
16
- */
17
- export { USDCodeGen } from './usd-codegen';
18
- export type { IsaacLabConfig } from './usd-codegen';
19
- export { Lexer, TokenType } from './lexer';
20
- export type { Token } from './lexer';
21
- export { Parser } from './parser';
22
- export * from './ast';
23
- export type { DomainRandomizationConfig, ActuatorGroupConfig } from './ast';
24
- import type { CompositionNode, DomainRandomizationConfig, ActuatorGroupConfig } from './ast';
25
- export interface ROS2Config {
26
- ros_bridge_url: string;
27
- namespace?: string;
28
- tf_prefix?: string;
29
- }
30
- export interface GazeboConfig {
31
- world_file?: string;
32
- model_sdf?: string;
33
- spawn_position?: [number, number, number];
34
- }
35
- export interface RobotJoint {
36
- name: string;
37
- type: 'revolute' | 'prismatic' | 'fixed' | 'continuous';
38
- parent_link: string;
39
- child_link: string;
40
- axis?: [number, number, number];
41
- limits?: {
42
- lower: number;
43
- upper: number;
44
- effort: number;
45
- velocity: number;
46
- };
47
- }
48
- export interface RobotLink {
49
- name: string;
50
- inertial?: {
51
- mass: number;
52
- inertia: number[];
53
- };
54
- visual?: {
55
- geometry: string;
56
- material?: string;
57
- };
58
- collision?: {
59
- geometry: string;
60
- };
61
- }
62
- export interface RobotTransmission {
63
- name: string;
64
- joint: string;
65
- actuator: string;
66
- mechanicalReduction: number;
67
- hardwareInterface: 'position' | 'velocity' | 'effort';
68
- }
69
- export interface HoloTraitLike {
70
- name: string;
71
- properties?: Record<string, unknown>;
72
- }
73
- export interface HoloCompositionNodeLike {
74
- id?: string;
75
- name: string;
76
- type?: string;
77
- properties?: Record<string, unknown>;
78
- traits?: HoloTraitLike[];
79
- children?: HoloCompositionNodeLike[];
80
- }
81
- export interface HoloCompositionTreeLike {
82
- name: string;
83
- children?: HoloCompositionNodeLike[];
84
- }
85
- export interface ExtractedRobotModel {
86
- name: string;
87
- links: RobotLink[];
88
- joints: RobotJoint[];
89
- transmissions: RobotTransmission[];
90
- xml: string;
91
- }
92
- export interface URDFExtractionOptions {
93
- defaultJointType?: RobotJoint['type'];
94
- defaultAxis?: [number, number, number];
95
- baseLinkName?: string;
96
- hardwareScale?: number;
97
- }
98
- export declare function buildURDFXML(model: Omit<ExtractedRobotModel, 'xml'>): string;
99
- export declare function extractURDFFromHoloComposition(composition: HoloCompositionTreeLike, options?: URDFExtractionOptions): ExtractedRobotModel;
100
- export * from './traits/ROS2HardwareLoopTrait';
101
- export declare const VERSION = "1.0.0";
102
- declare const _default: {
103
- VERSION: string;
104
- buildURDFXML: typeof buildURDFXML;
105
- extractURDFFromHoloComposition: typeof extractURDFFromHoloComposition;
106
- generateIsaacLabFeed: typeof generateIsaacLabFeed;
107
- };
108
- export default _default;
109
- export interface IsaacLabFeedReceipt {
110
- sourceHoloHash: string;
111
- usdHash: string;
112
- configHash: string;
113
- generatedAt: string;
114
- isaacLabVersion: string;
115
- readyForTraining: boolean;
116
- notes: string;
117
- }
118
- export interface IsaacLabFeedBundle {
119
- usd: string;
120
- taskConfig: Record<string, unknown>;
121
- randomization: DomainRandomizationConfig | undefined;
122
- actuators: ActuatorGroupConfig[];
123
- receipt: IsaacLabFeedReceipt;
124
- }
125
- export declare function generateIsaacLabFeed(ast: CompositionNode, opts?: {
126
- isaacLabVersion?: string;
127
- }): IsaacLabFeedBundle;
package/dist/index.js DELETED
@@ -1,349 +0,0 @@
1
- /**
2
- * @holoscript/robotics-plugin v1.0.0
3
- * Complete robotics solution: Compile-time (USD/URDF) + Runtime (ROS2/Gazebo)
4
- *
5
- * Features:
6
- * - USD codegen for NVIDIA Isaac Sim (from holoscript-compiler)
7
- * - Isaac Lab sim-to-real interop (Path A)
8
- * - PhysicsDriveAPI for PD actuator control
9
- * - PhysxJointAxisAPI for per-axis friction assumptions
10
- * - Domain randomization configuration blocks
11
- * - URDF/SDF export for ROS2/Gazebo
12
- * - ROS2 runtime integration (roslibjs)
13
- * - VR teleoperation and digital twins
14
- *
15
- * @packageDocumentation
16
- */
17
- // Compile-time: USD/URDF codegen (from holoscript-compiler)
18
- export { USDCodeGen } from './usd-codegen';
19
- export { Lexer, TokenType } from './lexer';
20
- export { Parser } from './parser';
21
- export * from './ast';
22
- import { USDCodeGen } from './usd-codegen';
23
- const DEFAULT_URDF_AXIS = [0, 0, 1];
24
- function normalizeTraitName(name) {
25
- return name.replace(/^@/, '').trim().toLowerCase();
26
- }
27
- function sanitizeRobotName(name) {
28
- return name.trim().replace(/[^A-Za-z0-9_]+/g, '_') || 'robot';
29
- }
30
- function xmlEscape(value) {
31
- return value
32
- .replace(/&/g, '&amp;')
33
- .replace(/</g, '&lt;')
34
- .replace(/>/g, '&gt;')
35
- .replace(/"/g, '&quot;')
36
- .replace(/'/g, '&apos;');
37
- }
38
- function asRecord(value) {
39
- return value && typeof value === 'object' && !Array.isArray(value)
40
- ? value
41
- : {};
42
- }
43
- function asNumber(value, fallback) {
44
- return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
45
- }
46
- function asString(value, fallback) {
47
- return typeof value === 'string' && value.trim().length > 0 ? value : fallback;
48
- }
49
- function asVec3(value, fallback) {
50
- if (Array.isArray(value) && value.length >= 3) {
51
- return [asNumber(value[0], fallback[0]), asNumber(value[1], fallback[1]), asNumber(value[2], fallback[2])];
52
- }
53
- return fallback;
54
- }
55
- function asJointLimits(value, fallback) {
56
- if (Array.isArray(value) && value.length >= 4) {
57
- return {
58
- lower: asNumber(value[0], fallback?.lower ?? -1.57),
59
- upper: asNumber(value[1], fallback?.upper ?? 1.57),
60
- effort: asNumber(value[2], fallback?.effort ?? 10),
61
- velocity: asNumber(value[3], fallback?.velocity ?? 1),
62
- };
63
- }
64
- const record = asRecord(value);
65
- if (Object.keys(record).length > 0) {
66
- return {
67
- lower: asNumber(record.lower, fallback?.lower ?? -1.57),
68
- upper: asNumber(record.upper, fallback?.upper ?? 1.57),
69
- effort: asNumber(record.effort, fallback?.effort ?? 10),
70
- velocity: asNumber(record.velocity, fallback?.velocity ?? 1),
71
- };
72
- }
73
- return fallback;
74
- }
75
- function findTrait(node, predicate) {
76
- for (const trait of node.traits ?? []) {
77
- const normalizedName = normalizeTraitName(trait.name);
78
- if (predicate(normalizedName)) {
79
- return { normalizedName, trait };
80
- }
81
- }
82
- return null;
83
- }
84
- function getJointTrait(node) {
85
- return findTrait(node, (name) => name === 'joint' ||
86
- name === 'hinge' ||
87
- name === 'slider' ||
88
- name.startsWith('joint_'));
89
- }
90
- function getMotorTrait(node) {
91
- return findTrait(node, (name) => name === 'motor' || name === 'servo' || name === 'actuator' || name.endsWith('_motor'));
92
- }
93
- function jointTypeFromTrait(jointTrait, nodeProps, defaultJointType) {
94
- const explicitType = normalizeTraitName(asString(nodeProps.joint_type ?? nodeProps.type, defaultJointType));
95
- switch (explicitType) {
96
- case 'revolute':
97
- case 'prismatic':
98
- case 'fixed':
99
- case 'continuous':
100
- return explicitType;
101
- case 'hinge':
102
- return 'revolute';
103
- case 'slider':
104
- return 'prismatic';
105
- }
106
- switch (jointTrait?.normalizedName) {
107
- case 'joint_revolute':
108
- case 'hinge':
109
- return 'revolute';
110
- case 'joint_prismatic':
111
- case 'slider':
112
- return 'prismatic';
113
- case 'joint_continuous':
114
- return 'continuous';
115
- case 'joint_fixed':
116
- return 'fixed';
117
- default:
118
- return defaultJointType;
119
- }
120
- }
121
- function hardwareInterfaceFromMotor(motorProps) {
122
- const commandMode = normalizeTraitName(asString(motorProps.commandMode ?? motorProps.mode, 'position'));
123
- if (commandMode === 'velocity')
124
- return 'velocity';
125
- if (commandMode === 'effort' || commandMode === 'torque')
126
- return 'effort';
127
- return 'position';
128
- }
129
- function scaleMass(mass, hardwareScale) {
130
- return Number((mass * Math.pow(hardwareScale, 3)).toFixed(6));
131
- }
132
- function mapNodeToRobotLink(node, hardwareScale) {
133
- const props = asRecord(node.properties);
134
- const baseMass = asNumber(props.mass, 1);
135
- const inertia = Array.isArray(props.inertia)
136
- ? props.inertia.map((value) => asNumber(value, 0))
137
- : [0.01, 0.01, 0.01, 0, 0, 0];
138
- const geometry = asString(props.geometry, node.type ?? 'box');
139
- const material = typeof props.material === 'string' ? props.material : undefined;
140
- const collisionGeometry = asString(props.collisionGeometry ?? props.geometry, geometry);
141
- return {
142
- name: sanitizeRobotName(node.name || node.id || 'link'),
143
- inertial: {
144
- mass: scaleMass(baseMass, hardwareScale),
145
- inertia,
146
- },
147
- visual: {
148
- geometry,
149
- material,
150
- },
151
- collision: {
152
- geometry: collisionGeometry,
153
- },
154
- };
155
- }
156
- function createTransmission(jointName, motorProps, hardwareScale) {
157
- return {
158
- name: sanitizeRobotName(asString(motorProps.name, `${jointName}_transmission`)),
159
- joint: jointName,
160
- actuator: sanitizeRobotName(asString(motorProps.actuator ?? motorProps.name, `${jointName}_motor`)),
161
- mechanicalReduction: Number((asNumber(motorProps.mechanicalReduction ?? motorProps.gearRatio, 1) * hardwareScale).toFixed(6)),
162
- hardwareInterface: hardwareInterfaceFromMotor(motorProps),
163
- };
164
- }
165
- function buildLinkXml(link) {
166
- const lines = [` <link name="${xmlEscape(link.name)}">`];
167
- if (link.inertial) {
168
- const [ixx = 0.01, iyy = 0.01, izz = 0.01, ixy = 0, ixz = 0, iyz = 0] = link.inertial.inertia;
169
- lines.push(' <inertial>');
170
- lines.push(` <mass value="${link.inertial.mass}"/>`);
171
- lines.push(` <inertia ixx="${ixx}" iyy="${iyy}" izz="${izz}" ixy="${ixy}" ixz="${ixz}" iyz="${iyz}"/>`);
172
- lines.push(' </inertial>');
173
- }
174
- if (link.visual) {
175
- lines.push(' <visual>');
176
- lines.push(` <geometry><mesh filename="${xmlEscape(link.visual.geometry)}"/></geometry>`);
177
- if (link.visual.material) {
178
- lines.push(` <material name="${xmlEscape(link.visual.material)}"/>`);
179
- }
180
- lines.push(' </visual>');
181
- }
182
- if (link.collision) {
183
- lines.push(' <collision>');
184
- lines.push(` <geometry><mesh filename="${xmlEscape(link.collision.geometry)}"/></geometry>`);
185
- lines.push(' </collision>');
186
- }
187
- lines.push(' </link>');
188
- return lines.join('\n');
189
- }
190
- function buildJointXml(joint) {
191
- const lines = [` <joint name="${xmlEscape(joint.name)}" type="${joint.type}">`];
192
- lines.push(` <parent link="${xmlEscape(joint.parent_link)}"/>`);
193
- lines.push(` <child link="${xmlEscape(joint.child_link)}"/>`);
194
- if (joint.axis) {
195
- lines.push(` <axis xyz="${joint.axis.join(' ')}"/>`);
196
- }
197
- if (joint.limits && joint.type !== 'fixed') {
198
- lines.push(` <limit lower="${joint.limits.lower}" upper="${joint.limits.upper}" effort="${joint.limits.effort}" velocity="${joint.limits.velocity}"/>`);
199
- }
200
- lines.push(' </joint>');
201
- return lines.join('\n');
202
- }
203
- function buildTransmissionXml(transmission) {
204
- return [
205
- ` <transmission name="${xmlEscape(transmission.name)}">`,
206
- ' <type>transmission_interface/SimpleTransmission</type>',
207
- ` <joint name="${xmlEscape(transmission.joint)}">`,
208
- ` <hardwareInterface>${transmission.hardwareInterface}</hardwareInterface>`,
209
- ' </joint>',
210
- ` <actuator name="${xmlEscape(transmission.actuator)}">`,
211
- ' <hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>',
212
- ` <mechanicalReduction>${transmission.mechanicalReduction}</mechanicalReduction>`,
213
- ' </actuator>',
214
- ' </transmission>',
215
- ].join('\n');
216
- }
217
- export function buildURDFXML(model) {
218
- const lines = [`<robot name="${xmlEscape(model.name)}">`];
219
- lines.push(...model.links.map(buildLinkXml));
220
- lines.push(...model.joints.map(buildJointXml));
221
- lines.push(...model.transmissions.map(buildTransmissionXml));
222
- lines.push('</robot>');
223
- return lines.join('\n');
224
- }
225
- export function extractURDFFromHoloComposition(composition, options = {}) {
226
- const defaultJointType = options.defaultJointType ?? 'fixed';
227
- const defaultAxis = options.defaultAxis ?? DEFAULT_URDF_AXIS;
228
- const hardwareScale = options.hardwareScale ?? 1;
229
- const links = [];
230
- const joints = [];
231
- const transmissions = [];
232
- const visitNode = (node, parentLinkName) => {
233
- const props = asRecord(node.properties);
234
- const link = mapNodeToRobotLink(node, hardwareScale);
235
- links.push(link);
236
- const jointTrait = getJointTrait(node);
237
- const motorTrait = getMotorTrait(node);
238
- const jointName = sanitizeRobotName(asString(props.jointName, `${link.name}_joint`));
239
- if (parentLinkName && jointTrait) {
240
- const limits = asJointLimits(props.joint_limits ?? props.limits, {
241
- lower: -1.57,
242
- upper: 1.57,
243
- effort: 10 * hardwareScale,
244
- velocity: 1 * hardwareScale,
245
- });
246
- const joint = {
247
- name: jointName,
248
- type: jointTypeFromTrait(jointTrait, props, defaultJointType),
249
- parent_link: sanitizeRobotName(parentLinkName),
250
- child_link: link.name,
251
- axis: asVec3(props.joint_axis ?? props.axis, defaultAxis),
252
- limits,
253
- };
254
- joints.push(joint);
255
- if (motorTrait) {
256
- const motorProps = {
257
- ...props,
258
- ...asRecord(motorTrait.trait.properties),
259
- };
260
- transmissions.push(createTransmission(joint.name, motorProps, hardwareScale));
261
- }
262
- }
263
- for (const child of node.children ?? []) {
264
- visitNode(child, link.name);
265
- }
266
- };
267
- const baseLinkName = sanitizeRobotName(options.baseLinkName ?? `${composition.name}_base`);
268
- links.push({
269
- name: baseLinkName,
270
- inertial: {
271
- mass: scaleMass(1, hardwareScale),
272
- inertia: [0.01, 0.01, 0.01, 0, 0, 0],
273
- },
274
- visual: {
275
- geometry: 'base_link',
276
- },
277
- collision: {
278
- geometry: 'base_link',
279
- },
280
- });
281
- for (const child of composition.children ?? []) {
282
- visitNode(child, baseLinkName);
283
- }
284
- const modelWithoutXml = {
285
- name: sanitizeRobotName(composition.name),
286
- links,
287
- joints,
288
- transmissions,
289
- };
290
- return {
291
- ...modelWithoutXml,
292
- xml: buildURDFXML(modelWithoutXml),
293
- };
294
- }
295
- // Traits
296
- export * from './traits/ROS2HardwareLoopTrait';
297
- // Version
298
- export const VERSION = '1.0.0';
299
- // Re-export for convenience
300
- export default {
301
- VERSION,
302
- buildURDFXML,
303
- extractURDFFromHoloComposition,
304
- generateIsaacLabFeed,
305
- };
306
- export function generateIsaacLabFeed(ast, opts = {}) {
307
- const version = opts.isaacLabVersion || '2.3';
308
- const codegen = new USDCodeGen({ isaacLabVersion: version });
309
- const usd = codegen.generate(ast);
310
- // Pull randomization + actuators that the AST already carries
311
- const randomization = ast.domainRandomization;
312
- const actuators = [];
313
- for (const obj of ast.objects ?? []) {
314
- if (obj.actuatorGroups)
315
- actuators.push(...obj.actuatorGroups);
316
- }
317
- // Minimal Isaac Lab task config stub (observations / actions / randomization ranges)
318
- const taskConfig = {
319
- env: 'HoloScriptRobotEnv',
320
- num_envs: 4096,
321
- seed: 42,
322
- observations: ['joint_pos', 'joint_vel', 'imu'],
323
- actions: ['joint_torques'],
324
- randomization: randomization || {},
325
- actuator_groups: actuators,
326
- source: 'holoscript',
327
- usd_prim: ast.name,
328
- };
329
- // Simple content hashes for the receipt (evidence loop)
330
- const sourceHoloHash = `holo:${ast.name}:${(ast.objects?.length || 0)}`;
331
- const usdHash = `usd:${usd.length}`;
332
- const configHash = `cfg:${JSON.stringify(taskConfig).length}`;
333
- const receipt = {
334
- sourceHoloHash,
335
- usdHash,
336
- configHash,
337
- generatedAt: new Date().toISOString(),
338
- isaacLabVersion: version,
339
- readyForTraining: true,
340
- notes: 'Narrow feed bundle — assets + randomization + actuator config. Policy training & real-robot eval are downstream.',
341
- };
342
- return {
343
- usd,
344
- taskConfig,
345
- randomization,
346
- actuators,
347
- receipt,
348
- };
349
- }
package/dist/lexer.d.ts DELETED
@@ -1,52 +0,0 @@
1
- /**
2
- * HoloScript Lexer (Tokenizer)
3
- *
4
- * Converts HoloScript source code into a stream of tokens for parsing.
5
- * Supports: keywords, identifiers, traits (@trait), strings, numbers, symbols
6
- */
7
- export declare enum TokenType {
8
- KEYWORD = "KEYWORD",// composition, object, using, template, group
9
- IDENTIFIER = "IDENTIFIER",// variable_name, link1, base
10
- TRAIT = "TRAIT",// @joint_revolute, @force_sensor
11
- STRING = "STRING",// "Base", "metal", "cylinder"
12
- NUMBER = "NUMBER",// 0.1, 3.14, 100, -2.0
13
- LBRACE = "LBRACE",// {
14
- RBRACE = "RBRACE",// }
15
- LBRACKET = "LBRACKET",// [
16
- RBRACKET = "RBRACKET",// ]
17
- COLON = "COLON",// :
18
- COMMA = "COMMA",// ,
19
- COMMENT = "COMMENT",// // comment
20
- EOF = "EOF"
21
- }
22
- export interface Token {
23
- type: TokenType;
24
- value: string;
25
- line: number;
26
- column: number;
27
- }
28
- export declare class Lexer {
29
- private source;
30
- private position;
31
- private line;
32
- private column;
33
- private tokens;
34
- private readonly keywords;
35
- constructor(source: string);
36
- tokenize(): Token[];
37
- private scanToken;
38
- private scanTrait;
39
- private scanString;
40
- private scanNumber;
41
- private scanIdentifierOrKeyword;
42
- private scanSymbol;
43
- private skipWhitespace;
44
- private skipComment;
45
- private currentChar;
46
- private peek;
47
- private advance;
48
- private isWhitespace;
49
- private isDigit;
50
- private isAlpha;
51
- private isAlphaNumericOrUnderscore;
52
- }