L3G4200D Tripple Axis Gyroscope + Arduino

Wednesday, June 15 th , 2011

Before we begin, just note, that while this all works, I believe the output is scaled wrong. The noise floor is very high. But from everything I have found it looks like this is how it is.
We have covered, accelerometers, GPSs, compasses… But no gyros. Why? Not sure, but I figured today I would put an end to that, so I grabbed a L3G4200D 3-axis gyro from sparkfun.

The L3G4200D is a 3-axis angular rate sensor, aka gyro/gyroscope with a user selectable 250, 500 or 2000º/Sec scale. I was about to write about what a gyro is, but Sparkfun has done a really great job of that, so to quote them:

Gyroscopes measure angular velocity, how fast something is spinning about an axis. If you’re trying to monitor the orientation of an object in motion, an accelerometer may not give you enough information to know exactly how it’s oriented. Unlike accelerometers gyros are not affected by gravity, so they make a great complement to each other. You’ll usually see angular velocity represented in units of rotations per minute (RPM), or degrees per second (°/s). The three axes of rotation are either referenced as x, y, and z, or roll, pitch, and yaw.

Hooking It Up

The L3G4200D has a lot of pins on it because it supports both SPI and I2C but also has some other features as well such as programmable interrupts. We are going to go as simple with this as possible.

The L3G4200D supports both SPI and I2C, but we are just going to talk I2C here. I2C is a 2-wire serial connection, so you just need to connect the SDA (Data) and SCL (Clock) lines to your Arduino for communication. On your Arduino (everything but the mega) SDA is on analog pin 4, and SCL is on analog pin 5. On an arduino mega, SDA is digital 20, and SCL is digital 21.

But other than Power, Ground, and the I2C pins, we just need to connect SD0 to 3.3v (to set the I2c Address).

Code

The code for this is a little complex mainly because it is a digital device. But I tried to simplify it as much as possible for you. You may have noticed that Sparkfun already had a code example written. Yep… And part of this code is based on that. I actually decided to write new code for 2 reasons. 1: Their code is CreativeCommons licensed. I like MIT better because you are more free to do what you need with it. 2: I like I2C better than SPI – Why? 2 less wires!

This code just outputs the x,y,z axis angular rate (in deg/sec) in the serial terminal. Simple as that.

According to the data sheet, this is all correct. But when the sensor is sitting still and is set to 2000º/sec, I am seeing readings of 0-70 on all 3 axises. I know gyros drift, but this seems weird. If someone knows what is going wrong here please let me know.

[code lang=”arduino”]
//Arduino 1.0+ only

#include

#define CTRL_REG1 0x20
#define CTRL_REG2 0x21
#define CTRL_REG3 0x22
#define CTRL_REG4 0x23
#define CTRL_REG5 0x24

int L3G4200D_Address = 105; //I2C address of the L3G4200D

int x;
int y;
int z;

void setup(){

Wire.begin();
Serial.begin(9600);

Serial.println(“starting up L3G4200D”);
setupL3G4200D(2000); // Configure L3G4200 – 250, 500 or 2000 deg/sec

delay(1500); //wait for the sensor to be ready
}

void loop(){
getGyroValues(); // This will update x, y, and z with new values

Serial.print(“X:”);
Serial.print(x);

Serial.print(” Y:”);
Serial.print(y);

Serial.print(” Z:”);
Serial.println(z);

delay(100); //Just here to slow down the serial to make it more readable
}

