def find_closest(x0,
                 curve,
                 t_range=None,
                 max_time=INF,
                 max_iterations=INF,
                 distance_fn=None,
                 verbose=False):
    assert (max_time < INF) or (max_iterations < INF)
    if t_range is None:
        t_range = Interval(curve.x[0], curve.x[-1])
    t_range = Interval(max(t_range[0], curve.x[0]),
                       min(curve.x[-1], t_range[-1]))
    if distance_fn is None:
        distance_fn = get_distance
    start_time = time.time()
    closest_dist, closest_t = INF, None
    for iteration in irange(max_iterations):
        if elapsed_time(start_time) >= max_time:
            break
        t = random.uniform(*t_range)  # TODO: halton
        x = curve(t)
        dist = distance_fn(x0, x)
        if dist < closest_dist:
            closest_dist, closest_t = dist, t
            if verbose:
                print(
                    'Iteration: {} | Dist: {:.3f} | T: {:.3f} | Time: {:.3f}'.
                    format(iteration, closest_dist, t,
                           elapsed_time(start_time)))
    return closest_dist, closest_t
def rrt(start,
        goal_sample,
        distance,
        sample,
        extend,
        collision,
        goal_test=lambda q: False,
        iterations=RRT_ITERATIONS,
        goal_probability=.2):
    if collision(start):
        return None
    if not callable(goal_sample):
        g = goal_sample
        goal_sample = lambda: g
    nodes = [TreeNode(start)]
    for i in irange(iterations):
        goal = random() < goal_probability or i == 0
        s = goal_sample() if goal else sample()

        last = argmin(lambda n: distance(n.config, s), nodes)
        for q in extend(last.config, s):
            if collision(q):
                break
            last = TreeNode(q, parent=last)
            nodes.append(last)
            if goal_test(last.config):
                return configs(last.retrace())
        else:
            if goal:
                return configs(last.retrace())
    return None
def birrt(q1,
          q2,
          distance,
          sample,
          extend,
          collision,
          restarts=RRT_RESTARTS,
          iterations=RRT_ITERATIONS,
          smooth=RRT_SMOOTHING):
    path = direct_path(q1, q2, extend, collision)
    if path is not None:
        return path
    for _ in irange(restarts + 1):
        path = rrt_connect(q1,
                           q2,
                           distance,
                           sample,
                           extend,
                           collision,
                           iterations=iterations)
        if path is not None:
            if smooth is None:
                return path
            return smooth_path(path, extend, collision, iterations=smooth)
    return None
