1. Home
  2. Knowledge Base
  3. MODBUS registers read position

MODBUS registers read position via port 502.

Application Description:
This example shows the use of internal MODBUS registers 400-405 on the Universal-Robots to read the robot position from external device.

The application uses the MODBUS server running at port 502 on the Universal-Robots. The MODBUS server has a range of register available with dedicated content and register 128 to 255 are for general purpose use. In this example register 400 to 405 will be used because they contain the values of the robot position as

400 = TCP-x in tenth of mm (in base frame)
401 = TCP-y in tenth of mm (in base frame)
402 = TCP-z in tenth of mm (in base frame)
403 = TCP-rx in mrad (in base frame)
404 = TCP-ry in mrad (in base frame)
405 = TCP-rz in mrad (in base frame)

A list of the MODBUS and register can be found at this link UR Modbus page

The commands are send from a external host with Python code.
Function description:
The external host (PC) is connected to the UR via Ethernet and access the MODBUS registers on the UR on TCP port 502.

For the MODBUS protcol and meaning of the raw data there are more informations at this link MODBUS registers Input and Output handling via port 502.

 

Program description:
The external host reads the register 400-405 every 5 seconds and convert the raw data to readable data in mm.

(Further Below is the same program with more conversation data shown on the screen for evaluation purpose).

Program code:

No program on UR.

Host program in Python code.

# Echo client program
import socket
import time

HOST = "192.168.0.9" # The remote host
PORT_502 = 502

print "Starting Program"

count = 0
home_status = 0
program_run = 0

