Author Archives: paynterf

Integrating Time, Memory, and Heading Capability, Part V

Posted 10 August 2018

Well, it appears I spoke too soon about having solved the I2C hangup problem on my Wall-E2 wall-following robot.  In my last post on this subject, I described all the troubleshooting efforts I employed to nail down the cause of intermittent hangups when trying to use the MPU6050 6DOF IMU on the robot, along with several other I2C devices (a Teensy 3.5 used for IR homing, and Adafruit RTC, and FRAM modules).

After (I thought) figuring out that the I2C SCL/SDA line lengths were the root problem of the hangups I had been experiencing, my grandson Danny and I spent some quality time reworking Wall-E2’s layout to accommodate shorter line lengths.  Instead of mounting the IMU and it’s companion sensors on the second deck as before, we 3D printed a small plastic plate to attach to one of the hexagonal 2nd deck standoff posts and provide a 1st deck mounting area for the sensors.  The previous and new mounting locations are shown below:

2nd deck mounting location. The MPU6050 is the module with the illuminated blue LED toward the rear of the robot

1st deck mounting location for I2C sensors (lower right-hand corner of the photo). The Teensy 3.5 IR homing module is shown mounted on the IR detector housing (above the red plastic plate)

Unfortunately, as I was doing some final tests on this setup, I started experiencing hangups again.  After a day or so moping and some very choice words, I started all over again trying to figure out what happened.

On previous searches through the i-verse, I had run across several posts indicating that the Arduino Wire library had some basic problems with I2C bus edge conditions; there were several places where it uses several blocking ‘while()’ loops to transmit and receive data on the I2C bus, and there was no way to recover from a ‘while()’ loop where the exit condition was never satisfied.   After literally exhausting all the other possibilities, it was becoming apparent that this must be what was happening – the MPU6050 must occasionally fail to respond correctly to a I2C transaction, causing the associated ‘while()’ loop to never exit.

So, I started looking for solutions to this problem.  Again, I found some posts where folks had modified the low-level I2C bus handling code found in twi.c/.h, the code underlying the Android Wire class.  I found a post by ‘unaie’ (http://forum.arduino.cc/index.php/topic,19624.0.html) with the same complaint, but he also posted modified versions of twi.c and twi.h that solved these problems by forcing the ‘while()’ loops to exit after a set number of iterations, and resetting the I2C bus when this happens.  His modified versions can be downloaded at:

http://liken.otsoa.net/pub/ntwi/twi.h

http://liken.otsoa.net/pub/ntwi/twi.c

I downloaded these files and tried to replace the ‘stock’ twi.c/h with the modified versions. Unfortunately, unaie’s modifications were made on a quite old version of the files, and conflicted with the later ‘repeated start’ versions of these files that are in the current ‘wire’ library.

So, I did a ‘diff’ between the ‘repeated start’ version and unaie’s version, and created a modified version of the latest ‘repeated start’ twi.c/h.  In addition, I added a couple of functions to allow monitoring of the number of times a bus reset was required due to a ‘while()’ loop timeout.  When I was finished, I ran the sensor for over 24 hours with no failures, but in that time there were three instances where a ‘while()’ loop timed out and a I2C bus reset was required.  A small snippet of this run is shown below.  The blue line is the yaw value, and the plot snippet shows where I manually rotated the sensor just after 24 hours, and the horizontal orange line shows the number of bus resets.

Small snippet of 24-hour sensor run. blue line is reported yaw value; orange shows the I2C bus reset counter

So it is clear that, absent the lockup recovery modifications, the I2C bus would have locked up long before, and that with the modifications ‘while()’ loop deadlocks have been successfully handled.

11 August 2018 Update:

The sensor is still going strong after 44 hours with no hangups, and the reset counter is still holding at 3.

The complete twi.c & twi.h codes are included below:

 

Stay tuned!

Frank

 

Integrating Time, Memory, and Heading Capability, Part IV

Posted 07/26/18,

In my last post on this subject, I described my efforts to troubleshoot an intermittent ‘bad data’ problem I experienced with the Inversense MPU6050/DMP breakout board from DFRobots.  The calculated yaw value would occasionally ‘lose synch with reality’ and start varying wildly.  I finally tracked this down to occasional bad reads from the DMP FIFO; the read would extract bytes from two different packets, producing an invalid yaw value.  The fix for this problem is to monitor the FIFO ‘bytes remaining’ count and reset the FIFO whenever the ‘bytes remaining’ count is not an integral multiple of the packet size.

After demonstrating that I could run the MPU6050 for days (literally) without any bad data occurrences, I thought I was home free in my effort to provide relative heading information for precise turns, but I ran into yet another problem when I tried to integrate the MPU6050 back onto the robot.  This time the problem was a hangup problem; after some tens of minutes, the program would stop responding at all – as if it had gone into an infinite loop somewhere (which is exactly what was happening, but I’m getting ahead of myself…).

This problem turned out to be a ‘simple’ I2C wire-length issue; I was able to demonstrate that the problem would occur any time the I2C ICL/SDA wire length went beyond about 42 cm, and would not occur with wire lengths below about 30 cm.  The problem did not appear to be sensitive to I2C bus speed (at least not for the default 100KHz or for a reduced clock speed of 50KHz) or pullup resistor value – just to wire length.

The rest of this post is a copy of my troubleshooting notes from the effort to track this problem down and solve it.  I have found in the past that when facing a non-trivial problem with multiple possible causal factors, a troubleshooting journal is an absolute must.  In the pre-computer days (you do remember there was a time before ubiquitous computing don’t you?), I used a real MIT engineering notebook for this purpose, and then later on a 3-ring binder into which I added quadrille-ruled sheets covered with my notes and drawings.  Then I moved on to Word documents – nicer because I could include Excel plots, Visio drawings, photos, and other mixed media.  Now that I have graduated to a WordPress blog, I can use it as a repository of my working notes, while also allowing others to see the inner workings of a mad scientist’s mind ;-).

