Commit Graph

217 Commits

Author SHA1 Message Date
Yuval Tassa 2f1843f4a7 Redesign the dcmotor controller: setpoint inputs, torque-space gains.
The dcmotor input block is any subset of the canonical list [pos, vel,
ff, voltage], selected with input="pos vel ff voltage" and recorded as
mjtCtrlInput bits in actuator_ctrlspec like pid. Tokens are required in
canonical order: the attribute denotes a set, the block always packs
canonically, and accepting permutations invites reading the string as a
layout choice. The mode flag in gainprm[8] is retired (reserved,
written 0).

Controller gains are now in torque space, as for pid: the controller
commands tau = kp*(q*-l) + kd*(v*-ldot) + ki*x_I + tau_ff over the
present inputs (absent setpoints frozen at zero) and converts to drive
voltage V = R/K * tau + K*ldot. The second term compensates back-EMF,
as the current loop of a real torque-mode driver does (torque commands
are current commands): commanded torque is delivered exactly until a
limit binds, and the torque-speed envelope emerges from the Vmax clamp.
The map uses the nameplate R: thermal resistance growth is not
compensated, so a hot motor under-delivers by R/R(T). A stateless
setpoint dcmotor now matches <pid> exactly, for any K and R; the old
back-EMF droop remains available as the physical behavior of the raw
voltage path. Voltage-space datasheet gains convert by K/R. Controller
inputs require a positive motor constant (the map divides by K), and
controller gains require a controller input.