while (True):
 if program_run == 0:
  try:
   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   s.settimeout(10)
   s.connect((HOST, PORT_502))
   time.sleep(0.05)
   print ""
   reg_400 = ""
   s.send ("\x00\x04\x00\x00\x00\x06\x00\x03\x01\x90\x00\x01") #request data from register 128-133 (cartisian data)
   reg_400 = s.recv(1024)
   reg_400 = reg_400.replace ("\x00\x04\x00\x00\x00\x05\x00\x03\x02", "")
   reg_400 = reg_400.encode("hex") #convert the data from \x hex notation to plain hex
   if reg_400 == "":
     reg_400 = "0000"
     reg_400_i = int(reg_400,16)
   if reg_400_i < 32768:
     reg_400_f = float(reg_400_i)/10
   if reg_400_i > 32767:
     reg_400_i = 65535 - reg_400_i
     reg_400_f = float(reg_400_i)/10*-1
   print "X = ",reg_400_f

   reg_401 = ""
   s.send ("\x00\x04\x00\x00\x00\x06\x00\x03\x01\x91\x00\x01") #request data from register 128-133 (cartisian data)
   reg_401 = s.recv(1024)
   reg_401 = reg_401.replace ("\x00\x04\x00\x00\x00\x05\x00\x03\x02", "")
   reg_401 = reg_401.encode("hex") #convert the data from \x hex notation to plain hex
   if reg_401 == "":
     reg_401 = "0000"
     reg_401_i = int(reg_401,16)
   if reg_401_i < 32768:
     reg_401_f = float(reg_401_i)/10
   if reg_401_i > 32767:
     reg_401_i = 65535 - reg_401_i
     reg_401_f = float(reg_401_i)/10*-1
   print "Y = ",reg_401_f

   reg_402 = ""
   s.send ("\x00\x04\x00\x00\x00\x06\x00\x03\x01\x92\x00\x01") #request data from register 128-133 (cartisian data)
   reg_402 = s.recv(1024)
   reg_402 = reg_402.replace ("\x00\x04\x00\x00\x00\x05\x00\x03\x02", "")
   reg_402 = reg_402.encode("hex") #convert the data from \x hex notation to plain hex
   if reg_402 == "":
     reg_402 = "0000"
     reg_402_i = int(reg_402,16)
   if reg_402_i < 32768:
     reg_402_f = float(reg_402_i)/10
   if reg_402_i > 32767:
     reg_402_i = 65535 - reg_402_i
   reg_402_f = float(reg_402_i)/10*-1
   print "Z = ",reg_402_f

   reg_403 = ""
   s.send ("\x00\x04\x00\x00\x00\x06\x00\x03\x01\x93\x00\x01") #request data from register 128-133 (cartisian data)
   reg_403 = s.recv(1024)
   reg_403 = reg_403.replace ("\x00\x04\x00\x00\x00\x05\x00\x03\x02", "")
   reg_403 = reg_403.encode("hex") #convert the data from \x hex notation to plain hex
   if reg_403 == "":
     reg_403 = "0000"
     reg_403_i = int(reg_403,16)
   if reg_403_i < 32768:
     reg_403_f = float(reg_403_i)/1000
   if reg_403_i > 32767:
     reg_403_i = 65535 - reg_403_i
     reg_403_f = float(reg_403_i)/1000*-1
   print "Rx = ",reg_403_f

   reg_404 = ""
   s.send ("\x00\x04\x00\x00\x00\x06\x00\x03\x01\x94\x00\x01") #request data from register 128-133 (cartisian data)
   reg_404 = s.recv(1024)
   reg_404 = reg_404.replace ("\x00\x04\x00\x00\x00\x05\x00\x03\x02", "")
   reg_404 = reg_404.encode("hex") #convert the data from \x hex notation to plain hex
   if reg_404 == "":
     reg_404 = "0000"
     reg_404_i = int(reg_404,16)
   if reg_404_i < 32768:
     reg_404_f = float(reg_404_i)/1000
   if reg_404_i > 32767:
     reg_404_i = 65535 - reg_404_i
     reg_404_f = float(reg_404_i)/1000*-1
   print "Ry = ",reg_404_f

   reg_405 = ""
   s.send ("\x00\x04\x00\x00\x00\x06\x00\x03\x01\x95\x00\x01") #request data from register 128-133 (cartisian data)
   reg_405 = s.recv(1024)
   reg_405 = reg_405.replace ("\x00\x04\x00\x00\x00\x05\x00\x03\x02", "")
   reg_405 = reg_405.encode("hex") #convert the data from \x hex notation to plain hex
   if reg_405 == "":
     reg_405 = "0000"
     reg_405_i = int(reg_405,16)
   if reg_405_i < 32768:
     reg_405_f = float(reg_405_i)/1000
   if reg_405_i > 32767:
     reg_405_i = 65535 - reg_405_i
     reg_405_f = float(reg_405_i)/1000*-1
   print "Rz = ",reg_405_f

   time.sleep(5.00)
   home_status = 1
   program_run = 0
   s.close()
 except socket.error as socketerror:
   print("Error: ", socketerror)
print "Program finish"

Program run:

The robot is in this position – Notice the X, Y, Z, Rx, Ry, Rz values in the Move screen.

universal-robots-zacobria-modbus-read-position-1

Below is the printout on the screen with the X, Y, Z, Rx, Ry, Rz values when the Python program is executed. The values are collected from the MODBUS registers and correspond with the actual values of the robot position. The X, Y, Z are in mm and Rx, Ry, Rz are in radians.

>>>
Starting Program

X = 0.0
Y = 300.0
Z = 300.0
Rx = 0.0
Ry = 3.14
Rz = 0.0

 

Notes:
For the purpose of monitor and evaluation of the data is below the same program, but with more data printout on the screen so it can be observed how the data are converted to readable data in mm and radians.

Program code:

No program on UR.

Host program in Python code with more data printout.

# Echo client program
import socket
import time

HOST = "192.168.0.9" # The remote host
PORT_502 = 502

print "Starting Program"

count = 0
home_status = 0
program_run = 0