I2C Hangup problem with Inversense MPU6050

Stay tuned,

Frank

 

Integrating Time, Memory, and Heading Capability, Part III

Posted 12 July 2018

In the last installment of this particular saga, I described another chapter in my ongoing effort to add heading knowledge to Wall-E2’s (my autonomous wall-following robot) super powers.  In that post, I described my attempt to utilize the Inversense IMU 6050 6DOF breakout board from DFRobots.  I posted some results that showed problems with vibration screwing up the results, and then getting error-free results using an ‘air pillow’ (a piece of air-filled packing material).  At the time, this led me to believe that the cause of the bad data was motor vibration.  However, when I tried adding some foam vibration dampening material, it didn’t seem to help – I was still getting intermittent stretches of bad data, with or without the motors running.  Clearly I still didn’t understand what was happening.

Once again I ran away from the whole thing, to regroup and let my mind work on the problem for a while; back to basketball, bridge, and general goofing off.

After some more web research and just thinking about what I knew and didn’t know, I started to suspect that what I was seeing was an artifact of the way the sensor(s) communicated with the main controller via the I2C serial interface.  When yaw measurements went bad, they went really bad, rapidly cycling from positive to negative values, and this didn’t make a lot of sense.  Maybe the main controller wasn’t keeping up with the sensor data stream, and  the software was trying to form heading values using bits from two different measurements; this would explain why the heading sign changed from measurement to measurement.  Also, I wasn’t utilizing the INT pin on the IMU6050 module, just pulling data out of the FIFO as rapidly as possible; could that be part of the problem too?

So, I decided to start all over again with the IMU6050 sensor on an ASP plugboard, with a spare Arduino Mega 2560 controller identical to the one being used to run Wall-E2, as shown in the following photo.  I also hooked up the INT pin, and used Jeff Rowberg’s I2CDev materials and MPU6050 example programs as the starting point.

DFRobots Inversense IMU6050 breakout board (board with blue LED, between FRAM and RTC) on an ASP plugboard, controlled by an Arduino Mega 2560

After getting everything going, I ran some long-term tests to see I could produce ‘bad’ yaw readings independent of the robot platform.  And, of course, I couldn’t get the darned thing to fail, no matter how long I ran it.  Shown below is a 20-minute long plot

20-minute run with no observed problems

Next, I tried inserting some delays into the ‘do other stuff’ part of the main loop, to try and simulate the normal robot processing delays.  This had no effect up until the delay reached 40mSec or so, and then I started to see problems very similar to what I had seen before with both the MPU9250 and 6050 sensor setups.

