Runtime programming an industrial robot in RCML

In this article, runtime programming refers to the process of creating an executable program for a robot controller (hereinafter simply a robot) on an external controller. The process of execution of the created program by the robot in this case occurs iteratively, by transmitting to it the minimum executable command or package of commands. In other words, during runtime programming, the executable program is transferred to the robot portionwise, while the robot does not possess, does not store, and does not know in advance the entire executable program. This approach allows you to create an abstract parameterized executable program, which is formed by an external device "on the go", ie runtime.
Under the cat is a description and a real example of how runtime programming works.
Typically, a program for a robot is a sequence of positions to which a robot manipulator should come. Each of these positions is characterized by the position of TCP (Tool Center Point) - the point of the tip of the tool mounted on the manipulator. By default, TCP is in the center of the robot flange, see the figure below, but its position can be reconfigured and most often so that TCP matches the tip of the installed tool on the robot arm. Therefore, when programming, the position of TCP in space is usually set, and the robot determines the position of the joints of the manipulator itself. Further in the article, the term “TCP position” will be used, or in other words, the point at which the robot must “come”.The program for the robot may also contain primitive control logic (branches, loops), simple mathematical operations, as well as peripheral control commands - analog and digital inputs / outputs. In the proposed approach of runtime programming, an ordinary PC is used as an external controller, on which powerful programming tools can be used that provide the necessary level of abstraction (OOP and other paradigms) and tools that provide speed and ease of developing complex logic (high-level programming languages). On the robot, only logic critical to the reaction rate remains, for the execution of which requires the reliability of an industrial controller, for example, an operational and adequate response to an emergency situation. Controlling peripherals connected to the robot it is simply "proxied" by the robot itself on the PC, allowing software from the PC to turn on or off the corresponding signals on the robot. This is somewhat similar to controlling the legs on an Arduino.

As noted earlier, runtime programming allows the program to be transmitted to the robot in batches - parts. Typically, a set of output signal states and a small number of points, or just one point at all, are transmitted at a time. Thus, the TCP trajectory performed by the robot can be built dynamically and its individual parts can belong to different technological processes, or even to different robots (connected to one external controller) if a group of robots is working, i.e. there are prerequisites for the dynamic replacement of robots in the process.
For example, moving a robot between work areas. In each zone, he performs the necessary operations and then moves on to the next zone, then to another, and then again to the first, etc. In different working areas, the robot performs the operations necessary for different technological processes, the execution of the programs of which takes place in parallel flows on an external controller, which allocates the robot to different processes that do not require the constant presence of the robot. This mechanism is similar to how the OS allocates the time of the processor core (executive resource) to different threads (tasks) and at the same time, different executors are not tied to threads throughout the entire program execution period.
A little more theory and move on to practice.
Description of existing methods for programming industrial robots
Without taking into account the runtime programming approach introduced in this article, it is customary to distinguish two ways of programming industrial robots. Offline and online programming.
The process of online programming occurs with the direct interaction of the programmer with the robot at the place of its use. Using the control panel or physical movement, a tool (TCP) is mounted on the robot flange to the required point in space.
The offline programming process , as the name implies, occurs remotely from the robot and its controller. The executable program is developed in a specialized environment for programming industrial robots on a PC, and then downloaded to the robot as a whole. However, software tools for such a development are not included in the basic delivery package of the robot and are additional options that are purchased separately and are not cheap in their entirety.
The process of online programming occurs with the direct interaction of the programmer with the robot at the place of its use. Using the control panel or physical movement, a tool (TCP) is mounted on the robot flange to the required point in space.
- The advantage of this method of programming is the simplicity of the approach to programming the robot. No need to know programming as such, just show the robot a sequence of positions.
- Significant disadvantages of this approach include significant time spent increasing the program to at least several tens (not to mention thousands) of points and its (program) subsequent modification. In addition, the robot during such training cannot be involved in the work.
The offline programming process , as the name implies, occurs remotely from the robot and its controller. The executable program is developed in a specialized environment for programming industrial robots on a PC, and then downloaded to the robot as a whole. However, software tools for such a development are not included in the basic delivery package of the robot and are additional options that are purchased separately and are not cheap in their entirety.
- The advantage of offline programming is that the robot can be involved in production and work while the program is being developed. A robot is needed only for debugging a written program. There is no need to go to the automation object and engage in robot programming in person.
- A big disadvantage of existing offline programming environments is their high cost. In addition, it is impossible to dynamically distribute the executable program between different robots.
As an example, consider the creation of a robot program in runtime mode, which provides the technological process of writing an ad with a marker.
Result:
ATTENTION! The video is not an advertisement, the vacancy is closed. The article was written after the video lost its relevance in order to demonstrate the proposed programming approach.
ATTENTION! The video is not an advertisement, the vacancy is closed. The article was written after the video lost its relevance in order to demonstrate the proposed programming approach.
Written text:
HELLO PEOPLE! WE NEED A
DEVELOPER. TO
CREATE A WEB INTERFACE OF OUR
KNOWLEDGE SYSTEM . SO WE WILL BE ABLE
TO TAKE FROM YOU HUMANOIDS OF KNOWLEDGE.
AND FINALLY WE WILL
BE ABLE TO GET IMPROVE THIS WORLD
MORE: HTTP://ROBOTCT.COM/HI
SINCERELY YOUR SKYNET = ^ - ^ =
DEVELOPER. TO
CREATE A WEB INTERFACE OF OUR
KNOWLEDGE SYSTEM . SO WE WILL BE ABLE
TO TAKE FROM YOU HUMANOIDS OF KNOWLEDGE.
AND FINALLY WE WILL
BE ABLE TO GET IMPROVE THIS WORLD
MORE: HTTP://ROBOTCT.COM/HI
SINCERELY YOUR SKYNET = ^ - ^ =
To write this text, it was necessary to transfer more than 1700 points to the robot.
As an example, a spoiler shows a screenshot from the remote control of a robot that draws a square. There are only 5 points in it (lines 4-8), each point essentially represents a complete expression (operator) and occupies one line. The manipulator bypasses each of the four points and, upon completion, returns to the starting point.
Screenshot of the remote control with an executable program

If you write a program in this way, it would be a minimum of 1700 statements — lines of code, per statement per point. But what if later it was required to change the text or the height of the letters, or the distance between them? Edit all 1700 line points? This is contrary to the spirit of automation!
So, let's get to the solution ...
We have a FANUC LR Mate 200iD robot with an R-30i series B cabinet controller. The robot is pre-configured with TCP at the end of the marker and the coordinate system of the desktop, so we can send coordinates without directly worrying about converting the coordinates from the coordinate system of the table to the coordinate system of the robot.
To implement a program for transmitting coordinates to a robot that will calculate the absolute values of each specific point, we will use the RCML programming language, which supports the proposed approach, has modules for communicating with this robot, and which, which is important for free for any use.
Let us describe each letter with points, but not in the real coordinates of space, but in the relative inside the frame into which the letter will be inscribed. Each letter will be drawn by a separate function, which receives as input parameters the serial number of the letter in the line, the line number, as well as the size of the letter, and sends a set of points to the robot with the calculated absolute coordinates of each point.
To write text we need to call a sequence of functions that draw letters in the same sequence in which they (letters) are indicated in the text. RCML has a meager toolkit for working with strings, so let's create an external Python script that will generate an RCML program - in fact, only generate a sequence of function calls of the corresponding letter sequence.
All the code is available in the GitHub repository: rct_paint_words
Let us consider the output file in more detail, execution starts with the main () function:
Sample RCML Output File
include "chars.rcml"
function main(){
try {
//Задействование робота
@fr = robot_fanuc;
system.echo("Start move program\n");
//Предварительная настройка окружения робота, координатная система, нагрузка, скорость
@fr->set_real_di("speed", SPEED);
@fr->set_real_di("cnt", CNT);
@fr->startProgram(UFRAME, UTOOL, PAYLOAD);
system.echo("prepare\n");
@fr->prepare();
system.echo("start draw\n");
//Сгенерированный, на Python, участок
@fr->draw_r_P(0, 0);
@fr->draw_P(1, 0);
@fr->draw_r_I(2, 0);
@fr->draw_B(3, 0);
@fr->draw_E(4, 0);
@fr->draw_T(5, 0);
@fr->draw_Comm(6, 0);
@fr->draw_r_L(8, 0);
@fr->draw_r_Yu(9, 0);
@fr->draw_r_D(10, 0);
@fr->draw_r_I(11, 0);
@fr->draw_Exclamation(12, 0);
@fr->draw_H(14, 0);
@fr->draw_A(15, 0);
@fr->draw_M(16, 0);
@fr->draw_H(18, 0);
@fr->draw_r_U(19, 0);
@fr->draw_r_Je(20, 0);
@fr->draw_E(21, 0);
@fr->draw_H(22, 0);
@fr->draw_P(0, 1);
@fr->draw_A(1, 1);
@fr->draw_r_Z(2, 1);
@fr->draw_P(3, 1);
@fr->draw_A(4, 1);
@fr->draw_r_B(5, 1);
@fr->draw_O(6, 1);
@fr->draw_T(7, 1);
@fr->draw_r_Che(8, 1);
@fr->draw_r_I(9, 1);
@fr->draw_K(10, 1);
@fr->draw_Dot(11, 1);
@fr->draw_r_D(12, 1);
@fr->draw_r_L(13, 1);
@fr->draw_r_Ya(14, 1);
@fr->draw_C(16, 1);
@fr->draw_O(17, 1);
@fr->draw_r_Z(18, 1);
@fr->draw_r_D(19, 1);
@fr->draw_A(20, 1);
@fr->draw_H(21, 1);
@fr->draw_r_I(22, 1);
@fr->draw_r_Ya(23, 1);
@fr->draw_B(25, 1);
@fr->draw_E(26, 1);
@fr->draw_r_B(27, 1);
@fr->draw_r_I(0, 2);
@fr->draw_H(1, 2);
@fr->draw_T(2, 2);
@fr->draw_E(3, 2);
@fr->draw_P(4, 2);
@fr->draw_r_F(5, 2);
@fr->draw_E(6, 2);
@fr->draw_r_Ii(7, 2);
@fr->draw_C(8, 2);
@fr->draw_A(9, 2);
@fr->draw_C(11, 2);
@fr->draw_r_I(12, 2);
@fr->draw_C(13, 2);
@fr->draw_T(14, 2);
@fr->draw_E(15, 2);
@fr->draw_M(16, 2);
@fr->draw_r_y(17, 2);
@fr->draw_H(19, 2);
@fr->draw_A(20, 2);
@fr->draw_r_Sha(21, 2);
@fr->draw_r_I(22, 2);
@fr->draw_X(23, 2);
@fr->draw_r_Z(0, 3);
@fr->draw_H(1, 3);
@fr->draw_A(2, 3);
@fr->draw_H(3, 3);
@fr->draw_r_I(4, 3);
@fr->draw_r_Ii(5, 3);
@fr->draw_Dot(6, 3);
@fr->draw_T(8, 3);
@fr->draw_A(9, 3);
@fr->draw_K(10, 3);
@fr->draw_M(12, 3);
@fr->draw_r_y(13, 3);
@fr->draw_C(15, 3);
@fr->draw_M(16, 3);
@fr->draw_O(17, 3);
@fr->draw_r_Je(18, 3);
@fr->draw_E(19, 3);
@fr->draw_M(20, 3);
@fr->draw_r_P(22, 3);
@fr->draw_E(23, 3);
@fr->draw_P(24, 3);
@fr->draw_E(25, 3);
@fr->draw_H(26, 3);
@fr->draw_r_Ya(27, 3);
@fr->draw_T(28, 3);
@fr->draw_soft_sign(29, 3);
@fr->draw_O(0, 4);
@fr->draw_T(1, 4);
@fr->draw_B(3, 4);
@fr->draw_A(4, 4);
@fr->draw_C(5, 4);
@fr->draw_r_Ge(7, 4);
@fr->draw_r_U(8, 4);
@fr->draw_M(9, 4);
@fr->draw_A(10, 4);
@fr->draw_H(11, 4);
@fr->draw_O(12, 4);
@fr->draw_r_Ii(13, 4);
@fr->draw_r_D(14, 4);
@fr->draw_O(15, 4);
@fr->draw_B(16, 4);
@fr->draw_r_Z(18, 4);
@fr->draw_H(19, 4);
@fr->draw_A(20, 4);
@fr->draw_H(21, 4);
@fr->draw_r_I(22, 4);
@fr->draw_r_Ya(23, 4);
@fr->draw_Dot(24, 4);
//Изменение ориентации маркера, чтобы роботу было проще дотянуться до края стола
@fr->set_real_di("speed", 10);
@fr->rotateMarker();
@fr->set_real_di("speed", SPEED);
@fr->draw_r_I(0, 6);
@fr->draw_H(2, 6);
@fr->draw_A(3, 6);
@fr->draw_K(4, 6);
@fr->draw_O(5, 6);
@fr->draw_H(6, 6);
@fr->draw_E(7, 6);
@fr->draw_r_Ce(8, 6);
@fr->draw_Minus(9, 6);
@fr->draw_T(10, 6);
@fr->draw_O(11, 6);
@fr->draw_M(13, 6);
@fr->draw_r_y(14, 6);
@fr->draw_C(16, 6);
@fr->draw_M(17, 6);
@fr->draw_O(18, 6);
@fr->draw_r_Je(19, 6);
@fr->draw_E(20, 6);
@fr->draw_M(21, 6);
@fr->draw_r_Z(0, 7);
@fr->draw_A(1, 7);
@fr->draw_X(2, 7);
@fr->draw_B(3, 7);
@fr->draw_A(4, 7);
@fr->draw_T(5, 7);
@fr->draw_r_I(6, 7);
@fr->draw_T(7, 7);
@fr->draw_soft_sign(8, 7);
@fr->draw_r_U(10, 7);
@fr->draw_r_L(11, 7);
@fr->draw_r_U(12, 7);
@fr->draw_r_Che(13, 7);
@fr->draw_r_Sha(14, 7);
@fr->draw_r_I(15, 7);
@fr->draw_T(16, 7);
@fr->draw_soft_sign(17, 7);
@fr->draw_r_aE(19, 7);
@fr->draw_T(20, 7);
@fr->draw_O(21, 7);
@fr->draw_T(22, 7);
@fr->draw_M(24, 7);
@fr->draw_r_I(25, 7);
@fr->draw_P(26, 7);
@fr->draw_r_P(0, 9);
@fr->draw_O(1, 9);
@fr->draw_r_D(2, 9);
@fr->draw_P(3, 9);
@fr->draw_O(4, 9);
@fr->draw_r_B(5, 9);
@fr->draw_H(6, 9);
@fr->draw_E(7, 9);
@fr->draw_E(8, 9);
@fr->draw_two_dots(9, 9);
@fr->draw_H(11, 9);
@fr->draw_T(12, 9);
@fr->draw_T(13, 9);
@fr->draw_P(14, 9);
@fr->draw_two_dots(15, 9);
@fr->draw_Slash(16, 9);
@fr->draw_Slash(17, 9);
@fr->draw_R(18, 9);
@fr->draw_O(19, 9);
@fr->draw_B(20, 9);
@fr->draw_O(21, 9);
@fr->draw_T(22, 9);
@fr->draw_C(23, 9);
@fr->draw_T(24, 9);
@fr->draw_Dot(25, 9);
@fr->draw_C(26, 9);
@fr->draw_O(27, 9);
@fr->draw_M(28, 9);
@fr->draw_Slash(29, 9);
@fr->draw_H(30, 9);
@fr->draw_I(31, 9);
@fr->draw_r_I(2, 10);
@fr->draw_C(3, 10);
@fr->draw_K(4, 10);
@fr->draw_P(5, 10);
@fr->draw_E(6, 10);
@fr->draw_H(7, 10);
@fr->draw_H(8, 10);
@fr->draw_E(9, 10);
@fr->draw_B(11, 10);
@fr->draw_A(12, 10);
@fr->draw_r_Sha(13, 10);
@fr->draw_S(15, 10);
@fr->draw_K(16, 10);
@fr->draw_Y(17, 10);
@fr->draw_N(18, 10);
@fr->draw_E(19, 10);
@fr->draw_T(20, 10);
@fr->draw_Equal(22, 10);
@fr->draw_Roof(23, 10);
@fr->draw_Minus(24, 10);
@fr->draw_Roof(25, 10);
@fr->draw_Equal(26, 10);
// Конец сгенерированного участка
@fr->stopProgram();
@fr->go_home();
} catch(E){
system.echo("Exception catched!");
return E;
}
return 0;
}
Consider the code for rendering a letter using the example of the letter A:
function robot_fanuc::draw_A(x_cell,y_cell){
//Постановка маркера в точку, координаты точки 5% по Х и 95% по Y в рамке буквы
robot->setPoint(x_cell, y_cell, 5, 95);
//Ведем линию
robot->movePoint(x_cell, y_cell, 50, 5);
//Ведем вторую линию
robot->movePoint(x_cell, y_cell, 95, 95);
//Получили "крышу" /\
//Переносим маркер с отрывом от стола для отрисовки палочки
robot->setPoint(x_cell, y_cell, 35, 50);
//Рисуем палочку
robot->movePoint(x_cell, y_cell, 65, 50);
//отрываем маркер от доски для перехода к следующей букве
robot->marker_up();
}
The functions of moving a marker to a point with or without a break are also very simple:
//Перемещение в точку с отрывом маркера или установка точки для начала рисования
function robot_fanuc::setPoint(x_cell, y_cell, x_percent, y_precent){
//вычисляем абсолютные координаты
x = calculate_absolute_coords_x(x_cell, x_percent);
y = calculate_absolute_coords_y(y_cell, y_precent);
robot->marker_up(); // отрываем маркер от стола
robot->marker_move(x,y); // перемещаем
robot->marker_down(); // ставим маркер на стол
}
//Перемещение в точку без отрыва маркера/рисование
function robot_fanuc::movePoint(x_cell, y_cell, x_percent, y_precent){
x = calculate_absolute_coords_x(x_cell, x_percent);
y = calculate_absolute_coords_y(y_cell, y_precent);
// тут все понятно :)
robot->marker_move(x,y);
}
The functions marker_up, marker_down, marker_move contain only the transfer code to the robot of the changed part of the coordinate of the TCP point (Z or XY)
function robot_fanuc::marker_up(){
robot->set_real_di("z", SAFE_Z);
er = robot->sendMoveSignal();
if (er != 0){
system.echo("error marker up\n");
throw er;
}
}
function robot_fanuc::marker_down(){
robot->set_real_di("z", START_Z);
er = robot->sendMoveSignal();
if (er != 0){
system.echo("error marker down\n");
throw er;
}
}
function robot_fanuc::marker_move(x,y){
robot->set_real_di("x", x);
robot->set_real_di("y", y);
er = robot->sendMoveSignal();
if (er != 0){
system.echo("error marker move\n");
throw er;
}
}
All configuration constants, including the size of the letters, their number per line, etc., were taken out in a separate chars_config.rcml file.
Chars_config.rcml configuration file
define CHAR_HEIGHT_MM 50 // Высота символов в мм
define CHAR_WIDTH_PERCENT 60 // Ширина символов в процентах от высоты
define SAFE_Z -20 // Безопасное положение наконечника маркера по оси z
define START_Z 0 // Рабочее положение наконечника маркера по оси z
// Границы рабочей зоны
define BORDER_Y 120
define BORDER_X 75
// Сигналы ON/OFF
define ON 1
define OFF 0
// Паузы между отправкой сигналов мс
define _SIGNAL_PAUSE_MILLISEC 50
define _OFF_PAUSE_MILLISEC 200
// Углы Эйлера начального положения маркера – углы ориентации инструмента
define START_W -179.707 // Крен
define START_P -2.500 // Тангаж
define START_R 103.269 // Рыскание
// Углы Эйлера после поворота маркера
define SECOND_W -179.704 // Крен
define SECOND_P -2.514 // Тангаж
define SECOND_R -14.699 // Рыскание
define CHAR_OFFSET_MM 4 // Отступ между буквами
define UFRAME 4 // Номер стола
define UTOOL 2 // Номер инструмента
define PAYLOAD 4 // Номер нагрузки
define SPEED 100 // Скорость
define CNT 0 // Параметр сглаженности перемещения
define ROTATE_SPEED // Скорость при повороте
define HOME_PNS 4 // Номер PNS программы перехода в домашнюю позицию
As a result, in total we received approximately 300 lines of high-level code, the design and writing of which took no more than 2 hours.
If this problem was solved “on the forehead” by online point-by-point programming, then it would have taken more than 9 hours (approximately 20-25 seconds per point, given that there are more than 1,700 points). In this case, the developer’s suffering is hard to imagine :), especially when it turned out that he forgot about the indentation between the letters, or made a mistake with the height of the letters and the text did not fit, and now you have to start all over again.
Conclusion:
Runtime programming allows you to solve the problem of moving the robot in a general way, dynamically composing a private movement program depending on the given parameters. Moreover, a program that solves the problem in a general way can be developed without the need for a robot, which on the one hand can be attributed to the offline approach to programming an industrial robot. On the other hand, a transfer program directly for the robot is already created for a specific instance and particular parameters for solving the problem on the spot, as in online programming.
In the considered example, the general algorithm was the lettering, and such parameters as their size, indentation between them, the number of letters in a line, etc., depended on the particular conditions on the site with the robot.
As noted, such an approach with dynamic construction of the trajectory of movement creates the prerequisites for the implementation of the robot switching (on an event basis), as an executive resource, between several simultaneously occurring tasks.
However, this approach should be used with caution.
In the demonstrated variation (with the transfer of one point at a time), the runtime approach has a significant limitation - the robot does not correctly understand the motion smoothing (CNT) instruction or ignores it, because when transmitting always one current point, the robot does not know anything about the next and cannot calculate the smoothed trajectory of going around the current point.
What is CNT?
When moving the robot tool, it is possible to influence two parameters:
Both of these parameters affect the final trajectory obtained, which is illustrated in the figure below:

In the worst case, the danger of using this instruction in runtime mode is that the robot reports that it has arrived at the intended smoothing point, although in reality it still goes to it. The robot does this to request the next point and calculate the smoothing. Obviously, it is impossible to know exactly what position the robot is when passing such a point, moreover, at a certain point it may be necessary, for example, to turn on the tool on the manipulator. The robot will give a signal that it has reached the point, but actually not. In this case, the tool will be turned on sooner than it should.
In the best case, the robot simply ignores the CNT instruction (depending on the model).
This is treated by transferring 2 or more points at a time, where the CNT point is not the last, however, this increases the complexity of the program and the load on the programmer.
What is CNT?
When moving the robot tool, it is possible to influence two parameters:
- Speed of movement - sets the speed of movement of the tool in mm / sec;
- Smoothing Level (CNT) - allows you to walk a group of points along the path with the smallest distance between the extreme points of the group.
Both of these parameters affect the final trajectory obtained, which is illustrated in the figure below:

In the worst case, the danger of using this instruction in runtime mode is that the robot reports that it has arrived at the intended smoothing point, although in reality it still goes to it. The robot does this to request the next point and calculate the smoothing. Obviously, it is impossible to know exactly what position the robot is when passing such a point, moreover, at a certain point it may be necessary, for example, to turn on the tool on the manipulator. The robot will give a signal that it has reached the point, but actually not. In this case, the tool will be turned on sooner than it should.
In the best case, the robot simply ignores the CNT instruction (depending on the model).
This is treated by transferring 2 or more points at a time, where the CNT point is not the last, however, this increases the complexity of the program and the load on the programmer.
I hope you find this article helpful.
I will be happy to answer your questions.