while (True):
 if program_run == 0:
   try:
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     s.settimeout(10)
     s.connect((HOST, PORT_502))
     time.sleep(0.05)

     print ""
     print "Request reg 400"
     print "Sending: x00 x04 x00 x00 x00 x06 x00 x03 x01 x90 x00 x01"
     reg_400 = ""
     s.send ("\x00\x04\x00\x00\x00\x06\x00\x03\x01\x90\x00\x01") #request data from register 128-133 (cartisian data)
     print "Modbus command send to read reg 400"
     print "Received"
     reg_400 = s.recv(1024)
     print repr(reg_400) #Print the receive data in \x hex notation (notice that data above 32 hex will berepresented at the ascii code e.g. 50 will show P
     print ""
     reg_400 = reg_400.replace ("\x00\x04\x00\x00\x00\x05\x00\x03\x02", "")
     reg_400 = reg_400.encode("hex") #convert the data from \x hex notation to plain hex
     if reg_400 == "":
       reg_400 = "0000"
     print reg_400
     print ""
     reg_400_i = int(reg_400,16)
     print reg_400_i
     if reg_400_i < 32768:
       reg_400_f = float(reg_400_i)/10
     if reg_400_i > 32767:
       reg_400_i = 65535 - reg_400_i
       reg_400_f = float(reg_400_i)/10*-1
     print "X = ",reg_400_f

     print ""
     print "Request reg 401"
     print "Sending: x00 x04 x00 x00 x00 x06 x00 x03 x01 x91 x00 x01"
     reg_401 = ""
     s.send ("\x00\x04\x00\x00\x00\x06\x00\x03\x01\x91\x00\x01") #request data from register 128-133 (cartisian data)
     print "Modbus command send to read reg 401"
     print "Received"
     reg_401 = s.recv(1024)
     print repr(reg_401) #Print the receive data in \x hex notation (notice that data above 32 hex will berepresented at the ascii code e.g. 50 will show P
     print ""
     reg_401 = reg_401.replace ("\x00\x04\x00\x00\x00\x05\x00\x03\x02", "")
     reg_401 = reg_401.encode("hex") #convert the data from \x hex notation to plain hex
     if reg_401 == "":
       reg_401 = "0000"
     print reg_401
     print ""
     reg_401_i = int(reg_401,16)
     print reg_401_i
     if reg_401_i < 32768:
       reg_401_f = float(reg_401_i)/10
     if reg_401_i > 32767:
       reg_401_i = 65535 - reg_401_i
       reg_401_f = float(reg_401_i)/10*-1
     print "Y = ",reg_401_f

     print ""
     print "Request reg 402"
     print "Sending: x00 x04 x00 x00 x00 x06 x00 x03 x01 x92 x00 x01"
     reg_402 = ""
     s.send ("\x00\x04\x00\x00\x00\x06\x00\x03\x01\x92\x00\x01") #request data from register 128-133 (cartisian data)
     print "Modbus command send to read reg 402"

     print "Received"
     reg_402 = s.recv(1024)
     print repr(reg_402) #Print the receive data in \x hex notation (notice that data above 32 hex will berepresented at the ascii code e.g. 50 will show P
     print ""
     reg_402 = reg_402.replace ("\x00\x04\x00\x00\x00\x05\x00\x03\x02", "")
     reg_402 = reg_402.encode("hex") #convert the data from \x hex notation to plain hex
     if reg_402 == "":
       reg_402 = "0000"
     print reg_402
     print ""
     reg_402_i = int(reg_402,16)
     print reg_402_i
     if reg_402_i < 32768:
       reg_402_f = float(reg_402_i)/10
     if reg_402_i > 32767:
     reg_402_i = 65535 - reg_402_i
     reg_402_f = float(reg_402_i)/10*-1
     print "Z = ",reg_402_f
 
     print ""
     print "Request reg 403"
     print "Sending: x00 x04 x00 x00 x00 x06 x00 x03 x01 x93 x00 x01"
     reg_403 = ""
     s.send ("\x00\x04\x00\x00\x00\x06\x00\x03\x01\x93\x00\x01") #request data from register 128-133 (cartisian data)
     print "Modbus command send to read reg 403"
     print "Received"
     reg_403 = s.recv(1024)
     print repr(reg_403) #Print the receive data in \x hex notation (notice that data above 32 hex will berepresented at the ascii code e.g. 50 will show P
     print ""
     reg_403 = reg_403.replace ("\x00\x04\x00\x00\x00\x05\x00\x03\x02", "")
     reg_403 = reg_403.encode("hex") #convert the data from \x hex notation to plain hex
     if reg_403 == "":
       reg_403 = "0000"
     print reg_403
     print ""
     reg_403_i = int(reg_403,16)
     print reg_403_i
     if reg_403_i < 32768:
       reg_403_f = float(reg_403_i)/1000
     if reg_403_i > 32767:
     reg_403_i = 65535 - reg_403_i
     reg_403_f = float(reg_403_i)/1000*-1
     print "Rx = ",reg_403_f

     print ""
     print "Request reg 404"
     print "Sending: x00 x04 x00 x00 x00 x06 x00 x03 x01 x94 x00 x01"
     reg_404 = ""
     s.send ("\x00\x04\x00\x00\x00\x06\x00\x03\x01\x94\x00\x01") #request data from register 128-133 (cartisian data)
     print "Modbus command send to read reg 404"
     print "Received"
     reg_404 = s.recv(1024)
     print repr(reg_404) #Print the receive data in \x hex notation (notice that data above 32 hex will berepresented at the ascii code e.g. 50 will show P
     print ""
     reg_404 = reg_404.replace ("\x00\x04\x00\x00\x00\x05\x00\x03\x02", "")
     reg_404 = reg_404.strip("\x00\x04\x00\x00\x00\x05\x00\x03\x02")
     reg_404 = reg_404.encode("hex") #convert the data from \x hex notation to plain hex
     if reg_404 == "":
       reg_404 = "0000"
     print reg_404
     print ""
     reg_404_i = int(reg_404,16)
     print reg_404_i
     if reg_404_i < 32768:
       reg_404_f = float(reg_404_i)/1000
     if reg_404_i > 32767:
       reg_404_i = 65535 - reg_404_i
       reg_404_f = float(reg_404_i)/1000*-1
     print "Ry = ",reg_404_f
 
     print ""
     print "Request reg 405"
     print "Sending: x00 x04 x00 x00 x00 x06 x00 x03 x01 x95 x00 x01"
     reg_405 = ""
     s.send ("\x00\x04\x00\x00\x00\x06\x00\x03\x01\x95\x00\x01") #request data from register 128-133 (cartisian data)
     print "Modbus command send to read reg 405"
     print "Received"
     reg_405 = s.recv(1024)
     print repr(reg_405) #Print the receive data in \x hex notation (notice that data above 32 hex will berepresented at the ascii code e.g. 50 will show P
     print ""
     reg_405 = reg_405.replace ("\x00\x04\x00\x00\x00\x05\x00\x03\x02", "")
     reg_405 = reg_405.strip("\x00\x04\x00\x00\x00\x05\x00\x03\x02")
     reg_405 = reg_405.encode("hex") #convert the data from \x hex notation to plain hex
     if reg_405 == "":
       reg_405 = "0000"
     print reg_405
     print ""
     reg_405_i = int(reg_405,16)
     print reg_405_i
     if reg_405_i < 32768:
       reg_405_f = float(reg_405_i)/1000
     if reg_405_i > 32767:
       reg_405_i = 65535 - reg_405_i
       reg_405_f = float(reg_405_i)/1000*-1
     print "Rz = ",reg_405_f

     time.sleep(5.00)
     home_status = 1
     program_run = 0
     s.close()
   except socket.error as socketerror:
     print("Error: ", socketerror)
