I haven't tried to do anything with the c++ here, but I have been digging more into the python library.
I have found that pyserial (serialposix.py) is hanging on write on this line:
Code: Select all
abort, ready, _ = select.select([self.pipe_abort_write_r], [self.fd], [], None)
Per the documentation,
select.select(rlist, wlist, xlist[, timeout])
This is a straightforward interface to the Unix select() system call. The first three arguments are sequences of ‘waitable objects’: either integers representing file descriptors or objects with a parameterless method named fileno() returning such an integer:
rlist: wait until ready for reading
wlist: wait until ready for writing
xlist: wait for an “exceptional condition” (see the manual page for what your system considers such a condition)
Empty sequences are allowed, but acceptance of three empty sequences is platform-dependent. (It is known to work on Unix but not on Windows.) The optional timeout argument specifies a time-out as a floating point number in seconds. When the timeout argument is omitted the function blocks until at least one file descriptor is ready. A time-out value of zero specifies a poll and never blocks.
This blocking call can be avoided if we set a write_timeout in the Serial constructor, like this:
Code: Select all
self._port = serial.Serial(port=self.comport, baudrate=self.rate,
timeout=1,
inter_byte_timeout=self.timeout,
write_timeout=10)
I tried with a write_timout of 1 and even 10 and with both I still eventually had a timeout error (which makes sense since before it was blocking forever), but now I have no blocking beyond the timeout period and eventual error. So I just took this as an opportunity to wrap the roboclaw self._port.write() command in a while loop with a retry option to just attempt the command again. So ever so often it will timeout, reattempt write, and carry on.
This probably isn't the most elegant solution, but will have to do for me for now. I just hope there are no adverse effects from this hack.
If anyone can offer some tips to improve this, or if you want to dig more into why it's timing out, I would be glad to hear your feedback.
If you want to test this:
--add this function to roboclaw.py:
----and update all calls to
--------self._port.write(...
-----------with
--------self._port_write(...
Code: Select all
def _port_write(self, bytes, retry_count=1):
try_count = 0
while try_count <= retry_count:
try:
self._port.write(bytes)
break
except:
# We probably don't need a 10ms sleep to clear buffer
# since the timeout itself should have been enough time.
try_count += 1
--adjust this in roboclaw.py:
Code: Select all
def Open(self):
try:
# I think current roboclaw.py is setting param
# interCharTimeout instead of newer inter_byte_timeout that
# I'm using in python3, so adjust as needed.
self._port = serial.Serial(port=self.comport, baudrate=self.rate,
timeout=1,
inter_byte_timeout=self.timeout,
write_timeout=0.02)
except:
return 0
return 1