YashsharmaPhD commited on
Commit
07fc24a
·
verified ·
1 Parent(s): 75a446c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +181 -73
app.py CHANGED
@@ -1,105 +1,213 @@
 
1
  import gradio as gr
2
  import matplotlib.pyplot as plt
 
 
3
  import numpy as np
4
  import random
 
 
 
 
5
 
6
- # Robot and environment variables
7
- pose = [250, 250, 0]
8
- trajectory = []
 
 
 
 
9
  obstacles = []
10
  auto_mode = False
11
 
12
- def generate_obstacles(num_obstacles=5):
13
- global obstacles
14
- obstacles = []
15
- for _ in range(num_obstacles):
16
- x = random.randint(50, 450)
17
- y = random.randint(50, 450)
18
- w = random.randint(20, 50)
19
- h = random.randint(20, 50)
20
- obstacles.append((x, y, w, h))
 
 
 
 
 
 
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  def move_robot(direction):
23
  global pose, trajectory
24
- dx, dy = 0, 0
25
- step_size = 10
 
26
  if direction == "W":
27
- dy = -step_size
 
28
  elif direction == "S":
29
- dy = step_size
 
30
  elif direction == "A":
31
- dx = -step_size
 
32
  elif direction == "D":
33
- dx = step_size
34
- pose[0] += dx
35
- pose[1] += dy
36
- trajectory.append(tuple(pose[:2]))
37
- return render_env(), render_slam_map(), None, f"Moved {direction}"
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  def render_env():
40
- fig, ax = plt.subplots(figsize=(5, 5))
41
- ax.set_xlim(0, 500)
42
- ax.set_ylim(0, 500)
43
- ax.set_aspect('equal')
44
- # Draw robot
45
- ax.plot(pose[0], pose[1], 'bo', label="Robot")
46
- if trajectory:
47
- ax.plot(*zip(*trajectory), 'b--', label="Trajectory")
48
- # Draw obstacles
49
- for (x, y, w, h) in obstacles:
50
- ax.add_patch(plt.Rectangle((x, y), w, h, color='red'))
51
- ax.legend()
52
- plt.close()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  return fig
54
 
 
55
  def render_slam_map():
56
- fig, ax = plt.subplots(figsize=(5, 5))
57
- ax.set_xlim(0, 500)
58
- ax.set_ylim(0, 500)
59
- ax.set_aspect('equal')
60
- ax.plot(pose[0], pose[1], 'go', label="SLAM Robot")
61
- ax.legend()
62
- plt.close()
 
 
 
 
 
 
 
 
63
  return fig
64
 
65
- def toggle_auto(auto_state):
66
- return not auto_state, "Auto mode ON" if not auto_state else "Auto mode OFF"
 
67
 
68
- def auto_step(auto_state):
69
- if auto_state:
70
- direction = random.choice(["W", "A", "S", "D"])
71
- return move_robot(direction)
72
- return render_env(), render_slam_map(), None, "Auto mode is OFF"
 
 
 
 
73
 
74
- # Build Gradio UI
75
- with gr.Blocks() as demo:
76
- gr.Markdown("## SLAM Robot Demo with Auto Mode")
77
- env_plot = gr.Plot()
78
- slam_plot = gr.Plot()
79
- collision_audio = gr.Audio(type="filepath", label="Collision")
80
- status_text = gr.Textbox(label="Status")
81
 
82
- auto_state = gr.State(False)
 
 
 
 
83
 
84
- with gr.Row():
85
- gr.Button("⬆️").click(fn=move_robot, inputs=gr.Textbox(value="W", visible=False), outputs=[env_plot, slam_plot, collision_audio, status_text])
86
- gr.Button("⬇️").click(fn=move_robot, inputs=gr.Textbox(value="S", visible=False), outputs=[env_plot, slam_plot, collision_audio, status_text])
87
- gr.Button("⬅️").click(fn=move_robot, inputs=gr.Textbox(value="A", visible=False), outputs=[env_plot, slam_plot, collision_audio, status_text])
88
- gr.Button("➡️").click(fn=move_robot, inputs=gr.Textbox(value="D", visible=False), outputs=[env_plot, slam_plot, collision_audio, status_text])
89
- auto_button = gr.Button("Toggle Auto Mode")
 
 
 
 
90
 
91
- # Auto mode toggle updates state
92
- auto_button.click(fn=toggle_auto, inputs=auto_state, outputs=[auto_state, status_text])
 
 
93
 
94
- # Manual auto-step button (simulates periodic move)
95
- auto_step_btn = gr.Button("🔁 Auto Step")
96
- auto_step_btn.click(fn=auto_step, inputs=auto_state, outputs=[env_plot, slam_plot, collision_audio, status_text])
 
 
97
 
98
- # Initial load state
99
- demo.load(fn=lambda: (render_env(), render_slam_map(), None, " Ready"),
100
- outputs=[env_plot, slam_plot, collision_audio, status_text])
 
 
 
 
 
