IOError in python read/write between A-Star and Raspberry Pi

Hello,

I frequently get the following IOError when calling the AStar.read_analog() method. It works for some time, anywhere from 10s to a few minutes, but eventually occurs if I let the program run long enough. It seems to be somewhat random and independent of the frequency at which I call the method (tested from 20 to 50Hz).

  File "/home/pi/git/RasPiBot202/examples/wii_remote_obstacle_avoidance.py", line 59, in <module>
rpb202.readAStar()
  File "../robot.py", line 34, in readAStar
    self.analog = self.aStar.read_analog()
  File "../astarRPB202.py", line 43, in read_analog
    return self.read_unpack(12, 12, "HHHHHH")
  File "../astarRPB202.py", line 20, in read_unpack
   byte_list.append(self.bus.read_byte(20))
IOError: [Errno 5] Input/output error

I’ve been having the issue sporadically since the beginning but it seems more frequent when I use the read_analog() method of the AStar class in parallel with the read_encoders() method I added (code in https://github.com/DrGFreeman/RasPiBot202/blob/master/astarRPB202.py).

When not calling the AStar.read_analog() method, I sometimes get a similar error when calling AStar.read_encoders():

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 763, in run
    self.__target(*self.__args, **self.__kwargs)
  File "../motioncontroller.py", line 115, in _run
    self.odometer.update()
  File "../odometer.py", line 47, in update
    countLeft, countRight = self.encoders.readCounts()
  File "../encoders.py", line 14, in readCounts
    countLeft, countRight = self.aStar.read_encoders()
  File "../astarRPB202.py", line 46, in read_encoders
    return self.read_unpack(25, 4, "hh")
  File "../astarRPB202.py", line 20, in read_unpack
    byte_list.append(self.bus.read_byte(20))
IOError: [Errno 5] Input/output error

I tried calling the AStar.read8() method in a python shell and got a similar error after a few seconds:

>>> a = astarRPB202.AStar()
>>> while True:
...     a.test_read8()
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "astarRPB202.py", line 52, in test_read8
    self.read_unpack(0, 8, 'cccccccc')
  File "astarRPB202.py", line 20, in read_unpack
    byte_list.append(self.bus.read_byte(20))
IOError: [Errno 5] Input/output error

Finally, I tried running the benchmary.py example in the pololu-rpi-slave-arduino-library and immediately got a similar error though this time the error occurred in the call to self.bus.write_i2c_block_data():

pi@raspibot202:~/tmp/pololu-rpi-slave-arduino-library/pi $ python benchmark.py 
Traceback (most recent call last):
  File "benchmark.py", line 12, in <module>
    total_time = timeit.timeit(a_star.test_write8, number=n)
  File "/usr/lib/python2.7/timeit.py", line 230, in timeit
    return Timer(stmt, setup, timer).timeit(number)
  File "/usr/lib/python2.7/timeit.py", line 195, in timeit
    timing = self.inner(it, self.timer)
  File "/usr/lib/python2.7/timeit.py", line 100, in inner
    _func()
  File "/home/pi/tmp/pololu-rpi-slave-arduino-library/pi/a_star.py", line 49, in test_write8
    self.bus.write_i2c_block_data(20, 0, [0,0,0,0,0,0,0,0])
IOError: [Errno 5] Input/output error

Any idea what could be the cause and how I could improve the situation?

Thanks in advance!

P.S. An example program where I use both the sensors (read_analog) and the encoders is here: https://github.com/DrGFreeman/RasPiBot202/blob/in_work/examples/wii_remote_obstacle_avoidance.py

Hello.

Did you increase your I2C speed to 400kHz as suggested in our tutorial? The I2C needs to be set to 400kHz, or you can insert a delay using the second template parameter to PololuRpiSlave to work around the RPi I2C clock-stretching bug. This is mentioned in comments near the top of PololuRPiSlave.h in the pololu-rpi-slave-arduino-library.

- Amanda

Hello Amanda,

Yes, I followed the steps of the turorial and changed the I2C baud rate by adding dtparam=i2c_arm_baudrate=400000 in my /boot/config.txt file.

Regarding the PololuRpiSlave template delay parameter, I modified the example sketch from the library for my encoders but did not change the line where the slave instance is created (PololuRPiSlave<struct Data,0> slave;). The delay parameter (second argument) is 0 as is suggested for a 400 KHz I2C speed in the comments in the PololuRpiSlave.h file.

Thanks again for your help!

Do you get the same error when running benchmark.py with the original AStarRPiSlaveDemo.ino? You mentioned having this issue since the beginning, but it is not clear if you were using a modified version of the example slave code.

- Amanda

Hello Amanda, thank you for the follow-up!

Although I do not remember trying benchmark.py when I first set up my A-Star, I have been having the IOError using the AStarRPiSlaveDemo.ino sketch as-is before I modified it to add the encoders.

Today I reloaded the original AStarRPiSlaveDemo.ino sketch, ran the benchmark.py script and got the same result as above.

I noticed the IOErrors I get are typically when reading the buffer whereas the benchmark.py error occurs upon writing to the buffer so I tried commenting out lines 11-15 (write test) of the benchmark.py file and was able to run the read test successfully:

pi@raspibot202:~/tmp/pololu-rpi-slave-arduino-library/pi $ python benchmark2.py 
Reads of 8 bytes: 80.5 kilobits/second

This number seems good compared to what is stated in the README of the Pololu RPi Slave Arduino Library. But I am puzzled as to why all the errors I get occur during read.

For what it’s worth, I ran a few tests in a python shell (original AStar class and AStarRPiSlaveDemo.ino sketch from the Pololu RPi Slave Arduino Library). As you can see in the attached out.txt file, I got the error twice when calling AStar.read_analog() followed by AStar.motors() but ran the same sequence a third time without error. Also interesting is the fact that I was able to “benchmark” the write operation without calling timeit in the last test (see below).

>>> for once in range(1): # To avoid delay between next two lines
        t0 = time.time()
        for i in range(500):
	    a.test_write8()
	total_time = time.time() - t0
	
>>> 8 * 500 * 8 / total_time / 1000
130.68810369539477

This result is in-line with the expected write speed of ~140 kbits/second stated in the library README.

This issue seems to be quite random; yesterday my son was running his maze solving algorithm on a large maze (~90 turns in and out) and we were trying to capture the whole sequence (~5 min) on video and, although the line following and maze solving were working perfectly, we had to start over 5 or 6 times because the robot would stop on the IOError before completing the maze. It sometimes occured quickly (< 1 min), sometimes in the last few turns :frowning: We did manage to complete it twice (video coming soon).

Still investigating…

out.txt (2.5 KB)

We tested the AStarRPiSlaveDemo sketch and benchmark.py with a new setup using Raspberry Pi 3 Model B and Raspbian Jessie and got the same error as you did. We are looking into the issue more on our end.

What version of the Raspberry Pi and Raspbian are you using?

- Amanda

Hello Amanda,

I’m running Raspbian Jessie on Raspberry Pi model 3B. I ran apt-get dist-upgrade when a new distribution became available late last November. Otherwise, I keep it up to date running apt-get update and upgrade on a regular basis (~weekly basis).

I noticed there is a new image available since a few days, I can try to run dist-upgrade again.

Again, thanks for the support!

Hello!

We have been looking into this problem and found some Raspberry Pi 3 specific issues. There are actually two problems that might be affecting you, but luckily each has an easy solution:

  1. The Pi 3 is much faster than the A+ that we initially used when developing this library. This makes write-to-read transitions much faster, exacerbating the problem described in the comments of AStar.read_unpack. Solution: add a short delay (100 us is enough) after every write.

  2. The Pi 3 performs CPU scaling, alternating between 600 and 1200 MHz depending on CPU load, and the CPU speed affects the I2C bus speed. So when you set the I2C clock to 400 kHz, it will actually run at 200 kHz most of the time! Solution: change the second template parameter to PololuRPiSlave from 0 to 5, to guarantee that clock stretching will work at the slower speed. For 100 kHz you should use a delay of 20.

I have made the changes that I think we need on a branch of our GitHub repository so you can try them out; please let me know if they help. For more reliability, I would definitely recommend some kind of error handling system, since I2C is not immune to errors.

Sorry about the trouble, and I hope this helps you and your son get the project back on track! I am very excited to see the video when you have it ready.

-Paul

Thank @paul, I’ve been running it extensively over the weekend and everything seems to be working fine so far. No more IOErrors!

Regarding error handling, I had already implemented a command to stop the robot in case of an IOError, ensuring a fail-safe system. I could look into pushing it further to have the program recover from an IOError but with a more reliable I2C communication, the benefit may not be worth the effort at this time.

Many thanks to @AmandaS and you for the great support! This modification will certainly also benefit other Pi 3 users that may be having the same issue.

1 Like

Hi,

I am hitting the same problem but none of the workarounds are helping. My setup is:

    1. Raspberry Pi 3 Model B with Raspbian Stretch Lite (updated and upgraded, I2C enabled and set to 400KHz rate)
    1. A-Star 32u4 Robot Controller SV
    1. pololu-rpi-slave-arduino-library-2.0.0.tar.gz

If I flash the 32u4 with slave sketch, and then run blink.py, it will run for a little while (usually under a minute) and then the 32u4 will reset - I hear the startup beeps again. I’ve tried various different power configurations so I don’t believe that to be an issue.

Thanks

PS - I hope it’s okay that I resurrected a 2 year old thread - I figured it was worth keeping all of the information in one place.

Hello.

I’m sorry you’re having problems getting the blink example from the Raspberry Pi slave library for Arduino to work. Can you list all the different powering methods you’ve already tried? Can you post a picture of your current setup showing how everything is connected? Do you get the same behavior if you ran a different script?

- Amanda