A quick, hands‑on guide to building AirTag‑style UWB ranging with Reyax RYUW122_Lite modules. Includes wiring photos, a one‑click Windows EXE GUI (plus source), step‑by‑step AT commands, and a live demo so makers and students can measure centimeter‑class distances in minutes.
You’ll learn how to:
- Set up two UWB modules (anchor + tag)
- Connect them via USB-to-TTL converters
- Send and receive AT commands automatically
- Visualize distance in real-time with a progress bar
- Extend to a browser-based dashboard using Web Serial
Whether you're a hobbyist, educator, or embedded systems developer, this guide gives you a modular, expressive way to explore UWB ranging.
🧰 What You’ll Need- 2× Reyax RYUW122_Lite UWB modules - One acts as the anchor, the other as the tag for ranging.
- 1× DFRobot Rainbow USB-to-TTL converters - for serial communication between the UWB modules and your PC.
- Jumper wires (male-to-female or female-to-female) - To connect TX, RX, VCC, and GND between modules and converters.
- Windows PC withor without Python 3.12+ installed - Used to run the automation script and visualize distance.
Ultra‑Wideband (UWB) is a short‑range radio technology that transmits very short, nanosecond‑scale pulses across a wide frequency band—often spanning several gigahertz—to achieve high time resolution and low power consumption. UWB is optimized for precise ranging and location discovery rather than long‑range data throughput, making it ideal for centimeter‑class distance measurements and proximity services
UWB transmitters send billions of extremely short pulses across a wide spectrum. A receiver looks for the same pulse pattern and converts pulse timing into data. Ranging is done using Time‑of‑Flight (ToF) measurements: devices exchange challenge/response packets, measure round‑trip times, and convert that time into distance.
Two common roles are Anchor (fixed, known location) and Tag (mobile).
Reyax RYUW122_Lite UWB modulesA compact Ultra‑Wideband transceiver for accurate short‑range time‑of‑flight ranging. Designed for rapid prototyping, it exposes an easy UART/AT command interface so you can get centimeter‑class distance readings into a PC or microcontroller quickly.
Key points
- Technology: Ultra‑Wideband (time‑of‑flight)
- Interface: UART / AT commands (115200 baud typical)
- Typical use: anchor + tag ranging, asset tracking, proximity sensing
- Power: 3.3 V operation; low‑power standby available
- Precision: centimeter‑level in favorable, line‑of‑sight conditions
Connect each RYUW122_Lite to a USB-to-TTL converter:
- VCC → 3.3V
- GND → GND
- TX → RX
- RX → TX
Plug both converters into your PC. Use Device Manager to identify COM ports (e.g., COM16 for anchor, COM17 for tag).
📜 AT Command PrimerThe RYUW122_Lite uses AT commands for configuration and ranging. Here are the essentials:
AT+MODE=1→ Set as anchorAT+MODE=0→ Set as tagAT+ADDRESS=ANCHR003→ Set anchor addressAT+ADDRESS=DAVID123→ Set tag addressAT+NETWORKID=REYAX123→ Set network groupAT+CPIN=FABC0002EEDCAA90FABC0002EEDCAA90→ Set 32-character encryption keyAT+ANCHOR_SEND=DAVID123,5,HELLO→ Send ranging request
Refer to Reyax’s AT Command Manual for full syntax.
If you want to use direct.exe files without the python, you can skip the next part and move to the No Python just an.EXE (Quick Start)No Python just an.EXE (Quick Start)
If you are beginner or don't want to use the python code here is the rapid quick start guide. Just use the.EXE file and you can directly work on the modules without any hardcoding's.
Here is the procedure to use the.EXE file.
- Copy the.EXE to a Windows PC where USB-to-TTL drivers are installed.
You can download the.EXE file from this page - pradeeplogu0/RYUW122_Lite
- Plug in both USB-to-TTL adapters connected to your Anchor and Tag modules.
- Double-click the.EXE to launch the UWB Ranging Dashboard GUI.
- Click Refresh Ports, choose the Anchor and Tag COM ports, then click Connect Anchor and Connect Tag.
- Click Setup Anchor and Setup Tag to apply AT settings (addresses, network id, CPIN).
- Enter a Payload (e.g., HELLO) and Duration (seconds).
- Click Start Ranging. Watch live distance updates, progress bar, and console output. Click Stop to end.
This script configures both modules, sends ranging requests every second, and displays distance as a live progress bar.
📦 Script Highlights
import serial
import time
import sys
# 🎨 ANSI Colors
RESET = "\033[0m"
GREEN = "\033[92m"
RED = "\033[91m"
YELLOW = "\033[93m"
CYAN = "\033[96m"
MAGENTA = "\033[95m"
BOLD = "\033[1m"
# 🎯 Configuration
ANCHOR_PORT = 'COM16'
TAG_PORT = 'COM17'
BAUD_RATE = 115200
ANCHOR_ADDRESS = "ANCHR003"
TAG_ADDRESS = "DAVID123"
NETWORK_ID = "REYAX123"
CPIN = "FABC0002EEDCAA90FABC0002EEDCAA90"
PAYLOAD = "HELLO"
MAX_DISTANCE_CM = 100 # Scale progress bar to this max
# 🧰 Utility Functions
def open_serial(port_name):
print(f"{CYAN}🔌 Opening serial port: {port_name}{RESET}")
try:
port = serial.Serial(port_name, BAUD_RATE, timeout=1)
print(f"{GREEN}✅ Connected to {port_name}{RESET}")
return port
except Exception as e:
print(f"{RED}❌ Failed to open {port_name}: {e}{RESET}")
return None
def send_command(port, command):
if not port:
print(f"{RED}⚠️ Port not available.{RESET}")
return ""
print(f"{CYAN}➡️ [{port.port}] Sending: {command}{RESET}")
port.write((command + '\r\n').encode())
time.sleep(0.2)
response = port.read_all().decode(errors='ignore').strip()
if response:
print(f"{GREEN}⬅️ [{port.port}] Response: {response}{RESET}")
else:
print(f"{YELLOW}⚠️ [{port.port}] No response received.{RESET}")
return response
def setup_module(port, role, address, networkid, cpin):
role_name = "Anchor" if role == 1 else "Tag"
print(f"{YELLOW}🧭 Setting up {role_name} on {port.port}{RESET}")
cmds = [
f"AT+MODE={role}",
f"AT+ADDRESS={address}",
f"AT+NETWORKID={networkid}",
f"AT+CPIN={cpin}",
"AT"
]
for cmd in cmds:
resp = send_command(port, cmd)
if "OK" in resp:
print(f"{GREEN}✅ {cmd} applied successfully{RESET}")
elif "+ERR=" in resp:
print(f"{RED}❌ Error in {cmd}: {resp}{RESET}")
else:
print(f"{YELLOW}⚠️ Unexpected response for {cmd}: {resp}{RESET}")
time.sleep(0.1)
def update_progress_bar(distance_cm):
try:
distance = float(distance_cm)
bar_length = 30
filled = int((distance / MAX_DISTANCE_CM) * bar_length)
filled = min(filled, bar_length)
bar = "█" * filled + "-" * (bar_length - filled)
sys.stdout.write(f"\r{MAGENTA}📏 {distance_cm} cm {RESET} {BOLD}[{bar}]{RESET}")
sys.stdout.flush()
except:
sys.stdout.write(f"\r{RED}⚠️ Invalid distance format{RESET}")
sys.stdout.flush()
def parse_anchor_rcv(response):
if "+ANCHOR_RCV" in response:
try:
parts = response.split(",")
distance = parts[3].replace("cm", "").strip()
update_progress_bar(distance)
except Exception as e:
sys.stdout.write(f"\r{RED}⚠️ Parse error: {e}{RESET}")
sys.stdout.flush()
elif "+ERR=" in response:
sys.stdout.write(f"\r{RED}❌ Error: {response}{RESET}")
sys.stdout.flush()
else:
sys.stdout.write(f"\r{YELLOW}🕵️ Unexpected response: {response}{RESET}")
sys.stdout.flush()
def auto_ranging(anchor_port, target_address, payload, duration_sec):
print(f"\n{CYAN}⏱️ Auto-ranging for {duration_sec} seconds...{RESET}\n")
start_time = time.time()
while time.time() - start_time < duration_sec:
cmd = f"AT+ANCHOR_SEND={target_address},{len(payload)},{payload}"
response = send_command(anchor_port, cmd)
parse_anchor_rcv(response)
time.sleep(1)
print(f"\n{GREEN}⏹️ Auto-ranging complete.{RESET}")
# 🚀 Main Execution
print(f"{BOLD}{CYAN}🔧 Starting UWB diagnostics...{RESET}\n")
anchor_serial = open_serial(ANCHOR_PORT)
tag_serial = open_serial(TAG_PORT)
if anchor_serial and tag_serial:
setup_module(anchor_serial, 1, ANCHOR_ADDRESS, NETWORK_ID, CPIN)
setup_module(tag_serial, 0, TAG_ADDRESS, NETWORK_ID, CPIN)
try:
duration = int(input(f"{BOLD}⏳ Enter ranging duration in seconds: {RESET}"))
auto_ranging(anchor_serial, TAG_ADDRESS, PAYLOAD, duration)
except ValueError:
print(f"{RED}⚠️ Invalid input. Please enter a number.{RESET}")
anchor_serial.close()
tag_serial.close()
print(f"\n{GREEN}✅ Diagnostics and ranging complete.{RESET}")
else:
print(f"{RED}❌ Could not initialize both modules.{RESET}")Please change the COM port as per your configurations.
Once you run the script, you can see this kind of response from the modules. First portion the script will try too setup the Anchor and in the second block it will try to setup the Tag and finally it will ask how long you need to do the measurements.
Here is the distance response from the UWB modules.
The Reyax RYUW122_Lite UWB project delivers a fast, hands‑on path from hardware to usable results: wire two modules to USB‑TTL adapters, run the provided GUI or EXE, and you get reliable, centimeter‑scale ranging, live visualization, and CSV logging in minutes. It’s ideal for demos, workshops, and quick prototyping—ready to extend into multi‑anchor systems, trilateration, or classroom exercises.


Comments