On Reverse-Engineering The KUKA Robot Language
On Reverse-Engineering The KUKA Robot Language
On Reverse-Engineering The KUKA Robot Language
Abstract— Most commercial manufacturers of industrial potentially dangerous operations such as direct memory
robots require their robots to be programmed in a proprietary access. However, a major drawback of these languages is the
language tailored to the domain – a typical domain-specific lack of extensibility. They are tailored to the underlying con-
language (DSL). However, these languages oftentimes suffer
from shortcomings such as controller-specific design, limited troller and, as a consequence, only offer a fixed, controller-
expressiveness and a lack of extensibility. For that reason, we specific set of instructions. Due to this design, even robot
developed the extensible Robotics API for programming indus- manufacturers have difficulties extending these languages
arXiv:1009.5004v1 [cs.RO] 25 Sep 2010
trial robots on top of a general-purpose language. Although be- with new instructions or adapting them to novel, challenging
ing a very flexible approach to programming industrial robots, requirements such as the synchronization of cooperating
a fully-fledged language can be too complex for simple tasks.
Additionally, legacy support for code written in the original robots or the tight integration of sensor-guided motions.
DSL has to be maintained. For these reasons, we present a For that reason, we have developed a novel software
lightweight implementation of a typical robotic DSL, the KUKA architecture [2] for programming industrial robots in the
Robot Language (KRL), on top of our Robotics API. This work research project SoftRobot. Its core part is the Robotics API
deals with the challenges in reverse-engineering the language which represents an extensible object-oriented framework
and mapping its specifics to the Robotics API. We introduce
two different approaches of interpreting and executing KRL for robotic applications (available in Java and C#). Similar
programs: tree-based and bytecode-based interpretation. to robotic DSLs, the Robotics API offers an abstraction
from real-time programming facilitating the development
I. I NTRODUCTION of robotic software. With a general-purpose programming
For programming industrial robots, Biggs and MacDonald language and a robotic-specific application programming
distinguish between two major principles: automatic and interface (API), rapid development of domain-specific lan-
manual programming [1]. While automatic programming guages for industrial robots is possible. In contrast to exist-
often uses programming-by-demonstration, manual program- ing robotics programming languages, we intend to develop
ming is by far the most common technique; the developer lightweight DSLs, that is, languages which are implemented
has to explicitly specify the desired behavior of the robot using well-defined interfaces and without other dependencies
in a machine-readable syntax, usually using a formal text- on the underlying robot system. As a proof-of-concept, we
based or graphical language. Hence, a straightforward idea decided to reverse-engineer the KUKA Robot Language
is to program the robot directly using a general-purpose (KRL) and implement it on top of our architecture. We
programming language. This approach has the major dis- have chosen KRL to show that we can achieve a similar
advantage that the developer is responsible for developing expressiveness as classical robot programming languages
code which satisfies all necessary real-time constraints of and simulate their execution semantics. Moreover, we can
the robot controller. Any errors in the code may not only execute legacy code written in KRL this way and thus
lead to a failure of the program itself, but to severe damages maintain a certain degree of compatibility.
of the entire robot. The paper is structured as follows: In Sect. II, the KUKA
To mitigate this shortcoming, most commercial manufac- Robot Language is introduced and its main features are
turers of industrial robots provide domain-specific languages explained using an example. Subsequently, Sect. III describes
for their robot systems. These languages are usually text- the Robotics API and our software architecture which was
based and offer the possibility to declare robotic-specific data used to implement a lightweight interpreter for KRL. The
types, to specify simple motions, and to interact with tools steps required for reverse-engineering KRL are explained in
and sensors via I/O operations. Examples are the KUKA Sect. IV. While static preprocessing of KRL programs is
Robot Language or RAPID from ABB. To run such a described in Sect. V, different approaches for interpreting
program, it is transmitted to the robot controller, where it KRL on top of our software architecture are discussed in
is executed obeying real-time constraints. These languages Sect. VI. Finally, Sect. VII concludes the paper.
focus on a narrow set of required features and prohibit
II. KUKA ROBOT L ANGUAGE
Andreas Angerer, Alwin Hoffmann, Henrik Mühe, and Wolfgang Reif Today, every KUKA industrial robot is programmed using
are with the Institute for Software and Systems Engineering, University of
Augsburg, D-86135 Augsburg, Germany. E-mail of corresponding author: the proprietary KUKA Robot Language which is an imper-
hoffmann@informatik.uni-augsburg.de ative programming language similar to Pascal. In addition
This work presents results of the research project SoftRobot which is to typical programming statements such as variable assign-
funded by the European Union and the Bavarian government within the
High-Tech-Offensive Bayern. The project is carried out together with KUKA ments, conditionals and loops, KRL provides robotic-specific
Roboter GmbH and MRK-Systeme GmbH. statements e.g. for specifying motions and interacting with
DEF example() deceleration phases. To indicate that a target position does
DECL INT i
DECL POS cpos not need to be reached exactly, an additional parameter (e.g.
DECL AXIS jpos C_DIS in the example program) is used in the corresponding
FOR i=1 TO 6 motion statement. However, there are KRL statements like
$VEL_AXIS[i]=60 reading an input which stop the advance run making it
ENDFOR
impossible to blend between two motions [3].
jpos = {AXIS: A1 0,A2 -90,A3 90,A4 0,A5 0,A6 0}
PTP jpos
L1
IF $IN[1] == TRUE THEN
cpos = {POS: X 300,Y -100,Z 1500,A 0,B 90,C 0}
L2
ELSE
cpos = {POS: X 250,Y -200,Z 1300,A 0,B 90,C 0} Smoothing
ENDIF
Fig. 2. Two blended linear motions, L1 and L2 , with n automatically
INTERRUPT DECL 3 WHEN $IN[2]==FALSE DO BRAKE
INTERRUPT ON 3 generated transition.
Sect. III. Although translating KRL to Java with calls to the AST
ROOT
Robotics API is possible, we chose to build an interpreter
for the DSL. The official KUKA implementations of KRL DEFDAT DEF DEF
offer some debugging options and features like backward $global INT m INT = mo INT
execution of movement commands. Trying to mimic these
features in a translation-based approach would complicate a b a 5 c
s1 s2
the translation process. An interpreter, on the other hand, al-
lows a high level of interaction with the interpreted program.
It simulates a CPU but can be accessed and manipulated Fig. 5. KRL sourcecode, AST generated by the parser and associated
symbol table hierarchy.
easier than the physical CPU. Further advantages of the
interpretation approach will be detailed in Sect. VI.
V. P REPROCESSING with the type of the expression on the right. In the context
From the grammar, both lexer and parser were generated of an assignment, two types are considered compatible if
using ANTLR [7] (ANother Tool for Language Recognition). lossless conversion between the type of the expression and
We enriched the grammar with the description of a tree the variable is possible. A set of similar constraints was
structure that the generated parser uses to output an Abstract found for all expressions in KRL and implemented in the
Syntax Tree (AST) instead of a parse tree. A parse tree type checker. The type checker also adds type information
is a representation of which rules were used to parse the to the AST to avoid having to compute this information again
input whereas an AST is less verbose and represents only in the interpreter.
the information necessary for the purpose of interpretation.
VI. I NTERPRETATION
Since KRL is both statically and explicitly typed, compre-
hensive type-checking is possible before actually executing Traversing the AST is a simple way of executing a DSL.
a program. This is advantageous, since having to terminate a We will call this approach tree-based interpretation. It is
program because of an invalid assignment while in the mid- a straightforward implementation of an interpreter, but not
dle of the execution is discouraged, especially in a DSL that the only feasible method. Literature suggests that a different
is used to control heavy machinery. Type checking requires approach, called bytecode interpretation, is also widely used
all symbols and their types to be known. Additionally, it is [9]. Since our implementation using a tree-based approach is
paramount that symbol scoping, that is, different visibility in both more mature and versatile than our implementation of a
different areas of the program, is established. Thus, a symbol bytecode interpreter, we will focus tree-based interpretation
table has to be generated before a type checker can be run. first. Later in this chapter, a bytecode-based prototype will
The program that fills the symbol table works on the AST be introduced and compared to the original approach.
created by the parser – an example is displayed in Fig. 5. Tree-based interpretation relies on the idea that a KRL
A hierarchy of symbol tables is established to allow for program can be effectively executed by walking the AST
easy integration of scoping: only symbols are visible that generated from it and executing each node in it as shown
are in a symbol table which is an ancestor to the current in Fig. 6. For simple statements, like a variable declaration
symbol table. In this context, current symbol table means (see Fig. 5, label s1), execution comes down to reading the
local to the expression for which visibility of a symbol has declaration node, reading the variable name in the child node
to be determined. If a statement in a method m tries to read and allocating a corresponding amount of memory. For more
a variable a, the symbol table used to collect symbols of complex statements like an assignment (see Fig. 5, label
said method is the current symbol table. In the symbol table s2), execution requires executing both child-nodes. The value
hierarchy given at the top of Fig. 5, variable a is thus visible returned by executing the second child-node – and thus the
to method m, since it is in a symbol table that is an ancestor right side of the assignment – needs to be assigned to the
of the current symbol table for statements in method m. position in memory referenced by the first child-node.
After having collected all symbols in a given KRL pro- Control flow constructs like loops are simple to execute:
gram, type checking is trivial: The AST has to be read a for an unconditional loop, its body is executed iteratively
second time and every expression has to be checked for until a statement which causes the loop to exit is encountered.
type compatibility. Type checking can be done by verifying However, a serious problem arises with executing statements
that a set of type constraints is met [8]. Considering the that severely impact control flow (e.g. a return statement,
source code in Fig. 5, we must verify that the type of the a procedure, a function call, or a GOTO). It is sufficient to
variable on the left side of the assignment is compatible focus on the most difficult of these statements, GOTO, since
test.src AST test.src AST
bytecode compiler
Interpreter Textual bytecode
.method TEST Assembled bytecode
stackframesize 2
int_loadConst 0 8, 0, 0, 0, 2, 4, 0, 0, 0,
int_store 0 # C 0, 2, 0, 0, 0, 0, 4, 0, 0,
int_loadConst 1 0, 1, 2, 0, 0, 0, 1, 0, 0,
int_store 1 # X 0, 0, 1, 4, 0, 0, 39, 16,
16, 14, 0, 0, 0, 78, 0, 0,
Fig. 6. Architecture when using a tree-based interpreter. .label 0
int_load 1 # X 0, 0, 0, 0, 0, 0, 0, 1, 11,
int_loadConst 10000 2, 0, 0, 0, 0, 0, 0, 0, 0,
int_lt 1, 4, 0, 0, 0, 1, 11, 2, 0,
jmp_false 1 0, 0, 1, 13, 0, 0, 0, 25
int_load 0 # C
int_load 1 # X bytecode assembler
int_add
int_store 0 # C