|
@@ -5,6 +5,7 @@ This is dynamic rrt code for 3D
|
|
|
import numpy as np
|
|
import numpy as np
|
|
|
from numpy.matlib import repmat
|
|
from numpy.matlib import repmat
|
|
|
from collections import defaultdict
|
|
from collections import defaultdict
|
|
|
|
|
+import copy
|
|
|
import time
|
|
import time
|
|
|
import matplotlib.pyplot as plt
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
|
|
@@ -13,108 +14,227 @@ import sys
|
|
|
|
|
|
|
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../../Sampling-based Planning/")
|
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../../Sampling-based Planning/")
|
|
|
from rrt_3D.env3D import env
|
|
from rrt_3D.env3D import env
|
|
|
-from rrt_3D.utils3D import getDist, sampleFree, nearest, steer, isCollide, near, visualization, cost, path, edgeset, isinbound
|
|
|
|
|
|
|
+from rrt_3D.utils3D import getDist, sampleFree, nearest, steer, isCollide, near, cost, path, edgeset, isinbound, isinside
|
|
|
from rrt_3D.rrt3D import rrt
|
|
from rrt_3D.rrt3D import rrt
|
|
|
|
|
+from rrt_3D.plot_util3D import make_get_proj, draw_block_list, draw_Spheres, draw_obb, draw_line, make_transparent
|
|
|
|
|
|
|
|
-class dynamic_rrt_3D(rrt):
|
|
|
|
|
|
|
+class dynamic_rrt_3D():
|
|
|
|
|
|
|
|
def __init__(self):
|
|
def __init__(self):
|
|
|
- # variables in rrt
|
|
|
|
|
self.env = env()
|
|
self.env = env()
|
|
|
- self.Parent = {}
|
|
|
|
|
- self.E = edgeset() # edgeset
|
|
|
|
|
- self.V = [] # nodeset
|
|
|
|
|
- self.i = 0
|
|
|
|
|
- self.maxiter = 10000 # at least 2000 in this env
|
|
|
|
|
- self.stepsize = 0.5
|
|
|
|
|
- self.gamma = 500
|
|
|
|
|
- self.eta = 2*self.stepsize
|
|
|
|
|
|
|
+ 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
|
|
|
|
|
+ self.GoalProb = 0.05 # probability biased to the goal
|
|
|
|
|
+ self.WayPointProb = 0.05 # probability falls back on to the way points
|
|
|
|
|
+
|
|
|
|
|
+ self.V = [] # vertices
|
|
|
|
|
+ self.Parent = {} # parent child relation
|
|
|
|
|
+ self.Edge = set() # edge relation (node, parent node) tuple
|
|
|
self.Path = []
|
|
self.Path = []
|
|
|
- self.done = False
|
|
|
|
|
- self.x0 = tuple(self.env.goal)
|
|
|
|
|
- self.xt = tuple(self.env.start)
|
|
|
|
|
- # additional variables
|
|
|
|
|
- self.Flag = {}
|
|
|
|
|
- self.xrobot = tuple(self.env.start)
|
|
|
|
|
-
|
|
|
|
|
- self.V.append(self.x0)
|
|
|
|
|
|
|
+ self.flag = {}# flag dictionary
|
|
|
self.ind = 0
|
|
self.ind = 0
|
|
|
- self.fig = plt.figure(figsize=(10, 8))
|
|
|
|
|
|
|
+ self.i = 0
|
|
|
|
|
|
|
|
- def RegrowRRT(self, xrobot):
|
|
|
|
|
|
|
+#--------Dynamic RRT algorithm
|
|
|
|
|
+ def RegrowRRT(self):
|
|
|
self.TrimRRT()
|
|
self.TrimRRT()
|
|
|
- self.GrowRRT(xrobot = xrobot)
|
|
|
|
|
|
|
+ self.GrowRRT()
|
|
|
|
|
|
|
|
def TrimRRT(self):
|
|
def TrimRRT(self):
|
|
|
S = []
|
|
S = []
|
|
|
i = 1
|
|
i = 1
|
|
|
- for qi in self.V:
|
|
|
|
|
- if qi == self.x0:
|
|
|
|
|
- continue
|
|
|
|
|
|
|
+ print('trimming...')
|
|
|
|
|
+ while i < len(self.V):
|
|
|
|
|
+ qi = self.V[i]
|
|
|
qp = self.Parent[qi]
|
|
qp = self.Parent[qi]
|
|
|
- if qp == self.x0:
|
|
|
|
|
- continue
|
|
|
|
|
- if self.Flag[qp] == 'Invalid':
|
|
|
|
|
- self.Flag[qi] = 'Invalid'
|
|
|
|
|
- self.E.remove_edge([qi,qp]) # REMOVE edge that parent is invalid
|
|
|
|
|
- if self.Flag[qi] != 'Invalid':
|
|
|
|
|
|
|
+ if self.flag[qp] == 'Invalid':
|
|
|
|
|
+ self.flag[qi] = 'Invalid'
|
|
|
|
|
+ if self.flag[qi] != 'Invalid':
|
|
|
S.append(qi)
|
|
S.append(qi)
|
|
|
i += 1
|
|
i += 1
|
|
|
- self.V, self.E = self.CreateTreeFromNodes(S)
|
|
|
|
|
|
|
+ self.CreateTreeFromNodes(S)
|
|
|
|
|
+ print('trimming complete...')
|
|
|
|
|
|
|
|
- def InvalidateNodes(self, obstacle, mode):
|
|
|
|
|
- E = self.FindAffectedEdges(obstacle, mode)
|
|
|
|
|
- for e in E:
|
|
|
|
|
- qe = self.ChildEndpointNode(e)
|
|
|
|
|
- self.Flag[qe] = 'Invalid'
|
|
|
|
|
|
|
+ def InvalidateNodes(self, obstacle):
|
|
|
|
|
+ Edges = self.FindAffectedEdges(obstacle)
|
|
|
|
|
+ for edge in Edges:
|
|
|
|
|
+ qe = self.ChildEndpointNode(edge)
|
|
|
|
|
+ self.flag[qe] = 'Invalid'
|
|
|
|
|
+
|
|
|
|
|
+#--------Extend RRT algorithm-----
|
|
|
|
|
+ def initRRT(self):
|
|
|
|
|
+ self.V.append(self.x0)
|
|
|
|
|
+ self.flag[self.x0] = 'Valid'
|
|
|
|
|
+
|
|
|
|
|
+ def GrowRRT(self):
|
|
|
|
|
+ print('growing')
|
|
|
|
|
+ qnew = self.x0
|
|
|
|
|
+ tree = None
|
|
|
|
|
+ distance_threshold = self.stepsize
|
|
|
|
|
+ self.ind = 0
|
|
|
|
|
+ while self.ind <= self.maxiter:
|
|
|
|
|
+ qtarget = self.ChooseTarget()
|
|
|
|
|
+ qnearest = self.Nearest(tree, qtarget)
|
|
|
|
|
+ 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()
|
|
|
|
|
+ print('growing complete...')
|
|
|
|
|
+
|
|
|
|
|
+ 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:
|
|
|
|
|
+ i = np.random.randint(0, high = len(self.V) - 1)
|
|
|
|
|
+ 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())
|
|
|
|
|
+
|
|
|
|
|
+ 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'
|
|
|
|
|
+
|
|
|
|
|
+ def Nearest(self, tree, target):
|
|
|
|
|
+ # TODO use kdTree to speed up search
|
|
|
|
|
+ return nearest(self, target, isset=True)
|
|
|
|
|
|
|
|
|
|
+ def Extend(self, nearest, target):
|
|
|
|
|
+ extended, dist = steer(self, nearest, target, DIST = True)
|
|
|
|
|
+ collide, _ = isCollide(self, nearest, target, dist)
|
|
|
|
|
+ return extended, collide
|
|
|
|
|
+
|
|
|
|
|
+#--------Main function
|
|
|
def Main(self):
|
|
def Main(self):
|
|
|
- qgoal = tuple(self.env.start)
|
|
|
|
|
- qstart = tuple(self.env.goal)
|
|
|
|
|
|
|
+ # qstart = qgoal
|
|
|
|
|
+ self.x0 = tuple(self.env.goal)
|
|
|
|
|
+ # qgoal = qrobot
|
|
|
|
|
+ self.xt = tuple(self.env.start)
|
|
|
|
|
+ self.initRRT()
|
|
|
self.GrowRRT()
|
|
self.GrowRRT()
|
|
|
- self.done = True
|
|
|
|
|
- # visualization(self)
|
|
|
|
|
- self.done = False
|
|
|
|
|
- # change the enviroment
|
|
|
|
|
- new0,old0 = self.env.move_block(a=[0, 0, -2], s=0.5, block_to_move=1, mode='translation')
|
|
|
|
|
- while qgoal != qstart:
|
|
|
|
|
- qgoal = self.Parent[qgoal]
|
|
|
|
|
- # TODO move to qgoal and check for new obs
|
|
|
|
|
- xrobot = qstart
|
|
|
|
|
- # TODO if any new obstacle are observed
|
|
|
|
|
- self.InvalidateNodes(new0, mode = 'translation')
|
|
|
|
|
- for xi in self.Path:
|
|
|
|
|
- if self.Flag[tuple(xi[0])] == 'Invalid':
|
|
|
|
|
- self.RegrowRRT(tuple(self.env.start))
|
|
|
|
|
- self.done = True
|
|
|
|
|
self.Path, D = path(self)
|
|
self.Path, D = path(self)
|
|
|
- visualization(self)
|
|
|
|
|
|
|
+ self.done = True
|
|
|
|
|
+ self.visualization()
|
|
|
plt.show()
|
|
plt.show()
|
|
|
-
|
|
|
|
|
- def GrowRRT(self, Reversed = True, xrobot = None):
|
|
|
|
|
- # rrt.run()
|
|
|
|
|
- self.run(Reversed = Reversed, xrobot = xrobot)
|
|
|
|
|
-
|
|
|
|
|
- def CreateTreeFromNodes(self, S):
|
|
|
|
|
- return S, self.E
|
|
|
|
|
-
|
|
|
|
|
- def FindAffectedEdges(self, obstacle, mode):
|
|
|
|
|
- # if the nodes appears inside of the new range an obstacle moved,
|
|
|
|
|
- # find the edges associated with this node. (the node is the parent)
|
|
|
|
|
- nodes = np.array(self.V)
|
|
|
|
|
- if mode == 'translation':
|
|
|
|
|
- affected_nodes = nodes[isinbound(obstacle, nodes, isarray = True)]
|
|
|
|
|
- elif mode == 'rotation':
|
|
|
|
|
- affected_nodes = nodes[isinbound(obstacle, nodes, mode = 'obb', isarray = True)]
|
|
|
|
|
- if len(affected_nodes) == 0:
|
|
|
|
|
- return []
|
|
|
|
|
- return self.E.get_edge(affected_nodes)
|
|
|
|
|
-
|
|
|
|
|
- def ChildEndpointNode(self, e):
|
|
|
|
|
- # if self.E.isEndNode(e[1]):
|
|
|
|
|
- return e[1]
|
|
|
|
|
- #else:
|
|
|
|
|
- # return self.ChildEndpointNode(e[1])
|
|
|
|
|
|
|
+ t = 0
|
|
|
|
|
+ while True:
|
|
|
|
|
+ # move the block while the robot is moving
|
|
|
|
|
+ new, old = self.env.move_block(a=[0, 0, -0.2], mode='translation')
|
|
|
|
|
+ self.InvalidateNodes(new)
|
|
|
|
|
+ # if solution path contains invalid node
|
|
|
|
|
+ self.done = True
|
|
|
|
|
+ self.visualization()
|
|
|
|
|
+ plt.show()
|
|
|
|
|
+ invalid = self.PathisInvalid(self.Path)
|
|
|
|
|
+ if invalid:
|
|
|
|
|
+ self.done = False
|
|
|
|
|
+ self.RegrowRRT()
|
|
|
|
|
+ self.Path = []
|
|
|
|
|
+ self.Path, D = path(self)
|
|
|
|
|
+
|
|
|
|
|
+ if t == 8:
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+#--------Additional utility functions
|
|
|
|
|
+ def FindAffectedEdges(self, obstacle):
|
|
|
|
|
+ # scan the graph for the changed edges in the tree.
|
|
|
|
|
+ # return the end point and the affected
|
|
|
|
|
+ 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):
|
|
|
|
|
+ self.V = []
|
|
|
|
|
+ Parent = {}
|
|
|
|
|
+ edges = set()
|
|
|
|
|
+ for v in Nodes:
|
|
|
|
|
+ self.V.append(v)
|
|
|
|
|
+ Parent[v] = self.Parent[v]
|
|
|
|
|
+ edges.add((v, Parent[v]))
|
|
|
|
|
+ self.Parent = Parent
|
|
|
|
|
+ self.Edge = edges
|
|
|
|
|
+
|
|
|
|
|
+ def PathisInvalid(self, path):
|
|
|
|
|
+ for edge in path:
|
|
|
|
|
+ if self.flag[tuple(edge[0])] == 'Invalid' or self.flag[tuple(edge[1])] == 'Invalid':
|
|
|
|
|
+ return True
|
|
|
|
|
+
|
|
|
|
|
+ def path(self, Path=[], dist=0):
|
|
|
|
|
+ x = self.xt
|
|
|
|
|
+ while x != self.x0:
|
|
|
|
|
+ x2 = self.Parent[x]
|
|
|
|
|
+ Path.append(np.array([x, x2]))
|
|
|
|
|
+ dist += getDist(x, x2)
|
|
|
|
|
+ x = x2
|
|
|
|
|
+ return Path, dist
|
|
|
|
|
+
|
|
|
|
|
+#--------Visualization specialized for dynamic RRT
|
|
|
|
|
+ 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
|
|
|
|
|
+ edges = []
|
|
|
|
|
+ for i in self.Parent:
|
|
|
|
|
+ edges.append([i,self.Parent[i]])
|
|
|
|
|
+ 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.)
|
|
|
|
|
+ ax.view_init(elev=8., azim=120.)
|
|
|
|
|
+ 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)
|
|
|
|
|
+ #plt.xlabel('x')
|
|
|
|
|
+ #plt.ylabel('y')
|
|
|
|
|
+ ax.set_axis_off()
|
|
|
|
|
+ plt.pause(0.0001)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
if __name__ == '__main__':
|
|
|
rrt = dynamic_rrt_3D()
|
|
rrt = dynamic_rrt_3D()
|