Logical Scene Configuration Support

The separation of logical scene and physical scene is a critical feature of the task trees framework. It can largely eliminate the need to modify the source code due to changes in the physical scene, including the environment and the robot manipulator physcial attributes.

The use of string-based logical poses (positions and rotations) also improves code readability, facilitate reusability, and eases code maintainance.

The key enabling component of the logical scene support is scene configuration file, which is a yaml file comprising definitions of logical positions and rotations in the scene, definitions of subscenes and collision objects.

Scene Configuration File

Basic Structure of a Scene Configuration File

A scene configuration file can be divided into one or more scenes. The first scene must be known as root. The scene is the top-level identifier for refering to all the resource keys in the configuration file. Each scene defines its own reference frame and optionally an visual object attached. A scene without a specified visual object is called a frame-type scene or simply known as a frame.

The significance betwwen the root scene and the other scenes is the namespace of their configuration key-value pairs. All key-value defined under the root scene may be replaced with an empty namespace, while the variables under a subscene requires the subscene name as the namespace.

The configuration file must starts with the key scenes, under which each scene can be added by the name as the head the scene branch. In the following example, root is the mandatory scene, and scene_1 and scene_2 are names of custom scenes.

---
scenes:
  root:
  ... variables of the root scene go here

    named_poses:
      ... optional definitions of named poses

  scene_1:
    link: 
      ... pose definitions of scene (which are also reference frames)
    ... variables of the subscene scene_1 go here

  scene_2:
    ... variables of the subscene scene_2 go here

Specifying Configurations in the Root Scene and Other Scenes

Consider the example task_scene_4.yaml source code below. In this example, all configuration keys are under the root scene. No subscene is defined.

---
scenes:
  root:
    named_poses: 
      home: [0.0, -0.785, 0.0, -2.36, 0.0, 1.57, 0.785] # from base
    positions:
      default_z: [null, null, 0.5]
  area_1:
    link:
      parent_frame: root
      type: box
      model_file: null
      dimensions: [0.2, 0.2, 0.01]
      xyz: [0.4, 0.20, 0.00]
      rpy: [0, 0, 3.14]
  area_2:
    link:
      parent_frame: root
      type: box
      model_file: null
      dimensions: [0.2, 0.2, 0.01]
      xyz: [0.4, -0.20, 0.00]
      rpy: [0, 0, 3.14]

A scene is firstly a namespace for queries and key references. It should also be the reference frame to which the poses are defined. The scene name is both the name of a reference frame and, if defined, a collision object.

The scene configuration file below defines one scene called area_1, in which several configuration keys are defined. Note that area_1 is a reference frame (a side effect of defining a collision object). Normally, pose keys such as area_1.positions.start and their scene (referene frame) area_1 are used together in using the move behaviours.

scenes:
  area_1:
    link:
      parent_frame: root
      type: box
      model_file: null
      dimensions: [0.2, 0.2, 0.01]
      xyz: [0.4, 0.20, 0.00]
      rpy: [0, 0, 3.14]
    positions:
      hover: [null, null, 0.40]
      down: [null, null, 0.27]
      start: [0, 0.11, null]
      centre: [0, -0.015, null] # -0.01
      restart: [0, -0.185, null]
      end: [0, -0.06, null]

Loading and Querying the Scene Configuration File

To load the query the logical scene configuration, the task trees framework offers the class task_trees_task_scene.Scene as an alternative. The class recognizes definitions of scene and subscenes and provides a more convenient way to query and obtain configuration values.

from task_trees.task_scene import Scene
...
    self.the_scene = Scene(os.path.join(os.path.dirname(__file__), 'task_scene_4.yaml'))

The Scene class gives every configuration key a unique reference. The reference is a dot-separated string made up of the scene namespace followed by keys of the ancestors of a key-value configuration. For example, the reference named_poses.home refers to the home child of the named_poses node under the root scene (therefore the empty namespace). A configuration key under a subscene has a prepended namespace. For example, area.positions.start refers to the value [0, 0.11, null] in the above example.

The following code snippet demonstrates the functions key_list_under_config_key and query_config for listing the children keys and querying for the value of a configuration reference.

        self.the_scene = Scene(os.path.join(os.path.dirname(__file__), 'task_scene.yaml'))

        # setup name poses
        self.named_poses = self.the_scene.key_list_under_config_key('named_poses')
        for pose_name in self.named_poses:
            pose_name = 'named_poses.' + pose_name
            self.arm_commander.add_named_pose(pose_name, self.the_scene.query_config(pose_name))

Partial Specification of Positions and Rotations

The null value signifies that the component is to be resolved by other specification in a compositional move target. For example the configuration positions.default_z has the value [null, null, 0.5]. Only the z component is specified, and the other components are omitted.

In the following compositional move target example, the missing x and y components are to be provided by the function self.generate_random_xyz.

        DoMoveXYZ('move_xy', True, arm_commander=self.arm_commander, scene=self.the_scene, 
            target_xyz=['positions.default_z', self.generate_random_xyz], reference_frame='area_2'),   

Branches Recognized by the Task Tree Manager

The named branches of link, and named_poses have dedicated functions in the scene configuration.

  • The key link under a scene with the type equals to box, sphere, and object is recognized by the task tree manager TaskTreesManager class as definitions of collision objects. In the task trees, collision objects are also recognized as custom reference frames.

  • The type of frames under the key link of a scene is recognized as definitions of custom reference frames.

  • The keynamed_poses under the root scene is also recognized by the task tree manager as the named poses adding to the arm commander.