print "Program finish"

 

Program run:

The robot is in this position – Notice the X, Y, Z, Rx, Ry, Rz values in the Move screen.

universal-robots-zacobria-modbus-read-position-1

Below is the printout on the screen with the X, Y, Z, Rx, Ry, Rz values when the Python program is executed. The values are collected from the MODBUS registers and correspond with the actual values of the robot position. The X, Y, Z are in mm and Rx, Ry, Rz are in radians.

>>>
Starting Program

Request reg 400
Sending: x00 x04 x00 x00 x00 x06 x00 x03 x01 x90 x00 x01
Modbus command send to read reg 400
Received
‘\x00\x04\x00\x00\x00\x05\x00\x03\x02\x00\x00’

0000

0
X = 0.0

Request reg 401
Sending: x00 x04 x00 x00 x00 x06 x00 x03 x01 x91 x00 x01
Modbus command send to read reg 401
Received
‘\x00\x04\x00\x00\x00\x05\x00\x03\x02\x0b\xb8’

0bb8

3000
Y = 300.0

Request reg 402
Sending: x00 x04 x00 x00 x00 x06 x00 x03 x01 x92 x00 x01
Modbus command send to read reg 402
Received
‘\x00\x04\x00\x00\x00\x05\x00\x03\x02\x0b\xb8’

