I’m trying to send joint positions as a string via a socket connection to a python script I have. I’m having trouble sending stringified joint positions via TCP communication.
The python script receives strings, stores them in a buffer, and when the buffer is full dumps it.
Here’s a snippet of my script:
def listen_for_string(ip, port):
global last_timestamp
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((ip, port))
sock.listen(1)
print("Daemon listening on {}:{}".format(ip, port))
while True:
connection, client_address = sock.accept()
remainder = "" # Buffer to hold partial messages
try:
while True:
data = connection.recv(1024)
if not data:
break
combined = remainder + data.decode('utf-8')
parts = combined.split(']')
remainder = parts.pop()
for p in parts:
if '[' in p:
raw_values = p.split('[')[-1]
try:
joint_array = [float(x) for x in raw_values.split(',')]
current_timestamp = datetime.now()
delta_t = 0
if last_timestamp is not None:
delta_t = int((current_timestamp - last_timestamp).total_seconds() * 1000000)
last_timestamp = current_timestamp
entry = {
"delta_t": delta_t,
"joints": joint_array
}
with ring_lock:
ring_buffer.append(entry)
if len(ring_buffer) >= RING_SIZE:
threading.Thread(target=dump_to_json).start()
except ValueError:
continue
If anyone can see why my socket communication is not working, please let me know.
It does nothing at all from what I can tell: Returns false due to failure.
When I put a counter in the same loop which would increment each time the socket sent a string, the counter updated very slowly, which I believe means that the socket request blocks the thread, then times out.
My aim is to sample joint positions in the background and stream them very quickly to a python server via this socket.
Yes, I am. I run the thread, then writeChildren(), then kill the thread.
I’ve also tried just sending one string in the same way as an example I found on the forum, only to get the same result. This is how my generateScript looked then:
Start even simpler. You’ve got your python script doing quite a bit of stuff. When I hit the “nothing is working” state, it usually helps me to dial way back. For example, sending an array is a step further than I would go at this point. Can you send a single piece of text or a single number? Don’t try to parse it into something meaningful yet, just print it to the screen.
In my experience, the socket communication on the UR is fairly slow. At least when piping it back to a URCAP. That’s what the RTDE is for. For applications like yours, where you’re trying to stream joint positions to python, I see most people go the RTDE route. Which is where I would have to leave you with a wave and a “good luck” since I’ve never been able to get that working properly.
Currently I’m using and XML-RPC daemon to send the position information.
According to this page, socket communication should definitely be faster than XML, and due to the limitations of my project, I need to stick with local port communication (i.e. can’t use RTDE).
I’m using this thread to set up my socket communication.
I’ll take your advice and try scale my script back, but I don’t see what I’m doing wrong. The array parsing is straight from the above example.
I’m glad you’ve figured out your problem, but I would recommend using RTDE for monitoring things like joint angles - it requires nothing at all in your robot script as the interface is there and working anyway. The UR sample RTDE client for Python has always worked well for me; just update the recipe file to specify that you want the joint angles, and run the sample “record” script and voila you have a CSV of joint angles.
after setting up what fields I want in the record_configuration.xml file. The data is written to robot_data.csv in the examples/ directory. That can be altered by another command-line option, though. And if I were making this into a proper production script I would instead use the sample as guidance and write something more specific, but the principle is all there.
What works and doesn’t work for you? I’m not sure what you mean by “I can’t get the sampling to work”.
I’m trying to adapt the RTDE package to pull joint positions to a locally running python daemon, then send joint positions to a csv (or json) in a local /programs/…/ folder. Currently I have the default daemon implementation from the SDK examples wired up to the record.py script. I start it normally through the Java DaemonService class with no additions:
// IN THE DAEMONSERVICE CLASS
@Override
public URL getExecutable() {
try {
return new URL("file:com/Company/DaemonCapt/impl/record.py");
} catch (MalformedURLException e) {
return null;
}
}
// IN A URCAP INSTALLATION
daemonService_.startDaemon();
First of all, is this reasonable/possible? Secondly, if so, am I missing some arguments to pass in? I’ve started and stopped daemons through the installation before, so I see no reason why I shouldn’t be able to do this.
I didn’t change anything else (to do with paths as well) because I assumed the daemon would put the csv somewhere visible in the file manager, but I cannot see any csv file.
I think this is probably reasonable, though you may want to make some tweaks to it once you’ve got the fundamentals going. Do you also have the record_configuration.xml file installed with your URCap? The script relies on that file to determine what RTDE fields to request. Other than that, the default values for all the arguments are reasonable for a starting point so it should work without them and write data out to robot_data.csv in the same directory as the script. I’m not sure where the URCap puts the script, I assume you’ve found that?
If it’s not working, I would start by trying to run the script manually, as that way you will get to see any error messages more easily.