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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +105 -162
app.py CHANGED
@@ -1,201 +1,144 @@
1
  import gradio as gr
2
  import matplotlib.pyplot as plt
3
- import matplotlib.patches as patches
4
- import matplotlib.image as mpimg
5
  import numpy as np
6
- import random
7
  import threading
8
  import time
 
9
 
10
- # Global simulation state
11
- pose = {"x": 0, "z": 0, "angle": 0}
12
- trajectory = [(0, 0)]
13
- obstacle_hits = []
14
- color_index = 0
15
- noise_enabled = True
16
- obstacles = []
17
  auto_mode = False
18
- auto_direction = 'W'
19
 
20
- rgb_colors = ['red', 'green', 'blue']
 
 
21
 
 
 
 
 
 
 
 
 
22
 
23
- def generate_obstacles(count=10):
24
- return [{
25
- "x": random.uniform(-8, 8),
26
- "z": random.uniform(-8, 8),
27
- "radius": random.uniform(0.5, 1.2)
28
- } for _ in range(count)]
29
-
30
-
31
- obstacles = generate_obstacles(10)
32
-
33
-
34
- def toggle_noise():
35
- global noise_enabled
36
- noise_enabled = not noise_enabled
37
- return f"Noise: {'ON' if noise_enabled else 'OFF'}"
38
-
39
-
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(), "", f"Simulation Reset with {count} obstacles"
48
-
49
-
50
- def check_collision(x, z):
51
- for obs in obstacles:
52
- dist = np.hypot(obs["x"] - x, obs["z"] - z)
53
- if dist <= obs["radius"] + 0.2:
54
- return True
55
- return False
56
-
57
-
58
- def move_robot(direction):
59
- global pose, trajectory
60
- direction = direction.upper()
61
- step = 1
62
- new_x, new_z = pose["x"], pose["z"]
63
-
64
- angle_map = {"W": 90, "S": -90, "A": 180, "D": 0}
65
- move_map = {"W": (0, step), "S": (0, -step), "A": (-step, 0), "D": (step, 0)}
66
-
67
- if direction in move_map:
68
- dx, dz = move_map[direction]
69
- new_x += dx
70
- new_z += dz
71
- pose["angle"] = angle_map[direction]
72
- else:
73
- return render_env(), render_slam_map(), "", "❌ Invalid Key"
74
-
75
- if check_collision(new_x, new_z):
76
- return render_env(), render_slam_map(), "collision1.mp3", "🚫 Collision Detected!"
77
-
78
- pose["x"], pose["z"] = new_x, new_z
79
- noisy_x = pose["x"] + random.uniform(-0.1, 0.1) if noise_enabled else pose["x"]
80
- noisy_z = pose["z"] + random.uniform(-0.1, 0.1) if noise_enabled else pose["z"]
81
- trajectory.append((noisy_x, noisy_z))
82
-
83
- return render_env(), render_slam_map(), "", f"Moved {direction}"
84
 
 
 
 
 
85
 
86
- def render_env():
87
- fig, ax = plt.subplots()
88
- ax.set_xlim(-10, 10)
89
- ax.set_ylim(-10, 10)
90
- ax.set_title("SLAM Environment View")
91
-
92
- try:
93
- bg = mpimg.imread("map.png")
94
- ax.imshow(bg, extent=(-10, 10, -10, 10), alpha=0.2)
95
- except:
96
- pass
97
-
98
- for obs in obstacles:
99
- ax.add_patch(plt.Circle((obs["x"], obs["z"]), obs["radius"], color="gray", alpha=0.6))
100
-
101
- ax.plot(pose["x"], pose["z"], 'ro', markersize=8)
102
-
103
- angles = np.linspace(0, 2 * np.pi, 24)
104
- for ang in angles:
105
- for r in np.linspace(0, 3, 30):
106
- scan_x = pose["x"] + r * np.cos(ang)
107
- scan_z = pose["z"] + r * np.sin(ang)
108
- if check_collision(scan_x, scan_z):
109
- ax.plot([pose["x"], scan_x], [pose["z"], scan_z], 'g-', linewidth=0.5)
110
- obstacle_hits.append((scan_x, scan_z))
111
- break
112
-
113
- plt.close(fig)
114
  return fig
115
 
