Introduction: 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

Step 1: What You Need

Step 2: 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

Step 3: 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/

Step 4: 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.

Step 5: 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
  }
}

Step 6: 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

Step 7: 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
  }
}

Step 8: Here's a Video of It Working

Have Fun!

Comments

author
petervojtek (author)2015-01-23

what is the purpose of drawing a circle instead of a single dot?

from the level use case point of view, a single dot will be well enough, no? (maybe I missed some point).

About This Instructable

5,461views

6favorites

License:

Bio: Technologist, Electronic Engineer, sometime Coderdojo mentor.
More by akellyirl:Arduino Guitar Tuner Using DSP TechniquesSmart Home ThermostatArduino Yun Messager
Add instructable to: