示例#1
0
    def step_to_block(self, cfg_0, cfg_m):

        steps = [cfg_0, cfg_m]

        p0 = cfg_0.positions[-1]
        pm = cfg_m.positions[-1]
        d = gm.distance(p0, pm)
        # print(d)
        # print(p0, pm)
        theta = math.atan2(float(pm[1] - p0[1]), (pm[0] - p0[0]))
        # print(theta)
        num_steps = int(math.ceil(d * 1.0 / self.MAX_STEP))
        # print(num_steps)

        while len(steps) - 1 < num_steps:
            for i in range(num_steps - 1):
                cfg_1 = steps[i]
                cfg_nxt = self.config_from_point(gm.point_from_polar(
                    cfg_1.positions[-1], self.MAX_STEP, theta))
                steps.insert(i + 1, cfg_nxt)

                if (not self.validator.fits_bounds(cfg_nxt)) \
                        or self.validator.has_collision(
                        cfg_nxt, self.obstacles):
                    print(i)
                    print("hit block or out of bounds")
                    print(cfg_nxt.positions[-1])
                    return cfg_nxt.positions[-1]

        # print(steps)
        # print(len(steps))
        return None
示例#2
0
    def make_steps(self, cfg_0, cfg_m, check=True):
        """
        Interpolate a straight-line path between configurations in C-space.
        :param cfg_0: the initial configuration
        :param cfg_m: the final configuration
        :param check: check if the path is collision free if True
        :return: a tuple; the first element is 1 if a connection is
        made and 0 otherwise; the second element is the interpolated
        configurations from the initial to the final state inclusive.
        """
        connection = 0  # 1 if valid connection is made
        steps = [cfg_0, cfg_m]
        end_loop = False
        max_step = 1000.0  # max of all iterations

        while True:
            old_steps = list(steps)
            current_max_step = 0  # max of current iteration
            end_index = len(steps) - 1
            for i in range(end_index):
                # Interpolate the midpoint configuration
                cfg_1 = old_steps[i]
                cfg_2 = old_steps[i + 1]
                cfg_nxt = self.midpoint(cfg_1, cfg_2)
                steps.insert(2 * i + 1, cfg_nxt)
                i_max_step = gm.distance(cfg_1.positions[-1],
                                         cfg_nxt.positions[-1])

                if i_max_step > current_max_step:
                    current_max_step = i_max_step

                if check and (self.validator.has_collision(cfg_nxt,
                                                           self.obstacles)
                              or not self.validator.fits_bounds(cfg_nxt)):
                    end_loop = True
                    break

            if current_max_step < max_step:
                max_step = current_max_step

            if max_step < self.MAX_STEP:
                # No collision and primitive step size has been reached
                if check:
                    # Connect vertices in state graph
                    jump = PathJump(cfg_0, cfg_m)
                    cfg_0.add_connector(cfg_m, jump)
                    cfg_m.add_connector(cfg_0, jump)
                    connection = 1
                break
            if end_loop:
                break
        return connection, steps
 def max_distance(self, cfg_1):
     """
     Compute the maximum euclidean distance between corresponding
     positions of this configuration and the given configuration
     :param cfg_1:
     :return:
     """
     max_distance = 0.0
     for i in range(len(self.positions)):
         p0 = self.positions[i]
         p1 = cfg_1.positions[i]
         d = gm.distance(p0, p1)
         if d > max_distance:
             max_distance = d
     return max_distance
 def total_distance(self, cfg_1):
     total_distance = 0.0
     for i in range(len(self.positions)):
         total_distance += gm.distance(self.get_position(i),
                                       cfg_1.get_position(i))
     return total_distance
