Arduino Nano - IR Slotted Optical Speed Sensor

This tutorial instructs you how to use Arduino Nano to read the IR slotted optical speed sensor, a small U-shaped part that tells the board when something passes through its gap. In detail, we will learn:

We suggest:

Arduino Nano IR slotted optical speed sensor

Hardware Preparation

1×Official Arduino Nano
1×Alternatively, DIYables Nano V3.0 Development Board
1×USB A to Mini-B USB cable
1×IR Slotted Optical Speed Sensor
1×Jumper Wires
1×Breadboard
1×Optionally, Breadboard
1×Recommended: Screw Terminal Expansion Board for Arduino Nano
1×Recommended: Breakout Expansion Board for Arduino Nano
1×Recommended: Power Splitter for Arduino Nano

Or you can buy the following kits:

1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand, DIYables .

Overview of IR Slotted Optical Speed Sensor

People call this part by many names: slot sensor, photo interrupter, opto interrupter, or U-shaped IR sensor. All of them mean the same thing. It is a light gate. A light shines from one side of a gap to the other side, and the module reports whether that light gets through.

How It Detects an Object

How IR Slotted Optical Speed Sensor Works

Look at the two arms of the "U". The first arm has an infrared LED inside. The second arm has an NPN phototransistor inside. They look at each other across a gap of 5.9 mm.

There are only two cases:

  • The gap is empty. The phototransistor sees the infrared light, so the module sets OUT to HIGH.
  • Something opaque sits in the gap, such as a strip of card or one tooth of an encoder disc. The light cannot pass, so the module sets OUT to LOW.

The module also has a Schmitt trigger on board. Its job is to turn the raw light level into a sharp 0 or 1. Because the edges are already clean, your Arduino Nano sketch does not need any debounce code.

Two things to remember:

  • Clear plastic or glass can let infrared light through. Test with something you cannot see through.
  • A few modules from other brands work the other way round (LOW when empty). If yours does, swap LOW and HIGH in the first sketch. The RPM sketch counts one edge for each slot, so it gives the right answer with both kinds.

Specifications

IR Slotted Optical Speed Sensor
Sensor type Slot-type photoelectric (IR LED + NPN phototransistor)
Slot width 5.9 mm
Operating voltage 3.3V to 5V DC
Output Digital (TTL), LOW when blocked, HIGH when clear
Signal conditioning Built-in Schmitt trigger
Mounting M3 screw holes at both ends
Pins 3 (VCC, GND, OUT)

You will find this sensor in projects like these: a tachometer for a small motor, wheel speed feedback on a robot car, a counter for parts on a belt, an end-stop that tells a moving part it has reached its limit, and a simple odometer that counts how many times a wheel has turned.

The IR Slotted Optical Speed Sensor Pinout

IR Slotted Optical Speed Sensor Pinout

Only three pins come out of the module:

  • VCC pin: must be connected to the 5V pin of Arduino Nano
  • GND pin: must be connected to GND (0V)
  • OUT pin: the digital signal line; it must go to an input pin of Arduino Nano (D2 in this tutorial)

※ NOTE THAT:

The arrangement of pins on a module may differ from one manufacturer to another, and the order can even change between two batches of the same product. It is essential to always refer to the labels printed on the module when using it. Take a close look!

Turning Pulses into Speed

On its own, the sensor only sees "something" or "nothing". To read speed, we add an encoder disc. This is a thin wheel with holes around its edge. It sits on the motor shaft, and its edge spins through the gap. Every tooth cuts the beam once, so the OUT pin gives one LOW pulse per tooth.

The disc that comes with most TT gear motors has 20 slots. So 20 pulses mean one full turn. If Arduino Nano counts the pulses for one second, the math is:

RPM = (pulses in one second x 60) / 20

The "x 60" changes seconds into minutes. The "/ 20" changes pulses into turns.

Wiring Diagram

Place the Arduino Nano across the middle of the breadboard, then run three jumper wires from the sensor: VCC to 5V, GND to GND, and OUT to D2, as the picture below shows.

The wiring diagram between Arduino Nano and IR Slotted Optical Speed Sensor

This image is created using Fritzing. Click to enlarge image

See The best way to supply power to the Arduino Nano and other components.

The Nano is a 5V board, so we take power from its 5V pin. The OUT signal then moves between 0V and 5V, and that matches the Nano input pins exactly. You do not need a level shifter or any extra resistor.

How To Program For IR Slotted Optical Speed Sensor

You do not need to install a library. Both sketches use only functions that are already part of the Arduino core.

