mujoco-react 8.3.3 → 8.4.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 +69 -19
- package/dist/index.d.ts +87 -5
- package/dist/index.js +399 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/GenericIK.ts +13 -10
- package/src/core/MujocoProvider.tsx +91 -7
- package/src/core/MujocoSimProvider.tsx +48 -5
- package/src/core/SceneLoader.ts +343 -1
- package/src/hooks/useIkController.ts +30 -11
- package/src/index.ts +10 -0
- package/src/types.ts +72 -3
|
@@ -9,8 +9,8 @@ import * as THREE from 'three';
|
|
|
9
9
|
import { createControllerHook } from '../core/createController';
|
|
10
10
|
import { useMujocoContext, useBeforePhysicsStep } from '../core/MujocoSimProvider';
|
|
11
11
|
import { GenericIK } from '../core/GenericIK';
|
|
12
|
-
import { findSiteByName } from '../core/SceneLoader';
|
|
13
|
-
import type { IkConfig, IkContextValue, IKSolveFn, MujocoData } from '../types';
|
|
12
|
+
import { createContiguousControlGroup, findSiteByName, resolveControlGroup } from '../core/SceneLoader';
|
|
13
|
+
import type { ControlGroupInfo, IkConfig, IkContextValue, IKSolveFn, MujocoData } from '../types';
|
|
14
14
|
|
|
15
15
|
// Preallocated temp for syncGizmoToSite
|
|
16
16
|
const _syncMat4 = new THREE.Matrix4();
|
|
@@ -40,6 +40,7 @@ export const useIkController = createControllerHook<IkConfig, IkContextValue>(
|
|
|
40
40
|
const ikCalculatingRef = useRef(false);
|
|
41
41
|
const ikTargetRef = useRef<THREE.Group>(new THREE.Group());
|
|
42
42
|
const siteIdRef = useRef(-1);
|
|
43
|
+
const controlGroupRef = useRef<ControlGroupInfo | null>(null);
|
|
43
44
|
const genericIkRef = useRef<GenericIK>(new GenericIK(mujocoRef.current));
|
|
44
45
|
const firstIkEnableRef = useRef(true);
|
|
45
46
|
const needsInitialSync = useRef(true);
|
|
@@ -54,23 +55,32 @@ export const useIkController = createControllerHook<IkConfig, IkContextValue>(
|
|
|
54
55
|
duration: 1000,
|
|
55
56
|
});
|
|
56
57
|
|
|
57
|
-
// Resolve site ID when model loads or config changes
|
|
58
|
+
// Resolve site ID and model-aware control group when model loads or config changes.
|
|
58
59
|
useEffect(() => {
|
|
59
60
|
if (!config) {
|
|
60
61
|
siteIdRef.current = -1;
|
|
62
|
+
controlGroupRef.current = null;
|
|
61
63
|
return;
|
|
62
64
|
}
|
|
63
65
|
const model = mjModelRef.current;
|
|
64
66
|
if (!model || status !== 'ready') {
|
|
65
67
|
siteIdRef.current = -1;
|
|
68
|
+
controlGroupRef.current = null;
|
|
66
69
|
return;
|
|
67
70
|
}
|
|
68
71
|
siteIdRef.current = findSiteByName(model, config.siteName);
|
|
72
|
+
controlGroupRef.current = config.numJoints !== undefined
|
|
73
|
+
? createContiguousControlGroup(model, config.numJoints)
|
|
74
|
+
: resolveControlGroup(model, {
|
|
75
|
+
siteName: config.siteName,
|
|
76
|
+
joints: config.joints,
|
|
77
|
+
actuators: config.actuators,
|
|
78
|
+
});
|
|
69
79
|
const data = mjDataRef.current;
|
|
70
80
|
if (data && ikTargetRef.current) {
|
|
71
81
|
syncGizmoToSite(data, siteIdRef.current, ikTargetRef.current);
|
|
72
82
|
}
|
|
73
|
-
}, [config?.siteName, status, mjModelRef, mjDataRef, config]);
|
|
83
|
+
}, [config?.siteName, config?.numJoints, config?.joints, config?.actuators, status, mjModelRef, mjDataRef, config]);
|
|
74
84
|
|
|
75
85
|
// IK solve function
|
|
76
86
|
const ikSolveFn = useCallback(
|
|
@@ -79,9 +89,10 @@ export const useIkController = createControllerHook<IkConfig, IkContextValue>(
|
|
|
79
89
|
if (config.ikSolveFn) return config.ikSolveFn(pos, quat, currentQ);
|
|
80
90
|
const model = mjModelRef.current;
|
|
81
91
|
const data = mjDataRef.current;
|
|
82
|
-
|
|
92
|
+
const controlGroup = controlGroupRef.current;
|
|
93
|
+
if (!model || !data || !controlGroup || siteIdRef.current === -1) return null;
|
|
83
94
|
return genericIkRef.current.solve(
|
|
84
|
-
model, data, siteIdRef.current,
|
|
95
|
+
model, data, siteIdRef.current, controlGroup.qposAdr,
|
|
85
96
|
pos, quat, currentQ,
|
|
86
97
|
{ damping: config.damping, maxIterations: config.maxIterations },
|
|
87
98
|
);
|
|
@@ -126,12 +137,20 @@ export const useIkController = createControllerHook<IkConfig, IkContextValue>(
|
|
|
126
137
|
if (!target) return;
|
|
127
138
|
|
|
128
139
|
ikCalculatingRef.current = true;
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
140
|
+
const controlGroup = controlGroupRef.current;
|
|
141
|
+
if (!controlGroup) return;
|
|
142
|
+
|
|
143
|
+
const currentQ = Array.from(controlGroup.readQpos(data));
|
|
144
|
+
const solution = config.ikSolveFn
|
|
145
|
+
? config.ikSolveFn(target.position, target.quaternion, currentQ, {
|
|
146
|
+
model,
|
|
147
|
+
data,
|
|
148
|
+
siteId: siteIdRef.current,
|
|
149
|
+
controlGroup,
|
|
150
|
+
})
|
|
151
|
+
: ikSolveFnRef.current(target.position, target.quaternion, currentQ);
|
|
133
152
|
if (solution) {
|
|
134
|
-
|
|
153
|
+
controlGroup.writeCtrl(data, solution);
|
|
135
154
|
}
|
|
136
155
|
});
|
|
137
156
|
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
// Core
|
|
7
7
|
export { MujocoProvider, useMujocoWasm } from './core/MujocoProvider';
|
|
8
|
+
export type { MujocoLoader, MujocoLoaderOptions, MujocoProviderProps, MujocoWasmVariant } from './core/MujocoProvider';
|
|
8
9
|
export { MujocoCanvas } from './core/MujocoCanvas';
|
|
9
10
|
export { MujocoPhysics } from './core/MujocoPhysics';
|
|
10
11
|
export type { MujocoPhysicsProps } from './core/MujocoPhysics';
|
|
@@ -20,6 +21,10 @@ export {
|
|
|
20
21
|
findGeomByName,
|
|
21
22
|
findSensorByName,
|
|
22
23
|
findTendonByName,
|
|
24
|
+
getActuatedJoints,
|
|
25
|
+
getControlMap,
|
|
26
|
+
resolveControlGroup,
|
|
27
|
+
createContiguousControlGroup,
|
|
23
28
|
} from './core/SceneLoader';
|
|
24
29
|
|
|
25
30
|
// Controller factory
|
|
@@ -82,6 +87,11 @@ export type {
|
|
|
82
87
|
// Model introspection
|
|
83
88
|
BodyInfo,
|
|
84
89
|
JointInfo,
|
|
90
|
+
ActuatedJointInfo,
|
|
91
|
+
ControlJointInfo,
|
|
92
|
+
ControlGroupInfo,
|
|
93
|
+
ControlGroupSelector,
|
|
94
|
+
ResourceSelector,
|
|
85
95
|
GeomInfo,
|
|
86
96
|
SiteInfo,
|
|
87
97
|
ActuatorInfo,
|
package/src/types.ts
CHANGED
|
@@ -344,11 +344,27 @@ export interface SceneConfig {
|
|
|
344
344
|
|
|
345
345
|
// ---- IK Controller Config ----
|
|
346
346
|
|
|
347
|
+
export type ResourceSelector<TInfo, TName extends string = string> =
|
|
348
|
+
| TName
|
|
349
|
+
| readonly TName[]
|
|
350
|
+
| RegExp
|
|
351
|
+
| ((info: TInfo) => boolean);
|
|
352
|
+
|
|
347
353
|
export interface IkConfig {
|
|
348
354
|
/** MuJoCo site name for IK target. */
|
|
349
355
|
siteName: Sites;
|
|
350
|
-
/**
|
|
351
|
-
|
|
356
|
+
/**
|
|
357
|
+
* Explicit joints for IK. When omitted, the controller infers scalar hinge/slide
|
|
358
|
+
* joints by walking from the site body to the model root.
|
|
359
|
+
*/
|
|
360
|
+
joints?: ResourceSelector<JointInfo, Joints>;
|
|
361
|
+
/** Explicit actuators for IK control output. */
|
|
362
|
+
actuators?: ResourceSelector<ActuatorInfo, Actuators>;
|
|
363
|
+
/**
|
|
364
|
+
* Number of joints to solve for, assuming legacy contiguous qpos/ctrl layout
|
|
365
|
+
* starting at index 0. Prefer inferred IK or `joints`/`actuators`.
|
|
366
|
+
*/
|
|
367
|
+
numJoints?: number;
|
|
352
368
|
/** Custom IK solver. When omitted, uses built-in Damped Least-Squares solver. */
|
|
353
369
|
ikSolveFn?: IKSolveFn;
|
|
354
370
|
/** DLS damping. Default: 0.01. */
|
|
@@ -390,9 +406,17 @@ export interface PhysicsConfig {
|
|
|
390
406
|
export type IKSolveFn = (
|
|
391
407
|
pos: THREE.Vector3,
|
|
392
408
|
quat: THREE.Quaternion,
|
|
393
|
-
currentQ: number[]
|
|
409
|
+
currentQ: number[],
|
|
410
|
+
context?: IKSolveContext
|
|
394
411
|
) => number[] | null;
|
|
395
412
|
|
|
413
|
+
export interface IKSolveContext {
|
|
414
|
+
model: MujocoModel;
|
|
415
|
+
data: MujocoData;
|
|
416
|
+
siteId: number;
|
|
417
|
+
controlGroup: ControlGroupInfo;
|
|
418
|
+
}
|
|
419
|
+
|
|
396
420
|
// ---- Callbacks ----
|
|
397
421
|
|
|
398
422
|
export type PhysicsStepCallback = (
|
|
@@ -453,6 +477,48 @@ export interface ActuatorInfo {
|
|
|
453
477
|
range: [number, number];
|
|
454
478
|
}
|
|
455
479
|
|
|
480
|
+
export interface ActuatedJointInfo extends JointInfo {
|
|
481
|
+
actuatorId: number;
|
|
482
|
+
actuatorName: string;
|
|
483
|
+
ctrlAdr: number;
|
|
484
|
+
ctrlRange: [number, number];
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export interface ControlJointInfo extends JointInfo {
|
|
488
|
+
actuatorId: number | null;
|
|
489
|
+
actuatorName: string | null;
|
|
490
|
+
ctrlAdr: number | null;
|
|
491
|
+
ctrlRange: [number, number] | null;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export interface ControlGroupSelector {
|
|
495
|
+
/** Infer a kinematic chain from a MuJoCo site. */
|
|
496
|
+
siteName?: Sites;
|
|
497
|
+
/** Infer a kinematic chain from a body. */
|
|
498
|
+
bodyName?: Bodies;
|
|
499
|
+
/** Select joints by name, names, regex, or predicate. */
|
|
500
|
+
joints?: ResourceSelector<JointInfo, Joints>;
|
|
501
|
+
/** Select actuators by name, names, regex, or predicate. */
|
|
502
|
+
actuators?: ResourceSelector<ActuatorInfo, Actuators>;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
export interface ControlGroupInfo {
|
|
506
|
+
/** Joints in solve/control order. */
|
|
507
|
+
joints: ControlJointInfo[];
|
|
508
|
+
/** Actuators in control output order. */
|
|
509
|
+
actuators: ActuatorInfo[];
|
|
510
|
+
/** qpos addresses for scalar hinge/slide joints. */
|
|
511
|
+
qposAdr: number[];
|
|
512
|
+
/** dof addresses for scalar hinge/slide joints. */
|
|
513
|
+
dofAdr: number[];
|
|
514
|
+
/** ctrl addresses matching writable actuators. */
|
|
515
|
+
ctrlAdr: number[];
|
|
516
|
+
readQpos(data: MujocoData): Float64Array;
|
|
517
|
+
readCtrl(data: MujocoData): Float64Array;
|
|
518
|
+
writeQpos(data: MujocoData, values: ArrayLike<number>): void;
|
|
519
|
+
writeCtrl(data: MujocoData, values: ArrayLike<number>): void;
|
|
520
|
+
}
|
|
521
|
+
|
|
456
522
|
export interface SensorInfo {
|
|
457
523
|
id: number;
|
|
458
524
|
name: string;
|
|
@@ -629,6 +695,9 @@ export interface MujocoSimAPI {
|
|
|
629
695
|
// Actuator / control (spec 3.1)
|
|
630
696
|
setCtrl(nameOrValues: Actuators | Record<Actuators, number>, value?: number): void;
|
|
631
697
|
getCtrl(): Float64Array;
|
|
698
|
+
getControlMap(): ControlGroupInfo;
|
|
699
|
+
getActuatedJoints(): ActuatedJointInfo[];
|
|
700
|
+
resolveControlGroup(selector: ControlGroupSelector): ControlGroupInfo | null;
|
|
632
701
|
|
|
633
702
|
// Force application (spec 8.1)
|
|
634
703
|
applyForce(bodyName: Bodies, force: THREE.Vector3, point?: THREE.Vector3): void;
|