@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 ADDED
@@ -0,0 +1,13 @@
1
+ # @holoscript/robotics-plugin
2
+
3
+ Robotics plugin for HoloScript compile-time USD/URDF generation and ROS2/Gazebo
4
+ integration surfaces.
5
+
6
+ ## Public Consumption
7
+
8
+ ```js
9
+ import { Parser, USDCodeGen, extractURDFFromHoloComposition } from '@holoscript/robotics-plugin';
10
+ ```
11
+
12
+ The package root ships built JavaScript and declaration files. It does not
13
+ expose TypeScript source as the public runtime entry.
package/dist/index.d.ts CHANGED
@@ -14,14 +14,14 @@
14
14
  *
15
15
  * @packageDocumentation
16
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';
17
+ export { USDCodeGen } from './usd-codegen.js';
18
+ export type { IsaacLabConfig } from './usd-codegen.js';
19
+ export { Lexer, TokenType } from './lexer.js';
20
+ export type { Token } from './lexer.js';
21
+ export { Parser } from './parser.js';
22
+ export * from './ast.js';
23
+ export type { DomainRandomizationConfig, ActuatorGroupConfig } from './ast.js';
24
+ import type { CompositionNode, DomainRandomizationConfig, ActuatorGroupConfig } from './ast.js';
25
25
  export interface ROS2Config {
26
26
  ros_bridge_url: string;
27
27
  namespace?: string;
@@ -97,7 +97,7 @@ export interface URDFExtractionOptions {
97
97
  }
98
98
  export declare function buildURDFXML(model: Omit<ExtractedRobotModel, 'xml'>): string;
99
99
  export declare function extractURDFFromHoloComposition(composition: HoloCompositionTreeLike, options?: URDFExtractionOptions): ExtractedRobotModel;
100
- export * from './traits/ROS2HardwareLoopTrait';
100
+ export * from './traits/ROS2HardwareLoopTrait.js';
101
101
  export declare const VERSION = "1.0.0";
102
102
  declare const _default: {
103
103
  VERSION: string;
package/dist/index.js CHANGED
@@ -15,11 +15,11 @@
15
15
  * @packageDocumentation
16
16
  */
17
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';
18
+ export { USDCodeGen } from './usd-codegen.js';
19
+ export { Lexer, TokenType } from './lexer.js';
20
+ export { Parser } from './parser.js';
21
+ export * from './ast.js';
22
+ import { USDCodeGen } from './usd-codegen.js';
23
23
  const DEFAULT_URDF_AXIS = [0, 0, 1];
24
24
  function normalizeTraitName(name) {
25
25
  return name.replace(/^@/, '').trim().toLowerCase();
@@ -48,7 +48,11 @@ function asString(value, fallback) {
48
48
  }
49
49
  function asVec3(value, fallback) {
50
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])];
51
+ return [
52
+ asNumber(value[0], fallback[0]),
53
+ asNumber(value[1], fallback[1]),
54
+ asNumber(value[2], fallback[2]),
55
+ ];
52
56
  }
53
57
  return fallback;
54
58
  }
@@ -82,10 +86,7 @@ function findTrait(node, predicate) {
82
86
  return null;
83
87
  }
84
88
  function getJointTrait(node) {
85
- return findTrait(node, (name) => name === 'joint' ||
86
- name === 'hinge' ||
87
- name === 'slider' ||
88
- name.startsWith('joint_'));
89
+ return findTrait(node, (name) => name === 'joint' || name === 'hinge' || name === 'slider' || name.startsWith('joint_'));
89
90
  }
90
91
  function getMotorTrait(node) {
91
92
  return findTrait(node, (name) => name === 'motor' || name === 'servo' || name === 'actuator' || name.endsWith('_motor'));
@@ -293,7 +294,7 @@ export function extractURDFFromHoloComposition(composition, options = {}) {
293
294
  };
294
295
  }
295
296
  // Traits
296
- export * from './traits/ROS2HardwareLoopTrait';
297
+ export * from './traits/ROS2HardwareLoopTrait.js';
297
298
  // Version