Part 1: checking the slot with digitalRead()

  • The first step is to specify the Arduino Nano pin that is wired to OUT:
const int SENSOR_PIN = 2;
  • Inside setup(), that pin is set as an input. The module drives the line by itself, so a plain INPUT is enough:
pinMode(SENSOR_PIN, INPUT);
  • Inside loop(), the pin is read over and over. A LOW value tells us the beam is broken:
int state = digitalRead(SENSOR_PIN);
  • The sketch keeps the last value in lastState. It prints and counts only when the new value is not the same as the old one, so one object gives one count, even if it stays in the gap for a long time.

Part 2: catching fast pulses with an interrupt

The Arduino Nano has only two pins that can trigger an external interrupt: D2 and D3. This is why the sensor goes to D2. Any other digital pin works for Part 1, but not for Part 2.

  • The pulse counter is declared with the volatile keyword. This tells the compiler that the value can change at any moment, from outside the normal flow of loop():
volatile unsigned long pulseCount = 0;
  • The interrupt routine does one small job. It adds 1 to the counter and returns:
void countPulse() { pulseCount++; }
  • In setup(), the routine is linked to D2. The FALLING option starts it at the moment OUT drops from HIGH to LOW. That is the moment a tooth enters the gap, so each tooth is counted once:
attachInterrupt(digitalPinToInterrupt(SENSOR_PIN), countPulse, FALLING);
  • Once per second, the sketch copies the counter and sets it back to zero. The ATmega328P chip on the Nano handles 8 bits at a time, so copying a 4-byte number takes several steps. noInterrupts() and interrupts() make sure a new pulse cannot change the number halfway through the copy:
noInterrupts(); unsigned long pulses = pulseCount; pulseCount = 0; interrupts();
  • The last step uses the formula from above:
float rpm = pulses * 60.0 / SLOTS_PER_TURN;

Arduino Nano Code for Counting Objects in the Slot

The sketch below polls D2 in loop(). Each time a new object breaks the beam, it adds one to the count and prints it. When the gap is empty again, it prints a short message.

/* * This Arduino Nano code was developed by newbiely.com * * This Arduino Nano code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano/arduino-nano-ir-slotted-optical-speed-sensor */ const int SENSOR_PIN = 2; // Arduino Nano pin connected to the OUT pin of the speed sensor int lastState; // the previous state of the sensor int objectCount = 0; // how many times the slot was blocked void setup() { Serial.begin(9600); pinMode(SENSOR_PIN, INPUT); lastState = digitalRead(SENSOR_PIN); } void loop() { int state = digitalRead(SENSOR_PIN); if (state != lastState) { // the state has changed if (state == LOW) { // LOW = something is in the slot objectCount++; Serial.print("The slot is blocked - count: "); Serial.println(objectCount); } else { // HIGH = the slot is clear Serial.println("The slot is clear"); } lastState = state; } }

Detailed Instructions

  • If this is the first time you use Arduino Nano, see how to set up the environment for Arduino Nano in Arduino IDE.
  • Wire the components as shown in the diagram.
  • Connect the Arduino Nano board to your computer using a USB cable.
  • Open Arduino IDE on your computer.
  • Choose the Arduino Nano board and the COM port it is using. If the upload fails later, try ATmega328P (Old Bootloader) in the Processor menu.
  • Paste the code above into a new sketch.
  • Press the Upload button and wait for the "Done uploading" message.
  • Open the Serial Monitor and pick 9600 baud.
  • Slide a piece of card, or a finger, into the gap and take it out again. Do this three times.
  • Watch the messages on the Serial Monitor.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Arduino Nano
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Arduino Nano' on 'COM15')
New Line
9600 baud
The slot is blocked - count: 1 The slot is clear The slot is blocked - count: 2 The slot is clear The slot is blocked - count: 3 The slot is clear
Ln 11, Col 1
Arduino Nano on COM15
2

Do you see "blocked" while the gap is empty? Then your module has reversed logic. Swap the LOW and HIGH checks in the code and upload again.

Arduino Nano Code for Measuring Motor Speed (RPM)

A motor with a 20-slot disc can make hundreds of pulses per second. Polling may miss some of them, for example while Serial.print() is busy sending text. With an interrupt, the Nano pauses its current work for a very short time, counts the pulse, and then goes on. Every tooth gets counted.

The sketch prints the number of pulses and the RPM once per second. The constant SLOTS_PER_TURN is 20. If your disc has a different number of holes, count them and put that number in the code.

