Gyroscope Led Control With Arduino

22,712

60

87

About: I'm an electronics enthusiast, passionate about science, and programming. I am a web developer but i like the challenges involved with building things from scratch.

In this project i will show you how to build a simple 4 led tilt dimmer with a gyroscope and an arduino uno. There are 4 leds arranged in a "+" shape and they will light up more as you tilt the breadboard.

This won't involve any soldering, just basic breadboard assembly and basic arduino programming.

Step 1: Materials:

1) An Arduino Uno board and a USB cable. You can use a different board if you like but keep in mind that different boards have different pin configs, for example if you use an Arduino Mega the SDA and SCL pins are 20 and 21.

2) 4 leds, the leds should be identical , the color doesn't matter it's up to you :)

3) 4 identical resistors anywhere between 100 ohms and 1 K ohm, i recommend around 200

4) a breadboard

5) dupont wires

6) MPU-6050 gyro

7) U-shape jumper cables (optional). I've used these jumper cables because they look better on the breadboard, and the leds are more visible this way. You can find a box of 140 on ebay at about 4$. If you don't have these cables you can replace them with dupont wires.

Step 2: Assembly

1) Begin by placing the 4 leds on the breadboard in a "+" shape. The long pins of the leds are positive. I've placed the positive pins for the top and bottom leds on the right, and for the left and right leds below (see on the first picture.

2) Insert the four resistors in the breadboard.

3) Place the MPU6050 like in the picture

4) Insert the wires. The leds ground pins will go directly to the ground. The positive pins will go through a resistor into the arduino pins: pin 3 through a resistor to the front led, pin 5 through a resistor to the bottom led, and similar with pin 6 right led, pin 9 left led

The MPU6050 must be connected to ground and 5V+, after that connect SDA to A4 (analog 4), SCL to A5

I've also attached an fritzig schematic, if you want to make sure the connections are correct.

Step 3: The Code

   You will need two external libs I2CDev and MPU6050, i've attached them here, and i've posted below the source of the code. I've not written those libs it's not my merit :)

If you don't know how to install a library check this instructable:

Then copy paste or download my library and give it a try.

* I2CDev library source: https://github.com/jrowberg/i2cdevlib

Step 4: Improvements and Different Uses of the Gyro

This is the simplest project i've done with MPU6050, i can think of many derivatives from this idea:

- adding two or more leds for each direction, so the steeper the angel, the more leds will light up

- making a wearable that will warn you with a sound that you don't have a correct upright position

Those ugly conditions i think can be improved with some math (replace if's with some equations).

As a BONUS :) i've made a youtube video with another version of the project, i've added 3 leds for up, e for down, 2 for left and two for right.

If you want to check the video click here. I've also attached a picture of the breadboard above.

For those who are interested the code go here, and replace this line

#define SIMPLE_IMPLEMENTATION true

---------- with -----------

#define SIMPLE_IMPLEMENTATION false<br>

The new led pinout is: front leds: 3,12,11, bottom leds: 5,6,7, left leds: 10, 4, right leds: 6, 9

In my other tutorial i've shown how the gyroscope can be used toflip the display on the computer when the display is physically rotated. The instructable is here.

If you liked the youtube videos, you can get more by subscribing to my channel here

Step 5: A Recent Add-on to This Tutorial, a Neopixel Ring Driven by a Gyroscope

You can find the code here if you're interested about that.

Share

Recommendations

  • Warm and Fuzzy Contest

    Warm and Fuzzy Contest
  • Faux-Real Contest

    Faux-Real Contest
  • Sweet Treats Challenge

    Sweet Treats Challenge

87 Discussions

0
None
NartA2

6 weeks ago

Hello, i have done everything literally the way you did it. everything is working and the montoring is showing the values change. However, the LEDS are not working.
Do resistors have to be all similar in value?
I am currently using 1 k ohm resistors

3 replies
0
None
danionescuNartA2

Reply 6 weeks ago

Yes they should be similar values. To check if the wiring is good and the leds work well with the resistors upload the blink sketch, and modify the led pin. If it's all ok it should blink if not, the wiring is bad, or the led are busted, or the resistors have a higher value then needed. This is how you calculate the value for the resistor: http://www.ohmslawcalculator.com/led-resistor-calculator

0
None
NartA2danionescu

Reply 6 weeks ago

thank ykmour for your reply, it eventually worked with similar 1 k ohm resistors

0
None
AndreaU9

Question 3 months ago

