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:

image.png

and for the wiring, this is how everythings are connected

image 1.png
RC522-RFID-Reader-Writer-Module-Pinout.png
xinpin.png

Following are the bread board connections and i’ve plugged it in to my computer.

IMG_3988.jpeg
Testing with the bread board

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.

image 2.png
image 3.png
image 4.png
image 5.png
image 6.png
# 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

image 7.png
image 8.png

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);
  }
}
image 9.png

then I also ran dump info example file:

image 10.png
image 11.png
image 12.png

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:

  1. Plug in XIAO, open Arduino Serial Monitor and note the port name (or check device manager / ls /dev/).
  2. Edit PORT in the script or leave it blank and the script will prompt you.
  3. Edit UID_TO_URL to include the UIDs printed earlier and your desired URLs.
  4. Run: python open_rfid_url.py
  5. Tap a tag. The script will print the UID and open the mapped URL in your browser.

Group Assignment

IMG_3954.jpeg
IMG_3956.jpeg
IMG_3955.jpeg