Lua Interface

RobWork has an 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 SWIG. There is no automatic generation of API documentation for the Lua interface, but instead it is encouraged that you use the C++ API Reference, Java API Reference, or Python API Reference. Notice that it is also possible to call the help(object) function in Lua to print a list of available functions on a given object.

Lua can either be used as a stand-alone script in a generic interpreter, in a RobWork-specific interpreter or inside the RobWorkStudio Lua plugin. There are slight differences in how the scripts should be written and how they are run, which will be covered in the following sections.

Stand-alone Scripts

To run the script with a standard Lua interpreter, it is necessary to setup the LUA_CPATH environment variable to let the interpreter know where to find the RobWork Lua modules.

In Linux, this could for instance be set with the following command:

export LUA_CPATH="/path/to/RobWork/libs/BUILD_CONFIGURATION/Lua/?.so;/path/to/RobWorkStudio/libs/BUILD_CONFIGURATION/Lua/?.so;/path/to/RobWorkSim/libs/BUILD_CONFIGURATION/Lua/?.so"

Adjust the paths to actual path names on the system.

When running the Lua script, the modules must be loaded using the require function:

require("sdurw")
require("sdurw_simulation")

Building a Lua interpreter

It is possible to compile a Lua interpreter that has the RobWork types built in directly. The rwlibs::swig::openLuaLibXX functions are used for this, where XX is something different for each Lua module.

This program loads all the RobWork Lua modules into a Lua interpreter and runs a Lua script given on the command line:

 1#include <iostream>
 2#include <rwlibs/swig/lua/Lua_sdurw.hpp>
 3#include <rwlibs/swig/lua/Lua_sdurw_assembly.hpp>
 4#include <rwlibs/swig/lua/Lua_sdurw_control.hpp>
 5#include <rwlibs/swig/lua/Lua_sdurw_pathoptimization.hpp>
 6#include <rwlibs/swig/lua/Lua_sdurw_pathplanners.hpp>
 7#include <rwlibs/swig/lua/Lua_sdurw_proximitystrategies.hpp>
 8#include <rwlibs/swig/lua/Lua_sdurw_simulation.hpp>
 9#include <rwlibs/swig/lua/Lua_sdurw_task.hpp>
10
11int main(int argc, char** argv)
12{
13    if (argc != 2) {
14        std::cerr << "Usage: " << argv[0] << " <lua-script>\n";
15        return 1;
16    }
17
18    lua_State *L = luaL_newstate();
19    luaL_openlibs(L);
20
21    rwlibs::swig::openLuaLibRW_sdurw(L);
22    rwlibs::swig::openLuaLibRW_sdurw_assembly(L);
23    rwlibs::swig::openLuaLibRW_sdurw_control(L);
24    rwlibs::swig::openLuaLibRW_sdurw_pathoptimization(L);
25    rwlibs::swig::openLuaLibRW_sdurw_pathplanners(L);
26    rwlibs::swig::openLuaLibRW_sdurw_proximitystrategies(L);
27    rwlibs::swig::openLuaLibRW_sdurw_simulation(L);
28    rwlibs::swig::openLuaLibRW_sdurw_task(L);
29
30    const int error = luaL_dofile(L, argv[1]);
31    if (error) std::cerr << lua_tostring(L, -1) << "\n";
32    lua_close(L);
33
34    return error;
35}

RobWorkStudio and RobWorkSim provide similar functions.

Notice that this interpreter will not need the scripts to call require to load the RobWork modules. They are built in from the beginning.

RobWorkStudio Lua

To see the LuaConsole plugin, open the Lua lua plugin in RobWorkStudio.

You will see the following LuaConsole plugin, and by clicking at the plus button in the top left corner, you get the Lua editor window “Lua Teachpad”.

../../_images/luaplugin.png

The LuaConsole plugin and the Lua editor window.

In the LuaConsole and Lua Teachpad, you will not need to use the require function to load RobWork Lua libraries. They are already available in the interpreter used internally by RobWorkStudio.

Conventions & Utilities

The following conventions are used in the Lua interface:

  • RobWork math types are templated with the precision used, such as Rotation3D<double> and Rotation3D<float>. In the script interfaces, this can not be mapped directly. Instead those types are mapped to the types Rotation3Dd and Rotation3Df. For math types we follow this convention with d and f for double and float precision respectively.

  • The types must be written with a prefix giving the name of the Lua module where it origins. For instance it is necessary to write rw.Q or rw_simulation.Simulator. The using utility function is provided to allow the user to import the types a global names, such as using(“rw”) and using(“rw_simulation”). This is somewhat similar to the “using namespace” statements in C++.

Example of the construction of a Q vector without and with the using function:

-- rw prefix is necessary to create Q:
q1 = sdurw.Q(2,{1,2})
-- Import the rw types to global namespace:
using("sdurw")
-- rw prefix can now be left out
q2 = Q(2,{1,2})

Lua program example

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

 1function b2s(b)
 2    if b then
 3        return "true"
 4    else
 5        return "false"
 6    end
 7end
 8
 9x = 2.92