示例#5
0
    def move_block(self):

        push_behind = 50
        push_distance = 50
        max_push_distance = 150

        # Plan path with movable block removed until path found
        for block in self.scene.moveableBlocks:
            self.set_obstacles(self.scene, pucks=True)
            if block.y < 0:
                continue
            print("Attempting to remove block at ", block.x, block.y)
            print("Length before removal = ", len(self.obstacles))
            self.obstacles.remove(block.shape)
            print("Length after removal = ", len(self.obstacles))

            if len(self.scene.moveableBlocks) == 1:
                all_paths, costs = self.find_all_paths(impatient=False)
            else:
                all_paths, costs = self.find_all_paths(impatient=True)

            if self.all_paths_found:
                self.configs = []
                block_to_move = block
                x = block.x
                y = block.y
                if block.blockType == BlockSettings.CYLINDER:
                    push_behind = 40
                if block.blockType == BlockSettings.CUBE:
                    push_behind = 45
                elif block.blockType == BlockSettings.PRISM:
                    push_behind = 65
                break

            self.configs = []

        if not self.all_paths_found:
            print("Error: Couldn't find a path for block pushing")
            exit()

        # Goals are obstacles when it comes to pushing
        self.set_obstacles(self.scene, pucks=True, goals=True)
        self.obstacles.remove(block_to_move.shape)

        min_d1 = 1000000
        min_d2 = 1000000
        nearest_block1 = None
        nearest_block2 = None
        for block in self.scene.blocks:
            if block.y < 0:
                continue
            d = gm.distance((block.x, block.y), (x, y))
            if d < 0.5:
                # THIS IS THE BLOCK THATS MOVING. 0.5 IS ARBITRARY
                continue
            if d < min_d1:
                min_d2 = min_d1
                min_d1 = d
                nearest_block2 = nearest_block1
                nearest_block1 = (block.x, block.y)
            elif d < min_d2:
                min_d2 = d
                nearest_block2 = (block.x, block.y)

        # Check if block is closer to boundary than one of the nearest
        ww = WorkspaceSettings.WIDTH
        wh = WorkspaceSettings.HEIGHT
        bottom = gm.Line2D((-ww / 2, 0.0), (ww / 2, 0.0))
        right = gm.Line2D((ww / 2, 0.0), (ww / 2, wh))
        top = gm.Line2D((ww / 2, wh), (-ww / 2, wh))
        left = gm.Line2D((-ww / 2, wh), (-ww / 2, 0.0))
        boundaries = [bottom, right, top, left]
        # Make the boundary point one of the nearest if so
        min_db = 1000000
        for boundary in boundaries:
            p = boundary.p_point((x, y))
            d = boundary.p_distance((x, y))
            if d < min_d1:
                min_d2 = min_d1
                min_d1 = d
                nearest_block2 = nearest_block1
                nearest_block1 = p
            elif d < min_d2:
                min_d2 = d
                nearest_block2 = p

        if nearest_block1 is None or nearest_block2 is None:
            # Maybe there were not enought blocks or something?
            # This shouldn't happen, but if it does it will cause problems
            print("Planner: Error finding nearest blocks in moving blocks")
            return

        print("Found Nearest Blocks: ", nearest_block1, nearest_block2)

        nearest_block_line = gm.Line2D(nearest_block1, nearest_block2)

        m1, c1 = nearest_block_line.find_normal_at_point((x, y))
        print("Nearest block line: m,c: ", m1, c1)

        # Direction of push
        theta = math.atan2(m1, 1.0)
        print("Theta is ", theta)
        print("x,y is :", x, y)

        start_point = gm.point_from_polar((x, y), push_behind, theta + np.pi)
        start_point = (start_point[0], start_point[1] - 5.0)
        print("Start point is: ", start_point)
        start_cfg = self.config_from_point(start_point)
        max_point = gm.point_from_polar((x, y), max_push_distance, theta)
        max_cfg = self.config_from_point(max_point)

        # Move forward (~ along path)
        # Check each direction until not in collision

        # TODO: intersect functions for prism and cube
        nearest_collision = self.step_to_block(start_cfg, max_cfg)

        if nearest_collision is None:
            push_distance = max_push_distance
        else:
            push_distance = gm.distance((x, y), nearest_collision)
        print("Nearest collision for first direction: ", nearest_collision)

        # See if opposite direction is better
        print("Checking opposite push direction")
        start_point2 = gm.point_from_polar((x, y), push_behind, theta)
        start_point2 = (start_point2[0], start_point2[1] - 5.0)
        start_cfg2 = self.config_from_point(start_point2)
        max_point2 = gm.point_from_polar((x, y), max_push_distance, theta + np.pi)
        max_cfg2 = self.config_from_point(max_point)
        nearest_collision2 = self.step_to_block(start_cfg2, max_cfg2)
        print("Nearest collision for second direction: ", nearest_collision2)

        if nearest_collision2 is None:
            if nearest_collision is not None:
                # Opposite direction does not collide -> better
                theta += np.pi
                start_point = start_point2
                start_cfg = start_cfg2
                push_distance = max_push_distance
        # Both None -> go with first option
        elif nearest_collision is not None:
            # Both have collision -> choose longest available push
            push_distance2 = gm.distance((x, y), nearest_collision2)
            if push_distance2 > push_distance:
                print("Chose opposite direction")
                # Direction 2 is better
                theta += np.pi
                start_point = start_point2
                start_cfg = start_cfg2
                push_distance = push_distance2
        # Else no change, go with direction 1

        end_point = gm.point_from_polar((x, y), push_distance - 20, theta)
        end_point = (end_point[0], end_point[1] - 5.0)
        print("End point is: ", end_point)
        end_cfg = self.config_from_point(end_point)

        path = Path()
        path.path.append(start_cfg)
        path.path.append(end_cfg)
        path.movingPath = True
        self.super_path.paths.append(path)

        # Update block position after push (inaccurate)
        self.set_obstacles(self.scene, pucks=True)
        self.obstacles.remove(block_to_move.shape)
        block_to_move.x = end_point[0]
        block_to_move.y = end_point[1]
        block_to_move.find_shape()
        print("Adding back the moved block: ", block_to_move.shape)
        # Remove goals for path planning
        self.obstacles.append(block_to_move.shape)
