Skip to content

Commit 38c78a4

Browse files
committed
add animation
1 parent 03811e6 commit 38c78a4

File tree

2 files changed

+51
-36
lines changed

2 files changed

+51
-36
lines changed
2.91 MB
Loading

ArmNavigation/arm_obstacle_navigation/arm_obstacle_navigation.py

Lines changed: 51 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,26 @@
1010

1111
plt.ion()
1212

13-
#Simulation parameters
13+
# Simulation parameters
1414
M = 100
1515
obstacles = [[1.75, 0.75, 0.6], [0.55, 1.5, 0.5], [0, -1, 0.25]]
1616

17+
1718
def main():
1819
arm = NLinkArm([1, 1], [0, 0])
20+
start = (10, 50)
21+
goal = (58, 56)
1922
grid = get_occupancy_grid(arm, obstacles)
2023
plt.imshow(grid)
2124
plt.show()
22-
#(50,50) (58,56)
23-
route = astar_torus(grid, (10, 50), (58, 56))
25+
route = astar_torus(grid, start, goal)
2426
for node in route:
25-
theta1 = 2*pi*node[0]/M-pi
26-
theta2 = 2*pi*node[1]/M-pi
27+
theta1 = 2 * pi * node[0] / M - pi
28+
theta2 = 2 * pi * node[1] / M - pi
2729
arm.update_joints([theta1, theta2])
2830
arm.plot(obstacles=obstacles)
2931

32+
3033
def detect_collision(line_seg, circle):
3134
"""
3235
Determines whether a line segment (arm link) is in contact
@@ -48,18 +51,19 @@ def detect_collision(line_seg, circle):
4851
line_vec = b_vec - a_vec
4952
line_mag = np.linalg.norm(line_vec)
5053
circle_vec = c_vec - a_vec
51-
proj = circle_vec.dot(line_vec/line_mag)
54+
proj = circle_vec.dot(line_vec / line_mag)
5255
if proj <= 0:
5356
closest_point = a_vec
5457
elif proj >= line_mag:
5558
closest_point = b_vec
5659
else:
57-
closest_point = a_vec + line_vec*proj/line_mag
58-
if np.linalg.norm(closest_point-c_vec) > radius:
60+
closest_point = a_vec + line_vec * proj / line_mag
61+
if np.linalg.norm(closest_point - c_vec) > radius:
5962
return False
6063
else:
6164
return True
6265

66+
6367
def get_occupancy_grid(arm, obstacles):
6468
"""
6569
Discretizes joint space into M values from -pi to +pi
@@ -76,23 +80,24 @@ def get_occupancy_grid(arm, obstacles):
7680
Occupancy grid in joint space
7781
"""
7882
grid = [[0 for _ in range(M)] for _ in range(M)]
79-
theta_list = [2*i*pi/M for i in range(-M//2, M//2+1)]
83+
theta_list = [2 * i * pi / M for i in range(-M // 2, M // 2 + 1)]
8084
for i in range(M):
8185
for j in range(M):
8286
arm.update_joints([theta_list[i], theta_list[j]])
8387
points = arm.points
8488
collision_detected = False
85-
for k in range(len(points)-1):
89+
for k in range(len(points) - 1):
8690
for obstacle in obstacles:
87-
line_seg = [points[k], points[k+1]]
91+
line_seg = [points[k], points[k + 1]]
8892
collision_detected = detect_collision(line_seg, obstacle)
8993
if collision_detected:
9094
break
9195
if collision_detected:
92-
break
96+
break
9397
grid[i][j] = int(collision_detected)
9498
return np.array(grid)
9599

100+
96101
def astar_torus(grid, start_node, goal_node):
97102
"""
98103
Finds a path between an initial and goal joint configuration using
@@ -119,12 +124,12 @@ def astar_torus(grid, start_node, goal_node):
119124
heuristic_map = np.abs(X - goal_node[1]) + np.abs(Y - goal_node[0])
120125
for i in range(heuristic_map.shape[0]):
121126
for j in range(heuristic_map.shape[1]):
122-
heuristic_map[i,j] = min(heuristic_map[i,j],
123-
i + 1 + heuristic_map[M-1,j],
124-
M - i + heuristic_map[0,j],
125-
j + 1 + heuristic_map[i,M-1],
126-
M - j + heuristic_map[i,0]
127-
)
127+
heuristic_map[i, j] = min(heuristic_map[i, j],
128+
i + 1 + heuristic_map[M - 1, j],
129+
M - i + heuristic_map[0, j],
130+
j + 1 + heuristic_map[i, M - 1],
131+
M - j + heuristic_map[i, 0]
132+
)
128133