Look, we have this project that consists in a directional system for bikes, so we want to incorporate the MPU6050 in order to urn off the directional once the bike has finished the spin. The directional is activated by a buttom located in the handle and can be turn off by pushing the button again but we want the both opcions ( with thw button and with the MPUP6050 gyroscope),the question is how can we do it? ( the buttons send the order to the directional located in a vest through Bluetooth modules [hc-05])
We have tried a lot of sketches, the part that works is without the gyroscope, we ned to include the gyroscope, but it does not work. PLEASE HELP US!
Sorry for our English

5 answers
0
None
AndreaU9AndreaU9

Answer 3 months ago


#include //Protoo
struct pt hilo3;
struct pt hilo5;

#include //pulsadores
SoftwareSerial mySerial(10, 11); // RX, TX

# define _MPU6050_6AXIS_MOTIONAPPS20_H_ //Giroscopio
#include
#include
//#include
//#include
#include
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include
#endif //siempre hacerlo
static const int mpuAddress = 0x68; // Puede ser 0x68 o 0x69
MPU6050 mpu(mpuAddress);
static int ax, ay, az;
static int gx, gy, gz;

static int direccion = 0; //desactivar direccional
static int comparacion = 0;
static int b = 0;
static int c = 0;
static long tiempo_prev;
static float dt;
static float ang_x, ang_y;
static float ang_x_prev, ang_y_prev;

void updateFiltered() {
static const int mpuAddress = 0x68; // Puede ser 0x68 o 0x69
MPU6050 mpu(mpuAddress);
static int ax, ay, az;
static int gx, gy, gz;
static long tiempo_prev;
static float dt;
static float ang_x, ang_y;
static float ang_x_prev, ang_y_prev;
dt = ((millis() - tiempo_prev) / 1000.0);
tiempo_prev = millis();

//Calcular los ángulos con acelerometro
static float accel_ang_x = atan(ay / sqrt(pow(ax, 2) + pow(az, 2))) * (180.0 / 3.14);
static float accel_ang_y = atan(-ax / sqrt(pow(ay, 2) + pow(az, 2))) * (180.0 / 3.14);

//Calcular angulo de rotación con giroscopio y filtro complementario
ang_x = 0.98 * (ang_x_prev + (gx / 131) * dt) + 0.02 * accel_ang_x;
ang_y = 0.98 * (ang_y_prev + (gy / 131) * dt) + 0.02 * accel_ang_y;

ang_x_prev = ang_x;
ang_y_prev = ang_y;
}

void setup() {
PT_INIT(&hilo3);
PT_INIT(&hilo5);
}
void loop() {
pulsadores(&hilo3);
Giros(&hilo5);
}

void pulsadores(struct pt *pt) {
PT_BEGIN(pt);

pinMode(8, INPUT);
pinMode(7, INPUT);
pinMode(6, INPUT);
pinMode(5, INPUT);
Serial.begin(9600);
mySerial.begin(9600);

static long val = 0;
static long val_ant = 0;
// el val esta ligado a salida1
static long val1 = 0;
static long val_ant1 = 0;
// el val1 esta ligado a salida2
static long val2 = 0;
static long val_ant2 = 0;
// el val2 esta ligado a salida3
static long val3 = 0;
static long val4 = 0;
static long con1 = 0;
static long con2 = 0;
static long con3 = 0;
static long con4 = 0;
static long con5 = 0;
static long salida1 = 0;
static long salida2 = 0;
static long salida3 = 0;
static long t3 = 0;
static long t4 = 0;
static long t5 = 0;
static long t13 = 0;

do {
val = digitalRead(7);
if ((val == HIGH) && (val_ant == LOW)) {
salida1 = 1 - salida1;
t3 = millis();
PT_WAIT_UNTIL(pt, (millis() - t3) >= 10);
}
val_ant = val;

if (salida1 == 1) {
con3++;
if (con3 == 1) {
mySerial.write('a'); Serial.println("a");
Serial.write('a'); Serial.println("b");
direccion = ang_x;
comparacion = direccion - 30;
con1 = 0;
}
}
else {
con1++;
if (con1 == 1 ) {
mySerial.write('b'); Serial.println("b");
Serial.write('b'); Serial.println("b");
con3 = 0;
}
else {
if ( comparacion > ang_x) {
do {
b = ang_x;
t13 = millis;
PT_WAIT_UNTIL(pt, (millis() - t13) >= 4000);
c = ang_x;
if (con1 == 1) {
break;
}
} while ( b != c);
mySerial.write('b'); Serial.println("b");
Serial.write('b'); Serial.println("b");
con3 = 0;
}
}
}

//hasta aqui la derecha

val1 = digitalRead(8);
if ((val1 == HIGH) && (val_ant1 == LOW)) {
salida2 = 1 - salida2;
t4 = millis();
PT_WAIT_UNTIL(pt, (millis() - t4) >= 10);
}
val_ant1 = val1;

if (salida2 == 1) {
con5++;
if (con5 == 1) {

mySerial.write('e'); Serial.println("e");
Serial.write('e'); Serial.println("e");
con2 = 0;
}
}
else {
con2++;
if (con2 == 1) {

mySerial.write('f'); Serial.println("f");
Serial.write('f'); Serial.println("f");
con5 = 0;
}
}

// hasta aqui la izquierda

val3 = digitalRead(6);
val4 = digitalRead(5);
if ((val3 == HIGH) && (val4 == HIGH)) {

mySerial.write('c'); Serial.println("c");
Serial.write('c'); Serial.println("c");
con4 = 0;
}
else {
con4++;
if (con4 == 1) {

mySerial.write('d'); Serial.println("d");
Serial.write('d'); Serial.println("d");
}
t5 = millis();
PT_WAIT_UNTIL(pt, (millis() - t5) >= 10);
}
} while (true);
PT_END(pt);
}