101
 
102
- # Initialize obstacles
103
- generate_obstacles()
 
 
 
 
 
 
104
 
105
  demo.launch()
 
1
+
2
  import gradio as gr
3
  import matplotlib.pyplot as plt
4
+ import matplotlib.patches as patches
5
+ import matplotlib.image as mpimg
6
  import numpy as np
7
  import random
8
+ import os
9
+ import threading
10
+ import time
11
+ from IPython.display import Audio, display
12
 
13
+ # Global state
14
+ pose = {"x": 0, "z": 0, "angle": 0}
15
+ trajectory = [(0, 0)]
16
+ obstacle_hits = []
17
+ color_index = 0
18
+ rgb_colors = ['red', 'green', 'blue']
19
+ noise_enabled = True
20
  obstacles = []
21
  auto_mode = False
22
 
23
+ # Generate obstacles
24
+ def generate_obstacles(count=10):
25
+ return [{
26
+ "x": random.uniform(-8, 8),
27
+ "z": random.uniform(-8, 8),
28
+ "radius": random.uniform(0.5, 1.2)
29
+ } for _ in range(count)]
30
+
31
+ obstacles = generate_obstacles(10)
32
+
33
+ # Toggle noise
34
+ def toggle_noise():
35
+ global noise_enabled
36
+ noise_enabled = not noise_enabled
37
+ return "Noise: ON" if noise_enabled else "Noise: OFF"
38
 
39
+ # Reset simulation
40
+ def reset_sim(count):
41
+ global pose, trajectory, obstacles, obstacle_hits, color_index
42
+ pose = {"x": 0, "z": 0, "angle": 0}
43
+ trajectory = [(0, 0)]
44
+ obstacle_hits = []
45
+ color_index = 0
46
+ obstacles = generate_obstacles(int(count))
47
+ return render_env(), render_slam_map(), None, f"Simulation Reset with {count} obstacles"
48
+
49
+ # Check collision
50
+ def check_collision(x, z):
51
+ for obs in obstacles:
52
+ dist = np.sqrt((obs["x"] - x)**2 + (obs["z"] - z)**2)
53
+ if dist <= obs["radius"] + 0.2:
54
+ return True
55
+ return False
56
+
57
+ # Movement logic
58
  def move_robot(direction):
59
  global pose, trajectory
60
+ step = 1
61
+ direction = direction.upper()
62
+
63
  if direction == "W":
64
+ new_x, new_z = pose["x"], pose["z"] + step
65
+ pose["angle"] = 90
66
  elif direction == "S":
67
+ new_x, new_z = pose["x"], pose["z"] - step
68
+ pose["angle"] = -90
69
  elif direction == "A":
70
+ new_x, new_z = pose["x"] - step, pose["z"]
71
+ pose["angle"] = 180
72
  elif direction == "D":
73
+ new_x, new_z = pose["x"] + step, pose["z"]
74
+ pose["angle"] = 0
75
+ else:
76
+ return render_env(), render_slam_map(), None, "❌ Invalid Key"
 
77
 
78
+ if check_collision(new_x, new_z):
79
+ # Play collision1.mp3 directly if in Jupyter/Colab
80
+ if os.path.exists("collision1.mp3"):
81
+ try:
82
+ display(Audio("collision1.mp3", autoplay=True))
83
+ except:
84
+ pass
85
+ return render_env(), render_slam_map(), None, "🚫 Collision detected!"
86
+
87
+ pose["x"], pose["z"] = new_x, new_z
88
+ if noise_enabled:
89
+ noisy_x = pose["x"] + random.uniform(-0.1, 0.1)
90
+ noisy_z = pose["z"] + random.uniform(-0.1, 0.1)
91
+ trajectory.append((noisy_x, noisy_z))
92
+ else:
93
+ trajectory.append((pose["x"], pose["z"]))
94
+
95
+ return render_env(), render_slam_map(), None, "Moved " + direction
96
+
97
+ # Environment view
98
  def render_env():
99
+ global obstacle_hits
100
+ fig, ax = plt.subplots()
101
+ ax.set_xlim(-10, 10)
102
+ ax.set_ylim(-10, 10)
103
+ ax.set_title("SLAM Environment View")
104
+
105
+ try:
106
+ bg = mpimg.imread("map.png")
107
+ ax.imshow(bg, extent=(-10, 10, -10, 10), alpha=0.2)
108
+ except:
109
+ pass
110
+
111
+ for obs in obstacles:
112
+ circ = plt.Circle((obs["x"], obs["z"]), obs["radius"], color="gray", alpha=0.6)
113
+ ax.add_patch(circ)
114
+
115
+ ax.plot(pose["x"], pose["z"], 'ro', markersize=8)
116
+
117
+ angles = np.linspace(0, 2*np.pi, 24)
118
+ for ang in angles:
119
+ for r in np.linspace(0, 3, 30):
120
+ scan_x = pose["x"] + r * np.cos(ang)
121
+ scan_z = pose["z"] + r * np.sin(ang)
122
+ if check_collision(scan_x, scan_z):
123
+ ax.plot([pose["x"], scan_x], [pose["z"], scan_z], 'g-', linewidth=0.5)
124
+ obstacle_hits.append((scan_x, scan_z))
125
+ break
126
+
127
+ plt.close(fig)
128
  return fig
