"9 Degrees of Freedom" IMU

About: I'm a Research Engineer at Adobe. Previously, I was a grad student at the Center for Bits and Atoms at MIT Media Lab. Before that, I worked at Instructables, writing code for the website and iOS apps and m...
More About amandaghassaei »

I'm working on a project that requires full orientation information, so I built an Inertial Measurement Unit from scratch. I really like the 9DOF IMU board that Sparkfun makes - the calibration code that comes with it is fantastic - but I wanted to redesign the board so that it could be made at a much lower price using a single-sided PCB mill. I think the electronics come out to about $20 for this project. All the code, schematics, and PCB milling files are up on github (click the cloud-shaped button to download).

Step 1: I2C Communication

All the communication between the components on this board happens through a digital language called I2C. Components connected through I2C are either masters or slaves. A master component will set the clock of the I2C communication and the slaves listen to this clock signal.

All components communicating across I2C are connected through to the same two lines - SDA and SCL; to avoid confusion, each component has a unique address where it can send or receive messages, it will ignore messages going to different addresses. The addresses for I2C components are usually set by the manufacturer, though you may be able to modify some or all of the address bits yourself (check the datasheet).

I'm using the Wire library to communicate with my hardware via I2C - this library comes automatically installed in newer releases of the Arduino IDE.

When I want to set a register on one of my sensors, I run code that looks like this:

Both of the sensors I'm using for this project have many user-defined parameters that affect operation (range of acc/mag/gyro operation, offsets, interrupts, resolution, refresh time, etc). To begin programming with I2C devices, you will have to read through the datasheet, especially the section called "Register Description", so that you know how to properly set each of these parameters on your chip.

Step 2: LSM303

The LSM303 is a 3 axis accelerometer/magnetometer that costs only $3-4 in quantities of 1.

I got the diagrams above from the datasheet of the LSM303. I used the mechanical drawings and pin layout to create a custom component in Eagle for this part. Each connection on the LSM303 has a 0.25mm pad with 0.25mm spacing in a 16 pin, 3mm package. I followed these instructions to create the component and added it to amanda.lbr. You can install amanda.lbr into your eagle environment using these directions.

One note from the datasheet I kept in mind while routing my board:

"High current in wiring and printed circuit traces can be the cause of errors in magnetic field measurements for compassing. Conductor-generated magnetic fields add to the Earth’s magnetic field creating errors in compass heading computations. Keep currents higher than 10 mA a few millimeters further away from the sensor IC."

Step 3: ITG-3200

The ITG-3200 is a 3 axis gyroscope that costs about $4-5 in quantities of 1, the same gyro used on the Sparkfun board.

I modified the ITG-3200 from the Sparkfun Eagle library to have slightly smaller pads that can be routed with a 10mil end mill and added it to amanda.lbr. The ITG-3200 has the same 0.5mm pitch that the LSM303 has. The sample wiring diagram for the chip is shown above (from the datasheet).

An important note from the datasheet:

"The exposed die pad is not required for heat sinking, and should not be soldered to the PCB since soldering to it contributes to performance changes due to package thermo - mechanical stress."

Step 4: Schematics and Board Layout in Eagle

I reworked the schematics provided from Sparkfun for their board to use the new accelerometer/magnetometer chip and changed all the resistor/capacitor sizes to more human-friendly 1206 packages. I used a few 0Ohm resistor jumpers to route the circuit in one layer. All my eagle files are included in the github repository.

You can see that there is an extra set of pin connections on the right side of the board that is not connected to the rest of the circuit. I added this to more easily mount my board on my particular project. You could omit these if you want.

Step 5: Mill PCB

I exported the board layout top layer from eagle as a black and white png at 2400 dpi. I created an image of the very small details on the board, so that I could do an extra pass of just these areas with a tiny end mill. I also created an outline layer that will allow me to cut out the border of the board and drill holes for the through hole connections. You could choose to omit those holes if you wanted to use surface mount headers. I've attached all the pngs and the photoshop document above (most recent stuff is on github).

To create my tool paths, I ran the files through the online fab modules with input format png, output format Roland MDX-20, and process mill PCB traces. I wanted to clear all the unwanted copper from my board and I had a lot of surface to cover so I put a 1/32" end mill in the Roland and changed the diameter of the tool to 0.79mm. I also set the number of offsets to -1 to completely fill the board with paths. The resulting path looked like this:

