UniversalRobots / RTDE_Python_Client_Library

RTDE client library and examples
BSD 3-Clause "New" or "Revised" License
100 stars 35 forks source link

Times out after 10s #6

Open jason-cso opened 2 years ago

jason-cso commented 2 years ago

Seems like RTDE expects you to poll it continuously after you connect if you want fresh data. It'd be good if that was clearly called out in the docs.

If I do this:

rtde.connect()
time.sleep(11)
rtde.receive()

I get errors like received 0 bytes from Controller, probable cause: Controller has stopped or received 0 bytes from Controller. Also, I'll often get two stale messages before it notices the disconnect.

gsim-inbolt commented 2 years ago

Got the same issue here, ended up calling rtde.receive() at 500 Hz in a thread. I wonder if this is by design of the RTDE protocol or caused by a mistake in this implementation though

michal-milkowski commented 1 year ago

You're both right, after starting connection controller will send rt data, and python client is expected to read it. I'll add a line in documentation (as minimum).

michal-milkowski commented 1 year ago

I'm thinking about either adding an example with thread specifically for reading socket, or adding a method to library that clears receive buffer. Method would need to be called periodically. What would be easier to use?

jason-cso commented 1 year ago

They both sound pretty useful. Could we have both? BTW this is how I solved it. Not very elegant, but I'm not latency sensitive.

    def receive(self):
        for i in range(10):
            now = time.monotonic()
            try:
                # RTDE seems to time out after 10s, so we'll use 8s for a little margin
                if now - self.last_receive > 8.0:
                    log.info("Calling RTDE receive() 2 extra times to notice likely disconnect")
                    results = self.rtde.receive(binary=False)
                    results = self.rtde.receive(binary=False)

                results = self.rtde.receive(binary=False)
                self.last_receive = time.monotonic()
                return results
            except rtde.RTDEException as e:
                log.error("RTDE error on attempt %d: %s", i, e)
                self.rtde.disconnect()
                self._setup()

        raise Exception("Couldn't receive")
michal-milkowski commented 1 year ago

That makes a lot of sense. What would be the use case for ignoring incoming data?

jason-cso commented 1 year ago

Some things are only accessible by rtde (like the registers and joints), so I have to use it even though I don't need its realtime nature. I did consider using a thread to keep it drained, but python's global interpreter lock and making sure I got setup/teardown right dissuaded me.

gsim-inbolt commented 1 year ago

A method clearing the whole buffer would be quite interesting, but the thread fulfills a different purpose imo so as @jason-cso mentioned having both would not feel redundant. Doing it cleanly with a thread certainly takes more effort though.

sri331 commented 1 year ago

Got the same issue here, ended up calling rtde.receive() at 500 Hz in a thread. I wonder if this is by design of the RTDE protocol or caused by a mistake in this implementation though

I am trying to add a thread to handle connection lost issue but not successful ... Could you share sample code for the thread you implemented?

gsim-inbolt commented 1 year ago

Something similar to what we had would be:

def get_state():
    while not stop_event.is_set():
        state = rtde.receive()
        if state is None:
            logger.error("No data received, shutting down connection...")
            rtde.send_pause()
            rtde.disconnect()
            raise RTDEException
        if state_queue.full():
            state_queue.get_nowait()
        state_queue.put(state)
    return

robot_thread = th.Thread(target=get_state)
robot_thread.start()
tomek2311 commented 1 year ago

I am running into smiliar (but different) 10 sec timeout issue. Here is the scenario: I contenatized RTDE solution (based example provided in this repo) so that I can get access to UR states. When I run it from command line line (say: docker run --rm -dit -e ROBOT_IP="192.168.254.171" --name rtdeplugin rtdeplugin:latest) everything is fine - programs stays up. On the other hand, when I try to run it as a service (using systemd), executng same command, it runs for 10 seconds and exists, systemd starts it again (since I specified to run forever), and the process continues forrever.

Did anyone tried to run rtde controller solution as a service, and was sucessful ? Thanks, Tomasz

sri331 commented 1 year ago

Thanks gsim-inbolt . The thread is useful. I am not sure if rtde class is thread safe not resulting in race condition. I am using a thread to make the connection active but some times it is giving below issue and going to infinite loop. “Unknown package command: 0”