129
 
130
+ # SLAM map
131
  def render_slam_map():
132
+ global color_index
133
+ fig, ax = plt.subplots()
134
+ ax.set_title("SLAM Trajectory Map")
135
+ x_vals = [x for x, z in trajectory]
136
+ z_vals = [z for x, z in trajectory]
137
+ ax.plot(x_vals, z_vals, 'bo-', markersize=3)
138
+ ax.grid(True)
139
+
140
+ if obstacle_hits:
141
+ current_color = rgb_colors[color_index % 3]
142
+ for hit in obstacle_hits[-20:]:
143
+ ax.plot(hit[0], hit[1], 'o', color=current_color, markersize=6)
144
+ color_index += 1
145
+
146
+ plt.close(fig)
147
  return fig
148
 
149
+ # Text command
150
+ def handle_text_input(direction):
151
+ return move_robot(direction.strip().upper())
152
 
153
+ # Auto movement thread
154
+ def auto_movement(update_callback):
155
+ global auto_mode
156
+ directions = ['W', 'A', 'S', 'D']
157
+ while auto_mode:
158
+ direction = random.choice(directions)
159
+ env, slam, _, msg = move_robot(direction)
160
+ update_callback(env, slam, None, f"[AUTO] {msg}")
161
+ time.sleep(1)
162
 
163
+ def toggle_auto_mode(env_plot, slam_plot, collision_audio, status_text):
164
+ global auto_mode
165
+ auto_mode = not auto_mode
 
 
 
 
166
 
167
+ if auto_mode:
168
+ def update_ui(e, s, _, t):
169
+ env_plot.update(value=e)
170
+ slam_plot.update(value=s)
171
+ status_text.update(value=t)
172
 
173
+ thread = threading.Thread(target=auto_movement, args=(update_ui,))
174
+ thread.daemon = True
175
+ thread.start()
176
+ return "🟢 Auto Mode: ON"
177
+ else:
178
+ return " Auto Mode: OFF"
179
+
180
+ # UI
181
+ with gr.Blocks() as demo:
182
+ gr.Markdown("## 🤖 SLAM Simulation with Auto Mode + Collision Sound (No Play Button)")
183
 
184
+ obstacle_slider = gr.Slider(1, 20, value=10, step=1, label="Number of Obstacles")
185
+ direction_input = gr.Textbox(label="Type W / A / S / D and press Enter", placeholder="e.g., W")
186
+ status_text = gr.Textbox(label="Status")
187
+ collision_audio = gr.Audio(label="(Hidden) Collision Sound", interactive=False, visible=False)
188
 
189
+ with gr.Row():
190
+ with gr.Column():
191
+ env_plot = gr.Plot(label="Robot View")
192
+ with gr.Column():
193
+ slam_plot = gr.Plot(label="SLAM Map")
194
 
195
+ with gr.Row():
196
+ w = gr.Button("⬆️ W")
197
+ a = gr.Button("⬅️ A")
198
+ s = gr.Button("⬇️ S")
199
+ d = gr.Button("➡️ D")
200
+ reset = gr.Button("🔄 Reset")
201
+ toggle = gr.Button("🔀 Toggle Noise")
202
+ auto = gr.Button("🤖 Toggle Auto")
203
 
204
+ w.click(fn=move_robot, inputs=gr.State("W"), outputs=[env_plot, slam_plot, collision_audio, status_text])
205
+ a.click(fn=move_robot, inputs=gr.State("A"), outputs=[env_plot, slam_plot, collision_audio, status_text])
206
+ s.click(fn=move_robot, inputs=gr.State("S"), outputs=[env_plot, slam_plot, collision_audio, status_text])
207
+ d.click(fn=move_robot, inputs=gr.State("D"), outputs=[env_plot, slam_plot, collision_audio, status_text])
208
+ reset.click(fn=reset_sim, inputs=[obstacle_slider], outputs=[env_plot, slam_plot, collision_audio, status_text])
209
+ toggle.click(fn=lambda: (None, None, None, toggle_noise()), outputs=[env_plot, slam_plot, collision_audio, status_text])
210
+ auto.click(fn=toggle_auto_mode, inputs=[env_plot, slam_plot, collision_audio, status_text], outputs=auto)
211
+ direction_input.submit(fn=handle_text_input, inputs=direction_input, outputs=[env_plot, slam_plot, collision_audio, status_text])
212
 
213
  demo.launch()