Project File Specification

Overview

Work done in Choreonoid is managed as a Projects and can be saved as a “project file”. Project files are usually given the extension “.cnoid”.

This section explains the format of these project files. Project files are normally read and written automatically by Choreonoid, so users do not need to edit them directly. However, understanding their structure is useful when you want to:

  • Check the contents of a project as text

  • Manage differences with a version control system

  • Generate or process project files with scripts

  • Develop a plugin and design what an item saves

Basic Structure

A project file is a text file in YAML format. The following keys appear at the top level.

items:
  ...
views:
  ...
toolbars:
  ...
Body:
  ...
view_areas:
  ...
toolbar_layout:
  ...

The content of each key is as follows.

Key

Content

items

The contents of the items that make up the project. This is the central part of a project file.

views

The states of the views.

toolbars

The states of the toolbars.

view_areas

The arrangement (layout) of the views.

toolbar_layout

The arrangement of the toolbars.

others

Sections whose keys are plugin names. They are used when a plugin saves information other than the above.

Among these, view_areas and toolbar_layout are output only when Saving Layout is enabled. In addition, sections whose contents are empty are not output. For example, if the states of the views and toolbars are all left as default, views and toolbars do not appear.

Note that when specific plugins are required to load the project, a description like the following may be placed at the beginning of the file.

optional_plugins: [ PhysX, MuJoCo, Bullet, ODE, AGXDynamics ]

This indicates that the corresponding plugins should be loaded if they are available. Even in an environment where those plugins do not exist, the project can be loaded excluding those parts.

Description of Items

Under items, the Item Tree starting from the root item is stored. Each item is described with the following structure.

items:
  id: 0
  name: "RootItem"
  plugin: Base
  class: RootItem
  is_builtin_item: true
  children:
    -
      id: 1
      name: "World"
      plugin: Body
      class: WorldItem
      is_checked: true
      data:
        collision_detection: false
        collision_detector: AISTCollisionDetector
      children:
        -
          id: 2
          name: "SR1"
          ...

The keys common to all items are as follows.

Key

Content

id

An integer value that uniquely identifies the item within the project. See Item Identifiers for details.

name

The item name. This is the name displayed in the item tree view.

plugin

The name of the plugin that provides this item type.

class

The name of the item type (Item Types). The item type is identified by combining this with plugin.

data

The contents specific to each item type. See Item-Specific Contents for details.

children

The list of child items. The structure of the item tree is expressed by this.

is_checked

Written when the check box of the item is turned on.

is_builtin_item

Written for items that the system provides as standard, such as the root item.

When the item type cannot be identified by plugin and class, that is, when the corresponding plugin is not loaded, that item is skipped. In this case, the loading of the whole project still continues, and a message about it is displayed in the message view. Since a project file is written by many plugins in a divided manner, it is not practical to make the whole file unloadable because a part of it cannot be interpreted.

Item-Specific Contents

The contents under data are freely defined for each item type. They are read and written by the store and restore functions of the item class, and which keys are used is left to the implementation of each item class.

For example, in the case of a body item, contents like the following are stored.

data:
  schema: 2
  file: "${SHARE}/model/SR1/SR1.body"
  format: CHOREONOID-BODY
  current_base_link: "WAIST"
  root_translation: [ 0, 0, 0.7135 ]
  root_rotation: [ 1, 0, 0, 0 ]
  joint_displacements: [ 0, -2.1, 0, 4.5, ... ]
  fix_root: false

Although the contents are free for each item type, there are common conventions for some keys.

Key

Content

file

The path of the file when the contents of the item are loaded from a file.

format

A string that identifies the file format of file. It is used to determine which format to use when the same kind of data can be loaded in multiple file formats.

schema

The version of the specification of the contents under data. See Schema Version for details.

