Resources

Topics

RobWorkProject
Lua scripting language interface

Table of Contents

Introduction

RobWork has a small (experimental/beta) interface to the Lua scripting language. This section will present examples and general use patterns for using Lua in RobWork.

In general most functionality in the Lua interface is generated using Tolua++ and most apidoc from

1 rwlibs::lua

should be directly applicable in a lua script. E.g. the function from

1 rwlibs::lua::gripFrame()

can be called in a script using

rwlibs.lua.gripFrame(...) 

.

Lua interface basics

As described above the Lua interface is generated with ToLua++ and wrapper classes for most robwork classes has been created to seperate lua stuff from the c++ classes. This means that

1 rwlibs::lua::Vector3D

is a wrapper to

1 rw::math::Vector3D<>

where most functions are wrapped but not all. This design enables the lua interface to have a more simple script like nature. Whereas the C++ interface often has a more object oriented design and descriptive design. E.g. in C++ a function for calculating world to frame transform is names

1 rw::kinematics::Kinematics::worldTframe

whereas in lua its

1 rwlibs::lua::wTf

.

All wrapper classes implement a basic set of functions:

Creating objects with constructors

Creating a new object using the Lua interface is straight forward. An Object is created using one of its constructors. By default there are two ways to do this: global where you handle object destruction yourself and local where the tolua garbage collector destructs the object for you. Global:

1 q = rwlibs.lua.Q:new(2,{1,2})
2 -- dostuff
3 q:delete()

and the local method

1 q = rwlibs.lua.Q(2,{1,2})
2 -- dostuff

The lua interface is under expansion and this section will contain the preliminary interface that is wanted from the different rw packages.

Heres a list of the packages and what content that is most important

Building a Lua interpreter

rwlibs::lua implements a Lua module named rw that can be loaded into a Lua interpreter with rwlibs::lua::RobWork::open(). This program loads the rw module into a Lua interpreter and runs a Lua script given on the command line:

#include <rwlibs/swig/lua/Lua.hpp>
#include <iostream>
int main(int argc, char** argv)
{
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <lua-script>\n";
return 1;
}
lua_State *L = lua_open();
luaL_openlibs(L);
const int error = luaL_dofile(L, argv[1]);
if (error) std::cerr << lua_tostring(L, -1) << "\n";
lua_close(L);
return error;
}

Lua program example

This example showcases most of the functionality of the Lua script interface:

function b2s(b)
if b then
return "true"
else
return "false"
end
end
x = 2.92
print("Radians to degrees and back:", b2s(rw.d2r(rw.r2d(x)) == x))
print()
print("rpy is", rw.rpy(0.3, 0, 0))
print("rpy is", rw.rpy_deg(rw.r2d(0.3), 0, 0))
print("eaa is", rw.eaa(0.3, 0, 0))
print("eaa is", rw.eaa_deg(rw.r2d(0.3), 0, 0))
print()
q = rw.Q({1, 2, 3, 4, 5, 6, 7})
print("q is", q)
print()
v = rw.Vector3D({0, 3, -0.3})
print("v is", v)
print("v * 2 is", v * 2)
print("v + v - v is v:", b2s(v + v - v == v))
print()
r = rw.Rotation3D({1, 0, 0, 0, 1, 0, 0, 0, 1})
print("r is", r)
print("r^2 is", r * r)
print("rw.inverse(r) is", rw.inverse(r))
print("r:inverse() is", r:inverse())
print("The type of Rotation3D is", tolua.type(r))
print()
t = rw.Transform3D(v, r)
print("t is", t)
print("rw.inverse(t) is", rw.inverse(t))
print("t:inverse() is", t:inverse())
print("The rotation of t is", t:r())
print("The translation of t is v:", b2s(v == t:p()))
print()
print("r * v is", r * v)
print("(t * t) * v is", (t * t) * v)
print()
workcell = rw.loadWorkCell("workcell.wu")
print("Workcell is", workcell)
state = workcell:getDefaultState()
frame = workcell:getFrame("Device.TCP")
print("Frame is", frame)
world = workcell:getWorldFrame()
print("World frame is", world)
print("World to frame transform is", world:to(frame, state))
print("Frame world transform is", frame:wt(state))
print("Frame world translation is",
frame:wt(state):p() - world:wt(state):p())
print()
device = workcell:getDevice("Device")
print("Device is", device)
print("Device base is", device:getBase())
print("Device end is", device:getEnd())
print("Device configuration is", device:getQ(state))
print()
q = rw.Q{ 0.98, 1.503, -1.521, -0.76, -0.237, -0.895, 0}
print("Assigning device configuration to state.")
device:setQ(q, state)
print("Device configuration is assigned configuration:", b2s(device:getQ(state) == q))
print()
item = workcell:getFrame("Item")
pos = item:wt(state):p()
print("Item position is", pos)
rw.gripFrame(item, device:getEnd(), state)
print("Item position is", item:wt(state):p())
item:attachFrame(world, state)
print("Item position is", item:wt(state):p())

