YashsharmaPhD commited on
Commit
faeda15
·
verified ·
1 Parent(s): bc39a14

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -50
app.py CHANGED
@@ -18,15 +18,8 @@ SCAN_ANGLE = 60
18
  SCAN_RESOLUTION = 30
19
  SCAN_RANGE_DEFAULT = 6.0
20
  OBSTACLE_COUNT = 10
21
- scan_range = 5.0 # or whatever range your LiDAR/scanner is expected to use
22
-
23
-
24
- # State variables
25
- robot_pose = {'x': 0.0, 'y': 0.0, 'angle': 0.0}
26
- trajectory = []
27
- slam_points = []
28
- obstacles = []
29
 
 
30
  def to_canvas_coords(x, y):
31
  cx = int((x + WORLD_UNITS / 2) * SCALE)
32
  cy = int((WORLD_UNITS / 2 - y) * SCALE)
@@ -87,25 +80,30 @@ def move_robot(robot_pose, obstacles):
87
  def draw_environment(robot_pose, trajectory, obstacles):
88
  img = Image.new("RGB", (SPACE_SIZE, SPACE_SIZE), "white")
89
  draw = ImageDraw.Draw(img)
90
- # Draw grid lines
91
- for i in range(int(WORLD_UNITS)+1):
 
92
  x = int(i * SCALE)
93
- draw.line([(x,0), (x, SPACE_SIZE)], fill=(230,230,230))
94
- draw.line([(0,x), (SPACE_SIZE, x)], fill=(230,230,230))
95
- # Draw obstacles
 
96
  for ox, oy in obstacles:
97
  cx, cy = to_canvas_coords(ox, oy)
98
  r = int(OBSTACLE_RADIUS * SCALE)
99
  draw.ellipse([cx - r, cy - r, cx + r, cy + r], fill="gray")
100
- # Draw trajectory
 
101
  if len(trajectory) > 1:
102
  points = [to_canvas_coords(x, y) for x, y in trajectory]
103
  draw.line(points, fill="blue", width=2)
104
- # Draw robot
 
105
  rx, ry = to_canvas_coords(robot_pose['x'], robot_pose['y'])
106
  r = int(ROBOT_RADIUS * SCALE)
107
  draw.ellipse([rx - r, ry - r, rx + r, ry + r], fill="red")
108
- # Draw heading arrow
 
109
  dx = math.cos(math.radians(robot_pose['angle'])) * ROBOT_RADIUS * 2 * SCALE
110
  dy = math.sin(math.radians(robot_pose['angle'])) * ROBOT_RADIUS * 2 * SCALE
111
  draw.line([rx, ry, rx + dx, ry - dy], fill="darkred", width=2)
@@ -114,48 +112,49 @@ def draw_environment(robot_pose, trajectory, obstacles):
114
  def draw_slam_map(robot_pose, slam_points, scan_range):
115
  img = Image.new("RGB", (SPACE_SIZE, SPACE_SIZE), "white")
116
  draw = ImageDraw.Draw(img)
117
- # Draw grid lines
118
- for i in range(int(WORLD_UNITS)+1):
 
119
  x = int(i * SCALE)
120
- draw.line([(x,0), (x, SPACE_SIZE)], fill=(230,230,230))
121
- draw.line([(0,x), (SPACE_SIZE, x)], fill=(230,230,230))
122
- # Draw laser scan rays
 
123
  angles = np.linspace(-SCAN_ANGLE / 2, SCAN_ANGLE / 2, SCAN_RESOLUTION) + robot_pose['angle']
124
  for a in angles:
125
  rad = math.radians(a)
126
  dist = scan_range
127
- # Find closest slam point along this angle
128
- closest_dist = None
129
  for px, py in slam_points:
130
  vx, vy = px - robot_pose['x'], py - robot_pose['y']
131
  point_dist = math.hypot(vx, vy)
132
  point_angle = math.degrees(math.atan2(vy, vx))
133
  angle_diff = abs((point_angle - a + 180) % 360 - 180)
134
  if angle_diff < SCAN_ANGLE / SCAN_RESOLUTION:
135
- if closest_dist is None or point_dist < closest_dist:
136
- closest_dist = point_dist
137
- if closest_dist is not None:
138
- dist = closest_dist
139
  x_end = robot_pose['x'] + dist * math.cos(rad)
140
  y_end = robot_pose['y'] + dist * math.sin(rad)
141
  cx_start, cy_start = to_canvas_coords(robot_pose['x'], robot_pose['y'])
142
  cx_end, cy_end = to_canvas_coords(x_end, y_end)
143
  draw.line([cx_start, cy_start, cx_end, cy_end], fill="green")
144
- # Draw slam points
 
145
  for px, py in slam_points:
146
  cx, cy = to_canvas_coords(px, py)
147
- draw.ellipse([cx-2, cy-2, cx+2, cy+2], fill="black")
148
- # Draw robot
 
149
  rx, ry = to_canvas_coords(robot_pose['x'], robot_pose['y'])
150
  r = int(ROBOT_RADIUS * SCALE)
151
  draw.ellipse([rx - r, ry - r, rx + r, ry + r], fill="red")
