Project 3.2: "IR Transmission Between R32"
🚀 Project 3.2 – IR Transmission Between R32
🎯 What you’ll learn
- ✅ Goal 1: Send an IR command from one D1 R32 to another and see it in the serial monitor
- ✅ Goal 2: Confirm reception with clean messages and build a simple “START/STOP” protocol
- ✅ Goal 3: Send multiple values and make a two‑way confirmation (handshake)
Key ideas
- Short definition: IR communication sends small codes using invisible light.
- Real‑world link: TV remotes use IR to change channels or volume.
🧱 Blocks glossary (used in this project)
- IR send: Transmits an infrared code (like pressing a remote button).
- IR receive: Listens for IR codes and reads them when they arrive.
- Serial print: Shows status and data on your computer screen.
- Variable: Stores a number like a command code.
- if / else: Makes a choice based on what was received.
- Loop: Keeps checking or sending again and again.
🧰 What you need
| Part | How many? | Pin connection |
|---|---|---|
| D1 R32 (Sender) | 1 | USB cable |
| D1 R32 (Receiver) | 1 | USB cable |
| IR Transmitter Module | 1 | Pin 26 (Sender) |
| IR Receiver Module | 1 | Pin 26 (Receiver) |
🔌 Wiring tip: Point the transmitter at the receiver, 20–50 cm apart, with a clear line of sight.
📍 Pin map snapshot: Pin 26 reserved for IR in this project. Other pins remain free.
✅ Before you start
- Open two serial monitors (one per board): label them “Sender” and “Receiver”.
- Test print shows:
print("Ready!") # Confirm serial is working
🎮 Microprojects (5 mini missions)
🎮 Microproject 3.2.1 – Sending a simple IR command (Sender)
Goal: Transmit one IR command (hex) from the sender board.
Blocks used:
- IR send: Transmit one code
- Serial print: Announce the send
Block sequence:
- Setup IR transmitter on Pin 26
- Choose a command (0x45 = “1”)
- Transmit the command
- Print confirmation
MicroPython code (Sender):
# Microproject 3.2.1 – Sender: Send one IR command
import irremote # Load IR communication library
import time # Load time library for delays
ir_tx = irremote.NEC_TX(26, False, 100) # Create IR transmitter on Pin 26, not inverted, power 100%
print("[Sender] IR TX ready on Pin 26") # Confirm transmitter ready
cmd = 0x45 # Choose command code: 0x45 (IR remote '1')
addr = 0x00 # Use simple address 0 for demo
ctrl = 0x00 # Use simple control 0 for demo
print("[Sender] Sending CMD=0x45") # Announce the command to send
ir_tx.transmit(addr, cmd, ctrl) # Transmit (address, command, control)
print("[Sender] Command sent!") # Confirm send
time.sleep_ms(1000) # Wait to avoid spamming
Reflection: You sent a number using invisible light—just like a TV remote.
Challenge:
- Easy: Change the command to 0x46 (“2”).
- Harder: Send the command every 2 seconds inside a loop.
🎮 Microproject 3.2.2 – Reception and confirmation (Receiver)
Goal: Detect the incoming IR code and show it on the serial monitor.
Blocks used:
- IR receive: Listen for codes
- Serial print: Show received value
Block sequence:
- Setup IR receiver on Pin 26
- Check for any incoming code
- If available, read and print it
- Repeat in a loop
MicroPython code (Receiver):
# Microproject 3.2.2 – Receiver: Listen and print incoming IR code
import irremote # Load IR communication library
import time # Load time library for delays
ir_rx = irremote.NEC_RX(26, 8) # Create IR receiver on Pin 26 with buffer size 8
print("[Receiver] IR RX ready on Pin 26") # Confirm receiver ready
while True: # Start continuous listening loop
if ir_rx.any(): # Check if any IR code has arrived
received_code = ir_rx.code[0] # Read the first code from the buffer
print("[Receiver] Received:", hex(received_code)) # Show code in hex
else: # If no code available
print("[Receiver] Waiting...") # Print waiting status
time.sleep_ms(400) # Delay for readable updates
Reflection: Your receiver board “heard” the sender’s code—teamwork!
Challenge:
- Easy: Only print when data arrives (remove “Waiting…”).
- Harder: Add a counter that increments every time a code is received.
🎮 Microproject 3.2.3 – Basic communication protocol (START/STOP)
Goal: Map specific codes to actions: START (0x45) and STOP (0x46).
Blocks used:
- IR send: Transmit labeled actions
- IR receive: Decode and map
- if / else: Decide action
Block sequence:
- Sender sends START (0x45) then STOP (0x46)
- Receiver reads and prints action labels
- Repeat with timing
- Clear logs to stay readable
MicroPython code (Sender):
# Microproject 3.2.3 – Sender: Send START and STOP with IR
import irremote # Load IR communication library
import time # Load time library for delays
ir_tx = irremote.NEC_TX(26, False, 100) # Create IR transmitter on Pin 26
print("[Sender] Protocol TX ready") # Confirm transmitter ready
addr = 0x00 # Use simple address for demo
ctrl = 0x00 # Use simple control for demo
print("[Sender] START=0x45, STOP=0x46") # Show mapping for clarity
ir_tx.transmit(addr, 0x45, ctrl) # Send START code
print("[Sender] Sent START (0x45)") # Confirm START sent
time.sleep_ms(1200) # Wait 1.2 seconds
ir_tx.transmit(addr, 0x46, ctrl) # Send STOP code
print("[Sender] Sent STOP (0x46)") # Confirm STOP sent
time.sleep_ms(1200) # Wait 1.2 seconds
MicroPython code (Receiver):
# Microproject 3.2.3 – Receiver: Decode START/STOP
import irremote # Load IR communication library
import time # Load time library for delays
ir_rx = irremote.NEC_RX(26, 8) # Create IR receiver on Pin 26
print("[Receiver] Protocol RX ready") # Confirm receiver ready
while True: # Start decoding loop
if ir_rx.any(): # If a code arrived
code_value = ir_rx.code[0] # Read the first buffered code
print("[Receiver] Raw:", hex(code_value)) # Show raw hex code
if code_value == 0x45: # If equals START code
print("[Receiver] ACTION: START") # Announce START
elif code_value == 0x46: # If equals STOP code
print("[Receiver] ACTION: STOP") # Announce STOP
else: # Otherwise unknown
print("[Receiver] ACTION: UNKNOWN") # Mark unknown
else: # No code this cycle
print("[Receiver] Listening...") # Keep listening message
time.sleep_ms(400) # Delay for readability
Reflection: You turned numbers into clear actions—your first IR protocol.
Challenge:
- Easy: Add PAUSE with 0x47 and print it.
- Harder: Ignore duplicate codes by spacing sends at least 500 ms.
🎮 Microproject 3.2.4 – Sending multiple data (sequence)
Goal: Send a small sequence [0x45, 0x46, 0x47] and print each one received.
Blocks used:
- IR send: Transmit codes in a loop
- Loop: Iterate over the sequence
- Serial print: Show progress on both boards
Block sequence:
- Sender loops through list of codes
- Send each code with delay
- Receiver prints each arrival with a counter
- Keep logs short
MicroPython code (Sender):
# Microproject 3.2.4 – Sender: Send sequence [0x45, 0x46, 0x47]
import irremote # Load IR communication library
import time # Load time library for delays
ir_tx = irremote.NEC_TX(26, False, 100) # Create IR transmitter on Pin 26
print("[Sender] TX ready for sequence") # Confirm transmitter ready
addr = 0x00 # Use simple address
ctrl = 0x00 # Use simple control
seq = [0x45, 0x46, 0x47] # Define sequence codes
print("[Sender] Sequence:", [hex(x) for x in seq]) # Show sequence in hex
for item in seq: # Loop through each code
print("[Sender] Sending:", hex(item)) # Announce current code
ir_tx.transmit(addr, item, ctrl) # Send the code
time.sleep_ms(700) # Wait 0.7 seconds between sends
MicroPython code (Receiver):
# Microproject 3.2.4 – Receiver: Count received sequence items
import irremote # Load IR communication library
import time # Load time library for delays
ir_rx = irremote.NEC_RX(26, 8) # Create IR receiver on Pin 26
print("[Receiver] RX ready for sequence") # Confirm receiver ready
count = 0 # Initialize counter of received items
while True: # Start listening loop
if ir_rx.any(): # If a code arrived
code_item = ir_rx.code[0] # Read the first buffered code
count = count + 1 # Increase count by 1
print("[Receiver] #", count, "code:", hex(code_item)) # Show count and code
else: # If nothing yet
print("[Receiver] Waiting for next...") # Print waiting message
time.sleep_ms(350) # Delay for readable updates
Reflection: You sent and tracked a tiny “message” made of three IR codes.
Challenge:
- Easy: Change delay to 300 ms and test reliability.
- Harder: Require the receiver to detect all three, then print “Sequence OK”.
🎮 Microproject 3.2.5 – Two‑way communication (handshake)
Goal: Receiver replies with CONFIRM (0x1C), and sender waits for ACK.
Blocks used:
- IR receive: Listen for incoming request
- IR send: Reply with CONFIRM
- if / else: Check for the expected ACK
Block sequence:
- Sender sends REQUEST (e.g., 0x45)
- Receiver gets REQUEST and sends CONFIRM (0x1C)
- Sender waits for CONFIRM and prints “ACK received”
- Add timeout
MicroPython code (Receiver → confirms back):
# Microproject 3.2.5 – Receiver: Send confirmation (0x1C) after receiving any code
import irremote # Load IR communication library
import time # Load time library for delays
ir_rx = irremote.NEC_RX(26, 8) # Create IR receiver on Pin 26
ir_tx = irremote.NEC_TX(26, False, 100) # Create IR transmitter on Pin 26
print("[Receiver] Ready: RX+TX on Pin 26") # Confirm both RX and TX ready
addr = 0x00 # Use simple address
ctrl = 0x00 # Use simple control
confirm_cmd = 0x1C # Confirmation code (IR remote 'OK')
while True: # Start handshake loop
if ir_rx.any(): # If any code arrived
incoming = ir_rx.code[0] # Read first buffered code
print("[Receiver] Got:", hex(incoming)) # Show received code
print("[Receiver] Reply:", hex(confirm_cmd)) # Announce confirmation code
ir_tx.transmit(addr, confirm_cmd, ctrl) # Send confirmation via IR
else: # If no code now
print("[Receiver] Waiting for request...") # Print waiting message
time.sleep_ms(500) # Delay for timing and readability
MicroPython code (Sender → waits for ACK):
# Microproject 3.2.5 – Sender: Send request and wait for confirmation (ACK)
import irremote # Load IR communication library
import time # Load time library for delays
ir_tx = irremote.NEC_TX(26, False, 100) # Create IR transmitter on Pin 26
ir_rx = irremote.NEC_RX(26, 8) # Create IR receiver on Pin 26
print("[Sender] Ready: TX+RX on Pin 26") # Confirm both TX and RX ready
addr = 0x00 # Use simple address
ctrl = 0x00 # Use simple control
request_cmd = 0x45 # Request code (e.g., '1')
ack_cmd = 0x1C # Expected confirmation ('OK')
print("[Sender] Request:", hex(request_cmd)) # Announce request code
ir_tx.transmit(addr, request_cmd, ctrl) # Send request via IR
wait_steps = 0 # Initialize wait counter
while wait_steps < 10: # Check up to 10 times
if ir_rx.any(): # If any code was received
received = ir_rx.code[0] # Read first buffered code
print("[Sender] Received:", hex(received)) # Show received code
if received == ack_cmd: # If matches expected ACK
print("[Sender] ACK received!") # Print success message
break # Exit loop on success
else: # If no code this cycle
print("[Sender] Waiting for ACK...") # Print waiting status
time.sleep_ms(300) # Delay between checks
wait_steps = wait_steps + 1 # Increase wait counter
Reflection: You built a handshake: request → confirm → success—real protocol design.
Challenge:
- Easy: Change CONFIRM to 0x18 (UP) and retest.
- Harder: Add a timeout message if no ACK after 3 seconds.
✨ Main project – Basic IR communication protocol between two R32
🔧 Blocks steps (with glossary)
- IR send: Sender transmits “START” then “STOP”.
- IR receive: Receiver decodes and prints actions.
- Serial print: Clear logs of send/receive.
- if / else: Map codes to labels and handle confirmation.
Block sequence:
- Sender: Setup IR TX (Pin 26) → send 0x45 (“START”).
- Receiver: Setup IR RX (Pin 26) → read and print action.
- Sender: Send 0x46 (“STOP”).
- Receiver: Read and print action.
- Extend with confirmation (0x1C) as optional handshake.
🐍 MicroPython code (mirroring blocks)
# Project 3.2 – IR Transmission Between R32: Mini Protocol Demo
import irremote # Load IR communication library
import time # Load time library for delays
# Setup IR transmitter on Sender
ir_tx = irremote.NEC_TX(26, False, 100) # Create IR transmitter on Pin 26
print("[Sender] IR TX ready on 26") # Confirm TX ready
# Setup IR receiver on Receiver
ir_rx = irremote.NEC_RX(26, 8) # Create IR receiver on Pin 26
print("[Receiver] IR RX ready on 26") # Confirm RX ready
# Sender: Transmit START (0x45)
print("[Sender] TX START (0x45)") # Announce sending START
ir_tx.transmit(0x00, 0x45, 0x00) # Send address=0x00, command=0x45, control=0x00
time.sleep_ms(800) # Wait for receiver
# Receiver: Read first code if available
if ir_rx.any(): # Check if a code is available
code1 = ir_rx.code[0] # Read the first buffered code
print("[Receiver] Got:", hex(code1)) # Show code in hex
if code1 == 0x45: # If equals START
print("[Receiver] ACTION: START") # Announce START
else: # Otherwise unknown
print("[Receiver] ACTION: UNKNOWN") # Announce unknown
else: # If nothing arrived yet
print("[Receiver] No data") # Inform no data
# Sender: Transmit STOP (0x46)
print("[Sender] TX STOP (0x46)") # Announce sending STOP
ir_tx.transmit(0x00, 0x46, 0x00) # Send address=0x00, command=0x46, control=0x00
time.sleep_ms(800) # Wait for receiver
# Receiver: Read second code if available
if ir_rx.any(): # Check if a code is available
code2 = ir_rx.code[0] # Read the first buffered code
print("[Receiver] Got:", hex(code2)) # Show code in hex
if code2 == 0x46: # If equals STOP
print("[Receiver] ACTION: STOP") # Announce STOP
else: # Otherwise unknown
print("[Receiver] ACTION: UNKNOWN") # Announce unknown
else: # If nothing arrived yet
print("[Receiver] No data") # Inform no data
📖 External explanation
- What it teaches: How to send and receive IR codes and label them as actions.
- Why it works: The sender encodes a number; the receiver reads it and maps it to a known meaning (START/STOP).
- Key concept: Small, clear codes (hex values) make reliable communication.
✨ Story time
Two robots, one message beam. Your sender whispers “START” and “STOP” in light, and the receiver acts—like mission control.
🕵️ Debugging (2 common problems)
🐞 Debugging 3.2.A – IR signal not arriving
Problem: Receiver prints “No data” even though the sender is transmitting.
Clues: No “[Receiver] Got:” messages appear.
Broken code:
ir_rx = irremote.NEC_RX(23, 8) # Wrong pin (receiver wired to 26)
Fixed code:
ir_rx = irremote.NEC_RX(26, 8) # Correct pin (use Pin 26 as wired)
Why it works: The code must match the physical pin the IR module uses.
Avoid next time: Check pin numbers and aim the modules directly at each other.
🐞 Debugging 3.2.B – Corrupt or unknown codes
Problem: “[Receiver] ACTION: UNKNOWN” appears for expected sends.
Clues: Raw hex values don’t match 0x45 or 0x46.
Broken code:
if ir_rx.any():
print(ir_rx.code) # Prints whole buffer without checking a valid entry
Fixed code:
if ir_rx.any():
rx_code = ir_rx.code[0] # Read first valid code from buffer
if rx_code == 0x45: print("START") # Compare against known hex codes
Why it works: Reading a single valid entry avoids noise or old buffer values.
Avoid next time: Use small delays and compare to known hex codes.
✅ Final checklist
- I sent at least one IR command and saw it on the receiver
- I mapped codes to actions like START and STOP
- I created a handshake with a confirmation code or tested the sequence
📚 Extras
- 🧠 Student tip: Test in a dim room and keep modules close—IR is light.
- 🧑🏫 Instructor tip: Pair students as sender/receiver teams and rotate.
- 📖 Glossary:
- IR (infrared): Invisible light used for remote controls.
- Hex code: A number in base‑16 (like 0x45) used in protocols.
- Handshake: Request then acknowledgment to confirm communication.
- 💡 Mini tips:
- Space your sends (500–1200 ms) to avoid collisions.
- Print hex with
hex(value)for easier reading. - Keep the line of sight clear; avoid sunlight or strong lamps.