For items that correspond to a file, the contents of the item themselves are not stored in the project file but are saved as a reference by file and format. In the case of a body item, for example, the shape and joint structure of the model are on the side of the Model Files, and only its path and the current state such as the joint displacements are recorded in the project file. Therefore, when saving or moving a whole project, the referenced files must also be managed together.

A description such as ${SHARE} included in the path of file is a variable representing a directory of Choreonoid, and it is expanded to the actual path when loading. This makes it possible to use the same project file even in environments where the installation destination differs. A path relative to the project file may also be written.

Item Identifiers

The id given to each item is an identifier for referring to the item within the project file. The numbers are assigned in order while traversing the item tree when the project is saved, and they are not values that the items themselves hold permanently. Even for the same project, different values may be assigned each time it is saved.

This identifier is provided because references cannot be uniquely determined by item names. Item names are allowed to be duplicated, and references must not break when a name is changed.

References by id are mainly used in the following places.

First, when an item refers to another item. In this case, the id of the other item is written under data.

data:
  item1: 3
  item2: 5

Next, when a view records the items it targets. For example, the item tree view records the items expanded in the tree as a list of id values.

views:
  -
    id: 1
    plugin: Base
    class: ItemTreeView
    mounted: true
    state:
      expanded: [ 1, 2, 5 ]

They are also used when referring to items from a section saved by a plugin.

Body:
  "OperableSceneBody":
    scene_bodies:
      -
        body_item: 1
        show_cm: false

Note that when the reference target is a sub item that constitutes a Composite Items, it is written not as a single integer but as a list consisting of the id of the parent item and the sub item names from it.

data:
  target_item: [ 2, "SubItemName" ]

When loading, the actual items are resolved from these values. However, since they cannot be resolved while the referenced items have not been created yet, a mechanism is provided to resolve the references after the construction of the whole item tree is completed. When saving references between items in plugin development, this point must be taken into account.

States of Views

Under views, the state of each view is stored as a list.

views:
  -
    id: 0
    plugin: Base
    class: ItemPropertyView
    mounted: true
  -
    id: 4
    plugin: Base
    class: SceneView
    mounted: true
    state:
      operation_mode: view
      floor_grid: true
      background_color: [ 0.1, 0.1, 0.3 ]
      cameras:
        -
          camera: Perspective
          is_current: true
          eye: [ 3, 1.5, 1.2 ]
          direction: [ -0.880451, -0.440225, -0.17609 ]
          up: [ -0.1575, -0.0787499, 0.984374 ]
      ...

The keys of each view are as follows.

Key

Content

id

An integer value that identifies the view within the project file. It is used when referring to the view from view_areas. This is a different system from the id of items.

plugin

The name of the plugin that provides this view type.

class

The name of the view type (view class).

name

A name to distinguish views when multiple views of the same view type can be created.

mounted

Written when the view is placed on the main window.

state

The state specific to each view type. The contents depend on the implementation of each view class.

The contents of state are freely defined for each view type. In the case of the scene view, for example, the position and orientation of the cameras, the rendering mode, and the settings of the grids and light sources are stored.

States of Toolbars

Under toolbars, the state of each toolbar is stored with the toolbar name as its key.

toolbars:
  "TimeBar":
    current_time: 0
    min_time: 0
    max_time: 30
    frame_rate: 1000
    playback_frame_rate: 60
    playback_speed_ratio: 1
  "KinematicsBar":
    forward_kinematics: true
    inverse_kinematics: true
    preset_kinematics: true

Unlike views, toolbars are identified by name. The contents are freely defined by the implementation of each toolbar.

Plugin-Specific Sections

When a plugin saves information that does not belong to an item or a view, a section with the plugin name as its key is created.

Body:
  "KinematicFaultChecker":
    checkJointPositions: true
    angleMargin: 0
  "OperableSceneBody":
    scene_bodies:
      -
        body_item: 1
        show_cm: false

In this example, the Body plugin saves the settings of the kinematic fault checker dialog and the display state of the bodies in the scene. The structure inside a section can be freely decided by the plugin.

