YashsharmaPhD commited on
Commit
9b2a61a
·
verified ·
1 Parent(s): a8ea3e5

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +149 -0
app.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import matplotlib.pyplot as plt
3
+ import matplotlib.image as mpimg
4
+ import numpy as np
5
+ import random
6
+ import threading
7
+ import time
8
+
9
+ # Global state
10
+ pose = {"x": 0, "z": 0, "angle": 0}
11
+ trajectory = [(0, 0)]
12
+ obstacle_hits = []
13
+ color_index = 0
14
+ rgb_colors = ['red', 'green', 'blue']
15
+ noise_enabled = True
16
+ obstacles = []
17
+ auto_mode = True
18
+
19
+ def generate_obstacles(count=10):
20
+ return [{
21
+ "x": random.uniform(-8, 8),
22
+ "z": random.uniform(-8, 8),
23
+ "radius": random.uniform(0.5, 1.2)
24
+ } for _ in range(count)]
25
+
26
+ obstacles = generate_obstacles(10)
27
+
28
+ def reset_sim(count):
29
+ global pose, trajectory, obstacles, obstacle_hits, color_index
30
+ pose = {"x": 0, "z": 0, "angle": 0}
31
+ trajectory = [(0, 0)]
32
+ obstacle_hits.clear()
33
+ color_index = 0
34
+ obstacles[:] = generate_obstacles(int(count))
35
+ return render_env(), render_slam_map(), f"Simulation Reset with {count} obstacles"
36
+
37
+ def check_collision(x, z):
38
+ if abs(x) > 10 or abs(z) > 10:
39
+ return True
40
+ for obs in obstacles:
41
+ dist = np.sqrt((obs["x"] - x)**2 + (obs["z"] - z)**2)
42
+ if dist <= obs["radius"] + 0.3:
43
+ return True
44
+ return False
45
+
46
+ def try_move(dx, dz):
47
+ global pose, trajectory
48
+ new_x = pose["x"] + dx
49
+ new_z = pose["z"] + dz
50
+ if not check_collision(new_x, new_z):
51
+ pose["x"], pose["z"] = new_x, new_z
52
+ if noise_enabled:
53
+ noisy_x = pose["x"] + random.uniform(-0.1, 0.1)
54
+ noisy_z = pose["z"] + random.uniform(-0.1, 0.1)
55
+ trajectory.append((noisy_x, noisy_z))
56
+ else:
57
+ trajectory.append((pose["x"], pose["z"]))
58
+ return True
59
+ return False
60
+
61
+ def smart_auto_step():
62
+ directions = [(0, 1), (-1, 0), (1, 0), (0, -1)] # N, W, E, S
63
+ random.shuffle(directions)
64
+ for dx, dz in directions:
65
+ if try_move(dx, dz):
66
+ return f"Moved to ({pose['x']:.1f}, {pose['z']:.1f})"
67
+ return "No movement: blocked by obstacles"
68
+
69
+ def render_env():
70
+ global obstacle_hits
71
+ fig, ax = plt.subplots(figsize=(5, 5))
72
+ ax.set_xlim(-10, 10)
73
+ ax.set_ylim(-10, 10)
74
+ ax.set_title("SLAM Environment View")
75
+
76
+ for obs in obstacles:
77
+ circ = plt.Circle((obs["x"], obs["z"]), obs["radius"], color="gray", alpha=0.6)
78
+ ax.add_patch(circ)
79
+
80
+ ax.plot(pose["x"], pose["z"], 'ro', markersize=8)
81
+
82
+ # Clear and regenerate hits
83
+ obstacle_hits.clear()
84
+ angles = np.linspace(0, 2*np.pi, 24)
85
+ for ang in angles:
86
+ for r in np.linspace(0, 3, 30):
87
+ scan_x = pose["x"] + r * np.cos(ang)
88
+ scan_z = pose["z"] + r * np.sin(ang)
89
+ if check_collision(scan_x, scan_z):
90
+ ax.plot([pose["x"], scan_x], [pose["z"], scan_z], 'g-', linewidth=0.5)
91
+ obstacle_hits.append((scan_x, scan_z))
92
+ break
93
+
94
+ plt.close(fig)
95
+ return fig
96
+
97
+ def render_slam_map():
98
+ global color_index
99
+ fig, ax = plt.subplots(figsize=(5, 5))
100
+ ax.set_title("SLAM Trajectory Map")
101
+ x_vals = [x for x, z in trajectory]
102
+ z_vals = [z for x, z in trajectory]
103
+ ax.plot(x_vals, z_vals, 'bo-', markersize=3)
104
+ ax.grid(True)
105
+
106
+ if obstacle_hits:
107
+ current_color = rgb_colors[color_index % len(rgb_colors)]
108
+ for hit in obstacle_hits[-20:]:
109
+ ax.plot(hit[0], hit[1], 'o', color=current_color, markersize=6)
110
+ color_index += 1
111
+
112
+ plt.close(fig)
113
+ return fig
114
+
115
+ def auto_movement(update_callback):
116
+ while auto_mode:
117
+ msg = smart_auto_step()
118
+ env = render_env()
119
+ slam = render_slam_map()
120
+ update_callback(env, slam, msg)
121
+ time.sleep(0.5)
122
+
123
+ # Gradio UI
124
+ with gr.Blocks() as demo:
125
+ gr.Markdown("## 🤖 Automatic SLAM Snake-like Navigation")
126
+
127
+ obstacle_slider = gr.Slider(1, 20, value=10, step=1, label="Number of Obstacles")
128
+ status_text = gr.Textbox(label="Status", interactive=False)
129
+
130
+ with gr.Row():
131
+ with gr.Column():
132
+ env_plot = gr.Plot(label="Robot View")
133
+ with gr.Column():
134
+ slam_plot = gr.Plot(label="SLAM Map")
135
+
136
+ reset = gr.Button("🔄 Reset")
137
+
138
+ reset.click(fn=reset_sim, inputs=[obstacle_slider], outputs=[env_plot, slam_plot, status_text])
139
+
140
+ def update_ui(e, s, t):
141
+ env_plot.update(value=e)
142
+ slam_plot.update(value=s)
143
+ status_text.update(value=t)
144
+
145
+ # Start auto mode immediately
146
+ thread = threading.Thread(target=auto_movement, args=(update_ui,), daemon=True)
147
+ thread.start()
148
+
149
+ demo.launch()