Robot Documentations/Guides
Visualize Targets on Map
This guide shows how to fetch the robot's map and all defined targets, then render them together in a single matplotlib window using Python. When you run the script you will see the occupancy-grid map as the background with every target drawn as a labeled marker on top.
Prerequisites:
- The robot API is reachable, e.g.,
http://192.168.1.100:7242 - Python 3.8+ is installed
- Install dependencies once:
pip install requests matplotlib pillow
#!/usr/bin/env python3
"""
Visualize robot targets on the map.
Requirements:
pip install requests matplotlib pillow
Usage:
python visualize_targets.py
ROBOT_URL=http://192.168.1.100:7242 python visualize_targets.py
"""
import base64
import io
import os
import sys
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import requests
from PIL import Image
# ── configuration ────────────────────────────────────────────────────────────
ROBOT_URL = os.getenv("ROBOT_URL", "http://192.168.1.100:7242")
# ─────────────────────────────────────────────────────────────────────────────
def fetch_map() -> dict:
resp = requests.get(f"{ROBOT_URL}/api/v1/mapping/map", timeout=10)
resp.raise_for_status()
return resp.json()
def fetch_targets() -> list:
resp = requests.get(f"{ROBOT_URL}/api/v1/targets", timeout=10)
resp.raise_for_status()
return resp.json()
def world_to_pixel(wx: float, wy: float, origin: dict, resolution: float, height: int):
"""Convert world coordinates (meters) to image pixel coordinates."""
px = (wx - origin["x"]) / resolution
py = height - (wy - origin["y"]) / resolution # flip y because image origin is top-left
return px, py
def main():
print(f"Robot URL : {ROBOT_URL}")
# 1 ── fetch map ──────────────────────────────────────────────────────────
print("[1/2] Fetching map...")
try:
map_data = fetch_map()
except Exception as exc:
print(f" ✗ Could not fetch map: {exc}")
sys.exit(1)
resolution = map_data["resolution"] # meters / pixel
img_height = map_data["height"] # pixels
origin = map_data.get("origin", {"x": 0.0, "y": 0.0, "z": 0.0})
image_bytes = base64.b64decode(map_data["map_png_base64"])
map_image = Image.open(io.BytesIO(image_bytes))
print(f" ✓ Map loaded ({map_data['width']} × {img_height} px, {resolution} m/px)")
# 2 ── fetch targets ──────────────────────────────────────────────────────
print("[2/2] Fetching targets...")
try:
targets = fetch_targets()
except Exception as exc:
print(f" ✗ Could not fetch targets: {exc}")
sys.exit(1)
print(f" ✓ {len(targets)} target(s) found")
# 3 ── plot ───────────────────────────────────────────────────────────────
colors = plt.cm.tab10.colors
DPI = 100
MAX_INCHES = 22
MIN_INCHES = 16
img_w = map_data["width"]
# derive figure size from actual image pixels, capped to screen-safe range
aspect = img_height / img_w if img_w else 1
fw = max(MIN_INCHES, min(img_w / DPI, MAX_INCHES))
fh = max(MIN_INCHES * aspect, min(fw * aspect, MAX_INCHES))
fig, ax = plt.subplots(figsize=(fw, fh), dpi=DPI)
ax.imshow(map_image, cmap="gray", origin="upper")
# lock axes to image bounds so out-of-range targets don't shrink the map
ax.set_xlim(0, img_w)
ax.set_ylim(img_height, 0) # imshow origin=upper → y increases downward
ax.set_title(f"Robot Targets on Map ({len(targets)} targets)", fontsize=14, pad=12)
ax.set_xlabel("X (pixels)")
ax.set_ylabel("Y (pixels)")
for i, target in enumerate(targets):
wx = float(target.get("px") or 0)
wy = float(target.get("py") or 0)
name = target.get("name", "?")
ttype = target.get("type", "default")
px, py = world_to_pixel(wx, wy, origin, resolution, img_height)
color = colors[i % len(colors)]
ax.plot(
px, py,
"o",
markersize=10,
color=color,
markeredgecolor="white",
markeredgewidth=1.5,
)
ax.annotate(
f"{name}\n({ttype})",
xy=(px, py),
xytext=(8, 8),
textcoords="offset points",
fontsize=8,
color=color,
bbox=dict(boxstyle="round,pad=0.2", fc="white", alpha=0.7),
)
if targets:
legend_handles = [
mpatches.Patch(color=colors[i % len(colors)], label=t.get("name", "?"))
for i, t in enumerate(targets)
]
ax.legend(handles=legend_handles, loc="upper right", fontsize=7, title="Targets")
plt.tight_layout()
plt.show()
if __name__ == "__main__":
main()What the script does step by step:
- Fetch map — calls
GET /api/v1/mapping/map, decodes the base64 PNG and reads theresolution(m/px) andorigin(world position of the bottom-left corner). - Fetch targets — calls
GET /api/v1/targetsto get all targets with their world position (px,pyin meters). - Convert coordinates — converts each target's world position to pixel coordinates using the map's origin and resolution.
- Render — displays the occupancy map as a grayscale background and draws every target as a coloured dot with a name + type label. A legend is shown in the top-right corner.