OctaveMATLAB

From OpenRAVE
Jump to: navigation, search


Contents

Installation

Unfortunately, MATLAB mex file binaries cannot be re-distributed with OpenRAVE since there are many versions of the tool and the compilers are non-free. Therefore, starting with OpenRAVE 0.4, the mex source files are distributed in the share/openrave-*/matlab directory. In order to use MATLAB, will need to compile each of the cpp files into mex files and add that directory to your MATLAB path. The files are:

- orcreate.cpp - orread.cpp - orwrite.cpp

Windows users have a special runmex.bat file to help them with this.

Introduction to Scripting

One of the biggest features that separates OpenRAVE from other simulation/planning environments is that it supports scripting over the network. This makes it possible to free OpenRAVE of complex GUIs. At initialization, OpenRAVE starts listening on specific ports for the commands. This allows any computer to open a socket connection with OpenRAVE, which can be running on a different computer, and communicate with it. The official release supports Matlab and Octave as the scripting engines. Note that all script commands are sent as text across the network; therefore, it is possible to do everything in Python or Perl.

The rest of this document is written using the Matlab/Octave functions found in the matlab/ directory. For any function, type 'help functionname' to get a help message describing its parameters and usage. Some formatting rules:

  • All OpenRAVE functions start with or.
  • All KinBody specific functions start with orBody.
  • All Robot specific functions start with orRobot. Every robot can use all orBody functions.
  • All general environment functions start with orEnv.
  • All problem instance specific functions start with orProblem

Check out the RaveServer constructor in src/server.cpp for a complete list of commands supported.

Examples

All examples can be found in $INSTALL/share/openrave/octave

To run MATLAB/Octave examples, first start openrave and then in a separate terminal execute the *.m files.

Communicating with OpenRAVE

Usually communicating with an OpenRAVE instance running on the same computer as the scripting environment is simple. Just call the methods in the matlab folder directly without having to worry about setting ip address. If OpenRAVE is running on a different computer, the IP address will have to be set manually through a global variable orConnectionParams. To set the address of the remote OpenRAVE in Octave/Matlab instance type

global orConnectionParams
orConnectionParams.ip = 'myopenrave_ip'; 
orConnectionParams.port = 4765; 

The scripting environment can communicate with multiple OpenRAVE instances at once, just set orConnectionParams to the appropriate instance. Also, OpenRAVE can handle multiple scripting environments talking to the same instance simultaneously.

Openrave network.png

The default port openrave starts is 4765, use the -server option to change the port. For example,

./openrave -server 3000

starts openrave to listen for connections on port 3000.

Tutorial

NOTE: Remember that warnings and responses can appear both in the Matlab/Octave window and the console window where openrave is started from.

Basic commands

First start openrave and leave it in the background. Then start an Octave or Matlab instance and make sure the paths to the Octave/Matlab scripts are added to the path.

To load a simple scene with the Barrett WAM and Hand: <source lang="matlab"> orEnvLoadScene('data/lab1.env.xml', 1) </source>

The 1 is a flag to reset the whole OpenRAVE scene before loading lab1.env.xml. If it wasn't there, lab1.env.xml would get appended to the current OpenRAVE scene. Now let's query and display all the objects in the scene <source lang="matlab"> bodies = orEnvGetBodies() celldisp(bodies) </source>

Every object has a unique id. Use this id for any function that performs an operation on the object. We can move the first joint of the robot 0.5 radians by <source lang="matlab"> orRobotSetDOFValues(1,0.5,0) </source>

or the first 10 joints: <source lang="matlab"> orRobotSetDOFValues(1,0.5*ones(1,10),0:9) </source>

Here '1' is the unique id of the robot.

If the third argument is not specified, then the default degrees of fredom (joints) used will be the active DOFs. The default active DOFs are all the joints of the robot. To make only the first 7 joints active type: <source lang="matlab"> orRobotSetActiveDOFs(1,0:6,0) </source>

