Building a “Follow Light” with Arduino
Tags: arduino, iot, microcontroller
Published: 2020-12-02 15:01:20

At my workplace in Frankfurt/Main, I'm walking through a long black corridor to get to my desk, which is kinda boring.

So some colleagues and I had an idea: How about making it a bit more colorful by adding some LEDs?

And when you walk through, we **light the LEDs closest to your position**, so it will look like it follows you - a follow light.

## Measurements and components

We started by writing down a **concept paper**. 

- What do we want to archive?
- How can we archive that?
- What are the dimensions of the corridor? 
- Which parts would we need? 
- How much would it cost?

![A photo of said corridor and a rough sketch of its dimensions](https://dev-to-uploads.s3.amazonaws.com/i/5filqhgh1eb5zez5c6n2.jpg)
<figcaption>The corridor is around 8m long and connects our welcome area with the office.</figcaption>

We figured out we would need a controller, two LED strips and some kind of sensor, which can "see" you walking through. 

So we discussed some hardware options and possible **solutions** and debating the pros and cons. 

### Microcontroller

We quickly agreed on an **Arduino**. It's a well known platform and a Raspberry Pi felt like overkill after we decided against the XBox Kinect sensor. But more about that later.

### LED lightstrip

Every single LED of the lightstrip needs to be **addressable**, so we can control specific LEDs. And we require a really long LED strip.

To make it work easier with the [Adafruit NeoPixel Library](https://github.com/adafruit/Adafruit_NeoPixel) we decided for two 5m "WS2812b like" lightstrips with 300 LEDs each.

But that much LEDs require a lot of power.

One LED takes ~0.06 Ampere. So we would need `0.06 * 600` = 36 Ampere if we want to light all LEDs in bright white.

We came to the conclusion, that the Arduino alone would not be able to deliver enough power. 

So we added an **extra power supply** (5V10A) to our setup.

This is not enough to lighten all LEDs in bright white, but bright white LEDs are really harsh to your eyes which means we have to dim them anyway (=requires less power).

We're also using colors (=requires less power) and we won't use all LEDs at the same time (=you guessed it: requires less power).


### Distance Sensor

Each sensor we came up with has a different **Field of View** (short FOV, basically an angle of how much area it can grasp) and max distance. 

**XBox Kinect:** Huge FOV, can detect multiple people, expensive, but just medium range (~5m), power supply is a concern and it doesn’t work well with just an Arduino.

**Photoelectric Sensor:** Cheap, small FOV, short range, we would require quite a lot of them for tracking someone and also wiring is an issue.

**Ultrasonic Distance Sensor:** Cheap, easy setup, medium FOV, but short range (~2m).

**LiDAR Sensor:** Long range (~10m), easy setup, but a small FOV

Our corridor is quite long and narrow, so the trackable distance is more important than the FOV.

In the end we decided in favor of the **LiDAR Sensor**. This way the power supply isn’t an issue, we need less wires and it’s comparably cheap. (Later, we also tested the Ultra Sonic sensor, since one was part of the Arduino Starter Kit).

### Our Hardware

We ended up with the following components and a price tag of ~225€.

- Arduino UNO R3 (together with a Starter Kit)
- SK6812 IC LED Stripes (like WS2812B)
- Benewake TFmini Plus LiDAR
- Power Supply 5V10A (for the LED strips)

---

## Creating a Prototype

After buying the hardware we started exploring.

Beside the Arduino IDE we installed the **Arduino CLI**, so we can compile and upload our code from the command line.

### Setup

```sh
$ brew update
$ brew install arduino-cli
$ arduino-cli core update-index

# Install board core
$ arduino-cli core install arduino:avr

# Install libs
$ arduino-cli lib install "Adafruit NeoPixel"
$ arduino-cli lib install "TFMPlus"
```

### Compile and upload

After connecting the Arduino via USB we can compile and upload our code with these commands:

```sh
# Show connected boards with port
$ arduino-cli board list

# Compile
$ arduino-cli compile --fqbn arduino:avr:uno followlight

# Upload (replace /dev/cu.usbmodem144101 with your port)
$ arduino-cli upload --port /dev/cu.usbmodem144101 --fqbn arduino:avr:uno followlight
```

---

### Getting each component to work

Before screwing everything together, we needed to learn and understand how we get the **independent components** to work.

There are quite a lot of tutorials on how to get the LED strip running, but [this one (German)](https://starthardware.org/viele-leds-mit-arduino-steuern-ws2812/) helped us a lot.

The most important learnings for us:

- Make sure you have a wire connecting the Arduino **ground** (GND) with the LED power supply.
- Add a **resistor** of 300 to 500 Ohm between the Arduino pin and the LED data pin. This protects the LED from receiving too much power through this wire and burning out.
- It's recommended to add a **capacitor** of 1000 microfarad to support the power supply of your LED strip.
- You should get some **DC Power Connector** with screws to connect the lightstrip wires with the power supply and you wont need to solder them.

![Photo showing the Arduino connected to one LED strip through a breadboard](https://dev-to-uploads.s3.amazonaws.com/i/loog5cibprva95n4pnun.jpg)
<figcaption>The red wire conducts current (+5V), the white wire is ground (-, GRND) and the green wire is our data channel.</figcaption>

Getting the LiDAR Sensor to work was a bit confusing since the documentation mentioned a **blue wire, which is actually green**.

Thanks to Bud Ryerson and his [Arduino Library for the Benewake TFMini-Plus Lidar sensor](https://github.com/budryerson/TFMini-Plus) we now had a working sensor setup.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/btefts44awg15mtai1br.jpg)
<figcaption>The red wire conducts current (+5V), the black wire is ground (-, GND), white is receiving (RXD) and green is transmitting (TXD)</figcaption>

---

## Putting everything together

The logic of our first prototype looked somewhat like this.

```c++
#define FOLLOW_LIGHT_LENGTH 5 // LEDs we want to light at once

int x = 0;      // x sensor value in cm
int xLed = 0;   // x position of active led

void loop()
{
    x = getDistanceTFMiniPlus();
    
    // calculate the led (300 LEDs / 500cm)
    xLed = round(0.6 * x);

    pixels.clear();
    pixels.fill(pixels.Color(100, 0, 0), xLed, FOLLOW_LIGHT_LENGTH);
    pixels.show();
}
```
The TF Mini Plus LiDAR sensor returns a value in centimeters, but the NeoPixel Library can only switch single LEDs, so we have to convert the centimeters to a pixel LED.

We have 300 LEDs equally distributed over 500cm, `300 / 500` = 0.6 LED per cm and we don't have half LEDs so we round that to an integer value.

And that's our prototype:

![Video Gif showing a lightstrip controlled by a distance sensor](https://dev-to-uploads.s3.amazonaws.com/i/pdhn0x495wkq1po6n12k.gif)<figcaption>The GIF actually shows our setup with an HC-SR04 Ultra Sonic Distance Sensor, but it works the same with our TFmini Plus LiDAR Sensor.</figcaption>

---

## What's next?

Well, we want a smooth animation, this prototype has only one LED strip and we actually need to install it in our corridor.

So watch out for a part 2 about our Follow Light.