0bb8

3000
Z = 300.0

Request reg 403
Sending: x00 x04 x00 x00 x00 x06 x00 x03 x01 x93 x00 x01
Modbus command send to read reg 403
Received
‘\x00\x04\x00\x00\x00\x05\x00\x03\x02\x00\x00’

0000

0
Rx = 0.0

Request reg 404
Sending: x00 x04 x00 x00 x00 x06 x00 x03 x01 x94 x00 x01
Modbus command send to read reg 404
Received
‘\x00\x04\x00\x00\x00\x05\x00\x03\x02\x0cD’

0c44

3140
Ry = 3.14

Request reg 405
Sending: x00 x04 x00 x00 x00 x06 x00 x03 x01 x95 x00 x01
Modbus command send to read reg 405
Received
‘\x00\x04\x00\x00\x00\x05\x00\x03\x02\x00\x00’

0000

0
Rz = 0.0

Disclaimer: While the Zacobria Pte. Ltd. believes that information and guidance provided is correct, parties must rely upon their skill and judgement when making use of them. Zacobria Pte. Ltd. assumes no liability for loss or damage caused by error or omission, whether such an error or omission is the result of negligence or any other cause. Where reference is made to legislation it is not to be considered as legal advice. Any and all such liability is disclaimed.

If you need specific advice (for example, medical, legal, financial or risk management), please seek a professional who is licensed or knowledgeable in that area.

Author:
By Zacobria Lars Skovsgaard
Accredited Universal Robots support Centre and Forum.

Also check out the CB3 forum



Was this article helpful?