/* * This Arduino Nano code was developed by newbiely.com * * This Arduino Nano code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano/arduino-nano-ir-slotted-optical-speed-sensor */ const int SENSOR_PIN = 2; // Arduino Nano pin connected to the OUT pin of the speed sensor const int SLOTS_PER_TURN = 20; // number of slots (holes) in the encoder disc volatile unsigned long pulseCount = 0; // changed inside the interrupt unsigned long lastTime = 0; // runs every time a tooth of the disc blocks the slot void countPulse() { pulseCount++; } void setup() { Serial.begin(9600); pinMode(SENSOR_PIN, INPUT); attachInterrupt(digitalPinToInterrupt(SENSOR_PIN), countPulse, FALLING); } void loop() { if (millis() - lastTime >= 1000) { // every 1 second lastTime = millis(); noInterrupts(); // read and reset the counter safely unsigned long pulses = pulseCount; pulseCount = 0; interrupts(); float rpm = pulses * 60.0 / SLOTS_PER_TURN; // pulses per second -> turns per minute Serial.print("Pulses: "); Serial.print(pulses); Serial.print(" | Speed: "); Serial.print(rpm); Serial.println(" RPM"); } }

Detailed Instructions

  • Do not change the wiring from the first sketch. OUT must stay on D2. D3 is the only other choice on the Nano; if you use it, set SENSOR_PIN to 3.
  • Mount the encoder disc on the motor shaft or wheel. Line it up so the teeth run through the middle of the gap and do not rub the plastic.
  • Paste the RPM code into Arduino IDE and upload it to the Nano.
  • Open the Serial Monitor at 9600 baud.
  • Turn the disc with your hand, or switch on the motor. The Arduino Nano - DC Motor tutorial shows how to drive a motor from the Nano.
  • Read the speed on the Serial Monitor.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Arduino Nano
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Arduino Nano' on 'COM15')
New Line
9600 baud
Pulses: 0 | Speed: 0.00 RPM Pulses: 98 | Speed: 294.00 RPM Pulses: 101 | Speed: 303.00 RPM Pulses: 100 | Speed: 300.00 RPM Pulses: 99 | Speed: 297.00 RPM Pulses: 0 | Speed: 0.00 RPM
Ln 11, Col 1
Arduino Nano on COM15
2

Here the motor turns at about 300 RPM. Take the line with 98 pulses: 98 x 60 = 5880 pulses per minute, and 5880 / 20 = 294 RPM. The 0 lines at the top and bottom were printed before the motor started and after it stopped.

Good habits for interrupt code on the Nano:

  • Mark every variable that the interrupt routine changes as volatile.
  • Keep the routine tiny. Never put delay() or Serial.print() inside it.
  • Stay with FALLING. CHANGE would fire twice per tooth and double your RPM.

Additional Knowledge

Which Sensor Should You Pick?

A slot sensor, an IR obstacle sensor and a rotary encoder can all give pulses to Arduino Nano. Still, each one solves a different problem. Ask yourself these questions:

  • Does the object pass through a small, fixed gap (a disc tooth, a flag on a moving part)? Pick the IR slotted optical speed sensor. It gives one clean digital signal for each pass.
  • Is the object somewhere in front of the sensor, not inside a gap (a wall, a hand, a box on a table)? Pick the IR obstacle avoidance sensor. It sees reflected light in open space.
  • Does a person turn a knob, and does the code need the direction (left or right)? Pick the rotary encoder. It has two outputs (CLK and DT) and a push button.

It is evident that the slotted sensor gives the most reliable count for fast spinning parts, since the target always crosses the same 5.9 mm gap at the same place. Its only limit is that it cannot tell the direction of rotation.

Two Wheels, Two Sensors

A small robot car often has two driven wheels. The Nano has exactly two interrupt pins, so one sensor can go on D2 and a second sensor on D3. Each sensor then needs its own counter and its own interrupt routine. Keep this in mind before you plan the rest of the robot: if D2 and D3 are already used by other parts, move those parts to other pins, because no other Nano pin can do this job.

Troubleshooting

Problem What to check
Count never changes Check that OUT goes to D2 and VCC goes to 5V. Read the pin labels on your module, because the order is not the same on every batch.
"Blocked" when the gap is empty Your module uses reversed logic. Swap LOW and HIGH in the first sketch.
RPM is always 0 The disc teeth may not reach the gap. Move the sensor so the teeth pass through the middle of the slot.
RPM jumps up and down Make sure the disc is tight on the shaft and does not wobble or touch the sensor.
RPM is too high or too low SLOTS_PER_TURN does not match your disc. Count the holes and fix the constant.

Video Tutorial

Function References

※ OUR MESSAGES

  • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!