UDP Server for KUKA RSI : Python Server with GUI for Axis Jogging from Master Computer | ROS Connectivity to KUKA Robot via Robot Sensor Interface

KUKA Robot controller has inbuilt Ethernet port called KLI (KUKA LINE INTERFACE, Static IP) which is used for UDP/TCP IP connections from external system.

Real Time Axis/Cartesian Position corrections (Delta) can be achieved via KUKA Optional Technology Package called RSI.(Robot Sensor Interface)

Now, Here RSI installed on Controller will behave as UDP Client and External Computer/System should be Server.

Step 1: Use RSIVisual (Graphical XML/RSI Editor) supplied by KUKA to generate .XML and .RSI files.

Step 2: Copy all these (.RSI, .Diagram, .XML, Config.XML) files inside KUKA Controller under path: C:/KRC/Roboter/Config/User/Common/SensorInterface

Step 3: Start ServerApp.py on External Computer. (ServerApp.py Attached)

KUKA RSI GUI Python
KUKA RSI GUI Python

Step 4: Run RSI_Ethernet.src file on KUKA Controller. (This src is supplied by KUKA RSI — Example Folder)

Step 5: Post Connection is established with Controller, Run GUI.py to Control Axis 1 to Axis 6 in Real Time.

Enjoy!

Thanks.

Project Source Code: https://github.com/pawankumargurav/kukarsiserver

Source 1: Example Code to demonstrate working principle of KUKA RSI IPOC Reflection using PY:

# if the customer is creating his own server with someother software then python then provide him the Port no of the Cotroller which will 
# be coming on "socket_of_krc" line no 38 


import socket

UDP_IP = "192.168.1.100" # ip address of your computer

UDP_PORT = 59152 #port enabled in KRC NAT port configuration
    
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # Create a UDP socket
sock.bind((UDP_IP, UDP_PORT))
xml_file = open("rsi.xml", "r") #the rsi.xml files contains the data that is to be send 
default_command = xml_file.read()

# The function below is used to reflect the IPOC value received from the controller data. if the IPOC does not reply for the given timeout set in Ethernet 
#block of the kuka RSIX file the controller shows an error of RSI bad Timeout. 

def mirroripoc(received_data, data_to_send):

    ipoc_begin_index = int (received_data.index("<IPOC>"))
    ipoc_end_index = int(received_data.index("</IPOC>"))
    received_ipoc = int (received_data[ipoc_begin_index + 6: ipoc_end_index])

    old_ipoc_begin_index = data_to_send.index("<IPOC>")
    old_ipoc_end_index = data_to_send.index("</IPOC>")
    old_ipoc = data_to_send[old_ipoc_begin_index + 6: old_ipoc_end_index]

    oldipocrsi =  f"<IPOC>{old_ipoc}</IPOC>" 
   
    newipocrsi = f"<IPOC>{received_ipoc}</IPOC>"

   
    return data_to_send.replace(oldipocrsi,newipocrsi)
   


while True:

    received_data, socket_of_krc = sock.recvfrom(1024)  # buffer size is 1024 bytes

    received_data =  received_data.decode('utf-8')

    data_to_send = default_command

    data_to_send = mirroripoc(received_data, data_to_send)


    bytesToSend = str.encode(data_to_send)
    sock.sendto(bytesToSend, socket_of_krc)

    xml_file.close()





    

Source 2: Server with GUI for RSI Jogging of KUKA Robot:

ServerApp.py : Connects to KUKA Controller. Read Write ActualPos.xml

import socket
import os
import time;
from bs4 import BeautifulSoup
import xml.etree.cElementTree as ET
import sys

localIP     = "192.168.100.111" ## Address of your Computer -- Same must be entered in RSI Config File

localPort   = 9508  ## Port on your computer

bufferSize  = 1024 ## No need to change

 


 

# Create a datagram socket

UDPServerSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)

 

# Bind to address and ip

UDPServerSocket.bind((localIP, localPort))

 

print("UDP server up and listening for KUKA RSI !  - Set your Server Computer IP to 192.168.100.111 , Port : 9508 ")

 

# Listen for incoming datagrams