ff and voltage are distinct inputs, different in kind: ff is a torque
feedforward added to the controller output, uniform with pid's ff
(feedforward in the actuator's output space), while voltage is the raw
terminal voltage of the physical device, injected downstream of the
controller and its Vmax clamp, unclamped (ctrlrange bounds it if
desired). input="voltage" is the default: the plain voltage-commanded
motor, whose behavior is unchanged by this commit. The integrator
always accumulates position error; the old velocity mode's integral
term, ki*(int(u)dt - theta), which tracked the integral of the velocity
command, is retired without replacement, keeping ki mode-independent --
commanded integrated velocity belongs to an integrator activation
state, not to controller gains. slewmax rate-limits the first controller
input -- position setpoint (rad/s), velocity setpoint (rad/s^2) or torque
feedforward (N*m/s), each a real driver feature (reference ramping,
ramped-velocity and ramped-torque input modes); the raw voltage input
is never rate-limited and slewmax requires a controller input.

input="none" selects the empty signature: the actuator owns no controls
at all (nu = 0 is now legal with actuators present) and is purely
passive -- LuGre friction, cogging and back-EMF braking as passive
joint forces. This exists because auxiliary dynamic states (the LuGre
bristle) attach to actuators, not joints. The terminal voltage is
identically zero, i.e. a shorted motor (dynamic braking); motorconst=0
decouples the electrical branch. mjINPUT_NONE is a distinct enum value
because ctrlspec = 0 means "unset, use the type default". History and
delay require an input; the controller voltage override and input read
in mj_fwdActuation are gated on a nonempty block.

The analytic velocity derivative of the controller becomes
dV/dw = -kd*R/K + K, whose second term cancels the back-EMF bias
exactly: the net damping of an unclipped torque-mode motor is -kd, and
of a voltage-mode or passive motor -K^2/R. Viewers label inputs via
mj_actuatorInputName: pos, vel, ff, voltage.

The dcmotor LaTeX design doc is updated accordingly: torque-space
units, the tau->V map and its saturation-generated envelope, the
input-block pipeline figure, and a Passive Operation section.

PiperOrigin-RevId: 965795351
Change-Id: Ibc308ca21bd6bad014e77f950ee08feaad449b73
2026-08-17 00:43:48 -07:00
Yuval Tassa 9553926158 Save flex node coordinates in the new nodecoord attribute.
Interpolated flexes with pinned nodes could not be reloaded after saving:
pinned nodes share their parent body, and their positions within it lived
only in mjsFlex.node, which had no MJCF attribute. On reload the pinned
nodes collapsed onto the parent body origin, degenerating the trilinear
interpolation grid ("flex grid rotation R0 is not orthonormal"). This
made model/flex/strain.xml and gripper_trilinear.xml fail to round-trip.

Add flex/nodecoord, real(3*nnode), the node analog of flex/vertex: local
node coordinates within the corresponding body frames. The reader picks
it up from the regenerated schema tables; the writer emits it with the
precision-aware WriteVector, since VectorToString ignores the XML
precision setting and truncating node coordinates to 6 digits while body
positions carry 17 fails the R0 orthonormality check at full precision.

Add a WritesPinnedFlexNodes round-trip regression test, and remove the
two write-read sweep exclusions documenting this bug. The removed
substring filter "strain" was also matching core_constraint, silently
excluding that entire testdata directory from the sweep; its ~40 models
are now covered and pass.

PiperOrigin-RevId: 959025281
Change-Id: I2fed28c01491c5a8431e813102a423d12b659911
2026-08-04 08:04:27 -07:00
Yuval Tassa 574b6bd6bf More schema-related cleanup.
- Declare every nonzero default; make the defaults cross-check total.
- Skip default-valued attributes in the hand-written writer paths.
- Fix type facts on hand-read elements, found by the dm_control diff.

PiperOrigin-RevId: 958999733
Change-Id: I3064ccc6ae1f049c20f273abc234cd02990a8b7e
2026-08-04 07:05:41 -07:00
Yuval Tassa b475bb6f36 Move schema related generated files into their own directory
PiperOrigin-RevId: 958296165
Change-Id: I48cacc72c7df5994f5f816489ba069a5813845a1
2026-08-03 04:23:56 -07:00
Yuval Tassa 5e99ca6cb8 Table-driven attribute writing: rebase the writer on the shared rows.
The writer consumes the same generated rows as the reader.
mjXWriter::WriteAttrTable drives the mechanical attributes of an
element from its mjXAttr rows: each bound field is compared against
the class default at the same offset -- the default object is the same
struct type, so the rows carry no comparison values -- and attributes
equal to their default are skipped. A null default object means the
element has no defaults, and every defined value is written.
Ranged-arity rows write with trailing-default trimming, which the
reader makes round-trip exact by refilling from the same default.
Call sites upcast to the private mjs base (the friend declarations
permit it; mjCMesh gains the friendship its siblings had); the
comparison object is def->X().spec, a freshly-defaulted struct for
the sections, or zero-initialized for size, whose spec defaults (-1,
auto) are resolved by compilation.

Converted: pair, geom, site, joint, camera, light, material, the
equality family, both tendon types (the fixed rows are the spatial
rows without appearance attributes -- exactly the tag difference), the
actuator, flex with its three sub-elements, mesh, skin, option, the
six visual sub-sections, statistic and size. The remnants keep names,
files, resolved reference strings (the mjC classes null their private
base's string pointers; resolved names live behind accessors), and the
writing=custom policies the schema declares: compile directives never
saved (fromto, springdamper, fitscale), type-dependent lengths and
attributes (sizes, joint pos/axis/limited, shellinertia), and
alternatives (mass/density, fovy-versus-intrinsics, the plugin-gated
gain/bias family). Compiler keeps its write-if-nonzero policy;
keyframe keeps its model-sized vectors.

Saved files are canonical: attributes follow schema declaration order
with remnants trailing, and sections follow the schema's dependency
order (statistic before visual, deformable before the contact and
equality sections that name flexes, tendon before the equality
constraints that name tendons, custom demoted to the data tail).
Uniform behavior fixes fall out: default-equal positionals are
dropped, dynprm is trimmed like every other ranged vector, and mesh
material -- read into the spec but never written -- now survives
save/load round trips. Changelog entries ride along.

Verified: full suite, doc_test, and the two-tier A/B harness --
saved XML reorders attributes, and every corpus model reloads to a
byte-identical binary.
PiperOrigin-RevId: 958255003
Change-Id: I5fe7346014450db88b2f3f8680a8f616f7d31266
2026-08-03 02:27:22 -07:00
Yuval Tassa 4278c7b0cd Table-driven attribute reading: rebase the reader on generated rows.
Every mechanical attribute read in MJCF now derives from mjcf.schema.
generate_read_table.py emits typed mjXAttr rows (mjcf_read_table.inc,
doc_test-gated) binding each attribute to its spec struct field; field
offsets are offsetof() expressions, so binding mistakes are compile
errors, and the field's C type -- parsed from the headers -- selects the
row kind, so mjtNum-versus-double is decided by the struct, not the
schema. mjXReader::ReadAttrTable is the generic loop; its static core
also serves the section parsers and records XML-authored fields via
mjs_setAuthored for attach conflict resolution. Row kinds cover
strings, string lists, numeric scalars and vectors (exact and ranged),
enums (int- and byte-width), bitwise flag sets, bools, unbounded typed
vectors, fixed char arrays, and identity constants declared by 'set'.
The rows are inline variables, and carry the writing=custom flag,
because the writer will share them.

The keyword maps the rows reference are generated too: the ~48
hand-written mjMap tables become mjcf_map.h, one map and size constant
per enum as C++17 inline variables, retiring the hand-maintained
extern block in xml_base.h. Map names follow the schema enum names
(fluid->fluidshape, TFAuto->FalseTrueAuto, FAuto->FalseAuto,
joint->jointtype, geom->geomtype, jac->jacobian); all maps are
key-order- and value-identical to the hand tables they replace, and
bool_map is hand-emitted (the bool type is built in, not a schema
enum).

The OneX() parsers reduce to genuine irregulars, schema-marked as
reading=custom: orientation alternatives, file attributes (VFS and
asset-dir context), the actuator shorthand remappings and per-type
input maps, springlength's one-value copy, mesh builtin construction,
hfield elevation, texture cube files, flexcomp seeding, the memory
suffix parse, and the flag bit families. All 41 sensors that are pure
identity-plus-references -- including the frame family and insidesite
-- dispatch through a generated tag table; frame-sensor
objtype/reftype vocabulary tightens from the full mju_str2Type
namespace to the documented body/xbody/geom/site/camera subset, so an
invalid keyword now fails at parse time instead of compile time. The
equality family and both tendon types read shared group rows; the
twelve actuator shorthands share the general rows, with per-tag
legality enforced by the schema check. Sections bind non-mjs structs,
the visual sub-sections reaching their anonymous sub-structs through
member paths declared by an element-level field= facet.

Latent irregularities surfaced by the migration and preserved via
schema declarations or remnants: key's name is set even when absent,
eulerseq and gridlayout are fixed char arrays (chars[n], arity in
characters), gridlayout's length-must-match-gridsize stays a
value-conditional remnant, and constructor-style elements (tendon
wraps, asset model, replicate, attach) are annotated as such -- their
attributes are arguments, not field writes.

Two coherence tests guard the schema against the C sources: every
schema enum constant must be a member of the C enum it claims, and
every C member must be a keyword, a count sentinel, or a documented
exemption; and generate_default_table.py emits one row per defaulted
attribute (mjcf_default_table.inc), compared by SchemaDefaultsTest
against a freshly-constructed spec -- the schema cannot disagree with
the C default-constructors without failing the suite.

Verified: doc_test regenerates and diffs every artifact; the full
suite; and an A/B harness compiling the model corpus against the
pre-migration reader -- saved XML and binary models are byte-identical.
PiperOrigin-RevId: 958075724
Change-Id: I9715fe4deeb438eec988fd5084d74ba8b466b10b
2026-08-02 17:24:45 -07:00
Yuval Tassa 790f8fac30 Generate the MJCF grammar table and enforce its constraints.
The hand-written MJCF[] table in xml_native_reader.cc is replaced by
mjcf_table.inc, emitted from mjcf.schema by generate_mjcf_table.py and
checked for freshness by doc_test. nMJCF is now self-sizing. The two
tables are identical as trees of (tag, cardinality, attribute-set);
within-row attribute order changes where the schema factors shared
groups and projects default-context rows, and top-level rows follow
the schema's dependency order -- neither affects validation, which is
set-based, nor XMLschema.rst, whose generator orders sections itself
(regenerated here, reading the .inc instead of the reader source).

The schema's constraint declarations become enforcement: the emitter
writes a companion MJCF_constraints[] array (row-indexed into MJCF[]),
and mjXSchema::Check evaluates each element's constraints after its
attribute check, with uniform messages derived from the declaration:
"at most one of 'fovy', 'sensorsize' can be specified", "attributes
'reftype', 'refname' must be specified together", and so on.
Multi-attribute bundles render as ('site1', 'site2').

Fifteen hand-written co-occurrence checks across fourteen elements are
deleted -- connect/weld semantics mixing and completeness, the actuator
transmission mutex, camera fovy/sensorsize, light directional/type,
inertial fullinertia-versus-orientation, rangefinder and the distance
family, contact's matching criteria, user-sensor pairing, the frame
family's reftype/refname, size memory exclusivities, mesh builtin
exclusions, and attach body/frame (newly declared). Tests assert the
uniform messages.

Two findings along the way: sensorsize-requires-resolution is a
value-level compiler rule (positive resolution), not a presence rule --
a presence constraint would be wrong and is not declared; and Size()'s
nstack/njmax range checks tested the spec value before assignment, so
they never validated the parsed value -- now they do.

Verified by compiling all 81 models in the model/ corpus.

PiperOrigin-RevId: 958064622
Change-Id: I802cf5c0aee08a62926e36a281320ff9e34c0668
2026-08-02 16:30:02 -07:00
Copybara-Service de26b05861 Merge pull request #3439 from smallquail:flex-metric-blocks
PiperOrigin-RevId: 957063540
Change-Id: I86e7b2ec92c7b2acd1f1f7140e3b8a7578c48dbf
2026-07-31 08:07:22 -07:00
Alessio 55d13aec5f Replace the flex metric factorization with a block preconditioner
Every step, the flex block of the implicit effective metric M + K was
factorized by sparse Cholesky, because K depends on the configuration. On
model/flex/bag.xml, added here, that is roughly half the step, against a
comparable share for the constraint solve it exists to accelerate.

Keep only the metric's per-vertex 3x3 diagonal blocks, prefactored. Neither
consumer needs the exact inverse: the CG constraint solver only wants a
preconditioner, and qacc_smooth can come from an iterative solve using those
blocks. They are O(n) to build and to apply, but weaker, so CG runs about twice
the iterations and qacc_smooth becomes an iteration rather than a direct solve.
Net, the bag model steps roughly twice as fast.

The preconditioner, by metric state. Inactive, meaning no flex elasticity or an
explicit integrator: M^-1, unchanged. Bending only (nefmK == 0): M^-1 plus the
exact constant bending factor from mj_setConst on the dofs it covers,
unchanged; that factor is built at model compile time and costs nothing per
step. Per-step stiffness: M^-1 plus the 3x3 blocks, where before it was a
per-step sparse Cholesky, or, when M couples across the flex block, an inner
PCG of up to 50 iterations run once per outer CG iteration.

Only models carrying per-step stretch stiffness change in wall-clock. Both
ponchos hold their timing and take slightly fewer CG iterations than before,
because the preconditioner is now symmetric: it applies M^-1 and the covered
blocks to disjoint sets of dofs, where previously the two overlapped and the
operator was not symmetric, which PCG requires.

mjd_effSolve is the accurate solve of (M + K)x = b; what used to carry that
name only preconditions and is now mjd_effPrec. Its CG guarded the division by
pAp with mjMINVAL, an absolute floor on a quantity that scales with the square
of the right-hand side, so a small b aborted the solve while the curvature was
healthy: four flex models were quietly left short of tolerance. For an SPD
metric the guard is positivity, and with that the same solves converge. The qacc_smooth call site in
mj_fwdAcceleration is textually unchanged but now reaches the iterative solve,
which converges on opt.tolerance rather than a hardcoded threshold, floored in
mjUSESINGLE builds where the squared target is unreachable in float. Reaching
the iteration cap names the ill-conditioned flex stiffness and then reports it
through mjWARN_INERTIA, rather than returning an under-converged result.
Covered dofs are located by walking the covered rows of the stiffness matrix,
as they need not be 3-aligned from dof 0: any joint declared before a flexcomp
shifts them.

mjData.efm_L_rownnz, efm_L_rowadr and efm_L_colind described the sparsity of
the deleted factorization and are removed: left NULL with nonzero mjxmacro
extents they made the Python bindings hand back uninitialized arrays.
efm_active loses the value 2 for the same reason, nothing selects a solve path
on preconditioner exactness any more. Both are recorded under breaking changes.

model/flex/bag.xml is added because no shipped model carried per-step stretch
stiffness. The ponchos are bending-only and trampoline.xml uses an explicit
integrator, so the metric never activates there. It is excluded from
WriteReadCompareTest: stretch stiffness amplifies rest geometry that XML rounds
on save.
2026-07-29 14:36:15 +01:00
Yuval Tassa 56a93979e0 Interpret position and intvelocity setpoints on 3D rotational transmissions (ball joints, site+refsite) on the circle. The force uses the setpoint representative nearest the current length for smooth tracking beyond pi.
- Wrapping in force path is local; act is re-anchored at integration time.
- Remove hardcoded `actrange` for intvelocity actuators.

PiperOrigin-RevId: 949566477
Change-Id: I349fdf17eedfbb2174d698cc1a6a91d52810b4a3
2026-07-17 07:49:30 -07:00
Yuval Tassa 4787c8094c Add geom surfacevel: zero-dof conveyors, treadmills and turntables.
https://www.youtube.com/watch?v=PdSdrqhSiZA

The new geom attribute surfacevel (6 numbers: linear and angular velocity in the geom's local frame, angular about the geom frame origin) specifies the velocity of the geom's surface material relative to the geom frame. The relative surface velocity of the two geoms is added to the tangential contact rows of efc_vel in mj_referenceConstraint, so friction drives touching bodies toward the motion of the surface: objects on a conveyor are transported at belt speed, turntables impart omega x r with torsional spin-up for condim >= 4, and surface velocities compose with each other and with body motion. The component along the contact normal is projected out: probe experiments showed that velocity-space emission chatters mass-independently and ingestion merely deepens penetration; normal-direction effects belong to force-space features.

surfacevel is interpreted in the geom frame as authored: for mesh geoms, whose compiled frame absorbs the mesh centering and principal-axes transform, the compiler re-expresses the authored value in the compiled frame.

No special interaction with sleeping: objects being transported do not fall asleep because they are moving; objects at rest on an active surface may sleep like any other resting object.

Includes showcase models (model/surfacevel/): a luggage carousel whose ring is a spinning square-profile supertorus fed by a cascade of belts with matched spinning end rollers, bags dropping in and circulating indefinitely; and a treadmill with a passive humanoid.

PiperOrigin-RevId: 948647785
Change-Id: I0c6559a91cc7ece1237eb8ac2e51986e7342d962
2026-07-15 17:58:17 -07:00
Google DeepMind faf0dabc32 Fix damper kv inheritance from default classes in XML native reader
Ensured dampers correctly read inherited values from gainprm[2].

PiperOrigin-RevId: 945086959
Change-Id: I10900f3ad057036115da88ad6d649d3d058e7373
2026-07-09 06:44:22 -07:00
Yuval Tassa 5618666a7d Add body/simple attribute to control simple body optimization.
PiperOrigin-RevId: 942164766
Change-Id: I1e83bb99b6a1955917eb9b2e9bed0dc7b8e6a161
2026-07-03 09:09:30 -07:00
Yuval Tassa 2d283b5e9d Allow self-attach in MJCF
PiperOrigin-RevId: 941676717
Change-Id: I9ff8fc89716bc14b438a41e2b4075bbe5fdb83cf
2026-07-02 06:51:46 -07:00
Yuval Tassa 0e58c48504 Clean up MJCF attach code.
PiperOrigin-RevId: 941603845
Change-Id: I94f275e2073b1eb81cfabdc0bed80021c6f15b1c
2026-07-02 03:45:39 -07:00
Yuval Tassa c6c3ec3149 Add "frame" attribute to <attach> element.
The `<attach>` element now supports a "frame" attribute, allowing users to specify either a "body" or a "frame" to attach to, but not both. The XML parser has been updated to handle this new attribute and the mutual exclusivity constraint.

PiperOrigin-RevId: 941245904
Change-Id: I4c0edeed5f3a9e456aed96c373b1647fe79841d9
2026-07-01 12:49:55 -07:00
Kyle Bayes 1490336955 Change LoadModelFromString to return a smart pointer, add MakeData, and update tests to have C++ RAII clean up model and data.
PiperOrigin-RevId: 935980153
Change-Id: I41d25bfab4935494dc984168820cb7cad123cadf
2026-06-22 04:19:01 -07:00
Yuval Tassa cedaa47d61 Migrate tests to use MockWarningHandler for warning interception.
PiperOrigin-RevId: 933656759
Change-Id: Ia21514c302799034bf598445933dd90427284737
2026-06-17 05:06:57 -07:00
Yuval Tassa 410c73168c Add policies for global attribute conflict resolution upon attach
For example when loading parent_merge.xml:

```
WARNING: Attach conflict when attaching 'child' to 'parent_merge', policy is 'merge'
timestep: parent has 0.005, child has 0.002, taking the minimum
iterations: parent has 50, child has 100, taking the maximum
flag 'Damper': added from child
```

When loading parent_error.xml:

```
XML Error: Attach conflict when attaching 'child' to 'parent_error', policy is 'error'
timestep: parent has 0.005, child has 0.002
iterations: parent has 50, child has 100
Element 'attach', line 10
```
PiperOrigin-RevId: 933620810
Change-Id: Ib477863b5ef763474d27fb4be5a4148be1d5d500
2026-06-17 03:36:10 -07:00
Yuval Tassa 6f8bb5ef55 Refactor compiler warning handling.
Compiler warnings are now accumulated in a vector of strings within the mjSpec object. New API functions `mjs_numWarnings` and `mjs_getWarning` are added to access these warnings. The compiler's log handler now chains warnings to the global log handler, ensuring they are still displayed immediately. Call sites in `mj_loadXML`, `mj_compile`, and the Python and WASM bindings have been updated to use the new warning API.

PiperOrigin-RevId: 933361650
Change-Id: I47cab98a460c57b0898c0a1a43fce2a5b9648eb1
2026-06-16 16:28:33 -07:00
Yuval Tassa 67a1ea6dca Track authored flags for global attributes
PiperOrigin-RevId: 931585539
Change-Id: Ifdc8c59de6c5a553daf6e0af09d8192aff6b0610
2026-06-13 02:58:32 -07:00
Yuval Tassa d80a847bae Move CompareModel to a separate library.
PiperOrigin-RevId: 927174846
Change-Id: Ia8b8b2c8593133d8910399be755e614282bf3252
2026-06-05 02:44:53 -07:00
Yuval Tassa 5ce9a0ad0b Split large parameterized tests into dedicated files.
PiperOrigin-RevId: 927159897
Change-Id: Ib0e11727c49195bc03d190b736c01b14c10268fe
2026-06-05 02:07:47 -07:00
Yuval Tassa 4358a102cd Add manual test for CG converence
Also add MJTOL_SCALE to fixture to allow tests to be run with zero tolerance. This is useful when assesing the impact of code changes (A/B comparison of failure values)

PiperOrigin-RevId: 924219083
Change-Id: Ifdd09ac850904ca8dd79179930ce738a4b37d284
2026-05-31 03:15:54 -07:00
Kevin Zakka 6f9725a1da Make mju_getXMLDependencies read XMLs through the resource provider.
The function called tinyxml2's LoadFile directly, which only works on
the OS file system. Reading through mju_openResource lets it work
against any registered backend (VFS, HTTP, github:, ...).
2026-05-26 16:01:48 -07:00
Yuval Tassa 393c1e4217 Migrate mjtByte to mjtBool for boolean-valued fields.
PiperOrigin-RevId: 921408093
Change-Id: Icb00457836359779f0f72fc02d6a7c0dc9f6bd23
2026-05-26 05:35:49 -07:00
Yuval Tassa 2810edd27a Rename mjtnum.h to mjtype.h, move enum types to mjtype.h
PiperOrigin-RevId: 919020039
Change-Id: I441295c0baa0b7456f78239fbd5478d32ffc07c1
2026-05-21 06:43:29 -07:00
Sam Haves fa8ac7a516 Implement mjz encoder.
PiperOrigin-RevId: 918493808
Change-Id: I150d182ff27801d829537a8001a0b3a04c1a0499
2026-05-20 09:32:51 -07:00
Sam Haves eddfbcfc50 Move mjz_decoder out of experimental to xml/mjz.
Since the mjz format is just an archive for MJCF assets this seems like a sensible place. The upcoming mjz encoder will also need to make use of the full precision XML utility that is local to src/xml.

PiperOrigin-RevId: 912044746
Change-Id: I6a9fef24b1c3fec5b5edc3a8d4c8e22584273264
2026-05-07 10:52:03 -07:00
Alessio Quaglino 7d54123303 Make flex vert0 rotation-invariant for interpolated flexes.
The `vert0` array, used for parametric vertex coordinates in flexes, is now computed in the flex's local, unrotated frame when using interpolation. This ensures that the parametric coordinates are independent of the flex's initial orientation. A new test confirms that `flex_vert0` is identical for an unrotated and a rotated flex grid.

PiperOrigin-RevId: 908196464
Change-Id: I47d6bcc2bc5df581479d485480e0e947ec6d3ffd
2026-04-30 08:41:01 -07:00
Sam Haves a744b366fb Include obj and stl decoder plugins as sources in CMake builds.
This removes the need to load these decoders via mj_loadAllPluginLibraries when using MuJoCo built with CMake. Other plugins are unchanged.

PiperOrigin-RevId: 897114719
Change-Id: Iee914cc5e05798186f384a67901f1cf86bc2f887
2026-04-09 07:58:28 -07:00
Yuval Tassa 81720071b8 Changes to dcmotor:
- Remove `lugre:viscous`, should now be added directly to actuator `damping`. Trying to do this for the user was incompatible with default inheritance (compounding instead of overriding).
- Move voltage limiting from the `saturation` to the `controller` attribute.
- Fix indexing issues in default inheritance.

PiperOrigin-RevId: 897087642
Change-Id: I5388c2633e15c7e223992e7eb5d6a28db75a6438
2026-04-09 06:52:45 -07:00
Yuval Tassa 70a7647ad9 Add <dcmotor> actuator and related docs and tests.
PiperOrigin-RevId: 892927987
Change-Id: I38ed6412801341ba03ddf5fe7b93a6081df24d37
2026-04-01 07:50:23 -07:00
Yuval Tassa 9f5fc99711 Convert monolithic RecompileCompare and WriteReadCompare tests into test suites, one test per file.
PiperOrigin-RevId: 890149850
Change-Id: Ib3e8c032a7b43b4a3f85e7a922e25987050cd77c
2026-03-26 18:21:49 -07:00
Yuval Tassa 510d75f4cf Allow actuators to add damping and armature to joint and tendon transmissions.
PiperOrigin-RevId: 886899849
Change-Id: I02200ee0d4f7c96096d8188b95f823b566562a30
2026-03-20 11:41:15 -07:00
Yuval Tassa 9fa3f6f77e Enable float32 testing for most MuJoCo engine and user tests.
PiperOrigin-RevId: 886697701
Change-Id: I4a96fae03ea18494c3fcef8eb17b3b6f0863e9b7
2026-03-20 04:05:06 -07:00
Sam Haves ef78f07ffb Automated g4 rollback of changelist 885555524.
*** Reason for rollback ***

Rolling back obj/stl decoder inclusion as sources due to broken windows build.

*** Original change description ***

Include obj and stl decoder plugins as sources in CMake builds.

This removes the need to load these decoders via mj_loadAllPluginLibraries when using MuJoCo built with CMake. Other plugins are unchanged.

***

PiperOrigin-RevId: 885576586
Change-Id: I31e6fa4d10697862f7d800d0d771ca752747e36d
2026-03-18 07:18:19 -07:00
Sam Haves 15ca42ff68 Include obj and stl decoder plugins as sources in CMake builds.
This removes the need to load these decoders via mj_loadAllPluginLibraries when using MuJoCo built with CMake. Other plugins are unchanged.

PiperOrigin-RevId: 885555524
Change-Id: I20aa5b6c55b678398345d49cb1c47667ae2bebcf
2026-03-18 06:23:26 -07:00
Sam Haves 91d3565cd5 Move OBJ handling to a mjpDecoder.
PiperOrigin-RevId: 878041994
Change-Id: I6e7f6876e65fd2184ff5637d4268644cefcabecf
2026-03-03 11:22:02 -08:00
Sam Haves 0ec836b281 Rollback of Move OBJ handling to a mjpDecoder.
PiperOrigin-RevId: 875705083
Change-Id: I21403d84abd56ef72de915bddc724fe3efa506e6
2026-02-26 07:04:39 -08:00
Sam Haves b907ffedaa Move OBJ handling to a mjpDecoder.
PiperOrigin-RevId: 875194599
Change-Id: I2cccc683d69a217f1817e70d16bc1815e366d00c
2026-02-25 09:13:09 -08:00
Sam Haves 82e92cbcaa Remove PluginTest and make MujocoTest load plugins.
MujocoTest now loads plugins from MUJOCO_PLUGIN_DIR if set.
PluginTest is removed; all tests use MujocoTest directly.
testspeed binary loads plugins from MUJOCO_PLUGIN_DIR.

This is in preparation for moving common asset format parsing (obj, msh, stl, etc.) where we will always want to load those plugins.

PiperOrigin-RevId: 874194428
Change-Id: Id90805a9ba5de4627911b56d8b9c4ab4e1b29310
2026-02-23 12:15:22 -08:00
Adrian Collister d881e9e374 Change tex_adr type to mjtSize.
Adds a test which verifies that we can index into the texture buffer at offsets larger than can be represented by a 32-bit signed int.

PiperOrigin-RevId: 868756646
Change-Id: Ibc1a2b269fce41aec370611b0aab77803837e7a8
2026-02-11 11:09:36 -08:00
Yuval Tassa 6419534bad Add actuator and sensor delays. Fixes #1004
PiperOrigin-RevId: 866478839
Change-Id: Id21a6da0f98454c8fa39ea5af8a5e213d6eae497
2026-02-06 08:47:36 -08:00
Haroon Qureshi b073cd2ca4 Refactor mjVFS and resource management.
Resource operations (e.g. mju_openResource, mju_readResource, and
mju_closeResource, etc.) are now all handled by a VFS instance. It
is now up to the VFS to determine which provider to use in order to
handle those operations.

This allows us to dynamically add/remove (aka "mount") providers to
a VFS to handle special requests. mj_addFileVFS and mj_addBufferVFS
have been reimplemented as two such use-cases. Moreover, we expose
the mounting behaviour with two new functions: mj_mountVFS and
mj_unmountVFS.

PiperOrigin-RevId: 863248779
Change-Id: I8bcbd5445814ba1e72c6d7b80ad6a054f5f1df57
2026-01-30 08:20:53 -08:00
Haroon Qureshi 2fd9b5e92f Partial roll back VFS refactor due internal breakages
PiperOrigin-RevId: 862210191
Change-Id: Ia15a345a267bcef4b593d507d54f1668da0c0611
2026-01-28 06:40:11 -08:00
Haroon Qureshi 0ddbb46fa1 Refactor mjVFS and resource management.
Resource operations (e.g. mju_openResource, mju_readResource, and
mju_closeResource, etc.) are now all handled by a VFS instance. It
is now up to the VFS to determine which provider to use in order to
handle those operations.

This allows us to dynamically add/remove (aka "mount") providers to
a VFS to handle special requests. mj_addFileVFS and mj_addBufferVFS
have been reimplemented as two such use-cases. Moreover, we expose
the mounting behaviour with two new functions: mj_mountVFS and
mj_unmountVFS.

PiperOrigin-RevId: 861550939
Change-Id: I070eb4bcc2982466c8f368f7918005538baa5185
2026-01-26 23:53:29 -08:00
Yuval Tassa 30b903b6c0 Migrate mjModel size fields from int to mjtSize.
This change updates all size-related members within the `mjModel` struct from `int` to `mjtSize`. This allows MuJoCo to handle models with a larger number of elements. Corresponding changes were made to macros, function signatures, and I/O routines to accommodate the new `mjtSize` type.

PiperOrigin-RevId: 860144595
Change-Id: I701c6d607715d240766b6210a9773cd9e4258c59
2026-01-23 09:41:49 -08:00
Google DeepMind cbc1136502 Roll back VFS refactor due internal breakages
PiperOrigin-RevId: 856273160
Change-Id: I4097e05ed4e48ebee05b4347d0f227d4f39c1b09
2026-01-14 10:38:29 -08:00
Haroon Qureshi d387578783 Refactor mjVFS and resource management.
Resource operations (e.g. mju_openResource, mju_readResource, and
mju_closeResource, etc.) are now all handled by a VFS instance. It
is now up to the VFS to determine which provider to use in order to
handle those operations.

This allows us to dynamically add/remove (aka "mount") providers to
a VFS to handle special requests. mj_addFileVFS and mj_addBufferVFS
have been reimplemented as two such use-cases. Moreover, we expose
the mounting behaviour with two new functions: mj_mountVFS and
mj_unmountVFS.

PiperOrigin-RevId: 856166919
Change-Id: Id723d612ffc0bff020705cf19ef95fbf24676840
2026-01-14 05:19:57 -08:00