Export Direct-Workflow Policies with LEAPP
This advanced tutorial shows how to prepare a Direct workflow policy for export with LEAPP. If your policy is manager-based, follow the standard LEAPP deployment workflow instead.
For background on LEAPP concepts, supported node patterns, state feedback, and runtime validation, see the LEAPP documentation.
Quick Start
To export a Direct workflow policy with LEAPP, you add LEAPP annotations to the
environment code. During export, LEAPP traces the annotated tensors and builds an
intermediate representation of the full policy pipeline. These annotations remain
dormant during normal environment execution and only add a small amount of
overhead until export time. They are activated by
isaaclab leapp export --rl_library rsl_rl when you run the export flow.
This tutorial uses scripts/tutorials/06_deploy/anymal_c_env.py as a concrete
example of adding LEAPP annotations to a Direct workflow environment. Apply the same
annotation pattern to your own Direct RL environment.
This export flow requires leapp. leapp is a specialized optional extra (it is not
part of --extra all). Select extras the same way as isaaclab train: add
--extra leapp on every uv run, and add the backend extra that matches your task
(isaacsim, ovphysx, or none for kitless Newton). See
Install and run your first task and
/source/policy_deployment/05_leapp/exporting_policies_with_leapp.
If you want to run the exported example with the existing
IsaacContrib-Velocity-Rough-AnymalC-Direct task registration, copy the annotated
tutorial environment into the task package:
Linux
Windows
After your environment includes the required LEAPP input, output, and state annotations, export a trained policy with the same backend extra pattern as training. For example, on Isaac Sim PhysX:
Linux
Windows
The --task argument is the registered task name, such as
IsaacContrib-Velocity-Rough-AnymalC-Direct. The --checkpoint argument
points to the trained RSL-RL checkpoint to export. Train with
uv run isaaclab train --rl_library rsl_rl --task <TASK_NAME> (see
Install and run your first task); do not use the removed per-backend train.py scripts.
The optional --export_save_path argument selects the output directory for the
exported artifacts. If you omit it, the export is written next to the checkpoint.
Unlike with managed environments, export_method is not a command-line option.
Set the export backend in the output annotation itself, for example
annotate.output_tensors(..., export_with="onnx-dynamo"). See the following
output annotation example for guidance.
This tutorial covers exporting direct rl policies only. direct rl
policies are not currently supported by
isaaclab leapp deploy.
For more information on the export arguments, see the standard LEAPP deployment workflow .
How the Annotations Work
The main task is to identify the inputs, outputs, and persistent state in the environment and register them with LEAPP. In this example, the script uses four annotation helpers:
annotate.input_tensorsmarks tensors that enter the policy pipeline.annotate.output_tensorsmarks tensors that leave the environment-side part of the pipeline.annotate.state_tensorsmarks tensors that behave like persistent state.annotate.update_stateupdates that persistent state after each step.
Input Annotations
Input annotations usually belong in _get_observations(), because that method
collects the tensors that are passed to the policy.
annotate.input_tensors() wraps a tensor so LEAPP can trace all downstream
operations that depend on it. The function takes two important arguments:
self.spec.ididentifies the node that owns the tensor. When you runisaaclab leapp export, this ID matches the exported policy node.- The second argument is a dictionary that maps a unique tensor name to the tensor itself. LEAPP uses these names in the exported metadata and for debugging.
In this example, the observation tensors are registered one by one for
readability, but annotate.input_tensors() can also register multiple tensors
in a single call.
Any inputs not explicitly annotated will be automatically inlined as a constant. This may be desired for certain values such as constant transforms or default values.
Output Annotations
Output annotations should be placed where the environment has finished preparing
the command that will be applied to the robot. In this example, that happens in
_pre_physics_step().
annotate.output_tensors() marks the tensors that leave the environment-side
part of the pipeline. As with input annotations, the call uses self.spec.id
together with a dictionary that maps tensor names to tensors.
The export_with argument restricts an output annotation to specific
export backends. The supported backend names are onnx-dynamo, onnx-torchscript,
jit-script, and jit-trace. This argument is needed to actually generate the IR
based on the tracing.
Unlike annotate.input_tensors(), output annotation should happen once for the
final outputs of the pipeline stage. In this example, processed_actions is
the tensor that should be exported. After calling
annotate.output_tensors(), you do not need to use a return value.
All tensors passed to annotate.output_tensors() must be traced tensors.
These tensors are created from inputs or tensors derived from inputs.
Do not place output annotations in _apply_action(). That method may be
called multiple times per environment step, depending on the decimation
setting, which would make the traced pipeline incorrect.
State Annotations
If your policy depends on internal state or feedback loops, register that data
explicitly with annotate.state_tensors() and update it with
annotate.update_state().
In this example, the environment uses the previous action as part of the
observation. That makes previous_actions a feedback state:
annotate.state_tensors()is called in_get_observations()so the state can participate in the traced observation pipeline.annotate.update_state()is called in_pre_physics_step()so the stored value is updated for the next step.
The state name must match across both calls. Here, both functions use the name
previous_actions, which lets LEAPP route the feedback tensor correctly.
Semantic Annotations
This example covers the minimum annotations needed to trace the pipeline. In more advanced export workflows, you may also want to attach semantic metadata so downstream runtimes know what each tensor represents. Semantic Annotations is a prerequisite for being able to deploy to a downstream deployment library.
For direct environments, semantic annotations are optional and need to be
authored explicitly by the user. Unlike the manager-based export path, Isaac Lab
does not infer tensor semantics automatically for direct environments, instead it
is up to the user to provide this data. LEAPP provides this through
TensorSemantics. You can use it to describe the meaning of tensors more
precisely and make the exported pipeline easier to inspect, validate, and integrate
into deployment systems.
Refer to the LEAPP semantic annotation guide and LEAPP API reference for details on authoring semantic annotations.