116
-
117
  def render_slam_map():
118
- global color_index
119
- fig, ax = plt.subplots()
120
- ax.set_title("SLAM Trajectory Map")
121
- x_vals = [x for x, _ in trajectory]
122
- z_vals = [z for _, z in trajectory]
123
- ax.plot(x_vals, z_vals, 'bo-', markersize=3)
124
- ax.grid(True)
125
-
126
- if obstacle_hits:
127
- current_color = rgb_colors[color_index % len(rgb_colors)]
128
- for hit in obstacle_hits[-20:]:
129
- ax.plot(hit[0], hit[1], 'o', color=current_color, markersize=6)
130
- color_index += 1
131
-
132
- plt.close(fig)
133
  return fig
134
 
 
 
 
 
 
 
 
 
135
 
136
- def handle_text_input(direction):
137
- return move_robot(direction.strip().upper())
 
 
 
 
 
138
 
 
 
 
139
 
140
- # Auto Mode Handler
141
- def auto_movement(status_text, env_plot, slam_plot, audio_component):
142
  global auto_mode
 
 
143
  while auto_mode:
144
- env, slam, sound, msg = move_robot(auto_direction)
145
- status_text.update(value=f"[AUTO] {msg}")
146
- env_plot.update(value=env)
147
- slam_plot.update(value=slam)
148
- if sound:
149
- audio_component.update(value=sound)
150
- time.sleep(1)
 
151
 
 
 
152
 
153
- def toggle_auto_mode(status_text, env_plot, slam_plot, audio_component):
 
154
  global auto_mode
155
- auto_mode = not auto_mode
156
  if auto_mode:
157
- thread = threading.Thread(
158
- target=auto_movement, args=(status_text, env_plot, slam_plot, audio_component))
 
 
 
159
  thread.daemon = True
160
  thread.start()
161
  return "🟢 Auto Mode: ON"
162
- else:
163
- return "⚪ Auto Mode: OFF"
164
 
 
 
 
 
 
 
 
165
 
166
- # Gradio UI
167
  with gr.Blocks() as demo:
168
- gr.Markdown("## 🤖 SLAM Simulation (Auto Mode + Collision Sound)")
 
 
 
169
 
170
- obstacle_slider = gr.Slider(1, 20, value=10, step=1, label="Number of Obstacles")
171
- direction_input = gr.Textbox(label="Type W / A / S / D and press Enter", placeholder="e.g., W")
172
- status_text = gr.Textbox(label="Status", interactive=False)
 
 
173
 
174
  with gr.Row():
175
- env_plot = gr.Plot(label="Robot View")
176
- slam_plot = gr.Plot(label="SLAM Map")
177
 
178
- audio_component = gr.Audio(label="", visible=False)
 
179
 
180
- with gr.Row():
181
- w = gr.Button("⬆️ W")
182
- a = gr.Button("⬅️ A")
183
- s = gr.Button("⬇️ S")
184
- d = gr.Button("➡️ D")
185
- reset = gr.Button("🔄 Reset")
186
- toggle = gr.Button("🔀 Toggle Noise")
187
- auto = gr.Button("🤖 Toggle Auto")
188
-
189
- w.click(fn=lambda: move_robot("W"), outputs=[env_plot, slam_plot, audio_component, status_text])
190
- a.click(fn=lambda: move_robot("A"), outputs=[env_plot, slam_plot, audio_component, status_text])
191
- s.click(fn=lambda: move_robot("S"), outputs=[env_plot, slam_plot, audio_component, status_text])
192
- d.click(fn=lambda: move_robot("D"), outputs=[env_plot, slam_plot, audio_component, status_text])
193
-
194
- reset.click(fn=reset_sim, inputs=[obstacle_slider], outputs=[env_plot, slam_plot, audio_component, status_text])
195
- toggle.click(fn=lambda: (None, None, "", toggle_noise()), outputs=[env_plot, slam_plot, audio_component, status_text])
196
- auto.click(fn=toggle_auto_mode, inputs=[status_text, env_plot, slam_plot, audio_component], outputs=auto)
197
-
198
- direction_input.submit(fn=handle_text_input, inputs=direction_input,
199
- outputs=[env_plot, slam_plot, audio_component, status_text])
200
 
201
  demo.launch()
 
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()