Universal Robots+

Read global variable through socket

Hi All,

I am trying to read global variables through either the primary or secondary port using socket connection. I understand that under the primary and secondary port, I am able to read it through message type 25, however, how should I proceed with that?

value returned from the my code does not make sense.

#!/usr/bin/env python

import socket
import string
import struct

TCP_PORT = 30001
BUFFER_SIZE = 1024

#TCP_IP = raw_input("Please enter IP address: ")
#if not TCP_IP:
#    print "No IP entered, using localhost"
#    TCP_IP = '127.0.0.1'
#data = []
while 1:
	TCP_IP = '127.0.0.1'

	# Connect to Port
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((TCP_IP, TCP_PORT))
	# Receive one package
	rcvd = s.recv(BUFFER_SIZE)
	s.close()	
	
	data = struct.unpack('!s',rcvd[25])
	print "Variable state: ", data

image

Thank you!

Your message is not enough to debug your code. In my experience, you’d better use a loop to pass “unnecessary” message or packages till you get the type 25 message and then parse the byte stream according to the client interface doc. One key note is the global variable message could be following other messages or packages, this is why I said use a loop to pass. And if your variables are too many, it can be separated by multi packages which is marked by the startindex.

HI @SonglinCai

Thank you so much for the prompt reply! I have modified my code, would like your advise to see if I am actually getting the correct data. Thank you!

packet_1_len = s.recv(4)
packet_1_len = packet_1_len.encode("hex")
y = str(packet_1_len)
y = struct.unpack('!i',packet_1_len.decode('hex'))[0]
print "Length: ", y
packet_1 = s.recv(1)
packet_1 = packet_1.encode("hex")
y = str(packet_1)
y = struct.unpack('!B',packet_1.decode('hex'))[0]
print "Content: ", y
packet_1_time = s.recv(4)
packet_1_time = packet_1_time.encode("hex")
y = str(packet_1_time)
y = struct.unpack('!i',packet_1_time.decode('hex'))[0]
print "Time: ", y
packet_1_RobCon = s.recv(1)
packet_1_RobCon = packet_1_RobCon.encode("hex")
y = str(packet_1_RobCon)
y = struct.unpack('!?',packet_1_RobCon.decode('hex'))[0]
print "RobCon: ", y
s.close()	

Following this is my output:
image

Thank you!

1 Like

Hi,

I have been trying to decipher the data that is being streamed in, however I cant seem to get the data to make sense.

Should I actually stream in the entire package of data or one package at a time?

if I were to decode it according to the scheme as shown:
image

with my following code:

overall_len = s.recv(4)
RobMessType = s.recv(1)

packet_1_len = s.recv(4)
packet_1_len = packet_1_len.encode("hex")
y = str(packet_1_len)
y = struct.unpack('!i',packet_1_len.decode('hex'))[0]
print "Length: ", y

packet_1_MessType = s.recv(1)
y = str(packet_1_MessType)
packet_1_MessType = packet_1_MessType.encode("hex")
y = str(packet_1_MessType)
y = struct.unpack('!B',packet_1_MessType.decode('hex'))[0]
print "Package Type: ", y

the result does not match the indicated output.

image

Hope to shed some light into this. Thank you!

Hi @colin.lee,

Your problem here is that you’re trying to treat the primary datastream like the realtime datastream, but the formatting is very different. While the realtime stream is formatted as a list of doubles in the same order, where you can just grab the ones you need, the primary datastream contains a number of different messages, and sub message types within those, so you need to check the message types and find the parts you need.

I appreciate that the client interface spreadsheet doesn’t explain this particularly clearly. Here’s a sample that grabs variable names and their values from the primary datastream. It’s still a bit messy but hopefully it’s enough to get you started.

#!/usr/bin/env python
# encoding: utf=8

""" 
#UR Controller Primary Client Interface Reader
# For software version 3.x
#
# Datastream info found here: http://support.universal-robots.com/Technical/PrimaryAndSecondaryClientInterface
# Struct library used to extract data, info found here: https://docs.python.org/2/library/struct.html
"""

import socket, struct

def main():

	#Establish connection to controller
	HOST = '127.0.0.1'
	PORT = 30001
	intlen = 4
	variables = {}
	varval = {}

	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
	s.connect((HOST, PORT))

	while 1:
		#Loop forever, receive 4096 bytes of data (enough to store any packet)
		data = s.recv(4096)
		if data:
			#unpack message length and message type according to Client_Interface.xlsx
			msglen =  (struct.unpack('!i', data[0:intlen]))[0]
			msgtype = (struct.unpack('!B', data[4]))[0] 
	
			#If it's a variable message
			if msgtype == 25:
			#check if it's a variable update or setup message
				robotmsgtype = (struct.unpack('!B', data[13]))[0] 
				#print 'msglen: ' + str(msglen)
				#if it's a variable setup message
				if robotmsgtype == 0:
					#skip straight to the char array containing variable names
					j=16
					#initialise variable to hold the title
					title=''
					#step through the remaining bytes in the message
					while j < msglen:
					#add the ascii character represending each byte to the title string
						title = title + chr((struct.unpack('!b', data[j]))[0])
						j=j+1
					#print title
					#each variable name ends with a newline \n, so split the string to get the individual names
					variables = title.split('\n')
					
				#if it's a variable update message			
				if robotmsgtype == 1:
					#start reading the variables from position 16 onwards
					i=16
					x=0
					#keep looping until no more variables
					while i+5<msglen:
						#extract variable type (one byte)
						vartype = (struct.unpack('!b', data[i]))[0] 
						i=i+1
						#if it's an integer value
						if vartype == 14:
							#read out the next 4 bytes (we know an int is 4 bytes)
							varval[x] = (struct.unpack('!i', data[i:i+intlen]))[0]
							#then print the result, together with the appropriate variable name
							print variables[x] + ' : ' + str(varval[x])
							#and increment the position to read the next variable
							i=i+5
							x=x+1