298
299
  export const VERSION = '1.0.0';
299
300
  // Re-export for convenience
@@ -327,7 +328,7 @@ export function generateIsaacLabFeed(ast, opts = {}) {
327
328
  usd_prim: ast.name,
328
329
  };
329
330
  // Simple content hashes for the receipt (evidence loop)
330
- const sourceHoloHash = `holo:${ast.name}:${(ast.objects?.length || 0)}`;
331
+ const sourceHoloHash = `holo:${ast.name}:${ast.objects?.length || 0}`;
331
332
  const usdHash = `usd:${usd.length}`;
332
333
  const configHash = `cfg:${JSON.stringify(taskConfig).length}`;
333
334
  const receipt = {
package/dist/parser.d.ts CHANGED
@@ -4,8 +4,8 @@
4
4
  * Converts token stream into Abstract Syntax Tree (AST).
5
5
  * Uses recursive descent parsing.
6
6
  */
7
- import { Token } from './lexer';
8
- import { CompositionNode } from './ast';
7
+ import { Token } from './lexer.js';
8
+ import { CompositionNode } from './ast.js';
9
9
  export declare class Parser {
10
10
  private tokens;
11
11
  private position;
package/dist/parser.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Converts token stream into Abstract Syntax Tree (AST).
5
5
  * Uses recursive descent parsing.
6
6
  */
7
- import { TokenType } from './lexer';
7
+ import { TokenType } from './lexer.js';
8
8
  export class Parser {
9
9
  constructor(tokens) {
10
10
  this.position = 0;
@@ -0,0 +1,5 @@
1
+ export declare const ROBOTICS_PLUGIN_ID: "robotics";
2
+ export interface TraitRegistrar {
3
+ registerTrait(name: string, handler: unknown): void;
4
+ }
5
+ export declare function registerRoboticsTraitHandlers(registrar: TraitRegistrar): void;
@@ -0,0 +1,6 @@
1
+ import { registerPluginTraits } from '@holoscript/core/runtime';
2
+ import { createROS2HardwareLoopHandler } from './traits/ROS2HardwareLoopTrait.js';
3
+ export const ROBOTICS_PLUGIN_ID = 'robotics';
4
+ export function registerRoboticsTraitHandlers(registrar) {
5
+ registerPluginTraits(registrar, ROBOTICS_PLUGIN_ID, [createROS2HardwareLoopHandler()]);
6
+ }
@@ -11,5 +11,5 @@ export interface ROS2State {
11
11
  activeTopics: string[];
12
12
  hardwareSyncDriftMs: number;
13
13
  }
14
- import type { TraitHandler } from './types';
14
+ import type { TraitHandler } from './types.js';
15
15
  export declare function createROS2HardwareLoopHandler(): TraitHandler<ROS2Config>;
@@ -1,9 +1,19 @@
1
1
  export function createROS2HardwareLoopHandler() {
2
2
  return {
3
3
  name: 'ros2_hardware_loop',
4
- defaultConfig: { nodeName: 'holo_rig_01', topicPrefix: '/holo', updateFrequencyHz: 60, bidirectional: true },
4
+ defaultConfig: {
5
+ nodeName: 'holo_rig_01',
6
+ topicPrefix: '/holo',
7
+ updateFrequencyHz: 60,
8
+ bidirectional: true,
9
+ },
5
10
  onAttach(n, c, ctx) {
6
- n.__ros2State = { connected: false, lastPingMs: 0, activeTopics: [], hardwareSyncDriftMs: 0 };
11
+ n.__ros2State = {
12
+ connected: false,
13
+ lastPingMs: 0,
14
+ activeTopics: [],
15
+ hardwareSyncDriftMs: 0,
16
+ };
7
17
  ctx.emit?.('ros2:init', { node: c.nodeName });
8
18
  },
9
19
  onDetach(n, _c, ctx) {
@@ -25,7 +35,10 @@ export function createROS2HardwareLoopHandler() {
25
35
  case 'scene:transform_change':
26
36
  if (c.bidirectional && s.connected) {
27
37
  // Push virtual set transform to physical robot joint
28
- ctx.emit?.('ros2:publish', { topic: `${c.topicPrefix}/joint_cmd`, payload: evt.payload });
38
+ ctx.emit?.('ros2:publish', {
39
+ topic: `${c.topicPrefix}/joint_cmd`,
40
+ payload: evt.payload,
41
+ });
29
42
  }
30
43
  break;
31
44
  case 'ros2:telemetry':
@@ -40,10 +53,12 @@ export function createROS2HardwareLoopHandler() {
40
53
  const dynamicTopic = `${c.topicPrefix}/ttu_sync/${crdtRoot}`;
41
54
  s.activeTopics.push(dynamicTopic);
42
55
  ctx.emit?.('ros2:subscribe', { topic: dynamicTopic });
43
- ctx.emit?.('ros2:log', { message: `Bridged digital twin for TTU root: ${crdtRoot}` });
56
+ ctx.emit?.('ros2:log', {
57
+ message: `Bridged digital twin for TTU root: ${crdtRoot}`,
58
+ });
44
59
  }
45
60
  break;
46
61
  }
47
- }
62
+ },
48
63
  };
49
64
  }
@@ -9,7 +9,7 @@
9
9
  * - Emits PhysxJointAxisAPI for per-axis joint friction assumptions
10
10
  * - Supports domain randomization metadata for sim-to-real transfer
11
11
  */
12
- import { CompositionNode } from './ast';
12
+ import { CompositionNode } from './ast.js';
13
13
  export interface IsaacLabConfig {
14
14
  /** Isaac Lab version target for generated code */
15
15
  isaacLabVersion?: string;
@@ -376,7 +376,8 @@ export class USDCodeGen {
376
376
  return schemas;
377
377
  }
378
378
  hasDriveProperties(props) {
379
- return this.numberProp(props, 'kp', 'stiffness', 'kd', 'damping', 'joint_effort', 'max_effort') !== undefined;
379
+ return (this.numberProp(props, 'kp', 'stiffness', 'kd', 'damping', 'joint_effort', 'max_effort') !==
380
+ undefined);
380
381
  }
381
382
  hasPhysxJointAxisProperties(props) {
382
383
  return (this.numberProp(props, 'joint_friction', 'friction', 'joint_static_friction', 'joint_dynamic_friction', 'joint_viscous_friction', 'armature', 'max_velocity') !== undefined);
package/package.json CHANGED
@@ -1,8 +1,22 @@
1
1
  {
2
2
  "name": "@holoscript/robotics-plugin",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "HoloScript plugin for robotics: compile-time USD/URDF codegen + runtime ROS2/Gazebo integration. VR robot programming and digital twins.",
5
- "main": "src/index.ts",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "LICENSE",
11
+ "README.md",
12
+ "plugin.manifest.json"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "test": "vitest run",
17
+ "clean": "rimraf dist",
18
+ "test:coverage": "vitest run --coverage"
19
+ },
6
20
  "keywords": [
7
21
  "holoscript",
8
22
  "plugin",
@@ -17,15 +31,9 @@
17
31
  "author": "HoloScript Contributors",
18
32
  "license": "MIT",
19
33
  "peerDependencies": {
20
- "@holoscript/core": "8.0.6"
34
+ "@holoscript/core": ">=8.0.0"
21
35
  },
22
36
  "engines": {
23
37
  "node": ">=20.0.0"
24
- },
25
- "scripts": {
26
- "build": "tsc",
27
- "test": "vitest run",
28
- "clean": "rimraf dist",
29
- "test:coverage": "vitest run --coverage"
30
38
  }
31
- }
39
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "id": "robotics-plugin",
3
+ "version": "2.0.2",
4
+ "name": "Robotics",
5
+ "description": "HoloScript plugin for robotics: compile-time USD/URDF codegen + runtime ROS2/Gazebo integration. VR robot programming and digital twins.",
6
+ "traits": ["ros2_hardware_loop"],
7
+ "autoRegister": true,
8
+ "coreVersion": ">=8.0.0",
9
+ "runtimeEntry": "./src/runtime.ts"
10
+ }
package/CHANGELOG.md DELETED
@@ -1,14 +0,0 @@
1
- # @holoscript/robotics-plugin
2
-
3
- ## 2.0.1
4
-
5
- ### Patch Changes
6
-
7
- - Updated dependencies [c64fc1a]
8
- - @holoscript/core@8.0.6
9
-
10
- ## 2.0.0
11
-
12
- ### Patch Changes
13
-
14
- - @holoscript/core@6.1.0
@@ -1,63 +0,0 @@
1
- # Isaac Lab Sim-to-Real Bridge Prototype v0.1
2
- # Task: task_1779183224900_643n [p3][build] — minimal bridge (idea-seed 51)
3
- # Source memo: research/2026-04-19_isaac-lab-sim-to-real.md (Claude 2026-04-19)
4
- #
5
- # Demonstrates the *declarative authoring surface* for Path A (HoloScript → Isaac Lab feed).
6
- # This composition is the thinnest runnable example that encodes the sim-to-real
7
- # parameters identified in the memo (§1.1–1.3): domain randomization, non-ideal actuators,
8
- # and future USD friction schema.
9
- #
10
- # Current state (2026-05-19): parser ignores the @isaac_lab block (no IsaacLabCompiler yet).
11
- # Future: usd-codegen.ts emits PhysxArticulationAPI + drive:* + joint-friction schema;
12
- # IsaacLabCompiler.ts emits ManagerBasedRLEnvCfg + EventTermCfg references.
13
- #
14
- # See packages/plugins/robotics-plugin/python/isaac_lab_bridge.py for the matching
15
- # thin shim that "executes" the bridge concept without requiring an Isaac Sim license.
16
-
17
- robot spot {
18
- # Base from existing robotics examples (robot-arm-complete.holo)
19
- @urdf_export "spot.urdf"
20
- @usd_export "spot.usd"
21
- @ros_node { topic: "/joint_states", rate_hz: 30 }
22
-
23
- @isaac_lab {
24
- # Memo Path A, step 3 (DR vocabulary) + step 4 (actuator groups)
25
- actuator_model: "DelayedPDActuator", # maps to isaaclab.actuators.DelayedPDActuator
26
- actuator_groups: {
27
- legs: { kp: 120.0, kd: 8.0, latency_ms: 4 } # explicit comms delay (sim-to-real)
28
- }
29
-
30
- domain_randomization: {
31
- # EventTermCfg targets (isaaclab.envs.mdp.*)
32
- rigid_body_mass: { range: [0.95, 1.05], mode: "reset" }
33
- rigid_body_friction: { range: [0.7, 1.3], mode: "reset" }
34
- joint_damping: { range: [0.8, 1.2], mode: "interval", interval_s: 2.0 }
35
- push_force: { magnitude: 120, interval_s: [3, 12] }
36
- }
37
-
38
- observation_noise: {
39
- joint_pos: 0.012,
40
- joint_vel: 0.025,
41
- imu: 0.018
42
- }
43
-
44
- # Future: emit PhysxJointFrictionAPI / PhysxArticulation:friction:* (memo §1.4)
45
- joint_friction_schema: "physx"
46
- }
47
-
48
- # Minimal kinematic skeleton (enough for USD/Isaac import)
49
- base_link { mass: 12.0 }
50
- joints {
51
- FL_hip { type: revolute, axis: "y", limits: [-1.57, 1.57] }
52
- FL_knee { type: revolute, axis: "x", limits: [-2.5, 2.5 ] }
53
- # ... (truncated for prototype; full 12-DOF in real Spot asset)
54
- }
55
- }
56
-
57
- # Done criteria for this task satisfied by:
58
- # - 1 runnable demo: python .../isaac_lab_bridge.py (emits Isaac Lab stub config)
59
- # - Docs: this file header + memo cross-ref + py docstring
60
- # - Thin interop shim: maps HoloScript declarative → Isaac Lab EventTermCfg/ActuatorCfg
61
- #
62
- # Next (out of scope for p3): full IsaacLabCompiler.ts + usd-codegen patches (memo steps 1-5).
63
- # Verification: see commit that landed these two files + `python` execution output.
@@ -1,127 +0,0 @@
1
- // Isaac Lab Sim-to-Real Example
2
- // Demonstrates Path A: HoloScript -> Isaac Lab asset/export
3
- // Features:
4
- // - PhysicsDriveAPI for PD actuator control
5
- // - PhysxJointAxisAPI for per-axis joint friction assumptions
6
- // - Domain randomization configuration
7
- // - Delayed actuator metadata for communication latency
8
-
9
- composition "TwoLinkArm_IsaacLab" {
10
- // Domain randomization at composition level
11
- // These values are emitted as comments for Isaac Lab Python codegen
12
- domain_randomization: {
13
- physics: {
14
- massScale: [0.8, 1.2]
15
- frictionRange: [0.3, 0.7]
16
- dampingRange: [0.0, 0.1]
17
- armatureRange: [0.0001, 0.002]
18
- }
19
- actuator: {
20
- kpNoise: 0.1
21
- kdNoise: 0.05
22
- latencyNoise: 0.002
23
- }
24
- observation: {
25
- jointPosNoise: 0.001
26
- jointVelNoise: 0.01
27
- imuNoise: 0.005
28
- }
29
- initialState: {
30
- rootPoseRange: [-0.5, 0.5, -0.5, 0.5, 0.0, 1.0]
31
- }
32
- disturbance: {
33
- forceRange: [0.0, 5.0]
34
- intervalRange: [1.0, 3.0]
35
- }
36
- }
37
-
38
- object "base_link" {
39
- @static
40
- geometry: "cylinder"
41
- radius: 0.1
42
- height: 0.05
43
- mass: 2.0
44
- position: [0, 0, 0]
45
- material: "metal"
46
- }
47
-
48
- object "joint1" {
49
- @joint_revolute
50
- joint_parent: "base_link"
51
- joint_origin: [0, 0, 0.05]
52
- joint_axis: [0, 0, 1]
53
- joint_limits: [-3.14, 3.14]
54
- joint_effort: 50
55
- max_velocity: 3.14
56
- // PD gains for Isaac Lab drive control
57
- kp: 100.0
58
- kd: 10.0
59
- // Joint friction (sim-to-real)
60
- joint_friction: 0.05
61
- joint_viscous_friction: 0.01
62
- armature: 0.001
63
- // Actuator latency for DelayedPDActuator
64
- actuator_latency: 0.005
65
- actuator_group: {
66
- name: "arm_group"
67
- type: "DelayedPDActuator"
68
- joints: ["joint1", "joint2"]
69
- stiffness: 100
70
- damping: 10
71
- friction: 0.05
72
- latency: 0.005
73
- }
74
- }
75
-
76
- object "link1" {
77
- @joint_revolute
78
- joint_parent: "joint1"
79
- geometry: "cylinder"
80
- radius: 0.05
81
- length: 0.3
82
- mass: 1.0
83
- position: [0, 0, 0.15]
84
- material: "metal"
85
- // Inertia tensor
86
- inertia: [0.01, 0.01, 0.001, 0, 0, 0]
87
- // PD gains
88
- kp: 80.0
89
- kd: 8.0
90
- joint_friction: 0.03
91
- }
92
-
93
- object "joint2" {
94
- @joint_revolute
95
- joint_parent: "link1"
96
- joint_origin: [0, 0, 0.3]
97
- joint_axis: [0, 1, 0]
98
- joint_limits: [-1.57, 1.57]
99
- joint_effort: 30
100
- max_velocity: 3.14
101
- kp: 80.0
102
- kd: 8.0
103
- joint_friction: 0.03
104
- actuator_latency: 0.005
105
- }
106
-
107
- object "link2" {
108
- geometry: "cylinder"
109
- radius: 0.04
110
- length: 0.25
111
- mass: 0.8
112
- position: [0, 0, 0.125]
113
- material: "metal"
114
- inertia: [0.005, 0.005, 0.0008, 0, 0, 0]
115
- kp: 60.0
116
- kd: 6.0
117
- joint_friction: 0.02
118
- }
119
-
120
- object "end_effector" {
121
- geometry: "sphere"
122
- radius: 0.03
123
- mass: 0.2
124
- position: [0, 0, 0.25]
125
- material: "plastic"
126
- }
127
- }
@@ -1,157 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Minimal Isaac Lab Sim-to-Real Bridge Shim (HoloScript prototype v0.1)
4
- Task: task_1779183224900_643n [p3][build] — from idea-seed 51
5
-
6
- Source: research/2026-04-19_isaac-lab-sim-to-real.md (memo §1, §3 Path A)
7
-
8
- Runnable demo (no Isaac Sim / GPU required):
9
- python packages/plugins/robotics-plugin/python/isaac_lab_bridge.py
10
-
11
- What it does (thin interop shim):
12
- - Takes a declarative HoloScript-style robot spec (the @isaac_lab block from
13
- the companion .holo example).
14
- - Emits a stub of the exact Python objects Isaac Lab 2.3+ expects:
15
- * EventTermCfg list for domain randomization (mdp.* functions)
16
- * ActuatorCfg using DelayedPDActuator (memo §1.3)
17
- - This is the "runnable demo" half of the p3 deliverable. The .holo is the
18
- "example composition" half.
19
-
20
- Real compiler work (out of scope for this minimal p3 task):
21
- - IsaacLabCompiler.ts (packages/plugins/robotics-plugin/src/isaaclab-compiler.ts)
22
- - usd-codegen.ts patches for PhysxArticulationAPI + joint-friction schema
23
- - Parser support for domain_randomization { } and actuator groups
24
-
25
- See the .holo file header for the exact mapping and memo citations.
26
- """
27
-
28
- from __future__ import annotations
29
- import json
30
- from typing import Any, Dict
31
-
32
-
33
- def emit_isaac_lab_stub(holo_spec: Dict[str, Any]) -> str:
34
- """
35
- Core of the bridge shim.
36
- holo_spec mirrors the @isaac_lab block + top-level robot attrs from the .holo.
37
- Returns a multi-line string that is valid Python for a real Isaac Lab env cfg.
38
- """
39
- name = holo_spec.get("name", "spot")
40
- actuator_model = holo_spec.get("actuator_model", "DelayedPDActuator")
41
- dr = holo_spec.get("domain_randomization", {})
42
- obs_noise = holo_spec.get("observation_noise", {})
43
-
44
- # Build the EventTermCfg fragments exactly as Isaac Lab expects them
45
- # (references, not implementations — per memo recommendation)
46
- dr_terms = []
47
- if "rigid_body_mass" in dr:
48
- rng = dr["rigid_body_mass"].get("range", [0.95, 1.05])
49
- dr_terms.append(
50
- f' "randomize_mass": EventTermCfg(\n'
51
- f' func=mdp.randomize_rigid_body_mass,\n'
52
- f' mode="{dr["rigid_body_mass"].get("mode", "reset")}",\n'
53
- f' params={{"mass_range": {rng}}}\n'
54
- f' ),'
55
- )
56
- if "rigid_body_friction" in dr:
57
- rng = dr["rigid_body_friction"].get("range", [0.7, 1.3])
58
- dr_terms.append(
59
- f' "randomize_friction": EventTermCfg(\n'
60
- f' func=mdp.randomize_rigid_body_friction,\n'
61
- f' mode="{dr["rigid_body_friction"].get("mode", "reset")}",\n'
62
- f' params={{"friction_range": {rng}}}\n'
63
- f' ),'
64
- )
65
- if "push_force" in dr:
66
- mag = dr["push_force"].get("magnitude", 120)
67
- iv = dr["push_force"].get("interval_s", [3, 12])
68
- dr_terms.append(
69
- f' "push_perturbation": EventTermCfg(\n'
70
- f' func=mdp.push_perturbation,\n'
71
- f' mode="interval",\n'
72
- f' interval_s={iv},\n'
73
- f' params={{"force_range": [{-mag}, {mag}]}}\n'
74
- f' ),'
75
- )
76
-
77
- dr_block = "\n".join(dr_terms) if dr_terms else " # (no DR terms in spec)"
78
-
79
- # Observation noise example (memo §1.2)
80
- noise_lines = []
81
- for k, v in obs_noise.items():
82
- noise_lines.append(f' # noise on {k}: UniformNoiseCfg(mean=0.0, std={v})')
83
- noise_block = "\n".join(noise_lines) if noise_lines else " # (no explicit noise)"
84
-
85
- # Actuator (the hard sim-to-real piece — memo §1.3)
86
- actuator_comment = (
87
- f"# Actuator model: {actuator_model}\n"
88
- f"# Future: map HoloScript actuator_groups to isaaclab.actuators.{actuator_model}\n"
89
- f"# (DelayedPDActuator simulates the 4-8 ms network latency that breaks real policies)"
90
- )
91
-
92
- code = f'''# === Isaac Lab 2.3+ env config stub (generated by HoloScript bridge shim v0.1) ===
93
- # Task: task_1779183224900_643n
94
- # Memo: research/2026-04-19_isaac-lab-sim-to-real.md (Path A, steps 1-4)
95
- # Source .holo: packages/plugins/robotics-plugin/examples/isaac-lab-sim-to-real-bridge.holo
96
-
97
- from isaaclab.envs import ManagerBasedRLEnvCfg
98
- from isaaclab.envs.mdp import EventTermCfg
99
- import isaaclab.envs.mdp as mdp
100
- # from isaaclab.actuators import DelayedPDActuator, ActuatorCfg # real import
101
-
102
- {actuator_comment}
103
-
104
- env_cfg = ManagerBasedRLEnvCfg(
105
- # scene, observations, actions, rewards would be emitted from full .holo compile
106
- )
107
-
108
- # Domain randomization (memo §1.1) — the primary sim-to-real lever
109
- env_cfg.events = {{
110
- {dr_block}
111
- }}
112
-
113
- # Observation noise (memo §1.2)
114
- {noise_block}
115
-
116
- print("Isaac Lab bridge prototype: config emitted for", {json.dumps(name)})
117
- print("Actuator model requested:", {json.dumps(actuator_model)})
118
- print("DR terms generated:", {len(dr_terms)})
119
- return "SUCCESS: thin interop shim executed — HoloScript spec → Isaac Lab EventTermCfg/ActuatorCfg"
120
- '''
121
-
122
- return code
123
-
124
-
125
- def main() -> None:
126
- # Exact spec pulled from the companion .holo example (the "runnable demo" data)
127
- sample_holo_spec: Dict[str, Any] = {
128
- "name": "spot",
129
- "actuator_model": "DelayedPDActuator",
130
- "actuator_groups": {
131
- "legs": {"kp": 120.0, "kd": 8.0, "latency_ms": 4}
132
- },
133
- "domain_randomization": {
134
- "rigid_body_mass": {"range": [0.95, 1.05], "mode": "reset"},
135
- "rigid_body_friction": {"range": [0.7, 1.3], "mode": "reset"},
136
- "push_force": {"magnitude": 120, "interval_s": [3, 12]},
137
- },
138
- "observation_noise": {
139
- "joint_pos": 0.012,
140
- "joint_vel": 0.025,
141
- "imu": 0.018,
142
- },
143
- }
144
-
145
- print("=== HoloScript → Isaac Lab minimal bridge prototype (task_1779183224900_643n) ===")
146
- print("Loading spec from isaac-lab-sim-to-real-bridge.holo (simulated)")
147
- result = emit_isaac_lab_stub(sample_holo_spec)
148
- print(result)
149
- print("\n=== End of demo ===")
150
- print("Files delivered for p3 task:")
151
- print(" - examples/isaac-lab-sim-to-real-bridge.holo (example composition + docs)")
152
- print(" - python/isaac_lab_bridge.py (runnable shim + 1 demo)")
153
- print("Both files committed with explicit paths only.")
154
-
155
-
156
- if __name__ == "__main__":
157
- main()