Robot models are defined via XML files, where the kinematic structure as well as additional information (e.g. visualizations, joint definitions or physics information) is stored. A robot consists of so-called Robot Nodes
, which hold joint definitions and visualization data. After loading, these data structures can be accessed through the VirtualRobot
library.
In the following examples we start with a simple robot system in order to show how the XML definitions are structured. Later more complex examples are given, where you can see how advanced robot definitions can be created.
This minimal example shows how to define a robot. The file can be found in the doc/tutorial folder of the simox source tree. It can be loaded with VirtualRobot
's RobotViewer
example (located at VirtualRobot/examples/RobotViewer).
<Robot Type="DemoRobot" RootNode="root">
<RobotNode name="root">
</RobotNode>
</Robot>
Now we add a visualization. In the following example, the Coin3D/Qt visualization support is used, indicated by the type="Inventor"
attribute of the visualization's File
tag (in case OpenSceneGraph is used for 3D-model importing and visualization, the attribute would be type="osg"
). The location of the joint.iv
file is given relatively to the location of the XML file, so that the directory iv
is searched for the file joint.iv
.
<Robot Type="DemoRobot" RootNode="root">
<RobotNode name="root">
<Visualization>
<File type="Inventor">iv/joint.iv</File>
</Visualization>
</RobotNode>
</Robot>
The joint.iv
file defines a cylinder in the OpenInventor format. As specified in OpenInventor, the cylinder is aligned with the y axis and it is 500 mm long. In order to set one side of the cylinder to the (local) origin, the object is moved by 250 mm.
#Inventor V2.0 ascii
Separator {
Translation {
translation 0 250 0
}
Cylinder {
radius 40
height 500
parts (SIDES | TOP | BOTTOM)
}
}
In this example the robot gets a movable joint. The Joint
type is specified with the revolute
attribute and the rotation axis. The Transform
tag specifies a fixed transformation that is applied before the joint. Hence, a RobotNode
may imply two transformations:
Transform
This fixed transformation is applied to the parent's global pose. Joint
: This transformation depends on the joint value and the resulting pose specifies the location where the visualization is linked to. This final pose of the RobotNode is noted as GlobalPose
in Simox. This is the starting point for computing the coordinate systems of all children. <Robot Type="DemoRobot" RootNode="root">
<RobotNode name="root">
<Child name="joint 1"/>
</RobotNode>
<RobotNode name="joint 1">
<Transform>
<Translation x="0" y="500" z="0"/>
</Transform>
<Joint type="revolute">
<Axis x="0" y="0" z="1"/>
</Joint>
<Visualization>
<File type="Inventor">iv/joint.iv</File>
</Visualization>
</RobotNode>
</Robot>
Now we build a longer kinematic chain by connecting multiple RobotNodes
. Some of the nodes are fixed (no Joint
tag), while others can be moved indicated by a <Joint type="revolute'>
definition.
<Robot Type="DemoRobot" RootNode="root">
<RobotNode name="root">
<Child name="joint 1"/>
</RobotNode>
<RobotNode name="joint 1">
<Joint type="revolute">
<Axis x="0" y="0" z="1"/>
</Joint>
<Visualization>
<File type="Inventor">iv/joint.iv</File>
</Visualization>
<Child name="node 1"/>
</RobotNode>
<RobotNode name="node 1">
<Transform>
<Translation x="0" y="500" z="0"/>
</Transform>
<Visualization>
<File type="Inventor">iv/ball.iv</File>
</Visualization>
<Child name="joint 2"/>
</RobotNode>
<RobotNode name="joint 2">
<Joint type="revolute">
<Axis x="0" y="1" z="0"/>
</Joint>
<Visualization>
<File type="Inventor">iv/joint2.iv</File>
</Visualization>
<Child name="node 2"/>
</RobotNode>
<RobotNode name="node 2">
<Transform>
<Translation x="0" y="0" z="500"/>
</Transform>
<Visualization>
<File type="Inventor">iv/ball.iv</File>
</Visualization>
<Child name="joint 3"/>
</RobotNode>
<RobotNode name="joint 3">
<Joint type="revolute">
<Axis x="1" y="0" z="0"/>
</Joint>
<Visualization>
<File type="Inventor">iv/joint.iv</File>
</Visualization>
</RobotNode>
</Robot>
A joint can also be definied with Denavit Hartenberg
paramters. Therefore the DH
tag with the two translational attributes a
, d
and with both rotational attributes alpha
and theta
can be used. Please note that you have to specify the units in which the rotation is given (degree
or radian
). Further, the Limits
tag is used to specify the lower and upper joint limits.
<Robot Type="DemoRobot" RootNode="root">
<RobotNode name="root">
<Child name="joint 1"/>
</RobotNode>
<RobotNode name="joint 1">
<Joint type="revolute">
<Limits lo="0" hi="120" units="degree"/>
</Joint>
<Visualization>
<File type="Inventor">iv/joint2.iv</File>
</Visualization>
<Child name="node 1"/>
</RobotNode>
<RobotNode name="node 1">
<Transform>
<DH a="0" d="500" alpha="-90" theta="0" units="degree"/>
</Transform>
<Visualization>
<File type="Inventor">iv/ball.iv</File>
</Visualization>
<Child name="joint 2"/>
</RobotNode>
<RobotNode name="joint 2">
<Joint type="revolute">
<Limits lo="-45" hi="45" units="degree"/>
</Joint>
<Visualization>
<File type="Inventor">iv/joint2.iv</File>
</Visualization>
<Child name="node 2"/>
</RobotNode>
<RobotNode name="node 2">
<Transform>
<DH a="0" d="500" alpha="90" theta="0" units="degree"/>
</Transform>
</RobotNode>
</Robot>
A RobotNode
may cover several transformations.
Transform
: This is a fixed transformation which is applied to the initial pose that is passed by the parent of this node. Joint
: This transformation depends on the joint type and the current joint value. In classical robot systems this transformation applies a rotation. The GlobalPose
of a RobotNode
is always the pose that is retrieved after applying all transformations.
In the following example a finger is modeled with DH parameters. Additionally to the 3D models, the CollisionModel
tag is used to specify visualization files that should be used for collision detection. The CollisionModels
will automatically be used whenever collision detection is performed, hence usually reduced models are used in order to speed up the collision detection. If the visualization models should be used for collision detection as well you can use the <UseAsCollisionModel/>
tag within a <VisualizationModel>
definition, in order to avoid loading the 3D model twice. Further, bounding boxes can be automatically created to be used as CollisionModels
. Therefore you have to use the attribute boundingbox="true"
within the CollisionModel's
File
tag.
<Robot Type="DemoRobot" RootNode="root">
<RobotNode name="root">
<Child name="Finger Joint1"/>
</RobotNode>
<RobotNode name="Finger Joint1">
<Joint type="revolute">
<Limits unit="degree" lo="-25" hi="25"/>
</Joint>
<Visualization enable="true">
<File type="Inventor">iv/LeftIndexFinger/leftIndexFinger0.iv</File>
</Visualization>
<CollisionModel>
<File type="Inventor">iv/LeftIndexFinger/col_leftIndexFinger0.iv</File>
</CollisionModel>
<Child name="BaseToFinger"/>
</RobotNode>
<RobotNode name="BaseToFinger">
<Transform>
<DH a="14.8" d="0" theta="0" alpha="90" units="degree"/>
</Transform>
<Child name="Finger Joint2"/>
</RobotNode>
<RobotNode name="Finger Joint2">
<Transform>
<DH a="0" d="1.75" theta="0" alpha="0" units="degree"/>
</Transform>
<Joint type="revolute">
<Limits unit="degree" lo="0" hi="90"/>
</Joint>
<Visualization enable="true">
<File type="Inventor">iv/LeftIndexFinger/leftIndexFinger1.iv</File>
</Visualization>
<CollisionModel>
<File type="Inventor">iv/LeftIndexFinger/col_leftIndexFinger1.iv</File>
</CollisionModel>
<Child name="Finger Joint3"/>
</RobotNode>
<RobotNode name="Finger Joint3">
<Transform>
<DH a="25.9" d="0" theta="0" alpha="0" units="degree"/>
</Transform>
<Joint type="revolute">
<Limits unit="degree" lo="0" hi="90"/>
</Joint>
<Visualization enable="true">
<File type="Inventor">iv/LeftIndexFinger/leftIndexFinger2.iv</File>
</Visualization>
<CollisionModel>
<File type="Inventor">iv/LeftIndexFinger/col_leftIndexFinger2.iv</File>
</CollisionModel>
<Child name="Finger Joint4"/>
</RobotNode>
<RobotNode name="Finger Joint4">
<Transform>
<DH a="22" d="0" theta="0" alpha="0" units="degree"/>
</Transform>
<Joint type="revolute">
<Limits unit="degree" lo="0" hi="90"/>
</Joint>
<Visualization enable="true">
<File type="Inventor">iv/LeftIndexFinger/leftIndexFingerTip.iv</File>
</Visualization>
<CollisionModel>
<File type="Inventor">iv/LeftIndexFinger/col_leftIndexFingerTip.iv</File>
</CollisionModel>
</RobotNode>
</Robot>
When building complex robot models, usually several parts of the robot can be separated. In order to reflect this fact, robots can be assembled from multiple files. In the following example a robot imports another robot and connects the root node to Joint1
. Further, you can see how coordinate axis visualizations are enabled and that a RobotNode
can have multiple children, allowing to build tree-like kinematic structures.
<Robot Type="robot1" RootNode="Joint1">
<RobotNode name="Joint1">
<Joint type="revolute">
<Limits unit="degree" lo="-90" hi="45"/>
</Joint>
<!-- Imports the kinematic structure form otherRobot.xml and adds otherRobot's rootnode as a child to this node -->
<ChildFromRobot>
<File importEEF="true">robot_howto7b.xml</File>
</ChildFromRobot>
<Child name="node2.1"/>
</RobotNode>
<RobotNode name="node2.1">
<Transform>
<DH a="0" d="500" theta="-30" alpha="0" units="degree"/>
</Transform>
</RobotNode>
</Robot>
The second file (robot_howto7b.xml
) looks like this. The file can also be used as a independent robot model.
<Robot Type="robot2" RootNode="node1">
<RobotNode name="node1">
<Child name="node2"/>
<Child name="node3"/>
</RobotNode>
<RobotNode name="node2">
<Transform>
<Translation x="0" y="500" z="0"/>
</Transform>
<Visualization enable="true">
<CoordinateAxis type="Inventor" enable="true" scaling="1" text="TCP1"/>
</Visualization>
</RobotNode>
<RobotNode name="node3">
<Transform>
<Translation x="0" y="-500" z="0"/>
</Transform>
<Visualization enable="true">
<CoordinateAxis type="Inventor" enable="true" scaling="1" text="TCP2"/>
</Visualization>
</RobotNode>
</Robot>
In VirtualRobot
so-called RobotNodeSets
are used to group joints or to define kinematic chains. A robot node set consists of a set of robot nodes and optionally
RobotNode
defining the Tool Center Point (TCP) coordinate system. This node specifies a TCP for a kinematic chain. The following example shows how a RobotNodeSet
is defined. Please note that the order of the joint definitions is preserved for later use. <Robot Type="DemoRobot" RootNode="root">
<RobotNode name="root">
<Child name="joint 1"/>
</RobotNode>
<RobotNode name="joint 1">
<Joint type="revolute">
<Axis x="0" y="0" z="1"/>
</Joint>
<Visualization>
<File type="Inventor">iv/joint.iv</File>
</Visualization>
<Child name="node 1"/>
</RobotNode>
<RobotNode name="node 1">
<Transform>
<Translation x="0" y="500" z="0"/>
</Transform>
<Visualization>
<File type="Inventor">iv/ball.iv</File>
</Visualization>
<Child name="joint 2"/>
</RobotNode>
<RobotNode name="joint 2">
<Joint type="revolute">
<Axis x="0" y="1" z="0"/>
</Joint>
<Visualization>
<File type="Inventor">iv/joint2.iv</File>
</Visualization>
<Child name="node 2"/>
</RobotNode>
<RobotNode name="node 2">
<Transform>
<Translation x="0" y="0" z="500"/>
</Transform>
<Visualization>
<File type="Inventor">iv/ball.iv</File>
</Visualization>
<Child name="joint 3"/>
</RobotNode>
<RobotNode name="joint 3">
<Joint type="revolute">
<Axis x="1" y="0" z="0"/>
</Joint>
<Visualization>
<File type="Inventor">iv/joint.iv</File>
</Visualization>
<Child name="tcp"/>
</RobotNode>
<RobotNode name="tcp">
<Transform>
<Translation x="0" y="500" z="0"/>
</Transform>
<Visualization>
<File type="Inventor">iv/ball.iv</File>
</Visualization>
</RobotNode>
<RobotNodeSet name="my kinematic chain" kinematicRoot="joint1" tcp="tcp">
<Node name="joint 1"/>
<Node name="joint 2"/>
<Node name="joint 3"/>
</RobotNodeSet>
</Robot>
When complex robot systems, such as humanoid robots, should be modeled a logical definition of their end-effectors is helpful especially in the context of grasp and manipulation planning. In order to access the robot's end-effector conveniently it can be defined in the robot's XML definition. An end-effector is a logical collection of static RobtoNodes
and so-called actors
which are lists of RobotNodes
defining a finger. Please note that the RobotNodes
have to be defined within the robot's XML definition. The static parts are not moved when the end-effector is accessed (e.g. closed or opened), whereas the actors
are moved. As shown in the example below, actors
consist of a set of RobotNodes
and for each node several options can be specified:
name
: The name string of the RobotNode
. This node must be present in the robot's definition. considerCollisions
: Here the behavior for collision detection can be adjusted. Possible options are all
(standard): Collisions between the static part and the RobotNode
and between other actors and the RobotNode
are considered. none
The node is not considered for collision detection. E.g. when closing the hand an actor will not stop if this node is in collision. actors
: Collisions between the static part of teh hand and the node are not considered, but collisions between other actors and the RobotNode
are. static
: Only collisions between this node and the static part of the end-effector are considered, while collision between this node and other actors are not considered. direction
: Here the moving direction can be inverted by setting this value to -1. Further, the relative speed of moving can be adjusted (the standard value is 1). <Robot Type="iCub Left Hand" RootNode="root">
...
<Endeffector name="Left Hand" base="Left Hand Init" tcp="Left Arm TCP" gcp="Left Arm GCP">
<Preshape name="Grasp Preshape">
<Node name="Left Hand Thumb Joint1" unit="radian" value="1.3"/>
</Preshape>
<Static>
<Node name="Left Hand Palm"/>
<Node name="Left Hand Thumb Joint1"/>
</Static>
<Actor name="Left Hand Thumb">
<Node name="Left Hand Thumb Joint2" considerCollisions="Actors"/>
<Node name="Left Hand Thumb Joint3" considerCollisions="All"/>
<Node name="Left Hand Thumb Joint4" considerCollisions="All"/>
</Actor>
<Actor name="Left Hand Index">
<Node name="Left Hand Index Joint2" considerCollisions="Actors"/>
<Node name="Left Hand Index Joint3" considerCollisions="All"/>
<Node name="Left Hand Index Joint4" considerCollisions="All"/>
</Actor>
<Actor name="Left Hand Middle">
<Node name="Left Hand Middle Joint2" considerCollisions="Actors"/>
<Node name="Left Hand Middle Joint3" considerCollisions="All"/>
<Node name="Left Hand Middle Joint4" considerCollisions="All"/>
</Actor>
<Actor name="Left Hand Ring">
<Node name="Left Hand Ring Joint2" considerCollisions="Actors"/>
<Node name="Left Hand Ring Joint3" considerCollisions="All"/>
<Node name="Left Hand Ring Joint4" considerCollisions="All"/>
</Actor>
<Actor name="Left Hand Pinky">
<Node name="Left Hand Pinky Joint2" considerCollisions="Actors"/>
<Node name="Left Hand Pinky Joint3" considerCollisions="All"/>
<Node name="Left Hand Pinky Joint4" considerCollisions="All"/>
</Actor>
</Endeffector>
</Robot>
Scenes can be defined via XML files, allowing to specify a setup for robots and obstacles. Further, configurations can be defined allowing to easily access them later on. The following tags can be used:
Robot
: Define a robot with a name
and an optional initial configuration initConfig
. File
tag specifies the robot's XML file from which the model should be loaded. path
can set to absolute
or relative
, in order to force absolute or relative (w.r.t. the scene file) path names. Configurations
can be defined, which can be accessed via their name strings. RobotNodes
with corresponding joint values. GlobalPose
tag encapsulates a Transfrom
tag which can be used to position the robot in the scene. Obstacles
can be loaded from files. Here the same syntax is provided as when setting Visualization
tags for a RobotNode
: type
of 3d model must be specified in the File
tag. Again the file names are searched in the paths, defined in VirtualRobot::RuntimeEnvironment. Optionally the attributes path='absolute'
or path='relative'
allow to specify absolute or scene-file-relative file names. GlobalPose
can be used to position the object. <UseAsCollisionModel/>
tag ensures that the visualization model is used as a collision model. ManipulationObject
is basically a 3d object with predefined grasping information. These objects can also be positioned via the GlobalPose
tag. <Scene name="Armar3Scene">
<Robot name="Armar3" initConfig="start">
<File>robots/ArmarIII/ArmarIII.xml</File>
<Configuration name="start">
<Node name="Shoulder 1 L" unit="radian" value="-0.85"/>
<Node name="Shoulder 2 L" unit="radian" value="-0.8"/>
<Node name="Upperarm L" unit="radian" value="-0.85"/>
<Node name="Shoulder 1 R" unit="radian" value="-0.85"/>
<Node name="Shoulder 2 R" unit="radian" value="0.8"/>
<Node name="Upperarm R" unit="radian" value="0.85"/>
</Configuration>
<GlobalPose>
<Transform>
<Translation x="1000" y="0" z="0"/>
</Transform>
</GlobalPose>
</Robot>
<Robot name="Armar3b">
<File>robots/ArmarIII/ArmarIII.xml</File>
</Robot>
<Obstacle name="Box">
<Visualization>
<File type="Inventor">objects/iv/box1000x500x300.iv</File>
<UseAsCollisionModel/>
</Visualization>
<GlobalPose>
<Transform>
<Translation x="9000" y="1500" z="150"/>
<rollpitchyaw units="degree" roll="0" pitch="0" yaw="90"/>
</Transform>
</GlobalPose>
</Obstacle>
<ManipulationObject name="Plate">
<File>objects/plate.xml</File>
<GlobalPose>
<Transform>
<Translation x="-250" y="0" z="600"/>
<rollpitchyaw units="degree" roll="90" pitch="0" yaw="90"/>
</Transform>
</GlobalPose>
</ManipulationObject>
</Scene>