@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
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 [
|
|
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}:${
|
|
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
package/dist/runtime.js
ADDED
|
@@ -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: {
|
|
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 = {
|
|
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', {
|
|
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', {
|
|
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
|
}
|
package/dist/usd-codegen.d.ts
CHANGED
|
@@ -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;
|
package/dist/usd-codegen.js
CHANGED
|
@@ -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') !==
|
|
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.
|
|
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
|
-
"
|
|
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.
|
|
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,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()
|