Building a reliable remote control with Arduino requires more than just copying legacy code from a decade-old forum post. The infrared (IR) ecosystem has evolved, and modern libraries handle carrier frequencies and protocol decoding differently. This guide walks through building a 4-channel IR remote control with Arduino to drive a 5V relay module, using the modern IRremote v4.x API. We will cover exact component selection, precise wiring, compilable code with protocol filtering, and a dedicated debugging section to solve the most common compile and runtime failures.
Parts List & Spec Sheet
Generic IR receivers often suffer from poor ambient light rejection. For a robust build, we specify the Vishay TSOP38238 instead of the unbranded "1838T" modules found in cheap starter kits. The TSOP series includes built-in filters against fluorescent lighting and optical noise.
| Component | Exact Variant / Part Number | Specification Notes | Est. Cost (2026) |
|---|---|---|---|
| Microcontroller | Arduino Nano (ATmega328P) | 5V logic, 16MHz. Do not use the Nano 33 IoT (3.3V) without logic level shifters for 5V relays. | $12.00 |
| IR Receiver | Vishay TSOP38238 | 38kHz carrier, optimized for NEC protocol. Requires 4.7µF decoupling capacitor. | $1.50 |
| Relay Module | 4-Channel 5V Relay (Optocoupler Isolated) | Active LOW trigger, 10A/250VAC contacts. Must have JD-VCC jumper removed for safe isolation. | $6.50 |
| IR Remote | Standard 24-Key NEC Remote | Commonly bundled with MP3 decoder modules. Uses NEC protocol. | $2.00 |
| Decoupling Cap | 4.7µF Electrolytic (16V+) | Placed across VCC and GND of the IR receiver to prevent brownouts during signal bursts. | $0.10 |
Pin Mapping & Wiring Steps
The Arduino Nano operates at 5V, which perfectly matches the logic requirements of standard 5V relay modules and the TSOP38238 receiver.
| Arduino Nano Pin | Component | Function |
|---|---|---|
| D2 | TSOP38238 (OUT) | IR Data Input (Hardware interrupt capable) |
| D4 | Relay IN1 | Channel 1 Control (Active LOW) |
| D5 | Relay IN2 | Channel 2 Control (Active LOW) |
| D6 | Relay IN3 | Channel 3 Control (Active LOW) |
| D7 | Relay IN4 | Channel 4 Control (Active LOW) |
| 5V | TSOP38238 (VCC) | Receiver Power (with 4.7µF cap to GND) |
| GND | Common Ground | Shared between Nano, Receiver, and Relay GND |
- Seat the Nano: Insert the Arduino Nano into the breadboard, ensuring the USB port faces the edge for cable clearance.
- Wire the IR Receiver: Connect the TSOP38238. Pin 1 (OUT) goes to Nano D2. Pin 2 (GND) to Nano GND. Pin 3 (VCC) to Nano 5V. Solder or insert the 4.7µF capacitor directly across the VCC and GND legs of the receiver.
- Wire the Relay Module: Connect IN1 through IN4 to Nano D4-D7. Connect the module's GND to the Nano GND. Crucial: If your relay module has a "JD-VCC" jumper, remove it and wire the JD-VCC pin directly to your external 5V power supply to maintain optocoupler isolation.
- Verify Dead: Before applying mains voltage to the relay contact side, use a multimeter in continuity mode to verify your load wiring is isolated from the low-voltage DC side.
Complete Arduino Code (IRremote v4.x)
This code targets the Arduino Nano (ATmega328P) and requires the IRremote library (v4.3.0 or newer). It uses the modern API, filtering specifically for the NEC protocol to ignore stray IR noise from sunlight or incandescent bulbs.
#include
// --- PIN DEFINITIONS ---
const int IR_RECEIVE_PIN = 2;
const int RELAY_PINS[4] = {4, 5, 6, 7};
// --- NEC COMMAND MAPPINGS (Standard 24-Key Remote) ---
// Use Serial Monitor to verify these match your specific remote
const uint16_t CMD_RELAY_1 = 0x16; // Button '1' or 'CH-'
const uint16_t CMD_RELAY_2 = 0x19; // Button '2' or 'CH'
const uint16_t CMD_RELAY_3 = 0x0D; // Button '3' or 'CH+'
const uint16_t CMD_RELAY_4 = 0x0C; // Button '4' or 'PREV'
// Track relay states (false = OFF/HIGH, true = ON/LOW for active-low relays)
bool relayStates[4] = {false, false, false, false};
void setup() {
Serial.begin(115200);
// Initialize Relay Pins as OUTPUT and set to HIGH (OFF state for active-low)
for (int i = 0; i < 4; i++) {
pinMode(RELAY_PINS[i], OUTPUT);
digitalWrite(RELAY_PINS[i], HIGH);
}
// Start IR Receiver with LED feedback disabled to save processing cycles
IrReceiver.begin(IR_RECEIVE_PIN, DISABLE_LED_FEEDBACK);
Serial.println("IR Remote Control Ready. Waiting for NEC signals...");
}
void loop() {
if (IrReceiver.decode()) {
// Error Handling: Ignore repeat frames to prevent rapid toggling
if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT) {
IrReceiver.resume();
return;
}
// Filter: Only process NEC protocol signals
if (IrReceiver.decodedIRData.protocol == NEC) {
uint16_t command = IrReceiver.decodedIRData.command;
int targetRelay = -1;
if (command == CMD_RELAY_1) targetRelay = 0;
else if (command == CMD_RELAY_2) targetRelay = 1;
else if (command == CMD_RELAY_3) targetRelay = 2;
else if (command == CMD_RELAY_4) targetRelay = 3;
// Toggle the target relay if a valid command was matched
if (targetRelay != -1) {
relayStates[targetRelay] = !relayStates[targetRelay];
digitalWrite(RELAY_PINS[targetRelay], relayStates[targetRelay] ? LOW : HIGH);
Serial.print("Relay ");
Serial.print(targetRelay + 1);
Serial.println(relayStates[targetRelay] ? " ENGAGED" : " DISENGAGED");
}
} else {
Serial.print("Ignored non-NEC protocol: ");
Serial.println(IrReceiver.decodedIRData.protocol);
}
// Resume receiving
IrReceiver.resume();
}
}
Debugging: First Three Things to Check When It Fails
IR projects frequently fail due to library version mismatches or power rail errors. If your remote control with Arduino is unresponsive, run through this diagnostic sequence.
1. The Compile Error: 'decode_results' does not name a type
Ranked Causes:
1. Outdated Code Syntax: You are using code written for IRremote v2.x or v3.x, but the Arduino IDE installed the modern v4.x library. The decode_results struct was entirely removed in v4.0.
2. Missing Include: You typed #include <IRremote.h> instead of the modern #include <IRremote.hpp>.
The Fix: Delete your old code and use the v4.x code block provided above. Do not attempt to downgrade the library via the Library Manager; the v4 API is vastly superior at handling memory and interrupts on the ATmega328P.
2. The Hardware Fault: Receiver Outputs Random Noise
Ranked Causes:
1. Missing Decoupling Capacitor: The TSOP38238 draws sudden current spikes when demodulating 38kHz bursts. Without the 4.7µF capacitor, the VCC rail sags, causing the internal AGC (Automatic Gain Control) to panic and output garbage.
2. 3.3V vs 5V Logic Mismatch: If you accidentally wired the receiver to the Nano's 3.3V pin, it will not operate. The TSOP38238 requires a minimum of 2.5V but performs optimally and interfaces cleanly with 5V logic at 5V.
3. Ambient CFL Interference: Compact Fluorescent Lamps emit broadband IR noise that overlaps the 38kHz band.
The Fix: Verify the capacitor is seated. Move the receiver away from desk lamps. Add a piece of heat-shrink tubing over the receiver dome to act as an optical bandpass filter.
3. The Logic Fault: Relays Chatter or Do Not Toggle
Ranked Causes:
1. Repeat Frame Processing: Holding the remote button sends a continuous stream of "REPEAT" flags. If your code doesn't filter these, the relay will toggle on and off 50 times a second, destroying the mechanical contacts.
2. Active-HIGH vs Active-LOW: Most optocoupler relay modules are Active-LOW. Sending HIGH turns them OFF. If your module is Active-HIGH, invert the digitalWrite logic in the code.
The Fix: Ensure the IRDATA_FLAGS_IS_REPEAT check is present in the code (as provided above). Check your relay module datasheet for trigger logic.
Extending or Simplifying the Build
Depending on your final application, you may need to adjust the complexity of this remote control with Arduino.
How to Extend (IoT Bridging): To integrate this IR-controlled relay bank into a smart home, add an ESP-01S (ESP8266) module. Wire the ESP-01S TX/RX to the Nano's D10/D11 using the SoftwareSerial library. When the Nano toggles a relay via IR, it sends a serial string to the ESP-01S, which publishes the state change to an MQTT broker (like Mosquitto). This allows Home Assistant to track the physical state of the relays even when controlled by the physical IR remote.
FAQ: Remote Control with Arduino
Can I use any TV remote for a remote control with Arduino?
Yes, but you must identify the protocol. Most modern Samsung and LG TVs use proprietary protocols or RC6, while older Sony remotes use SIRC. The IRremote v4 library supports almost all of them, but you must change the if (IrReceiver.decodedIRData.protocol == NEC) line in the code to match your remote's protocol (e.g., == SONY or == RC5). Always run the raw serial dump first to confirm the protocol and command bytes.
Why does my Arduino IR receiver pick up random signals when no remote is pressed?
This is almost always caused by optical noise. Direct sunlight contains massive amounts of infrared radiation. Furthermore, older CFL bulbs and some cheap LED drivers emit high-frequency noise that the receiver's AGC misinterprets as a 38kHz carrier signal. To fix this, ensure your code explicitly checks for a valid protocol (like NEC) and ignores UNKNOWN protocol results, rather than triggering actions on any raw hex value received.
How far can the IR remote control with Arduino reliably reach?
With a standard 24-key remote and a Vishay TSOP38238 receiver, expect a reliable line-of-sight range of 5 to 8 meters (16-26 feet) indoors. Range degrades significantly if the receiver is placed behind dark tinted acrylic or if the remote's IR LED is degraded. If you need to exceed 10 meters, you must build a custom transmitter using a high-power IR LED (like the TSAL6200) driven by a MOSFET, rather than relying on the remote's coin-cell-powered LED.
Is RF (433MHz) better than IR for Arduino remote control projects?
It depends entirely on the environment. RF (using modules like the SYN480R receiver and SC2262 encoder) penetrates walls and does not require line-of-sight, making it superior for whole-home lighting or garage door triggers. However, 433MHz is heavily congested by weather stations, tire pressure monitors, and neighboring garage openers, requiring robust software debouncing and address filtering. IR is strictly line-of-sight but is completely immune to RF congestion and requires zero FCC compliance considerations for hobbyist builds.






