Skip to content
Snippets Groups Projects
test_traj_opt.py 13.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.patches import Circle, Rectangle
    from casadi import *
    from guided_mrmp.conflict_resolvers.curve_path import smooth_path, calculate_headings
    
    from guided_mrmp.conflict_resolvers.traj_opt_resolver import TrajOptResolver
    
    def plot_paths(circle_obs, num_robots, starts, goals, x_opt, initial_guess, x_range, y_range):
            fig, ax = plt.subplots()
    
            # Plot obstacles
            for obstacle in circle_obs:
                # if len(obstacle) == 2:  # Circle
                ax.add_patch(Circle(obstacle, obstacle[2], color='red'))
                # elif len(obstacle) == 4:  # Rectangle
                #     ax.add_patch(Rectangle((obstacle[0], obstacle[1]), obstacle[2], obstacle[3], color='red'))
    
            colors = plt.cm.Set1(np.linspace(0, 1, num_robots))
    
            # Plot robot paths
            for r,color in zip(range(num_robots),colors):
                ax.plot(x_opt[r*2, :], x_opt[r*2+1, :], label=f'Robot {r+1}', color=color)
                ax.scatter(x_opt[r*2, :], x_opt[r*2+1, :], color=color, s=10 )
                ax.scatter(starts[r][0], starts[r][1], s=85,color=color)
                ax.scatter(goals[r][0], goals[r][1], s=85,facecolors='none', edgecolors=color)
                if initial_guess is not None:
                    ax.plot(initial_guess[r*3, :], initial_guess[r*3+1, :], color=color, linestyle='--')
                    ax.scatter(initial_guess[r*3, :], initial_guess[r*3+1, :], color=color, s=5 )
    
                plot_roomba(starts[r][0], starts[r][1], 0, color)
    
    
    
            plt.ylim(0, y_range[1])
            plt.xlim(0,x_range[1])
            plt.axis("equal")
            plt.axis("off")
            
    
            plt.tight_layout()
    
            plt.grid(False)
            plt.show()
    
    def plot_paths_db(circle_obs, num_robots, starts, goals, x_opt, initial_guess,x_range, y_range):
            fig, ax = plt.subplots()
    
            # Plot obstacles
            for obstacle in circle_obs:
                # if len(obstacleq) == 2:  # Circle
                ax.add_patch(Circle(obstacle, obstacle[2], color='red'))
                # elif len(obstacle) == 4:  # Rectangle
                #     ax.add_patch(Rectangle((obstacle[0], obstacle[1]), obstacle[2], obstacle[3], color='red'))
    
            colors = plt.cm.Set1(np.linspace(0, 1, num_robots))
    
            # Plot robot paths
            for r,color in zip(range(num_robots),colors):
                if x_opt is not None:
                    ax.plot(x_opt[r*2, :], x_opt[r*2+1, :], label=f'Robot {r+1}', color=color)
                    ax.scatter(x_opt[r*2, :], x_opt[r*2+1, :], color=color, s=10 )
                ax.scatter(starts[r][0], starts[r][1], s=85,color=color)
                ax.scatter(goals[r][0], goals[r][1], s=135,facecolors='none', edgecolors=color)
                if initial_guess is not None:
                    ax.plot(initial_guess[r*3, :], initial_guess[r*3+1, :], color=color, linestyle='--')
                    ax.scatter(initial_guess[r*3, :], initial_guess[r*3+1, :], color=color, s=5 )
    
                if x_opt is not None: plot_roomba(starts[r][0], starts[r][1], 0, color)
                # plot_roomba(self.goals[r][0], self.goals[r][1], 0, color)
    
    
    
            plt.ylim(0, y_range[1])
            plt.xlim(0,x_range[1])
            plt.axis("equal")
            # plt.axis("off")
            
    
            plt.tight_layout()
    
            plt.grid(False)
            plt.show()
    
    
    def plot_sim(x_histories, y_histories, h_histories, x_range, y_range):
    
        x_histories = np.array(x_histories)
        y_histories = np.array(y_histories)
        h_histories = np.array(h_histories)
    
        colors = plt.cm.Set1(np.linspace(0, 1, len(x_histories)))
    
    
        longest_traj = max([len(x) for x in x_histories])
    
        for i in range(longest_traj):
            plt.clf()
            for x_history, y_history, h_history, color in zip(x_histories, y_histories, h_histories, colors):
                
                # print(color)
    
                plt.plot(
                    x_history[:i],
                    y_history[:i],
                    c=color,
                    marker=".",
                    alpha=0.5,
                    label="vehicle trajectory",
                )
    
                if i < len(x_history):
                    plot_roomba(x_history[i-1], y_history[i-1], h_history[i-1], color)
                else:
                    plot_roomba(x_history[-1], y_history[-1], h_history[-1], color)
    
            
            plt.ylim(0, y_range[1])
            plt.xlim(0,x_range[1])
            plt.axis("equal")
            # plt.axis("off")
            
    
            plt.tight_layout()
    
            plt.grid(False)
    
            plt.draw()
            # plt.savefig(f"frames/sim_{i}.png")
            # plt.show()
            plt.pause(0.2)
        input()
    
    def plot_roomba(x, y, yaw, color, radius=.7):
        """
    
        Args:
            x ():
            y ():
            yaw ():
        """
        fig = plt.gcf()
        ax = fig.gca()
        circle = plt.Circle((x, y), radius, color=color, fill=False)
        ax.add_patch(circle)
    
        # Plot direction marker
        dx = radius * np.cos(yaw)
        dy = radius * np.sin(yaw)
        ax.arrow(x, y, dx, dy, head_width=0.1, head_length=0.05, fc='r', ec='r')
    
    def generate_prob_from_db(N, lib, cp_dist=-.5, sigma=0.0):
        
    
        d = lib.key_to_idx
    
        # get a random key from the library
        key, idx = random.choice(list(d.items()))
    
        # print(key)
        # print(len(key))
    
        num_robots = len(key) // 4
    
        start_nodes = []
        goal_nodes = []
    
        for i in range(0, len(key), 4):
            start = [int(key[i]), int(key[i+1])]
            goal = [int(key[i+2]), int(key[i+3])]
            start_heading = np.arctan2(goal[1] - start[1], goal[0] - start[0])
            start.append(start_heading)
            start_nodes.append(start)
            goal_nodes.append(goal)
    
    
        sol = lib.get_matching_solution(start_nodes, goal_nodes)
    
        # print(f"sol = {sol}")
    
        # turn this solution into an initial guess 
        initial_guess = np.zeros((num_robots*3, N+1))
        for i in range(num_robots):
    
            # print(f"Robot {i+1} solution:")
            rough_points = np.array(sol[i])
            points = []
            for point in rough_points:
                if point[0] == -1: break
                points.append(point)
            
            points = np.array(points)
            # print(f"points = {points}")
    
            smoothed_curve, _ = smooth_path(points, N+1, cp_dist)
            # print(f"smoothed_curve = {smoothed_curve}")
    
            initial_guess[i*3, :] = smoothed_curve[:, 0]        # x
            initial_guess[i*3 + 1, :] = smoothed_curve[:, 1]    # y
    
            # for j in range(N):
            #     dx = smoothed_curve[j+1, 0] - smoothed_curve[j, 0]
            #     dy = smoothed_curve[j+1, 1] - smoothed_curve[j, 1]
            #     initial_guess[i*3 + 2, j] = np.arctan2(dy, dx)
    
            headings = calculate_headings(smoothed_curve)
            headings.append(headings[-1])
    
            initial_guess[i*3 + 2, :] = headings
    
            # initial_guess[i*3 + 2, :] = np.arctan2(np.diff(smoothed_curve[:, 1]), 
            #                                        np.diff(smoothed_curve[:, 0]))
    
        
    
    
        # print(sol)
    
        # for i in range(num_robots):
        #     print(f"Robot {i+1} initial guess:")
        #     print(f"x: {initial_guess[i*3, :]}")
        #     print(f"y: {initial_guess[i*3 + 1, :]}")
        #     print(f"theta: {initial_guess[i*3 + 2, :]}")
    
        return start_nodes, goal_nodes, initial_guess
    
    if __name__ == "__main__":
    
        import os
        import numpy as np
        import random
    
        # load the yaml file
        import yaml
    
        with open("guided_mrmp/tests/initial_guesses.yaml") as file:
    
            settings = yaml.load(file, Loader=yaml.FullLoader)
    
        seed = 1123581
        seed = 112
        print(f"***Setting Python Seed {seed}***")
        os.environ['PYTHONHASHSEED'] = str(seed)
        np.random.seed(seed)
        random.seed(seed)
    
        # define obstacles
        circle_obs = np.array(settings['environment']['circle_obs'])
        rectangle_obs = np.array(settings['environment']['rectangle_obs'])
        
    
        # weights for the cost function
        dist_robots_weight = settings['cost_weights']['dist_robots_weight']
        dist_obstacles_weight = settings['cost_weights']['dist_obstacles_weight']
        control_costs_weight = settings['cost_weights']['control_costs_weight']
        time_weight = settings['cost_weights']['time_weight']
        goal_weight = settings['cost_weights']['goal_weight']
    
        # other params
        rob_radius = settings['robot_radius']
        N = settings['N']
    
        from guided_mrmp.utils import Library
        import random
        lib_name = settings['library']['name']
        lib = Library("guided_mrmp/database/"+lib_name+"_library")
        lib.read_library_from_file()
    
        cp_dist = float(settings['control_point_distance'])
        num_trials = settings['num_trials']
    
        h = settings['grid_resolution']
        x_max = settings['library']['x_max']
        y_max = settings['library']['y_max']
        x_range = (0, x_max*h)
        y_range = (0, y_max*h)
    
    
        times = []
        success = []
        goal_error = []
    
        for i in range(num_trials):
    
            print("i = ", i)
    
            robot_starts, robot_goals, initial_guess = generate_prob_from_db(N,lib, cp_dist)
    
            num_robots = len(robot_starts)
    
            robot_starts = np.array(robot_starts)
            robot_goals = np.array(robot_goals)
            robot_starts = robot_starts*h + .5*h
            robot_goals = robot_goals*h + .5*h
            initial_guess = initial_guess*h + .5*h
    
            initial_guesses = {
                'X': initial_guess,
                'T': settings['initial_guess']['T']
                }
    
            initial_guess_type = settings['initial_guess']['X']
            
            if initial_guess_type == 'line':
                initial_guess = np.zeros((num_robots*3,N+1))
                for i in range(0,num_robots*3,3):
                    start=robot_starts[int(i/3)]
                    goal=robot_goals[int(i/3)]
                    initial_guess[i,:] = np.linspace(start[0], goal[0], N+1)
                    initial_guess[i+1,:] = np.linspace(start[1], goal[1], N+1)
    
                    # make the heading initial guess the difference between consecutive points
                    for j in range(N):
                        dx = initial_guess[i,j+1] - initial_guess[i,j]
                        dy = initial_guess[i+1,j+1] - initial_guess[i+1,j]
                        initial_guess[i+2,j] = np.arctan2(dy,dx)
                
                initial_guesses = {
                'X': initial_guess,
                'T': settings['initial_guess']['T']
                }
    
            
            elif initial_guess_type == 'None':
                initial_guesses = None
    
            solver = TrajOptResolver(num_robots=num_robots, 
                                    robot_radius=rob_radius,
                                    starts=robot_starts, 
                                    goals=robot_goals, 
                                    circle_obstacles=circle_obs, 
                                    rectangle_obstacles=rectangle_obs,
                                    rob_dist_weight=dist_robots_weight,
                                    obs_dist_weight=dist_obstacles_weight,
                                    control_weight=control_costs_weight,
                                    time_weight=time_weight,
                                    goal_weight=goal_weight
                                    )
            
            
    
            solver_options = {'ipopt.print_level': settings['solver_options']['print_level'],
                              'print_time': settings['solver_options']['print_time'],}
    
            
            import time
            start = time.time()
            sol,pos, vels, omegas, xs, ys, thetas = solver.solve(N, x_range, y_range, initial_guesses, solver_options)
            end = time.time()
            # times.append(end-start)
    
    
            if sol is None:
                print("failed")
                success.append(0)
    
            else:
                # check if the solution is valid
                # check if any robots overlap
                valid = True
                for k in range(N):
                    for i in range(num_robots):
                        for j in range(i+1, num_robots):
                            if np.linalg.norm(np.array([xs[i,k] - xs[j,k], ys[i,k] - ys[j,k]]), axis=0) < 2*rob_radius:
                                print("robot collision")
                                valid = False
                                break
                
                        
    
                # check if any robots are in obstacles
                for k in range(N):
                    for i in range(num_robots):
                        for obs in circle_obs:
                            if np.any(np.linalg.norm(np.array([xs[i,k] - obs[0], ys[i,k] - obs[1]]), axis=0) < rob_radius + obs[2]):
                                print("circle collision")
                                valid = False
                                break   
                
                if valid:
                    success.append(1)
    
                    # calculate the average goal error
                    goal_error.append(np.mean(np.linalg.norm(np.array([xs[:,-1] - robot_goals[:,0], ys[:,-1] - robot_goals[:,1]]), axis=0)))
    
                    times.append(end-start)
    
                else:
                    success.append(0)
                    times.append(end-start)
    
                print(f"Time to solve = {end-start}")
                print(sol.stats()["iter_count"])
    
    
                # print(xs)
            
                pos_vals = np.array(sol.value(pos))
    
                # print(xs)
                plot_paths_db(circle_obs, num_robots, robot_starts, robot_goals, None, initial_guess, x_range, y_range)
                # plot_paths_db(circle_obs, num_robots, robot_starts, robot_goals, pos_vals, None, x_range, y_range)
                plot_sim(xs, ys, thetas, x_range, y_range)
    
    
    
        times = np.array(times)
        success = np.array(success)
        goal_error = np.array(goal_error)
        print(f"times = {times}")
        print(f"success = {success}")
        print(f"goal_error = {goal_error}")
        print(f"avg time = {np.mean(times)}")
        print(f"success rate = {np.mean(success)}")
        print(f"avg goal error = {np.mean(goal_error)}")
        # print the standard deviation of the times
        print(f"std dev of time = {np.std(times)}")