Remote stepper, a whole turn a press, on an Arduino Uno
An IR receiver on pin 12 and a 28BYJ-48 on its ULN2003 board, pins 8 to 11: >>| on the remote turns the shaft one whole turn, >|| turns it back. The whole build, an Arduino Uno and 3 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.
Intermediate About 25 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $35. On Mokxi they're free.
What you'll learn
- Reading IR commands with the IRremote library
- Stepper steps per turn on a 28BYJ-48
- Named constants for remote button codes
- Pin order quirks with the Stepper library
- Difficulty: Intermediate
- Time: About 25 minutes
- Board: Arduino Uno R3
- Parts: 5
How it works
An IR receiver on pin 12 decodes the remote. The >>| button, command 0x40, turns a 28BYJ-48 stepper a whole turn clockwise. The >|| button, command 0x43, turns it a whole turn back. A whole turn is 2048 steps.
The ULN2003 driver board is on pins 8 to 11. After each move, release turns the coil pins off. Held buttons are ignored, and presses that arrive while the motor is turning are thrown away when it finishes.
Parts list
5 parts, plus the jumper wires. They retail for about $35; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Half breadboard
- 1 × Stepper motor, 28BYJ-48 with ULN2003
- 1 × Infrared receiver, VS1838B
- 1 × Infrared remote, 21 buttons
Kits that can build it
These 7 starter kits have every part in the circuit. Each kit's page lists what else it can build.
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 pin | Connects to |
|---|---|
| Infrared receiver, VS1838B pin OUT | Arduino Uno R3 pin 12 |
| Stepper motor, 28BYJ-48 with ULN2003 pin IN4 | Arduino Uno R3 pin 11 |
| Stepper motor, 28BYJ-48 with ULN2003 pin IN3 | Arduino Uno R3 pin 10 |
| Stepper motor, 28BYJ-48 with ULN2003 pin IN2 | Arduino Uno R3 pin 9 |
| Stepper motor, 28BYJ-48 with ULN2003 pin IN1 | Arduino Uno R3 pin 8 |
| Stepper motor, 28BYJ-48 with ULN2003 pin VCC | Arduino Uno R3 pin 5V |
| Infrared receiver, VS1838B pin VCC | Arduino Uno R3 pin 5V |
| Stepper motor, 28BYJ-48 with ULN2003 pin GND | Arduino Uno R3 pin GND |
| Infrared receiver, VS1838B pin GND | Arduino Uno R3 pin GND |
| Infrared remote, 21 buttons pin IR | Infrared receiver, VS1838B pin IR |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Remote stepper: two buttons on the IR remote turn a stepper a whole turn.
//
// IR receiver S (OUT) -> pin 12, - -> GND, + -> 5V
// ULN2003 board IN1 -> pin 8, IN2 -> pin 9, IN3 -> pin 10, IN4 -> pin 11
// + -> 5V, - -> GND
//
// Press >>| (the remote's command 0x40) and the shaft turns one whole turn
// clockwise; press >|| (command 0x43) and it turns one whole turn back. The
// 28BYJ-48 takes 2048 steps for one turn of its output shaft.
//
// The Stepper library wants the pins in the order IN1, IN3, IN2, IN4: that
// is why the constructor below says 8, 10, 9, 11.
// The handset speaks NEC, so only that decoder is compiled in, as IRremote's
// own examples do to save flash.
#define DECODE_NEC
#include <IRremote.hpp>
#include <Stepper.h>
const int RECEIVER_PIN = 12;
const int STEPS_PER_TURN = 2048;
const uint8_t TURN_FORWARD = 0x40;
const uint8_t TURN_BACK = 0x43;
Stepper motor(STEPS_PER_TURN, 8, 10, 9, 11);
void release() {
// Let the coils go after a move, so the driver stays cool.
for (int pin = 8; pin <= 11; pin++) digitalWrite(pin, LOW);
}
void setup() {
Serial.begin(9600);
IrReceiver.begin(RECEIVER_PIN, ENABLE_LED_FEEDBACK);
motor.setSpeed(15);
Serial.println("Mokxi Uno: remote stepper. >>| turns it forward, >|| back.");
}
void loop() {
if (!IrReceiver.decode()) return;
bool repeat = IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT;
uint8_t command = IrReceiver.decodedIRData.command;
IrReceiver.resume();
if (repeat) return;
if (command == TURN_FORWARD) {
Serial.println("one turn clockwise");
motor.step(STEPS_PER_TURN);
release();
} else if (command == TURN_BACK) {
Serial.println("one turn back");
motor.step(-STEPS_PER_TURN);
release();
} else {
Serial.print("button 0x");
Serial.print(command, HEX);
Serial.println(" does nothing here");
}
// Any presses that came in while the motor turned are old news.
IrReceiver.resume();
}
Code walkthrough
The key functions of the sketch, and what each one does.
release sketch.ino
Sets pins 8 to 11 LOW after a move, so the coils are not left energized and the driver does not get hot.
void release() {
// Let the coils go after a move, so the driver stays cool.
for (int pin = 8; pin <= 11; pin++) digitalWrite(pin, LOW);
}setup sketch.ino
Opens serial, starts the receiver on pin 12 with LED feedback and sets the motor to 15 rpm. It prints which buttons turn the shaft forward and back.
void setup() {
Serial.begin(9600);
IrReceiver.begin(RECEIVER_PIN, ENABLE_LED_FEEDBACK);
motor.setSpeed(15);
Serial.println("Mokxi Uno: remote stepper. >>| turns it forward, >|| back.");
}loop sketch.ino
Gets a decoded IR code if one is ready, ignoring repeats. TURN_FORWARD steps STEPS_PER_TURN forward and TURN_BACK steps the same amount back, each followed by release. Other buttons print their code. A final IrReceiver.resume drops presses made mid-move.
void loop() {
if (!IrReceiver.decode()) return;
bool repeat = IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT;
uint8_t command = IrReceiver.decodedIRData.command;
IrReceiver.resume();
if (repeat) return;
if (command == TURN_FORWARD) {
Serial.println("one turn clockwise");
motor.step(STEPS_PER_TURN);
release();
} else if (command == TURN_BACK) {
Serial.println("one turn back");
motor.step(-STEPS_PER_TURN);
release();
} else {
Serial.print("button 0x");
Serial.print(command, HEX);
Serial.println(" does nothing here");
}
// Any presses that came in while the motor turned are old news.
IrReceiver.resume();
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The motor hums and does not turn This project
The Stepper constructor needs 8, 10, 9, 11, meaning IN1, IN3, IN2, IN4. Keep it that way. - A button does nothing This project
Check the serial monitor for the code it prints. Your remote's codes must matchTURN_FORWARDandTURN_BACK. - A turn takes a long time This project
A whole turn is 2048 steps at 15 rpm, so it takes a few seconds. That is expected. - The motor buzzes or shakes and does not turn. The coil pins IN1 to IN4 are in the wrong order for the library. Stepper motor
For Arduino's Stepper library on a 28BYJ-48, create it with pins 8, 10, 9, 11 (IN1, IN3, IN2, IN4). Or use AccelStepper with HALF4WIRE and the same pin order. - It stalls or skips when spun fast or powered from the Arduino 5 V pin. It also draws more than a USB port may give. Stepper motor
Power the ULN2003 board from a separate 5 V supply and join the grounds. Run it slowly, about 10 to 15 RPM, and ramp up speed gradually. - No signal is seen, or the module gets hot, because the three legs are in the wrong order. Infrared receiver
On the VS1838B, with the dome facing you, the legs are usually OUT, GND, VCC from left to right. Check your module's marking before powering it. Supply is 2.7 to 5.5 V. - A plain LED blinking at the receiver is never detected. Infrared receiver
The receiver only responds to light modulated at about 38 kHz. Send with a library such as IRremote, which makes the carrier. OUT idles high and goes low during a burst, so decode that inverted signal. - Button codes come out wrong or do not match another sketch. Infrared remote
Remotes differ. Print the raw codes for your buttons first, then compare against those values. A repeat while you hold a button is a special repeat code, not a new press.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.