void Giros (struct pt *pt) {
PT_BEGIN(pt);
static long t12 = 0;
static const int mpuAddress = 0x68; // Puede ser 0x68 o 0x69
MPU6050 mpu(mpuAddress);
static int ax, ay, az;
static int gx, gy, gz;
static long tiempo_prev;
static float dt;
static float ang_x, ang_y;
static float ang_x_prev, ang_y_prev;

Serial.begin(9600);
Wire.begin();
mpu.initialize();
Serial.println(mpu.testConnection() ? F("IMU iniciado correctamente") : F("Error al iniciar IMU"));
do {
// Leer las aceleraciones y velocidades angulares
mpu.getAcceleration(&ax, &ay, &az);
mpu.getRotation(&gx, &gy, &gz);

updateFiltered();

Serial.print(F("\n Rotacion en X: \t"));
Serial.print(ang_x);

t12 = millis();
PT_WAIT_WHILE(pt, (millis() - t12)
} while (true);
PT_END(pt);
}

0
None
AndreaU9AndreaU9

Reply 3 months ago

That is our actual sketch, we onky tried with the right direction.

0
None
danionescuAndreaU9

Reply 3 months ago

Hello
I need to know what are the project specifications, what does " in a directional system for bikes" mean ? Can you describe the algorithm in simple words? I'll try to come up with a solution if possible :)

1
None
AndreaU9danionescu

Reply 3 months ago

The system works from the bluetooth communication between 3 pushbuttons located on the handlebar of the bicycle (connected to an arduino Mega and a bluetooth module HC-05 master) and 3 strips of LEDs (connected to an arduino nano and a bt HC- 05 slave) located on the back of the vest that the person wears, in this way when the person wants to turn left, the person presses the left button and by bluetooth this command arrives at the arduino nano, and the left led strip is activated, and once the bicycle has finished turning, the person must manually deactivate the directional by pressing the left button again. What we are trying to do is incorporate the gyroscope to the buttons, so that it detects when the bicycle has finished turning and automatically deactivates the directional, giving two options that are deactivated manually or that the gyroscope does.

We appreciate your help

0
None
danionescuAndreaU9

Reply 3 months ago

Sorry for the late response. I've given it a deeper thought. I think a gyroscope it's not suited for this kind of use case. The gyro axys are relative to the earth poles not to the byke position, that means that you won't know when the byke has finished turning.
I recommend you either use a simple "timeout" for the signal lights or that you'll install a small switch that is "pressed" when the handlebar is in the straight position, in this way when the signal button is pressed you'll turn the lights on, and when the switch is pressed you cancel the command (light).
I hope this helped you a little.

0
None
t03n

Question 3 months ago on Introduction

Hey, does anyone know if this is also possible with an arduino nano? I connected everything to it,downloaded the code and it uploads to the board just fine.. but nothing happens the MPU 6050 does not even light up =/

2 answers
0
None
danionescut03n

Answer 3 months ago

It should work with a Nano. Hmm double check the connections, i cant't tell you much from the distance. You could try this checklist though:
- check power connections
- check data connections
- check both the arduino and mpu6050 are working by uploading a default sketch which uses the MPU
- replace breadbord and cables (including the USB cable)

0
None
AndreaU9t03n

Answer 3 months ago

Si es posible con una nano, conectaste correctamente? Vcc----5v
GND---GND
SCL----A5
SDA---A4
Recuerda que primero debes calibrar el grioscopio. Saludes desde Colombia :)

