2020-07-26 14:44:35 -07:00
|
|
|
"""
|
|
|
|
|
This is dynamic rrt code for 3D
|
|
|
|
|
@author: yue qi
|
|
|
|
|
"""
|
|
|
|
|
import numpy as np
|
|
|
|
|
import time
|
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
import sys
|
|
|
|
|
|
2020-08-04 15:34:15 -07:00
|
|
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../../Sampling_based_Planning/")
|
2020-07-26 14:44:35 -07:00
|
|
|
from rrt_3D.env3D import env
|
2020-08-04 23:44:20 -07:00
|
|
|
from rrt_3D.utils3D import getDist, sampleFree, nearest, steer, isCollide
|
2020-08-03 19:59:23 -07:00
|
|
|
from rrt_3D.plot_util3D import make_get_proj, draw_block_list, draw_Spheres, draw_obb, draw_line, make_transparent
|
2020-07-26 14:44:35 -07:00
|
|
|
|
2020-08-04 15:34:15 -07:00
|
|
|
|
|
|
|
|
class dynamic_rrt_3D:
|
|
|
|
|
|
2020-07-26 14:44:35 -07:00
|
|
|
def __init__(self):
|
|
|
|
|
self.env = env()
|
2020-08-03 19:59:23 -07:00
|
|
|
self.x0, self.xt = tuple(self.env.start), tuple(self.env.goal)
|
|
|
|
|
self.qrobot = self.x0
|
|
|
|
|
self.current = tuple(self.env.start)
|
|
|
|
|
self.stepsize = 0.25
|
|
|
|
|
self.maxiter = 10000
|
2020-08-04 15:34:15 -07:00
|
|
|
self.GoalProb = 0.05 # probability biased to the goal
|
|
|
|
|
self.WayPointProb = 0.02 # probability falls back on to the way points
|
|
|
|
|
self.done = False
|
|
|
|
|
self.invalid = False
|
|
|
|
|
|
|
|
|
|
self.V = [] # vertices
|
|
|
|
|
self.Parent = {} # parent child relation
|
|
|
|
|
self.Edge = set() # edge relation (node, parent node) tuple
|
2020-07-26 14:44:35 -07:00
|
|
|
self.Path = []
|
2020-08-04 15:34:15 -07:00
|
|
|
self.flag = {} # flag dictionary
|
2020-07-26 22:04:23 -07:00
|
|
|
self.ind = 0
|
2020-08-03 19:59:23 -07:00
|
|
|
self.i = 0
|
2020-07-26 14:44:35 -07:00
|
|
|
|
2020-08-04 15:34:15 -07:00
|
|
|
# --------Dynamic RRT algorithm
|
2020-08-03 19:59:23 -07:00
|
|
|
def RegrowRRT(self):
|
2020-07-26 14:44:35 -07:00
|
|
|
self.TrimRRT()
|
2020-08-03 19:59:23 -07:00
|
|
|
self.GrowRRT()
|
2020-07-26 14:44:35 -07:00
|
|
|
|
|
|
|
|
def TrimRRT(self):
|
2020-07-26 22:04:23 -07:00
|
|
|
S = []
|
2020-07-26 14:44:35 -07:00
|
|
|
i = 1
|
2020-08-03 19:59:23 -07:00
|
|
|
print('trimming...')
|
|
|
|
|
while i < len(self.V):
|
|
|
|
|
qi = self.V[i]
|
2020-07-26 22:04:23 -07:00
|
|
|
qp = self.Parent[qi]
|
2020-08-03 19:59:23 -07:00
|
|
|
if self.flag[qp] == 'Invalid':
|
|
|
|
|
self.flag[qi] = 'Invalid'
|
|
|
|
|
if self.flag[qi] != 'Invalid':
|
2020-07-26 22:04:23 -07:00
|
|
|
S.append(qi)
|
2020-07-26 14:44:35 -07:00
|
|
|
i += 1
|
2020-08-03 19:59:23 -07:00
|
|
|
self.CreateTreeFromNodes(S)
|
2020-08-04 15:34:15 -07:00
|
|
|
|
2020-08-03 19:59:23 -07:00
|
|
|
def InvalidateNodes(self, obstacle):
|
|
|
|
|
Edges = self.FindAffectedEdges(obstacle)
|
|
|
|
|
for edge in Edges:
|
|
|
|
|
qe = self.ChildEndpointNode(edge)
|
|
|
|
|
self.flag[qe] = 'Invalid'
|
|
|
|
|
|
2020-08-04 15:34:15 -07:00
|
|
|
# --------Extend RRT algorithm-----
|
2020-08-03 19:59:23 -07:00
|
|
|
def initRRT(self):
|
|
|
|
|
self.V.append(self.x0)
|
|
|
|
|
self.flag[self.x0] = 'Valid'
|
|
|
|
|
|
|
|
|
|
def GrowRRT(self):
|
2020-08-04 23:44:20 -07:00
|
|
|
print('growing...')
|
2020-08-03 19:59:23 -07:00
|
|
|
qnew = self.x0
|
|
|
|
|
distance_threshold = self.stepsize
|
|
|
|
|
self.ind = 0
|
|
|
|
|
while self.ind <= self.maxiter:
|
|
|
|
|
qtarget = self.ChooseTarget()
|
2020-08-04 15:34:15 -07:00
|
|
|
qnearest = self.Nearest(qtarget)
|
2020-08-03 19:59:23 -07:00
|
|
|
qnew, collide = self.Extend(qnearest, qtarget)
|
|
|
|
|
if not collide:
|
|
|
|
|
self.AddNode(qnearest, qnew)
|
|
|
|
|
if getDist(qnew, self.xt) < distance_threshold:
|
|
|
|
|
self.AddNode(qnearest, self.xt)
|
|
|
|
|
self.flag[self.xt] = 'Valid'
|
|
|
|
|
break
|
|
|
|
|
self.i += 1
|
|
|
|
|
self.ind += 1
|
|
|
|
|
# self.visualization()
|
|
|
|
|
|
|
|
|
|
def ChooseTarget(self):
|
|
|
|
|
# return the goal, or randomly choose a state in the waypoints based on probs
|
|
|
|
|
p = np.random.uniform()
|
|
|
|
|
if len(self.V) == 1:
|
|
|
|
|
i = 0
|
|
|
|
|
else:
|
2020-08-04 15:34:15 -07:00
|
|
|
i = np.random.randint(0, high=len(self.V) - 1)
|
2020-08-03 19:59:23 -07:00
|
|
|
if 0 < p < self.GoalProb:
|
|
|
|
|
return self.xt
|
|
|
|
|
elif self.GoalProb < p < self.GoalProb + self.WayPointProb:
|
|
|
|
|
return self.V[i]
|
|
|
|
|
elif self.GoalProb + self.WayPointProb < p < 1:
|
|
|
|
|
return tuple(self.RandomState())
|
2020-08-04 15:34:15 -07:00
|
|
|
|
2020-08-03 19:59:23 -07:00
|
|
|
def RandomState(self):
|
|
|
|
|
# generate a random, obstacle free state
|
|
|
|
|
xrand = sampleFree(self, bias=0)
|
|
|
|
|
return xrand
|
|
|
|
|
|
|
|
|
|
def AddNode(self, nearest, extended):
|
|
|
|
|
self.V.append(extended)
|
|
|
|
|
self.Parent[extended] = nearest
|
|
|
|
|
self.Edge.add((extended, nearest))
|
|
|
|
|
self.flag[extended] = 'Valid'
|
|
|
|
|
|
2020-08-04 15:34:15 -07:00
|
|
|
def Nearest(self, target):
|
2020-08-03 19:59:23 -07:00
|
|
|
# TODO use kdTree to speed up search
|
|
|
|
|
return nearest(self, target, isset=True)
|
2020-07-26 14:44:35 -07:00
|
|
|
|
2020-08-03 19:59:23 -07:00
|
|
|
def Extend(self, nearest, target):
|
2020-08-04 15:34:15 -07:00
|
|
|
extended, dist = steer(self, nearest, target, DIST=True)
|
2020-08-03 19:59:23 -07:00
|
|
|
collide, _ = isCollide(self, nearest, target, dist)
|
|
|
|
|
return extended, collide
|
|
|
|
|
|
2020-08-04 15:34:15 -07:00
|
|
|
# --------Main function
|
2020-07-26 22:04:23 -07:00
|
|
|
def Main(self):
|
2020-08-03 19:59:23 -07:00
|
|
|
# qstart = qgoal
|
|
|
|
|
self.x0 = tuple(self.env.goal)
|
|
|
|
|
# qgoal = qrobot
|
|
|
|
|
self.xt = tuple(self.env.start)
|
|
|
|
|
self.initRRT()
|
2020-07-26 22:04:23 -07:00
|
|
|
self.GrowRRT()
|
2020-08-04 15:34:15 -07:00
|
|
|
self.Path, D = self.path()
|
2020-08-03 19:59:23 -07:00
|
|
|
self.done = True
|
2020-08-04 15:34:15 -07:00
|
|
|
self.visualization()
|
2020-08-03 19:59:23 -07:00
|
|
|
t = 0
|
|
|
|
|
while True:
|
|
|
|
|
# move the block while the robot is moving
|
2020-08-04 23:44:20 -07:00
|
|
|
new, _ = self.env.move_block(a=[0.2, 0, -0.2], mode='translation')
|
2020-08-03 19:59:23 -07:00
|
|
|
self.InvalidateNodes(new)
|
2020-08-04 15:34:15 -07:00
|
|
|
self.TrimRRT()
|
2020-08-03 19:59:23 -07:00
|
|
|
# if solution path contains invalid node
|
|
|
|
|
self.visualization()
|
2020-08-04 15:34:15 -07:00
|
|
|
self.invalid = self.PathisInvalid(self.Path)
|
|
|
|
|
if self.invalid:
|
2020-08-03 19:59:23 -07:00
|
|
|
self.done = False
|
|
|
|
|
self.RegrowRRT()
|
|
|
|
|
self.Path = []
|
2020-08-04 15:34:15 -07:00
|
|
|
self.Path, D = self.path()
|
|
|
|
|
self.done = True
|
|
|
|
|
self.visualization()
|
2020-08-03 19:59:23 -07:00
|
|
|
if t == 8:
|
|
|
|
|
break
|
2020-08-04 15:34:15 -07:00
|
|
|
t += 1
|
|
|
|
|
self.visualization()
|
|
|
|
|
plt.show()
|
2020-08-03 19:59:23 -07:00
|
|
|
|
2020-08-04 15:34:15 -07:00
|
|
|
# --------Additional utility functions
|
2020-08-03 19:59:23 -07:00
|
|
|
def FindAffectedEdges(self, obstacle):
|
|
|
|
|
# scan the graph for the changed edges in the tree.
|
|
|
|
|
# return the end point and the affected
|
2020-08-04 23:44:20 -07:00
|
|
|
print('finding affected edges...')
|
2020-08-03 19:59:23 -07:00
|
|
|
Affectededges = []
|
|
|
|
|
for e in self.Edge:
|
|
|
|
|
child, parent = e
|
|
|
|
|
collide, _ = isCollide(self, child, parent)
|
|
|
|
|
if collide:
|
|
|
|
|
Affectededges.append(e)
|
|
|
|
|
return Affectededges
|
|
|
|
|
|
|
|
|
|
def ChildEndpointNode(self, edge):
|
|
|
|
|
return edge[0]
|
|
|
|
|
|
|
|
|
|
def CreateTreeFromNodes(self, Nodes):
|
2020-08-04 23:44:20 -07:00
|
|
|
print('creating tree...')
|
2020-08-04 15:34:15 -07:00
|
|
|
# self.Parent = {node: self.Parent[node] for node in Nodes}
|
|
|
|
|
self.V = [node for node in Nodes]
|
|
|
|
|
self.Edge = {(node, self.Parent[node]) for node in Nodes}
|
|
|
|
|
# if self.invalid:
|
|
|
|
|
# del self.Parent[self.xt]
|
2020-08-03 19:59:23 -07:00
|
|
|
|
|
|
|
|
def PathisInvalid(self, path):
|
|
|
|
|
for edge in path:
|
|
|
|
|
if self.flag[tuple(edge[0])] == 'Invalid' or self.flag[tuple(edge[1])] == 'Invalid':
|
|
|
|
|
return True
|
|
|
|
|
|
2020-08-04 15:34:15 -07:00
|
|
|
def path(self, dist=0):
|
|
|
|
|
Path=[]
|
2020-08-03 19:59:23 -07:00
|
|
|
x = self.xt
|
2020-08-04 15:34:15 -07:00
|
|
|
i = 0
|
2020-08-03 19:59:23 -07:00
|
|
|
while x != self.x0:
|
|
|
|
|
x2 = self.Parent[x]
|
|
|
|
|
Path.append(np.array([x, x2]))
|
|
|
|
|
dist += getDist(x, x2)
|
|
|
|
|
x = x2
|
2020-08-04 15:34:15 -07:00
|
|
|
if i > 10000:
|
|
|
|
|
print('Path is not found')
|
|
|
|
|
return
|
|
|
|
|
i+= 1
|
2020-08-03 19:59:23 -07:00
|
|
|
return Path, dist
|
2020-08-04 15:34:15 -07:00
|
|
|
|
|
|
|
|
# --------Visualization specialized for dynamic RRT
|
2020-08-03 19:59:23 -07:00
|
|
|
def visualization(self):
|
|
|
|
|
if self.ind % 100 == 0 or self.done:
|
|
|
|
|
V = np.array(self.V)
|
|
|
|
|
Path = np.array(self.Path)
|
|
|
|
|
start = self.env.start
|
|
|
|
|
goal = self.env.goal
|
2020-08-04 15:34:15 -07:00
|
|
|
# edges = []
|
|
|
|
|
# for i in self.Parent:
|
|
|
|
|
# edges.append([i, self.Parent[i]])
|
|
|
|
|
edges = np.array([list(i) for i in self.Edge])
|
2020-08-03 19:59:23 -07:00
|
|
|
ax = plt.subplot(111, projection='3d')
|
|
|
|
|
# ax.view_init(elev=0.+ 0.03*initparams.ind/(2*np.pi), azim=90 + 0.03*initparams.ind/(2*np.pi))
|
|
|
|
|
# ax.view_init(elev=0., azim=90.)
|
2020-08-04 15:34:15 -07:00
|
|
|
ax.view_init(elev=0., azim=90.)
|
2020-08-03 19:59:23 -07:00
|
|
|
ax.clear()
|
|
|
|
|
# drawing objects
|
|
|
|
|
draw_Spheres(ax, self.env.balls)
|
|
|
|
|
draw_block_list(ax, self.env.blocks)
|
|
|
|
|
if self.env.OBB is not None:
|
|
|
|
|
draw_obb(ax, self.env.OBB)
|
|
|
|
|
draw_block_list(ax, np.array([self.env.boundary]), alpha=0)
|
|
|
|
|
draw_line(ax, edges, visibility=0.75, color='g')
|
|
|
|
|
draw_line(ax, Path, color='r')
|
|
|
|
|
# if len(V) > 0:
|
|
|
|
|
# ax.scatter3D(V[:, 0], V[:, 1], V[:, 2], s=2, color='g', )
|
|
|
|
|
ax.plot(start[0:1], start[1:2], start[2:], 'go', markersize=7, markeredgecolor='k')
|
|
|
|
|
ax.plot(goal[0:1], goal[1:2], goal[2:], 'ro', markersize=7, markeredgecolor='k')
|
|
|
|
|
# adjust the aspect ratio
|
|
|
|
|
xmin, xmax = self.env.boundary[0], self.env.boundary[3]
|
|
|
|
|
ymin, ymax = self.env.boundary[1], self.env.boundary[4]
|
|
|
|
|
zmin, zmax = self.env.boundary[2], self.env.boundary[5]
|
|
|
|
|
dx, dy, dz = xmax - xmin, ymax - ymin, zmax - zmin
|
|
|
|
|
ax.get_proj = make_get_proj(ax, 1 * dx, 1 * dy, 2 * dy)
|
|
|
|
|
make_transparent(ax)
|
2020-08-05 12:53:19 -07:00
|
|
|
# plt.xlabel('s')
|
2020-08-04 15:34:15 -07:00
|
|
|
# plt.ylabel('y')
|
2020-08-03 19:59:23 -07:00
|
|
|
ax.set_axis_off()
|
|
|
|
|
plt.pause(0.0001)
|
|
|
|
|
|
|
|
|
|
|
2020-07-26 22:04:23 -07:00
|
|
|
if __name__ == '__main__':
|
|
|
|
|
rrt = dynamic_rrt_3D()
|
|
|
|
|
rrt.Main()
|