YashsharmaPhD commited on
Commit
209c586
·
verified ·
1 Parent(s): 6d77c3c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -181
app.py CHANGED
@@ -1,213 +1,102 @@
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()
 
 
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
+ ax.plot(*zip(*trajectory), 'b--', label="Trajectory")
47
+ # Draw obstacles
48
+ for (x, y, w, h) in obstacles:
49
+ ax.add_patch(plt.Rectangle((x, y), w, h, color='red'))
50
+ ax.legend()
51
+ plt.close()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  return fig
53
 
 
54
  def render_slam_map():
55
+ fig, ax = plt.subplots(figsize=(5, 5))
56
+ ax.set_xlim(0, 500)
57
+ ax.set_ylim(0, 500)
58
+ ax.set_aspect('equal')
59
+ ax.plot(pose[0], pose[1], 'go', label="SLAM Robot")
60
+ ax.legend()
61
+ plt.close()
 
 
 
 
 
 
 
 
62
  return fig
63
 
64
+ def toggle_auto(auto_state):
65
+ return not auto_state, "Auto mode ON" if not auto_state else "Auto mode OFF"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
+ def auto_step(auto_state):
68
+ if auto_state:
69
+ direction = random.choice(["W", "A", "S", "D"])
70
+ return move_robot(direction)
71
+ return render_env(), render_slam_map(), None, "Auto mode is OFF"
72
 
73
+ # Build Gradio UI
 
 
 
 
 
 
 
74
  with gr.Blocks() as demo:
75
+ gr.Markdown("## SLAM Robot Demo with Auto Mode")
76
+ env_plot = gr.Plot()
77
+ slam_plot = gr.Plot()
78
+ collision_audio = gr.Audio(type="auto", label="Collision")
79
  status_text = gr.Textbox(label="Status")
 
80
 
81
+ auto_state = gr.State(False)
 
 
 
 
82
 
83
  with gr.Row():
84
+ gr.Button("⬆️").click(fn=move_robot, inputs=gr.Textbox(value="W", visible=False), outputs=[env_plot, slam_plot, collision_audio, status_text])
85
+ gr.Button("⬇️").click(fn=move_robot, inputs=gr.Textbox(value="S", visible=False), outputs=[env_plot, slam_plot, collision_audio, status_text])
86
+ gr.Button("⬅️").click(fn=move_robot, inputs=gr.Textbox(value="A", visible=False), outputs=[env_plot, slam_plot, collision_audio, status_text])
87
+ gr.Button("➡️").click(fn=move_robot, inputs=gr.Textbox(value="D", visible=False), outputs=[env_plot, slam_plot, collision_audio, status_text])
88
+ auto_button = gr.Button("Toggle Auto Mode")
89
+
90
+ # Auto mode toggle updates state
91
+ auto_button.click(fn=toggle_auto, inputs=auto_state, outputs=[auto_state, status_text])
92
+
93
+ # Periodic polling that runs every second to check auto state
94
+ demo.load(fn=auto_step, inputs=auto_state, outputs=[env_plot, slam_plot, collision_audio, status_text], every=1)
95
+
96
+ demo.load(fn=lambda: (render_env(), render_slam_map(), None, "Ready"),
97
+ outputs=[env_plot, slam_plot, collision_audio, status_text])
98
 
99
+ # Reset obstacles and robot pose
100
+ generate_obstacles()
 
 
 
 
 
 
101
 
102
  demo.launch()