def rrt_connect(q1,
                q2,
                distance,
                sample,
                extend,
                collision,
                iterations=RRT_ITERATIONS):
    if collision(q1) or collision(q2):
        return None
    root1, root2 = TreeNode(q1), TreeNode(q2)
    nodes1, nodes2 = [root1], [root2]
    for _ in irange(iterations):
        if len(nodes1) > len(nodes2):
            nodes1, nodes2 = nodes2, nodes1
        s = sample()

        last1 = argmin(lambda n: distance(n.config, s), nodes1)
        for q in extend(last1.config, s):
            if collision(q):
                break
            last1 = TreeNode(q, parent=last1)
            nodes1.append(last1)

        last2 = argmin(lambda n: distance(n.config, last1.config), nodes2)
        for q in extend(last2.config, last1.config):
            if collision(q):
                break
            last2 = TreeNode(q, parent=last2)
            nodes2.append(last2)
        else:
            path1, path2 = last1.retrace(), last2.retrace()
            if path1[0] != root1:
                path1, path2 = path2, path1
            return configs(path1[:-1] + path2[::-1])
    return None
    def grow(self,
             goal_sample,
             iterations=50,
             goal_probability=.2,
             store=ts.PATH,
             max_tree_size=500):
        if not callable(goal_sample):
            goal_sample = lambda: goal_sample
        nodes, new_nodes = list(
            take(randomize(self.nodes.values()), max_tree_size)), []
        for i in irange(iterations):
            goal = random() < goal_probability or i == 0
            s = goal_sample() if goal else self.sample()

            last = argmin(lambda n: self.distance(n.config, s),
                          nodes + new_nodes)
            for q in self.extend(last.config, s):
                if self.collision(q):
                    break
                last = TreeNode(q, parent=last)
                new_nodes.append(last)
            else:
                if goal:
                    path = last.retrace()
                    if store in [ts.ALL, ts.SUCCESS]:
                        self.add(*new_nodes)
                    elif store == ts.PATH:
                        new_nodes_set = set(new_nodes)
                        self.add(*[n for n in path if n in new_nodes_set])
                    return path
        if store == ts.ALL:
            self.add(*new_nodes)
        return None
    def grow(self, goal, iterations=50, store=ts.PATH, max_tree_size=500):
        if goal in self:
            return self[goal].retrace()
        if self.collision(goal):
            return None
        nodes1, new_nodes1 = list(
            take(randomize(self.nodes.values()), max_tree_size)), []
        nodes2, new_nodes2 = [], [TreeNode(goal)]
        for _ in irange(iterations):
            if len(nodes1) + len(new_nodes1) > len(nodes2) + len(new_nodes2):
                nodes1, nodes2 = nodes2, nodes1
                new_nodes1, new_nodes2 = new_nodes2, new_nodes1

            s = self.sample()
            last1 = argmin(lambda n: self.distance(n.config, s),
                           nodes1 + new_nodes1)
            for q in self.extend(last1.config, s):
                if self.collision(q):
                    break
                last1 = TreeNode(q, parent=last1)
                new_nodes1.append(last1)

            last2 = argmin(lambda n: self.distance(n.config, last1.config),
                           nodes2 + new_nodes2)
            for q in self.extend(last2.config, last1.config):
                if self.collision(q):
                    break
                last2 = TreeNode(q, parent=last2)
                new_nodes2.append(last2)
            else:
                if len(nodes1) == 0:
                    nodes1, nodes2 = nodes2, nodes1
                    new_nodes1, new_nodes2 = new_nodes2, new_nodes1
                    last1, last2 = last2, last1

                path1, path2 = last1.retrace(), last2.retrace()[:-1][::-1]
                for p, n in pairs(path2):
                    n.parent = p
                if len(path2) == 0:  # TODO - still some kind of circular error
                    for n in new_nodes2:
                        if n.parent == last2:
                            n.parent = path1[-1]
                else:
                    path2[0].parent = path1[-1]
                path = path1 + path2

                if store in [ts.ALL, ts.SUCCESS]:
                    self.add(*(new_nodes1 + new_nodes2[:-1]))
                elif store == ts.PATH:
                    new_nodes_set = set(new_nodes1 + new_nodes2[:-1])
                    self.add(*[n for n in path if n in new_nodes_set])
                return path
        if store == ts.ALL:
            self.add(*new_nodes1)
        return None
def mpc(x0,
        v0,
        curve,
        dt_max=0.5,
        max_time=INF,
        max_iterations=INF,
        v_max=None,
        **kwargs):
    assert (max_time < INF) or (max_iterations < INF)
    from scipy.interpolate import CubicHermiteSpline
    start_time = time.time()
    best_cost, best_spline = INF, None
    for iteration in irange(max_iterations):
        if elapsed_time(start_time) >= max_time:
            break
        t1 = random.uniform(curve.x[0], curve.x[-1])
        future = (curve.x[-1] - t1)  # TODO: weighted
        if future >= best_cost:
            continue
        x1 = curve(t1)
        if (v_max is not None) and (max((x1 - x0) / v_max) > dt_max):
            continue
        # if quickest_inf_accel(x0, x1, v_max=v_max) > dt_max:
        #     continue
        v1 = curve(t1, nu=1)
        #dt = dt_max
        dt = random.uniform(0, dt_max)
        times = [0., dt]
        positions = [x0, x1]
        velocities = [v0, v1]
        spline = CubicHermiteSpline(times, positions, dydx=velocities)
        if not check_spline(spline, **kwargs):
            continue
        # TODO: optimize to find the closest on the path within a range

        cost = future + (spline.x[-1] - spline.x[0])
        if cost < best_cost:
            best_cost, best_spline = cost, spline
            print('Iteration: {} | Cost: {:.3f} | T: {:.3f} | Time: {:.3f}'.
                  format(iteration, cost, t1, elapsed_time(start_time)))
            print(best_cost, t1, elapsed_time(start_time))
    return best_cost, best_spline
