mujoco-react 8.4.1 → 8.5.0
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 +79 -22
- package/dist/index.d.ts +65 -1
- package/dist/index.js +96 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ObservationBuilder.ts +120 -0
- package/src/hooks/useObservation.ts +38 -0
- package/src/index.ts +8 -0
- package/src/types.ts +45 -0
package/README.md
CHANGED
|
@@ -100,6 +100,58 @@ function ResetButton() {
|
|
|
100
100
|
}
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
+
## Map Controls to Joints
|
|
104
|
+
|
|
105
|
+
Use control groups when a robot's actuator order does not match a simple `qpos[0..n]` layout:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import { useRef } from "react";
|
|
109
|
+
import { resolveControlGroup, useBeforePhysicsStep } from "mujoco-react";
|
|
110
|
+
import type { ControlGroupInfo } from "mujoco-react";
|
|
111
|
+
|
|
112
|
+
function HoldTcpPose() {
|
|
113
|
+
const armRef = useRef<ControlGroupInfo | null>(null);
|
|
114
|
+
|
|
115
|
+
useBeforePhysicsStep((model, data) => {
|
|
116
|
+
armRef.current ??= resolveControlGroup(model, { siteName: "tcp" });
|
|
117
|
+
if (!armRef.current) return;
|
|
118
|
+
|
|
119
|
+
armRef.current.writeCtrl(data, armRef.current.readQpos(data));
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`resolveControlGroup()` accepts `{ siteName }`, `{ bodyName }`, `{ joints }`, or `{ actuators }`. Selectors can be a name, ordered name array, regex, or predicate.
|
|
127
|
+
|
|
128
|
+
## Build Observations
|
|
129
|
+
|
|
130
|
+
Build policy-ready observation vectors from common MuJoCo state without hard-coding offsets:
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
import { buildObservation, useBeforePhysicsStep } from "mujoco-react";
|
|
134
|
+
|
|
135
|
+
function PolicyDriver() {
|
|
136
|
+
useBeforePhysicsStep((model, data) => {
|
|
137
|
+
const obs = buildObservation(model, data, {
|
|
138
|
+
qpos: true,
|
|
139
|
+
qvel: true,
|
|
140
|
+
ctrl: true,
|
|
141
|
+
sensors: ["imu_gyro", "imu_accel"],
|
|
142
|
+
sites: ["tcp"],
|
|
143
|
+
projectedGravity: "torso",
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
runPolicy(obs.values, obs.layout);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Use `output: "float64"` when a downstream model expects double precision. Named resources are skipped when absent, so `obs.layout` is the source of truth for the current model.
|
|
154
|
+
|
|
103
155
|
## WebSocket Control
|
|
104
156
|
|
|
105
157
|
Stream actuator commands over a WebSocket and send simulation state back. Use a schema validator such as Zod at this boundary because socket messages are untrusted app input (`npm install zod` for this example):
|
|
@@ -109,32 +161,28 @@ import { useEffect, useRef } from "react";
|
|
|
109
161
|
import { z } from "zod";
|
|
110
162
|
import { useMujoco, useBeforePhysicsStep, useAfterPhysicsStep } from "mujoco-react";
|
|
111
163
|
|
|
112
|
-
const CtrlCommand = z.
|
|
113
|
-
type: z.literal("ctrl_command"),
|
|
114
|
-
ctrl: z.array(z.number()),
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
type CtrlCommand = z.infer<typeof CtrlCommand>;
|
|
118
|
-
|
|
119
|
-
function parseSocketMessage(data: string): CtrlCommand | null {
|
|
164
|
+
const CtrlCommand = z.preprocess((data) => {
|
|
120
165
|
try {
|
|
121
|
-
|
|
122
|
-
return parsed.success ? parsed.data : null;
|
|
166
|
+
return typeof data === "string" ? JSON.parse(data) : data;
|
|
123
167
|
} catch {
|
|
124
|
-
return
|
|
168
|
+
return undefined;
|
|
125
169
|
}
|
|
126
|
-
}
|
|
170
|
+
}, z.object({
|
|
171
|
+
type: z.literal("ctrl_command"),
|
|
172
|
+
ctrl: z.array(z.number()),
|
|
173
|
+
}));
|
|
127
174
|
|
|
128
175
|
function useWebSocketControls(url: string) {
|
|
129
176
|
const wsRef = useRef<WebSocket | null>(null);
|
|
130
|
-
const
|
|
177
|
+
const latestCtrlRef = useRef<number[] | null>(null);
|
|
131
178
|
|
|
132
179
|
useEffect(() => {
|
|
133
180
|
const ws = new WebSocket(url);
|
|
134
181
|
wsRef.current = ws;
|
|
135
182
|
|
|
136
183
|
ws.onmessage = (evt) => {
|
|
137
|
-
|
|
184
|
+
const command = CtrlCommand.safeParse(evt.data);
|
|
185
|
+
if (command.success) latestCtrlRef.current = command.data.ctrl;
|
|
138
186
|
};
|
|
139
187
|
|
|
140
188
|
return () => ws.close();
|
|
@@ -142,10 +190,10 @@ function useWebSocketControls(url: string) {
|
|
|
142
190
|
|
|
143
191
|
// Apply incoming actuator controls each physics step.
|
|
144
192
|
useBeforePhysicsStep((model, data) => {
|
|
145
|
-
const
|
|
146
|
-
if (!
|
|
147
|
-
for (let i = 0; i < Math.min(
|
|
148
|
-
data.ctrl[i] =
|
|
193
|
+
const ctrl = latestCtrlRef.current;
|
|
194
|
+
if (!ctrl) return;
|
|
195
|
+
for (let i = 0; i < Math.min(ctrl.length, model.nu); i++) {
|
|
196
|
+
data.ctrl[i] = ctrl[i];
|
|
149
197
|
}
|
|
150
198
|
});
|
|
151
199
|
|
|
@@ -659,13 +707,19 @@ useGamepad({
|
|
|
659
707
|
Framework-agnostic decimation loop for RL policies:
|
|
660
708
|
|
|
661
709
|
```tsx
|
|
662
|
-
const {
|
|
710
|
+
const obs = useObservation({ qpos: true, qvel: true, projectedGravity: "torso" });
|
|
711
|
+
|
|
712
|
+
const policy = usePolicy({
|
|
663
713
|
frequency: 50,
|
|
664
|
-
onObservation: (
|
|
714
|
+
onObservation: () => obs.readValues(),
|
|
665
715
|
onAction: (action, model, data) => applyAction(action, data),
|
|
666
716
|
});
|
|
667
717
|
```
|
|
668
718
|
|
|
719
|
+
### `buildObservation(model, data, config)` / `useObservation(config)`
|
|
720
|
+
|
|
721
|
+
Build a flat `Float32Array` or `Float64Array` plus a layout map from qpos, qvel, ctrl, actuator activations, sensordata, named sensors, named site positions, and projected gravity.
|
|
722
|
+
|
|
669
723
|
### `useTrajectoryRecorder(config)` / `useTrajectoryPlayer(trajectory, config)`
|
|
670
724
|
|
|
671
725
|
Record and play back simulation trajectories:
|
|
@@ -770,7 +824,11 @@ The full API object available via `ref` or `useMujoco()` (when `isReady`):
|
|
|
770
824
|
| `setQpos(values)` / `getQpos()` | Direct qpos access |
|
|
771
825
|
| `setQvel(values)` / `getQvel()` | Direct qvel access |
|
|
772
826
|
| `setCtrl(nameOrValues, value?)` | Set control by name or batch |
|
|
773
|
-
| `getCtrl(
|
|
827
|
+
| `getCtrl()` | Get all control values |
|
|
828
|
+
| `getControlMap()` | Map directly actuated scalar joints to qpos/dof/ctrl addresses |
|
|
829
|
+
| `getActuatedJoints()` | List scalar hinge/slide joints with matching actuators |
|
|
830
|
+
| `resolveControlGroup(selector)` | Resolve qpos/ctrl mapping from a site, body, joint selector, or actuator selector |
|
|
831
|
+
| `buildObservation(model, data, config)` | Build policy-ready observation vectors with layout metadata |
|
|
774
832
|
| `applyKeyframe(nameOrIndex)` | Apply a keyframe |
|
|
775
833
|
| `getKeyframeNames()` / `getKeyframeCount()` | Keyframe introspection |
|
|
776
834
|
|
|
@@ -861,7 +919,6 @@ Features planned but not yet implemented:
|
|
|
861
919
|
| **User-uploaded model loading** | P2 | `loadFromFiles(FileList)` -- detect meshdir, write to VFS |
|
|
862
920
|
| **URDF loading** | P2 | Load URDF models via MuJoCo's built-in URDF compiler |
|
|
863
921
|
| **XML mutation / recompile** | P1 | `addBody()`, `removeBody()`, `recompile()` for runtime XML editing |
|
|
864
|
-
| **Observation builder utilities** | P2 | Helpers for projected gravity, joint positions/velocities for RL |
|
|
865
922
|
| **Physics interpolation** | P1 | Smooth rendering between physics ticks for very high refresh displays |
|
|
866
923
|
| **Instanced geom rendering** | P2 | `<InstancedGeomRenderer />` for particle/granular sims |
|
|
867
924
|
| **Web Worker physics** | P2 | Run `mj_step` off main thread via SharedArrayBuffer |
|
package/dist/index.d.ts
CHANGED
|
@@ -477,6 +477,44 @@ interface PolicyConfig {
|
|
|
477
477
|
onObservation: (model: MujocoModel, data: MujocoData) => Float32Array | Float64Array | number[];
|
|
478
478
|
onAction: (action: Float32Array | Float64Array | number[], model: MujocoModel, data: MujocoData) => void;
|
|
479
479
|
}
|
|
480
|
+
type ObservationOutput = 'float32' | 'float64';
|
|
481
|
+
interface ObservationConfig {
|
|
482
|
+
/** Include scalar simulation time. */
|
|
483
|
+
time?: boolean;
|
|
484
|
+
/** Include all qpos values. */
|
|
485
|
+
qpos?: boolean;
|
|
486
|
+
/** Include all qvel values. */
|
|
487
|
+
qvel?: boolean;
|
|
488
|
+
/** Include all ctrl values. */
|
|
489
|
+
ctrl?: boolean;
|
|
490
|
+
/** Include all actuator activation values. */
|
|
491
|
+
act?: boolean;
|
|
492
|
+
/** Include all raw sensordata values. */
|
|
493
|
+
sensordata?: boolean;
|
|
494
|
+
/** Include named sensor values in the configured order. */
|
|
495
|
+
sensors?: readonly Sensors[];
|
|
496
|
+
/** Include named site world positions in the configured order. */
|
|
497
|
+
sites?: readonly Sites[];
|
|
498
|
+
/** Include world gravity projected into each named body's local frame. */
|
|
499
|
+
projectedGravity?: Bodies | readonly Bodies[];
|
|
500
|
+
/** Output array type. Defaults to Float32Array. */
|
|
501
|
+
output?: ObservationOutput;
|
|
502
|
+
}
|
|
503
|
+
interface ObservationLayoutItem {
|
|
504
|
+
name: string;
|
|
505
|
+
start: number;
|
|
506
|
+
size: number;
|
|
507
|
+
}
|
|
508
|
+
interface ObservationResult {
|
|
509
|
+
values: Float32Array | Float64Array;
|
|
510
|
+
layout: ObservationLayoutItem[];
|
|
511
|
+
}
|
|
512
|
+
interface ObservationHandle {
|
|
513
|
+
/** Read a fresh observation from the current live MuJoCo model/data refs. */
|
|
514
|
+
read(): ObservationResult;
|
|
515
|
+
/** Read just the vector values for policy inference. */
|
|
516
|
+
readValues(): Float32Array | Float64Array;
|
|
517
|
+
}
|
|
480
518
|
interface DebugProps {
|
|
481
519
|
showGeoms?: boolean;
|
|
482
520
|
showSites?: boolean;
|
|
@@ -831,6 +869,19 @@ interface LoadResult {
|
|
|
831
869
|
*/
|
|
832
870
|
declare function loadScene(mujoco: MujocoModule, config: SceneConfig, onProgress?: (msg: string) => void): Promise<LoadResult>;
|
|
833
871
|
|
|
872
|
+
/**
|
|
873
|
+
* @license
|
|
874
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
875
|
+
*/
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* Build a flat observation vector plus a layout map from live MuJoCo state.
|
|
879
|
+
*
|
|
880
|
+
* Missing named resources are skipped. The returned layout is the source of
|
|
881
|
+
* truth for the vector produced from the current model.
|
|
882
|
+
*/
|
|
883
|
+
declare function buildObservation(model: MujocoModel, data: MujocoData, config: ObservationConfig): ObservationResult;
|
|
884
|
+
|
|
834
885
|
/**
|
|
835
886
|
* @license
|
|
836
887
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -1182,6 +1233,19 @@ declare function usePolicy(config: PolicyConfig): {
|
|
|
1182
1233
|
readonly lastObservation: Float64Array<ArrayBufferLike> | Float32Array<ArrayBufferLike> | number[] | null;
|
|
1183
1234
|
};
|
|
1184
1235
|
|
|
1236
|
+
/**
|
|
1237
|
+
* @license
|
|
1238
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
1239
|
+
*/
|
|
1240
|
+
|
|
1241
|
+
/**
|
|
1242
|
+
* Live observation reader for policy loops and telemetry.
|
|
1243
|
+
*
|
|
1244
|
+
* The handle is stable; call `read()` inside callbacks to sample the latest
|
|
1245
|
+
* MuJoCo model/data state without forcing React renders.
|
|
1246
|
+
*/
|
|
1247
|
+
declare function useObservation(config: ObservationConfig): ObservationHandle;
|
|
1248
|
+
|
|
1185
1249
|
/**
|
|
1186
1250
|
* @license
|
|
1187
1251
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -1386,4 +1450,4 @@ interface CameraAnimationAPI {
|
|
|
1386
1450
|
*/
|
|
1387
1451
|
declare function useCameraAnimation(): CameraAnimationAPI;
|
|
1388
1452
|
|
|
1389
|
-
export { type ActuatedJointInfo, type ActuatorInfo, type Actuators, type Bodies, Body, type BodyInfo, type BodyProps, type BodyStateResult, type CameraAnimationAPI, type ContactInfo, ContactListener, type ContactListenerProps, ContactMarkers, type ControlGroupInfo, type ControlGroupSelector, type ControlJointInfo, type ControllerComponent, type ControllerOptions, type CtrlHandle, Debug, type DebugProps, DragInteraction, type DragInteractionProps, FlexRenderer, type GeomInfo, type Geoms, type IKSolveFn, type IkConfig, type IkContextValue, IkGizmo, type IkGizmoProps, type JointInfo, type JointStateResult, type Joints, type KeyBinding, type KeyboardTeleopConfig, type Keyframes, type ModelOptions, MujocoCanvas, type MujocoCanvasProps, type MujocoContact, type MujocoContactArray, type MujocoContextValue, type MujocoData, type MujocoLoader, type MujocoLoaderOptions, type MujocoModel, type MujocoModule, MujocoPhysics, type MujocoPhysicsProps, MujocoProvider, type MujocoProviderProps, type MujocoSimAPI, MujocoSimProvider, type MujocoWasmVariant, type PhysicsConfig, type PhysicsStepCallback, type PlaybackState, type PolicyConfig, type RayHit, type Register, type ResourceSelector, type SceneConfig, SceneLights, type SceneLightsProps, type SceneMarker, type SceneObject, type SensorHandle, type SensorInfo, type SensorResult, type Sensors, type SiteInfo, type SitePositionResult, type Sites, type StateSnapshot, TendonRenderer, type TrajectoryData, type TrajectoryFrame, type TrajectoryInput, TrajectoryPlayer, type TrajectoryPlayerProps, type XmlPatch, createContiguousControlGroup, createController, createControllerHook, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getContact, getControlMap, getName, loadScene, resolveControlGroup, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyState, useCameraAnimation, useContactEvents, useContacts, useCtrl, useCtrlNoise, useGamepad, useGravityCompensation, useIkController, useJointState, useKeyboardTeleop, useMujoco, useMujocoWasm, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
|
|
1453
|
+
export { type ActuatedJointInfo, type ActuatorInfo, type Actuators, type Bodies, Body, type BodyInfo, type BodyProps, type BodyStateResult, type CameraAnimationAPI, type ContactInfo, ContactListener, type ContactListenerProps, ContactMarkers, type ControlGroupInfo, type ControlGroupSelector, type ControlJointInfo, type ControllerComponent, type ControllerOptions, type CtrlHandle, Debug, type DebugProps, DragInteraction, type DragInteractionProps, FlexRenderer, type GeomInfo, type Geoms, type IKSolveFn, type IkConfig, type IkContextValue, IkGizmo, type IkGizmoProps, type JointInfo, type JointStateResult, type Joints, type KeyBinding, type KeyboardTeleopConfig, type Keyframes, type ModelOptions, MujocoCanvas, type MujocoCanvasProps, type MujocoContact, type MujocoContactArray, type MujocoContextValue, type MujocoData, type MujocoLoader, type MujocoLoaderOptions, type MujocoModel, type MujocoModule, MujocoPhysics, type MujocoPhysicsProps, MujocoProvider, type MujocoProviderProps, type MujocoSimAPI, MujocoSimProvider, type MujocoWasmVariant, type ObservationConfig, type ObservationHandle, type ObservationLayoutItem, type ObservationOutput, type ObservationResult, type PhysicsConfig, type PhysicsStepCallback, type PlaybackState, type PolicyConfig, type RayHit, type Register, type ResourceSelector, type SceneConfig, SceneLights, type SceneLightsProps, type SceneMarker, type SceneObject, type SensorHandle, type SensorInfo, type SensorResult, type Sensors, type SiteInfo, type SitePositionResult, type Sites, type StateSnapshot, TendonRenderer, type TrajectoryData, type TrajectoryFrame, type TrajectoryInput, TrajectoryPlayer, type TrajectoryPlayerProps, type XmlPatch, buildObservation, createContiguousControlGroup, createController, createControllerHook, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getContact, getControlMap, getName, loadScene, resolveControlGroup, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyState, useCameraAnimation, useContactEvents, useContacts, useCtrl, useCtrlNoise, useGamepad, useGravityCompensation, useIkController, useJointState, useKeyboardTeleop, useMujoco, useMujocoWasm, useObservation, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
|
package/dist/index.js
CHANGED
|
@@ -1953,6 +1953,81 @@ var MujocoPhysics = forwardRef(
|
|
|
1953
1953
|
);
|
|
1954
1954
|
}
|
|
1955
1955
|
);
|
|
1956
|
+
|
|
1957
|
+
// src/core/ObservationBuilder.ts
|
|
1958
|
+
function append(values, layout, name, chunk) {
|
|
1959
|
+
const start = values.length;
|
|
1960
|
+
for (let i = 0; i < chunk.length; i++) values.push(chunk[i] ?? 0);
|
|
1961
|
+
layout.push({ name, start, size: chunk.length });
|
|
1962
|
+
}
|
|
1963
|
+
function appendScalar(values, layout, name, value) {
|
|
1964
|
+
const start = values.length;
|
|
1965
|
+
values.push(value);
|
|
1966
|
+
layout.push({ name, start, size: 1 });
|
|
1967
|
+
}
|
|
1968
|
+
function namedBodyList(names) {
|
|
1969
|
+
if (!names) return [];
|
|
1970
|
+
return typeof names === "string" ? [names] : names;
|
|
1971
|
+
}
|
|
1972
|
+
function normalizedGravity(model) {
|
|
1973
|
+
const gx = model.opt.gravity[0] ?? 0;
|
|
1974
|
+
const gy = model.opt.gravity[1] ?? 0;
|
|
1975
|
+
const gz = model.opt.gravity[2] ?? -9.81;
|
|
1976
|
+
const length = Math.hypot(gx, gy, gz);
|
|
1977
|
+
if (length === 0) return [0, 0, 0];
|
|
1978
|
+
return [gx / length, gy / length, gz / length];
|
|
1979
|
+
}
|
|
1980
|
+
function rotateWorldVectorToBody(data, bodyId, world) {
|
|
1981
|
+
const adr = bodyId * 4;
|
|
1982
|
+
const w = data.xquat[adr] ?? 1;
|
|
1983
|
+
const x = -(data.xquat[adr + 1] ?? 0);
|
|
1984
|
+
const y = -(data.xquat[adr + 2] ?? 0);
|
|
1985
|
+
const z = -(data.xquat[adr + 3] ?? 0);
|
|
1986
|
+
const vx = world[0];
|
|
1987
|
+
const vy = world[1];
|
|
1988
|
+
const vz = world[2];
|
|
1989
|
+
const tx = 2 * (y * vz - z * vy);
|
|
1990
|
+
const ty = 2 * (z * vx - x * vz);
|
|
1991
|
+
const tz = 2 * (x * vy - y * vx);
|
|
1992
|
+
return [
|
|
1993
|
+
vx + w * tx + y * tz - z * ty,
|
|
1994
|
+
vy + w * ty + z * tx - x * tz,
|
|
1995
|
+
vz + w * tz + x * ty - y * tx
|
|
1996
|
+
];
|
|
1997
|
+
}
|
|
1998
|
+
function buildObservation(model, data, config) {
|
|
1999
|
+
const values = [];
|
|
2000
|
+
const layout = [];
|
|
2001
|
+
if (config.time) appendScalar(values, layout, "time", data.time);
|
|
2002
|
+
if (config.qpos) append(values, layout, "qpos", data.qpos);
|
|
2003
|
+
if (config.qvel) append(values, layout, "qvel", data.qvel);
|
|
2004
|
+
if (config.ctrl) append(values, layout, "ctrl", data.ctrl);
|
|
2005
|
+
if (config.act) append(values, layout, "act", data.act);
|
|
2006
|
+
if (config.sensordata) append(values, layout, "sensordata", data.sensordata);
|
|
2007
|
+
for (const name of config.sensors ?? []) {
|
|
2008
|
+
const sensorId = findSensorByName(model, name);
|
|
2009
|
+
if (sensorId < 0) continue;
|
|
2010
|
+
const start = model.sensor_adr[sensorId] ?? 0;
|
|
2011
|
+
const dim = model.sensor_dim[sensorId] ?? 0;
|
|
2012
|
+
append(values, layout, `sensor:${name}`, data.sensordata.subarray(start, start + dim));
|
|
2013
|
+
}
|
|
2014
|
+
for (const name of config.sites ?? []) {
|
|
2015
|
+
const siteId = findSiteByName(model, name);
|
|
2016
|
+
if (siteId < 0) continue;
|
|
2017
|
+
const start = siteId * 3;
|
|
2018
|
+
append(values, layout, `site:${name}:xpos`, data.site_xpos.subarray(start, start + 3));
|
|
2019
|
+
}
|
|
2020
|
+
const gravity = normalizedGravity(model);
|
|
2021
|
+
for (const name of namedBodyList(config.projectedGravity)) {
|
|
2022
|
+
const bodyId = findBodyByName(model, name);
|
|
2023
|
+
if (bodyId < 0) continue;
|
|
2024
|
+
append(values, layout, `projectedGravity:${name}`, rotateWorldVectorToBody(data, bodyId, gravity));
|
|
2025
|
+
}
|
|
2026
|
+
return {
|
|
2027
|
+
values: config.output === "float64" ? new Float64Array(values) : new Float32Array(values),
|
|
2028
|
+
layout
|
|
2029
|
+
};
|
|
2030
|
+
}
|
|
1956
2031
|
function shallowEqual(a, b) {
|
|
1957
2032
|
const keysA = Object.keys(a);
|
|
1958
2033
|
const keysB = Object.keys(b);
|
|
@@ -4086,6 +4161,26 @@ function usePolicy(config) {
|
|
|
4086
4161
|
}
|
|
4087
4162
|
};
|
|
4088
4163
|
}
|
|
4164
|
+
var EMPTY_OBSERVATION = {
|
|
4165
|
+
values: new Float32Array(0),
|
|
4166
|
+
layout: []
|
|
4167
|
+
};
|
|
4168
|
+
function useObservation(config) {
|
|
4169
|
+
const { mjModelRef, mjDataRef } = useMujocoContext();
|
|
4170
|
+
const configRef = useRef(config);
|
|
4171
|
+
configRef.current = config;
|
|
4172
|
+
return useMemo(() => ({
|
|
4173
|
+
read() {
|
|
4174
|
+
const model = mjModelRef.current;
|
|
4175
|
+
const data = mjDataRef.current;
|
|
4176
|
+
if (!model || !data) return EMPTY_OBSERVATION;
|
|
4177
|
+
return buildObservation(model, data, configRef.current);
|
|
4178
|
+
},
|
|
4179
|
+
readValues() {
|
|
4180
|
+
return this.read().values;
|
|
4181
|
+
}
|
|
4182
|
+
}), [mjDataRef, mjModelRef]);
|
|
4183
|
+
}
|
|
4089
4184
|
function useTrajectoryRecorder(options = {}) {
|
|
4090
4185
|
const { mjModelRef } = useMujocoContext();
|
|
4091
4186
|
const recordingRef = useRef(false);
|
|
@@ -4573,6 +4668,6 @@ function useCameraAnimation() {
|
|
|
4573
4668
|
* useCameraAnimation — composable camera animation hook.
|
|
4574
4669
|
*/
|
|
4575
4670
|
|
|
4576
|
-
export { Body, ContactListener, ContactMarkers, Debug, DragInteraction, FlexRenderer, IkGizmo, MujocoCanvas, MujocoPhysics, MujocoProvider, MujocoSimProvider, SceneLights, TendonRenderer, TrajectoryPlayer, createContiguousControlGroup, createController, createControllerHook, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getContact, getControlMap, getName, loadScene, resolveControlGroup, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyState, useCameraAnimation, useContactEvents, useContacts, useCtrl, useCtrlNoise, useGamepad, useGravityCompensation, useIkController, useJointState, useKeyboardTeleop, useMujoco, useMujocoWasm, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
|
|
4671
|
+
export { Body, ContactListener, ContactMarkers, Debug, DragInteraction, FlexRenderer, IkGizmo, MujocoCanvas, MujocoPhysics, MujocoProvider, MujocoSimProvider, SceneLights, TendonRenderer, TrajectoryPlayer, buildObservation, createContiguousControlGroup, createController, createControllerHook, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getContact, getControlMap, getName, loadScene, resolveControlGroup, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyState, useCameraAnimation, useContactEvents, useContacts, useCtrl, useCtrlNoise, useGamepad, useGravityCompensation, useIkController, useJointState, useKeyboardTeleop, useMujoco, useMujocoWasm, useObservation, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
|
|
4577
4672
|
//# sourceMappingURL=index.js.map
|
|
4578
4673
|
//# sourceMappingURL=index.js.map
|