152
- # Draw heading arrow
 
153
  dx = math.cos(math.radians(robot_pose['angle'])) * ROBOT_RADIUS * 2 * SCALE
154
  dy = math.sin(math.radians(robot_pose['angle'])) * ROBOT_RADIUS * 2 * SCALE
155
  draw.line([rx, ry, rx + dx, ry - dy], fill="red", width=2)
156
  return img
157
 
158
- # State container to persist between calls
159
  class SimulationState:
160
  def __init__(self):
161
  self.robot_pose = {'x': 0.0, 'y': 0.0, 'angle': 0.0}
@@ -167,6 +166,7 @@ class SimulationState:
167
 
168
  state = SimulationState()
169
 
 
170
  def reset_simulation(obstacle_count):
171
  state.robot_pose = {'x': 0.0, 'y': 0.0, 'angle': 0.0}
172
  state.trajectory = []
@@ -179,43 +179,39 @@ def reset_simulation(obstacle_count):
179
  return env_img, slam_img, "Simulation reset"
180
 
181
  def step_simulation(scan_range):
182
- # Move robot and update trajectory
183
  pose_before = state.robot_pose.copy()
184
  new_pose, moved = move_robot(state.robot_pose, state.obstacles)
185
  if moved:
186
  state.trajectory.append((new_pose['x'], new_pose['y']))
187
- # Scan environment and update slam points
188
  new_points = scan_environment(state.robot_pose, state.obstacles, scan_range)
189
- # Add only new points that are not close to existing points
190
  for pt in new_points:
191
  if all(math.hypot(pt[0] - p[0], pt[1] - p[1]) > 0.1 for p in state.slam_points):
192
  state.slam_points.append(pt)
193
- # Draw images
194
  env_img = draw_environment(state.robot_pose, state.trajectory, state.obstacles)
195
- #slam_img = gr.Image(label="SLAM Map View", height=SPACE_SIZE, width=SPACE_SIZE)
196
- #slam_img = draw_slam_map(state.robot_pose, state.slam_points, scan_range)
197
- slam_img = draw_slam_map(state.robot_pose, state.slam_points)
198
 
199
- # If recording, save frames
200
  if state.recording:
201
  combined = Image.new('RGB', (SPACE_SIZE * 2, SPACE_SIZE))
202
  combined.paste(env_img, (0, 0))
203
  combined.paste(slam_img, (SPACE_SIZE, 0))
204
  state.video_frames.append(np.array(combined))
 
205
  return env_img, slam_img, f"Robot moved: {moved}, Position: ({state.robot_pose['x']:.2f}, {state.robot_pose['y']:.2f})"
206
 
207
  def toggle_recording(record):
208
  state.recording = record
209
- if not record:
210
- # Stop recording
211
- if len(state.video_frames) == 0:
212
- return None
213
- video_path = "/tmp/slam_simulation.mp4"
214
- imageio.mimsave(video_path, state.video_frames, fps=10)
215
- return video_path
216
- else:
217
- state.video_frames = []
218
- return None
219
 
220
  # Default obstacle count
221
  OBSTACLE_COUNT = 10
 
18
  SCAN_RESOLUTION = 30
19
  SCAN_RANGE_DEFAULT = 6.0
20
  OBSTACLE_COUNT = 10
 
 
 
 
 
 
 
 
21
 
22
+ # Utilities
23
  def to_canvas_coords(x, y):
24
  cx = int((x + WORLD_UNITS / 2) * SCALE)
25
  cy = int((WORLD_UNITS / 2 - y) * SCALE)
 
80
  def draw_environment(robot_pose, trajectory, obstacles):
81
  img = Image.new("RGB", (SPACE_SIZE, SPACE_SIZE), "white")
82
  draw = ImageDraw.Draw(img)
83
+
84
+ # Grid
85
+ for i in range(int(WORLD_UNITS) + 1):
86
  x = int(i * SCALE)
87
+ draw.line([(x, 0), (x, SPACE_SIZE)], fill=(230, 230, 230))
88
+ draw.line([(0, x), (SPACE_SIZE, x)], fill=(230, 230, 230))
89
+
90
+ # Obstacles
91
  for ox, oy in obstacles:
92
  cx, cy = to_canvas_coords(ox, oy)
93
  r = int(OBSTACLE_RADIUS * SCALE)
94
  draw.ellipse([cx - r, cy - r, cx + r, cy + r], fill="gray")
95
+
96
+ # Trajectory
97
  if len(trajectory) > 1:
98
  points = [to_canvas_coords(x, y) for x, y in trajectory]
99
  draw.line(points, fill="blue", width=2)
100
+
101
+ # Robot
102
  rx, ry = to_canvas_coords(robot_pose['x'], robot_pose['y'])
103
  r = int(ROBOT_RADIUS * SCALE)
104
  draw.ellipse([rx - r, ry - r, rx + r, ry + r], fill="red")
105
+
106
+ # Heading
107
  dx = math.cos(math.radians(robot_pose['angle'])) * ROBOT_RADIUS * 2 * SCALE
108
  dy = math.sin(math.radians(robot_pose['angle'])) * ROBOT_RADIUS * 2 * SCALE
