An I2C Mystery Solved? Seeing Through The Docker Container Wall

When I added an INA219 Voltage/Current sensor to GoPi5Go-Dave, I discovered the sensor needed multi-process I2C protection. I created an “EasyINA219” class that used the Dexter Industries I2C mutex.

Next up was to create a ROS “Battery node” that uses the EasyINA219 class to publish battery information periodically for other nodes that need to make decisions based on the remaining battery level or the charging/discharging status.

The ROS Battery node lives inside a Docker container but some of my non-ROS programs that live outside the Docker container also access the INA219 sensor (my docking test program, battery status script, and others.) I mapped the Raspberry PiOS I2C bus to the Ubuntu I2C bus inside the Docker container to allow the EasyINA219 class inside the container to communicate with the INA219 sensor hardware attached to the Raspberry Pi PiOS I2C bus.

About a month ago, I hit a snag as I was translating my docking test program into a ROS program, where testing the ROS battery node inside the container would mess up the docking test program outside the container, even though both were using the same “mutex protected” EasyINA219 class. I decided to take a break from working in ROS with no idea why my INA219 class was not working as designed.

Also about a month ago, @jimrh asked about using a mutex on his GoPiGo3 robot to protect SPI access. We worked out how the Dexter Industries mutex could be used for his applications.

Only today, a light popped on! The EasyINA219 class was accessing its mutex in the Raspberry PiOS /var/lock/ folder but the Docker container has a totally separate Ubuntu /var/lock/ folder! I need to map that folder so that the EasyINA219 class inside the container can see if any Raspberry PiOS processes have locked the I2C bus, and vice versa.

I need to test the mutex between the two environments, and if the mapping works I can restart my ROS battery node and continue porting my pure Python docking test program into a ROS 2 docking test node.

I think the mystery has been solved.

2 Likes

Glad I could, (inadvertently), help.

2 Likes

It is true - in fact the test programs I wrote in that exercise show that my inside and outside mutexes are properly adjudicating access now with the /var/lock/ mapping:

Everytime the inside Docker releases, the “waiting” outside Docker gets it.
Everytime the outside Docker releases, the “waiting” inside Docker gets it.

Now, I’m wondering about inside and outside SPI bus communication to the GoPiGo3 red board. DI invested a bunch to make an I2C mutex, but they didn’t make an SPI mutex for some reason.

2 Likes

Uh,oh… 3 SPI read errors in 200,000 gopigo.get_voltage_battery() calls across the SPI bus.

The official GoPiGo3 class is written to “eat” No SPI Response errors and continue on normally.
The write routines do not have any SPI error detection coded.

GOPIGO3 SPI BUS ERROR TEST

Two programs are launched:

  • spitest.py checks gopigo3.get_voltage_battery() every 0.001 seconds
  • spitest2.py checks gopigo3.get_voltage_battery() every 0.0013 seconds
  • use special instrumented spi_gopigo3.py that counts “No SPI RESPONSE” errors in spi_read_8(), spi_read_16(), and spi_read32()
    get_voltage_battery() uses spi_read_16()

Results

  • Test 1 with spitest2.py in ROS2/Ubuntu22 Docker container, spitest.py in PiOS Bookworm:
    21 SPI errors reported in 800,000 voltage checks between the two processes.
  • Test 2 with both spitest.py and spitest2.py in PiOS Bookworm
    29 SPI errors reported in 820,000 voltage checks between the two processes.
2 Likes