IO Descriptors 101
In this tutorial, we will learn about IO descriptors, what they are, how to export them, and how to add them to your environments. We will use the Anymal-D robot as an example to demonstrate how to export IO descriptors from an environment, and use our own terms to demonstrate how to attach IO descriptors to custom action and observation terms.
What are IO Descriptors?
Before we dive into IO descriptors, let’s first understand what they are and how they can be useful.
IO descriptors are a way to describe the inputs and outputs of a policy trained using the ManagerBasedRLEnv in Isaac Lab. In other words, they describe the action and observation terms of a policy. This description is used to generate a YAML file that can be loaded in an external tool to run the policies without having to manually input the configuration of the action and observation terms.
In addition to this the IO Descriptors provide the following information:
- The parameters of all the joints in the articulation.
- Some simulation parameters including the simulation time step, and the policy time step.
- For some action and observation terms, it provides the joint names or body names in the same order as they appear in the action/observation terms.
- For both the observation and action terms, it provides the terms in the exact same order as they appear in the managers. Making it easy to reconstruct them from the YAML file.
Here is an example of what the action part of the YAML generated from the IO descriptors looks like for the Anymal-D robot:
Here is an example of what a portion of the observation part of the YAML generated from the IO descriptors looks like for the Anymal-D robot:
Something to note here is that both the action and observation terms are returned as list of dictionaries, and not a dictionary of dictionaries.
This is done to ensure the order of the terms is preserved. Hence, to retrieve the action or observation term, the users need to look for the
name key in the dictionaries.
For example, in the following snippet, we are looking at the projected_gravity observation term. The name key is used to identify the term.
The full_path key is used to provide an explicit path to the function in Isaac Lab’s source code that is used to compute this term. Some flags
like mdp_type and observation_type are also provided, these don’t have any functional impact. They are here to inform the user that this is the
category this term belongs to.
Exporting IO Descriptors from an Environment
In this section, we will cover how to export IO descriptors from an environment. Keep in mind that this feature is only available to the manager based RL environments.
If a policy has already been trained using a given configuration, then the IO descriptors can be exported using:
For example, if we want to export the IO descriptors for the Anymal-D robot, we can run:
When training a policy, it is also possible to request the IO descriptors to be exported at the beginning of the training.
This can be done by setting the export_io_descriptors flag in the command line.
Attaching IO Descriptors to Custom Observation Terms
In this section, we will cover how to attach IO descriptors to custom observation terms.
Let’s take a look at how we can attach an IO descriptor to a simple observation term:
Here, we are defining a custom observation term called base_lin_vel that computes the root linear velocity of the robot.
We are also attaching an IO descriptor to this term. The IO descriptor is defined using the @generic_io_descriptor decorator.
The @generic_io_descriptor decorator is a special decorator that is used to attach an IO descriptor to a custom observation term.
It takes arbitrary arguments that are used to describe the observation term, in this case we provide extra information that could be
useful for the end user:
units: The units of the observation term.axes: The axes of the observation term.observation_type: The type of the observation term.
You’ll also notice that there is an on_inspect argument that is provided. This is a list of functions that are used to inspect the observation term.
In this case, we are using the record_shape and record_dtype functions to record the shape and dtype of the output of the observation term.
These functions are defined like so:
They always take the output tensor of the observation term as the first argument, and the descriptor as the second argument.
In the kwargs all the inputs of the observation term are provided. In addition to the on_inspect functions, the decorator
will also call call some functions in the background to collect the name, the description, and the full_path of the
observation term. Note that adding this decorator does not change the signature of the observation term, so it can be used safely
with the observation manager!
Let us now take a look at a more complex example: getting the relative joint positions of the robot.
Similarly to the previous example, we are adding an IO descriptor to a custom observation term with a set of functions that probe the observation term.
To get the name of the joints we can write the following function:
Note that we can access all the inputs of the observation term in the kwargs dictionary. Hence we can access the asset_cfg, which contains the
configuration of the articulation that the observation term is computed on.
To get the offsets, we can write the following function:
With this in mind, you should now be able to attach an IO descriptor to your own custom observation terms! However, before we close this tutorial, let’s take a look at how we can attach an IO descriptor to a custom action term.
Attaching IO Descriptors to Custom Action Terms
In this section, we will cover how to attach IO descriptors to custom action terms. Action terms are classes that
inherit from the managers.ActionTerm class. To add an IO descriptor to an action term, we need to expand
upon its ~managers.ActionTerm.IO_descriptor property.
By default, the ~managers.ActionTerm.IO_descriptor property returns the base descriptor and fills the following fields:
name: The name of the action term.full_path: The full path of the action term.description: The description of the action term.export: Whether to export the action term.
To add more information to the descriptor, we need to override the ~managers.ActionTerm.IO_descriptor property.
Let’s take a look at an example on how to add the joint names, scale, offset, and clip to the descriptor.
This is it! You should now be able to attach an IO descriptor to your own custom action terms which concludes this tutorial.