109
  draw.line([rx, ry, rx + dx, ry - dy], fill="darkred", width=2)
 
112
  def draw_slam_map(robot_pose, slam_points, scan_range):
113
  img = Image.new("RGB", (SPACE_SIZE, SPACE_SIZE), "white")
114
  draw = ImageDraw.Draw(img)
115
+
116
+ # Grid
117
+ for i in range(int(WORLD_UNITS) + 1):
118
  x = int(i * SCALE)
119
+ draw.line([(x, 0), (x, SPACE_SIZE)], fill=(230, 230, 230))
120
+ draw.line([(0, x), (SPACE_SIZE, x)], fill=(230, 230, 230))
121
+
122
+ # Laser scan lines
123
  angles = np.linspace(-SCAN_ANGLE / 2, SCAN_ANGLE / 2, SCAN_RESOLUTION) + robot_pose['angle']
124
  for a in angles:
125
  rad = math.radians(a)
126
  dist = scan_range
 
 
127
  for px, py in slam_points:
128
  vx, vy = px - robot_pose['x'], py - robot_pose['y']
129
  point_dist = math.hypot(vx, vy)
130
  point_angle = math.degrees(math.atan2(vy, vx))
131
  angle_diff = abs((point_angle - a + 180) % 360 - 180)
132
  if angle_diff < SCAN_ANGLE / SCAN_RESOLUTION:
133
+ if point_dist < dist:
134
+ dist = point_dist
 
 
135
  x_end = robot_pose['x'] + dist * math.cos(rad)
136
  y_end = robot_pose['y'] + dist * math.sin(rad)
137
  cx_start, cy_start = to_canvas_coords(robot_pose['x'], robot_pose['y'])
138
  cx_end, cy_end = to_canvas_coords(x_end, y_end)
139
  draw.line([cx_start, cy_start, cx_end, cy_end], fill="green")
140
+
141
+ # SLAM points
142
  for px, py in slam_points:
143
  cx, cy = to_canvas_coords(px, py)
144
+ draw.ellipse([cx - 2, cy - 2, cx + 2, cy + 2], fill="black")
145
+
146
+ # Robot
147
  rx, ry = to_canvas_coords(robot_pose['x'], robot_pose['y'])
148
  r = int(ROBOT_RADIUS * SCALE)
149
  draw.ellipse([rx - r, ry - r, rx + r, ry + r], fill="red")
150
+
151
+ # Heading
152
  dx = math.cos(math.radians(robot_pose['angle'])) * ROBOT_RADIUS * 2 * SCALE
153
  dy = math.sin(math.radians(robot_pose['angle'])) * ROBOT_RADIUS * 2 * SCALE
154
  draw.line([rx, ry, rx + dx, ry - dy], fill="red", width=2)
155
  return img
156
 
157
+ # Simulation State
158
  class SimulationState:
159
  def __init__(self):
160
  self.robot_pose = {'x': 0.0, 'y': 0.0, 'angle': 0.0}
 
166
 
167
  state = SimulationState()
168
 
169
+ # Handlers
170
  def reset_simulation(obstacle_count):
171
  state.robot_pose = {'x': 0.0, 'y': 0.0, 'angle': 0.0}
172
  state.trajectory = []
 
179
  return env_img, slam_img, "Simulation reset"
180
 
181
  def step_simulation(scan_range):
 
182
  pose_before = state.robot_pose.copy()
183
  new_pose, moved = move_robot(state.robot_pose, state.obstacles)
184
  if moved:
185
  state.trajectory.append((new_pose['x'], new_pose['y']))
186
+
187
  new_points = scan_environment(state.robot_pose, state.obstacles, scan_range)
 
188
  for pt in new_points:
189
  if all(math.hypot(pt[0] - p[0], pt[1] - p[1]) > 0.1 for p in state.slam_points):
190
  state.slam_points.append(pt)
191
+
192
  env_img = draw_environment(state.robot_pose, state.trajectory, state.obstacles)
193
+ slam_img = draw_slam_map(state.robot_pose, state.slam_points, scan_range)
 
 
194
 
 
195
  if state.recording:
196
  combined = Image.new('RGB', (SPACE_SIZE * 2, SPACE_SIZE))
197
  combined.paste(env_img, (0, 0))
198
  combined.paste(slam_img, (SPACE_SIZE, 0))
199
  state.video_frames.append(np.array(combined))
200
+
201
  return env_img, slam_img, f"Robot moved: {moved}, Position: ({state.robot_pose['x']:.2f}, {state.robot_pose['y']:.2f})"
202
 
203
  def toggle_recording(record):
204
  state.recording = record
205
+ return f"Recording {'started' if record else 'stopped'}."
206
+
207
+ def export_video():
208
+ if not state.video_frames:
209
+ return None, "No frames recorded."
210
+ buffer = io.BytesIO()
211
+ imageio.mimsave(buffer, state.video_frames, format="GIF", duration=0.1)
212
+ buffer.seek(0)
213
+ return buffer, "Video exported."
214
+
215
 
216
  # Default obstacle count
217
  OBSTACLE_COUNT = 10