Posted 20 August 2018
In my continuing quest to add relative heading sensing to Wall-E2, my autonomous wall-following robot, I have been trying to make the Inversense MPU-6050 module sold by DFRobots work on my robot.
In my last post on this topic, I had finally figured out that the program lockup problems I had been experiencing were due to a well-known-but-never-fixed bug in twi.c the low-level code associated with the Arduino I2C library. This utility program has a number of while() loops used to send and receive bytes across the I2C bus, and every one of them is prone to deadlock when the device(s) on the other end of the bus misbehaves at all. Then the while() loop never exits, and whatever program is running dies a horrible death.
The weird thing about this problem is that it has been known for at least a decade (yep – 10 years!!!), and has actually been fixed multiple times by multiple people over this period, but the fixes have never made it into the ‘official’ Arduino Wire library. This makes NO SENSE, as the Wire library code is open-source, and is available on GitHub. I thought the whole idea behind open-source code and GitHub was that others could contribute code fixes in a reliable revision-tracked way, so that when someone finds a bug, it can be fixed quickly and then propagated out to all users. Apparently the guys at Arduino never got the memo, because it is apparently next-to-impossible to get a ‘Pull Request’ containing the bug fix through the code-maintainer’s gauntlet.
Thinking this was just a logistics problem that I could solve with just a few hours of elbow grease, and would be a good training exercise for other open-source collaboration projects, I decided to take a swing at this problem myself – how hard could it be?
- I thoroughly researched the technical issues, made the changes to my local copies of Wire.cpp/h and twi.c/h, and verified that they indeed fully solved the hangup problems
- Found the releveant Arduino Wire library source tree on GitHub
- Forked the Arduino Wire library source tree to my own GitHub Account
- Cloned my fork of the Arduino Wire Library to my PC
- Made all the relevant changes to my local repo, tested the result, and pushed the changes to my GitHub repo.
- Created a ‘Pull Request’ with all the changes, with a descriptive note
By this time, I had expended a LOT of time, but that was OK as I had learned a lot that would pay off in future efforts, and besides I was finished – I thought!
Then I got a very nice email from the Arduino maintainer of the Wire library, listing all the things I had done wrong, and making it clear that the changes wouldn’t be merged into the ‘official’ Wire library until all was correct to their satisfaction. When I looked at the list of problems, I realized most of it was about ‘whitespace’ mismatches between my submission and the official version. Now, I don’t know about you, but I stopped thinking about whitespace a decade or so ago, when it became clear that whitespace was just a figment of the programmer’s mind, and had NOTHING WHATSOEVER to do with how well or poorly the code actually worked. Now I was being asked to manually correct all the literally hundreds/thousands of places where my code had 2 spaces and the ‘official’ code had 3! So, if I wanted this bugfix to get into the main distribution, I was going to have to spend a HUGE amount of time dealing with nit-picking aesthetics that have nothing whatsoever to do with anything but somebody’s misplaced idea of right and wrong with respect to whitespace, for source files that are rarely, if ever, viewed by 99% of the Arduino programming community. I mean, this would be like refusing to make a small, but important change to the maintenance manual for a car because the shop technician’t penmanship wasn’t up to par! What is penmanship going to matter when known defects aren’t corrected?
So, I thought about that some more, and I came to realize why this I2C hangup bug has been around for so long – nobody’s pull request has ever made it through the ‘penmanship contest’ gauntlet; the Arduino maintainers are more interested in penmanship than in fixing clearly defective code that has (and still is) causing grief for anyone who tries to use the I2C bus. My personal response to this problem was “screw them – I’m not going to spend all that effort just to please someone’s weird affection for whitespace, especially since my local copy of these files has already been fixed.
With just a little bit of searching, I found Steve Bian’s ‘SBWire’ library with timeouts added to all the while() loops in twi.c, and was quickly able to ascertain that Steve’s library did indeed solve my hangup problems. Moreover, Steve actually answered my emails, and is unddoubtedly much more open to open-source collaboration than the guys at Arduino.
The sad thing about all this is that Arduino is not doing themselves any favors by making themselves part of the problem rather than part of the solution. If they aren’t going to actively maintain their baseline code distribution, it (and Arduino) will become irrelevant as users find other ways around the obstacles.
25 August update:
So, I did the same thing with Shuning (Steve) Bain’s SBWire library that I had done with Arduino’s Wire library. Forked his repo, cloned it to my PC, made the small changes I wanted, pushed to my repo, and created a pull request. Two Days later, Shuning had merged my changes into the library. Now I do realize that SBWire isn’t ARduino Wire, so maybe a ‘higher standard’ might be justified for the ‘gold standard’ I2C library. However, I think we could all agree that EIGHT FRIGGIN’ YEARS of known defects is probably a bit much!
So, my advice, if you’ve been having problems with I2C hangups, is to throw the Arduino Wire library in the nearest trashcan and use Shuning’s SBWire library
26 August Update:
I have been running SBWire on a little I2C test board, and I left it running over the weekend while my wife and I were away on a trip. When I came back, some 95 hours later, the board was still running merrily. I did note that the ‘lockup counter’ (the number of times the standard Wire library code would have locked up) stood at 14, or about once every 7 hours or so. Actually I’m a bit surprised by this number, as in my personal experience the Wire library never lasted more than about 2 hours before locking up.
Just another reason to dump the Arduino Wire library and use something useful like SBWire ;-).