10print("Radians to degrees and back:", b2s(rw.d2r(rw.r2d(x)) == x))
11print()
12
13print("rpy is", rw.rpy(0.3, 0, 0))
14print("rpy is", rw.rpy_deg(rw.r2d(0.3), 0, 0))
15print("eaa is", rw.eaa(0.3, 0, 0))
16print("eaa is", rw.eaa_deg(rw.r2d(0.3), 0, 0))
17print()
18
19q = rw.Q({1, 2, 3, 4, 5, 6, 7})
20print("q is", q)
21print()
22
23v = rw.Vector3D({0, 3, -0.3})
24print("v is", v)
25print("v * 2 is", v * 2)
26print("v + v - v is v:", b2s(v + v - v == v))
27print()
28
29r = rw.Rotation3D({1, 0, 0, 0, 1, 0, 0, 0, 1})
30print("r is", r)
31print("r^2 is", r * r)
32print("rw.inverse(r) is", rw.inverse(r))
33print("r:inverse() is", r:inverse())
34print("The type of Rotation3D is", tolua.type(r))
35print()
36
37t = rw.Transform3D(v, r)
38print("t is", t)
39print("rw.inverse(t) is", rw.inverse(t))
40print("t:inverse() is", t:inverse())
41print("The rotation of t is", t:r())
42print("The translation of t is v:", b2s(v == t:p()))
43print()
44
45print("r * v is", r * v)
46print("(t * t) * v is", (t * t) * v)
47print()
48
49workcell = rw.loadWorkCell("workcell.wu")
50print("Workcell is", workcell)
51
52state = workcell:getDefaultState()
53
54frame = workcell:getFrame("Device.TCP")
55print("Frame is", frame)
56
57world = workcell:getWorldFrame()
58print("World frame is", world)
59print("World to frame transform is", world:to(frame, state))
60print("Frame world transform is", frame:wt(state))
61print("Frame world translation is",
62      frame:wt(state):p() - world:wt(state):p())
63print()
64
65device = workcell:getDevice("Device")
66print("Device is", device)
67print("Device base is", device:getBase())
68print("Device end is", device:getEnd())
69print("Device configuration is", device:getQ(state))
70print()
71
72q = rw.Q{ 0.98, 1.503, -1.521, -0.76, -0.237, -0.895, 0}
73print("Assigning device configuration to state.")
74device:setQ(q, state)
75print("Device configuration is assigned configuration:", b2s(device:getQ(state) == q))
76print()
77
78item = workcell:getFrame("Item")
79pos = item:wt(state):p()
80print("Item position is", pos)
81rw.gripFrame(item, device:getEnd(), state)
82print("Item position is", item:wt(state):p())
83item:attachFrame(world, state)
84print("Item position is", item:wt(state):p())

The output of running the script in the interpreter is as follows:

 1Radians to degrees and back:	true
 2
 3rpy is	Rotation3D {0.955336, -0.29552, 0, 0.29552, 0.955336, 0, 0, 0, 1}
 4rpy is	Rotation3D {0.955336, -0.29552, 0, 0.29552, 0.955336, 0, 0, 0, 1}
 5eaa is	Rotation3D {1, 0, 0, 0, 0.955336, -0.29552, 0, 0.29552, 0.955336}
 6eaa is	Rotation3D {1, 0, 0, 0, 0.955336, -0.29552, 0, 0.29552, 0.955336}
 7
 8q is	Q[7]{1, 2, 3, 4, 5, 6, 7}
 9
10v is	Vector3D {0, 3, -0.3}
11v * 2 is	Vector3D {0, 6, -0.6}
12v + v - v is v:	true
13
14r is	Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1}
15r^2 is	Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1}
16rw.inverse(r) is	Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1}
17r:inverse() is	Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1}
18The type of Rotation3D is	rwlibs::lua::internal::Rotation3D
19
20t is	Transform3D(Vector3D {0, 3, -0.3}, Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1})
21rw.inverse(t) is	Transform3D(Vector3D {0, -3, 0.3}, Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1})
22t:inverse() is	Transform3D(Vector3D {0, -3, 0.3}, Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1})
23The rotation of t is	Rotation3D {1, 0, 0, 0, 1, 0, 0, 0, 1}
24The translation of t is v:	true
25
26r * v is	Vector3D {0, 3, -0.3}
27(t * t) * v is	Vector3D {0, 9, -0.9}
28
29Workcell is	WorkCell[workcell.wu]
30Frame is	Frame[Device.TCP]
31World frame is	Frame[WORLD]
32World 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})
33Frame 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})
34Frame world translation is	Vector3D {-0.955356, 0.107485, 0.161679}
35
36Device is	Device[Device]
37Device base is	Frame[Device]
38Device end is	Frame[Device.J6]
39Device configuration is	Q[7]{0.98, 1.503, -1.521, -0.76, -0.237, -0.895, 0}
40
41Assigning device configuration to state.
42Device configuration is assigned configuration:	true
43
44Item position is	Vector3D {0, 0.5, 0.5125}
45Item position is	Vector3D {1.07946e-016, 0.5, 0.5125}
46Item position is	Vector3D {0.365482, -0.558872, -0.862516}

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 c rw package to access variables of the RobWorkStudio environment.

c sdurw.getWorkCell() returns the currently loaded workcell:

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

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

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

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

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

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

q = sdurw.Q{0.5, 0, 0, 0, 0, 0}; d:setQ(q, s); sdurw.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 = sdurw.CompositeDevice(devices, state, options)
detector = sdurw.getCollisionDetector(options)
collision = detector:inCollision(state)
strategy = sdurw.getCollisionStrategy(options)
planner = sdurw.getPathPlanner(device,
     { tcp = frame, state = state, detector = detector })
path = planner:query(from, to)
path = sdurw.Path(states)
path1 + path2
sdurw.storeStatePath(workcell, path, file)
sdurw.getOutput()