The TaskTreesManager class offers the functions _define_links, _define_frames and _define_named_poses for adding the scenes/collision objects, the custom reference frames, and named poses defined in the scene configuration.

Internal Logical References

Subclasses of SceneConditionalCommanderBehaviour accepts internal references when resolving logical positions and rotations. This is handy in avoiding redundency in scene configuration.

The following part of a configuration file is extracted from task_scene.yaml source code under /demos/pushblock.

scenes:
  root:
    named_poses: 
      stow: [0.0, -1.244, 0.0, -2.949, 0.0, 1.704, 0.785] # from base
      home: [0.0, -0.785, 0.0, -2.36, 0.0, 1.57, 0.785] # from base
    regions:
      workspace: [-0.5, -0.75, -0.1, 1.0, 0.5, 1.0]  # min_x, min_y, min_z, max_x, max_y, max_z
      inner: [-0.5, -0.75, 0.30, 0.5]  # min_x, min_y, max_x, max_y
    rotations:
      # alpha: [3.14, null, 0.78] 
      # beta: [3.14, null, -0.78]
      alpha: [3.14, 0, -0.785] 
      beta: [3.14, 0, 2.358]      
    push_block:
        dimensions: [0.05, 0.05, 0.05]
        xyz: [0.0, 0.025, 0.151]
        rpy: [0, 0, 0]    
...
  area_1:
    rotation: rotations.alpha
    link:
      type: box
      model_file: null
      dimensions: [0.1, 0.1, 0.25]
      xyz: [0.4, 0.0, 0.125]
      rpy: [0, 0, 1.57]
  area_2:
    rotation: rotations.beta
    link:
      type: box
      model_file: null
      dimensions: [0.1, 0.1, 0.25]
      xyz: [0.50, -0.10, 0.125]
      rpy: [0, 0, 3.14]
  area_3:
    rotation: rotations.beta
    link:
      type: box
      model_file: null
      dimensions: [0.1, 0.1, 0.25]
      xyz: [0.6, 0.0, 0.125]
      rpy: [0, 0, -1.57]
  area_4:
    rotation: rotations.alpha
    link:
      type: box
      model_file: null
      dimensions: [0.1, 0.1, 0.25]
      xyz: [0.50, 0.10, 0.125]
      rpy: [0, 0, 0] 

The key rotation of the four area scenes are mapped to either rotation.alpha or rotation.beta. For example, in resolving the key area_1.rotation, if the value is a string, SceneConditionalCommanderBehaviour attempts to resolve it once more using the scene configuration.

The internal logical reference feature improves the readability and maintainability of the configuration file.

The Scene class

The functions provided by the Scene class are listed below.

Functions

Remarks

query_config(self, name:str, default=None)

The name is in the format of dot separated reference

exists_config(self, name:str)

Return True if the configuration name exists

key_list_under_config_key(self, key:str)

Return the children keys of a configuration reference as a list

len_of_key_list_under_config_key(self, key:str)

Return the number of children under a list-type configuration reference

list_scene_names(self)

Return the names of the defined scenes as a list

get_scene_config_as_dict(self, scene_name)

Return the scene config branch in the config file as a dict

get_link_of_scene(self, scene_name)

Return the link of the scene as a LinkConfig

list_frame_names(self)

Return the names of the defined frame-type scenes as a list

get_frame_config_as_dict(self, frame_name)

Return the frame-type scene config branch in the config file as a dict

get_link_of_frame(self, frame_name)

Return the link of the frame as a LinkConfig

get_named_poses_of_root_as_dict(self, name)

Return the config of a subscene as a dict

Refer to the API Reference for more details about these functions.

Subclassing the Scene class

Any configuration key-value pair can be queried using the Scene class. A subclass of Scene can be developed to add computation to the configurations.

For example, in the gridscan demo application source code, the physical position in a grid is determined by the grid cell index and the size of grid cell. The class GridScanScene was developed to compute the conversion of grid cell index to the corresponding physical position, based on the grid cell size specified in the scene configuration file.

Customized Configuration File

The function query_config allows the query of any configuration key using a dot-separated query key. Each item in the query key corresponds to a node in the configuration yaml file. The item to reference a list-list structure must be a zero-starting integer. The item to reference a dict-like structure must be a string.

For example, tke query key positions.start refers to a configuration key under the root scene.

scenes:
  root:
    positions:
      start: [1, 2, 3]
      end: [2, 3, 5]

On the other hand, the query key grid.1.rotation.alpha matches the following structure, and it refers to the value [0, 0, 1.57]. The 1 refers to the index 1 of the list-like child under grid.

scenes:
  root:
    grid:
      - rotation:
          alpha: [3.14, 0, 0]
      - rotation:
          alpha: [0, 0, 1.57]

To refer to a configuration key under a non-root scene, the query key should start with the scene name. Given the following configuration yaml file.

subscenes:
  the_tank:
    grid
      - rotation:
          alpha: [3.14, 0, 0]
      - rotation:
          alpha: [0, 0, 1.57]

The query key the_tank.grid.0.rotation.alpha refers to the value [3.14, 0, 0].

Application developers can design a suitable configuration structure and use the function query_config to rerieve configuration values.

Author

Dr Andrew Lui, Senior Research Engineer
Robotics and Autonomous Systems, Research Engineering Facility
Research Infrastructure
Queensland University of Technology

Latest update: Mar 2024