Tagged: ADXL345 RSS

  • Rutger 14:06 on 6 December, 2010 Permalink | Reply
    Tags: , ADXL345, , C, , , , software,   

    ADXL345 and ITG-3200: The Software Side 

    Connecting all the sensors required to create our IMU (Ineartial Measurement Unit) is one thing, but the next and equally important step is writing the software. Since we had quite a few headaches about this and there are not that many instructions on how to do this floating around, we thought it was worth another tutorial.

    Both the ADXL345 and the ITG-3200 are digital I2C devices, which is awesome, since it gives you a lot of features and the Arduino support is pretty good. The basics are the same for each I2C device. Every device has an address and a few registers on the chip which you can access with help from the send and receive methods from the Arduino Wire library. Sounds easy enough, but there are a few quirks that are not that obvious at first.

    Firstly, you want to include the Wire library header at the top of your code, like this

    #include "Wire.h"

    Writing to a register

    I'll start off with the definition of a simple write method, that writes a single byte to a register. Don't forget to call the Wire.begin() method in your setup().

    void write(byte device, byte register, byte value) {
     
        // Setup transmission
        Wire.beginTransmission(device);
     
        // Write value to register at address
        Wire.send(register);
        Wire.send(value);
        Wire.endTransmission();
    }

    Looks simple enough, right? What we're doing here is setting up a transmission to the device at the specified address. You'll have to look this address up in the manual of your sensor. For the ADXL345, this is 0x53 when the SDO pin is tied to ground and 0x1D when the SDO pin is tied to the voltage input (you could potentially use this for avoiding device address conflicts). For the ITG-3200 this address is 0x69. When that is set up, we send two bytes to the address. First one is the register we want to write to, the second one the value we want to write there. After that we end the transmission.

    A 'problem' here is that a lot of devices use a single 1-byte register for multiple settings and/or data. For example, in the 0x16 register of the ITG-3200 bit 4 and 3 are used for configuring the FS_SEL (the 'full-scale range' of the gyroscope, according to the datasheet), and bit 2, 1 and 0 are used to configure the DLPF_CFG ('digital low pass filter configuration') value. Bit 7 through 5 are unused.

    How to use this notation method? It's actually quite simple: say you want to write value 3 (2000 degrees per second) to the FS_SEL, and 0 to the DLPG_CFG (256Hz low pass filter bandwidth and 8kHz internal sample rate). Now just fill in registers in binary, like this:

    Unused FS_SEL DLPG_CFG
    0 0 0 1 1 0 0 0

    Now simply convert that big number back to normal decimals (or hex, if you prefer), which would give you 24 or 0x18 in this case. This is the value you want to write to the register.

    Reading from one or multiple registers

    The read method is little bigger, mostly because this will allow you to read multiple registers at once. This is quite a cost saver since we're going to be mostly reading multiple registers at a time.

    void read(byte device, byte fromAddress, int num, byte result[]) {
     
        // Set which byte we're going to read
        Wire.beginTransmission(device);
        Wire.send(fromAddress);
        Wire.endTransmission();
     
        // Request byte, and receive when available
        Wire.requestFrom((int)device, num);
        int i = 0;
        while(Wire.available()) {
            result[i] = Wire.receive();
            i++;
        }
    }

    The parameters may require some explanation. We're going to be reading num registers, starting at the fromAddress register. The result byte array will be where the results end up in (oh really? yes, really!). The reason this is in the parameters instead of as a return value is, of course, because of C limitations.

    We start off the same as with the write method, beginning a transmission and sending what register we want to read from. It gets a bit confusing after this, because reading bytes is handled in a different way than writing, which I still think is kind of weird and confusing, although they'll (probably/hopefully) have their reasons ;) We end the transmission, which ends the sending data part. We then have to indicate how many registers/bytes we are going to be reading. After that, we use a busy wait (ew!) to wait for the data to be delivered to us.

    Getting useful readings

    There are again some complications. Both the ADXL345 and the ITG-3200 store their sensor readings in 2 registers, because of how big the numbers can get. Those readings can be combined into integers like this:

    esult[0] = (((int)result[0]) << 8 ) | result[1];

    This might look a bit complicated, but it's actually quite simple once you know the meaning of the operators. The operators used here are so-called bitwise operators, which don't act on the number the bits represent, but on the collection of bits itself. x << y shifts all the bits from x y positions to the left. In this case, it creates a space of 8 zeros on the right of the result of the first register. The | operator is an OR operator, so it can be used to combine the already bitshifted first result with the second result. Like this:

    (10101010 << 8 ) | 01010101
    1010101000000000 | 01010101
    1010101001010101

    One thing to remember is that sequence in which the registers are supposed to be read isn't exactly standardized. The above example is from the ITG-3200, while the ADXL345 wants it the other way around.

    Now that we have this, we can write functions for both the ADXL345 and the ITG-3200 for reading the 3 axis results from both sensors:

    void getGyroscopeReadings(int result[]) {
     
        // Buffer
        byte buffer[6];
     
        // Read from device
        read(0x69,0x1D,6,buffer);
     
        // Convert to integers
        result[0] = (((int)buffer[0]) << 8 ) | buffer[1];
        result[1] = (((int)buffer[2]) << 8 ) | buffer[3];
        result[2] = (((int)buffer[4]) << 8 ) | buffer[5];
    } 
     
    void getAccelerometerReadings(int result[]) { 	 	
     
        // Buffer
        byte buffer[6]; 	 	
     
        // Read from device
        read(0x53,0x32,6,buffer);
     
        // Convert to integers
        result[0] = (((int)buffer[1]) << 8 ) | buffer[0];
        result[1] = (((int)buffer[3]) << 8 ) | buffer[2];
        result[2] = (((int)buffer[5]) << 8 ) | buffer[4]
    }

    As you can see, the code is mostly the same, although the conversion to integers is reversed. The buffers to be read can be found in the data sheet for each sensor.

    And that concludes this small article, I hope to post some more articles of this nature in the near future :)

    
     
  • Rutger 21:14 on 26 October, 2010 Permalink | Reply
    Tags: , ADXL345, , hardware, , ,   

    Connecting the ADXL345 accelerometer and ITG-3200 gyroscope 

    Since we finally got the sensors (the ADXL345 accelerometer and the ITG-3200 gyroscope) and the software for reading them working correctly last week, we thought we'd take the time out to write a few tutorials on how to accomplish this yourself, hopefully without making all the small mistakes we made ;)

    The ADXL345 and the ITG-3200 are just chips. You can buy them bare-bone and solder everything yourself, but it saves you a lot of hassle to just buy breakout boards that have them pre-soldered on, so you just have to solder on some breakout-pins. We bought ours at SparkFun, since their support and the documentation available is pretty good. Here's a picture of our accelerometer and gyroscope breakout boards with breakout-pins soldered on:

    I2C

    Both these sensors support the I2C protocol, which is awesome since the Arduino has great support for this. Both also have the option of using the SPI protocol, which is harder to use, but allegedly a little faster. Since we're going for a pretty simple setup here, we're going to use the I2C protocol.

    A great plus with using I2C is that it grants you the ability to connect as much devices as you want to your microprocessor with just two wires. You don't have to worry about preventing conflicts, since the protocol will take care of that. The actual mechanics of how this works on the inside are completely hidden when you use Arduino's Wire library, so we won't delve any deeper into that.

    Connecting

    To find out where all pins need to be connected to, you will mostly need to use the datasheets that accompany the devices, although most are easy to guess. SCL (Serial Clock Signal) and SDA (Serial Data Signal) are typically for I2C communication. When using the Wire library, SCL goes to the Analog 5 pin and SDA goes to the Analog 4 pin. VCC/VDD and GND are also pretty easy: these connect to the voltage input and ground of your power supply. INT is used for interrupts, so the exact function will depend on the device. We won't be using these in this setup.

    Some pins aren't that self-explanatory. The ADXL345 has an additional SDO (Serial Data Output) and CS port. The CS port is either tied to the voltage input if you want to use I2C, or tied to the microprocessor if you want to use SPI. The SDO port is used as data output when using the SPI protocol, or used as a way to choose an alternative address space when using I2C (more on that later). Since we are going to use I2C, CS is going to be connected to the voltage input, and we should tie SDO to ground.

    The ITG-3200 has an additional CLK (Clock) and VIO (Logic voltage) pin. The CLK pin can be used to connect an external clock crystal to the gyroscope. We're not going to use that here, so it can just be tied to ground to use the internal oscillator. The VIO pin can be used to set a different voltage level for the I2C communication, instead of using the same voltage as the power supply. It's a cool feature, but we just want it to be the same as the power supply (as explained in the next section), so it can just be connected to the voltage input.

    There's one final hurdle to take before we can start looking at the software: a lot of Arduino boards run on 5V, while these (and a lot of other) sensors use 3.3V.  If you have a 3.3V Arduino board (like some versions of the Arduino Pro), you won't have any troubles of course, but the rest of us needs a better solution. There are two problems to take care of: powering the sensors, and communicating with the sensors. Most Arduino boards have a separate 3.3V output pin, so the first problem is pretty easy to solve for most people. If your board does not have a dedicated 3.3V pin, there are a few things you can do. First option is to just connect two simple AA batteries (which output 3V, which in most cases will be enough) and use them as your power supply. The second, and probably better option, is to make sure the 5V output from your Arduino can be converted to 3.3V via a separate power supply. You can either buy one pre-built, or just make your own. I will not go in further detail about this, so I will just assume you have some way to output 3.3V.

    The second problem is the conversion of the logic levels for I2C communication. Again, you will need some kind of converter. And again, these can either be bought pre-built, or you can build your own. We bought one on SparkFun, since they are quite cheap ($2), and to save ourselves the hassle.  The documentation on these was actually quite vague, but once you get the idea they're very simple to use.

    This particular logic level converter has three sections: two channels and one power supply, meaning that you can connect two wires to this thing: just right for what we want. All three sections have an LV (Low Voltage) and HV (High Voltage) side. Also, every channel has a TX and RX pin. The TX pins are bi-directional, which is perfect for our purpose, since I2C needs two-way communication. So, you just connect one TX on the LV side to both SCL pins of the sensors, the other TX on the LV side to both SDA's, and the TX'es on the other side to the A4 and A5 pin on the Arduino, as mentioned above. Next, you just hook up the power supply HV and LV to their respective voltage inputs and grounds.

    Other remarks

    If you look at the datasheets of both the ADXL345 and the ITG-3200, they suggest that you use pull-up resistors on the SDA and SCL pins. Normally, these are used to to make sure the analog signal is stable (in this case, pulled up to logic level), and are actually required by the I2C protocol. Adding them here though causes some funky problems (which we ourself ran into), because as it turns out, the ATMEGA chip the Arduino uses has it's own internal pull-up resistors, which are disabled by default but can be activated by software. The Wire library does this for you by default, so you're only going to make things worse by adding your own ;)

    Seeing how this thing is getting kinda long, we'll post the follow-up about how to configure the sensors and access their readings later on :)

     
    • Terica 15:57 on 27 October, 2010 Permalink | Reply

      Hey :D Is it alright that I go a bit off topic? I’m trying to read your post on my new iPhone but it doesn’t display properly, any suggestions? Thank you for the help I hope! Terica x :)

    • Israel 19:48 on 4 November, 2010 Permalink | Reply

      hey do you know how to get the angle with the gyroscope, because i am using the same gyroscope but i only can get the rate in º/s, and to obtaing the angle i try to multiply it for a time but it doesn’t work.

      • Rutger 02:44 on 9 November, 2010 Permalink | Reply

        Hey Israel,

        Gyroscopes only measure the rate of change, not the actual angle. If you want to know the actual angle you will have to use an accelerometer, since it can measure the change in gravity. Biggest problem is that accelerometers are pretty sensitive to small disturbances, so to get a real solid reading on tilting, you have to use or create an IMU (Inertial Measurement Unit), which combines data from a gyroscope and an accelerometer using some nifty math. I will make a post on it in a while (since we are building that part right now), but you can already find a pretty good explanation over here: http://www.instructables.com/id/Accelerometer-Gyro-Tutorial/

        Good luck!

        • Israel 22:37 on 16 November, 2010 Permalink | Reply

          Thanks for the links they were very useful, i found a method that give me the angle i use numerical analysis, the Runge–Kutta method RK4 and with this i can get the angle, multiplying de rate by a time and then use this method for the result, but there it’s an error that makes the angle increase constantly but i think that with a kalman filter can be solved so i hope this would be of use for your project too.

          • Rutger 11:28 on 20 November, 2010 Permalink | Reply

            Yeah, Kalman filters are a nice and relatively simple way to reliably calculate the angle. We actually use a simplified version of that in our current implementation :)

    • jack 20:45 on 29 October, 2011 Permalink | Reply

      what do we do when we wanna get scaled data rather than raw data?
      in other way how do we convert the raw into scaled?

c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
esc
cancel