mirror of
https://github.com/AtsushiSakai/PythonRobotics.git
synced 2026-01-10 23:18:03 -05:00
334 lines
12 KiB
Python
334 lines
12 KiB
Python
"""
|
|
Bug Planning
|
|
author: Sarim Mehdi(muhammadsarim.mehdi@studio.unibo.it)
|
|
Source: https://web.archive.org/web/20201103052224/https://sites.google.com/site/ece452bugalgorithms/
|
|
"""
|
|
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
|
|
show_animation = True
|
|
|
|
|
|
class BugPlanner:
|
|
def __init__(self, start_x, start_y, goal_x, goal_y, obs_x, obs_y):
|
|
self.goal_x = goal_x
|
|
self.goal_y = goal_y
|
|
self.obs_x = obs_x
|
|
self.obs_y = obs_y
|
|
self.r_x = [start_x]
|
|
self.r_y = [start_y]
|
|
self.out_x = []
|
|
self.out_y = []
|
|
for o_x, o_y in zip(obs_x, obs_y):
|
|
for add_x, add_y in zip([1, 0, -1, -1, -1, 0, 1, 1],
|
|
[1, 1, 1, 0, -1, -1, -1, 0]):
|
|
cand_x, cand_y = o_x+add_x, o_y+add_y
|
|
valid_point = True
|
|
for _x, _y in zip(obs_x, obs_y):
|
|
if cand_x == _x and cand_y == _y:
|
|
valid_point = False
|
|
break
|
|
if valid_point:
|
|
self.out_x.append(cand_x), self.out_y.append(cand_y)
|
|
|
|
def mov_normal(self):
|
|
return self.r_x[-1] + np.sign(self.goal_x - self.r_x[-1]), \
|
|
self.r_y[-1] + np.sign(self.goal_y - self.r_y[-1])
|
|
|
|
def mov_to_next_obs(self, visited_x, visited_y):
|
|
for add_x, add_y in zip([1, 0, -1, 0], [0, 1, 0, -1]):
|
|
c_x, c_y = self.r_x[-1] + add_x, self.r_y[-1] + add_y
|
|
for _x, _y in zip(self.out_x, self.out_y):
|
|
use_pt = True
|
|
if c_x == _x and c_y == _y:
|
|
for v_x, v_y in zip(visited_x, visited_y):
|
|
if c_x == v_x and c_y == v_y:
|
|
use_pt = False
|
|
break
|
|
if use_pt:
|
|
return c_x, c_y, False
|
|
if not use_pt:
|
|
break
|
|
return self.r_x[-1], self.r_y[-1], True
|
|
|
|
def bug0(self):
|
|
"""
|
|
Greedy algorithm where you move towards goal
|
|
until you hit an obstacle. Then you go around it
|
|
(pick an arbitrary direction), until it is possible
|
|
for you to start moving towards goal in a greedy manner again
|
|
"""
|
|
mov_dir = 'normal'
|
|
cand_x, cand_y = -np.inf, -np.inf
|
|
if show_animation:
|
|
plt.plot(self.obs_x, self.obs_y, ".k")
|
|
plt.plot(self.r_x[-1], self.r_y[-1], "og")
|
|
plt.plot(self.goal_x, self.goal_y, "xb")
|
|
plt.plot(self.out_x, self.out_y, ".")
|
|
plt.grid(True)
|
|
plt.title('BUG 0')
|
|
|
|
for x_ob, y_ob in zip(self.out_x, self.out_y):
|
|
if self.r_x[-1] == x_ob and self.r_y[-1] == y_ob:
|
|
mov_dir = 'obs'
|
|
break
|
|
|
|
visited_x, visited_y = [], []
|
|
while True:
|
|
if self.r_x[-1] == self.goal_x and \
|
|
self.r_y[-1] == self.goal_y:
|
|
break
|
|
if mov_dir == 'normal':
|
|
cand_x, cand_y = self.mov_normal()
|
|
if mov_dir == 'obs':
|
|
cand_x, cand_y, _ = self.mov_to_next_obs(visited_x, visited_y)
|
|
if mov_dir == 'normal':
|
|
found_boundary = False
|
|
for x_ob, y_ob in zip(self.out_x, self.out_y):
|
|
if cand_x == x_ob and cand_y == y_ob:
|
|
self.r_x.append(cand_x), self.r_y.append(cand_y)
|
|
visited_x[:], visited_y[:] = [], []
|
|
visited_x.append(cand_x), visited_y.append(cand_y)
|
|
mov_dir = 'obs'
|
|
found_boundary = True
|
|
break
|
|
if not found_boundary:
|
|
self.r_x.append(cand_x), self.r_y.append(cand_y)
|
|
elif mov_dir == 'obs':
|
|
can_go_normal = True
|
|
for x_ob, y_ob in zip(self.obs_x, self.obs_y):
|
|
if self.mov_normal()[0] == x_ob and \
|
|
self.mov_normal()[1] == y_ob:
|
|
can_go_normal = False
|
|
break
|
|
if can_go_normal:
|
|
mov_dir = 'normal'
|
|
else:
|
|
self.r_x.append(cand_x), self.r_y.append(cand_y)
|
|
visited_x.append(cand_x), visited_y.append(cand_y)
|
|
if show_animation:
|
|
plt.plot(self.r_x, self.r_y, "-r")
|
|
plt.pause(0.001)
|
|
if show_animation:
|
|
plt.show()
|
|
|
|
def bug1(self):
|
|
"""
|
|
Move towards goal in a greedy manner.
|
|
When you hit an obstacle, you go around it and
|
|
back to where you hit the obstacle initially.
|
|
Then, you go to the point on the obstacle that is
|
|
closest to your goal and you start moving towards
|
|
goal in a greedy manner from that new point.
|
|
"""
|
|
mov_dir = 'normal'
|
|
cand_x, cand_y = -np.inf, -np.inf
|
|
exit_x, exit_y = -np.inf, -np.inf
|
|
dist = np.inf
|
|
back_to_start = False
|
|
second_round = False
|
|
if show_animation:
|
|
plt.plot(self.obs_x, self.obs_y, ".k")
|
|
plt.plot(self.r_x[-1], self.r_y[-1], "og")
|
|
plt.plot(self.goal_x, self.goal_y, "xb")
|
|
plt.plot(self.out_x, self.out_y, ".")
|
|
plt.grid(True)
|
|
plt.title('BUG 1')
|
|
|
|
for xob, yob in zip(self.out_x, self.out_y):
|
|
if self.r_x[-1] == xob and self.r_y[-1] == yob:
|
|
mov_dir = 'obs'
|
|
break
|
|
|
|
visited_x, visited_y = [], []
|
|
while True:
|
|
if self.r_x[-1] == self.goal_x and \
|
|
self.r_y[-1] == self.goal_y:
|
|
break
|
|
if mov_dir == 'normal':
|
|
cand_x, cand_y = self.mov_normal()
|
|
if mov_dir == 'obs':
|
|
cand_x, cand_y, back_to_start = \
|
|
self.mov_to_next_obs(visited_x, visited_y)
|
|
if mov_dir == 'normal':
|
|
found_boundary = False
|
|
for x_ob, y_ob in zip(self.out_x, self.out_y):
|
|
if cand_x == x_ob and cand_y == y_ob:
|
|
self.r_x.append(cand_x), self.r_y.append(cand_y)
|
|
visited_x[:], visited_y[:] = [], []
|
|
visited_x.append(cand_x), visited_y.append(cand_y)
|
|
mov_dir = 'obs'
|
|
dist = np.inf
|
|
back_to_start = False
|
|
second_round = False
|
|
found_boundary = True
|
|
break
|
|
if not found_boundary:
|
|
self.r_x.append(cand_x), self.r_y.append(cand_y)
|
|
elif mov_dir == 'obs':
|
|
d = np.linalg.norm(np.array([cand_x, cand_y] -
|
|
np.array([self.goal_x,
|
|
self.goal_y])))
|
|
if d < dist and not second_round:
|
|
exit_x, exit_y = cand_x, cand_y
|
|
dist = d
|
|
if back_to_start and not second_round:
|
|
second_round = True
|
|
del self.r_x[-len(visited_x):]
|
|
del self.r_y[-len(visited_y):]
|
|
visited_x[:], visited_y[:] = [], []
|
|
self.r_x.append(cand_x), self.r_y.append(cand_y)
|
|
visited_x.append(cand_x), visited_y.append(cand_y)
|
|
if cand_x == exit_x and \
|
|
cand_y == exit_y and \
|
|
second_round:
|
|
mov_dir = 'normal'
|
|
if show_animation:
|
|
plt.plot(self.r_x, self.r_y, "-r")
|
|
plt.pause(0.001)
|
|
if show_animation:
|
|
plt.show()
|
|
|
|
def bug2(self):
|
|
"""
|
|
Move towards goal in a greedy manner.
|
|
When you hit an obstacle, you go around it and
|
|
keep track of your distance from the goal.
|
|
If the distance from your goal was decreasing before
|
|
and now it starts increasing, that means the current
|
|
point is probably the closest point to the
|
|
goal (this may or may not be true because the algorithm
|
|
doesn't explore the entire boundary around the obstacle).
|
|
So, you depart from this point and continue towards the
|
|
goal in a greedy manner
|
|
"""
|
|
mov_dir = 'normal'
|
|
cand_x, cand_y = -np.inf, -np.inf
|
|
if show_animation:
|
|
plt.plot(self.obs_x, self.obs_y, ".k")
|
|
plt.plot(self.r_x[-1], self.r_y[-1], "og")
|
|
plt.plot(self.goal_x, self.goal_y, "xb")
|
|
plt.plot(self.out_x, self.out_y, ".")
|
|
|
|
straight_x, straight_y = [self.r_x[-1]], [self.r_y[-1]]
|
|
hit_x, hit_y = [], []
|
|
while True:
|
|
if straight_x[-1] == self.goal_x and \
|
|
straight_y[-1] == self.goal_y:
|
|
break
|
|
c_x = straight_x[-1] + np.sign(self.goal_x - straight_x[-1])
|
|
c_y = straight_y[-1] + np.sign(self.goal_y - straight_y[-1])
|
|
for x_ob, y_ob in zip(self.out_x, self.out_y):
|
|
if c_x == x_ob and c_y == y_ob:
|
|
hit_x.append(c_x), hit_y.append(c_y)
|
|
break
|
|
straight_x.append(c_x), straight_y.append(c_y)
|
|
if show_animation:
|
|
plt.plot(straight_x, straight_y, ",")
|
|
plt.plot(hit_x, hit_y, "d")
|
|
plt.grid(True)
|
|
plt.title('BUG 2')
|
|
|
|
for x_ob, y_ob in zip(self.out_x, self.out_y):
|
|
if self.r_x[-1] == x_ob and self.r_y[-1] == y_ob:
|
|
mov_dir = 'obs'
|
|
break
|
|
|
|
visited_x, visited_y = [], []
|
|
while True:
|
|
if self.r_x[-1] == self.goal_x \
|
|
and self.r_y[-1] == self.goal_y:
|
|
break
|
|
if mov_dir == 'normal':
|
|
cand_x, cand_y = self.mov_normal()
|
|
if mov_dir == 'obs':
|
|
cand_x, cand_y, _ = self.mov_to_next_obs(visited_x, visited_y)
|
|
if mov_dir == 'normal':
|
|
found_boundary = False
|
|
for x_ob, y_ob in zip(self.out_x, self.out_y):
|
|
if cand_x == x_ob and cand_y == y_ob:
|
|
self.r_x.append(cand_x), self.r_y.append(cand_y)
|
|
visited_x[:], visited_y[:] = [], []
|
|
visited_x.append(cand_x), visited_y.append(cand_y)
|
|
del hit_x[0]
|
|
del hit_y[0]
|
|
mov_dir = 'obs'
|
|
found_boundary = True
|
|
break
|
|
if not found_boundary:
|
|
self.r_x.append(cand_x), self.r_y.append(cand_y)
|
|
elif mov_dir == 'obs':
|
|
self.r_x.append(cand_x), self.r_y.append(cand_y)
|
|
visited_x.append(cand_x), visited_y.append(cand_y)
|
|
for i_x, i_y in zip(range(len(hit_x)), range(len(hit_y))):
|
|
if cand_x == hit_x[i_x] and cand_y == hit_y[i_y]:
|
|
del hit_x[i_x]
|
|
del hit_y[i_y]
|
|
mov_dir = 'normal'
|
|
break
|
|
if show_animation:
|
|
plt.plot(self.r_x, self.r_y, "-r")
|
|
plt.pause(0.001)
|
|
if show_animation:
|
|
plt.show()
|
|
|
|
|
|
def main(bug_0, bug_1, bug_2):
|
|
# set obstacle positions
|
|
o_x, o_y = [], []
|
|
|
|
s_x = 0.0
|
|
s_y = 0.0
|
|
g_x = 167.0
|
|
g_y = 50.0
|
|
|
|
for i in range(20, 40):
|
|
for j in range(20, 40):
|
|
o_x.append(i)
|
|
o_y.append(j)
|
|
|
|
for i in range(60, 100):
|
|
for j in range(40, 80):
|
|
o_x.append(i)
|
|
o_y.append(j)
|
|
|
|
for i in range(120, 140):
|
|
for j in range(80, 100):
|
|
o_x.append(i)
|
|
o_y.append(j)
|
|
|
|
for i in range(80, 140):
|
|
for j in range(0, 20):
|
|
o_x.append(i)
|
|
o_y.append(j)
|
|
|
|
for i in range(0, 20):
|
|
for j in range(60, 100):
|
|
o_x.append(i)
|
|
o_y.append(j)
|
|
|
|
for i in range(20, 40):
|
|
for j in range(80, 100):
|
|
o_x.append(i)
|
|
o_y.append(j)
|
|
|
|
for i in range(120, 160):
|
|
for j in range(40, 60):
|
|
o_x.append(i)
|
|
o_y.append(j)
|
|
|
|
if bug_0:
|
|
my_Bug = BugPlanner(s_x, s_y, g_x, g_y, o_x, o_y)
|
|
my_Bug.bug0()
|
|
if bug_1:
|
|
my_Bug = BugPlanner(s_x, s_y, g_x, g_y, o_x, o_y)
|
|
my_Bug.bug1()
|
|
if bug_2:
|
|
my_Bug = BugPlanner(s_x, s_y, g_x, g_y, o_x, o_y)
|
|
my_Bug.bug2()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main(bug_0=True, bug_1=False, bug_2=False)
|