# Copyright (c) 2022-2025, The Isaac Lab Project Developers.# All rights reserved.## SPDX-License-Identifier: BSD-3-Clause"""Common functions that can be used to activate certain terminations.The functions can be passed to the :class:`isaaclab.managers.TerminationTermCfg` object to enablethe termination introduced by the function."""from__future__importannotationsimporttorchfromtypingimportTYPE_CHECKINGfromisaaclab.assetsimportArticulation,RigidObjectfromisaaclab.managersimportSceneEntityCfgfromisaaclab.sensorsimportContactSensorifTYPE_CHECKING:fromisaaclab.envsimportManagerBasedRLEnvfromisaaclab.managers.command_managerimportCommandTerm"""MDP terminations."""
[docs]deftime_out(env:ManagerBasedRLEnv)->torch.Tensor:"""Terminate the episode when the episode length exceeds the maximum episode length."""returnenv.episode_length_buf>=env.max_episode_length
[docs]defcommand_resample(env:ManagerBasedRLEnv,command_name:str,num_resamples:int=1)->torch.Tensor:"""Terminate the episode based on the total number of times commands have been re-sampled. This makes the maximum episode length fluid in nature as it depends on how the commands are sampled. It is useful in situations where delayed rewards are used :cite:`rudin2022advanced`. """command:CommandTerm=env.command_manager.get_term(command_name)returntorch.logical_and((command.time_left<=env.step_dt),(command.command_counter==num_resamples))
"""Root terminations."""
[docs]defbad_orientation(env:ManagerBasedRLEnv,limit_angle:float,asset_cfg:SceneEntityCfg=SceneEntityCfg("robot"))->torch.Tensor:"""Terminate when the asset's orientation is too far from the desired orientation limits. This is computed by checking the angle between the projected gravity vector and the z-axis. """# extract the used quantities (to enable type-hinting)asset:RigidObject=env.scene[asset_cfg.name]returntorch.acos(-asset.data.projected_gravity_b[:,2]).abs()>limit_angle
[docs]defroot_height_below_minimum(env:ManagerBasedRLEnv,minimum_height:float,asset_cfg:SceneEntityCfg=SceneEntityCfg("robot"))->torch.Tensor:"""Terminate when the asset's root height is below the minimum height. Note: This is currently only supported for flat terrains, i.e. the minimum height is in the world frame. """# extract the used quantities (to enable type-hinting)asset:RigidObject=env.scene[asset_cfg.name]returnasset.data.root_pos_w[:,2]<minimum_height
"""Joint terminations."""
[docs]defjoint_pos_out_of_limit(env:ManagerBasedRLEnv,asset_cfg:SceneEntityCfg=SceneEntityCfg("robot"))->torch.Tensor:"""Terminate when the asset's joint positions are outside of the soft joint limits."""# extract the used quantities (to enable type-hinting)asset:Articulation=env.scene[asset_cfg.name]# compute any violationsout_of_upper_limits=torch.any(asset.data.joint_pos>asset.data.soft_joint_pos_limits[...,1],dim=1)out_of_lower_limits=torch.any(asset.data.joint_pos<asset.data.soft_joint_pos_limits[...,0],dim=1)returntorch.logical_or(out_of_upper_limits[:,asset_cfg.joint_ids],out_of_lower_limits[:,asset_cfg.joint_ids])
[docs]defjoint_pos_out_of_manual_limit(env:ManagerBasedRLEnv,bounds:tuple[float,float],asset_cfg:SceneEntityCfg=SceneEntityCfg("robot"))->torch.Tensor:"""Terminate when the asset's joint positions are outside of the configured bounds. Note: This function is similar to :func:`joint_pos_out_of_limit` but allows the user to specify the bounds manually. """# extract the used quantities (to enable type-hinting)asset:Articulation=env.scene[asset_cfg.name]ifasset_cfg.joint_idsisNone:asset_cfg.joint_ids=slice(None)# compute any violationsout_of_upper_limits=torch.any(asset.data.joint_pos[:,asset_cfg.joint_ids]>bounds[1],dim=1)out_of_lower_limits=torch.any(asset.data.joint_pos[:,asset_cfg.joint_ids]<bounds[0],dim=1)returntorch.logical_or(out_of_upper_limits,out_of_lower_limits)
[docs]defjoint_vel_out_of_limit(env:ManagerBasedRLEnv,asset_cfg:SceneEntityCfg=SceneEntityCfg("robot"))->torch.Tensor:"""Terminate when the asset's joint velocities are outside of the soft joint limits."""# extract the used quantities (to enable type-hinting)asset:Articulation=env.scene[asset_cfg.name]# compute any violationslimits=asset.data.soft_joint_vel_limitsreturntorch.any(torch.abs(asset.data.joint_vel[:,asset_cfg.joint_ids])>limits[:,asset_cfg.joint_ids],dim=1)
[docs]defjoint_vel_out_of_manual_limit(env:ManagerBasedRLEnv,max_velocity:float,asset_cfg:SceneEntityCfg=SceneEntityCfg("robot"))->torch.Tensor:"""Terminate when the asset's joint velocities are outside the provided limits."""# extract the used quantities (to enable type-hinting)asset:Articulation=env.scene[asset_cfg.name]# compute any violationsreturntorch.any(torch.abs(asset.data.joint_vel[:,asset_cfg.joint_ids])>max_velocity,dim=1)
[docs]defjoint_effort_out_of_limit(env:ManagerBasedRLEnv,asset_cfg:SceneEntityCfg=SceneEntityCfg("robot"))->torch.Tensor:"""Terminate when effort applied on the asset's joints are outside of the soft joint limits. In the actuators, the applied torque are the efforts applied on the joints. These are computed by clipping the computed torques to the joint limits. Hence, we check if the computed torques are equal to the applied torques. """# extract the used quantities (to enable type-hinting)asset:Articulation=env.scene[asset_cfg.name]# check if any joint effort is out of limitout_of_limits=torch.isclose(asset.data.computed_torque[:,asset_cfg.joint_ids],asset.data.applied_torque[:,asset_cfg.joint_ids])returntorch.any(out_of_limits,dim=1)
"""Contact sensor."""
[docs]defillegal_contact(env:ManagerBasedRLEnv,threshold:float,sensor_cfg:SceneEntityCfg)->torch.Tensor:"""Terminate when the contact force on the sensor exceeds the force threshold."""# extract the used quantities (to enable type-hinting)contact_sensor:ContactSensor=env.scene.sensors[sensor_cfg.name]net_contact_forces=contact_sensor.data.net_forces_w_history# check if any contact force exceeds the thresholdreturntorch.any(torch.max(torch.norm(net_contact_forces[:,:,sensor_cfg.body_ids],dim=-1),dim=1)[0]>threshold,dim=1)