0
None
Rujutas

7 months ago

Hello again! So I would like to do the following function.

I want to check if the angle is the same for certain amount of time (say for 15 seconds), if that is the case it prints something. Basically if I keep rotating that means the angles are changing, but if i put it at one particular angle say right and the right led is lit up and it stays lit up for 15 seconds then i want to print something, basically send some signal.I am doing a project with IOT device and I want the user to rotate the object and send a signal when the object is at a particular angle and not moving aymore. I am unable to figure out where to make changes. It would be great if you can help. I hope i was clear enough. I appreciate the help. :)

4 replies
0
None
danionescuRujutas

Reply 7 months ago

I've attached the code below in the comments. You'll neede to chane "millisToConsiderStill" variable from 3000 (milliseconds) to whatever you need. Also you can change "maximumAcceptedMovement" this variable means that variances in angle below that value (i've set a default of 4 degrees) will no be considered movement.

You'll need to place your code inside this if statement:

if (isAxysStill(x)) {

# do something here like trigger a pin HIGH

# the next line needs to stay if you need to reset the notification from that moment on, you can experiment what happens if you remove it or keep it

updateStillness(x, true);

}

I've tested the code below with an arduino unu and it seems to work. I hope it's what you needed :)

/**

* Simple implementation false

*

* means that for pitch/yaw there only be

* a single led for each direction. The led will get more bright

* as the direction increases

*

* Simple implementation true

* means that for pitch/yaw there will be multiple led's that light up one by one

*

* The accelerometer/gyro is a MPU6050, it should be wired to the SDA and SCL pins

*/

#define SIMPLE_IMPLEMENTATION false

const int frontLed = 3;

const int bottomLed = 5;

const int rightLed = 6;

const int leftLed = 9;

long int lastPrintTime;

typedef struct

{

byte pin;

byte positionInsideGroup;

char thePosition; // Left, Right, Up, Down

byte minAngle;

byte maxAngle;

} ledConfig;

typedef struct

{

byte maximumAcceptedMovement = 4;

unsigned int millisToConsiderStill = 3000;

byte firstActualAngle = 0;

unsigned long firstActualAngleMillis = 0;

} axysStillness;

axysStillness xAxys;

ledConfig leds[] = {

{3, 1, 'u', 31, 45},

{12, 2, 'u', 16, 30},

{11, 3, 'u', 5, 15},

{5, 1, 'd', 5, 15},

{6, 2, 'd', 16, 30},

{7, 3, 'd', 31, 45},

{8 , 1, 'r', 5, 23},

{9, 2, 'r', 24, 45},

{10, 1, 'l', 5, 23},

{4, 2, 'l', 24, 45},

};

#include "I2Cdev.h"

#include "MPU6050_6Axis_MotionApps20.h"

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE

#include "Wire.h"

#endif

MPU6050 mpu;

bool dmpReady = false; // set true if DMP init was successful

uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU

uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)

uint16_t packetSize; // expected DMP packet size (default is 42 bytes)

uint16_t fifoCount; // count of all bytes currently in FIFO

uint8_t fifoBuffer[64]; // FIFO storage buffer

// orientation/motion vars

Quaternion q; // [w, x, y, z] quaternion container

VectorInt16 aa; // [x, y, z] accel sensor measurements

VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements

VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements

VectorFloat gravity; // [x, y, z] gravity vector

float euler[3]; // [psi, theta, phi] Euler angle container

float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector

volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high

void setup()

{

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE

Wire.begin();

TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)

#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE

Fastwire::setup(400, true);

#endif

Serial.begin(9600);

while (!Serial); // wait for Leonardo enumeration, others continue immediately

Serial.println(F("Initializing I2C devices..."));

mpu.initialize();

Serial.println(F("Testing device connections..."));

Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

Serial.println(F("Initializing DMP..."));

devStatus = mpu.dmpInitialize();

mpu.setXGyroOffset(220);

mpu.setYGyroOffset(76);

mpu.setZGyroOffset(-85);

mpu.setZAccelOffset(1788); // 1688 factory default for my test chip

if (devStatus == 0) {

// turn on the DMP, now that it's ready

Serial.println(F("Enabling DMP..."));

mpu.setDMPEnabled(true);

Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));

attachInterrupt(0, dmpDataReady, RISING);