I saved the file as 9Dof32RoughCut.rml (attached).

Next I went in with a 1/64" end mill and milled out more details. This time I set the tool diameter to 0.39mm and the number of offsets to 1. Here is the resulting path:

I saved the file as 9Dof64FinishCut.rml (attached).

Next I used a 10mil end mill to get the last bit of detail This time uploaded the details.png to the fab modules, set diameter to 0.25mm and num offsets to 1, and set the speed to 2mm/s. Here is the path:

I saved this as 9DofFinish10milPass.rml (attached).

Finally I cut out the board and drilled holes for the FTDI header pins using a 1/32" end mill. I loaded the outline.png file into the fab modules and selected PCB outline under process. Here is what the path looks like:

and the Modela file is called 9Dof32Outline.rml (attached).

My finished board is shown above, it turned out great. There were some minor issues of course: there was one short circuit left over after milling that I had to remove with a razor blade, and a few of the orphaned leads to my Gyro chip popped off during milling - this shouldn't be too much of an issue. I also accidentally dug into one of my traces because I started a finishing path with the wrong x/y offset - be sure to double check these each time you run the Modela. (see images above)

Tips:

I'd definitely recommend taking your time when stepping down to very small end mills for the milling portion of this project. Try to get as much material out with the bigger bits if possible. Also make sure your bed is flat and the z-zero is set correctly across the entire dimensions of your cut. I broke a 10mil end mill on my first attempt with this board because one side was sticking up a lot in the z direction, so the end mill was digging deep into the material. I replaced the spoil board and thoroughly cleaned all the tape residue off the Modela with alcohol. I broke a second 10mil bit because I left the speed of the path at 4mm/s and tried to mill through the entire 0.1mm in one pass. Once I slowed things down I was able to get the whole job done without breaking anything (though it did take about 1.5hrs to get through all the milling for this board).

Attachments

Step 6: Populate PCB

Attaching these tiny chips onto the board is tricky, I tried a few techniques before I landed on something that worked.

First I tried solder paste. Generally, solder paste seems like a good idea with surface mount components. On my first try I laid down a line of solder paste over the tiny 0.5mm pitch leads, stuck the components down, and used a heat gun to set everything. I think this technique might work well on a professionally fabricated board, where the traces rest flush with the surface of the board. My milled board had grooves between each of the traces, and the solder paste tended to get stuck in these grooves instead of wicking toward the traces. I also had a harder time controlling the amount of solder paste on my leads, and with this type of thing, you want to use as little solder as possible.

Next I laser cut an alignment mask using mask.pdf (attached) - I thought this would help me with lining everything up for soldering. In the end, the mask didn't get me any more precision than placing the components by hand.

Here is the technique that worked for me:

First I applied a tiny bit of solder to the pads of my board - try to use as little as possible, just cover the pads with solder. Also be careful not to get any solder on the traces running under the gyro (it said in the data sheet that soldering to the underside of the chip would put mechanical strain on the device that would affect gyro readout). Then I clamped my board in a vice and slowly brought it up to temperature with the heat gun. Then, as I saw the solder begin to melt (get shiny) I slowly brought down each chip, held the heat on it for a little bit, and placed it onto the pads. I used a pair of tweezers to gently nudge the chip until it fell into alignment (this took a few tries, just keep reheating with the heat gun and applying flux until you get the alignment right).

Note - the Gyro chip should be attached with pin 1 on the bottom right corner

Here is a nice video showing approximately the same process (but do not put solder on the center pad of the gyro!):

Once everything was cool, I unclamped the vice and checked to see if my chips were soldered down. Then I checked every lead with a multimeter, looking for short circuits between adjacent pins. Double check that ground and Vcc are not connected.

Once I felt pretty sure the first two chips were down, I attached the rest of my components. I had to sub in a few through hole resistors and capacitors on my board because I couldn't find the correct surface mount components. Do not connect the solder jumper attached to the ISP header unless you are sure you want to do that. This will allow you to power your board from a 3.3V ISP programmer, but if you have a 5V ISP programmer, you will fry your chips.

