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
AlexR385 made it!
87 Discussions
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
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
Reply 6 weeks ago
thank ykmour for your reply, it eventually worked with similar 1 k ohm resistors
Reply 6 weeks ago
Great! :)
Question 3 months ago
Getting errors in that code you mentioned
Reply 3 months ago
Hello. You'll need to download and istall this library: https://github.com/jrowberg/i2cdevlib
Here are some tips on how to install a library in the arduino ide : https://www.instructables.com/id/How-to-install-Li...
Hope it helps
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
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);
}
Reply 3 months ago
That is our actual sketch, we onky tried with the right direction.
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 :)
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
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.
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 =/
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)
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 :)
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. :)
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;
}
Reply 7 months ago
Okay, I will try it.Thank you so much. :)
Reply 7 months ago
Was this what you wanted ? :)
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.