Layout

view_areas stores the arrangement of the views, and toolbar_layout stores the arrangement of the toolbars. These are output only when Saving Layout is enabled.

view_areas is expressed by a nested structure of “splitters” that divide the screen and “panes” that hold views.

view_areas:
  -
    type: embedded
    tabs: true
    contents:
      type: splitter
      orientation: horizontal
      sizes: [ 969, 307 ]
      children:
        -
          type: pane
          views: [ 1 ]
        -
          type: pane
          views: [ 0, 8 ]
          current: 0

In splitter, the direction of division is specified by orientation and the ratio of division by sizes. In views of pane, the views placed in that pane are listed by the id values in the views section. When multiple views are placed in one pane, they are switched by tabs, and current indicates the view that is currently selected.

In toolbar_layout, the arrangement of the toolbars for each row is described.

toolbar_layout:
  rows:
    -
      - { name: "FileBar", x: 0, priority: 0 }
      - { name: "SimulationBar", x: 0, priority: 2 }
    -
      - { name: "BodyBar", x: 0, priority: 0 }
      - { name: "KinematicsBar", x: 0, priority: 1 }

Schema Version

The specification of what an item saves may be changed as the development of Choreonoid proceeds. To avoid making existing project files unreadable in this case, a key called schema can be written under data to indicate the version of the specification of the saved contents.

data:
  schema: 2
  ...

Since schema determines how the item-specific contents should be interpreted, it is written at the beginning of data.

The meaning of the value of this key is defined independently for each item type. There is no relationship between the schema of one item type being 2 and the schema of another item type being 2. The format of the value can also be freely decided by each item type. It may be a simple integer version number, or a string or list may be used if necessary.

The reason the version of the specification is managed for each item type in this way is that a project file is a composite document written by the main body and many plugins in a divided manner. A scheme in which the whole project has a single version number cannot cope with the case where a plugin developed externally changes its specification on its own. By managing the version with the same unit as the entity that writes the saved contents, each item type can evolve its specification independently.

The conventions for handling schema are as follows.

  • When schema is not written, it is regarded as the first specification of that item type (corresponding to version 1). This makes it possible to load project files saved before this mechanism was introduced in the same way as before.

  • The version is raised when a change is made that alters the interpretation of the saved contents. It does not need to be raised for changes that an old implementation can safely ignore, such as adding a key.

  • On the loading side, the version should be judged with a “greater than or equal to” comparison. By doing this, the changes made up to that point are carried over even when the version is raised further in the future.

  • When the loading side encounters a new version that it does not expect, it outputs a warning and then continues loading as far as it can interpret. Since a project consists of many items, restoring as much as possible is more practical than aborting the loading of the whole project because a part of it cannot be interpreted.

Note that what this mechanism can cope with is the case where a new implementation loads an old project file. Conversely, when an old implementation loads a new project file, the existence of schema itself is not recognized, so the contents may not be interpreted correctly.

Schema of the Body Item

For reference, the history of schema in the body item is shown below.

Value

Content

1

The first specification. The schema key is not written. In joint_displacements and initial_joint_displacements, which store joint displacements, the values of prismatic joints were also converted to degrees in the same way as those of revolute joints.

2

The joint displacements of prismatic joints are written in meters as they are.

In version 1, the same conversion was applied to the values of prismatic joints both when loading and when writing, so the state of the project itself was restored correctly, but the numbers in the file did not have a physical meaning. This is corrected in version 2.

Sub Projects

A part of a project can be separated as another project file and loaded for use. This is called a “sub project” and is handled by a sub project item.

The file of a sub project itself is also in the same format as a normal project file. However, when it is saved as a sub project, the layout information given by view_areas and toolbar_layout is not included. The layout is something that is determined once for the whole project, and it is not something that a sub project, which is a part of it, should have on its own.