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
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.
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()
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.
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),
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.
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…
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:
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.
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!
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…