129134
explored_heuristic_map = np.full((M, M), np.inf)
130135
distance_map = np.full((M, M), np.inf)
@@ -134,7 +139,8 @@ def astar_torus(grid, start_node, goal_node):
134139
grid[start_node] = 4
135140
grid[goal_node] = 5
136141

137-
current_node = np.unravel_index(np.argmin(explored_heuristic_map, axis=None), explored_heuristic_map.shape)
142+
current_node = np.unravel_index(
143+
np.argmin(explored_heuristic_map, axis=None), explored_heuristic_map.shape)
138144
min_distance = np.min(explored_heuristic_map)
139145
if (current_node == goal_node) or np.isinf(min_distance):
140146
break
@@ -145,23 +151,23 @@ def astar_torus(grid, start_node, goal_node):
145151
i, j = current_node[0], current_node[1]
146152

147153
neighbors = []
148-
if i-1 >= 0:
149-
neighbors.append((i-1, j))
154+
if i - 1 >= 0:
155+
neighbors.append((i - 1, j))
150156
else:
151-
neighbors.append((M-1, j))
157+
neighbors.append((M - 1, j))
152158

153-
if i+1 < M:
154-
neighbors.append((i+1, j))
159+
if i + 1 < M:
160+
neighbors.append((i + 1, j))
155161
else:
156162
neighbors.append((0, j))
157163

158-
if j-1 >= 0:
159-
neighbors.append((i, j-1))
164+
if j - 1 >= 0:
165+
neighbors.append((i, j - 1))
160166
else:
161-
neighbors.append((i, M-1))
167+
neighbors.append((i, M - 1))
162168

163-
if j+1 < M:
164-
neighbors.append((i, j+1))
169+
if j + 1 < M:
170+
neighbors.append((i, j + 1))
165171
else:
166172
neighbors.append((i, 0))
167173

@@ -196,18 +202,20 @@ def astar_torus(grid, start_node, goal_node):
196202

197203
return route
198204

205+
199206
class NLinkArm(object):
200207
"""
201208
Class for controlling and plotting a planar arm with an arbitrary number of links.
202209
"""
210+
203211
def __init__(self, link_lengths, joint_angles):
204212
self.n_links = len(link_lengths)
205213
if self.n_links is not len(joint_angles):
206214
raise ValueError()
207215

208216
self.link_lengths = np.array(link_lengths)
209217
self.joint_angles = np.array(joint_angles)
210-
self.points = [[0, 0] for _ in range(self.n_links+1)]
218+
self.points = [[0, 0] for _ in range(self.n_links + 1)]
211219

212220
self.lim = sum(link_lengths)
213221
self.update_points()
@@ -217,28 +225,35 @@ def update_joints(self, joint_angles):
217225
self.update_points()
218226

219227
def update_points(self):
220-
for i in range(1, self.n_links+1):
221-
self.points[i][0] = self.points[i-1][0] + self.link_lengths[i-1]*np.cos(np.sum(self.joint_angles[:i]))
222-
self.points[i][1] = self.points[i-1][1] + self.link_lengths[i-1]*np.sin(np.sum(self.joint_angles[:i]))
228+
for i in range(1, self.n_links + 1):
229+
self.points[i][0] = self.points[i - 1][0] + \
230+
self.link_lengths[i - 1] * \
231+
np.cos(np.sum(self.joint_angles[:i]))
232+
self.points[i][1] = self.points[i - 1][1] + \
233+
self.link_lengths[i - 1] * \
234+
np.sin(np.sum(self.joint_angles[:i]))
223235

224236
self.end_effector = np.array(self.points[self.n_links]).T
225237

226238
def plot(self, obstacles=[]):
227239
plt.cla()
228240

229241
for obstacle in obstacles:
230-
circle = plt.Circle((obstacle[0], obstacle[1]), radius=0.5*obstacle[2], fc='k')
242+
circle = plt.Circle(
243+
(obstacle[0], obstacle[1]), radius=0.5 * obstacle[2], fc='k')
231244
plt.gca().add_patch(circle)
232245

233-
for i in range(self.n_links+1):
246+
for i in range(self.n_links + 1):
234247
if i is not self.n_links:
235-
plt.plot([self.points[i][0], self.points[i+1][0]], [self.points[i][1], self.points[i+1][1]], 'r-')
248+
plt.plot([self.points[i][0], self.points[i + 1][0]],
249+
[self.points[i][1], self.points[i + 1][1]], 'r-')
236250
plt.plot(self.points[i][0], self.points[i][1], 'k.')
237251

238252
plt.xlim([-self.lim, self.lim])
239253
plt.ylim([-self.lim, self.lim])
240254
plt.draw()
241255
plt.pause(1e-5)
242256

257+
243258
if __name__ == '__main__':
244259
main()

0 commit comments

Comments
 (0)