The workcell.wu file loaded in the script is described in section Example of a workcell containing a device and item.

The output of running the script in the interpreter (see section Building a Lua interpreter) is as follows:

Radians to degrees and back: true
rpy is Rotation3D {0.955336, -0.29552, 0, 0.29552, 0.955336, 0, 0, 0, 1}
rpy is Rotation3D {0.955336, -0.29552, 0, 0.29552, 0.955336, 0, 0, 0, 1}
eaa is Rotation3D {1, 0, 0, 0, 0.955336, -0.29552, 0, 0.29552, 0.955336}
eaa is Rotation3D {1, 0, 0, 0, 0.955336, -0.29552, 0, 0.29552, 0.955336}
q is Q[7]{1, 2, 3, 4, 5, 6, 7}
v is Vector3D {0, 3, -0.3}
v * 2 is Vector3D {0, 6, -0.6}
v + v - v is v: true
r is Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1}
r^2 is Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1}
rw.inverse(r) is Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1}
r:inverse() is Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1}
The type of Rotation3D is rwlibs::lua::internal::Rotation3D
t is Transform3D(Vector3D {0, 3, -0.3}, Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1})
rw.inverse(t) is Transform3D(Vector3D {0, -3, 0.3}, Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1})
t:inverse() is Transform3D(Vector3D {0, -3, 0.3}, Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1})
The rotation of t is Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1}
The translation of t is v: true
r * v is Vector3D {0, 3, -0.3}
(t * t) * v is Vector3D {0, 9, -0.9}
Workcell is WorkCell[workcell.wu]
Frame is Frame[Device.TCP]
World frame is Frame[WORLD]
World to frame transform is Transform3D(Vector3D {-0.955356, 0.107485, 0.161679}, Rotation3D {0.121395, -0.856918, -0.500954, -0.227824, 0.467159, -0.854318, 0.966105, 0.217839, -0.138515})
Frame world transform is Transform3D(Vector3D {-0.955356, 0.107485, 0.161679}, Rotation3D {0.121395, -0.856918, -0.500954, -0.227824, 0.467159, -0.854318, 0.966105, 0.217839, -0.138515})
Frame world translation is Vector3D {-0.955356, 0.107485, 0.161679}
Device is Device[Device]
Device base is Frame[Device]
Device end is Frame[Device.J6]
Device configuration is Q[7]{0.98, 1.503, -1.521, -0.76, -0.237, -0.895, 0}
Assigning device configuration to state.
Device configuration is assigned configuration: true
Item position is Vector3D {0, 0.5, 0.5125}
Item position is Vector3D {1.07946e-016, 0.5, 0.5125}
Item position is Vector3D {0.365482, -0.558872, -0.862516}

Executing Lua from commandline using rw-lua tool

Executing Lua from commandline using rw-lua tool

Lua code can be executed in RobWorkStudio via the Lua plugin interface. The Lua plugin has some additional Lua functions in the rw package to access variables of the RobWorkStudio environment.

rw.getWorkCell() returns the currently loaded workcell:

w = rw.getWorkCell(); print(w)
--
WorkCell[D:/movebots/FanucSchunk/scene.wu]

rw.getDevice(name) retrieves the device of the given name:

d = rw.getDevice("Robot"); print(d)
--
Device[Robot]

rw.getState() returns a copy of the current workcell state of RobWorkStudio:

s = rw.getState(); print(d:getQ(s))
--
Q[6]{0, 0, 0, 0, 0, 0}

The workcell state can be written back to RobWorkStudio with rw.setState():

q = rw.Q{0.5, 0, 0, 0, 0, 0}; d:setQ(q, s); rw.setState(s)

This will update the position of the device as displayed in RobWorkStudio.

Other Lua functions and methods

The interface has some additional experimental functions and methods that will be documented and expanded as RobWork matures.

device = rw.CompositeDevice(devices, state, options)
detector = rw.getCollisionDetector(options)
collision = detector:inCollision(state)
strategy = rw.getCollisionStrategy(options)
planner = rw.getPathPlanner(device,
     { tcp = frame, state = state, detector = detector })
path = planner:query(from, to)
path = rw.Path(states)
path1 + path2
rw.storeStatePath(workcell, path, file)
rw.getOutput()

Reference

Classes

Most classes accessible from lua is wrapper classes. The object which an wrapper class wraps can allways be returned using the get() function.