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 |
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 |
schema |
The version of the specification of the contents under |
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 |
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
schemais 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 |
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.