if __name__ == '__main__':
    import sys
    main()
3 Likes

I can get the program to run under Python 2.7. If I try to run it under Python 3.6, I get the following error::

/Users/mchollett/PycharmProjects/ur5/venv/bin/python /Users/mchollett/PycharmProjects/ur5/venv/ur5variable.py
Traceback (most recent call last):
File “/Users/mchollett/PycharmProjects/ur5/venv/ur5variable.py”, line 80, in
main()
File “/Users/mchollett/PycharmProjects/ur5/venv/ur5variable.py”, line 33, in main
msgtype = (struct.unpack(’!B’, data[4]))[0]
TypeError: a bytes-like object is required, not ‘int’

Process finished with exit code 1

Any idea on what needs to be changed to correct the syntax for Python 3 ?

Would also appreciate any help on how to set variables using Python.

Thanks,
Mark Chollett

Hi,

I am also trying to read global variable through primary client interface.

I am reading the 4th byte of package I have been receving but unfortunatly I see only number 16 (which is correct it is Robot State Messages) and 5 ( I am not able to find what it is in Client Interface file),

I am looking for number 25 but it has never come.

Could you help me what I am doing wrong?

Thanks!

I was able to take a step forward with my problem, but problems arose. I will describe everything step by step.

  1. On the robot I wrote a simple program that is always running. Of course, both variables are global.


2. In the Node-RED (Javascript) environment I have created a flow that connects to the robot via primary interface.

Problem 1: Connection to port 30001. I read byte 4 from the signal I received, unfortunately I have never received a message with the number 25. Only connecting to port 30011 results in receiving this message.

Problem 2: I wrote the next step of the program to check byte 13, unfortunately I only receive information with number 1, I never received with number 0 or 2.

Problem 3: In the robot program, variable values ​​change every 3 seconds. In my program in Node-RED, subsequent messages are very irregular. Sometimes the same message is repeated every 1 sec, sometimes it only changes after a minute.

At the moment, I am able to read (irregularly) the values ​​of global variables, unfortunately I am not able to receive their description.

Is there anybody who could help me ?

I’m not too sure if this helps, but when you read msglen; shouldn’t it be from 0 to 4 (when looking at the Python code posted by ajp) ? I also noticed that you have used the same method for signed and unsigned char. It seems like, some data are missing by looking at your problems…

1 Like

Hi thph,

Thank you for your sharp eyes :wink:

I am quite new in programming in JavaScript, so I can’t be 100% sure.

I checked diffrent types of methodes but I still received the same results in both mentioned problems.

So I tried it out but with Python code above - connecting to port 30001 where i print the mgstype in my terminal - At first I got the values:
image

where it keeps skipping between 16 and 5 but when I run the program on PolyScope:

image

I got these value for msgtype:
image

I can try to see if it is possible with JavaScript :slight_smile:

If you still have the problem - I have looked into the JavaScript code and your problem 1 and 2. Using JavaScript on port 30001 I was able to get message type 25 and get the number 1 and 0 using the check on byte 13 - notice that number 2 says Deprecated….
Here is the print:

image
Robot message type 0 is shown when reading byte 13 and it is only shown if you start the robot-program, or when you stop and then start again. If you would like to see the code just tell me and I will upload it.

@thph

You’re the best! Thank you very much for taking the time to work on my problem.

Unfortunately, apart from being the best, you are also lucky.

I did the test you suggested and unfortunately I still didn’t get 0 in byte 13.

If this is not a problem, please share your code with me, I may use the wrong methods, for example. I don’t know

I just want you to be aware that my code might use different libraries and also I run mine directly from terminal using node js
I have attached the links I’ve been using as well. The IP address is localhost… I really hope this helps!

//https://www.tutorialspoint.com/nodejs/nodejs_net_module.htm
//https://millermedeiros.github.io/mdoc/examples/node_api/doc/buffers.html#buffer.slice//

var net = require(‘net’);
var client = net.connect({port: 30001}, function() {
console.log(‘connected to server!’);
});

client.on(‘data’, function(data) {

if(data instanceof Buffer){

 var buf1msglen = data.slice(0,4);
 var buf2msgtype = data.slice(4,5);

 var msglen = buf1msglen = buf1msglen.readUInt32BE(0);
 var msgtype = buf2msgtype.readUInt8(0);

 //console.log('Message length: ' + msglen);
 console.log('Message type: ' + msgtype);


 if(msgtype === 25){
     console.log('_____________________found messagetype 25________________________--');

     var buf3robotmsgtype = data.slice(13,14);
     var robotmsgtype = buf3robotmsgtype.readUInt8(0);

     console.log('Robot message type: ' + robotmsgtype); 

 }

}

});

client.on(‘end’, function() {
console.log(‘disconnected from server’);
})

Still the same.

I copied your code, and still no 0 in byte 13.

The Robot message type 0 is only shown ONCE, when the robot program starts (pressed play button). So I had to roll to the top to see the message type 0. To get the 0 again I stop and Start the program. I’m using CB3 simulator sw. 3.10 and e-series sw. 5.4…

I did everything that you mentioned above.

I am connecting to real robot CB3 with 3.10 software.

Hi @thph,

Could you tell me please what kind of tool did you use to run this javascript code? :slight_smile:

Hello,

I used node js to run the code. :slightly_smiling_face:

1 Like

Thank you, it is work perfectly .

1 Like