RobWorkProject  23.9.11-
Lua scripting language interface

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

rwlibs::lua

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

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

rwlibs::lua::Vector3D

is a wrapper to

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

rw::kinematics::Kinematics::worldTframe

whereas in lua its

rwlibs::lua::wTf

.

All wrapper classes implement a basic set of functions:

  • get - gets the robwork class that is wrapped.
  • __tostring - enables output through the lua print function.

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:

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

and the local method

q = rwlibs.lua.Q(2,{1,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

  • math - All math types (Vector3D, Transform3D, RPY ...) in this package is important since they are basic building blocks in all of robwork. Besides these basic types some of the more popular utillity functions need be available (SVD, conversion, ran, min, max, clamp, metrics)
  • common - Most of the stuff in common is utility functions and are not that important in script interface. Though some filefunctions, timerfunctions and log functions could come inhandy.
  • geometry - factory methods and

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 <iostream>
#include <rwlibs/swig/lua/Lua_sdurw.hpp>
#include <rwlibs/swig/lua/Lua_sdurw_assembly.hpp>
#include <rwlibs/swig/lua/Lua_sdurw_control.hpp>
#include <rwlibs/swig/lua/Lua_sdurw_pathoptimization.hpp>
#include <rwlibs/swig/lua/Lua_sdurw_pathplanners.hpp>
#include <rwlibs/swig/lua/Lua_sdurw_proximitystrategies.hpp>
#include <rwlibs/swig/lua/Lua_sdurw_simulation.hpp>
#include <rwlibs/swig/lua/Lua_sdurw_task.hpp>
int main(int argc, char** argv)
{
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <lua-script>\n";
return 1;
}
lua_State *L = luaL_newstate();
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;
}
int openLuaLibRW_sdurw_proximitystrategies(lua_State *L)
Initialize a Lua state.
int openLuaLibRW_sdurw_simulation(lua_State *L)
Initialize a Lua state.
int openLuaLibRW_sdurw_pathplanners(lua_State *L)
Initialize a Lua state.
int openLuaLibRW_sdurw_assembly(lua_State *L)
Initialize a Lua state.
int openLuaLibRW_sdurw_control(lua_State *L)
Initialize a Lua state.
int openLuaLibRW_sdurw_pathoptimization(lua_State *L)
Initialize a Lua state.
int openLuaLibRW_sdurw_task(lua_State *L)
Initialize a Lua state.
int openLuaLibRW_sdurw(lua_State *L)
Initialize a Lua state.

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 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}
PerspectiveTransform2D< T > inverse(const PerspectiveTransform2D< T > &aRb)
Take the inverse of a PerspectiveTransform2D.
Definition: PerspectiveTransform2D.hpp:232
Deprecated namespace since 16/4-2020 for this class.
Definition: common/AnyPtr.hpp:28

Executing Lua from commandline using rw-lua tool

Executing Lua code in RobWorkStudio

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.