YashsharmaPhD commited on
Commit
6d77c3c
·
verified ·
1 Parent(s): 224ca6f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +179 -110
app.py CHANGED
@@ -1,144 +1,213 @@
 
1
  import gradio as gr
2
  import matplotlib.pyplot as plt
 
 
3
  import numpy as np
 
 
4
  import threading
5
  import time
6
- import os
7
-
8
- # Environment and robot parameters
9
- env_size = 10
10
- obstacles = [(2, 2), (3, 5), (6, 7), (7, 3), (5, 5)]
11
- robot_position = [0, 0]
 
 
 
 
12
  auto_mode = False
13
- robot_path = [tuple(robot_position)]
14
-
15
- # Collision detection
16
- def check_collision(x, y):
17
- return (x, y) in obstacles or not (0 <= x < env_size and 0 <= y < env_size)
18
 
19
- # Environment rendering
20
- def render_env():
21
- fig, ax = plt.subplots(figsize=(5, 5))
22
- ax.set_xlim(0, env_size)
23
- ax.set_ylim(0, env_size)
24
- ax.set_xticks(np.arange(0, env_size + 1, 1))
25
- ax.set_yticks(np.arange(0, env_size + 1, 1))
26
- ax.grid(True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
- for (ox, oy) in obstacles:
29
- ax.add_patch(plt.Rectangle((ox, oy), 1, 1, color="red"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
- for i in range(1, len(robot_path)):
32
- x_values = [robot_path[i - 1][0] + 0.5, robot_path[i][0] + 0.5]
33
- y_values = [robot_path[i - 1][1] + 0.5, robot_path[i][1] + 0.5]
34
- ax.plot(x_values, y_values, "b--")
35
 
36
- rx, ry = robot_position
37
- ax.plot(rx + 0.5, ry + 0.5, "bo", markersize=15)
38
- ax.set_title("Robot Environment")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  return fig
40
 
41
- # SLAM map simulation
42
  def render_slam_map():
43
- fig, ax = plt.subplots(figsize=(5, 5))
44
- ax.imshow(np.random.rand(env_size, env_size), cmap="gray", origin="lower")
45
- ax.set_title("Simulated SLAM Map")
46
- return fig
47
-
48
- # Robot movement logic
49
- def move_robot(direction):
50
- dx, dz = {
51
- "up": (0, 1),
52
- "down": (0, -1),
53
- "left": (-1, 0),
54
- "right": (1, 0),
55
- }.get(direction, (0, 0))
56
 
57
- new_x, new_z = robot_position[0] + dx, robot_position[1] + dz
 
 
 
 
58
 
59
- if check_collision(new_x, new_z):
60
- sound_path = "collision1.mp3"
61
- if not os.path.isfile(sound_path):
62
- sound_path = ""
63
- return render_env(), render_slam_map(), sound_path, "🚫 Collision Detected!"
64
 
65
- robot_position[0], robot_position[1] = new_x, new_z
66
- robot_path.append(tuple(robot_position))
67
- return render_env(), render_slam_map(), None, "✅ Moved " + direction
68
 
69
- # Auto movement logic
70
- def auto_movement(env_plot, slam_plot, audio_trigger, status_text):
71
  global auto_mode
72
- directions = ["up", "right", "down", "left"]
73
- i = 0
74
  while auto_mode:
75
- direction = directions[i % len(directions)]
76
- env_img, slam_img, sound_path, status = move_robot(direction)
77
- env_plot.update(value=env_img)
78
- slam_plot.update(value=slam_img)
79
- status_text.update(value=status)
80
-
81
- if sound_path and os.path.isfile(sound_path):
82
- audio_trigger.play_event(sound_path)
83
-
84
  time.sleep(1)
85
- i += 1
86
 
87
- # Toggle auto mode
88
- def toggle_auto_mode(env_plot, slam_plot, audio_trigger, status_text):
89
  global auto_mode
 
 
90
  if auto_mode:
91
- auto_mode = False
92
- return "⚪ Auto Mode: OFF"
93
- else:
94
- auto_mode = True
95
- thread = threading.Thread(target=auto_movement, args=(env_plot, slam_plot, audio_trigger, status_text))
 
96
  thread.daemon = True
97
  thread.start()
98
  return "🟢 Auto Mode: ON"
 
 
99
 
100
- # Reset function
101
- def reset_simulation():
102
- global robot_position, robot_path, auto_mode
103
- auto_mode = False
104
- robot_position = [0, 0]
105
- robot_path = [tuple(robot_position)]
106
- return render_env(), render_slam_map(), None, "🔄 Reset Complete"
107
-
108
- # Gradio interface
109
  with gr.Blocks() as demo:
110
- gr.Markdown("## 🤖 Robot Environment Navigation")
111
- with gr.Row():
112
- env_plot = gr.Plot(label="Environment View")
113
- slam_plot = gr.Plot(label="SLAM Map View")
114
 
115
- with gr.Row():
116
- up_btn = gr.Button("⬆️ Up")
117
- down_btn = gr.Button("⬇️ Down")
118
- left_btn = gr.Button("⬅️ Left")
119
- right_btn = gr.Button("➡️ Right")
120
 
121
  with gr.Row():
122
- auto_btn = gr.Button("🔁 Toggle Auto Mode")
123
- reset_btn = gr.Button("🔄 Reset")
124
-
125
- status_text = gr.Textbox(label="Status", interactive=False)
126
- audio_component = gr.Audio(label="Collision Sound", interactive=False, type="filepath")
127
 
128
- class AudioTrigger:
129
- def __init__(self):
130
- self.play_event = lambda path: None
131
-
132
- trigger_audio = AudioTrigger()
133
- trigger_audio.play_event = lambda path: audio_component.update(value=path) if path and os.path.isfile(path) else None
134
-
135
- up_btn.click(fn=lambda: move_robot("up"), outputs=[env_plot, slam_plot, audio_component, status_text])
136
- down_btn.click(fn=lambda: move_robot("down"), outputs=[env_plot, slam_plot, audio_component, status_text])
137
- left_btn.click(fn=lambda: move_robot("left"), outputs=[env_plot, slam_plot, audio_component, status_text])
138
- right_btn.click(fn=lambda: move_robot("right"), outputs=[env_plot, slam_plot, audio_component, status_text])
139
- auto_btn.click(fn=lambda: toggle_auto_mode(env_plot, slam_plot, trigger_audio, status_text), outputs=auto_btn)
140
- reset_btn.click(fn=reset_simulation, outputs=[env_plot, slam_plot, audio_component, status_text])
141
-
142
- demo.load(fn=reset_simulation, outputs=[env_plot, slam_plot, audio_component, status_text])
 
 
143
 
144
  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()