Spaces:
Sleeping
Sleeping
File size: 6,335 Bytes
8ff2de6 07fc24a 0cd2dc0 6d77c3c 07fc24a 6d77c3c 07fc24a 6d77c3c e71fd51 e03a1d5 07fc24a 6d77c3c 07fc24a 1dbee15 07fc24a 1dbee15 7468a8c 07fc24a 6d77c3c 07fc24a 6d77c3c 07fc24a 6d77c3c 07fc24a 6d77c3c 07fc24a 6d77c3c 07fc24a 7468a8c e03a1d5 07fc24a 7468a8c 07fc24a 1dbee15 07fc24a 1dbee15 f3c2b5d 6d77c3c 07fc24a 03620db 07fc24a 1dbee15 07fc24a 03620db 07fc24a b40c950 8ff2de6 b40c950 07fc24a 03620db 07fc24a 03620db 07fc24a 6d77c3c 46bfc6d 07fc24a 6d77c3c 07fc24a 7468a8c 07fc24a 6d77c3c 7468a8c 07fc24a 8ff2de6 07fc24a 7468a8c 07fc24a d926bdc 03620db 07fc24a 7468a8c 07fc24a 03620db 209c586 07fc24a 1dbee15 209c586 07fc24a 209c586 07fc24a 6d77c3c 574bea2 7468a8c 0e76278 7468a8c b249855 8ff2de6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
import gradio as gr
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import random
import threading
import time
# Global state
pose = {"x": 0, "z": 0, "angle": 0}
trajectory = [(0, 0)]
obstacle_hits = []
color_index = 0
rgb_colors = ['red', 'green', 'blue']
noise_enabled = True
obstacles = []
auto_mode = False
def generate_obstacles(count=10):
return [{
"x": random.uniform(-8, 8),
"z": random.uniform(-8, 8),
"radius": random.uniform(0.5, 1.2)
} for _ in range(count)]
obstacles = generate_obstacles(10)
def toggle_noise():
global noise_enabled
noise_enabled = not noise_enabled
return "Noise: ON" if noise_enabled else "Noise: OFF"
def reset_sim(count):
global pose, trajectory, obstacles, obstacle_hits, color_index
pose = {"x": 0, "z": 0, "angle": 0}
trajectory = [(0, 0)]
obstacle_hits.clear()
color_index = 0
obstacles[:] = generate_obstacles(int(count))
return render_env(), render_slam_map(), f"Simulation Reset with {count} obstacles"
def check_collision(x, z):
for obs in obstacles:
dist = np.sqrt((obs["x"] - x)**2 + (obs["z"] - z)**2)
if dist <= obs["radius"] + 0.2:
return True
return False
def move_robot(direction):
global pose, trajectory
step = 1
direction = direction.upper()
if direction == "W":
new_x, new_z = pose["x"], pose["z"] + step
pose["angle"] = 90
elif direction == "S":
new_x, new_z = pose["x"], pose["z"] - step
pose["angle"] = -90
elif direction == "A":
new_x, new_z = pose["x"] - step, pose["z"]
pose["angle"] = 180
elif direction == "D":
new_x, new_z = pose["x"] + step, pose["z"]
pose["angle"] = 0
else:
return render_env(), render_slam_map(), "β Invalid Key"
if check_collision(new_x, new_z):
return render_env(), render_slam_map(), "π« Collision detected!"
pose["x"], pose["z"] = new_x, new_z
if noise_enabled:
noisy_x = pose["x"] + random.uniform(-0.1, 0.1)
noisy_z = pose["z"] + random.uniform(-0.1, 0.1)
trajectory.append((noisy_x, noisy_z))
else:
trajectory.append((pose["x"], pose["z"]))
return render_env(), render_slam_map(), f"Moved {direction}"
def render_env():
global obstacle_hits
fig, ax = plt.subplots(figsize=(5,5))
ax.set_xlim(-10, 10)
ax.set_ylim(-10, 10)
ax.set_title("SLAM Environment View")
try:
bg = mpimg.imread("map.png")
ax.imshow(bg, extent=(-10, 10, -10, 10), alpha=0.2)
except FileNotFoundError:
pass
for obs in obstacles:
circ = plt.Circle((obs["x"], obs["z"]), obs["radius"], color="gray", alpha=0.6)
ax.add_patch(circ)
ax.plot(pose["x"], pose["z"], 'ro', markersize=8)
# Clear previous hits to avoid infinite growth
obstacle_hits.clear()
angles = np.linspace(0, 2*np.pi, 24)
for ang in angles:
for r in np.linspace(0, 3, 30):
scan_x = pose["x"] + r * np.cos(ang)
scan_z = pose["z"] + r * np.sin(ang)
if check_collision(scan_x, scan_z):
ax.plot([pose["x"], scan_x], [pose["z"], scan_z], 'g-', linewidth=0.5)
obstacle_hits.append((scan_x, scan_z))
break
plt.close(fig)
return fig
def render_slam_map():
global color_index
fig, ax = plt.subplots(figsize=(5,5))
ax.set_title("SLAM Trajectory Map")
x_vals = [x for x, z in trajectory]
z_vals = [z for x, z in trajectory]
ax.plot(x_vals, z_vals, 'bo-', markersize=3)
ax.grid(True)
if obstacle_hits:
current_color = rgb_colors[color_index % len(rgb_colors)]
for hit in obstacle_hits[-20:]:
ax.plot(hit[0], hit[1], 'o', color=current_color, markersize=6)
color_index += 1
plt.close(fig)
return fig
def handle_text_input(direction):
return move_robot(direction.strip().upper())
def auto_movement(update_callback):
global auto_mode
directions = ['W', 'A', 'S', 'D']
while auto_mode:
direction = random.choice(directions)
env, slam, msg = move_robot(direction)
update_callback(env, slam, msg)
time.sleep(1)
def toggle_auto_mode(env_plot, slam_plot, status_text):
global auto_mode
auto_mode = not auto_mode
if auto_mode:
def update_ui(e, s, t):
env_plot.update(value=e)
slam_plot.update(value=s)
status_text.update(value=t)
thread = threading.Thread(target=auto_movement, args=(update_ui,), daemon=True)
thread.start()
return "π’ Auto Mode: ON"
else:
return "βͺ Auto Mode: OFF"
# Gradio UI
with gr.Blocks() as demo:
gr.Markdown("## π€ SLAM Simulation with Auto Mode + Collision Status")
obstacle_slider = gr.Slider(1, 20, value=10, step=1, label="Number of Obstacles")
direction_input = gr.Textbox(label="Type W / A / S / D and press Enter", placeholder="e.g., W")
status_text = gr.Textbox(label="Status", interactive=False)
with gr.Row():
with gr.Column():
env_plot = gr.Plot(label="Robot View")
with gr.Column():
slam_plot = gr.Plot(label="SLAM Map")
with gr.Row():
w = gr.Button("β¬οΈ W")
a = gr.Button("β¬
οΈ A")
s = gr.Button("β¬οΈ S")
d = gr.Button("β‘οΈ D")
reset = gr.Button("π Reset")
toggle = gr.Button("π Toggle Noise")
auto = gr.Button("π€ Toggle Auto")
w.click(fn=lambda: move_robot("W"), outputs=[env_plot, slam_plot, status_text])
a.click(fn=lambda: move_robot("A"), outputs=[env_plot, slam_plot, status_text])
s.click(fn=lambda: move_robot("S"), outputs=[env_plot, slam_plot, status_text])
d.click(fn=lambda: move_robot("D"), outputs=[env_plot, slam_plot, status_text])
reset.click(fn=reset_sim, inputs=[obstacle_slider], outputs=[env_plot, slam_plot, status_text])
toggle.click(fn=lambda: (None, None, toggle_noise()), outputs=[env_plot, slam_plot, status_text])
auto.click(fn=toggle_auto_mode, inputs=[env_plot, slam_plot, status_text], outputs=status_text)
direction_input.submit(fn=handle_text_input, inputs=direction_input, outputs=[env_plot, slam_plot, status_text])
demo.launch()
|