On robot test displaying yaw value and bytes remaining in MPU6050 FIFO

Then I modified the code again to check for FIFO byte lengths that weren’t an integral multiple of the normal packet length (42 in this case), and to reset the FIFO if the condition was detected. This seemed to eliminate the ‘bad data’ effect, regardless of the amount of delay introduced in the processing portion of loop().

About 6 minutes with the motors running. Program modified to reset the FIFO whenever a non-modulo ‘bytes remaining’ condition was detected

Detail view of the last 100 seconds of the previous plot

Summary:

The Invensense MPU6050/DMP/FIFO combination is sensitive to delays in the main  processing loop, even when using the INT line with an Interrupt Service Routine (ISR).  When the main loop processing delays get beyond about 40mSec, the ‘mpu.getFIFOBytes(fifoBuffer, packetSize);’ call will occasionally not remove the correct number of bytes from the FIFO, leaving a non-modulo (packetsize) number of bytes remaining in the FIFO.  When this happens, the next read will get (and process) bytes from two different packets, resulting in wildly varying yaw value outputs.  This condition is (now, after knowing what’s going on) fairly easy to recognize, as the error condition generally causes adjacent yaw values to have different signs, resulting in a classic sawtooth output.

The way to eliminate this artifact is to check for non-modulo (packetsize) FIFO bytes remaining value each time, and reset the FIFO when this happens.  Whatever good data is still in the FIFO will be lost, but the data that you do get will be valid.

I have included below my test program, with the FIFO modulo check and FIFO reset mechanism.  Note that this program also includes my motor control code, which obviously will not work with your setup.

 

Stay tuned,

Frank

 

 

 

 

Dawes Lightning 1500 Stem Bracket

Posted 13 June 2018

A friend got a new Dawes Lightning 1500 bike, and wants to install a ‘Swing Grip’ handle accessory on the piece (the ‘stem’) that connects the front fork post to the handlebars.  I had printed up a similar bracket for Ray in the past, and so he asked if I could do one for this bike too.

I had him bring the bike over so I could get a good look at the ‘stem’ shape and then built up a prototype in ABS.  I had a lot of difficulty with getting the ABS to print without lifting off the heated bed, and so eventually had to use a raft, which sucked because the raft stuck to the part too well.  When I got the part done I tried it on the bike, and of course it didn’t fit, but it did allow me to see where the design had to be changed.

Printing Notes:

I printed the PLA part with

layer height:  0.2mm

extruder temp: 205 for layer 1, 195 for 3 & up

print bed temp: 70C

speed: 30mm/sec

Z-offset: -0.05mm

I had to work a bit to get the PLA to stick to the bed, and the right combination was the above settings, plus attention to getting the bed levelled properly and the correct Z-axis offset so the first layer was ‘squished’ significantly.

 

 

Integrating Time, Memory, and Heading Capability, Part II

Posted 06 June 2018

About a month ago in early May I started another try at adding time, memory, and heading super-powers to Wall-E2’s repertoire.  In this post, I described the effort to add a FRAM board, an RTC board, and a 9DOF MPU9050 IMU board to Wall-E2’s already-existing I2C bus, and in this post I described fabricating a permanent ‘tri-sensor board’ for installation on Wall-E2’s second deck.

After installing the tri-sensor board on the second deck, I did some tests to confirm Wall-E2’s new found ability to make accurate turns, and instead of confirming success, I witnessed complete failure – Wall-E2 was even worse at making turns now than in the past when he was just doing timed turns – WTF!!

Backing up and doing some more tests, it quickly became apparent that the MPU9050 IMU worked fine until Wall-E2’s wheel motors started running, but went completely ga-ga after that.  I tried some quick tests to try and isolate the problem, but didn’t get anywhere.  So, I did what I always do when faced with an apparently intractable problem – I ran away ;-).  OK, I didn’t really run away, but I decided to put the whole thing on the back burner for a while and let my subconscious work on it for a while (I have discovered over and over again that my subconscious is a lot smarter than I am).  In the meantime I  had some other stuff to do, like going to a duplicate bridge tournament and going to a grand-daughter’s HS graduation.

After doing some web research, I began to suspect that the problem might be associated with the complexity associated with the Sparkfun 9DOF MPU9050 chip and the associated yaw/pitch/roll computation software, so I decided to see if there were other IMU solutions out there.  I ran across the DFRobots MPU-6050 6DOF IMU breakout board.