To get the number of active dofs type: <source lang="matlab"> orRobotGetActiveDOF(1) </source>

The concept of active DOFs is very powerful. All planners search only in the active DOFs when planning. In this example, the robot is a combination of an arm and a hand. Most of the time, we would only want to plan and move the arm while ignoring the hand. To do this, set the active DOFs to the joint indices of the arm only before calling the planner. Active DOFs are not limited to just joints, they can also be the translation or rotation components of the robot itself. For example, to plan for the robot arm while it is moving on the xy plane type: <source lang="matlab"> orRobotSetActiveDOFs(1,0:6,3) </source>

To have it rotate around the z-axis at the same time, type: <source lang="matlab"> orRobotSetActiveDOFs(1,0:6,11,[0 0 1]) </source>

Now, <source lang="matlab"> orRobotGetActiveDOF(1) </source>

returns 10: 7 for the arm, 2 for xy planar translation, and 1 for the rotation around z.

To query the transformations of all the links of the robot type: <source lang="matlab"> L = orBodyGetLinks(1) </source>

This will return a 12xN matrix for N links, where each column is a 3x4 transformation matrix (left 3x3 is a rotation, and last column is the translation component). For example, to extract the tranformation matrix of the second link, type: <source lang="matlab"> T = reshape(L(:,2),[3 4]) </source>

To set the transformation of the base robot do <source lang="matlab"> orBodySetTransform(1,[0 0 1],[0.707 0.707 0 0]) </source>

This will set the translation to (0,0,1). The third parameter is a rotation around the X axis by 90 degrees in quaternion form. It is also possible to directly input a 3x4 transformation matrix T by: <source lang="matlab"> orBodySetTransform(1,reshape(T,[1 12])) </source>

To add a cup on top of the table named 'table' type: <source lang="matlab"> destTransform = orBodyGetTransform(orEnvGetBody('table')); destPosition = destTransform(10:12); cupPosition = destPosition + [0;0;0.1]; cupid = orEnvCreateKinBody('MyCup','data/mug1.kinbody.xml'); orBodySetTransform(cupid, cupPosition,[0.707 0.707 0 0]); </source>

Executing planners - A Grasping Example

Openrave dishwasher.jpg

In this part, we'll be loading the manipulation plugin and using its various features to plan in the lab1.env.xml workspace with the BarrettWAM. The manipulation plugin exposes a Manipulation ProblemInstance and the Inverse Kinematics functions for the Barrett WAM arm.

First load <source lang="matlab"> orEnvLoadScene('data/lab1.env.xml', 1) robotid = orEnvGetBody('BarrettWAM') manipid = orEnvCreateProblem('BaseManipulation', 'BarrettWAM') </source>

Each ProblemInstance supports a 'SendCommand' function that is used to receive commands from the script server and send back responses. Matlab can communicate with this function by the 'orProblemSendCommand' function.

To move the hand safely to a particular preshape do: <source lang="matlab"> manips = orRobotGetManipulators(robotid); orBodySetJointValues(robotid,[0 0 0 pi/2],manips{1}.handjoints); </source>

Alternative: Can move the robot safely to a preshape using planners by: <source lang="matlab"> orRobotSetActiveDOFs(robotid,manips{1}.armjoints); handjoints = sprintf('%d ',manips{1}.handjoints); orProblemSendCommand(['MoveUnsyncJoints handjoints 4 0 0 0 1.57 ' handjoints],manipid); orBodySetJointValues(robotid,[0 0 0 pi/2],manips{1}.handjoints); </source>

To plan for a configuration space goal for the arm joints of the robot, type: <source lang="matlab"> orProblemSendCommand('MoveManipulator goal -0.005617 1.07 0.233 2.096 -4.194 -0.235 1.302520',manipid) </source>

Can squeeze the fingers of the hand by: <source lang="matlab"> orProblemSendCommand('CloseFingers',manipid) </source>

Grab the body by: <source lang="matlab"> orProblemSendCommand('GrabBody name mug6',manipid) </source>