Again, double check that ground and Vcc are not connected before proceeding.

Attachments

Step 7: Burn Bootloader

Power up the board using the 3.3V FTDI connector. You should see the red LED light up. If you do not see the red LED light up then you may have a problem with your 3.3V and ground connections - use a multimeter to debug this.

In order to program the board and send serial data over the FTDI connection, you'll have to burn the Arduino bootloader on the Atmega328 chip via the ISP headers.

Plug in the ISP programmer to your board (you will also need the FTDI connected for power).

Under Tools>>Programmer select your current configuration (I'm using USBTinyISP, if you are using an Arduino as an ISP programmer you will want to select Arduino as ISP)

Select Tool>>Burn Bootloader. The green LED should flash while this is happening. Eventually you will see a message that says "Done burning bootloader" and the green LED will flash about once per second.

Step 8: Test Atmega

If you were able to complete the last step, your Atmega board is probably working fine. Just to be sure, run this simple sketch:

This sketch should print out all I2C addresses on the hardware on the board. Open the Serial Monitor to see the output (Tools>Serial Monitor), be sure to set the baud rate to 57600 in the lower right corner of the Serial Monitor. The output from my board is shown above.

The accelerometer/magnetometer board is at address 30 and the gyro is at address 104.

If you don't see anything printed, or if you see strange characters printed, be sure that your baud rate is set to 57600 (lower right hand corner of the Serial Monitor, in a dropdown menu). If you see "looking for hardware..." and nothing else, the Atmega is not able to connect to your chips, check all the connections again with a multimeter. You may need to reflow the connections to your chip with a heat gun (that did the trick for me).

Step 10: Talk to Gyroscope With I2C

The following code should print out the X, Y and Z raw gyro data to the Serial Monitor. The output for my board is shown above.

Step 11: Talk to Accelerometer/Magnetometer With I2C

The following code prints raw acceleration and magnetic data for X, Y, and Z axis (first three numbers are X, Y, Z acceleration, last three are X, Y Z magnetic field). the output from my board is shown above.

Step 12: 9 DOF Firmware and Calibration

The final code for the board can be found on github (click the cloud-shaped button to download). Most of this was written by Peter Bartz for the Sparkfun IMU, I've just modified this to work with the LSM303. Open the file Arduino>>Razor_AHRS>>Razon_AHRS.ino and upload it to the board. This code takes the raw data from all the sensors, filters it, and combines it to calculate pitch, yaw, and roll. Click on the Serial Monitor to see the uncalibrated pitch, yaw, and roll (my boards output shown above).

Calibration is really important if you want this board to function optimally. Here is my uncalibrated board hooked up to a Processing sketch:

And here it is after calibration (calibration didn't make a huge difference for me, but it may for you):

The remaining calibration steps can be found on Peter Bartz tutorial here.

And by, "don't have the right to not be offended, even if. . . " actually DOES give me the right, so make up your mind. 'No smoking permitted' actually means you have the right to smoke but you can opt out.

I moved on days ago.

Sounds like you're a person that permits anyone to do anything to anyone as long as it doesn't affect you and are remiss in social consequences.

Ya know, if you but half the effort into looking at the context of the original comment,from several years ago, that you have put into throwing around outrage you'd see they were coworkers at instructibles.

And no, there is no contradiction in your not having the right to not be offended. If these negatives are hard for you then we can rephrase it: you lack the right to remain unoffended.

Sounds like your the kind of person that favors snap judgements and shakey assumptions over simple curiosity and humility.

I am a Naval Architect from the 80's era but as hobby do indulge in such electronics projects. Please help me with some advice;

I have already with me an ATSAMV71, BNO 055 Xplained Pro Bosch Gyro board and Bosch barometric sensor from ADAFRUIT and want to make a similar IMU like the one you have made out. As I see you have also used an ATMEL microcontroller so could the code you have written could be part similar for the controller on my ATSAMV71 Board ?

Could you guide me to some Kalman Routines for this IMU Project too, please.

I just want to verify this and make sure I'm not missing anything important. It looks like you simply wrote the sensor interface directly (in Sensors.ino) for the sensors you are using. You did not write a new driver, nor use an existing driver, for them. Do I have that right or not? Thanks again for an excellent 'Ible!