Since I wasn’t planning to use this for anything but yaw (z-axis rotation) information, the 6DOF limitation wasn’t a problem, and the integrated Digital Motion Processor™ (DMP) should simplify the control software.  In addition, the IMU6050 board is 5V compatible, so I can eliminate the level-shifting hardware required for the Sparkfun 9250 unit.  So, I ordered a couple of units and started playing with them.  Using the supplied libraries from DFRobots and their little example program,  I was able to get the unit up and running fairly quickly.  To test the ability to report yaw excursions, I modified the test program to report only yaw, and manually turned the sensor around its Z-axis.  As shown below, the yaw progressed smoothly.

Manually turned sensor while recording yaw

Next, I mounted just the IMU6050 board on the robot’s 2nd deck, as shown below, and ran some tests with and without the motor running.

MPU6050 mounted on robot with double-sided tape

Sensor mounted on robot with double-sided tape, no motors running

As shown above, with the sensor mounted on the 2nd deck and with motors not running, I got a smooth response from the yaw sensor as the robot was manually rotated.  However, when I tried the same trick with the motors running, I got the following plot:

Sensor mounted on robot with double-sided tape, left rear motor running

Then I mounted the sensor on an ‘air pillow’ (one section of a piece of air-filled packing material) and tried again, once again getting a smooth plot, even with one motor running.

MPU 6050 mounted on robot with an ‘air pillow’ (piece of some air-filled packing material)

6050 sensor mounted on air pillow, left rear wheel motor running

 

Integrating Time, Memory, and Heading Capability

Posted 06 May 2018

For the last two months I have been working on adding some secondary, but still important capabilities to Wall-E2, my wall-following autonomous robot.  As I noted back in April, Wall-E2 still can’t tell which way he is heading, which (among other problems) means he can’t make accurate turns.  In addition, Wall-E2 can’t tell how long (or even if) he has been turned off, making it impossible to tell how long it has been since he last was charged.

In the intervening months, I have been able to obtain and test individual modules to address the above issues; the Sparkfun MPU9250 9DOF IMU breakout board to obtain heading information, and the combination of an Adafruit MB85RC256V FRAM breakout board and an Adafruit DS3221 RTC breakout board to capture the date/time of any power interruptions.

Since all three of the above breakout boards are I2C-capable, it should be feasible to run all three from a single I2C bus on Wall-E2’s main controller – an Arduino Mega 2560.  Unfortunately, the Sparkfun MPU9250 module isn’t 5V tolerant, so integrating all three isn’t as simple as just daisy-chaining them all together.  Back to Google for some more research, where I eventually uncovered Philips Application Note AN97055 by Herman Schutte of The Netherlands dealing with bidirectional level-shifters for just this problem. Turns out that Philips introduced the I2C bus back in 1980, so they may know a thing or two about the issues ;-).  In any case, this 1997 paper described a 2-MOSFET bidirectional level-shifter that completely addresses the issue, and seemed to be pretty straightforward to implement.  It took me a couple of tries, but I got it working, with the result that I can now run all three modules (RTC, FRAM and IMU) from an Arduino Mega 2560, with the level-shifting MOSFET’s placed between the IMU and the rest of the circuit, as shown in the photo below.

All three sensors operating a the same time, controlled over a single I2C channel.

In the above photo, the modules are (from left to right): Adafruit MB85RC256K FRAM breakout, Adafruit DS3231 RTC breakout, and Sparkfun MPU9250 9DOF IMU breakout.  The two 2N7000 level-shifter MOSFETs can be seen at the top left-hand corner of the Sparkfun IMU breakout board.

I put together a small test program, combining pieces from the software used to test the power-down date/time capture idea, and the software used to test the ability to use the Sparkfun IMU to accurately manage rotations.  This program doesn’t do much at all, but it does demonstrate that all three modules can be controlled at the same time over a single I2C channel, as shown in the following output.

As shown in the above output, all three modules are initialized, and then the program enters a loop where the current time is displayed from the RTC, and the current IMU heading is displayed from the IMU.  Then every 10 times through the loop, a new value is written to the FRAM until the first 20 or so locations have been written. Then the program starts ‘un-writing’ the values until all the written locations have been cleared, at which point the cycle starts all over again.

