Week 8 — Input Devices
The goal of this week is to get the RFID to send a url back to my computer. And this url is going to be the VR html I developed with PlayCanvas couple of weeks ago from 3d scanning, it’s a gaussian splat model.
Test
Prep work
I started with a bread board and made sure things work, because last week my xiao was broken and I spent too much time figuring out what’s wrong and had no time to test if things actually works.
Following are the list:
and for the wiring, this is how everythings are connected
Following are the bread board connections and i’ve plugged it in to my computer.
Within Arduino
Navigate to File > Preferences, and fill Additional Boards Manager URLs with the url below:
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
Navigate to Tools-> Board-> Boards Manager..., type the keyword "RP2040" in the searching blank. Select the lastest version of "Raspberry Pi Pico/RP2040" and install it.
# open_rfid_url.py
import serial, webbrowser, time, sys
# --- CONFIG ---
PORT = None # e.g., "COM5" on Windows or "/dev/ttyACM0" on macOS/Linux
BAUD = 115200
COOLDOWN = 2.0 # seconds to ignore repeats
# Map UID hex strings (as printed by Arduino, no "UID:" prefix) to URLs
UID_TO_URL = {
"04986F2A": "https://qilmegd.com",
"A1B2C3D4": "https://playcanv.as/p/8YMBjJBn/",
# add more mappings here
}
# ----------------
def find_port():
# If user set a port, use it. Otherwise ask.
global PORT
if PORT:
return PORT
print("No PORT configured in script. Please enter the serial port where XIAO is connected.")
print(" - Windows example: COM5")
print(" - macOS example: /dev/tty.usbmodem#### or /dev/tty.usbserial-####")
print(" - Linux example: /dev/ttyACM0 or /dev/ttyUSB0")
PORT = input("Enter serial port: ").strip()
return PORT
def main():
port = find_port()
try:
ser = serial.Serial(port, BAUD, timeout=1)
except Exception as e:
print("Failed to open serial port:", e)
sys.exit(1)
print("Listening on", port)
last_time = 0
last_uid = ""
while True:
try:
line = ser.readline().decode('utf-8', errors='ignore').strip()
if not line:
continue
print("RX:", line)
if line.startswith("UID:"):
uid = line.split("UID:")[-1].strip().upper()
now = time.time()
# basic cooldown to avoid duplicate opens
if uid == last_uid and (now - last_time) < COOLDOWN:
print("Duplicate UID within cooldown — ignoring.")
continue
last_uid = uid
last_time = now
url = UID_TO_URL.get(uid, None)
if url:
print("Opening URL for UID", uid, "->", url)
webbrowser.open(url)
else:
print("No URL mapped for UID", uid, "- add it to UID_TO_URL in script.")
except KeyboardInterrupt:
print("Exiting.")
break
except Exception as e:
print("Error:", e)
time.sleep(0.5)
if __name__ == "__main__":
main()
didn’t take the code in the beginning, rebooted and it worked
Debugging
Everything works but the UID doesn’t show up, chatGPT told me to run this and see the result so we can debug
#include <SPI.h>
#include <MFRC522.h>
constexpr uint8_t PIN_SS = D3; // RC522 SDA / SS
constexpr uint8_t PIN_RST = D2; // RC522 RST
MFRC522 mfrc522(PIN_SS, PIN_RST);
String uidToHex(const MFRC522::Uid &uid) {
String s;
for (byte i = 0; i < uid.size; i++) {
if (uid.uidByte[i] < 0x10) s += "0";
s += String(uid.uidByte[i], HEX);
}
s.toUpperCase();
return s;
}
void setup() {
Serial.begin(115200);
while (!Serial) { delay(5); }
Serial.println("\n=== RC522 quick self-check ===");
Serial.println("1) Checking SPI + RC522 presence...");
SPI.begin();
mfrc522.PCD_Init();
// Dump version: should be 0x92 or 0x91 typically
byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
Serial.print("MFRC522 VersionReg: 0x");
Serial.println(v, HEX);
if (v == 0x00 || v == 0xFF) {
Serial.println("❌ RC522 not responding over SPI.");
Serial.println("Check wiring: VCC=3V3, GND, SCK->D8, MOSI->D10, MISO->D9, SS->D3, RST->D2.");
Serial.println("Also confirm you installed 'MFRC522 by miguelbalboa' and are powering 3.3V.");
} else {
Serial.println("✅ RC522 is alive. Bring a tag to the antenna.");
}
}
void loop() {
// Only try to read if a card is present
if (!mfrc522.PICC_IsNewCardPresent()) {
delay(50);
return;
}
if (!mfrc522.PICC_ReadCardSerial()) {
delay(50);
return;
}
String uidHex = uidToHex(mfrc522.uid);
Serial.print("UID: ");
Serial.println(uidHex);
// Halt & wait for removal (prevents spam)
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
delay(200);
// Wait until no card
unsigned long t0 = millis();
while (mfrc522.PICC_IsNewCardPresent() && (millis() - t0) < 2000) {
delay(100);
}
}
then I also ran dump info example file:
Python helper script (maps UID → URL and opens browser)
Install Python (3.8+) if you don’t have it. Then install pyserial:
pip install pyserial
Save this script as open_rfid_url.py and edit the PORT and the UID_TO_URL map to match the UID(s) you saw.
# open_rfid_url.py
import serial, webbrowser, time, sys
# --- CONFIG ---
PORT = None # e.g., "COM5" on Windows or "/dev/ttyACM0" on macOS/Linux
BAUD = 115200
COOLDOWN = 2.0 # seconds to ignore repeats
# Map UID hex strings (as printed by Arduino, no "UID:" prefix) to URLs
UID_TO_URL = {
"04986F2A": "https://qilmegd.com",
"A1B2C3D4": "https://playcanv.as/p/8YMBjJBn/",
# add more mappings here
}
# ----------------
def find_port():
# If user set a port, use it. Otherwise ask.
global PORT
if PORT:
return PORT
print("No PORT configured in script. Please enter the serial port where XIAO is connected.")
print(" - Windows example: COM5")
print(" - macOS example: /dev/tty.usbmodem#### or /dev/tty.usbserial-####")
print(" - Linux example: /dev/ttyACM0 or /dev/ttyUSB0")
PORT = input("Enter serial port: ").strip()
return PORT
def main():
port = find_port()
try:
ser = serial.Serial(port, BAUD, timeout=1)
except Exception as e:
print("Failed to open serial port:", e)
sys.exit(1)
print("Listening on", port)
last_time = 0
last_uid = ""
while True:
try:
line = ser.readline().decode('utf-8', errors='ignore').strip()
if not line:
continue
print("RX:", line)
if line.startswith("UID:"):
uid = line.split("UID:")[-1].strip().upper()
now = time.time()
# basic cooldown to avoid duplicate opens
if uid == last_uid and (now - last_time) < COOLDOWN:
print("Duplicate UID within cooldown — ignoring.")
continue
last_uid = uid
last_time = now
url = UID_TO_URL.get(uid, None)
if url:
print("Opening URL for UID", uid, "->", url)
webbrowser.open(url)
else:
print("No URL mapped for UID", uid, "- add it to UID_TO_URL in script.")
except KeyboardInterrupt:
print("Exiting.")
break
except Exception as e:
print("Error:", e)
time.sleep(0.5)
if __name__ == "__main__":
main()
How to run:
- Plug in XIAO, open Arduino Serial Monitor and note the port name (or check device manager /
ls /dev/). - Edit
PORTin the script or leave it blank and the script will prompt you. - Edit
UID_TO_URLto include the UIDs printed earlier and your desired URLs. - Run:
python open_rfid_url.py - Tap a tag. The script will print the UID and open the mapped URL in your browser.
Group Assignment