Built-in project · Arduino Uno R3

Distance rainbow on an Arduino Uno

A Sharp GP2Y0A21 measures a hand from 10 to 80 cm and a WS2812 stick lights up from green to red as it comes closer. The whole build, an Arduino Uno and 2 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Beginner About 15 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $41. On Mokxi they're free.

The circuit runs here once the page has loaded.

What you'll learn

  • Analog distance sensors and converting voltage to centimeters
  • Addressable LEDs driven from one data pin
  • Mapping a range of readings onto a count of LEDs
  • Mixing red and green to make a gradient
  • Clamping a value so it stays in range
  • Difficulty: Beginner
  • Time: About 15 minutes
  • Board: Arduino Uno R3
  • Parts: 4

How it works

The Sharp sensor sends back a voltage on A0 that depends on how far away your hand is. The SharpIR library turns that voltage into centimeters, from 10 to 80. The sketch asks for a new reading about every 50 ms.

The closer the hand, the more of the eight WS2812 pixels light up: none at 80 cm, all eight at 10 cm. Each lit pixel gets its own color, from green at the start of the strip to red at the end. So a close hand fills the stick with a red warning.

Parts list

4 parts, plus the jumper wires. They retail for about $41; on Mokxi they're free.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
Addressable RGB LEDs pin DINArduino Uno R3 pin 6
IR distance sensor, Sharp GP2Y0A21 pin VCCArduino Uno R3 pin 5V
Addressable RGB LEDs pin VDDArduino Uno R3 pin 5V
IR distance sensor, Sharp GP2Y0A21 pin GNDArduino Uno R3 pin GND
Addressable RGB LEDs pin VSSArduino Uno R3 pin GND
IR distance sensor, Sharp GP2Y0A21 pin VOArduino Uno R3 pin A0

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// Distance rainbow: a Sharp GP2Y0A21 and an eight-LED WS2812 stick.
//
//   A0      the sensor's VO (yellow); VCC and GND from the rails
//   pin 6   the stick's DIN
//
// SharpIR turns the sensor's voltage into centimeters, 10 to 80 (and 9 or 81
// past either end, as the real library answers). The nearer
// the hand, the more of the stick lights: none at 80 cm, all eight at 10, and
// each LED's color runs from green at the start of the stick to red at the
// end, so a close hand is a red warning.
//
// The sensor only measures every 38 ms, and reads a hand closer than 10 cm
// as further away, which is why the stick never quite fills when the hand is
// pressed right up against it.

#include <Adafruit_NeoPixel.h>
#include <SharpIR.h>

const int LEDS = 8;
const int STRIP_PIN = 6;

Adafruit_NeoPixel strip(LEDS, STRIP_PIN, NEO_GRB + NEO_KHZ800);
SharpIR sensor(SharpIR::GP2Y0A21YK0F, A0);

int lastCm = -1;

void setup() {
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: distance rainbow");
  strip.begin();
  strip.setBrightness(80);
  strip.show();
}

void loop() {
  int cm = sensor.getDistance();
  // 80 cm lights none, 10 cm all eight.
  int lit = (int)((80L - cm) * LEDS / 70);
  if (lit < 0) lit = 0;
  if (lit > LEDS) lit = LEDS;
  for (int i = 0; i < LEDS; i++) {
    if (i < lit) {
      // Green to red along the stick.
      int red = i * 255 / (LEDS - 1);
      strip.setPixelColor(i, strip.Color(red, 255 - red, 0));
    } else {
      strip.setPixelColor(i, 0);
    }
  }
  strip.show();
  if (cm != lastCm) {
    lastCm = cm;
    Serial.print(cm);
    Serial.print(" cm: ");
    Serial.print(lit);
    Serial.println(" lit");
  }
  delay(50);
}

Code walkthrough

The key functions of the sketch, and what each one does.

setup sketch.ino

Opens the serial port, prints a hello line, then starts the strip with strip.begin(). strip.setBrightness(80) keeps the pixels from being too bright. strip.show() sends the first update, which leaves every pixel dark.

void setup() {
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: distance rainbow");
  strip.begin();
  strip.setBrightness(80);
  strip.show();
}

loop sketch.ino

Reads cm from the sensor, then works out lit, how many pixels to light, with (80 - cm) * LEDS / 70. That value is clamped between 0 and LEDS. A loop then colors each pixel: lit ones get a green to red mix based on position, others are turned off. It prints a line only when the reading changes.

void loop() {
  int cm = sensor.getDistance();
  // 80 cm lights none, 10 cm all eight.
  int lit = (int)((80L - cm) * LEDS / 70);
  if (lit < 0) lit = 0;
  if (lit > LEDS) lit = LEDS;
  for (int i = 0; i < LEDS; i++) {
    if (i < lit) {
      // Green to red along the stick.
      int red = i * 255 / (LEDS - 1);
      strip.setPixelColor(i, strip.Color(red, 255 - red, 0));
    } else {
      strip.setPixelColor(i, 0);
    }
  }
  strip.show();
  if (cm != lastCm) {
    lastCm = cm;
    Serial.print(cm);
    Serial.print(" cm: ");
    Serial.print(lit);
    Serial.println(" lit");
  }
  delay(50);
}

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • The stick never lights all eight pixels This project
    The sensor reads a hand closer than 10 cm as further away. Hold your hand at about 10 cm, not pressed against it.
  • Nothing lights at all This project
    Check that the strip's DIN goes to pin 6 and that its VDD and VSS are on 5V and GND.
  • The distance reading is noisy or odd. IR distance sensor
    Add a capacitor of about 10 uF across the sensor supply. Average several readings. The output changes about every 38 ms, so do not read faster than that.
  • Close objects read as far away. IR distance sensor
    The output peaks near 6 cm and falls closer than that. Keep objects beyond the minimum range, and convert the voltage to distance using the datasheet curve, which is not linear.
  • The first LED flickers, shows wrong colors, or the whole strip glitches. Addressable RGB LEDs
    Join the grounds of the strip and the controller. Add a 300 to 500 ohm resistor in series with the data line. Put a 1000 uF capacitor across the strip's 5 V and GND.
  • The strip works at low brightness but dims, turns yellow, or resets when many LEDs go white. Addressable RGB LEDs
    Each LED can draw about 60 mA at full white. Use a 5 V supply sized for the count, feed power in at several points, and lower the brightness in code.
  • Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
    Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected.
  • Pins misbehave or the board resets when you power motors or servos from it. Arduino Uno R3
    Each I/O pin gives about 20 mA, 40 mA max. Power motors and servos from their own supply and join its ground to the Uno's GND.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.