Gyroscope Fun With Neopixel Ring




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 tutorial we'll going to use the MPU6050 gyroscope, a neopixel ring and an arduino to build a device that lights led's corresponding to the angle of inclination.

This is a simple and fun project and it's going to be assembled on a breadboard. If you'll follow the steps you'll build what you saw in the video. It's a good tutorial for learning about gyroscope and the neopixel ring.

I'm building this tutorial because of the interest i saw on my first instructable here (Gyroscope Led Control With Arduino). In this instructable i've replaced simple led's with a neopixel ring. The ring it's simpler to use through an Adafruit library and it's definitely more spectacular.

So if you have these components lying around this is a great way to make use of them, i'll try to take you step by step through building the device and also explain how it works in the last step.

Step 1: Things Required


1. Arduino pro mini 328p (eBay) 2 $

2. Breadboard

3. MPU6050 gyroscope (eBay) 1.2$

4. 24 neopixel led ring (Adafruit) 17 $

5. 4 x AA battery pack with 4 batteries

6. 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.


1. USB to serial FTDI adapter FT232RL to programm the arduino pro mini

2. Arduino IDE

1. Soldering, check this tutorial

3. Basic arduino programming, this tutorial might be useful

Step 2: Assembly

I've attached the fritzing schematic in fzz format and a picture of it for easy visualization of the connections

1. You need to solder 3 male pins on the back of the neopixel ring like shown in the picture

- solder the positive pin

- solder the ground

- solder the data input pin

2. Then the 4x battery holder should have a way of a connecting to the breadboard, a easy solution is to solder two male dupont wires to it's terminals.

3. Prepare the breadboard.

- place the neopixel ring, microcontroller and gyroscope on the breadboard like in the image

- place all the negative wires: to the microcontroller, neopixel ring, gyro

- place all the positive wires: to the microcontroller, neopixel ring, gyro

- place all the data wires:

* SDA and SCL from the to the microcontroller to the gyro

* pin D6 from the microcontroller to the neopixel ring

- double check all connections before powering

- optionally using duct tape, tape the battery pack on the back of the bradboard to hold it in place and make it more portable

Step 3: The Code and Calibration

First you need to download and install two libraries:

1. Adafruit neopixel library fir controlling the neopixel

2. MPU6050 library for the gyroscope

3. I2CDev library source

They are two great libraries that will do the heavy lifting!

More details on the neopixels here

Then download and install my library from here or copy it from below:

#include "I2Cdev.h"
#include <Adafruit_NeoPixel.h>
#include "MPU6050_6Axis_MotionApps20.h"

#include "Wire.h"

#define NUM_LEDS 24

const int MAX_ANGLE = 45;
const int LED_OFFSET = 12;
MPU6050 mpu;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, NEOPIXED_CONTROL_PIN, NEO_RBG + NEO_KHZ800);
unsigned long lastPrintTime = 0;

bool initialization = 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
Quaternion q;           // [w, x, y, z]         quaternion container
VectorFloat gravity;    // [x, y, z]            gravity vector
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</p><p>void setup() 
    Serial.println("Program started");
    initialization = initializeGyroscope();  