So, now that I have conclusively demonstrated the ability to add (relative) heading and FRAM-based non-volatile power-cycle date/time recording to Wall-E2, the next trick will be to actually mount the modules on the robot.  This will entail solving yet another set of problems, as it turns out (naturally) that although I have plenty of room on Wall-E2’s second deck, I have run out of available pins on the inter-deck connector.  This could be addressed by putting the modules somewhere on the first deck, but finding that ‘somewhere’ is going to be a real trick.  Time for either a second inter-deck connector, or to replace the current 8-pin model with a larger one.

10 May 2018 Update:

After verifying the proper operation of all three modules one one of my new high-quality ASP protoboards, I transferred everything to a permanent perfboard rendition more suitable for mounting on Wall-E2’s second deck, as shown below

Stay tuned!

Frank

 

 

Another try at heading information for Wall-E2

Posted 24 April 2018

A little over two years ago I started a project to give Wall-E2 ‘a sense of direction‘ by integrating a Mongoose 9DOF IMU board onto the robot chassis.  I worked on the idea for about six months before I finally determined that the magnetometer idea was not going to work in my indoor environment, as there was just too much magnetic interference due to indoor wiring, air handling motors, and the like.

However, it recently occurred to me that although the absolute magnetic heading problem was  intractable, I might be able to use one of the newer single-board IMU products (like the Sparkfun 9250) to generate relative heading information, which I could use to solve a different problem.  Wall-E2 occasionally needs to perform sharp turns, on the order of 90º, either as part of what I call an ‘open room step turn’ (like what happens when Wall-E2 exits a hallway into an open room, and needs to turn 90º in one direction or the other to continue wall-following), or as part of an evasion maneuver or as part of a recovery from a stuck condition.  In my ‘field’ testing to date I have noticed that Wall-E2’s effective turn rate varies considerably depending on the surface condition; very slow on shag carpeting, OK on tightly-woven rugs, and very fast on hard flooring.  This means that my current strategy of timed turns only works OK on the medium surfaces, but sucks the big weenie on the other two types.  So, if I had even relative heading information, I could use it to make sure Wall-E2’s 90º turns are actually 90º, as opposed to 45º or 180º.

It turns out there are a lot of single-board IMU solutions out there new, probably due to the wildly popular quad-copter market; they all need attitude-control (AHRS) module of some kind to make them flyable, and those modules need to be small and lightweight.  The one I started playing with first is the Sparkfun MPU-9250 breakout board, with 3-axis accelerometer, gyro, and magnetometer capability in a really small package for an incredibly cheap price.  And, as a bonus, there is a lot of good Arduino/Teensyduino software out there to help us mere mortals run the thing.  In particular, Kris Winer (of Pesky Products fame) has done a lot of work with sensor fusion software for the Arduino and Teensy line, and actively supports both his products and his software.

So, I got a board from Sparkfun and started playing around with it.  The first problem I ran into is that the MPU9250 is a 3.3V board, so I couldn’t run it from an Arduino without either potentially frying the board or having to implement a bidirectional level shifter. So, I grabbed a Teensy 3.2 from my stash and used it instead.  This, in turn, required some judicious sifting through the available software to find the Teensy 3.x compatible versions, but I eventually got that accomplished and started collecting data.

As usual, there were a lot of mis-steps along the way.  The biggest obstacle was figuring out how to avoid using the magnetometer data; almost all the software, including the all-important Madgwick quaternion routine for converting raw sensor data into yaw/pitch/roll values assumes the use of magnetometer data to obtain geo-magnetically referenced heading and to minimize/eliminate gyro drift.  In my case, I specifically wanted to decouple heading calculations from magnetometer input, as I already knew the magnetic environment in my house was too variable for reliable measurements.  With some guidance from Kris, I eventually found a 6DOF (3D rate gyro and 3D accelerometer) version of the Madgwick routine.

Once I started getting reliable yaw (heading) measurements from the sensor, I decided to modify my Teensy-based stepper motor rotary table measurement system to rotate the sensor in a uniform way to obtain constant-rate heading scan data.  The basic idea of the rotary table system is to rotate the unit under test X degrees, then stop, take some measurements, and then repeat.  So, I got it all set up, and got the following plot.

This data made no sense at all – for a full 360º rotation I should have rec