Config-3: Importing, editing & manipulating them
This scripts loads a mini scene defined in ‘mini.g’.
The ‘watchFile’ command allows you to edit the file in some other editor, while it is being redisplayed whenever you save.
‘set/getJointState’ shows how to access degrees-of-freedom of the scene
‘eval’ shows how to access other features, including its Jacobian
Importing robot models
Let’s first have a look at robot models that are already installed with rai. (They are defined in the rai-robotModels
github repo, which is partly copied into the .../site-packages/robotic/rai-robotModels
install path.)
[ ]:
import robotic as ry
[ ]:
print('The path where model files are pre-installed:\n', ry.raiPath(''))
# you could overwrite this with:
# ry.setRaiPath('your_path/rai-robotModels/')
[ ]:
C = ry.Config()
C.addFile(ry.raiPath('panda/panda.g')) .setPosition([1.,.0,.0]) .setQuaternion([1,0,0,1])
C.addFile(ry.raiPath('panda/panda.g'), 'r_') .setPosition([1.5,.0,.0]) .setQuaternion([1,0,0,1])
C.addFile(ry.raiPath('robotiq/robotiq.g')) .setParent(C.getFrame('panda_joint7')) .setRelativePosition([0., 0., .15])
C.addFile(ry.raiPath('g1/g1.g')) .setPosition([.5, 0., .8]) .setQuaternion([1,0,0,1])
C.addFile(ry.raiPath('pr2/pr2.g')) .setPosition([-.5,.0,.0])
C.addFile(ry.raiPath('baxter/baxter.g')) .setPosition([-1.5,.0,1.]) .setQuaternion([1,0,0,1])
C.view()
The addFile
returns the first frame defined in the file, which typically is the base frame of the whole robot. Therefore, by setting it’s position, you can move the whole loaded robot.
Sometimes you want to add a model twice, but avoid duplicated frame names. With addFile
you can specify a prefix
string (here r_
) which add that prefix to all frame names of the added robot. This is exemplified with the second panda added here.
The Robotiq example also shows that this base frame can be made a child of other frames – attaching the robotiq to the panda arm. (Here in addition to the existing gripper, which would first have to be removed using C.delFrame
.)
The following is a simple helper to articulare all dofs in the display (press q
to interrupt):
[ ]:
#C.animate()
C.animateSpline(5)
[ ]:
del C
Creating a grid of duplicated configurations
It’s become populat to setup simulations to include a grid of copies of the scene. Here how to do this:
[ ]:
import robotic as ry
[ ]:
C = ry.Config()
table = C.addFrame('table') .setShape(ry.ST.ssBox,[.5, .5, .1, .01]) .setPosition([0,0,1]) .setColor([.2])
panda = C.addFile(ry.raiPath('panda/panda.g'))
panda.setParent(table) .setRelativePosition([0,0,.05])
C.view()
[ ]:
Cgrid = ry.Config()
d = 6
for x in range(d):
for y in range(d):
base = Cgrid.addConfigurationCopy(C, f'x{x}_y{y}_') #the string adds a prefix to all frame names
base.setPosition([x-(d-1)/2,y-(d-1)/2,1])
print('#frame in grid:', Cgrid.getFrameDimension())
print('1st frame\'s name:', Cgrid.getFrames()[0].name)
Cgrid.view()
[ ]:
Cgrid.animateSpline()
[ ]:
del Cgrid
Conversion from URDF
The python package should install a script urdf2rai.py
in .local/bin
. That converts a urdf-file to a .g-file. For instance, place a ur10.urdf
and the ur_description
folder into the same folder and run:
urdf2rai.py ur10.urdf > ur10_org.g
That should generate a ur10_org.g
file that can be displayed with kinEdit ur10_org.g
. Note, by default that excludes exporting collision shapes (as I typically replace them, e.g. by the convex hull of the visual shapes). The -coll 1
option of the script should include also the collision shapes. The rai-robotModels
repository README provides more info on conversion from URDF, as well as specific examples for those models included in the package.
Configuration file (.g-file) syntax
The Appendix:Yaml-Graph Files provides a more detailed description of the underlying syntax of the .g-files. While the syntax should be yaml compatible, the fact that node names use (<parents>)
to define the parent(s) of a node, filenames should be strings <filename>
, and the additional Include
, Edit
, and Delete
tags extend the semantics of what can be define in such a file.
In essence, to describe a robot/world configuration, every node describes a frame, and is described by three things: <frame-name> ( <parent> ) { <attributes> }
, where <parent>
needs to be a previously defined frame, or omitted, if the frame is a root frame. The attributes define properties of the frame, such as its pose (X
), relative transformation (Q
), shape, joint, and inertia properties. The main interpreted attributes are the following. Internally, a few more attributes are
interpreted in experimental code (also your python code can retrieve attributes via f.info()
).
Frame: X Q
Shape: shape size contact mesh meshscale core sdf color texture
Joint: joint joint_scale q Q limits ctrl_limits ctrl_H sampleUniform joint_active mimic
Inertia: mass inertia
Interactive Editing
When developing your own model (robot or scene), you could of course just use the python commands addFrame
etc. But that might be cumbersome and not interactive enough. The .g-file format is fairly easy to edit. To help doing this more interactively, there is the watchFile
method:
Open the file you want to edit (here mini.g
) in any editor. At the same time, open it from within python and display it using watchFile
. The key benefit is that watchFile
reloads and re-displays the file whenever it is externally modified (it watches the file’s inode). That enables interactive editing. It also allows you to return information on objects you point on (their name and attributes), which helps a lot to inspect models. It also reports on collisions in the configuration.
A ry-view
command line script is shipped with the python package, which simply calls watchFile
. Editing from command line with this script makes it easier to see the info and error messages, e.g. when you get the syntax wrong. Jupyter is problematic, as it holds info messages back – still, here an example directly from within python:
[ ]:
import robotic as ry
[ ]:
C = ry.Config()
C.watchFile('mini.g')
[ ]:
del C
How to attach frames - faking grasps
Note, this is not real grasping. Just editing the kinematic tree in your configuration
[ ]:
import robotic as ry
import numpy as np
import time
[ ]:
C = ry.Config()
C.addFile(ry.raiPath('scenarios/pandasTable.g'))
C.view()
[ ]:
C.attach("l_gripper", "r_gripper")
[ ]:
#move a bit around
q = C.getJointState()
for t in range(30):
q[0] = np.sin(t/10)
C.setJointState(q)
C.view()
time.sleep(0.1)
[ ]:
del C
Advanced: YAML and dict representations
The following shows that configuration files are essentially YAML files with some special semantics. We can load the configuration description as a dict using yaml as follows:
[ ]:
import yaml
with open(ry.raiPath('panda/panda_clean.g'), 'r', encoding='utf-8') as fil:
model = yaml.safe_load(fil)
print(model)
This dict contains all information about the configuration.
[ ]: