Example: Textual horstFX-program with PLC logic control

An example program is presented here in which registers that determine the program sequence are accessed within a textual program on HORST.

1. Function

The robot program contains three cases, which are called up via a function number. The function number is sent from the PLC to the robot via the Int register.
Different subprograms can be called within the cases. In this example, no function is executed in case 0, different positions are approached in the second case and a position is approached in the third case, the coordinates of which are transferred from the PLC to the robot via the float register. The movements can be aborted via an abort command.
The program is controlled by setting action and status bits. A case is started via a start bit that is sent to the robot by the PLC. As soon as the start bit is recognized by the robot, the active bit is set. Once a case has been fully processed or aborted, the active bit is reset. A partial program can be aborted via the abort bit.

2. PLC program

A function block is created in OB1 in the TIA Portal to call up the cases. The case, which is selected via the function number, is executed via the start input.
The case can be canceled via the abort command. The function number is an integer that is given to the block at the input. If a case is executed, the block busy output assumes the value 1. Once the partial program has been executed, the busy output is reset and the done output is set.

In the first network of the "Execute_Function" function block, a query is made as to whether the done output is set. If this is the case, the following networks are skipped and a new start command is waited for.

If the busy output is not set, the busy output is set on a positive edge at the start input.

If the busy output assumes the value 1, no function number has yet been sent to the robot (start_ack) and the active bit is not set, the function number from the input is written to the first Int register. The mask of the respective controller must then be set so that the function number is transferred to the robot. The start bit and its mask are then also set to 1. The module-internal variable "start_ack" saves the state in which the function number was transferred to the register.

If the start_ack and busy bits are set and the program_start bit is not set, the mask for the Int register and the start bit is reset on a positive edge at the active bit.

The variable "program_started" saves the state in which the robot has detected the start bit and is now active.

If the abort bit (bit_register[2]) and its mask are set (while the busy and program-start bits are set), the abort command is sent to the robot.

A negative edge on the active bit signals to the PLC that the case has been fully processed or aborted. If this is the case, the busy output is reset and the done output is set. In addition, the internal variables and the edges are reset.

3. Robot program

In the robot program, the addresses for the action and status bits are defined and initialized at the beginning.

// Specify the register addresses of the action and status bits used
var bit_start = 0; // Start bit is sent from the PLC to the robot.
var bit_active = 1; // Sent from the robot to the PLC. Indicates that the robot is executing a case.
var bit_abort = 2; // Can be sent by the robot to the PLC to abort a case or subprogram.


// Initialize the bits
setBoolRegister(bit_start, 0);
setBoolRegister(bit_active, 0);
setBoolRegister(bit_abort, 0);

