5.2. voraus.app //codelink
The voraus.app //codelink (vcl) is a groundbreaking app designed to seamlessly integrate the execution of Python code within the context of robot-specific programming languages like KRL (KUKA Robot Language). It serves as a bridge between the versatility of Python and its associated development landscape and the traditional industrial robotics world. The voraus.app //codelink is best suited to upgrade existing applications.
Benefits
Cost-Efficient – Upgrade existing robot solutions quickly and easily with smart services thanks to our intuitive plugin architecture.
Enhanced Flexibility – Creation of custom functionalities and solutions tailored to ever-changing project requirements.
Future-Proof – Benefit from the growing Python eco-system and include e.g. latest AI functionality.
Functionality
Customizable Functionality |
Users can design their own Python components which allows - a high degree of customization and adaptability, - the use of standard libraries and examples from the Python community, - easily applying inhouse code development principles. |
---|---|
Plugin Management |
voraus.app //codelink provides a flexible plugin architecture for - fast deployment of custom modules to the real system and - easy update or replacement of the deployed modules. |
Seamless Integration |
Integration of Python files with voraus.app //codelink is streamlined by - copying them into the designated plugins directory and - automated registration of plugins enables seamless execution, e.g., from KUKA KRL scripts. |
Note
The use of voraus.app //codelink is currently available for voraus.core //KUKA. More robots will be supported soon.
5.2.1. Setting up voraus.app //codelink
Required KUKA option packages:
KUKA.EthernetKRL 3.1
KUKA.WorkVisual 6.0
Required voraus files:
pythonKRL.xml
voraus_ekrl.src
voraus_ekrl.dat
Take the following steps to set up voraus.app //codelink with a KUKA robot:
Follow the installation steps described in Kuka installation guide.
Create a new virtual network interface in the robot advanced network settings (e.g. virtual6, see RSI IP address on KUKA control). This interface requires a different IP address than the KLI interface (see IP of the robot) but uses the same physical network port of the KRC. If a second virtual network had already been created (e.g. to set up the voraus.operator), it can be used for voraus.app //codelink as well. The virtual network interface must have the same network range as the IP address configured in Changing the default IP address. It will be referred to as <IP_of_the_voraus.ipc>.
Open the Docker compose file in Portainer (see Stack file configuration) and ensure that:
voraus-code-link component is enabled.
port 59152 for the EthernetKRL server is configured to the IP address of the voraus.ipc.
plugin folder volume is set.
voraus-core: [...] environment: [...] VORAUS__components__voraus-code-link__enabled: True [...] ports: - 8080:80 # Port for the voraus webapp - 8081:8081 # Port for the voraus license handler - <IP_of_the_voraus.ipc>:59152:59152/tcp # EKRL Server - 48400:48400 # OPC UA SysCtrl [...] volumes: [...] - /home/localuser/pluginWorkspace/plugins/:/root/data/voraus/voraus-code-link/plugins/ [...]
If you made any changes, restart the Portainer stack.
Edit the file pythonKRL.xml so that it contains the IP address of the voraus.ipc (only if the default IP address must be changed):
<ETHERNETKRL>
<CONFIGURATION>
<EXTERNAL>
<IP>IP_of_the_voraus.ipc</IP>
<PORT>59152</PORT>
<TYPE>Server</TYPE>
</EXTERNAL>
Copy the file pythonKRL.xml to the EthernetKRL directory of the robot (e.g. C:/KRC/Robot/Config/User/Common/EthernetKRL).
Copy the files voraus_ekrl.src and voraus_ekrl.dat to the program directory of the robot.
The setup is ready to use. To activate a voraus.core license please follow the steps of the chapter License Activation.
5.2.2. Plugin Creation (Basic Example)
voraus.app //codelink uses a plugin architecture which enables the user to create their own functions in Python. All Python files must be copied to the plugins directory on the UP² to be registered by voraus.app //codelink automatically.
In order for a plugin to be registered, it has to inherit from the parent class CodeLinkPlugin and define an execute() method. The execute() method will be executed when the plugin is called from the KRL script. If an optional __init__() method exists, it will be executed when the system is started. As can be seen in the plugin template Basic plugin template, the parameters of the execute() method consist of the self reference and an arbitrary number of input parameters sent from the robot.
Warning
The order of the input arguments is important!
1#!/usr/bin/env python3
2
3"""My first plugin using voraus.codelink."""
4
5import logging
6
7from voraus_code_link import CodeLinkPlugin
8
9_logger = logging.getLogger(__name__)
10
11
12class BasicPluginTemplate(CodeLinkPlugin):
13 """A basic template for plugins using the voraus.codelink."""
14
15 def execute(
16 self,
17 input_var_1: int,
18 input_var_2: str,
19 ) -> tuple[float, float]:
20 """
21 Execute the custom plugin.
22
23 Args:
24 input_var_1: Some input variable.
25 input_var_2: Some other input variable.
26
27 Add arbitrary number of inputs with supported datatypes.
28
29 Returns:
30 Either a single value or a tuple of an arbitrary number of return values with supported datatypes.
31 """
32 _logger.info(
33 f"Received input input_var_1:{input_var_1} & input_var_2:{input_var_2}"
34 )
35 # Your code
36 # Your code
37 # Your code
38
39 # The return values must be stored in the payload tuple
40 outvar1 = 1.0
41 outvar2 = 2.0
42
43 return (outvar1, outvar2)
The following data types and structures are currently supported for the inputs and the return values. In order to use the KUKA specific data type the module KukaProtocol must be imported.
Integer
Real
String
Boolean
KUKA FRAME - 6 Reals (X, Y, Z, A, B, C)
KUKA AXIS - 6 Reals (A1, A2, A3, A4, A5, A6)
KUKA E6AXIS - 12 Reals, 6 internal, 6 external axes (A1, A2, A3, A4, A5, A6, E1, E2, E3, E4, E5, E6)
To return values back to the KRL script they must be added to the return statement of the plugin class. The output of the plugin can either be a single value or a tuple.
from voraus_code_link.command_interface.protocol.kuka_protocol import KukaProtocol
return (
1,
2.2,
"MyTestResponse",
True,
KukaProtocol.KukaFrame(1.0, 1.1, 1.2, 0.9, 0.1, 0.8),
KukaProtocol.KukaAxis(30.0, 45.0, 20.0, 10.0, 5.0, 5.0),
KukaProtocol.KukaAxis(30.0, 45.0, 20.0, 10.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ),
)
A basic example of a plugin to interact with voraus.app //codelink is displayed in Basic Plugin Example.
1#!/usr/bin/env python3
2
3"""My first plugin using voraus.codelink."""
4
5import logging
6
7from voraus_code_link import CodeLinkPlugin
8
9_logger = logging.getLogger(__name__)
10
11
12class BasicPluginExample(CodeLinkPlugin):
13 """A basic example for plugins using the voraus.codelink."""
14
15 def execute(
16 self,
17 pose_id: int,
18 ) -> tuple[float, float, float, bool]:
19 """Execute the custom plugin.
20
21 Args:
22 pose_id: The identifier for a specific pose to be executed.
23
24 Returns:
25 A tuple containing the X, Y, and Z coordinates
26 along with a boolean flag indicating the validity of the specified pose.
27 """
28
29 _logger.info(f"Executing command {self.__class__.__name__}")
30
31 # debug print
32 _logger.info(f"poseID= {pose_id}")
33
34 # check poseID
35 if pose_id == 1:
36 x = 0.455
37 y = 0.250
38 z = 0.550
39 pose_valid = True
40 elif pose_id == 2:
41 x = 0.455
42 y = -0.250
43 z = 0.550
44 pose_valid = True
45 elif pose_id == 3:
46 x = 0.455
47 y = 0.0
48 z = 0.790
49 pose_valid = True
50 else:
51 pose_valid = False
52 # start pose values
53 x = 0.455
54 y = 0.0
55 z = 0.790
56 _logger.warning("Invalid pose ID!")
57
58 return (x, y, z, pose_valid)
Advanced Plugin Example shows an example with an additionally __init__() method. It is used to establish a connection to a TCP server that is later used in the execute() method.
1#!/usr/bin/env python3
2
3"""My first plugin using voraus.codelink."""
4
5import logging
6import socket
7
8from voraus_code_link import CodeLinkPlugin
9
10_logger = logging.getLogger(__name__)
11
12
13class AdvancedPluginExample(CodeLinkPlugin):
14 """An advanced example for plugins using the voraus.codelink with some init functions.
15
16 As an example, the __init__() function is used here to establish the connection to a TCP server.
17 The connected client can then later be used inside the execute() method.
18 The init function is executed during the registration step when starting the software stack.
19
20 The destructor is executed when the software stack is terminated.
21 In this example the connection to the TCP server is closed.
22 """
23
24 def __init__(self) -> None:
25 """Initialize client connection."""
26 self.is_connected = False
27 self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
28 self.client_socket.settimeout(10)
29 self._connect(device_host="0.0.0.0", device_port=4242)
30
31 def _connect(self, device_host: str, device_port: int) -> None:
32 # Create a socket object (IPv4 address and TCP protocol)
33 try:
34 self.client_socket.connect((device_host, device_port))
35 self.is_connected = True
36 print(
37 f"Connection to the TCP socket {device_host}:{device_port} was successful!"
38 )
39 except socket.error as exc:
40 raise exc
41
42 def __del__(self):
43 self.client_socket.close()
44 _logger.info("Destructor called.")
45
46 def execute(self) -> bool:
47 """Execute the custom plugin.
48
49 Returns:
50 whether the command was successful.
51 """
52
53 _logger.info(f"Executing command {self.__class__.__name__}")
54
55 try:
56 # Send the "trigger" command
57 trigger_command = "TRG"
58 self.client_socket.sendall(trigger_command.encode("utf-8"))
59 return True
60
61 except socket.error as exc:
62 print("Error in trigger_job(): ", exc)
63
64 return False
5.2.3. Plugin Deployment
To deploy a new plugin it must be copied to the plugins directory on the UP².
The UP² can be accessed via SSH using:
ssh localuser@192.168.1.1
To avoid having to enter the password each time, your SSH key can be copied to the UP²:
ssh-copy-id -i [ssh-key-file] localuser@192.168.1.1
Copy the Python file to the directory pluginWorkspace/plugins. This can be done via SFTP tools such as FileZilla, WinSCP, etc. or directly via the terminal:
scp MyNewPlugin.py localuser@192.168.1.1:/home/localuser/pluginWorkspace/plugins
If you want to use custom Python modules, they must be in the same directory as the plugins that import them. Modules copied to the plugins directory must contain an __init__.py file in order to be recognized as Python modules as shown in Fig. 83/➋. A module can then be imported by their name (see Fig. 83).
from sensopart.sensopart import CameraClass
In order to register a new plugin, the voraus.core container must be restarted. Open a web browser and type in the IP address of the Portainer interface of the UP². The default IP adress is 192.168.1.1:9443. After signing in with the provided credentials the Portainer landing page will be displayed (Fig. 84). Click the button Live connect (Fig. 84/➊) to access the dashboard.
In the dashboard navigate to the menu element Stacks (Fig. 85/➊) to open the available stacks on the UP².
Select the voraus.app //codelink stack (e.g. vcl_1_0) (Fig. 86/➊).
On the stack details page, select the voraus-core container (Fig. 87/➊) and click on restart (Fig. 87/➋).
The new plugin will then be found and registered by the voraus.app //codelink, which can be seen in the Portainer log (Fig. 88/➊).
An instruction on how to install additional Python packages is provided in Installation of additional packages.
5.2.4. Calling Python Plugins from KRL
To call a Python plugin from a KRL script the template Basic KRL template to call a plugin provided in this section can be used. The template presents the KRL part of the Basic plugin template from the previous chapter.
1DEF vclKRLtemplate ( )
2
3; Plugin name
4DECL char plugin_name[80]
5
6; Declare all variables sent to the Python script here
7DECL int inputVar1, inputVar2
8
9
10; Declare all parameters that are returned from the Python script here
11DECL real outvar1, outvar2
12
13; KRL bridge variables
14DECL char param_buffer[2048]
15DECL char response_buffer[4096]
16DECL int offset
17DECL char format[255]
18DECL bool ret
19DECL char debug_message[80]
20DECL STATE_T state
21
22
23; Enter the name of the Python plugin here
24plugin_name[] = "BasicPluginTemplate"
25
26; Init the Python variables
27response_buffer[1] = " "
28debug_message[1] = " "
29
30; Set up the python KRL bridge variables for the function call
31offset = 0
32CAST_TO(param_buffer[], offset, inputVar1, inputVar2)
33
34; Supported formats:
35; %d = int
36; %f = float/real
37; %s = string
38; %b = bool - Note bool is 1byte and int is 4byte in KRL. Do not confuse these in the format string
39; %p = frame - 6 floats/reals (x,y,z,A,B,C)
40; %a = axis - 6 floats/reals (a1,a2,a3,a4,a5,a6)
41; %e = e6 axis - 12 floats/reals (a1..a6, e1..6) 6 internal, 6 external axes
42
43; Define the format of all variables sent to the Python script
44format[] = "%d %d"
45
46; Call the Python script
47ret = voraus_execute_python(plugin_name[], format[], param_buffer[], response_buffer[])
48
49if ret <> TRUE then
50 HALT ; Error while trying to execute python.
51 return
52endif
53
54; Cast the response bytes to the correct return values. The order is important
55offset = 0
56; Enter the names of the Python return variables in the correct order
57CAST_FROM(response_buffer[], offset, outvar1, outvar2)
58
59; Show the return values on the smartPAD
60offset = 0
61SWRITE(debug_message[], state, offset, "Python returns: actual outvar1=%f, outvar2=%f", outvar1, outvar2)
62MsgNotify(debug_message[], "voraus")
63
64
65END
To use the template, the input parameters (line 7) sent to the Python script as well as the output parameters (line 11) that are returned and the name of the Python plugin to be called (line 24) have to be declared. The name must match the name of the Python class.
Parameters to be sent to the Python command must be in the same order as they are declared in the plugin’s function signature. For the introduced template, the first element in the list is inputVar1 (line 32). Additionally, the format of the Python command parameters must be defined via the format list (line 44). The following data types are supported:
Format specifier |
Data type |
---|---|
%d |
int |
%f |
real |
%s |
string |
%b |
bool |
%p |
frame |
%a |
axis |
%e |
e6 axis |
The response of the Python plugin is parsed in the CAST_FROM() function (line 57). The output variables must be in the same order as the return values of the Python plugin. You can then use the output variables in the KRL program as needed, e.g. print them to the output window of the KUKA smartPAD (line 61) or as coordinates for a robot movement.
An implementation example using the KRL template is shown in Basic KRL example using a Python plugin. This example uses the Basic Plugin Example from the previous chapter to retrieve the coordinates of three different Cartesian positions. The KRL program moves the robot’s TCP between the positions. The KRL main program calls the function myKRLfunction() which is based on the vclKRLtemplate.
1DEF vclKRLexample ( )
2
3DECL int poseID
4DECL real x,y,z
5DECL BOOL posValid
6
7DECL int movementsDone ; debug counter. Number of completed movements
8
9; Init variables
10poseID = 1
11movementsDone = 0
12posValid = TRUE
13
14;Start in the home pose
15;FOLD PTP START_POS_AXIS Vel=10 % PDAT1 Tool[1] Base[0] ;%{PE}
16;FOLD Parameters ;%{h}
17;Params IlfProvider=kukaroboter.basistech.inlineforms.movement.old; Kuka.IsGlobalPoint=False; Kuka.PointName=START; Kuka.BlendingEnabled=False; Kuka.MoveDataPtpName=PDAT1; Kuka.VelocityPtp=10; Kuka.CurrentCDSetIndex=0; IlfCommand=PTP
18;ENDFOLD
19$BWDSTART = FALSE
20PDAT_ACT = PPDAT1
21FDAT_ACT = FSTART_POS_AXIS
22BAS(#PTP_PARAMS, 10.0)
23SET_CD_PARAMS (0)
24PTP START_POS_AXIS
25;ENDFOLD
26
27; Get a pose from the Python plugin
28WHILE ( posValid )
29
30 myKRLfunction(poseID, x, y, z, posValid ) ; a KRL function that calls a Python plugin
31
32 ; check return values
33 IF ( posValid ) THEN
34
35 ; save received position data
36 TARPOS.X = x * 1000; m -> mm
37 TARPOS.Y = y * 1000; m -> mm
38 TARPOS.Z = z * 1000; m -> mm
39 ;keep status and turn of the current pose
40 TARPOS.T = $POS_ACT.T
41 TARPOS.S = $POS_ACT.S
42
43 ;FOLD LIN TARPOS Vel=0.25 m/s CPDAT1 Tool[1] Base[0] ;%{PE}
44 ;FOLD Parameters ;%{h}
45 ;Params IlfProvider=kukaroboter.basistech.inlineforms.movement.old; Kuka.IsGlobalPoint=False; Kuka.PointName=TARPOS; Kuka.BlendingEnabled=False; Kuka.MoveDataName=CPDAT1; Kuka.VelocityPath=0.25; Kuka.CurrentCDSetIndex=0; Kuka.MovementParameterFieldEnabled=True; IlfCommand=LIN
46 ;ENDFOLD
47 $BWDSTART = FALSE
48 LDAT_ACT = LCPDAT1
49 ;FDAT_ACT = FTARPOS_1
50 BAS(#CP_PARAMS, 0.25)
51 SET_CD_PARAMS (0)
52 LIN TARPOS
53 ;ENDFOLD
54
55 ;increase movementsDone counter
56 movementsDone = movementsDone + 1
57
58 ; Update poseID (range 1 to 3)
59 IF ( poseID >= 3 ) THEN
60 poseID = 1
61 ELSE
62 poseID = poseID +1
63 ENDIF
64
65 ELSE
66 ;pose not valid -> Terminate
67 ENDIF
68ENDWHILE
69END
70
71DEF myKRLfunction (poseID:IN, x:OUT, y:OUT, z:OUT, posValid:OUT )
72
73; Plugin name
74DECL char plugin_name[80]
75
76; Declare all variables sent to the Python script here
77DECL int poseID
78
79; Declare all parameters that are returned from the Python script here
80DECL real x,y,z ; robot position in [m, m, m]
81DECL BOOL posValid ; is the given pose valid (poseID range check on Python side)
82
83; KRL bridge variables
84DECL char param_buffer[2048]
85DECL char response_buffer[4096]
86DECL int offset
87DECL char format[255]
88DECL bool ret
89DECL char debug_message[80]
90DECL STATE_T state
91
92; Enter the name of the Python plugin here
93plugin_name[] = "BasicPluginExample"
94
95; Init the Python variables
96response_buffer[1] = " "
97debug_message[1] = " "
98
99; Set up python krl bridge variables for the function call
100offset = 0
101CAST_TO(param_buffer[], offset, poseID)
102
103; Supported formats:
104; %d = int
105; %f = real
106; %s = string
107; %b = bool - Note bool is 1byte and int is 4byte in KRL. Do not confuse these in the format string!
108; %p = frame - 6 reals (x,y,z,A,B,C)
109; %a = axis - 6 reals (a1,a2,a3,a4,a5,a6)
110; %e = e6 axis - 12 reals (a1..a6, e1..6) 6 internal, 6 external axes
111
112; Define the format of all variables sent to the Python script
113format[] = "%d"
114
115; Call the Python script
116ret = voraus_execute_python(plugin_name[], format[], param_buffer[], response_buffer[])
117
118if ret <> TRUE then
119 HALT ; Error while trying to execute python.
120 return
121endif
122
123; Cast the response bytes to the correct return values. The order is important!
124offset = 0
125; Enter the names of the Python return variables in the correct order
126CAST_FROM(response_buffer[], offset, x, y, z, posValid )
127
128; Show the return values on the smartPAD
129offset = 0
130SWRITE(debug_message[], state, offset, "Last ID:%d, Latest Position: x=%f, y=%f, z=%f", poseID, x ,y, z)
131MsgNotify(debug_message[], "voraus")
132
133END
The function myKRLfunction() receives a poseID (int) and returns three coordinates (real) named x, y and z. The output variable posValid (bool) indicates if the required poseID corresponds to a valid ID. Parameters, name and responses of the Python plugin are modified in KRL according to the explanation above.
Furthermore, to use the above KRL example with a KUKA robot, a .dat file has to be created containing the default declarations as shown in Basic KRL example (dat file).
1DEFDAT vclKRLexample PUBLIC
2
3;Move PTP (Start Pose. x = 445, y = 0, z = 790, A = 180, B = 0, C = 180 (in [mm] and voraus-KARDAN angles)
4DECL E6AXIS START_POS_AXIS={A1 0.0,A2 -90.0000,A3 90.0000,A4 0.0,A5 90.0000,A6 0.0,E1 0.0,E2 0.0,E3 0.0,E4 0.0,E5 0.0,E6 0.0}
5DECL PDAT PPDAT1={VEL 10.0000,ACC 100.000,APO_DIST 500.000,APO_MODE #CDIS,GEAR_JERK 100.000,EXAX_IGN 0}
6
7
8;Move Lin (Python Pose)
9DECL POS TARPOS={X 455.000,Y 250.000,Z 550.000,A 180.000,B 1.08803544E-13,C -180.000,S 2,T 10}
10
11DECL LDAT LCPDAT1={VEL 0.250000,ACC 100.000,APO_DIST 500.000,APO_FAC 50.0000,AXIS_VEL 100.000,AXIS_ACC 100.000,ORI_TYP #VAR,CIRC_TYP #BASE,JERK_FAC 50.0000,GEAR_JERK 100.000,EXAX_IGN 0,CB {AUX_PT {ORI #CONSIDER,E1 #CONSIDER,E2 #CONSIDER,E3 #CONSIDER,E4 #CONSIDER,E5 #CONSIDER,E6 #CONSIDER},TARGET_PT {ORI #INTERPOLATE,E1 #INTERPOLATE,E2 #INTERPOLATE,E3 #INTERPOLATE,E4 #INTERPOLATE,E5 #INTERPOLATE,E6 #INTERPOLATE}}}
12
13DECL FDAT FSTART_POS_AXIS={TOOL_NO 1,BASE_NO 0,IPO_FRAME #BASE,POINT2[] " "}
14
15
16ENDDAT
5.2.5. Examples
Introduction
This example shows how to integrate the SensoPart V20 camera manufactured by SensoPart Industriesensorik GmbH with voraus.app //codelink. For this the client implementation from section Writing a Python TCP/IP client for the camera is used.
Getting Started
Requirements
Follow the steps in Tutorial: How to integrate a SensoPart camera with Python to set up the camera.
Implementation Steps
Copy the script sensopart.py Writing a Python TCP/IP client for the camera to the subfolder sensopart as described in Plugin Deployment. The code section below provides an implementation example for using the SensoPart camera. The main functionality for retrieving the object’s position is inside the execute() method. The TCP/IP connection is handled inside the constructor __init__() and desctructor __del__().
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4import logging
5import sensopart.sensopart as sensopart
6from typing import Tuple
7
8from voraus_code_link import CodeLinkPlugin
9
10_logger = logging.getLogger(__name__)
11
12
13class GetPose(CodeLinkPlugin):
14 def __init__(self):
15 device_host = "192.168.100.200"
16 self._request_channel = sensopart.V20(device_host, device_port=2006)
17 self._receive_channel = sensopart.V20(device_host, device_port=2005)
18 _logger.info("Connected to Camera")
19
20 def __del__(self):
21 # Disconnect the TCP clients
22 self._request_channel.disconnect()
23 self._receive_channel.disconnect()
24 _logger.info("Connection to Camera closed")
25
26 def execute(self) -> Tuple[float, float, float]:
27 """Execute the camera plugin.
28
29 Returns:
30 Tuple of x_pos, y_pos and z_rot
31 """
32 x_pos = 0.0
33 y_pos = 0.0
34 z_rot = 0.0
35
36 _logger.info(f"Executing command {self.__class__.__name__}")
37
38 # Call the current camera job via TCP/IP
39 self._request_channel.trigger_job()
40
41 # Get the camera result via TCP/IP
42 (x_pos, y_pos, z_rot) = self._receive_channel.read_results()
43
44 return (x_pos, y_pos, z_rot)
The corresponding KRL function to call the plugin is shown below
1DEF call_GetPose(x_pos: OUT,y_pos: OUT,a_rot: OUT)
2; Plugin name
3DECL char plugin_name[80]
4
5; KRL bridge variables
6DECL CHAR param_buffer[2048]
7DECL CHAR response_buffer[4096]
8DECL INT offset
9DECL CHAR format[255]
10DECL BOOL ret
11DECL CHAR debug_message[255]
12DECL STATE_T state
13DECL BOOL ret_str
14
15; Declare all variables sent to the Python script
16
17; Declare all parameters that are returned from the Python script
18DECL REAL x_pos
19DECL REAL y_pos
20DECL REAL a_rot
21
22; Initialize bridge variables
23response_buffer[1] = " "
24
25; Enter the name of the Python plugin here
26plugin_name[] = "GetPose"
27
28; Supported formats:
29; %d = int
30; %f = real
31; %s = string
32; %b = bool - Note bool is 1byte and int is 4byte in KRL. Do not confuse these in the format string
33; %p = frame - 6 floats/reals (x,y,z,A,B,C)
34; %a = axis - 6 floats/reals (a1,a2,a3,a4,a5,a6)
35; %e = e6 axis - 12 floats/reals (a1..a6, e1..6) 6 internal, 6 external axes
36; Define the format of all variables sent to the Python script
37format[] = " "
38
39; Initialize string variables (e.g. debug_message or plugin returns)
40debug_message[1] = " "
41param_buffer[1] = " "
42; Set up the python KRL bridge variables for the function call
43offset = 0
44;CAST_TO(param_buffer[], offset)
45
46; Call the Python script
47ret = voraus_execute_python(plugin_name[], format[], param_buffer[], response_buffer[])
48
49if ret <> TRUE then
50 HALT ; Error while trying to execute python.
51 return
52endif
53
54; Cast the response bytes to the correct return values. The order is important
55offset = 0
56CAST_FROM(response_buffer[], offset, x_pos)
57CAST_FROM(response_buffer[], offset, y_pos)
58CAST_FROM(response_buffer[], offset, a_rot)
59
60; Show the return values on the smartPAD
61offset = 0
62;SWRITE(debug_message[], state, offset, "Object position x_pos=%.2f, y_pos=%.2f, a_rot=%.2f", x_pos, y_pos, a_rot)
63MsgNotify(debug_message[], "voraus")
64ret = STRCLEAR(debug_message[])
65
66END
5.2.6. Troubleshooting
Error Message |
Comment |
---|---|
The plugin is not found/registered |
Check that the plugin inherits from the parent class CodeLinkPlugin and has an execute() method defined. |
Conflict between plugins |
The plugins get loaded and initialized automatically when starting the software stack. That also means that each __init__() method defined for the plugins is executed at the start. If for example two plugins try to access the same camera there can be a resource conflict. Consider outsourcing problematic functionalities of the __init__() into separate plugins or inside the execute() method. |
ValueError: Plugin name already registered |
Two or more plugins share the same class name. Make sure to remove deprecated plugins or rename them. |
ModuleNotFoundError |
Follow the instructions above to install missing dependencies. |
NotImplementedError |
Check that the plugin has a callable execute() method defined. |
ArgumentLengthMismatchError |
Check that the sent number of parameters defined in KRL matches the number of expected input arguments of the plugin. |