Page 3 of 3

Re: Losing communication with Roboclaw,TTL serial and Raspberry PI

Posted: Wed Sep 06, 2017 7:05 am
by gdoisy
@IMC Support: Now that the issue is confirmed by at least 2 persons, shouldn't the title of the topic be changed to something like "Linux kernel 4.10 and above breaks roboclaw python library" ?

Re: Serial Communications problem using Linux Kernel 4.10 and 4.12

Posted: Wed Sep 06, 2017 9:13 am
by Basicmicro Support
Currently we dont know if it is breaking the roboclaw library or a library the roboclaw uses(pyserial) or is a uart/CDC driver problem in Kernel 4.10 and possibly 4.12.

I've updated the subject to reflect the information we do have(eg Linux 4.10 and 4.12 are having communications problems).

Re: Serial Communications problem using Linux Kernel 4.10 and 4.12

Posted: Wed Sep 06, 2017 11:50 am
by robof
Does anyone have any idea how hard it would be to convert the arduino c++ roboclaw library to use the correct serial headers/functions to try this in Ubuntu? I've not coded much in c++ in around 10 years so not sure how feasible this is to try to compare to the pyserial library. It seems like it should be straight forward though.

Re: Serial Communications problem using Linux Kernel 4.10 and 4.12

Posted: Thu Sep 07, 2017 8:59 am
by gdoisy
I am very limited in time right now, but I am definitely interested if you start working in this direction?

Re: Serial Communications problem using Linux Kernel 4.10 and 4.12

Posted: Thu Sep 07, 2017 9:31 am
by Basicmicro Support
The arduino C++ library was rewriten a while ago to take a Software or Hardware Serial object. This means the vast majority of the C++ library is portable C++. In fact if you create a class that mimics the Serial object from arduino you would probably not need to make any changes to the Roboclaw C++ code at all.

Re: Serial Communications problem using Linux Kernel 4.10 and 4.12

Posted: Fri Sep 08, 2017 2:44 pm
by robof
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

Re: Serial Communications problem using Linux Kernel 4.10 and 4.12

Posted: Mon Sep 11, 2017 8:27 am
by gdoisy
Thanks for sharing.
I will wait a bit and if you don't report an issue with your solution i will use it. I already have several machine which updated automatically to the next kernel and it starts to be a real issue in our case.

Re: Serial Communications problem using Linux Kernel 4.10 and 4.12

Posted: Mon Sep 11, 2017 11:46 am
by Basicmicro Support
Interesting. I've never had a write timeout problem before, so we didnt implement any kind of timeout for writing(just reading) in the library. I honestly didnt think it was even possible(and it may only be possible with USB virtual serial ports). Your solution is probably at least as good as what I would implement. It will be a little while before we can update this in the roboclaw.py library but it will probably end up looking very similar. I'll have to go through the structure to see if there isnt a better option but I cant think of one off the top of my head.