void getGyroValues(){

byte xMSB = readRegister(L3G4200D_Address, 0x29);
byte xLSB = readRegister(L3G4200D_Address, 0x28);
x = ((xMSB << 8) | xLSB); byte yMSB = readRegister(L3G4200D_Address, 0x2B); byte yLSB = readRegister(L3G4200D_Address, 0x2A); y = ((yMSB << 8) | yLSB); byte zMSB = readRegister(L3G4200D_Address, 0x2D); byte zLSB = readRegister(L3G4200D_Address, 0x2C); z = ((zMSB << 8) | zLSB); } int setupL3G4200D(int scale){ //From Jim Lindblom of Sparkfun's code // Enable x, y, z and turn off power down: writeRegister(L3G4200D_Address, CTRL_REG1, 0b00001111); // If you'd like to adjust/use the HPF, you can edit the line below to configure CTRL_REG2: writeRegister(L3G4200D_Address, CTRL_REG2, 0b00000000); // Configure CTRL_REG3 to generate data ready interrupt on INT2 // No interrupts used on INT1, if you'd like to configure INT1 // or INT2 otherwise, consult the datasheet: writeRegister(L3G4200D_Address, CTRL_REG3, 0b00001000); // CTRL_REG4 controls the full-scale range, among other things: if(scale == 250){ writeRegister(L3G4200D_Address, CTRL_REG4, 0b00000000); }else if(scale == 500){ writeRegister(L3G4200D_Address, CTRL_REG4, 0b00010000); }else{ writeRegister(L3G4200D_Address, CTRL_REG4, 0b00110000); } // CTRL_REG5 controls high-pass filtering of outputs, use it // if you'd like: writeRegister(L3G4200D_Address, CTRL_REG5, 0b00000000); } void writeRegister(int deviceAddress, byte address, byte val) { Wire.beginTransmission(deviceAddress); // start transmission to device Wire.write(address); // send register address Wire.write(val); // send value to write Wire.endTransmission(); // end transmission } int readRegister(int deviceAddress, byte address){ int v; Wire.beginTransmission(deviceAddress); Wire.write(address); // register to read Wire.endTransmission(); Wire.requestFrom(deviceAddress, 1); // read a byte while(!Wire.available()) { // waiting } v = Wire.read(); return v; } [/code]

Get Touchy – Nintendo DS Touch Screen + Arduino

Monday, June 13 th , 2011

It seems like touch screens are plastered on every consumer electronic device from your phone to your refrigerator. And why not right? Well, even though those beautiful multitouch hi-res screens are a little pricy and crazy hard to develop with, doesn’t mean we cant still add a touch panel to our project. The touch panel from the Nintendo DS provides a very simple, inexpensive solution to allow us to do just that.

The Nintendo DS panel is a resistive panel making it very easy to hook it up to our Arduino, but it only recognizes a single input at a time and is a little imprecise.

Hooking It Up

If you are going to use this, I highly recommend using the breakout board with it because it is a little hard soldering directly to the ribbon cable. If you are using the breakout board: The ribbon from the panel it too thin to be used with the breakout board, and it will just fall out (weird I know). To fix this I stuck 2 layers of scotch tape over the back and cut off the excess with an x-acto blade – just make sure not to cut the ribbon. The brown plastic part of the breakout-board connector pulls out so you can slide the ribbon in it (pins side up). Once you have the ribbon in, and aligned nicely, make sure to slide the connector close to lock it into place.

Now that the panel is connected to the breakout, just note… the panel is actually now upside down (again… weird). I just flipped the panel over and to right so the ribbon was just bent at a 45º angle, but you can do whatever works best for you.

If you are wondering where the +/GND & resistors are… don’t worry about it. Just connect the 4 pins into the Arduino as shown and you are ready for the code. This really is how it goes, it gets power and ground from the pins based on how the code works.

Code

This code may look a little funky at first, so just hold on. If you didn’t know, the analog pins can be used as digital pins if needed and can be written to. The pins we are using need to act as digital pins at points and analog pins at others. Some people refer to the analog pins as pins 14-19 when using them as digital pins, and the Arduino will understand that. But that always confused the crud out of me when I was new to this so I will be referring to them as A0, A1, A2 & A3 because it does the same thing, and is much less confusing. Also, on the Arduino Mega, there is a digital pin 14, making things even weirder, so this takes that into consideration as well.

If you are still confused:

If you tell your arduino to do an analogRead on pin 0, it knows to read from analog pin 0. If you tell the arduino to do a digitalWrite on pin 0 it uses digital 0. We need to do a digitalWrite on analog 0, then an analogRead on analog 0 as well. So if we just said 0 for both, the Arduino would be confused and write to the digital 0 then read from analog 0. So we are saying A0 so it knows that whether we are reading or writing to that pin, we mean analog 0.

This code will just output the coordinates in the serial terminal when you touch it. The top left should be 0,0 and should move to about 800,770 in the bottom right. I shouldn’t output anything when it is not being touched.

If it does not respond when you touch the panel, try the other side, it is a little hard to tell just by looking at it, what the sensitive side is. If you tried both sides and it still does not respond, try repositioning the ribbon cable in the connector and try again.

[code lang=”arduino”]

int y1 = A0;
int x2 = A1;
int y2 = A2;
int x1 = A3;

void setup() {
Serial.begin(9600);
}

int readX(){
pinMode(y1, INPUT);
pinMode(x2, OUTPUT);
pinMode(y2, INPUT);
pinMode(x1, OUTPUT);

digitalWrite(x2, LOW);
digitalWrite(x1, HIGH);

delay(5); //pause to allow lines to power up

return analogRead(y1);
}

int readY(){

pinMode(y1, OUTPUT);
pinMode(x2, INPUT);
pinMode(y2, OUTPUT);
pinMode(x1, INPUT);

digitalWrite(y1, LOW);
digitalWrite(y2, HIGH);

delay(5); //pause to allow lines to power up

return analogRead(x2);
}

void loop()
{
int x = readX();
int y = readY();

if(x < 1000 & y < 1000){ Serial.print("x: "); Serial.print(x-100); Serial.print(" - y: "); Serial.println(y- 130); } delay(100); //just to slow this down so it is earier to read in the terminal - Remove if wanted } [/code]

Getting Data From The Web – Arduino + Ethernet

Friday, June 10 th , 2011

Yesterday we covered how you would go about controlling pins of your arduino over the internet using the Arduino Ethernet Shield set up as a server. Today we are going to take a look at using the shield as a client to get information off of a web page, and report back. I used this method a few months ago when I made the Nixie Twitter follower counter dubbed Twixie.

The ethernet shield can be used to access any non-password protected site with ease, but getting the information back to you is the hard part. For Twixie I created a special php page that queried the twitter API and displayed only the twitter count. This made it so I didn’t have to tell the arduino what to look for, or scour endless lines of HTML looking for a single number. For our example im going simplier. I created a PHP file that just outputs a random alphanumeric string. I did this because getting everyone setup with an API account somewhere is beyond the scope of this article, and unneeded to prove the concept and get you started. But, the idea is that you could easily take that PHP file (any web accessible file) and taylor it to display whatever you need.

In the client mode, the ethernet shield is able to access a webpage and return what is read. But the reading is done one byte at a time, and it reads the entire thing. So it can be like a needle in a haystack on large pages. Even if the page we are reading contains only the information we need, there is extra information at the beginning that is sent to the arduino. You never see it, but a web server actually sends extra information know as a “header” that tells the browser various information about that page (this is different than HTML’s tag).

Because of this, we need a way to tell the arduino what is junk, and what is the good stuff. To do this we are going to surround the information in < >. When the Arduino starts to read the page we tell it to ignore everything until it sees “<". From this point on we tell the arduino to record each following character until it sees our ending character ">“. At this point the arduino has everything it needs, and disconnects from the server then reports back with the data it found.

The Ethernet Shield library does not come with DNS support out of the box meaning we can not simply access the website we need by its simple URL (like http://arduino.cc). No, sadly, we need to have access the site through an IP address. For instance, bildr’s IP address is 174.123.231.247 and you can actually access bildr like so http://174.123.231.247/~bildr/ – Not every web-server allows you to do this, but when you can it is typically IPADDRESS/~ACCOUNT_USERNAME – So you can see the PHP file I created for you here http://174.123.231.247/~bildr/examples/ethernet/

Code

Without an extra library, the ethernet code does not support DHCP and therefore requires that we hardcode the IP Address, gateway address, and subnet mask for your network. This isn’t really that hard, it is more of a pain when especially if you want to plug it into a different network as the same settings may not work.

If you are familiar with your network and how to do this, awesome, just make sure you change the setting at the top of the code to fit your network. If you are not familiar with it, we can help you in the forum, and have posted some general help in there as well.

As of Arduino 1.0, DHCP is supported, so this should be able to just plug into most networks and start working.

NOW 1.0 COMPATIBLE
[code lang=”arduino”]
//ARDUINO 1.0+ ONLY
//ARDUINO 1.0+ ONLY
#include
#include

////////////////////////////////////////////////////////////////////////
//CONFIGURE
////////////////////////////////////////////////////////////////////////
byte server[] = { 174,123,231,247 }; //ip Address of the server you will connect to

//The location to go to on the server
//make sure to keep HTTP/1.0 at the end, this is telling it what type of file it is
String location = “/~bildr/examples/ethernet/ HTTP/1.0”;

// if need to change the MAC address (Very Rare)
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
////////////////////////////////////////////////////////////////////////

EthernetClient client;

char inString[32]; // string for incoming serial data
int stringPos = 0; // string index counter
boolean startRead = false; // is reading?

void setup(){
Ethernet.begin(mac);
Serial.begin(9600);
}

void loop(){
String pageValue = connectAndRead(); //connect to the server and read the output

Serial.println(pageValue); //print out the findings.

delay(5000); //wait 5 seconds before connecting again
}

String connectAndRead(){
//connect to the server

Serial.println(“connecting…”);

//port 80 is typical of a www page
if (client.connect(server, 80)) {
Serial.println(“connected”);
client.print(“GET “);
client.println(location);
client.println();

//Connected – Read the page
return readPage(); //go and read the output

}else{
return “connection failed”;
}

}

String readPage(){
//read the page, and capture & return everything between ‘<' and '>‘

stringPos = 0;
memset( &inString, 0, 32 ); //clear inString memory

while(true){

if (client.available()) {
char c = client.read();

if (c == ‘<' ) { //'<' is our begining character startRead = true; //Ready to start reading the part }else if(startRead){ if(c != '>‘){ //’>’ is our ending character
inString[stringPos] = c;
stringPos ++;
}else{
//got what we need here! We can disconnect now
startRead = false;
client.stop();
client.flush();
Serial.println(“disconnecting.”);
return inString;

}

}
}

}

}

[/code]

The example php file. This just creates a random alpha-numberic string like <1Hc2f>

[code lang=”php”]

//So if the output was <1kjhghk5> – the arduino would read 1kjhghk5

//Just generates a random alphanumeric string
$what_the_arduino_reads = ‘1’.base_convert(rand(10000,9999999), 10, 36);

echo ‘<'.$what_the_arduino_reads.'>‘;
?>
[/code]

« Older Entries
Newer Entries »