Showing posts with label ITG-3200. Show all posts
Showing posts with label ITG-3200. Show all posts

Saturday, October 15, 2011

Arduino, Wire, and I2C part 5: Data Analysis and Modeling

Now that I've managed to reduce noise levels in the sensors to a mostly manageable level, it's time to record some data and try and model the board. It's worth reiterating what it is I'm attempting to achieve here: a hand-held underwater metal detector. Magnetometers can be a great way to achieve this, but this particular device is measuring the strength of the magnetic field.

I'm fairly confident that linear movement of the magnetometer is not going to significantly change the sensor measurements. This is because Earth's magnetic "lines of force" don't change particularly rapidly. You would probably have to move hundreds of miles to be able to see any significant change in the magnetometer's measurements, and can you really say you've moved in a "straight line" by then? More than likely you'll have been moving in an arc relative to gravitational center of the earth, which would be even less likely to show a significant change in measurement. Therefore, I'm going to ignore ADXL measurements.

The drawing above shows the board and the axes of measurement for each device. Unfortunately, sparkfun mounted the magnetometer such that it is 90° out of phase with the other devices. This means that the positive X axis of the accelerometer and gyro is the positive Y axis of the magnetometer, and the positive Y axis of the accelerometer and gyro is the negative X axis of the magnetometer. An inconvenience, but hopefully just a minor one.

Data capture was achieved using a common spice rack. I wanted something that didn't have much, if any, metal in it, while having sufficient space to throw the entire test apparatus on. The sensor board is roughly centered (it's a little hard to see given that the tape holding it down is a similar color to the spice rack, but you can see the connector to it above the battery pack), with the power pack and the Arduino UNO, XBee shield and XBee around the edges. Data was transferred via the XBee radio to a PC running Linux. Data loss made it necessary to make the data processing software a bit more robust.