Move to the table: <source lang="matlab"> tableTrans = [ -0.035588 -0.995502 -0.087805 -0.466866

               -0.994116   0.026269   0.105090   0.869644
               -0.102311   0.091028  -0.990579   1.000000 ];

orProblemSendCommand(['MoveToHandPosition matrix ' sprintf('%f ',tableTrans(1:3,1:4))],manipid) </source>

Move the hand down a little: <source lang="matlab"> orProblemSendCommand(['MoveHandStraight direction 0 0 -1 maxdist 0.3 matrix ' sprintf('%f ',tableTrans(1:3,1:4))],manipid) </source>

Finally, to release the fingers use the ReleaseFingers command. ReleaseFingers is a little more general than CloseFingers because the fingers to move and the direction of movement can be specified. <source lang="matlab"> orRobotSetActiveDOFs(1,[7 8 9]); % want to move 3 joints orProblemSendCommand('releasefingers target mug6',manipid); </source>

Can now plan to original position: <source lang="matlab"> orProblemSendCommand('MoveManipulator goal 0 0 0 0 0 0 0',manipid); </source>

Can also test if an IK solution exists by giving the transformation matrix T of the wrist: <source lang="matlab"> s = orProblemSendCommand(['IKtest trans ', num2str(T(:,4)'), ' rot ', num2str(T(1:9))],manipid) if( ~isempty(s) )

   orRobotSetDOFValues(1, sscanf(s, '%f'),0:6)

end </source>

Logging

A scene can be easily saved by using the logging plugin. Once a scene is loaded and all the objects are in place, do the following commands: <source lang="matlab"> logid = orEnvCreateProblem('logging') orProblemSendCommand('savescene filename myscene.env.xml',logid) </source>

Loading IKFast Solvers

Most robots when loaded at first, do not have any IK solvers set. Use the following code to load a Transform6D IK solver to the currently set active manipulator:

<source lang="matlab"> probid = orEnvCreateProblem('ikfast'); s = orProblemSendCommand(['LoadIKFastSolver ' robotname ' Transform6D'],probid) </source>

Set the active manipulator with:

<source lang="matlab"> manips = orRobotGetManipulators(robotid); manipname = manips{1}.name; orRobotSetActiveManipulator(robotid,manipname); </source>

Matlab/Octave Partial Reference

This is not a complete list and use this only to introduce yourself to the functions, the real reference and usages can be found in the help files of each function by typing help function_name.

  • orBodyDestroy(bodyid)
Destroys a body of id bodyid. bodyid can also be a robot.
  • success = orBodyEnable(bodyid, enable)
Enables or disables the body. If a body is disabled, 
collision detection and physics will will be turned off for it.
  • aabb = orBodyGetAABB(bodyid)
Returns an axis-aligned boudning box of the body in world coordinates
aabb is a 3x2  vector where the first column is the position of the
box and the second is the extents.
  • aabbs = orBodyGetAABBs(bodyid)
returns the axis-aligned boudning boxes of all the links of the body in world coordinates
aabbs is a 6xn vector where each column describes the box for all n links.
The first 3 values in each column describe the position of the aabb, and the next
3 values describe the extents (half width/length/height) on each of the axes.


  • dof = orBodyGetDOF(robotid)
Returns the number of active joints of the body.
  • values = orBodyGetDOFValues(robotid, indices)
Gets the body's dof values in a Nx1 vector where N is the DOF
bodyid - unique id of the robot
indices [optional]- The indices of the joints whose values should be returned.
                    If not specified, all joints are returned
  • values = orBodyGetLinks(bodyid)
Returns the transformations of all the body's links in a 12 x L matrix. Where L
is the number of links and each column is a 3x4 transformation
(use T=reshape(., [3 4]) to recover).
T * [X;1] = Xnew
  • orBodySetJointValues(bodyid, values, indices)
Set the raw joint values of a body. If bodyid is a robot, sets the robot's
joints ignoring its current active degrees of freedom. If a controller on
the robot is running, this function might not have any effect. Instead
use orRobotSetDOFValues
indices [optional] - array specifying the indices to control
  • orBodySetTransform
orBodySetTransform(bodyid, translation, quaternion)
orBodySetTransform(bodyid, [quaternion translation])
orBodySetTransform(bodyid, transform matrix) (12x1, 1x12, or 3x4)
Set the affine transformation of the body. The transformation actually
describes the first link of the body. The rest of the links are derived by
the joint angles. A quaternion is related to axis and angle via: [cos(theta/2);sin(theta/2)*axis]
  • [collision, colbody] = orEnvCheckCollision(bodyid,excludeid)
Check collision of the robot with the environment. collision is 1 if the robot
is colliding, colbodyid is the id of the object that body collided with
  • orEnvClose(figureids)

closes the figures and plots figureids - array of ids returned from orEnvPlot or other plotting functions

  • bodyid = orEnvCreateKinBody(name, xmlfile)
  • plannerid = orEnvCreatePlanner(plannertype)
  • orEnvCreateProblem
problemid = orEnvCreateProblem(problemname, args)
problemid = orEnvCreateProblem([problemname, args])


  • problemid = orEnvCreateProblem(problemname, args, destroyduplicates)
Creates an instance of a problem and returns its id for future communicate with it
problemname - the problem name
args - a string of arguments to send to the problem's main function
destroyduplicates [optional] - if 1, will destroy any previous problems with the same problem name.
                              If 0, will not destroy anything.
                              The default value is 1. 
  • robotid = orEnvCreateRobot(robotname, xmlfile, type)
Creates a robot of the given type. If type is not specified, creates a generic robot
  • orEnvDestroyProblem(problemid)
Destroys problem instance whose id is problemid.
  • bodies = orEnvGetBodies()
bodies is a cell array of all body objects in the scene
every cell contains a struct with the following parameters
id - bodyid
filename - filename used to initialize the body with
name - human robot name
type - xml type of body
  • id = orEnvGetBody(bodyname)
returns the id of the body that corresponds to bodyname
  • robots = orEnvGetRobots()
robots is a cell array of robots
every cell contains a struct with the following parameters
id - robotid
filename - filename used to initialize the robot with
name - human robot name
type - type of robot
  • success = orEnvLoadPlugin(filename)
Loads a plugin.
filename - the relative path of the plugin to load. (*.so for linux, *.dll for windows)
  • orEnvLoadScene(filename, [ClearScene])
Loads a new environment.
filename - The filename of the scene to load. If a relative file
           is specified, note that it is relative to the current direction
           of the OpenRAVE executable.
ClearScene - If 1, then clears the scene before loading. Else leaves the 
             scene alone and loads in addition to it.
  • figureid = orEnvPlot(points,...)
plots points or lines in the openrave viewer
points - Nx3 vector of xyz positions
optional arguments include 'size', 'color', and 'line'
  color - Nx3 vector of RGB values between 0 and 1
  size - Nx1 vector of the sizes in pixels of each point/line
  line (or linestrip) - if specified, then openrave renders a line strip
  linelist - if specified, openrave renders a line for every two points
  trilist - if specified, openrave renders a triangle for every three
            vertices should be specified in counter-clockwise order
  sphere - if specified, openrave renders each point as a sphere
  transparency - [0,1], set transparency of plotted objects (0 is opaque)
  • [collision, colinfo] = orEnvRayCollision(rays)
performs ray collision checks and returns the position and normals
where all the rays collide
rays - a 6xN matrix where the first 3
rows are the ray position and last 3 are the ray direction
collision - N dim vector that is 1 for colliding rays and 0
for non-colliding rays colinfo is a 6xN vector that describes 
where the ray hit and the normal to the surface of the hit point
where the first 3 columns are position and last 3 are normals
if bodyid is specified, only checks collisions with that body
  • orEnvSetOptions('publishanytime 1')
Current options:
- simulation [start/stop] [time_step] - toggles the internal simulation loop, ie all the calls to SimulationStep. 
If time_step is specified, will set the simulation time step for all objects.
Note that this is not tied to real time at all, how fast the  simulation goes in reality depends on complexity
of the scene and the physics engine being used.
- physics engine_name - switches the physics engine to another one with id 'engine_name'
- gravity [x y z] - changes to gravity vector
- publishanytime [1/0] - switch between publishing the body transformations
         to the GUI anytime or only between stepsimulation and server  messsages.
         When publishing anytime, the GUI will reflect the body movements after every
         move. This is useful when visualizing internal C++ states. When off, the GUI
         will only reflect the state of robots after all calls to stepsimulation and
         server send messages have been done. The default is off.
- debug [debug level] - toggles debugging messages by RAVELOG.
                       0  - only RAVEPRINT statements show
                       1+ - RAVELOG statements with various debug levels show
- quit - closes the openrave instance
  • [tripoints, triindices] = orEnvTriangulate(inclusive, ids)
Returns the triangulation of various objects in the scenes controlled by name and options
Arguments:
  inclusive - if 1, will only triangulate the bodies pointed to by ids
              if 0, will triangulate all objects except the bodies pointed to by ids
              default value is 0.
  ids (optional) - the ids to include or exclude in the triangulation
To triangulate everything, just do orEnvTriangulate(0,[]), or orEnvTriangulate()
Output:
  tripoints - 3xN matrix of 3D points
  tripoints - 3xK matrix of indices into tripoints for every triangle.
  • success = orEnvWait(robotid, robot_timeout)
wait until all previously sent commands to matlab are finished.
Since problems are meant to last for a long time orEnvWait waits
until the problem's main function finishes.

robotid - optional argument. If a robot id is specified, will wait until
the robot finishes with its trajectory.

robot_timeout (s) - function will return with success set to 0 if robot
did not finish its commands by robot_timeout ms. If not specified, orEnvWait
will not return until robot completes.
  • success = orPlannerInit(planner, robot, parameters)
Initialize a planner to plan for a robot and give some parameters
  • trajectory = orPlannerPlan(planner)
Start planning. The planner returns a trajectory when successful (otherwise returns an empty matrix)
trajectory - (DOF+1)xN matrix where N is the number of points in the trajectory.
             The first row are the time values of each trajectory point.
  • output = orProblemSendCommand(cmd, problemid, dosync)
Sends a command to the problem. The function doesn't return until
ProblemInstance::SendCommand returns.
cmd - the string command to send the problem
problemid [optional] - returned id of the problem, if not specified, then
                      command is sent to all problems
dosync [optional] - If 1, the SendCommand is called in the main thread, in sync
                      with the rest of the primitives. If 0, called in a different thread.
output - the concatenated output of all the problems that the command is sent to
  • orRender(cmd)
Controls rendering properties. Cmd can be
start - starts the GUI to update the internal openrave state
stop - stops the GUI from updating the internal openrave state (can be used to speed up loading)
  • success = orRobotControllerSend(robotid, controllercmd)
sends a command to the current controller the robot is connected to.
OpenRAVE sends directly to ControllerBase::SendCmd,
ControllerBase::SupportsCmd is also used to check for support.

success - 1 if command was accepted, 0 if not
  • success = orRobotControllerSet(robotid, controllername, controllerargs)
Sets a new robot controller and destroys the old.
controllername - name used to query a controller
controllerargs [optional] - the arguments to ControllerBase::Init
  • dof = orRobotGetActiveDOF(robotid)
returns the robot's active degrees of freedom used for planning (not necessary corresponding to joints).
  • sensors = orRobotGetAttachedSensors(robotid)
sensors is a cell array describing the attached sensors of the robot
Each cell is a struct with fields:
  name - name of the attached sensor
  link - zero-based index of link sensor is attached to
  Trelative - 3x4 matrix of the relative transform of the camera with respect to the robot
  Tglobal - 3x4 matrix of the global transform of the sensor of the current robot
            Tglobal = Tlink * Trelative
  type - the xml id of the sensor that is attached
  • values = orRobotGetDOFLimits(robotid)
Gets the robot's dof limits in a Nx2 vector where N is the DOF, the first column
is the low limit and the second column is the upper limit.
  • values = orRobotGetDOFValues(robotid, indices)
Gets the robot's dof values in a Nx1 vector where N is the DOF
robotid - unique id of the robot
indices [optional]- The indices of the joints whose values should be returned.
                    If not specified, the active degreees of freedeom set by
                    orRobotSetActiveDOFs will be used.
  • manipulators = orRobotGetManipulators(robotid)
manipulators is a cell array describes the manipulators of the robot
Each cell is a struct with fields
  baselink - zero-based index of base link manipulator is attached to
  eelink - zero-based index of link defining the end-effector
  Tgrasp - 3x4 matrix of the grasp frame relative to the end effector link,
           Tglobalgrasp = Tendeffector*Tgrasp
  joints - 1xK zero-based joint indices of the hand attached to the end effector
  armjoints - 1xN zero-based manipulator joint indices that have an
              effect on the end effector
  iksolvername - name of ik solver to use
  • data = orRobotSensorGetData(robotid, sensorindex)
Gets the sensor data. The format returned is dependent on the type
of sensor. Look at the different data SensorData implementations in rave.h.
Although the data returned is not necessarily one of them.
options [optional] - options that specify what type of data to request (0 is default)
data.type - contains the id of the data type (see SensorBase::SensorType)
For laser data
 data.laserrange - 3xN array where each column is the direction * distance
 data.laserpos - 3xN array where each column is the corresponding origin of each range measurement
 data.laserint - 1xN optional laser intensity array
For image data
 data.KK - 3x3 intrinsic matrix
 data.T - 3x4 camera matrix (to project a point multiply by KK*inv(T))
 data.I - the rgb image size(I) = [height width 3]
  • out = orRobotSensorSend(robotid, sensorindex, controllercmd)
sends a command to a sensor attached to the robot 
OpenRAVE sends directly to SensorBase::SendCmd,
SensorBase::SupportsCmd is used to check for command support.
robotid - unique id of the robot
sensorindex - zero-based index of sensor into robot's attached sensor array
out - the output of the command
  • orRobotSetActiveDOfs(robotid, indices, affinedofs, rotationaxis)
robotid - unique id of the robot
indices - zero based indices of the robot joints to activate
affinedofs [optional] - is a mask of affine transformation for planning
      1 - X, 2 - Y, 4 - Z, 8 - RotationAxis (rotationaxis has to be avlid, 16 - full 3D rotation
rotationaxis [optional] - the rotation axis (if the RotationAxis bit is set in affinedofs)
  • orRobotSetDofValues(robotid, values, indices)
Sets the DOF values of the robot
robotid - unique id of the robot
values - the joint values of the robot
indices [optional] - the indices of the dofs to set of the robot. 
                     If indices is not specified the active degrees of freedom
                     set by previous calls to orRobotSetActiveDOFs will be used.
                     Note that specifying indices will not change the active dofs of the robot.
  • orRobotStartActiveTrajectory(robotid, jointvalues, timestamps, transformations)
Starts/Queues a robot trajectory of the robot where the size of
each trajectory point is the current active degrees of freedom
of the robot (others are held constants)
D is the number of active degrees of freedom.
N is the number of points of the trajectory
robotid - unique id of the robot
jointvalues - DxN matrix of the joint values of each point in the trajrectory.
timestamps [optional] - the time stamps in seconds of each trajectory point.
transformations [optional] - 12xN or 7xN matrix. The base link transformations of
                             each trajectory point.
                             If the column size is 12, then it is a 3x4 matrix
                             in column first order
                             If the column size is 7, then it is a quaterion and a translation.
                             If active degrees of freedom contains a affine transformation component
                             it is overwritten with the transformations matrices
Personal tools