def control_state(robot,
                  joints,
                  target_positions,
                  target_velocities=None,
                  position_tol=INF,
                  velocity_tol=INF,
                  max_velocities=None,
                  verbose=True):  # TODO: max_accelerations
    if target_velocities is None:
        target_velocities = np.zeros(len(joints))
    if max_velocities is None:
        max_velocities = get_max_velocities(robot, joints)
    assert (max_velocities > 0).all()
    max_velocity_control_joints(robot,
                                joints,
                                positions=target_positions,
                                velocities=target_velocities,
                                max_velocities=max_velocities)
    for i in irange(INF):
        current_positions = np.array(get_joint_positions(robot, joints))
        position_error = get_distance(current_positions,
                                      target_positions,
                                      norm=INF)
        current_velocities = np.array(get_joint_velocities(robot, joints))
        velocity_error = get_distance(current_velocities,
                                      target_velocities,
                                      norm=INF)
        if verbose:
            # print('Positions: {} | Target positions: {}'.format(current_positions.round(N_DIGITS), target_positions.round(N_DIGITS)))
            # print('Velocities: {} | Target velocities: {}'.format(current_velocities.round(N_DIGITS), target_velocities.round(N_DIGITS)))
            print(
                'Step: {} | Position error: {:.3f}/{:.3f} | Velocity error: {:.3f}/{:.3f}'
                .format(i, position_error, position_tol, velocity_error,
                        velocity_tol))
        # TODO: draw the tolerance interval
        if (position_error <= position_tol) and (velocity_error <=
                                                 velocity_tol):
            return  # TODO: declare success or failure by yielding or throwing an exception
        yield i
def follow_curve_old(robot, joints, curve, goal_t=None):
    # TODO: unify with /Users/caelan/Programs/open-world-tamp/open_world/simulation/control.py
    if goal_t is None:
        goal_t = curve.x[-1]
    time_step = get_time_step()
    target_step = 10 * time_step
    #distance_fn = get_distance_fn(robot, joints, weights=None, norm=2)
    distance_fn = get_duration_fn(robot,
                                  joints,
                                  velocities=MAX_VELOCITIES,
                                  norm=INF)
    for i in irange(INF):
        # if (i % 10) != 0:
        #     continue
        current_p = np.array(get_joint_positions(robot, joints))
        current_v = np.array(get_joint_velocities(robot, joints))
        goal_dist = distance_fn(current_p, curve(goal_t))
        print('Positions: {} | Velocities: {} | Goal distance: {:.3f}'.format(
            current_p.round(N_DIGITS), current_v.round(N_DIGITS), goal_dist))
        if goal_dist < 1e-2:
            return True

        # _, connection = mpc(current_p, current_v, curve, v_max=MAX_VELOCITIES, a_max=MAX_ACCELERATIONS,
        #                     dt_max=1e-1, max_time=1e-1)
        # assert connection is not None
        # target_t = 0.5*connection.x[-1]
        # target_p = connection(target_t)
        # target_v = connection(target_t, nu=1)
        # #print(target_p)

        closest_dist, closest_t = find_closest(current_p,
                                               curve,
                                               t_range=None,
                                               max_time=1e-2,
                                               max_iterations=INF,
                                               distance_fn=distance_fn,
                                               verbose=True)
        target_t = min(closest_t + target_step, curve.x[-1])
        target_p = curve(target_t)
        #target_v = curve(target_t, nu=1)
        target_v = curve(closest_t, nu=1)

        #target_v = MAX_VELOCITIES
        #target_v = INF*np.zeros(len(joints))

        handles = draw_waypoint(target_p)
        #times, confs = time_discretize_curve(curve, verbose=False, resolution=resolutions)  # max_velocities=v_max,

        # set_joint_positions(robot, joints, target_p)
        max_velocity_control_joints(robot,
                                    joints,
                                    positions=target_p,
                                    velocities=target_v,
                                    max_velocities=MAX_VELOCITIES)

        #next_t = closest_t + time_step
        #next_p = current_p + current_v*time_step
        yield target_t
        actual_p = np.array(get_joint_positions(robot, joints))
        actual_v = np.array(get_joint_velocities(robot, joints))
        next_p = current_p + actual_v * time_step
        print('Predicted: {} | Actual: {}'.format(next_p.round(N_DIGITS),
                                                  actual_p.round(N_DIGITS)))
        remove_handles(handles)