Data capture was successful, and the graph to the right is a plot of the gyro measurements. As you can see in the graph, the rotation was primarily occurring around the Z axis, which matches the diagram of the axes and the picture of the apparatus. What you can't really see very well in the graph is that the Y and X axes were also showing measurable rotation. Those measurements show the same oscillation that can be seen on the Z-axis measurements. This is always going to be the case in any real-world measurements. You're simply never going to be able to get all the axes completely lined up and the axis of rotation perfectly aligned with the Z-axis (or whichever axis you're picking as "up"). You might get a lot closer than what I achieved with some really expensive lab equipment. The Z rotation is negative, indicating that the rotation was in a counter-clockwise direction around the Z axis.

Before looking at the magnetometer data, it's time to take a quick excursion back (for me at least) to Euclid and his geometry, though for the sake of simplicity, I'm going to stick with a 2-dimensional geometry for now. When translating between polar coordinates (angle and radius) and Euclidian coordinates, the following formulae apply:
$\begin{array}{rcl}x_{1} & = & r \cos \alpha,\\y_{1} & = & r \sin \alpha.\end{array}$

where r is the radius and α is the angle. In Euclidian geometry, your axes are always orthogonal, meaning they're at angles of 90° to each other. As such, the trigonometric operations sine and cosine are also 90° out of phase with each other. This phase offset shows up clearly in the recorded data. Given that the experiment was intended to rotate the board at a reasonably constant rate around the Z axis, the X and Y magnetometer measurements will look like sinusoidal waves 90° out of phase with each other. The following two graphs demonstrate. The first graph is the actual data, while the second graph is a simulation of the data set using only cos and sin functions, which are scaled to the appropriate mean and amplitude.
Recorded Measurements
Simulated with Trig functions


The "simulation" in the second plot is of the following functions in standard form:
$\begin{array}{rcl}y_{1}(t) & = & A_{1}\cdot \cos (\omega t + \varphi ) + D_{1},\\y_{2}(t) & = & A_{2}\cdot \sin (\omega t + \varphi ) + D_{2},\\A_{1} & = & 82,\\D_{1} & = & 15.73,\\A_{2} & = & 93.5,\\D_{2} & = & -75.6,\\\omega & = & \frac{1}{4.6},\\\varphi & = & -6.\end{array}$
Note that the frequency (ω) and phase (φ) are the same for both equations. Only the amplitude (A) and center amplitude (D) are different.

One important thing to note (in fact, pretty much the whole point of this post) is that ω is almost certainly a function of the Z-measurement of the gyro. In the simplified environment of a perfect rotation about a co-axial Z axis for the two sensors, this might be expressed as:
$\omega = \gamma z_{g}$
where γ is some constant. The reason for this is that the gyro is measuring some Δα, that is, the rotation rate around a given axis. This is, in fact, the frequency ω. It only needs some scale factor applied to it to match the measurements to the model. The value of that constant scale factor can probably be derived from the data, but I probably need to take a few more sample runs at various speeds of rotation before I can feel comfortable quantifying it.

More to come...

Tuesday, September 27, 2011

Arduino, Wire, and I2C Part 3: gyro

The SEN-10724 board includes three distinct sensors on it. The linear accelerometer and magnetometer were covered in previous posts. The experience gained in working with those two sensors made it a relatively trivial matter to implement an Arduino sketch to get measurements from the 3-axis gyro.

Set-up of the IC is relatively straight-forward. The defaults are fine in most cases. Because my intent is to eventually couple the measurements from each sensor (the first being the magnetometer and gyro), I configured the data rate to be the same as the magnetometer's default. There is a single register that sets that, the sample rate divisor (SMPLRT_DIV). The datasheet provides a formula (in section 8.2) to derive the desired output rate:
Fsample=Finternal/(divider+1)
F is the frequency (sample rate) in Hz. The internal sample frequency can be either 1kHz or 8kHz. I chose an internal sample frequency of 1kHz to start with, and with the desired 15Hz output rate, that resulted in:
15Hz=1000Hz/(divider+1)
divider+1=1000Hz/15Hz
divider=65

One other piece of initialization needs to be done to take measurements, and that is to set the DLPF_FS (digital low-pass filter/full-scale) register. The "full-scale" part of the register has only one valid value, which is to set the full sale range of the gyros to ±2000°/s. The DLPF portion of the register sets the bandwidth of the filter in conjunction with the internal sample rate. For this test, I picked the value that had the most bandwidth in the 1kHz sample rate. I honestly don't understand what the low-pass filter is being used for, but that's not important right now.

I've made the Arduino sketch available. There's no self-test available, but I can get an idea as to whether the data makes any sense by picking up the board and rotating it around. It seems to work. Also, I can look at the temperature sensor measurements and do a quick sanity check.

According to the table in section 3.1, the reference point for the temperature sensor is -13200LSB=35°C, with 1°C=280LSB (i.e. each bit in the temperature measurement is 1/280°C). The measurements looked fairly stable so I just picked one at random: -15106:
(-15106+13200)/280=-6.8°C + 35°C = 28.2°C = 82.75°F
This seems a tad warm to me, but it's not completely unbelievable.

Now that I've gotten measurements (or at least test measurements) out of each device, it's time to start aggregating the data...

Monday, September 12, 2011

"9" degrees of freedom IMU on Arduino

This past weekend I finally got around to playing with the "9 degrees of freedom" sensor board (SEN-10724) I'd purchased from sparkfun.com.  I'm not sure if it makes sense to call it that, but what you get is a 3-axis gyro, a 3-axis accelerometer and a 3-axis magnetometer.  The gyros give you information about rotational acceleration, the accelerometer measures linear acceleration, and the magnetometer works like a 3-axis compass.

The circuit off to the side there shows how I managed to get it hooked up and talking through my Arduino UNO.  The short of it is this: it's a 3.3V device (well, 3 devices) and it needs pull-up resistors (I used 4.7K) on the data and clock lines in order to function.  It's wired up to the analog inputs 4 and 5 on the Arduino board, which is what the provided "Wire" library uses to talk to devices like this, that use the I2C protocol.

Honestly, I'm a little bit unclear as to how it's actually able to talk to the sensor stick/IMU (inertial measurement unit) without doing level conversion between the 5V Arduino and the 3.3V IMU, but it does seem to work reliably in this configuration.  If I were doing something more significant (a production board, for example) I'd probably be a bit more careful about matching the signal levels.

The Wire library for Arduino is just a basic library for talking to I2C devices.  Getting into the specific interfaces is another matter, though for a quick start, I used the HMC588L compass library provided by Love Electronics in the UK.  This was enough to get me started and verify that I was able to communicate with the magnetometer.  There's a pretty decent tutorial on that page on how to use the library, though the sample works pretty well as-is.  If you have trouble compiling the sample code, I found that for some reason it has a period (".") at the very beginning of the file - remove that period to make it compile.

Quick update - looking at the example .pde file in linux using hd (hex dump), it turned out there were three unprintable characters at the beginning of the file.  The easiest way I found to fix the problem was to remove any odd characters before the /* at the start of the file, then save it as a new sketch.  That new .pde file can then be used to replace the original example .pde file in the library, or you can just use the fixed version in your sketchbook.