void loop() 
    if (!initialization) {
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();
    fifoCount = mpu.getFIFOCount();
    if (hasFifoOverflown(mpuIntStatus, fifoCount)) {
    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);
        redrawLeds(ypr[0] * 180/M_PI, ypr[1] * 180/M_PI, ypr[2] * 180/M_PI);

boolean hasFifoOverflown(int mpuIntStatus, int fifoCount) 
    return mpuIntStatus & 0x10 || fifoCount == 1024;

void redrawLeds(int x, int y, int z)
    x = constrain(x, -1 * MAX_ANGLE, MAX_ANGLE);
    y = constrain(y, -1 * MAX_ANGLE, MAX_ANGLE);
    if (y < 0 and z > 0) {
        lightLeds(y, z, 0, 5, 0, 89);      
    } else if (y < 0 and z < 0) {
        lightLeds(y, z, 6, 12, 89, 0);  
    } else if (y > 0 and z < 0) {
        lightLeds(y, z, 13, 19, 0, 89);     
    } else if (y > 0 and z > 0) {
        lightLeds(y, z, 20, 24, 89, 0);     

void lightLeds(int x, int y, int fromLedPosition, int toLedPosition, int fromAngle, int toAngle) 
    double angle = (atan((double) abs(x) / (double) abs (y)) * 4068) / 71;
    int ledNr = map(angle, fromAngle, toAngle, fromLedPosition, toLedPosition);
    printDebug(x, y, ledNr, angle);  
    uint32_t color;

    for (int i=0; i < NUM_LEDS; i++) {
        color = strip.Color(0, 0, 0);
        if (i == ledNr) {
           color = strip.Color(0, 180, 0);
        } else if (i == ledNr - 1) {
           color = strip.Color(0, 5, 0);
        strip.setPixelColor(normalizeLedPosition(i), color);;

int normalizeLedPosition(int position)
    if (NUM_LEDS > position + LED_OFFSET) {
        return position + LED_OFFSET;

    return position + LED_OFFSET - NUM_LEDS;

void printDebug(int y, int z, int lightLed, int angle)
    if (millis() - lastPrintTime < 500) {
    Serial.print("a=");Serial.print(angle);Serial.print("; ");
    Serial.print("ll=");Serial.print(lightLed);Serial.print("; ");
    Serial.print("y=");Serial.print(y);Serial.print("; ");
    Serial.print("z=");Serial.print(z);Serial.println("; ");
    lastPrintTime = millis();

bool initializeGyroscope() {
    TWBR = 24;  
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
    Serial.println(F("Initializing DMP..."));
    devStatus = mpu.dmpInitialize();
    if (devStatus != 0) {
        Serial.print(F("DMP Initialization failed (code "));Serial.println(devStatus);
        return false;
    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..."));
    packetSize = mpu.dmpGetFIFOPacketSize();
    return true;

void dmpDataReady() 
    mpuInterrupt = true;

Upload the code:

Using the FTDI adapter upload the code to the arduino.

Connect the power supply (batteries)


The most important thing to calibrate here is "LED_OFFSET" constant. In my example is 12. You need to adjust this from 0 to 23 so that after powering the board the led will light in the direction you tilt the board.

If you want to find out more details about how it works check out the last step

Step 4: How It Works (optional)

First a little information about the MPU6050 gyroscope. This is a MEMS gyroscope (MEMS stands for Microelectromechanical systems).

Each type of MEMs gyroscope has some form of oscillating component from where the acccleration, and hence direction change, can be detected. This is because, as per the conservation of motion law, a vibrating object likes to continue vibrating in the same plane, and any vibrational deviation can be used to derive a change in direction.

The gyro also contains a microcontroller of it's own to compute the roll, pitch and yaw through some fancy maths.

But the gyro raw data suffers from noise and drift, so we used an external library to smooth things out and give us clean usable data.

The Neopixel are RGB leds individually addressable and chained into bands and rings. They work on 5V and they contain they own circuitry so you only need to power the neopixels and to communicate with them using the data line. The communication is done with a single data line containing clock and data (more details here). Adafruit provides a clean library for interacting with the neopixel rings.

The code

Inside the loop() function the MPU6050_6Axis_MotionApps20 library is called. When the library has new data from the gyroscpe it calls redrawLeds(x, y, z) with 3 arguments representing yaw, pitch and roll

Inside redrawLeds():

- we're focusing on two axis : y, z

- we're constraining both axys from -MAX_ANGLE to +MAX_ANGLE, we defined max angle to 45 and it's changable

- we're splitting 360 degreeds into 4 quadrants and call lightLeds() functions for each as follows:

* y negative, z positive first quadrant will control led's from 0 to 5, the angle will be from 0 to 89

* y negative, z negative second quadrant controls led's from 6 to 12, the angle will be from 89 to 0

* ...etc

- inside the lightLeds function

* i'm calculating an angle based on the two axis using arctangent (check the attached picture)

* i'm calculating what led to show using the arduino map function

* i'm resetting the led strip all but two led's, the one corresponding to the led position i've calculated before and a led position before (to show a fade effect)

* i'm using a function called normalizeLedPosition() to take into account the neopixel calibration. The calibration is useful because the neopixel ring can be rotated as pleased, and should be aligned with the gyroscope

* i'm also printing the tow axis, what led has light and the angle

The math

I've attached a picture with the led ring and the trigonometric function used to determine the angle.



    • Growing Beyond Earth Maker Contest

      Growing Beyond Earth Maker Contest
    • Sensors Contest

      Sensors Contest
    • Pets Challenge

      Pets Challenge

    17 Discussions


    Question 7 weeks ago

    Hi I wanted to ask you, in my city I only found neopixel of 16 leds, what would I have to change in the code to make it work ?. Thank you

    1 answer

    Reply 6 weeks ago

    Try changing the following lines:
    #define NUM_LEDS 24
    #define NUM_LEDS 16
    const int LED_OFFSET = 12;
    const int LED_OFFSET = 6;
    if (y < 0 and z > 0) {
    lightLeds(y, z, 0, 5, 0, 89);
    } else if (y < 0 and z < 0) {
    lightLeds(y, z, 6, 12, 89, 0);
    } else if (y > 0 and z < 0) {
    lightLeds(y, z, 13, 19, 0, 89);
    } else if (y > 0 and z > 0) {
    lightLeds(y, z, 20, 24, 89, 0);

    if (y < 0 and z > 0) {
    lightLeds(y, z, 0, 3, 0, 89);
    } else if (y < 0 and z < 0) {
    lightLeds(y, z, 4, 8, 89, 0);
    } else if (y > 0 and z < 0) {
    lightLeds(y, z, 9, 12, 0, 89);
    } else if (y > 0 and z > 0) {
    lightLeds(y, z, 13, 16, 89, 0);

    I hope this helps, good luck! :)

    joe cowell

    3 months ago

    Hi,I put everything together and downloaded the libraries that you supplied but when I tried to run the project, the code for it uses different libraries than the ones you've supplied I know this is probably a silly mistake (on my behalf) but if you could help that would be great.

    2 replies
    danionescujoe cowell

    Reply 7 weeks ago

    Sorry for the late response, how can i help? Do you have an error ?


    4 months ago

    Thanks for this, I have just purchased the neopixel ring and the MPU5060. Could I use my Uno for this project? Sorry if this is a silly question, I'm just starting out :)

    2 replies

    Reply 4 months ago

    Hello, first of all no question is silly :) And yes you can use the Arduino UNO instead of Pro Mini for this project, there are Arduino boards which needs a bit of code tweaks for some functionalities but with with UNO is not the case. Enjoy the thinkering ;)


    5 months ago

    Salut, fain tutorialul ! Am totusi o intrebare, in determinarea unghiului pt variabila "angle", de ce arata formula trigonometrica asa ? Nu imi dau seama de ce trebuie inmultit cu 4068 si apoi impartit la 71. Multumesc :D

    2 replies

    Reply 5 months ago

    Multumesc pentru intrebare.
    The question was: why do the magical numbers 4068 and 71 are appearing in my angle formula.
    So my answer will be, because it's how you convert degrees from radians (as an aproximaion) with this formula: "degrees = radians * 4068 / 71". And "atan" function gives radians as a result.
    Hope this help :)


    8 months ago on Step 3

    Thanks for this project. I intend to do a full standalone gyroscope with the ring in a case. I just wanted to reply cause I found something in the code. Neopixel ring with 24 leds are from 0 to 24. So first quadrant is led 0 to 5, 2. from 6 to 11, 3. from 12 to 17 and 4. from 18 to 23. Correct me if Im wrong.

    3 replies

    Reply 8 months ago

    If you're referring to this line:

    for (int i=0; i < NUM_LEDS; i++) {...

    It will loop 0 to 23


    Reply 8 months ago

    No I meant the quadrant lines.

    else if (y lightLeds(y, z, 6, 12, 89, 0);

    Shouldnt it be 6 to 11 (6 leds per quadrant)?

    Next is redrawleds.
    You constrain yaw (x) and pitch (y) but calculate with the values y and z further in the code. And in the description you say you need pitch and roll.

    Which should I constrain? y and z, or did I misunderstand something?


    Reply 8 months ago

    Yep, it seems that one led is missing somewhere in the script. As for the x,y,z axys they are relative to the gyroscope mounting position. Try changing your gyro position or use, other axes


    1 year ago

    Foarte simplu si frumos, bravo!

    S-ar putea pune si un led central care sa lumineze cand senzorul este asezat pe o suprafata perfect plana?

    In felul asta ar putea fi folosit pe post de nivela similar cu cele cu lichid si o bula de aer.

    1 reply

    Reply 1 year ago

    Multumesc, da s-ar putea ar trebui pus un led, un rezistor si cateva linii de cod in plus.