The program then waits in a (while) loop for the start bit to be set. The command getBoolRegister(address) can be used to read from the individual bit registers.
If this condition is met, the active bit is set (setBitRegsiter(address,value) and the function number is read from the first (or 0th) Int register.  The Int register is read using the "getIntRegsiter(address)" command.

// Continuous loop for querying the bits or calling the function number
while(true){
          if(getBoolRegister(bit_start) == 1){
                    //Bit indicates that the robot is now active and is executing a movement
                    setBoolRegister(bit_active, 1);
                    
                    // Read the function number from the Int registers
                    var function_number = getIntRegister(0);

                    // Call the execute function in which the cases are created
                    execute_function(function_number);
          }

          //Wait for 200 ms to minimize the computing load
          sleep(200);
}

The case, which is selected via the function number, is then executed. The cases consist of a try-catch function. The actual partial program takes place within the try area. If this is not possible or if an error occurs, this is displayed in a message text in the catch area. Once the partial program has been successfully executed or an error has been confirmed, the active bit is reset.

function execute_function(function_number){
     try {
          switch(function_number){
               case 0: {
                  // no action for function number = 0
                     break;
               }
               case 1: {
                  // execute program 1
                    program_1();
                    break;
               }
               case 2: {
                  // execute program 2
                    program_2();
                    break;
               }
          }
     }
     catch(e) {
        //Show a possible error as info
          show_info(e);
     } finally{
        //Reset the bit_active so that the PLC can determine whether the movement has been completed
          setBoolRegister(bit_active, 0);
     }
}

In Case 1, three random positions are moved to. The move is carried out using the extended move command. With this command, it is possible to define an abort condition.
The abort command is generated via an interrupt. The abort bit is monitored within the interrupt; if it assumes the value 1, the move command is aborted.
The variable "bit_abort", which is called in the name of the interrupt, is a variable that contains the address of the abort bit. In this example, the variable bit_abort contains the number 2 (note that the numbering of the registers starts at 0). In addition to aborting the move command, it is also possible to pause the move command. The different options of the extended move command are described in the link above.

function program_1(){
// Exemplary approach of different points, with abort condition bit_abort =1

move({
    'Coord': 'JOINT',
    'MoveType': 'JOINT',
    'PoseRelation': 'ABSOLUTE',
    'anyconfiguration': false,
    'speed.ratio': 1.0,
    'targetjoints.j1': -36.78999999999998,
    'targetjoints.j2': 55.24999999999907,
    'targetjoints.j3': -9.32936896029222,
    'targetjoints.j4': 0.0,
    'targetjoints.j5': 0.0,
    'targetjoints.j6': 0.0,

     'interrupt':[
          {
               'name': 'BOOL_REGISTER_'+bit_abort,
               'operator': '==',
               'type': 'CANCEL',
               'value': 1.0
          }
     ]
}, "Waypoint 1");

move({
    'Coord': 'JOINT',
    'MoveType': 'JOINT',
    'PoseRelation': 'ABSOLUTE',
    'anyconfiguration': false,
    'speed.ratio': 1.0,
    'targetjoints.j1': 0.259999999999728,
    'targetjoints.j2': 65.38999999999908,
    'targetjoints.j3': -47.969368814615606,
    'targetjoints.j4': 0.0,
    'targetjoints.j5': 0.0,
    'targetjoints.j6': 0.0,

     'interrupt':[
          {
               'name': 'BOOL_REGISTER_'+bit_abort,
               'operator': '==',
               'type': 'CANCEL',
               'value': 1.0
          }
     ]
}, "Waypoint 2");

move({
    'Coord': 'JOINT', 
    'MoveType': 'JOINT', 
    'PoseRelation': 'ABSOLUTE', 
    'anyconfiguration': false, 
    'speed.ratio': 1.0, 
    'targetjoints.j1': -60.83999999999948, 
    'targetjoints.j2': 65.38999999999908, 
    'targetjoints.j3': -47.969368814615606, 
    'targetjoints.j4': 0.0, 
    'targetjoints.j5': 0.0, 
    'targetjoints.j6': 0.0, 

     'interrupt':[
          {
               'name': 'BOOL_REGISTER_'+bit_abort, 
               'operator': '==', 
               'type': 'CANCEL', 
               'value': 1.0
          }
     ]
}, "Waypoint 3");

}

In Case 2, a position is transferred from the PLC to the robot and moved to as soon as the start bit is set by the PLC. This move command is also carried out via the extended move command.
In this command, you can select, among other things, how the position is to be approached. In this example, the position is defined via the axis angles. The six axis angles are transferred from the PLC to the robot in the first six float registers. To do this, the addresses for the six axis angles are assigned and then the respective float registers are called up directly in the move command. Alternatively, the Cartesian coordinates can be selected within the move command and the x, y, z coordinates and the rx, ry, rz rotations can be transferred to the robot in the float registers.

function program_2(){
// Exemplary approach to a position, the coordinates are transferred from the PLC to the robot.
// With abort condition bit_abort =1

// Specify the float register addresses
var axis_angle_1= 0;
var axis_angle_2= 1;
var axis_angle_3= 2;
var axis_angle_4= 3;
var axis_angle_5= 4;
var axis_angle_6= 5;


move({
    'Coord': 'JOINT',
    'MoveType': 'JOINT',
    'PoseRelation': 'ABSOLUTE',
    'anyconfiguration': false,
    'speed.ratio': 1.0,
    'targetjoints.j1': getFloatRegister(Axis_angle_1),
    'targetjoints.j2': getFloatRegister(Achswinkel_2),
    'targetjoints.j3': getFloatRegister(Achswinkel_3),
    'targetjoints.j4': getFloatRegister(Achswinkel_4),
    'targetjoints.j5': getFloatRegister(Achswinkel_5),
    'targetjoints.j6': getFloatRegister(Achswinkel_6),

     'interrupt':[
          {
               'name': 'BOOL_REGISTER_'+bit_abort,
               'operator': '==',
               'type': 'CANCEL',
               'value': 1.0
          }
     ]
}, 'waypoint 4');

}

The robot program as well as the PLC program can be downloaded from the following links:

Example program horstFX Cases

PLC-Program Cases