mpuIntStatus = mpu.getIntStatus();

Serial.println(F("DMP ready! Waiting for first interrupt..."));

dmpReady = true;

packetSize = mpu.dmpGetFIFOPacketSize();

} else {

Serial.print(F("DMP Initialization failed (code "));

Serial.print(devStatus);

Serial.println(F(")"));

}

if (SIMPLE_IMPLEMENTATION) {

initializeLEDsSimple();

} else {

initializeLEDsMultiple();

}

lastPrintTime = millis();

}

void updateStillness(byte angle, bool forceReset)

{

if (abs(xAxys.firstActualAngle - angle) > xAxys.maximumAcceptedMovement || forceReset) {

xAxys.firstActualAngle = angle;

xAxys.firstActualAngleMillis = millis();

}

}

bool isAxysStill(byte angle)

{

return millis() - xAxys.firstActualAngleMillis >= xAxys.millisToConsiderStill;

}

void loop()

{

if (!dmpReady) return;

mpuInterrupt = false;

mpuIntStatus = mpu.getIntStatus();

fifoCount = mpu.getFIFOCount();

if ((mpuIntStatus & 0x10) || fifoCount == 1024) {

mpu.resetFIFO();

Serial.println(F("FIFO overflow!"));

} else if (mpuIntStatus & 0x02) {

while (fifoCount < packetSize) {

fifoCount = mpu.getFIFOCount();

}

mpu.getFIFOBytes(fifoBuffer, packetSize);

fifoCount -= packetSize;

mpu.dmpGetQuaternion(&q, fifoBuffer);

mpu.dmpGetGravity(&gravity, &q);

mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);

int x = ypr[0] * 180/M_PI;

int y = ypr[1] * 180/M_PI;

int z = ypr[2] * 180/M_PI;

//Serial.print(y);Serial.print("\t");Serial.println(z);

updateStillness(x, false);

if (isAxysStill(x)) {

Serial.println("axys still at");

Serial.println(x);

updateStillness(x, true);

}

if (SIMPLE_IMPLEMENTATION) {

flashLEDsSimple(x, y, z);

} else {

flashLEDsMultiple(x, y, z);

}

}

}

void initializeLEDsSimple()

{

pinMode(frontLed, OUTPUT);

pinMode(bottomLed, OUTPUT);

pinMode(rightLed, OUTPUT);

pinMode(leftLed, OUTPUT);

}

void initializeLEDsMultiple()

{

for (int i=0; i<10; i++) {

Serial.println(leds[i].pin);

pinMode(leds[i].pin, OUTPUT);

}

delay(3000);

}

void flashLEDsSimple(int x, int y, int z)

{

if (y > 0) {

analogWrite(rightLed, y*4);

analogWrite(leftLed, 0);

} else {

analogWrite(leftLed, y*4*-1);

analogWrite(rightLed, 0);

}

if (z > 0) {

analogWrite(bottomLed, z*4);

analogWrite(frontLed, 0);

} else {

analogWrite(frontLed, z*4*-1);

analogWrite(bottomLed, 0);

}

}

void flashLEDsMultiple(int x, int y, int z)

{

for (int i=0; i<10; i++) {

//Serial.print(z);Serial.print(",");Serial.print(leds[i].thePosition);Serial.print(",");Serial.println(leds[i].minAngle);

bool modified = false;

if (z < 0 && leds[i].thePosition == 'u' && abs(z) > leds[i].minAngle) {

digitalWrite(leds[i].pin, HIGH);

modified = true;

}

if (z > 0 && leds[i].thePosition == 'd' && abs(z) > leds[i].minAngle) {

digitalWrite(leds[i].pin, HIGH);

modified = true;

}

if (y < 0 && leds[i].thePosition == 'l' && abs(y) > leds[i].minAngle) {

digitalWrite(leds[i].pin, HIGH);

modified = true;

}

if (y > 0 && leds[i].thePosition == 'r' && abs(y) > leds[i].minAngle) {

digitalWrite(leds[i].pin, HIGH);

modified = true;

}

if (!modified) {

digitalWrite(leds[i].pin, LOW);

}

}

}

void dmpDataReady()

{

mpuInterrupt = true;

}

0
None
Rujutasdanionescu

Reply 7 months ago

Okay, I will try it.Thank you so much. :)

0
None
danionescuRujutas

Reply 7 months ago

Hello there. I'll try to come up with a solution for you and put it here:)

The angle will not likely be the same, so i'll have to come up with an algorithm that will analize the angle changed over a period of time and check if the differences in change are small enough.