12 comments

  1. Hi!

    Thank you so much for the helpful information!

    I just want to ask for your advice on a particular matter:

    Im trying to send hex commands from CodeSys via ModBus TCP,in a string format as shown in this example. However the robot didnt seem to respond as intended.

    When I sent the same string via the socket function in python, it worked.

    My suspicion is that the socket function in python converts the hex string into some data that is readable by the robot behind the scenes, that is why sending a hex string directly to the robot via CodeSys didnt work.

    Any idea of what format of this data might he? Binary? Decimal? Etc?

    Thanks!

    1. Hi Jun

      Thanks for the question.

      It is Hex format and no conversion.

      Maybe consider to make a test for what your application really send out e.g. using the Socket test as setup as server on your IP address and the port you send the data to and see what is really send out.

      Author:
      By Zacobria Lars Skovsgaard
      Accredited Universal Robots support Centre and Forum.

      Also check out the CB3 forum



  2. Hello!
    Thanks for your vital information and approaches.
    My question is that the values returned are all unsigned when I use your python code to read the joint angles via modbus server. And I referenced the information that all values restored in modbus register are unsigned, if I want to convert to signed integers, program “if (val > 32768): val = val – 65535 at https://www.universal-robots.com/how-tos-and-faqs/how-to/ur-how-tos/modbus-server-16377/.
    Because the joint angles values returned is all less than 32768, the result shows all unsigned,in other words, they’re all positive number.
    So how can I get the precious signed joint angle in accord with pendant data via modbus server? Is there any ways to solve or deal with it?

    Thanks,
    Rey

    1. Hello Rey

      Thanks for the question.

      Can you give an example of a robot pose and the returned data you read – and compared to the data you see in the pendant ?

      Author:
      By Zacobria Lars Skovsgaard
      Accredited Universal Robots support Centre and Forum.

      Also check out the CB3 forum



      1. Yeah. I used my code to get the joint angles data in hex format as follows: 0027, 10be, 0734, 183e, 07d9,1270. And I transformed these hex data to radian values that is 0.039, 4.286, 1.844, 6.206, 2.009, 4.720. However, the joint angles data on the teaching pendant is 2.22°, -114.43°, 105.66°, -4.44°, 115.09, 270.42°.
        Is there any methods to deal with the problems?Or maybe I made mistakes? Thanks for your helps in advcance.

        1. Hello Rey

          Have you tried the conversion method shown in the example at the link below ?

          Is it a UR3 or UR5 or UR10 you are working with ?

          What is the pose (not angles) X, Y, Z, Rx, Ry, Rz that you see on the pendant ?

          http://www.zacobria.com/universal-robots-knowledge-base-tech-support-forum-hints-tips/knowledge-base/modbus-registers-read-position/

          Author:
          By Zacobria Lars Skovsgaard
          Accredited Universal Robots support Centre and Forum.

          Also check out the CB3 forum



          1. Yes, I tried that before. And I’m working with UR5. Under this situation, the pose information on the teaching pendant is as follows: X = -302.664, Y= -86.017, Z= 461.780, Rx= -1.782, Ry= 0.470, Rz= 2.248.
            Meanwhile, I used MODBUS TCP to get the matlab data that was the same as the pendant data.

          2. Hello Rey

            The MODBUS TCP is not the Matlab data ?

            Which port are you connecting ? and for which situation of reading ?

            Author:
            By Zacobria Lars Skovsgaard
            Accredited Universal Robots support Centre and Forum.

            Also check out the CB3 forum



  3. Hi,

    Thank you for your information.
    Checked your information, we got a lot of help.
    We pass through your sample program and read the joint angles.
    Is there a way to read the motor rotation angle before the reducer?
    And what is stored in general purpose register 128-255?
    Thanks for your help.

    Allmight

    1. Hi Allmight

      Thanks for the question.

      1.
      I have not seen any method of reading the motor rotation.

      2.
      The general purpose registers are empty, but can be used for general purpose to store data from the user program.

      Author:
      By Zacobria Lars Skovsgaard
      Accredited Universal Robots support Centre and Forum.

      Also check out the CB3 forum



  4. Hello,

    I looked through your Client-Interfaces Cartesian Matlab Data topic and i made a C# program to get the position data. This was successful but i can only access the data once.

    I get the data on first click but when i send a movej command to the robot and it moves, the data received after that is rubbish.

    Is there a way to tell the robot to send the new set of bytes to get the new position?

    1. Hello Harsh

      Thanks for the question and thanks for contributing to the forum.

      I have not seen such function to ask the the Matlab data because the matlab data is just send as a constant stream and flow of data.

      Maybe it can be a timing issue for when to start reading the data.

      Author:
      By Zacobria Lars Skovsgaard
      Accredited Universal Robots support Centre and Forum.

      Also check out the CB3 forum



Leave a Reply

Your email address will not be published. Required fields are marked *