示例#6
0
    def do_query(self, root_index, goal_index):
        """
        Search for a path between the specified root and goal via the roadmap
        :return: True if a path was found
        """

        self.validator.set_enlarge_factor(0.5)
        print("Planner: finding path from puck {0} to goal {1}"
              .format(root_index, goal_index))

        root = self.get_end_state(0, index=root_index)
        goal = self.get_end_state(1, index=goal_index)
        if not self.validator.is_valid_sample(root, self.obstacles, debug=False) or \
                not self.validator.is_valid_sample(goal, self.obstacles, debug=False):
            print("Planner: ERROR: invalid end states")
            print("Valid root: ", self.validator.is_valid_sample(root, self.obstacles))
            print("Valid goal: ", self.validator.is_valid_sample(goal, self.obstacles))
            exit()

        if self.safety:
            self.validator.set_enlarge_factor(self.SAFE_FACTOR)
        else:
            self.validator.set_enlarge_factor(self.RISKY_FACTOR)

        # Try direct path
        direct_connection = self.make_steps(root, goal, check=True)[0]
        if direct_connection:
            self.path.set_path([root, goal])
            self.path_found = True
            self.path.cost = gm.distance(root.positions[-1],
                                         goal.positions[-1])
            print("Planner: goal found directly")
            return True

        # Find vertices nearest initial and goal configs
        connected_root = self.connect_configs(root)
        connected_goal = self.connect_configs(goal)

        # Check if root and goal were connected
        if not (connected_root and connected_goal):
            # Solution not possible
            return False

        # Initial and goal states are now in the roadmap
        # Search for a path
        ass = AStarSearch(root, goal)
        print("Planner: searching")
        ass.search()

        if ass.goal_found:
            # print("Planner: visualising")
            # self.visualise_graph()
            # Record solution
            path = ass.path
            full_path = []

            while len(path) > 1:
                cfg_0 = path.pop(0)
                # Uncomment below 4 lines to display/calculate curved paths
                # cfg_m = path[0]
                # steps = self.make_steps(cfg_0, cfg_m, check=False)[1]
                # steps.pop()
                # full_path += steps

                full_path.append(cfg_0)

            full_path.append(goal)
            self.path.set_path(full_path)
            self.path.cost = ass.total_cost
            self.path_found = True
            # Remove this root and goal from the roadmap, ready for the next
            for cfg in root.connectors:
                cfg.connectors.pop(root, False)
            for cfg in goal.connectors:
                cfg.connectors.pop(goal, False)
            return True

        return False