mujoco-react 7.0.0 → 8.0.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 +37 -17
- package/dist/index.d.ts +86 -27
- package/dist/index.js +35 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/hooks/useBodyState.ts +2 -2
- package/src/hooks/useContacts.ts +3 -3
- package/src/hooks/useCtrl.ts +31 -18
- package/src/hooks/useJointState.ts +2 -2
- package/src/hooks/useSensor.ts +14 -5
- package/src/hooks/useSitePosition.ts +2 -2
- package/src/index.ts +11 -0
- package/src/types.ts +62 -13
package/README.md
CHANGED
|
@@ -70,17 +70,14 @@ Inside `<MujocoCanvas>` or `<MujocoPhysics>`, `useMujoco()` gives you the simula
|
|
|
70
70
|
import { useMujoco } from 'mujoco-react';
|
|
71
71
|
|
|
72
72
|
function MyComponent() {
|
|
73
|
-
const { api,
|
|
74
|
-
const sim = useMujoco();
|
|
73
|
+
const { isPending, isError, error, api, mjModelRef } = useMujoco();
|
|
75
74
|
|
|
76
|
-
if (
|
|
77
|
-
if (
|
|
78
|
-
if (sim.isError) return <span>Error: {sim.error}</span>;
|
|
75
|
+
if (isPending) return <span>Loading...</span>;
|
|
76
|
+
if (isError) return <span>Error: {error}</span>;
|
|
79
77
|
|
|
80
|
-
// sim.api is fully typed here
|
|
81
78
|
return (
|
|
82
|
-
<button onClick={() =>
|
|
83
|
-
Reset ({
|
|
79
|
+
<button onClick={() => api.reset()}>
|
|
80
|
+
Reset ({mjModelRef.current?.nq} joints)
|
|
84
81
|
</button>
|
|
85
82
|
);
|
|
86
83
|
}
|
|
@@ -88,15 +85,18 @@ function MyComponent() {
|
|
|
88
85
|
|
|
89
86
|
## Writing a Controller
|
|
90
87
|
|
|
91
|
-
A controller is a React component that
|
|
88
|
+
A controller is a React component that uses handle-based hooks for type-safe actuator and sensor access:
|
|
92
89
|
|
|
93
90
|
```tsx
|
|
94
|
-
import { useBeforePhysicsStep } from 'mujoco-react';
|
|
91
|
+
import { useCtrl, useSensor, useBeforePhysicsStep } from 'mujoco-react';
|
|
95
92
|
|
|
96
93
|
function MyController() {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
const joint1 = useCtrl('joint1');
|
|
95
|
+
const force = useSensor('force_sensor');
|
|
96
|
+
|
|
97
|
+
useBeforePhysicsStep(() => {
|
|
98
|
+
joint1.write(Math.sin(Date.now() / 1000));
|
|
99
|
+
joint1.write(force.read()[0] * -0.5);
|
|
100
100
|
});
|
|
101
101
|
return null;
|
|
102
102
|
}
|
|
@@ -178,6 +178,23 @@ Returns `IkContextValue | null` with methods like `setIkEnabled`, `moveTarget`,
|
|
|
178
178
|
|
|
179
179
|
Pass the returned value to `<IkGizmo controller={ik} />` or to your own controller as a prop.
|
|
180
180
|
|
|
181
|
+
## Type-Safe Resource Names
|
|
182
|
+
|
|
183
|
+
Use TypeScript module augmentation to get autocomplete and type checking for actuator, sensor, body, joint, site, geom, and keyframe names:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
// e.g. in src/mujoco-register.d.ts
|
|
187
|
+
declare module 'mujoco-react' {
|
|
188
|
+
interface Register {
|
|
189
|
+
actuators: 'joint1' | 'joint2' | 'joint3' | 'gripper';
|
|
190
|
+
sensors: 'force_sensor' | 'torque_sensor';
|
|
191
|
+
bodies: 'link0' | 'link1' | 'hand';
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Once declared, hooks like `useCtrl`, `useSensor`, `useBodyState`, and API methods like `setCtrl`, `applyForce`, `getSensorData` will only accept the declared names. When no `Register` augmentation is provided, all names fall back to `string`.
|
|
197
|
+
|
|
181
198
|
## Loading Models
|
|
182
199
|
|
|
183
200
|
The loader fetches `src + sceneFile`, parses the XML for dependencies (meshes, textures, includes), recursively fetches those too, and writes everything to MuJoCo's in-memory WASM filesystem.
|
|
@@ -469,10 +486,11 @@ await moveCameraTo(
|
|
|
469
486
|
|
|
470
487
|
### `useSensor(name)` / `useSensors()`
|
|
471
488
|
|
|
472
|
-
Read sensor values by name (
|
|
489
|
+
Read sensor values by name. Returns a `SensorHandle` with `read()`, `dim`, and `name`:
|
|
473
490
|
|
|
474
491
|
```tsx
|
|
475
|
-
const
|
|
492
|
+
const force = useSensor('force_sensor_1');
|
|
493
|
+
// force.read() → Float64Array, force.dim → number
|
|
476
494
|
```
|
|
477
495
|
|
|
478
496
|
### `useBodyState(name)`
|
|
@@ -493,10 +511,11 @@ const { position, velocity } = useJointState('joint1');
|
|
|
493
511
|
|
|
494
512
|
### `useCtrl(name)`
|
|
495
513
|
|
|
496
|
-
Read/write actuator control by name
|
|
514
|
+
Read/write actuator control by name. Returns a `CtrlHandle` with `read()`, `write()`, `name`, and `range`:
|
|
497
515
|
|
|
498
516
|
```tsx
|
|
499
|
-
const
|
|
517
|
+
const gripper = useCtrl('gripper');
|
|
518
|
+
// gripper.read() → number, gripper.write(0.04), gripper.range → [min, max]
|
|
500
519
|
```
|
|
501
520
|
|
|
502
521
|
### `useContacts(bodyName?)` / `useContactEvents(bodyName, handlers)`
|
|
@@ -735,6 +754,7 @@ Features planned but not yet implemented:
|
|
|
735
754
|
| **Physics interpolation** | P1 | Smooth rendering between physics ticks for very high refresh displays |
|
|
736
755
|
| **Instanced geom rendering** | P2 | `<InstancedGeomRenderer />` for particle/granular sims |
|
|
737
756
|
| **Web Worker physics** | P2 | Run `mj_step` off main thread via SharedArrayBuffer |
|
|
757
|
+
| **Register codegen** | P2 | CLI to auto-generate `Register` type augmentation from MJCF XML |
|
|
738
758
|
|
|
739
759
|
### WASM Limitations (mujoco-js 0.0.7)
|
|
740
760
|
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,45 @@ import * as THREE from 'three';
|
|
|
9
9
|
* SPDX-License-Identifier: Apache-2.0
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Module augmentation interface for type-safe resource names.
|
|
14
|
+
*
|
|
15
|
+
* Declare your model's resource names via module augmentation:
|
|
16
|
+
* ```ts
|
|
17
|
+
* declare module 'mujoco-react' {
|
|
18
|
+
* interface Register {
|
|
19
|
+
* actuators: 'joint1' | 'joint2' | 'gripper';
|
|
20
|
+
* sensors: 'force_sensor' | 'torque_sensor';
|
|
21
|
+
* bodies: 'link0' | 'link1' | 'hand';
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* When no augmentation is declared, all names fall back to `string`.
|
|
27
|
+
*/
|
|
28
|
+
interface Register {
|
|
29
|
+
}
|
|
30
|
+
type Actuators = Register extends {
|
|
31
|
+
actuators: infer T extends string;
|
|
32
|
+
} ? T : string;
|
|
33
|
+
type Sensors = Register extends {
|
|
34
|
+
sensors: infer T extends string;
|
|
35
|
+
} ? T : string;
|
|
36
|
+
type Bodies = Register extends {
|
|
37
|
+
bodies: infer T extends string;
|
|
38
|
+
} ? T : string;
|
|
39
|
+
type Joints = Register extends {
|
|
40
|
+
joints: infer T extends string;
|
|
41
|
+
} ? T : string;
|
|
42
|
+
type Sites = Register extends {
|
|
43
|
+
sites: infer T extends string;
|
|
44
|
+
} ? T : string;
|
|
45
|
+
type Geoms = Register extends {
|
|
46
|
+
geoms: infer T extends string;
|
|
47
|
+
} ? T : string;
|
|
48
|
+
type Keyframes = Register extends {
|
|
49
|
+
keyframes: infer T extends string;
|
|
50
|
+
} ? T : string;
|
|
12
51
|
/**
|
|
13
52
|
* A single MuJoCo contact from the WASM module.
|
|
14
53
|
* Accessed via `data.contact.get(i)`.
|
|
@@ -245,7 +284,7 @@ interface SceneConfig {
|
|
|
245
284
|
}
|
|
246
285
|
interface IkConfig {
|
|
247
286
|
/** MuJoCo site name for IK target. */
|
|
248
|
-
siteName:
|
|
287
|
+
siteName: Sites;
|
|
249
288
|
/** Number of joints to solve for. */
|
|
250
289
|
numJoints: number;
|
|
251
290
|
/** Custom IK solver. When omitted, uses built-in Damped Least-Squares solver. */
|
|
@@ -365,7 +404,7 @@ interface TrajectoryData {
|
|
|
365
404
|
fps: number;
|
|
366
405
|
}
|
|
367
406
|
interface KeyBinding {
|
|
368
|
-
actuator:
|
|
407
|
+
actuator: Actuators;
|
|
369
408
|
delta?: number;
|
|
370
409
|
toggle?: [number, number];
|
|
371
410
|
set?: number;
|
|
@@ -410,12 +449,12 @@ interface TrajectoryPlayerProps {
|
|
|
410
449
|
onFrame?: (frameIdx: number) => void;
|
|
411
450
|
}
|
|
412
451
|
interface ContactListenerProps {
|
|
413
|
-
body:
|
|
452
|
+
body: Bodies;
|
|
414
453
|
onContactEnter?: (info: ContactInfo) => void;
|
|
415
454
|
onContactExit?: (info: ContactInfo) => void;
|
|
416
455
|
}
|
|
417
456
|
interface BodyProps {
|
|
418
|
-
name:
|
|
457
|
+
name: Bodies;
|
|
419
458
|
type: 'box' | 'sphere' | 'cylinder';
|
|
420
459
|
size: [number, number, number];
|
|
421
460
|
position?: [number, number, number];
|
|
@@ -438,20 +477,20 @@ interface MujocoSimAPI {
|
|
|
438
477
|
step(n?: number): void;
|
|
439
478
|
getTime(): number;
|
|
440
479
|
getTimestep(): number;
|
|
441
|
-
applyKeyframe(nameOrIndex:
|
|
480
|
+
applyKeyframe(nameOrIndex: Keyframes | number): void;
|
|
442
481
|
saveState(): StateSnapshot;
|
|
443
482
|
restoreState(snapshot: StateSnapshot): void;
|
|
444
483
|
setQpos(values: Float64Array | number[]): void;
|
|
445
484
|
setQvel(values: Float64Array | number[]): void;
|
|
446
485
|
getQpos(): Float64Array;
|
|
447
486
|
getQvel(): Float64Array;
|
|
448
|
-
setCtrl(nameOrValues:
|
|
487
|
+
setCtrl(nameOrValues: Actuators | Record<Actuators, number>, value?: number): void;
|
|
449
488
|
getCtrl(): Float64Array;
|
|
450
|
-
applyForce(bodyName:
|
|
451
|
-
applyTorque(bodyName:
|
|
452
|
-
setExternalForce(bodyName:
|
|
489
|
+
applyForce(bodyName: Bodies, force: THREE.Vector3, point?: THREE.Vector3): void;
|
|
490
|
+
applyTorque(bodyName: Bodies, torque: THREE.Vector3): void;
|
|
491
|
+
setExternalForce(bodyName: Bodies, force: THREE.Vector3, torque: THREE.Vector3): void;
|
|
453
492
|
applyGeneralizedForce(values: Float64Array | number[]): void;
|
|
454
|
-
getSensorData(name:
|
|
493
|
+
getSensorData(name: Sensors): Float64Array | null;
|
|
455
494
|
getContacts(): ContactInfo[];
|
|
456
495
|
getBodies(): BodyInfo[];
|
|
457
496
|
getJoints(): JointInfo[];
|
|
@@ -472,9 +511,9 @@ interface MujocoSimAPI {
|
|
|
472
511
|
bodyId: number;
|
|
473
512
|
geomId: number;
|
|
474
513
|
} | null;
|
|
475
|
-
setBodyMass(name:
|
|
476
|
-
setGeomFriction(name:
|
|
477
|
-
setGeomSize(name:
|
|
514
|
+
setBodyMass(name: Bodies, mass: number): void;
|
|
515
|
+
setGeomFriction(name: Geoms, friction: [number, number, number]): void;
|
|
516
|
+
setGeomSize(name: Geoms, size: [number, number, number]): void;
|
|
478
517
|
readonly mjModelRef: React__default.RefObject<MujocoModel | null>;
|
|
479
518
|
readonly mjDataRef: React__default.RefObject<MujocoData | null>;
|
|
480
519
|
}
|
|
@@ -499,10 +538,29 @@ interface MujocoContextValue {
|
|
|
499
538
|
status: 'loading' | 'ready' | 'error';
|
|
500
539
|
error: string | null;
|
|
501
540
|
}
|
|
541
|
+
/** @deprecated Use `SensorHandle` instead. */
|
|
502
542
|
interface SensorResult {
|
|
503
543
|
value: React__default.RefObject<Float64Array>;
|
|
504
544
|
size: number;
|
|
505
545
|
}
|
|
546
|
+
interface CtrlHandle {
|
|
547
|
+
/** Read the current ctrl value. */
|
|
548
|
+
read(): number;
|
|
549
|
+
/** Write a ctrl value (goes directly to data.ctrl). */
|
|
550
|
+
write(value: number): void;
|
|
551
|
+
/** Actuator name. */
|
|
552
|
+
name: Actuators;
|
|
553
|
+
/** Actuator control range [min, max]. */
|
|
554
|
+
range: [number, number];
|
|
555
|
+
}
|
|
556
|
+
interface SensorHandle {
|
|
557
|
+
/** Read the current sensor data. */
|
|
558
|
+
read(): Float64Array;
|
|
559
|
+
/** Sensor dimensionality. */
|
|
560
|
+
dim: number;
|
|
561
|
+
/** Sensor name. */
|
|
562
|
+
name: Sensors;
|
|
563
|
+
}
|
|
506
564
|
interface BodyStateResult {
|
|
507
565
|
position: React__default.RefObject<THREE.Vector3>;
|
|
508
566
|
quaternion: React__default.RefObject<THREE.Quaternion>;
|
|
@@ -862,7 +920,7 @@ declare function useActuators(): ActuatorInfo[];
|
|
|
862
920
|
* Returns reactive refs for a MuJoCo site's world position and orientation.
|
|
863
921
|
* Refs are updated every frame without triggering React re-renders.
|
|
864
922
|
*/
|
|
865
|
-
declare function useSitePosition(siteName:
|
|
923
|
+
declare function useSitePosition(siteName: Sites): SitePositionResult;
|
|
866
924
|
|
|
867
925
|
/**
|
|
868
926
|
* @license
|
|
@@ -885,10 +943,11 @@ declare function useGravityCompensation(enabled?: boolean): void;
|
|
|
885
943
|
*/
|
|
886
944
|
|
|
887
945
|
/**
|
|
888
|
-
* Access a single MuJoCo sensor by name. Returns a
|
|
889
|
-
*
|
|
946
|
+
* Access a single MuJoCo sensor by name. Returns a `SensorHandle` with
|
|
947
|
+
* `read()`, `dim`, and `name`. The backing array is updated every physics
|
|
948
|
+
* frame without causing React re-renders.
|
|
890
949
|
*/
|
|
891
|
-
declare function useSensor(name:
|
|
950
|
+
declare function useSensor(name: Sensors): SensorHandle;
|
|
892
951
|
/**
|
|
893
952
|
* Enumerate all sensors in the loaded MuJoCo model.
|
|
894
953
|
* Returns a stable array recomputed only when the model changes.
|
|
@@ -910,7 +969,7 @@ declare function useSensors(): SensorInfo[];
|
|
|
910
969
|
* For ball joints, position is quat (4), velocity is angular vel (3).
|
|
911
970
|
* For free joints, position is pos+quat (7), velocity is lin+ang vel (6).
|
|
912
971
|
*/
|
|
913
|
-
declare function useJointState(name:
|
|
972
|
+
declare function useJointState(name: Joints): JointStateResult;
|
|
914
973
|
|
|
915
974
|
/**
|
|
916
975
|
* @license
|
|
@@ -923,22 +982,22 @@ declare function useJointState(name: string): JointStateResult;
|
|
|
923
982
|
* Track a MuJoCo body's world position, quaternion, and velocities.
|
|
924
983
|
* All values are ref-based — updated every physics frame without re-renders.
|
|
925
984
|
*/
|
|
926
|
-
declare function useBodyState(name:
|
|
985
|
+
declare function useBodyState(name: Bodies): BodyStateResult;
|
|
927
986
|
|
|
928
987
|
/**
|
|
929
988
|
* @license
|
|
930
989
|
* SPDX-License-Identifier: Apache-2.0
|
|
931
990
|
*
|
|
932
|
-
* useCtrl —
|
|
991
|
+
* useCtrl — handle-based read/write access to a named actuator's ctrl value (spec 3.1)
|
|
933
992
|
*/
|
|
993
|
+
|
|
934
994
|
/**
|
|
935
995
|
* Access a single actuator's control value by name.
|
|
936
996
|
*
|
|
937
|
-
* Returns
|
|
938
|
-
*
|
|
939
|
-
* - `setValue` writes directly to `data.ctrl[actuatorId]`.
|
|
997
|
+
* Returns a `CtrlHandle` with `read()` and `write()` methods that
|
|
998
|
+
* operate directly on `data.ctrl` without causing React re-renders.
|
|
940
999
|
*/
|
|
941
|
-
declare function useCtrl(name:
|
|
1000
|
+
declare function useCtrl(name: Actuators): CtrlHandle;
|
|
942
1001
|
|
|
943
1002
|
/**
|
|
944
1003
|
* @license
|
|
@@ -953,13 +1012,13 @@ declare function useCtrl(name: string): [React.RefObject<number>, (value: number
|
|
|
953
1012
|
* Calls the callback every physics frame with current contact list.
|
|
954
1013
|
* Reads `data.ncon` first to avoid allocating for zero contacts.
|
|
955
1014
|
*/
|
|
956
|
-
declare function useContacts(bodyName?:
|
|
1015
|
+
declare function useContacts(bodyName?: Bodies, callback?: (contacts: ContactInfo[]) => void): React.RefObject<ContactInfo[]>;
|
|
957
1016
|
/**
|
|
958
1017
|
* Contact enter/exit events for a specific body (spec 2.5).
|
|
959
1018
|
* Tracks which geom pairs are in contact frame-to-frame and fires
|
|
960
1019
|
* onEnter/onExit callbacks on transitions.
|
|
961
1020
|
*/
|
|
962
|
-
declare function useContactEvents(bodyName:
|
|
1021
|
+
declare function useContactEvents(bodyName: Bodies, handlers: {
|
|
963
1022
|
onEnter?: (info: ContactInfo) => void;
|
|
964
1023
|
onExit?: (info: ContactInfo) => void;
|
|
965
1024
|
}): void;
|
|
@@ -1195,4 +1254,4 @@ interface CameraAnimationAPI {
|
|
|
1195
1254
|
*/
|
|
1196
1255
|
declare function useCameraAnimation(): CameraAnimationAPI;
|
|
1197
1256
|
|
|
1198
|
-
export { type ActuatorInfo, Body, type BodyInfo, type BodyProps, type BodyStateResult, type CameraAnimationAPI, type ContactInfo, ContactListener, type ContactListenerProps, ContactMarkers, type ControllerComponent, type ControllerOptions, Debug, type DebugProps, DragInteraction, type DragInteractionProps, FlexRenderer, type GeomInfo, type IKSolveFn, type IkConfig, type IkContextValue, IkGizmo, type IkGizmoProps, type JointInfo, type JointStateResult, type KeyBinding, type KeyboardTeleopConfig, type ModelOptions, MujocoCanvas, type MujocoCanvasProps, type MujocoContact, type MujocoContactArray, type MujocoContextValue, type MujocoData, type MujocoModel, type MujocoModule, MujocoPhysics, type MujocoPhysicsProps, MujocoProvider, type MujocoSimAPI, MujocoSimProvider, type PhysicsConfig, type PhysicsStepCallback, type PolicyConfig, type RayHit, type SceneConfig, SceneLights, type SceneLightsProps, type SceneMarker, type SceneObject, type SensorInfo, type SensorResult, type SiteInfo, type SitePositionResult, type StateSnapshot, TendonRenderer, type TrajectoryData, type TrajectoryFrame, TrajectoryPlayer, type TrajectoryPlayerProps, type XmlPatch, createController, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getContact, getName, loadScene, 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 };
|
|
1257
|
+
export { type ActuatorInfo, type Actuators, type Bodies, Body, type BodyInfo, type BodyProps, type BodyStateResult, type CameraAnimationAPI, type ContactInfo, ContactListener, type ContactListenerProps, ContactMarkers, 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 MujocoModel, type MujocoModule, MujocoPhysics, type MujocoPhysicsProps, MujocoProvider, type MujocoSimAPI, MujocoSimProvider, type PhysicsConfig, type PhysicsStepCallback, type PolicyConfig, type RayHit, type Register, 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, TrajectoryPlayer, type TrajectoryPlayerProps, type XmlPatch, createController, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getContact, getName, loadScene, 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 };
|
package/dist/index.js
CHANGED
|
@@ -3305,7 +3305,15 @@ function useSensor(name) {
|
|
|
3305
3305
|
valueRef.current[i] = data.sensordata[adr + i];
|
|
3306
3306
|
}
|
|
3307
3307
|
});
|
|
3308
|
-
return
|
|
3308
|
+
return useMemo(() => ({
|
|
3309
|
+
read() {
|
|
3310
|
+
return valueRef.current;
|
|
3311
|
+
},
|
|
3312
|
+
get dim() {
|
|
3313
|
+
return sensorDimRef.current;
|
|
3314
|
+
},
|
|
3315
|
+
name
|
|
3316
|
+
}), [name]);
|
|
3309
3317
|
}
|
|
3310
3318
|
function useSensors() {
|
|
3311
3319
|
const { mjModelRef, status } = useMujocoContext();
|
|
@@ -3439,19 +3447,35 @@ function useBodyState(name) {
|
|
|
3439
3447
|
function useCtrl(name) {
|
|
3440
3448
|
const { mjModelRef, mjDataRef, status } = useMujocoContext();
|
|
3441
3449
|
const actuatorIdRef = useRef(-1);
|
|
3442
|
-
const
|
|
3450
|
+
const rangeRef = useRef([0, 0]);
|
|
3443
3451
|
useEffect(() => {
|
|
3444
3452
|
const model = mjModelRef.current;
|
|
3445
3453
|
if (!model || status !== "ready") return;
|
|
3446
|
-
|
|
3454
|
+
const id = findActuatorByName(model, name);
|
|
3455
|
+
actuatorIdRef.current = id;
|
|
3456
|
+
if (id >= 0) {
|
|
3457
|
+
rangeRef.current = [
|
|
3458
|
+
model.actuator_ctrlrange[id * 2],
|
|
3459
|
+
model.actuator_ctrlrange[id * 2 + 1]
|
|
3460
|
+
];
|
|
3461
|
+
}
|
|
3447
3462
|
}, [name, status, mjModelRef]);
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3463
|
+
return useMemo(() => ({
|
|
3464
|
+
read() {
|
|
3465
|
+
const data = mjDataRef.current;
|
|
3466
|
+
if (!data || actuatorIdRef.current < 0) return 0;
|
|
3467
|
+
return data.ctrl[actuatorIdRef.current];
|
|
3468
|
+
},
|
|
3469
|
+
write(value) {
|
|
3470
|
+
const data = mjDataRef.current;
|
|
3471
|
+
if (!data || actuatorIdRef.current < 0) return;
|
|
3472
|
+
data.ctrl[actuatorIdRef.current] = value;
|
|
3473
|
+
},
|
|
3474
|
+
name,
|
|
3475
|
+
get range() {
|
|
3476
|
+
return rangeRef.current;
|
|
3477
|
+
}
|
|
3478
|
+
}), [name, mjDataRef]);
|
|
3455
3479
|
}
|
|
3456
3480
|
function useKeyboardTeleop(config) {
|
|
3457
3481
|
const { mjModelRef, mjDataRef, status } = useMujocoContext();
|
|
@@ -3975,7 +3999,7 @@ function useCameraAnimation() {
|
|
|
3975
3999
|
* @license
|
|
3976
4000
|
* SPDX-License-Identifier: Apache-2.0
|
|
3977
4001
|
*
|
|
3978
|
-
* useCtrl —
|
|
4002
|
+
* useCtrl — handle-based read/write access to a named actuator's ctrl value (spec 3.1)
|
|
3979
4003
|
*/
|
|
3980
4004
|
/**
|
|
3981
4005
|
* @license
|