while(True):
    
    

    bytesAddressPair = UDPServerSocket.recvfrom(bufferSize)

    message = bytesAddressPair[0]

    address = bytesAddressPair[1]

    clientMsg = format(message)
    
    clientIP  = "Client IP Address:{}".format(address)
    

    #print(clientMsg)
    
    
    receivedData = BeautifulSoup(message, 'html.parser')
    
    #print(receivedData)
    
    axis1_act = receivedData.a1.get_text()
    axis2_act = receivedData.a2.get_text()
    axis3_act = receivedData.a3.get_text()
    axis4_act = receivedData.a4.get_text()
    axis5_act = receivedData.a5.get_text()
    axis6_act = receivedData.a6.get_text()
    

    ## Write to XML Actual Position
    root = ET.Element("root")
   

    ET.SubElement(root, "Axis1").text = axis1_act
    ET.SubElement(root, "Axis2").text = axis2_act 
    ET.SubElement(root, "Axis3").text = axis3_act
    ET.SubElement(root, "Axis4").text = axis4_act
    ET.SubElement(root, "Axis5").text = axis5_act
    ET.SubElement(root, "Axis6").text = axis6_act
    
    tree = ET.ElementTree(root)
    tree.write("actualpos.xml")
    
 
##Corrections Read from XML axiscorr and apply the same
   
    
    
    
    tree1 = ET.parse('axiscorr.xml')
             
    axis1_corr = tree1.find('Axis1').text
    axis2_corr = tree1.find('Axis2').text
    axis3_corr = tree1.find('Axis3').text
    axis4_corr = tree1.find('Axis4').text
    axis5_corr = tree1.find('Axis5').text
    axis6_corr = tree1.find('Axis6').text
    direction = tree1.find('Direction').text

   

    
    
    if(direction=="0"):
                    axis1_corr = "-"+axis1_corr
                    axis2_corr = "-"+axis2_corr
                    axis3_corr = "-"+axis3_corr
                    axis4_corr = "-"+axis4_corr
                    axis5_corr = "-"+axis5_corr
                    axis6_corr = "-"+axis6_corr
                
                 
    
    
    
    ## Correction
    
    
    
    
    
    ##Sending XML to RSI Client
    
    reflectIPOC = '<Sen Type="ImFree"><EStr>Message from RSI Control Server - PPG !</EStr><AxisCorr A1="'+axis1_corr+'" A2="'+axis2_corr+'" A3="'+axis3_corr+'" A4="'+axis4_corr+'" A5="'+axis5_corr+'" A6="'+axis6_corr+'"><RKorr X="0.00001" Y="0.0000" Z="0.0000" A="0.0000" B="0.0000" C="0.0000" /><IPOC>'+receivedData.ipoc.getText()+'</IPOC></Sen>\n'
    print("Commandin with <IPOC>:"+receivedData.ipoc.getText()+", Axis Actual Pos: " + (axis1_act+","+axis2_act+","+axis3_act+","+axis4_act+","+axis5_act+","+axis6_act))
   
    bytesToSend = str.encode(reflectIPOC)
    UDPServerSocket.sendto(bytesToSend, address)
    
    

GUI.py : Writes Corrections to AxisCorr.xml

from tkinter import *
import xml.etree.cElementTree as ET
window = Tk()
window.title("PawankumarG.com/KUKARSIServer")
window.geometry('600x600')
delta = "0.01" # Jogging speed
axis1 = Label(window, text="Axis 1")
axis2 = Label(window, text="Axis 2")
axis3 = Label(window, text="Axis 3")
axis4 = Label(window, text="Axis 4")
axis5 = Label(window, text="Axis 5")
axis6 = Label(window, text="Axis 6")
axis1.grid(column=0, row=0)
axis2.grid(column=0, row=1)
axis3.grid(column=0, row=2)
axis4.grid(column=0, row=3)
axis5.grid(column=0, row=4)
axis6.grid(column=0, row=5)
def clicked1p():
print("axis 1 plus")
delta = txtfld.get()
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = delta
ET.SubElement(root, "Axis2").text = "0.0"
ET.SubElement(root, "Axis3").text = "0.0"
ET.SubElement(root, "Axis4").text = "0.0"
ET.SubElement(root, "Axis5").text = "0.0"
ET.SubElement(root, "Axis6").text = "0.0"
ET.SubElement(root, "Direction").text = "1"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml")
def clicked2p():
print("axis 2 plus")
delta =  txtfld.get()
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = "0.0"
ET.SubElement(root, "Axis2").text = delta
ET.SubElement(root, "Axis3").text = "0.0"
ET.SubElement(root, "Axis4").text = "0.0"
ET.SubElement(root, "Axis5").text = "0.0"
ET.SubElement(root, "Axis6").text = "0.0"
ET.SubElement(root, "Direction").text = "1"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml")
def clicked3p():
print("axis 3 plus")
delta =  txtfld.get()
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = "0.0"
ET.SubElement(root, "Axis2").text = "0.0"
ET.SubElement(root, "Axis3").text = delta
ET.SubElement(root, "Axis4").text = "0.0"
ET.SubElement(root, "Axis5").text = "0.0"
ET.SubElement(root, "Axis6").text = "0.0"
ET.SubElement(root, "Direction").text = "1"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml")
def clicked4p():
print("axis 4 plus")
delta =  txtfld.get()
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = "0.0"
ET.SubElement(root, "Axis2").text = "0.0"
ET.SubElement(root, "Axis3").text = "0.0"
ET.SubElement(root, "Axis4").text = delta
ET.SubElement(root, "Axis5").text = "0.0"
ET.SubElement(root, "Axis6").text = "0.0"
ET.SubElement(root, "Direction").text = "1"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml")    
def clicked5p():
print("axis 5 plus")
delta =  txtfld.get()
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = "0.0"
ET.SubElement(root, "Axis2").text = "0.0"
ET.SubElement(root, "Axis3").text = "0.0"
ET.SubElement(root, "Axis4").text = "0.0"
ET.SubElement(root, "Axis5").text = delta
ET.SubElement(root, "Axis6").text = "0.0"
ET.SubElement(root, "Direction").text = "1"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml")    
def clicked6p():
print("axis 6 plus")
delta =  txtfld.get()
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = "0.0"
ET.SubElement(root, "Axis2").text = "0.0"
ET.SubElement(root, "Axis3").text = "0.0"
ET.SubElement(root, "Axis4").text = "0.0"
ET.SubElement(root, "Axis5").text = "0.0"
ET.SubElement(root, "Axis6").text = delta
ET.SubElement(root, "Direction").text = "1"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml")    
###    
def clicked1n():
print("axis 1 minus")
delta =  txtfld.get()
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = delta
ET.SubElement(root, "Axis2").text = "0.0"
ET.SubElement(root, "Axis3").text = "0.0"
ET.SubElement(root, "Axis4").text = "0.0"
ET.SubElement(root, "Axis5").text = "0.0"
ET.SubElement(root, "Axis6").text = "0.0"
ET.SubElement(root, "Direction").text = "0"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml")
def clicked2n():
print("axis 2 minus")
delta =  txtfld.get()
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = "0.0"
ET.SubElement(root, "Axis2").text = delta
ET.SubElement(root, "Axis3").text = "0.0"
ET.SubElement(root, "Axis4").text = "0.0"
ET.SubElement(root, "Axis5").text = "0.0"
ET.SubElement(root, "Axis6").text = "0.0"
ET.SubElement(root, "Direction").text = "0"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml")
def clicked3n():
print("axis 3 minus")
delta =  txtfld.get()
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = "0.0"
ET.SubElement(root, "Axis2").text = "0.0"
ET.SubElement(root, "Axis3").text = delta
ET.SubElement(root, "Axis4").text = "0.0"
ET.SubElement(root, "Axis5").text = "0.0"
ET.SubElement(root, "Axis6").text = "0.0"
ET.SubElement(root, "Direction").text = "0"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml")
def clicked4n():
print("axis 4 minus")
delta =  txtfld.get()
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = "0.0"
ET.SubElement(root, "Axis2").text = "0.0"
ET.SubElement(root, "Axis3").text = "0.0"
ET.SubElement(root, "Axis4").text = delta
ET.SubElement(root, "Axis5").text = "0.0"
ET.SubElement(root, "Axis6").text = "0.0"
ET.SubElement(root, "Direction").text = "0"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml")    
def clicked5n():
print("axis 5 minus")
delta =  txtfld.get()
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = "0.0"
ET.SubElement(root, "Axis2").text = "0.0"
ET.SubElement(root, "Axis3").text = "0.0"
ET.SubElement(root, "Axis4").text = "0.0"
ET.SubElement(root, "Axis5").text = delta
ET.SubElement(root, "Axis6").text = "0.0"
ET.SubElement(root, "Direction").text = "0"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml")    
def clicked6n():
print("axis 6 minus")
delta =  txtfld.get()
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = "0.0"
ET.SubElement(root, "Axis2").text = "0.0"
ET.SubElement(root, "Axis3").text = "0.0"
ET.SubElement(root, "Axis4").text = "0.0"
ET.SubElement(root, "Axis5").text = "0.0"
ET.SubElement(root, "Axis6").text = "0.0"
ET.SubElement(root, "Direction").text = "0"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml")     
def ClickstartRobot():
print("Stoping Robot")
root = ET.Element("root")
ET.SubElement(root, "Axis1").text = "0.0"
ET.SubElement(root, "Axis2").text = "0.0"
ET.SubElement(root, "Axis3").text = "0.0"
ET.SubElement(root, "Axis4").text = "0.0"
ET.SubElement(root, "Axis5").text = "0.0"
ET.SubElement(root, "Axis6").text = "0.0"
ET.SubElement(root, "Direction").text = "0"
tree = ET.ElementTree(root)
tree.write("axiscorr.xml") 
startRobot = Button(window, text="Stop Robot Movement", command=ClickstartRobot)  
inc = Label(window, text="Stop Robot Movement")         
axis1p = Button(window, text="Positive", command=clicked1p)
axis2p = Button(window, text="Positive", command=clicked2p)
axis3p = Button(window, text="Positive", command=clicked3p)
axis4p = Button(window, text="Positive", command=clicked4p)
axis5p = Button(window, text="Positive", command=clicked5p)
axis6p = Button(window, text="Positive", command=clicked6p)
axis1n = Button(window, text="Negative", command=clicked1n)
axis2n = Button(window, text="Negative", command=clicked2n)
axis3n = Button(window, text="Negative", command=clicked3n)
axis4n = Button(window, text="Negative", command=clicked4n)
axis5n = Button(window, text="Negative", command=clicked5n)
axis6n = Button(window, text="Negative", command=clicked6n)
txtfld=Entry(window, text="This is Entry Widget", bd=5)
txtfld.insert(END, '0.001')
startRobot.grid(column=5, row=3)
txtfld.grid(column=6, row=3)
axis1p.grid(column=1, row=0)
axis2p.grid(column=1, row=1)
axis3p.grid(column=1, row=2)
axis4p.grid(column=1, row=3)
axis5p.grid(column=1, row=4)
axis6p.grid(column=1, row=5)
axis1n.grid(column=2, row=0)
axis2n.grid(column=2, row=1)
axis3n.grid(column=2, row=2)
axis4n.grid(column=2, row=3)
axis5n.grid(column=2, row=4)
axis6n.grid(column=2, row=5)
window.mainloop()

