Arduino 2D Level
This is a project for Arduino to make a 2D Level, aimed at beginners.
Arduino draws a circle on an LED Matrix that moves around according to readings from a 2D Accelerometer.
Objectives:
* Learn how to draw a circle using simple Maths
* Learn how to use the LOL shield for the Arduino
* Learn how an accelerometer works
Arduino draws a circle on an LED Matrix that moves around according to readings from a 2D Accelerometer.
Objectives:
* Learn how to draw a circle using simple Maths
* Learn how to use the LOL shield for the Arduino
* Learn how an accelerometer works
What You Need
You will need:
* Arduino UNO
* LOL shield (http://jimmieprodgers.com/kits/lolshield/)
* Accelerometer (http://www.oomlout.co.uk/accelerometer-3axis-adxl335-p-247.html)
* Breadboard for wiring up e.g. (http://www.oomlout.co.uk/prototyping-bundle-for-arduino-ardp-p-186.html)
* Some Wires
* Arduino UNO
* LOL shield (http://jimmieprodgers.com/kits/lolshield/)
* Accelerometer (http://www.oomlout.co.uk/accelerometer-3axis-adxl335-p-247.html)
* Breadboard for wiring up e.g. (http://www.oomlout.co.uk/prototyping-bundle-for-arduino-ardp-p-186.html)
* Some Wires
Wire It Up
Attach the LOL shield to the Arduino.
Wire the Accelerometer as follows:
+3V
GND
X => A0
Y => A1
Z => N/C (Not Connected)
Note: The LOL shield does not come with Headers (as shown in the picture), attached to the topside.
I bought some here: http://www.amazon.co.uk/gp/product/B004RASBVY/ref=oh_details_o06_s00_i00
Wire the Accelerometer as follows:
+3V
GND
X => A0
Y => A1
Z => N/C (Not Connected)
Note: The LOL shield does not come with Headers (as shown in the picture), attached to the topside.
I bought some here: http://www.amazon.co.uk/gp/product/B004RASBVY/ref=oh_details_o06_s00_i00
Install the LOL Shield Libraries
Install the Arduino libraries for the LOL shield if you don't have them already.
You can get the link to them from this page:
http://jimmieprodgers.com/kits/lolshield/
You can get the link to them from this page:
http://jimmieprodgers.com/kits/lolshield/
Let's Start With a Circle
We'll start by drawing a circle.
This circle will eventually move around as we tilt the device. But first things first....
We'll illuminate individual pixels on the LOL shield using the LOL library command:
LedSign::Set(x, y , 1);
where x and y are the coordinates on the shield of the LED we wish to illuminate
Our job is to figure out how to calculate the x,y values that make a circle.
In Pseudo code we do it like this to draw just one quarter (Quadrant) of the circle:
for x = 0 to RADIUS
y=f(x); // This means y is some function of x. We haven't said what function yet
plot(x,y)
end
So what's the function?
r^2 = x^2 + y^2
where x^2 means "x squared" or "x to the power of 2"
We know x because it's the for loop iterator;
We know r because it's the radius,
So we re-arrange to find y
y = sqrt(r^2 - x^2) // sqrt() means square-root
When you code it up you get a circle as shown in the picture.
This circle will eventually move around as we tilt the device. But first things first....
We'll illuminate individual pixels on the LOL shield using the LOL library command:
LedSign::Set(x, y , 1);
where x and y are the coordinates on the shield of the LED we wish to illuminate
Our job is to figure out how to calculate the x,y values that make a circle.
In Pseudo code we do it like this to draw just one quarter (Quadrant) of the circle:
for x = 0 to RADIUS
y=f(x); // This means y is some function of x. We haven't said what function yet
plot(x,y)
end
So what's the function?
r^2 = x^2 + y^2
where x^2 means "x squared" or "x to the power of 2"
We know x because it's the for loop iterator;
We know r because it's the radius,
So we re-arrange to find y
y = sqrt(r^2 - x^2) // sqrt() means square-root
When you code it up you get a circle as shown in the picture.
Here's the Code
Here's the Arduino code to draw the circle.
Notice that the circle is drawn in 4 quadrants. We illuminate 4 LEDs for each y we calculate.
The pictures show the steps to draw the circle as x iterates from 0 to RADIUS
#include <Charliplexing.h>
// Circle: radius, inital and max x/y values
int radius = 3;
int cx = 6; // x-position of circle
int cy = 4; // y-position of circle
void setup()
{
Serial.begin(9600);
LedSign::Init();
}
void loop()
{
DrawCircle(1); // DRAW the circle
}
void DrawCircle(int ink)
// ink =0 : ERASE the circle
// ink =1 : DRAW the circle
{
for(int x = 0; x <= radius; x++) // x values from 0 to RADIUS (one Quadrant)
{
// solve r^2 = x^2 + y^2 for y
float y = sqrt(pow(radius, 2) - pow(x, 2));
y = round(y*1);
// Fill the y-position in the 4 quadrants of the circle
LedSign::Set(x + cx, y + cy, ink); // Quadrant 1
LedSign::Set(x + cx, cy - y, ink); // Quadrant 4
LedSign::Set(cx - x, y + cy, ink); // Quadrant 2
LedSign::Set(cx - x, cy - y, ink); // Quadrant 3
}
}
Notice that the circle is drawn in 4 quadrants. We illuminate 4 LEDs for each y we calculate.
The pictures show the steps to draw the circle as x iterates from 0 to RADIUS
#include <Charliplexing.h>
// Circle: radius, inital and max x/y values
int radius = 3;
int cx = 6; // x-position of circle
int cy = 4; // y-position of circle
void setup()
{
Serial.begin(9600);
LedSign::Init();
}
void loop()
{
DrawCircle(1); // DRAW the circle
}
void DrawCircle(int ink)
// ink =0 : ERASE the circle
// ink =1 : DRAW the circle
{
for(int x = 0; x <= radius; x++) // x values from 0 to RADIUS (one Quadrant)
{
// solve r^2 = x^2 + y^2 for y
float y = sqrt(pow(radius, 2) - pow(x, 2));
y = round(y*1);
// Fill the y-position in the 4 quadrants of the circle
LedSign::Set(x + cx, y + cy, ink); // Quadrant 1
LedSign::Set(x + cx, cy - y, ink); // Quadrant 4
LedSign::Set(cx - x, y + cy, ink); // Quadrant 2
LedSign::Set(cx - x, cy - y, ink); // Quadrant 3
}
}
Move the Circle by Tilting
Now we add the code to move the x,y position from the accelerometer readings.
As the accelerometer is tilted on its x any y axes its readings change.
The program first calibrates by measuring the at-rest readings of the accelerometer.
// Calibrate x and y values from Accelerometer
xAve = 0;
yAve = 0;
for (int i=0; i<8; i++) {
xAve = xAve + analogRead(A0);
yAve = yAve + analogRead(A1);
}
// Average x,y values correspond to "level"
xAve = xAve/8;
yAve = yAve/8;
}
Any deviation form these values is considered to be a tilt of the sensor.
// Calculate the Tilt away from "level"
// and draw the circle there
cx = cx0 + (xAve - analogRead(A0))/5;
cy = cy0 + (-yAve + analogRead(A1))/5;
The circle is drawn with centre at cx, cy:
DrawCircle(1); // DRAW the new circle
As the accelerometer is tilted on its x any y axes its readings change.
The program first calibrates by measuring the at-rest readings of the accelerometer.
// Calibrate x and y values from Accelerometer
xAve = 0;
yAve = 0;
for (int i=0; i<8; i++) {
xAve = xAve + analogRead(A0);
yAve = yAve + analogRead(A1);
}
// Average x,y values correspond to "level"
xAve = xAve/8;
yAve = yAve/8;
}
Any deviation form these values is considered to be a tilt of the sensor.
// Calculate the Tilt away from "level"
// and draw the circle there
cx = cx0 + (xAve - analogRead(A0))/5;
cy = cy0 + (-yAve + analogRead(A1))/5;
The circle is drawn with centre at cx, cy:
DrawCircle(1); // DRAW the new circle
Here's the Full Code
#include <Charliplexing.h>
// Circle: radius, inital and max x/y values
int radius = 2;
int cx0 = 6;
int cy0 = 4;
int cxMax = 13 - radius;
int cyMax = 8 - radius;
int cx, cy, xAve, yAve;
void setup()
{
Serial.begin(9600);
LedSign::Init();
// Calibrate x and y values from Accelerometer
xAve = 0;
yAve = 0;
for (int i=0; i<8; i++) {
xAve = xAve + analogRead(A0);
yAve = yAve + analogRead(A1);
}
// Average x,y values correspond to "level"
xAve = xAve/8;
yAve = yAve/8;
}
void loop()
{
DrawCircle(0); // ERASE the previous circle
// Calculate the Tilt away from "level"
// and draw the circle there
cx = cx0 + (xAve - analogRead(A0))/5;
cy = cy0 + (-yAve + analogRead(A1))/5;
if (cx > cxMax) cx = cxMax;
else if (cx < radius) cx = radius;
if (cy > cyMax) cy = cyMax;
else if (cy < radius) cy = radius;
DrawCircle(1); // DRAW the new circle
delay(100);
}
void DrawCircle(int ink)
// ink =0 : ERASE the circle
// ink =1 : DRAW the circle
{
for(int x = 0; x <= radius; x++) // x values from 0 to RADIUS (one Quadrant)
{
// solve r^2 = x^2 + y^2 for y
float y = sqrt(pow(radius, 2) - pow(x, 2));
y = round(y*1);
// Fill the y-position in the 4 quadrants of the circle
LedSign::Set(x + cx, y + cy, ink); // Quadrant 1
LedSign::Set(x + cx, cy - y, ink); // Quadrant 4
LedSign::Set(cx - x, y + cy, ink); // Quadrant 2
LedSign::Set(cx - x, cy - y, ink); // Quadrant 3
}
}
// Circle: radius, inital and max x/y values
int radius = 2;
int cx0 = 6;
int cy0 = 4;
int cxMax = 13 - radius;
int cyMax = 8 - radius;
int cx, cy, xAve, yAve;
void setup()
{
Serial.begin(9600);
LedSign::Init();
// Calibrate x and y values from Accelerometer
xAve = 0;
yAve = 0;
for (int i=0; i<8; i++) {
xAve = xAve + analogRead(A0);
yAve = yAve + analogRead(A1);
}
// Average x,y values correspond to "level"
xAve = xAve/8;
yAve = yAve/8;
}
void loop()
{
DrawCircle(0); // ERASE the previous circle
// Calculate the Tilt away from "level"
// and draw the circle there
cx = cx0 + (xAve - analogRead(A0))/5;
cy = cy0 + (-yAve + analogRead(A1))/5;
if (cx > cxMax) cx = cxMax;
else if (cx < radius) cx = radius;
if (cy > cyMax) cy = cyMax;
else if (cy < radius) cy = radius;
DrawCircle(1); // DRAW the new circle
delay(100);
}
void DrawCircle(int ink)
// ink =0 : ERASE the circle
// ink =1 : DRAW the circle
{
for(int x = 0; x <= radius; x++) // x values from 0 to RADIUS (one Quadrant)
{
// solve r^2 = x^2 + y^2 for y
float y = sqrt(pow(radius, 2) - pow(x, 2));
y = round(y*1);
// Fill the y-position in the 4 quadrants of the circle
LedSign::Set(x + cx, y + cy, ink); // Quadrant 1
LedSign::Set(x + cx, cy - y, ink); // Quadrant 4
LedSign::Set(cx - x, y + cy, ink); // Quadrant 2
LedSign::Set(cx - x, cy - y, ink); // Quadrant 3
}
}
Here's a Video of It Working
Have Fun!