Built-in Terms¶
Eden ships ready-made terms for every manager: action controllers, observations, rewards, terminations, commands, events, curricula, metrics and recorders, plus the modifiers that post-process term inputs and outputs. This section renders their API docs, one page per kind and one section per module.
To find what a term accepts, use the term catalog. It is generated from the registries, so it lists every registered term with its parameters, their types and defaults, and which are required. In a terminal:
eden terms --grep height # terms whose name, parameters or summary match a regex
eden terms --kind reward # one kind only
eden terms --json # the whole catalog, for tooling
Using a built-in term¶
Configure a term in a config with .configure(...), which returns its serializable options. A class term takes its
parameters as keyword arguments. A function term goes through the kind's function wrapper (short aliases in
eden.terms), with its parameters in params={...}. Those aliases are the function wrappers only:
eden.terms.RewardTerm is RewardTermFuncWrapper, not the class-term base eden.managers.reward_manager.RewardTerm
that shares its name (the same holds for EventTerm and MetricTerm). Subclass the base from its manager module. Excerpted from eden/tasks/benchmark/reacher/config.py and
eden/tasks/benchmark/move_forward/config.py:
from eden import observations, rewards
from eden.terms import RewardTerm
dofs_pos = observations.DofsPos.configure(entity_name="robot")
joint_vel_hinge = RewardTerm.configure(
func=rewards.dofs_vel_limits,
weight=-0.01,
params={"entity_name": "robot", "max_vel": 0.5},
)
tracking_lin_vel = rewards.TrackingLinVel.configure(
weight=1.0,
command_name="velocity_command",
entity_name="robot",
sigma=0.25,
)
from eden import observations, rewards, terminations, ... imports the built-in term modules lazily, on first
use. A term is looked up by its registry key, never by object identity, so a class term you write yourself must be
registered with @<KIND>_TERM_REGISTRY.register(). See the terms guide.
Function wrappers¶
Short aliases for FuncWrapper term classes.
Usage::
from eden.terms import ObsTerm, RewardTerm, DoneTerm, EventTerm, CurrTerm, MetricTerm
Classes¶
ObsTerm
¶
ObsTerm(func: FunctionType, env: EnvBase, options: ObservationTermOptions)
Bases: ConfigurableTermFuncWrapper[ObservationTermOptions], _ObservationTermFields
Base class for observation terms defined as function. See :class:ObservationTerm for the modifier
fields (options-only, not mirrored as attributes), for when each one is read, and for
:attr:effective_scale.
Stateless by construction. A function term is a pure forward of env state: the manager never
dispatches reset(), post_reset() or post_physics_refresh() to it (the inherited reset
and post_reset are no-ops, and there is no refresh hook to call), so state kept in a closure or a
module global is never zeroed at episode reset and advances on every one of the several compute()
calls a step may make. A term that needs per-episode or per-step state is a class term.
Source code in eden/managers/observation_manager.py
Methods:¶
RewardTerm
¶
RewardTerm(func: FunctionType, env: EnvBase, options: _TermOptionsT)
Bases: ConfigurableTermFuncWrapper[RewardTermOptions], _RewardTermFields
Base class for reward terms defined as a function.
Source code in eden/managers/base.py
DoneTerm
¶
DoneTerm(func: FunctionType, env: EnvBase, options: _TermOptionsT)
Bases: ConfigurableTermFuncWrapper[TerminationTermOptions], _TerminationTermFields
Base class for termination terms defined as a function.
Source code in eden/managers/base.py
EventTerm
¶
EventTerm(func: FunctionType, env: EnvBase, options: _TermOptionsT)
Bases: ConfigurableTermFuncWrapper[EventTermOptions], _EventTermFields
Base class for event terms defined as function.
Source code in eden/managers/base.py
CurrTerm
¶
CurrTerm(func: FunctionType, env: EnvBase, options: _TermOptionsT)
Bases: ConfigurableTermFuncWrapper[CurriculumTermOptions]
Base class for curriculum terms defined as a function.
Source code in eden/managers/base.py
MetricTerm
¶
MetricTerm(func: FunctionType, env: EnvBase, options: _TermOptionsT)
Bases: ConfigurableTermFuncWrapper[MetricTermOptions], SuccessCheckerMixin
Base class for metric terms defined as function. See :class:SuccessCheckerMixin for the shared fields.
Source code in eden/managers/base.py
Pages¶
| Kind | Page | Lazy namespace |
|---|---|---|
| Actions | Action terms | eden.actions |
| Observations | Observation terms | eden.observations |
| Rewards | Reward terms | eden.rewards |
| Terminations | Termination terms | eden.terminations |
| Commands | Command terms | eden.commands |
| Events | Event terms | eden.events |
| Curricula | Curriculum terms | eden.curricula |
| Metrics | Metric terms | eden.metrics |
| Recorders | Recorder terms | eden.recorders |
| Modifiers | Modifiers | — |
Shared term helpers¶
Building blocks the built-in terms reuse: resolve-once helpers for build() (resolve_link_idx,
resolve_terrain, resolve_metric_manager, ...) and cheap math helpers for compute() (projected_gravity,
base_height_above_ground, ...).
Shared helpers for manager terms.
Small building blocks reused across observation / reward term build() and compute() so the same
idiom (gravity projection, link-index resolution, base height over the ground, per-DOF std from a regex dict)
isn't re-implemented per term. Resolve-once helpers (resolve_link_idx / resolve_terrain /
resolve_per_dof_std / resolve_metric_manager) are meant to be called in build() — a function term,
which has none, calls them per step; the math helpers (gravity_vec / projected_gravity /
base_height_above_ground) are cheap enough for the hot path.
Attributes¶
Classes¶
Functions:¶
gravity_vec
¶
gravity_vec(num_envs: int, device) -> Tensor
World-frame down vector [0, 0, -1] expanded to (num_envs, 3).
Cache once in build(); pass to :func:projected_gravity as the gravity input and/or use directly as
the upright reference vector. Built on the device rather than copied from a host list, so a function term
that has no build() can call it per step without a GPU->CPU sync.
Source code in eden/managers/terms/utils.py
projected_gravity
¶
Express world-frame grav in the frame of quat (wxyz).
quat is (..., 4) and grav is the matching world-frame vector (e.g. from :func:gravity_vec).
It is inv_transform_by_quat with the operands in the opposite order.
Source code in eden/managers/terms/utils.py
resolve_metric_manager
¶
resolve_metric_manager(env: EnvBase, *, term: str, metric_name: str) -> MetricManager
Return env.metric_manager after checking that it exists and that metric_name is one of its terms.
For a metric pull term's build(): the metric manager is constructed ahead of the termination, reward
and observation managers (RLEnvBase._manager_order), so these mistakes surface at env construction
rather than on the first step. term is the pulling term's registry key. An empty metric_name —
the class terms' default, i.e. a configure() that forgot it — raises a ValueError saying so; an
unknown one raises the manager's own KeyError. Both list the active metrics.
Source code in eden/managers/terms/utils.py
resolve_metric_term
¶
resolve_metric_term(env: EnvBase, *, term: str, metric_name: str, expected: type[MetricT]) -> MetricT
The metric term metric_name, checked to be an expected: for a term whose build() reads a task's
metric (its ink, its grade) through the metric's own attributes rather than its value.
Fails as :func:resolve_metric_manager does for a missing manager or name, and with a TypeError naming the
metrics that are an expected when metric_name is some other metric. term is the reading term's name.
Source code in eden/managers/terms/utils.py
soft_dof_pos_violation
¶
Per-DOF distance outside the soft [lower, upper] position band (>= 0, zero inside).
dofs_pos is (..., num_dofs) and soft_limits is (..., num_dofs, 2) ([..., 0] lower,
[..., 1] upper). Sum over the DOF axis for a scalar penalty; compare > 0 for a limit-exceeded mask.
Source code in eden/managers/terms/utils.py
parallel_jaw_is_grasping
¶
parallel_jaw_is_grasping(entity: Entity, contact_info: dict[str, Tensor], left_gripper_link_idx: int, right_gripper_link_idx: int, gripper_idx_local: list[int], force_threshold: float, object_link_idx: int | Tensor | None = None) -> Tensor
Per-env bool (num_envs,): both gripper pads carry contact force aligned with the closing
direction above force_threshold — a parallel-jaw grasp.
Detects a grasp even when the fingers can't fully close (an object is held between them). Shared by
the IsGrasping metric/termination and the ParallelJawWelding action, so both apply the same
force test. They differ only in which contacts it sums:
object_link_idx=None(IsGrasping): each pad's force over all its contacts, so a grasp across two links of one multi-link object counts. So do pads pressing two different objects.object_link_idxgiven (ParallelJawWelding, once per candidate link): only contacts with that link, so both pads must press the one link that would be welded.
contact_info is entity.get_contacts(exclude_self_contact=True). gripper_idx_local is
[left_pad, right_pad] (local link indices) and defines the left→right closing direction; the pad
link indices (entity.get_link(...).idx) are the global indices matched against the contact pairs.
Source code in eden/managers/terms/utils.py
resolve_link_idx
¶
resolve_link_idx(entity: Entity, names: list[str], device, *, preserve_order: bool = True, term: str | None = None, field: str = 'links_name') -> Tensor
Resolve link name patterns to a local-index long tensor (call once in build()).
preserve_order=True matches RigidEntity.find_named_links_idx_local's default.
The entity must be a rigid one. Named links are a RigidEntity API, and so is every reason to
ask for their indices (get_links_pos / get_links_net_contact_force), so a particle or FEM
entity named here has neither the links nor the per-link readings the caller is about to take.
Checking it at this one chokepoint is what spares each link term its own copy — the same reason
:func:resolve_terrain checks get_height rather than leaving it to every height term.
An empty selection always raises. A pattern matching nothing already raises from the inner
resolve_matching_names, but an empty names matches nothing without raising, and every
caller is per-link by design: the silent result is a zero-width observation, a never-firing mask,
or — for the feet_link_names rewards, whose field defaults to [] — a penalty that
reads zero for a whole training run. That is the config mistake this helper exists to catch, so
the check is not opt-in; a caller that genuinely tolerates an empty selection branches before
calling, as :class:~eden.managers.terms.observations.contact.GroupedContactFlags does for its
optional partner links. term (the calling term's class name) and field (the config field
the patterns came from — not links_name on every term) only label the error.
Source code in eden/managers/terms/utils.py
resolve_terrain
¶
Resolve an optional terrain_entity_name to an entity that can report ground height.
None passes through as None — measure against the world-frame z, which is what a flat
scene wants and what Isaac Lab's height terms do. A name is looked up with
:func:~eden.utils.misc.resolve_named_entity, so a typo lists the scene's entities, and the result
is then checked for the one thing :func:base_height_above_ground needs from it: get_height.
Without that check the plausible mistake — naming the flat ground plane rather than a
:class:~eden.entities.terrain.Terrain — reaches the hot path and surfaces as an AttributeError
on the first step, which for a termination term means mid-run rather than at env construction.
Source code in eden/managers/terms/utils.py
base_height_above_ground
¶
base_height_above_ground(entity: Entity, terrain: Entity | None = None, *, relative: bool = False) -> Tensor
Height of an entity's base link above the ground, (num_envs,).
With terrain=None this is the world-frame z of the base — correct on a flat plane and
what Isaac Lab's root_height_below_minimum / base_pos_z measure. Pass a
:class:~eden.entities.terrain.Terrain to subtract the terrain height sampled under the base's
xy instead, which is what makes a height threshold meaningful on rough ground: on a slope the
world z of a perfectly-postured robot tracks the hill, so a fixed floor on it fires at the
bottom and never at the top.
relative selects the frame the base pose is read in, exactly as on
:func:~eden.managers.terms.observations.proprio.base_pos: False (the default, and what
:func:~eden.managers.terms.rewards.locomotion.base_height_l2 uses) is the solver frame, which
Genesis re-origins onto the body's inertial frame; True is the frame the asset was authored
in — the frame default_root_pos and Isaac Lab's root_pos_w are in. The two differ by the
base link's centre-of-mass offset, so a threshold tuned in one frame is wrong in the other.
Source code in eden/managers/terms/utils.py
resolve_per_dof_std
¶
resolve_per_dof_std(std_dict: dict[str, float], robot: Entity, device, *, default: float | None = None, field: str = 'std') -> Tensor
Per-DOF std tensor from a regex -> value dict over the robot's DOF names.
Every DOF must be matched by some pattern (later patterns override earlier ones); DOFs no pattern
matches raise a ValueError naming them, so a std map written for one robot cannot silently
mis-weight another's extra DOFs. An explicit ".*" entry is the opt-in for "everything else gets
this value"; passing default= instead fills unmatched DOFs with that value without raising.
The reverse is deliberately tolerated: a pattern matching no DOF is NOT an error, so one std map
can be shared across robots and carry entries for DOFs only some of them have (e.g. .*head.*
in a map used by both the G1 and the LimX Oli). field names the offending config field in the
error. Call once in build().