Q&A:

  1. RSI (Robot Sensor Interface) is an KUKA Optional package (Add-on on KUKA Software) which has following functions:
  2. KUKA Controller is connected to your Computer (ROS is here) with Ethernet LAN Cable.
  3. As we know ROS needs to send and receive axis position in Real Time.
  4. RSI installation enables Real Time connection between KUKA Controller and Computer with data transfer rate at 4 ms.
  5. RSI enable Soft Real Time i.e. 4 ms of data polling from ROS.
  6. Without RSI 4 ms data rate is NOT possible, as System Software has 12ms of Interpolation Time.
  7. RSI enable UDP data exchange with handshaking, Real Time Cartesian and Joint motion Correction.
  8. RSI Visual Shell allows you to create RSI Objects in Graphical Interface which is finally exported to XML files.
  9. Refer link to know how RSI interface is going to help for ROS: https://bit.ly/kukarsi
  1. KRL files are programs on KUKA Controller (On SmartHMI), mandatory to Start during initializing robot motion.
  2. Once KRL (KUKA Roboter Language) program started on controller then ROS can command robot for motion control.
  3. Point no. 2 is mandatory due to safety reasons. (BCO Run, Field Safety).
  4. KRL file create Ethernet node on KUKA Side where external ROS node will connect.
  5. KUKA RSI-Ethernet is always Client, External ROS will be Server.
  6. On running KRL file we are creating client socket on KUKA side and ROS will be Server.

From Github Community:

Question:

Hi,
Thanks for your good project. And I want to modify it to achieve position correction. I think I need to modify the files which need to be copied into controller. Could you tell me how to get these file with rsi visual? I think the kuka rsi manual doesn’t provide some useful information for this part.
One more issue, for set the controller IP, you just need to add a new ip for rsi in kuka network? Do I need some additioanl setting in HMI(like filter, mask….)?

Answer:

Hi Husheng,
Thanks for writing to me,
In order to modify your RSI files –
Step1 – Open RSI Visual Shell and from New select “Ethernet RSI”
Step 2 – Drag and Drop blocks from side pane as per your requirement like, POSCORR, POSMON and etc – Although this part is quite difficult to perform, but once you get familiar with process then its easy {write to me at [email protected] whenever you need assistance on RSI visual Shell}
Step 3: Press CTRL+S and select folder where you need rsi files to be saved. More than 1 files generated automatically.
Step 4: Transfer these files to RSI Path on KUKA controller.

And,

For setting IP for RSI —
Step1 : In SmartPAD, Minimise HMI
Step 2: Click on Windows start and select RSI Network Utility there .
Step 3: Set IP in the range of Target Computer.
Step 4: Cold start controller.

Note: No need to do any manual settings from HMI — filter mask etc

Feel free to write on [email protected] for further assistance

Thank you.

5 2 votes
Article Rating
Subscribe
Notify of
guest
4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Gerald T

Hi Thank you for publishing. Will this work as is with RSI V4? Thanks

Next Post

KUKA LBR iiwa-Joint Overlay using FRI-Monitoring and Commanding Joint Axis via KONI port

Tue Mar 24 , 2020
Refer […]

0

4
0
Would love your thoughts, please comment.x
()
x