Shuo Li commited on
Commit
f12661e
·
0 Parent(s):

first commit

Browse files
Files changed (4) hide show
  1. flight_environment.py +177 -0
  2. main.py +54 -0
  3. path_planner.py +24 -0
  4. trajectory_generator.py +17 -0
flight_environment.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import os
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+ from math import sin,cos,tan
6
+ from mpl_toolkits.mplot3d import Axes3D
7
+
8
+ class FlightEnvironment:
9
+ def __init__(self,obs_num):
10
+ self.env_width = 20.0
11
+ self.env_length = 20.0
12
+ self.env_height = 5
13
+ self.space_size = (self.env_width,self.env_length,self.env_height)
14
+ self._obs_num = obs_num
15
+
16
+ self.cylinders = self.generate_random_cylinders(self.space_size,self._obs_num,0.1,0.3,5,5)
17
+
18
+
19
+
20
+
21
+ def generate_random_cylinders(self,space_size, N,
22
+ min_radius, max_radius,
23
+ min_height, max_height,
24
+ max_tries=100000):
25
+
26
+ X, Y, Z = space_size
27
+ cylinders = []
28
+ tries = 0
29
+
30
+ while len(cylinders) < N and tries < max_tries:
31
+ tries += 1
32
+
33
+ r = np.random.uniform(min_radius, max_radius)
34
+ h = np.random.uniform(min_height, min(max_height, Z))
35
+
36
+ x = np.random.uniform(r, X - r)
37
+ y = np.random.uniform(r, Y - r)
38
+
39
+ candidate = np.array([x, y, h, r])
40
+
41
+ no_overlapping = True
42
+ for c in cylinders:
43
+ dx = x - c[0]
44
+ dy = y - c[1]
45
+ dist = np.hypot(dx, dy)
46
+ if dist < (r + c[3]):
47
+ no_overlapping = False
48
+ break
49
+
50
+ if no_overlapping:
51
+ cylinders.append(candidate)
52
+
53
+ if len(cylinders) < N:
54
+ raise RuntimeError("Unable to generate a sufficient number of non-overlapping cylinders with the given parameters. Please reduce N or decrease the radius range.")
55
+
56
+ return np.vstack(cylinders)
57
+
58
+
59
+ def is_outside(self,point):
60
+ """
61
+ Check whether a 3D point lies outside the environment boundary.
62
+
63
+ Parameters:
64
+ point : tuple or list (x, y, z)
65
+ The coordinates of the point to be checked.
66
+
67
+ Returns:
68
+ bool
69
+ True -> the point is outside the environment limits
70
+ False -> the point is within the valid environment region
71
+ """
72
+
73
+ x,y,z = point
74
+ if (0 <= x <= self.env_width and
75
+ 0 <= y <= self.env_length and
76
+ 0 <= z <= self.env_height):
77
+ outside_env = False
78
+ else:
79
+ outside_env = True
80
+ return outside_env
81
+
82
+
83
+
84
+ def is_collide(self, point, epsilon=0.2):
85
+ """
86
+ Check whether a point in 3D space collides with a given set of cylinders (including a safety margin).
87
+
88
+ Parameters:
89
+ point: A numpy array or tuple of (x, y, z)
90
+ cylinders: An N×4 numpy array, each row is [cx, cy, h, r]
91
+ where cx, cy are the cylinder center coordinates in XY,
92
+ h is the height, and r is the radius
93
+ epsilon: Safety margin; if the point is closer than (r + epsilon),
94
+ it is also considered a collision
95
+
96
+ Returns:
97
+ True -> Collision (or too close)
98
+ False -> Safe
99
+ """
100
+ cylinders = self.cylinders
101
+ px, py, pz = point
102
+
103
+ for cx, cy, h, r in cylinders:
104
+ if not (0 <= pz <= h):
105
+ continue
106
+ dist_xy = np.sqrt((px - cx)**2 + (py - cy)**2)
107
+ if dist_xy <= (r + epsilon):
108
+ return True
109
+
110
+ return False
111
+
112
+ def plot_cylinders(self,path = None):
113
+ """
114
+ cylinders: N×4 array, [cx, cy, h, r]
115
+ """
116
+
117
+ fig = plt.figure()
118
+ ax = fig.add_subplot(111, projection='3d')
119
+
120
+ cylinders = self.cylinders
121
+ space_size = self.space_size
122
+
123
+
124
+
125
+ Xmax, Ymax, Zmax = space_size
126
+ for cx, cy, h, r in cylinders:
127
+ z = np.linspace(0, h, 30)
128
+ theta = np.linspace(0, 2 * np.pi, 30)
129
+ theta, z = np.meshgrid(theta, z)
130
+
131
+ x = cx + r * np.cos(theta)
132
+ y = cy + r * np.sin(theta)
133
+
134
+ ax.plot_surface(x, y, z, color='skyblue', alpha=0.8)
135
+ theta2 = np.linspace(0, 2*np.pi, 30)
136
+ x_top = cx + r * np.cos(theta2)
137
+ y_top = cy + r * np.sin(theta2)
138
+ z_top = np.ones_like(theta2) * h
139
+ ax.plot_trisurf(x_top, y_top, z_top, color='steelblue', alpha=0.8)
140
+
141
+ ax.set_xlim(0, self.env_width)
142
+ ax.set_ylim(0, self.env_length)
143
+ ax.set_zlim(0, self.env_height)
144
+
145
+
146
+ if path is not None:
147
+ path = np.array(path)
148
+ xs, ys, zs = path[:, 0], path[:, 1], path[:, 2]
149
+ ax.plot(xs, ys, zs, linewidth=2)
150
+ ax.scatter(xs[0], ys[0], zs[0], s=40)
151
+ ax.scatter(xs[-1], ys[-1], zs[-1], s=40)
152
+ self.set_axes_equal(ax)
153
+ plt.show()
154
+
155
+
156
+ def set_axes_equal(self,ax):
157
+ """Make axes of 3D plot have equal scale.
158
+ Compatible with Matplotlib ≥ 1.0.0
159
+ """
160
+ x_limits = ax.get_xlim3d()
161
+ y_limits = ax.get_ylim3d()
162
+ z_limits = ax.get_zlim3d()
163
+
164
+ x_range = abs(x_limits[1] - x_limits[0])
165
+ y_range = abs(y_limits[1] - y_limits[0])
166
+ z_range = abs(z_limits[1] - z_limits[0])
167
+
168
+ max_range = max([x_range, y_range, z_range]) / 2.0
169
+
170
+ mid_x = (x_limits[0] + x_limits[1]) * 0.5
171
+ mid_y = (y_limits[0] + y_limits[1]) * 0.5
172
+ mid_z = (z_limits[0] + z_limits[1]) * 0.5
173
+
174
+ ax.set_xlim3d([mid_x - max_range, mid_x + max_range])
175
+ ax.set_ylim3d([mid_y - max_range, mid_y + max_range])
176
+ ax.set_zlim3d([mid_z - max_range, mid_z + max_range])
177
+
main.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flight_environment import FlightEnvironment
2
+ from path_planner import AStarPlanner
3
+
4
+ env = FlightEnvironment(50)
5
+ start = (1,2,0)
6
+ goal = (18,18,3)
7
+
8
+ # --------------------------------------------------------------------------------------------------- #
9
+ # Call your path planning algorithm here.
10
+ # The planner should return a collision-free path and store it in the variable `path`.
11
+ # `path` must be an N×3 numpy array, where:
12
+ # - column 1 contains the x-coordinates of all path points
13
+ # - column 2 contains the y-coordinates of all path points
14
+ # - column 3 contains the z-coordinates of all path points
15
+ # This `path` array will be provided to the `env` object for visualization.
16
+
17
+ path = [[0,0,0],[1,1,1],[2,2,2],[3,3,3]]
18
+
19
+ # --------------------------------------------------------------------------------------------------- #
20
+
21
+
22
+ env.plot_cylinders(path)
23
+
24
+
25
+ # --------------------------------------------------------------------------------------------------- #
26
+ # Call your trajectory planning algorithm here. The algorithm should
27
+ # generate a smooth trajectory that passes through all the previously
28
+ # planned path points.
29
+ #
30
+ # After generating the trajectory, plot it in a new figure.
31
+ # The figure should contain three subplots showing the time histories of
32
+ # x, y, and z respectively, where the horizontal axis represents time (in seconds).
33
+ #
34
+ # Additionally, you must also plot the previously planned discrete path
35
+ # points on the same figure to clearly show how the continuous trajectory
36
+ # follows these path points.
37
+
38
+
39
+
40
+
41
+ # --------------------------------------------------------------------------------------------------- #
42
+
43
+
44
+
45
+ # You must manage this entire project using Git.
46
+ # When submitting your assignment, upload the project to a code-hosting platform
47
+ # such as GitHub or GitLab. The repository must be accessible and directly cloneable.
48
+ #
49
+ # After cloning, running `python3 main.py` in the project root directory
50
+ # should successfully execute your program and display:
51
+ # 1) the 3D path visualization, and
52
+ # 2) the trajectory plot.
53
+ #
54
+ # You must also include the link to your GitHub/GitLab repository in your written report.
path_planner.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ In this file, you should implement your own path planning class or function.
3
+ Within your implementation, you may call `env.is_collide()` and `env.is_outside()`
4
+ to verify whether candidate path points collide with obstacles or exceed the
5
+ environment boundaries.
6
+
7
+ You are required to write the path planning algorithm by yourself. Copying or calling
8
+ any existing path planning algorithms from others is strictly
9
+ prohibited. Please avoid using external packages beyond common Python libraries
10
+ such as `numpy`, `math`, or `scipy`. If you must use additional packages, you
11
+ must clearly explain the reason in your report.
12
+ """
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
trajectory_generator.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ In this file, you should implement your trajectory generation class or function.
3
+ Your method must generate a smooth 3-axis trajectory (x(t), y(t), z(t)) that
4
+ passes through all the previously computed path points. A positional deviation
5
+ up to 0.1 m from each path point is allowed.
6
+
7
+ You should output the generated trajectory and visualize it. The figure must
8
+ contain three subplots showing x, y, and z, respectively, with time t (in seconds)
9
+ as the horizontal axis. Additionally, you must plot the original discrete path
10
+ points on the same figure for comparison.
11
+
12
+ You are expected to write the implementation yourself. Do NOT copy or reuse any
13
+ existing trajectory generation code from others. Avoid using external packages
14
+ beyond general scientific libraries such as numpy, math, or scipy. If you decide
15
+ to use additional packages, you must clearly explain the reason in your report.
16
+ """
17
+