Robot Dokümantasyonu/Rehberler
Hedefleri Haritada Göster
Bu rehberde robotun haritasını ve tanımlı tüm hedefleri alıp Python ile tek bir matplotlib penceresinde birlikte çizmeyi göreceksiniz. Betiği çalıştırdığınızda arka planda robotun doluluk ızgarası (occupancy grid) haritası, üzerinde de her hedef etiketli bir işaretle görünür.
Gereksinimler:
- Robota erişimi olan bir API anahtarı ve robotun ID'si (bkz. Başlangıç)
- Python 3.8 veya üstü
- Bağımlılıkların kurulumu (bir kez):
pip install requests matplotlib pillow
#!/usr/bin/env python3
"""
Visualize robot targets on the map.
Requirements:
pip install requests matplotlib pillow
Usage:
ROBOT_ID=<robot id> API_KEY=<api key> 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_ID = os.getenv("ROBOT_ID", "")
API_KEY = os.getenv("API_KEY", "")
ROBOT_URL = os.getenv("ROBOT_URL", f"https://robots.saharobotik.com/api/v1/{ROBOT_ID}/robot")
HEADERS = {"x-api-key": API_KEY}
# ─────────────────────────────────────────────────────────────────────────────
def fetch_map() -> dict:
resp = requests.get(f"{ROBOT_URL}/mapping/map", headers=HEADERS, timeout=10)
resp.raise_for_status()
return resp.json()
def fetch_targets() -> list:
resp = requests.get(f"{ROBOT_URL}/targets", headers=HEADERS, 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():
if not ROBOT_ID or not API_KEY:
print("Set the ROBOT_ID and API_KEY environment variables")
sys.exit(1)
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()Betik adım adım şunları yapar:
- Haritayı alır —
GET /mapping/mapisteğini gönderir, base64 PNG'yi çözer,resolution(metre/piksel) veorigin(haritanın sol alt köşesinin metre cinsinden konumu) değerlerini okur. - Hedefleri alır —
GET /targetsisteğiyle tüm hedefleri metre cinsinden konumlarıyla (px,py) alır. - Koordinatları dönüştürür — her hedefin metre cinsinden konumunu, haritanın
originveresolutiondeğerleriyle piksel koordinatına çevirir. - Çizer — doluluk haritasını gri tonlu arka plan olarak gösterir; her hedefi adı ve türü yazan renkli bir nokta olarak çizer. Sağ üst köşede bir lejant yer alır.