示例#1
0
def verticalWallScenarioEasy():

    # Create the occupancy grid
    occupancyGrid = OccupancyGrid(21, 21, 1)

    for y in xrange(1, 19):
        occupancyGrid.setCell(11, y, 1)

    start = (2, 18)
    goal = (20, 0)

    return start, goal, occupancyGrid
示例#2
0
def horizontalWallScenario():

    # Create the occupancy grid
    occupancyGrid = OccupancyGrid(21, 21, 1)

    for x in xrange(2, 20):
        occupancyGrid.setCell(x, 11, 1)

    start = (2, 2)
    goal = (20, 20)

    return start, goal, occupancyGrid
def test_map_loading():
    # create an occupancy grid
    grid_map = OccupancyGrid("../../resources/occ_maps/test_map.png", 0.01)

    # create a plot axis
    fig, ax = plt.subplots()
    ax.set_aspect('equal')
    ax.set_xlim(0, 7.5)
    ax.set_ylim(0, 6)

    # visualize map
    grid_map.visualize(ax)

    plt.show()
示例#4
0
def emptyGridScenario():

    occupancyGrid = OccupancyGrid(21, 21, 1)
    start = (5, 10)
    goal = (15, 10)

    return start, goal, occupancyGrid
    def __init__(self, parent=None):
        super(App, self).__init__(parent)

        #### Create Gui Elements ###########
        self.mainbox = QtGui.QWidget()
        self.setCentralWidget(self.mainbox)
        self.mainbox.setLayout(QtGui.QVBoxLayout())

        self.canvas = pg.GraphicsLayoutWidget()
        self.mainbox.layout().addWidget(self.canvas)

        self.label = QtGui.QLabel()
        self.mainbox.layout().addWidget(self.label)

        self.view = self.canvas.addViewBox()
        self.view.setAspectLocked(True)
        self.view.setRange(QtCore.QRectF(0, 0, 100, 100))

        #### Set Data  #####################
        self.idx = 10
        self.x = np.linspace(0, 50., num=100)
        self.X, self.Y = np.meshgrid(self.x, self.x)

        #  image plot
        self.img = pg.ImageItem(border='w')
        self.turtlebot = TurtleBotItem(self.X[:, self.idx], 1.5)
        self.view.addItem(self.img)
        self.view.addItem(self.turtlebot)

        self.counter = 0
        self.fps = 0.
        self.lastupdate = time.time()

        # Variables used for creating and visualizing the map
        self.grid = OccupancyGrid()
        self.data = self.grid.map * 255

        #### Start  #####################
        self._update()
示例#6
0
 def __init__(self, name, coord, dims):
     self.time = 0
     self.pos = coord
     self.name = name
     self.limits = dims
     self.obs = None
     self.S = OccupancyGrid(False, dims[0], dims[1])
     self.D = OccupancyGrid(False, dims[0], dims[1])
     self.T = OccupancyGrid(length=dims[0], width=dims[1])
     self.C = 80.0
示例#7
0
    def __init__(self):
        """ Intitialize map reading node. """
        rospy.wait_for_service('static_map')
        try:
            static_map = rospy.ServiceProxy('static_map', GetMap)
            resp = static_map()
            map = resp.map
            if map is not None:
                print "========================="
                print("MAP TYPE:,", type(map))
                print "========================="
            else:
                print "no map :("
            self.grid_map = OccupancyGrid(map)
            self.info = map.info

        except rospy.ServiceException, e:
            print "Service call failed: %s" % e
class App(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(App, self).__init__(parent)

        #### Create Gui Elements ###########
        self.mainbox = QtGui.QWidget()
        self.setCentralWidget(self.mainbox)
        self.mainbox.setLayout(QtGui.QVBoxLayout())

        self.canvas = pg.GraphicsLayoutWidget()
        self.mainbox.layout().addWidget(self.canvas)

        self.label = QtGui.QLabel()
        self.mainbox.layout().addWidget(self.label)

        self.view = self.canvas.addViewBox()
        self.view.setAspectLocked(True)
        self.view.setRange(QtCore.QRectF(0, 0, 100, 100))

        #### Set Data  #####################
        self.idx = 10
        self.x = np.linspace(0, 50., num=100)
        self.X, self.Y = np.meshgrid(self.x, self.x)

        #  image plot
        self.img = pg.ImageItem(border='w')
        self.turtlebot = TurtleBotItem(self.X[:, self.idx], 1.5)
        self.view.addItem(self.img)
        self.view.addItem(self.turtlebot)

        self.counter = 0
        self.fps = 0.
        self.lastupdate = time.time()

        # Variables used for creating and visualizing the map
        self.grid = OccupancyGrid()
        self.data = self.grid.map * 255

        #### Start  #####################
        self._update()

    def _update(self):
        if self.counter < params.x.shape[1]:
            self.grid.updateMap2(params.x[:, self.counter],
                                 params.z[:, :, self.counter])
            self.turtlebot.setPose(params.x[:, self.counter])
            self.counter += 1

        self.data = self.grid.map * 255.0
        self.img.setImage(self.data)

        now = time.time()
        dt = (now - self.lastupdate)
        if dt <= 0:
            dt = 0.000000000001
        fps2 = 1.0 / dt
        self.lastupdate = now
        self.fps = self.fps * 0.9 + fps2 * 0.1
        tx = 'Mean Frame Rate:  {fps:.3f} FPS'.format(fps=self.fps)
        self.label.setText(tx)
        QtCore.QTimer.singleShot(1, self._update)
示例#9
0
    arg_parser.add_argument('--start_y', type=int, default=0)
    arg_parser.add_argument('--robot_radius', type=float, default=0.8)
    arg_parser.add_argument('--robot_yaw', type=float, default=0)
    arg_parser.add_argument('--robot_sensor_range', type=float, default=7)
    arg_parser.add_argument('--robot_sensor_view_angle',
                            type=float,
                            default=60)
    arg_parser.add_argument('--wall_obseration_angle', type=float, default=70)
    arg_parser.add_argument('--output', type=str, default="waypoints.txt")
    arg_parser.add_argument('--show_plot', type=bool, default=True)
    args = arg_parser.parse_args()

    # Transform the provided 3D point cloud to a 2D grid representation.
    pcl_3d = PointCloud3D(read_point_cloud_log("pcl/sas_pc_0.bin", 3, False))
    pcl_2d = pcl_3d.to_2D(args.z_min, args.z_max)
    map_grid = OccupancyGrid(pcl_2d, args.grid_resolution)

    # Create a robot within the grid world.
    robot = Robot(args.start_x, args.start_y, args.robot_radius,
                  args.robot_yaw, args.robot_sensor_range,
                  args.robot_sensor_view_angle)

    # Plan a full coverage path for the robot to explore the gridworld.
    planner = FrontierPlanner(map_grid, robot, args.wall_obseration_angle,
                              args.show_plot)
    waypoints = planner.get_full_coverage_path()

    # Write the planned waypoints out to a file for later use.
    with open(args.output, "w") as f:
        for p in waypoints:
            f.write(",".join([str(v) for v in p]))
示例#10
0
    r1 = x
    r2 = r1 + 3
    c1 = y
    c2 = y + 3
    return env1[r1:r2, c1:c2]

if __name__ == "__main__":
    """
        2 robot test in 10X10 world
    """
    # Load world
    with open('./worlds/10X10.json') as file:
        maze = json.load(file)
        # Initialize maze
        dim = [maze['dim1'], maze['dim2']]
        world = OccupancyGrid(True, dim[0], dim[1])
        # Initialize robots
        robots = []
        for i in range(maze['n']):
            name = i + 3
            robots.append(Robot(name, maze['r' + str(i)], dim))
            world.update_robot_position(name, maze['r' + str(i)], maze['r' + str(i)])
        # Initialize static objects
        for obj in maze['static']:
            world.add_static_object(obj[0], obj[1])
        # Initialize Dynamic Objects
        for obj in maze['dynamic']:
            print(obj)
            world.add_dynamic_object(obj[0][0], obj[0][1], obj[1][0], obj[1][1])
        # Update poses
        for x in range(10):
示例#11
0
def main():
    # Instantiate obstacle manager

    try:
        s = rospy.Service('create_obstacle', obstacle_create_srv, handle_create_request)
        rospy.init_node('runtime', anonymous=True)
        tf_buffer = tf2_ros.Buffer()
        tf_listener = tf2_ros.TransformListener(tf_buffer)
        time.sleep(1)
        cf_tf_pos = tf_buffer.lookup_transform("world", "cf", rospy.Time(0))
        cf_pos = np.array([cf_tf_pos.transform.translation.x, cf_tf_pos.transform.translation.y]) # cf [x y] position from motive
        # subprocess.call(["roslaunch", "crazyflie_examples","hw_hover.launch", "takeoff_hover_x:=" + str(cf_pos[0]), "takeoff_hover_y:=" + str(cf_pos[1]), "takeoff_hover_z:=1.5"])



    except (rospy.ROSInterruptException, tf2_ros.LookupException, tf2_ros.ConnectivityException, tf2_ros.ExtrapolationException):
        rospy.loginfo("")
        # rospy.logerr("No takeoff position info, using defaults...")
        # subprocess.call(["roslaunch", "crazyflie_examples","hw_hover.launch"])

    # Build occupancy grid

    r = rospy.Rate(10)

    occupancy_grid = OccupancyGrid()
    occupancy_grid.Initialize()

    turtlebot_tracker = TrackTurtlebot()
    turtlebot_tracker.Initialize()
    track_flag = False

    # position_helper = PositionHelper()
    prev_cf_pos = [0,0]

    mydata = raw_input("Press any key to start: ")

    rospy.wait_for_service('/takeoff')
    subprocess.call(["rosservice", "call","/takeoff"])
    returnGrid = np.array([0,0])
    time.sleep(3)
    
    while not rospy.is_shutdown():

        try:
            occupancy_grid.Update(obstacle_manager.getObstacles())
            

        except rospy.ROSInterruptException:
            rospy.loginfo("")

        # Get current crazyflie grid pos to increase cost of returning to same grid
        try:
            mod_occupied_grid = occupancy_grid.getOccupancy()
            # mod_occupied_grid[returnGrid[0]][returnGrid[1]] = 1
            occupancy_grid.Visualize()

        except rospy.ROSInterruptException:
            rospy.loginfo("")

        # Track turtlebot
        try:
            
            track_flag, returnGrid = turtlebot_tracker.Track(occupancy_grid, obstacle_manager, mod_occupied_grid)

        except rospy.ROSInterruptException:
            rospy.loginfo("")

        if (track_flag == True):
            break
        
        r.sleep()
    rospy.spin()
示例#12
0
import json
import numpy as np
from robot import Robot
from occupancy_grid import OccupancyGrid

with open('.\\worlds\\10X10.json') as file:
    maze = json.load(file)
    # Initialize maze
    dim = [maze['dim1'], maze['dim2']]
    world = OccupancyGrid(True, dim[0], dim[1])
    # Initialize robots
    robots = []
    for i in range(maze['n']):
        name = i + 3
        robots.append(Robot(name, maze['r' + str(i)], dim))
        world.update_robot_position(name, maze['r' + str(i)],
                                    maze['r' + str(i)])
    # Initialize static objects
    for i in maze['static']:
        world.add_static_object(i[0], i[1])

    world.show()
示例#13
0
class Robot(object):
    def __init__(self, name, coord, dims):
        self.time = 0
        self.pos = coord
        self.name = name
        self.limits = dims
        self.obs = None
        self.S = OccupancyGrid(False, dims[0], dims[1])
        self.D = OccupancyGrid(False, dims[0], dims[1])
        self.T = OccupancyGrid(length=dims[0], width=dims[1])
        self.C = 80.0

    def move_right(self):
        ## check if no static  object
        self.pos[1] = self.pos[1] + 1 if self.pos[
            1] < self.limits[1] - 1 else self.pos[1]
        return self.pos

    def move_left(self):
        self.pos[1] = self.pos[1] - 1 if self.pos[1] > 0 else self.pos[1]
        return self.pos

    def move_up(self):
        self.pos[0] = self.pos[0] - 1 if self.pos[0] > 0 else self.pos[0]
        return self.pos

    def move_down(self):
        self.pos[0] = self.pos[0] + 1 if self.pos[
            0] < self.limits[0] - 1 else self.pos[0]
        return self.pos

    def setObs(self, observation):
        self.obs = observation  #3*3
        list_global = {}
        for i in range(3):
            for j in range(3):
                if observation[i][j] == -1:
                    continue
                observation[i][
                    j] = 0 if observation[i][j] >= 3 else observation[i][j]
                gx = self.pos[0]
                gy = self.pos[1]
                lx, ly = 1, 1
                nx = gx - (lx - i)
                ny = gy - (ly - j)
                list_global[(nx, ny)] = observation[i][j]
        for pose, obs in list_global.items():
            # print(pose, obs)
            # print(self.get_static_inv_sensor_model(pose, obs))
            self.update_static_grid(
                self.get_static_inv_sensor_model(pose, obs), pose)
            self.update_dynamic_grid(
                self.get_dynamic_inv_sensor_model(pose, obs), pose)
            self.T.update(self.time, pose)

        self.update_time()

    def update_time(self):
        observed = np.array(self.T.get_arr() > 0, np.int)
        delT = np.full((self.limits[0], self.limits[1]),
                       self.time) * observed - self.T.get_arr()
        delT = delT / self.C
        self.T.mat = self.T.mat - delT

    def merge(self, robot_S, robot_D, robot_T):
        for i in range(self.limits[0]):
            for j in range(self.limits[1]):
                if robot_T[i, j] > self.T.get_arr()[i, j]:
                    self.S.update(robot_S[i, j], (i, j))
                    self.D.update(robot_D[i, j], (i, j))
                    self.T.update(robot_T[i, j], (i, j))

    def get_position(self):
        return self.pos

    def get_static_inv_sensor_model(self, pose, obs):
        """
        :param s_prob_val: The previous occupancy probability value at the (x,y) position
        :param obs: The observation at a particular (x,y) location. 0: Free | 1: Occupied
        :return: The inverse sensor model
        """
        # print(self.S.get_arr())
        s_prob_val = self.S.get_arr()[pose]
        free_threshold = 0.45  # Probability below which position is certainly free
        occupied_threshold = 0.55  # Probability above which position is certainly occupied
        inv_sensor_low = 0.05
        inv_sensor_high = 0.85
        if s_prob_val <= free_threshold:
            if obs:
                return 0.01
            else:
                return inv_sensor_low  # Free, Free and Free, Occupied
        elif s_prob_val >= occupied_threshold:
            if obs:
                return inv_sensor_high  # Occupied, Occupied
            else:
                return inv_sensor_low  # Occupied, Free
        else:  # If unknown
            if obs:
                return inv_sensor_high  # Unknown, Occupied
            else:
                return inv_sensor_low  # Unknown, Free

    def get_dynamic_inv_sensor_model(self, pose, obs):
        """
        :param s_prob_val: The previous occupancy probability value at the (x,y) position
        :param obs: The observation at a particular (x,y) location. 0: Free | 1: Occupied
        :return: The inverse sensor model
        """
        s_prob_val = self.S.get_arr()[pose]
        free_threshold = 0.1  # Probability below which position is certainly free
        occupied_threshold = 0.9  # Probability above which position is certainly occupied
        inv_sensor_low = 0.05
        inv_sensor_high = 0.99
        if s_prob_val <= free_threshold:
            if obs:
                return inv_sensor_high  # Free, Occupied
            else:
                return inv_sensor_low  # Free, Free
        elif s_prob_val >= occupied_threshold:
            if obs:
                return inv_sensor_low  # Occupied, Free and Occupied, Occupied
            else:
                return 0.2
        else:  # If unknown
            return inv_sensor_low  # Unknown, Free and Unknown, Occupied

    def update_static_grid(self, inv_sensor_model, pose):
        prev_S = self.S.get_arr()[pose]
        S_update = 0
        for x, y in np.ndindex(self.S.get_arr().shape):
            c = np.exp(
                np.log(inv_sensor_model / (1 - inv_sensor_model)) +
                np.log(prev_S / (1.00001 - prev_S)))
            S_update = c / (1 + c)
        self.S.update(S_update, pose)

    def update_dynamic_grid(self, inv_sensor_model, pose):
        prev_D = self.D.get_arr()[pose]
        D_update = 0
        for x, y in np.ndindex(self.D.get_arr().shape):
            c = np.exp(
                np.log(inv_sensor_model / (1 - inv_sensor_model)) +
                np.log(prev_D / (1.00001 - prev_D)))
            D_update = c / (1 + c)
        self.D.update(D_update, pose)

    def step(self, action):
        self.time += 1
        if action == "r":
            return self.move_right()
        elif action == "o":
            return self.get_position()
        elif action == "l":
            return self.move_left()
        elif action == "u":
            return self.move_up()
        elif action == "d":
            return self.move_down()
    def __init__(self):

        # Build list of turn primitives.
        assert self.NUM_TURN_DIVISIONS % 2 == 1
        turn_angles = np.linspace(-self.MAX_TURN, self.MAX_TURN,
                                  self.NUM_TURN_DIVISIONS)
        np.testing.assert_almost_equal(
            turn_angles[self.NUM_TURN_DIVISIONS / 2], 0.0)
        turn_angles = sorted(turn_angles, key=lambda x: math.fabs(x))
        rospy.loginfo("Making turn angles: {}".format(turn_angles))
        self.primitives = [Turn_Primitive(angle) for angle in turn_angles]
        self.primitives.extend([
            Turn_Primitive(a * self.MAX_TURN_POSSIBLE,
                           total_time=self.MAX_TURN_TOTAL_TIME)
            for a in [1, -1]
        ])

        # Setup visualization publishers - latch them for easier debugging.
        self.display_tree = []
        self.display_path = []
        graph_viz_topic = utils.getParamOrFail(
            "/obstacle_avoidance/graph_viz_topic")
        path_viz_topic = utils.getParamOrFail(
            "/obstacle_avoidance/path_viz_topic")
        goal_line_viz_topic = utils.getParamOrFail(
            "/obstacle_avoidance/goal_line_viz_topic")
        self.graph_pub = rospy.Publisher(graph_viz_topic,
                                         Marker,
                                         queue_size=10,
                                         latch=True)
        self.path_pub = rospy.Publisher(path_viz_topic,
                                        Marker,
                                        queue_size=10,
                                        latch=True)
        self.goal_line_pub = rospy.Publisher(goal_line_viz_topic,
                                             Marker,
                                             queue_size=3,
                                             latch=True)

        # Data structure and publisher for the waypoints (PolygonStamped).
        self.line_trajectory = utils.LineTrajectory(
            viz_namespace='visualization')
        waypoint_topic = utils.getParamOrFail(
            "/obstacle_avoidance/trajectory_topic")
        self.waypoint_pub = rospy.Publisher(waypoint_topic,
                                            PolygonStamped,
                                            queue_size=10,
                                            latch=True)

        # Listen on /clicked_point for goal points.
        # This will execute a plan from the current pose to specified goal.
        self.clicked_point_sub = rospy.Subscriber("/clicked_point",
                                                  PointStamped,
                                                  self.clicked_point,
                                                  queue_size=10)

        # Stores a list of points for collision checking.
        # self.trajectory_plc = plc.Point2fList()
        self.trajectory_list = []
        self.current_trajectory_cost = None

        # Listen on /initialpose for start and goal poses.
        self.clicked_pose_sub = rospy.Subscriber("/initialpose",
                                                 PoseWithCovarianceStamped,
                                                 self.clicked_pose,
                                                 queue_size=10)

        self.pose_update_sub = rospy.Subscriber(
            utils.getParamOrFail("obstacle_avoidance/localization_topic"),
            PoseStamped,
            self.localization_cb,
            queue_size=1)

        # Setup occupancy grid.
        # self.local_grid_sub = rospy.Subscriber(
        #     utils.getParamOrFail("obstacle_avoidance/local_map_topic"), OGMSG, self.local_map_cb, queue_size=5
        # )

        self.occupancy_grid_sub = rospy.Subscriber(
            utils.getParamOrFail("obstacle_avoidance/dilated_map_topic"),
            OGMSG,
            self.occupancy_grid_cb,
            queue_size=1)

        self.occupancy_grid_msg = self.get_static_map(
        )  # Blocks until static map received.
        # self.occupancy_grid = plc.OccupancyGrid(self.occupancy_grid_msg)
        self.occupancy_grid = OccupancyGrid(self.occupancy_grid_msg)

        self.occupancy_grid.dilateOccupancyGrid(0.2, True)

        # Store state: (x, y, theta).
        self.previous_pose = None
        self.current_pose = None
        self.goal_point = None  # Set by the clicked point callback.

        rospy.loginfo("Initialized Primitive Planner node!")
class Primitive_Planner:
    # Primitive_Planner static params.
    MAX_TURN = utils.getParamOrFail(
        "/obstacle_avoidance/primitive_planner/max_turn_to_divide")
    NUM_TURN_DIVISIONS = utils.getParamOrFail(
        "/obstacle_avoidance/primitive_planner/num_turn_divisions")
    TURNING_RADIUS = utils.getParamOrFail(
        "/obstacle_avoidance/primitive_planner/turning_radius")
    SAMPLING_RATE = utils.getParamOrFail(
        "/obstacle_avoidance/primitive_planner/sampling_rate")
    MAX_TURN_POSSIBLE = utils.getParamOrFail(
        "/obstacle_avoidance/primitive_planner/max_turn_possible")
    MAX_TURN_TOTAL_TIME = utils.getParamOrFail(
        "/obstacle_avoidance/primitive_planner/max_turn_total_time")

    def __init__(self):

        # Build list of turn primitives.
        assert self.NUM_TURN_DIVISIONS % 2 == 1
        turn_angles = np.linspace(-self.MAX_TURN, self.MAX_TURN,
                                  self.NUM_TURN_DIVISIONS)
        np.testing.assert_almost_equal(
            turn_angles[self.NUM_TURN_DIVISIONS / 2], 0.0)
        turn_angles = sorted(turn_angles, key=lambda x: math.fabs(x))
        rospy.loginfo("Making turn angles: {}".format(turn_angles))
        self.primitives = [Turn_Primitive(angle) for angle in turn_angles]
        self.primitives.extend([
            Turn_Primitive(a * self.MAX_TURN_POSSIBLE,
                           total_time=self.MAX_TURN_TOTAL_TIME)
            for a in [1, -1]
        ])

        # Setup visualization publishers - latch them for easier debugging.
        self.display_tree = []
        self.display_path = []
        graph_viz_topic = utils.getParamOrFail(
            "/obstacle_avoidance/graph_viz_topic")
        path_viz_topic = utils.getParamOrFail(
            "/obstacle_avoidance/path_viz_topic")
        goal_line_viz_topic = utils.getParamOrFail(
            "/obstacle_avoidance/goal_line_viz_topic")
        self.graph_pub = rospy.Publisher(graph_viz_topic,
                                         Marker,
                                         queue_size=10,
                                         latch=True)
        self.path_pub = rospy.Publisher(path_viz_topic,
                                        Marker,
                                        queue_size=10,
                                        latch=True)
        self.goal_line_pub = rospy.Publisher(goal_line_viz_topic,
                                             Marker,
                                             queue_size=3,
                                             latch=True)

        # Data structure and publisher for the waypoints (PolygonStamped).
        self.line_trajectory = utils.LineTrajectory(
            viz_namespace='visualization')
        waypoint_topic = utils.getParamOrFail(
            "/obstacle_avoidance/trajectory_topic")
        self.waypoint_pub = rospy.Publisher(waypoint_topic,
                                            PolygonStamped,
                                            queue_size=10,
                                            latch=True)

        # Listen on /clicked_point for goal points.
        # This will execute a plan from the current pose to specified goal.
        self.clicked_point_sub = rospy.Subscriber("/clicked_point",
                                                  PointStamped,
                                                  self.clicked_point,
                                                  queue_size=10)

        # Stores a list of points for collision checking.
        # self.trajectory_plc = plc.Point2fList()
        self.trajectory_list = []
        self.current_trajectory_cost = None

        # Listen on /initialpose for start and goal poses.
        self.clicked_pose_sub = rospy.Subscriber("/initialpose",
                                                 PoseWithCovarianceStamped,
                                                 self.clicked_pose,
                                                 queue_size=10)

        self.pose_update_sub = rospy.Subscriber(
            utils.getParamOrFail("obstacle_avoidance/localization_topic"),
            PoseStamped,
            self.localization_cb,
            queue_size=1)

        # Setup occupancy grid.
        # self.local_grid_sub = rospy.Subscriber(
        #     utils.getParamOrFail("obstacle_avoidance/local_map_topic"), OGMSG, self.local_map_cb, queue_size=5
        # )

        self.occupancy_grid_sub = rospy.Subscriber(
            utils.getParamOrFail("obstacle_avoidance/dilated_map_topic"),
            OGMSG,
            self.occupancy_grid_cb,
            queue_size=1)

        self.occupancy_grid_msg = self.get_static_map(
        )  # Blocks until static map received.
        # self.occupancy_grid = plc.OccupancyGrid(self.occupancy_grid_msg)
        self.occupancy_grid = OccupancyGrid(self.occupancy_grid_msg)

        self.occupancy_grid.dilateOccupancyGrid(0.2, True)

        # Store state: (x, y, theta).
        self.previous_pose = None
        self.current_pose = None
        self.goal_point = None  # Set by the clicked point callback.

        rospy.loginfo("Initialized Primitive Planner node!")

    def localization_cb(self, msg):
        """
        Called every time a new pose estimate is received.
        """
        self.current_pose = (float(msg.pose.position.x),
                             float(msg.pose.position.y),
                             utils.quaternion_to_angle(msg.pose.orientation))

    def update_path(self, path_pt_1, path_pt_2):
        """
        Send a new path of waypoints to the controller (as PolygonStamped), and
        publish a visualization of the path.
        """
        rospy.loginfo('Updating path!')

        # Reset the trajectories for publishing and collision checking.
        self.line_trajectory.clear()
        # self.trajectory_plc = plc.Point2fList()
        self.trajectory_list

        for node in path_pt_1:
            for x, y, theta in node.poses:
                pt = plc.Point2f(x, y)
                self.line_trajectory.addPoint(pt)
                # self.trajectory_plc.append(pt)
                self.trajectory_list.append((x, y))
        for x, y, theta in path_pt_2:
            pt = plc.Point2f(x, y)
            self.line_trajectory.addPoint(pt)
            # self.trajectory_plc.append(pt)
            self.trajectory_list.append((x, y))

        # Send new path to controller.
        self.waypoint_pub.publish(self.line_trajectory.toPolygon())

        # Visualize the controller's new path.
        color = [0.2, 0.3, 1.0]
        marker = Marker()
        marker.header = utils.make_header("/map")
        marker.id = 106
        marker.type = 5  # Line list.
        marker.lifetime = rospy.Duration(0)  # Stay forever.
        marker.action = 0  # Add/update.
        marker.scale.x = 0.1
        marker.color.r = color[0]
        marker.color.g = color[1]
        marker.color.b = color[2]
        marker.color.a = 0.5
        for ii in range(len(self.line_trajectory.points) - 1):
            marker.points.append(
                Point32(self.line_trajectory.points[ii][0],
                        self.line_trajectory.points[ii][1], 0.0))
            marker.points.append(
                Point32(self.line_trajectory.points[ii + 1][0],
                        self.line_trajectory.points[ii + 1][1], 0.0))
        self.path_pub.publish(marker)

    def occupancy_grid_cb(self, msg, debug=False):  #local_map_cb(self, msg):
        """
        Called every time a new local map is received. Updates the occupancy grid and replans
        if the current path results in a collision.
        """
        # # Need a pose to transform local map into world map frame.
        # if (self.current_pose is not None):
        #     self.occupancy_grid.dynamicUpdate(msg, self.current_pose[0], self.current_pose[1], self.current_pose[2])
        # time.sleep(0.2)

        self.occupancy_grid_msg = msg
        # self.occupancy_grid = plc.OccupancyGrid(self.occupancy_grid_msg)
        self.occupancy_grid.setGridData(self.occupancy_grid_msg.data)

        if debug:
            pub = rospy.Publisher('/debugdebug', OGMSG, queue_size=5)
            pub.publish(self.occupancy_grid.getOccupancyGridMsg())

    def main(self):
        """
        Replans at a given frequency.
        """
        target_rate = 20
        target_time = 1.0 / target_rate
        starttime = time.time()

        while not rospy.is_shutdown():
            # Replan at every map update (after goal set) to see if a better path can be found.
            if (self.goal_point is not None):
                starttime = time.time()
                success, path_pt_1, path_pt_2, path_cost = self.plan_path(
                    self.current_pose, self.goal_point, visualize=True)
                rospy.loginfo('Planned for %f sec' % (time.time() - starttime))
                rospy.loginfo('Success: %d', success)

            # Publish the new path if (1) none has been found yet, (2) it improves cost
            # or (3) the current path causes a collision. Don't plan unless a goal point has
            # been clicked.
            if (self.goal_point is not None) and success:
                shouldUpdatePath = (
                    (self.current_trajectory_cost is None)
                    or ((self.current_trajectory_cost - path_cost) > 1.0) or
                    # self.occupancy_grid.pathOccupiedVectPoint2f(self.trajectory_plc)
                    self.occupancy_grid.pathOccupied(self.trajectory_list))

                isNone = (self.current_trajectory_cost is None)
                pathDiff = float('-inf') if isNone else (
                    self.current_trajectory_cost - path_cost)
                isShorter = (pathDiff > 5.0)
                # isOccupied = self.occupancy_grid.pathOccupiedVectPoint2f(self.trajectory_plc)
                isOccupied = self.occupancy_grid.pathOccupied(
                    self.trajectory_list)

                print("isNone:", isNone, "pathDiff:", pathDiff, "isShorter:",
                      isShorter, "isOccupied:", isOccupied)

                if shouldUpdatePath:
                    rospy.loginfo('Sending a new path to the controller!')
                    self.current_trajectory_cost = path_cost
                    self.update_path(path_pt_1, path_pt_2)

            sleeptime = target_time - (time.time() - starttime)
            time.sleep(0 if sleeptime < 0 else
                       sleeptime)  # Sleep long enough to hit target rate.

    def get_static_map(self):
        """
        Blocks until a map is received on the ~static_map service.
        Returns: a ROS Occupancy Grid message.
        """
        map_service_name = rospy.get_param("~static_map", "static_map")
        rospy.loginfo("Getting map from service: %s.", map_service_name)
        rospy.wait_for_service(map_service_name)
        map_msg = rospy.ServiceProxy(map_service_name, GetMap)().map
        return map_msg

    def clicked_pose(self, msg):
        self.previous_pose = self.current_pose
        self.current_pose = (msg.pose.pose.position.x,
                             msg.pose.pose.position.y,
                             utils.quaternion_to_angle(
                                 msg.pose.pose.orientation))
        rospy.loginfo('Current pose: %f %f %f' % self.current_pose)

    def clicked_point(self, msg):
        """
        Callback for /clicked_point from RViz. This will update the goal to be
        the (x,y) location of the click.
        """
        self.goal_point = (msg.point.x, msg.point.y, 0.0)
        self.current_trajectory_cost = None  # Mark that no trajectory has been found yet!

        goalVect = np.array([
            self.goal_point[0] - self.current_pose[0],
            self.goal_point[1] - self.current_pose[1]
        ])
        goalVect = goalVect / utils.norm(goalVect[0],
                                         goalVect[1])  # Unit vector.
        normal = (-1 * goalVect[1], goalVect[0])

        scale = 100
        endpoints = [(self.goal_point[0] + scale * normal[0],
                      self.goal_point[1] + scale * normal[1]),
                     (self.goal_point[0] - scale * normal[0],
                      self.goal_point[1] - scale * normal[1])]
        marker = Marker()
        marker.header = utils.make_header("/map")
        marker.id = 104
        marker.type = 5  # Line List.
        marker.lifetime = rospy.Duration(0)
        marker.scale.x = 0.1
        marker.action = 0  # Add/update.
        marker.color.g = 1.0
        marker.color.a = 1.0
        marker.points = [Point(pt[0], pt[1], 0) for pt in endpoints]
        self.goal_line_pub.publish(marker)

        rospy.loginfo('Updated goal point: %f %f %f' % self.goal_point)

    def update_occupancy_grid(self, grid):
        self.occupancy_grid = grid

    def plan_path(self, start_pose, goal_x, visualize=True):
        start_x, start_y, start_theta = start_pose

        root = AnyNode(start_pose=None,
                       poses=[],
                       end_pose=start_pose,
                       cost=0.,
                       discovered=False)
        success, (tree_leaf, dubins_path), cost = self.BFS(root,
                                                           self.goal_point,
                                                           visualize=visualize)

        if success:
            return success, tree_leaf.path, dubins_path, cost
        else:
            print 'Planning failed'
            return False, None, None, None

    def generate_and_check_dubins_curve(self, start, goal):
        # shortest_path returns a tuple of sampled poses and cumulative distances
        path, dists = dubins.shortest_path(
            start, goal, self.TURNING_RADIUS).sample_many(self.SAMPLING_RATE)
        total_dist = dists[-1]
        # path_plc = plc.Point2fList()
        # for x, y, theta in path:
        #     path_plc.append(plc.Point2f(x, y))
        # path_is_occupied = self.occupancy_grid.pathOccupiedVectPoint2f(path_plc)
        path_is_occupied = self.occupancy_grid.pathOccupied(path)

        if path_is_occupied:
            return None, None

        return path, total_dist

    def generate_children(self, node, visualize):
        children = []
        for i, primitive in enumerate(self.primitives):
            new_pose, new_poses = primitive.apply(node.end_pose,
                                                  self.occupancy_grid)

            if new_pose is not None:  # If this connection does not collide.
                children.append(
                    AnyNode(start_pose=node.end_pose,
                            poses=new_poses,
                            end_pose=new_pose,
                            primitive=primitive,
                            primitive_num=i,
                            cost=node.cost + primitive.TOTAL_TIME,
                            discovered=False,
                            parent=node))
                if visualize:
                    for p1, p2 in zip(new_poses, new_poses[1:]):
                        self.display_tree.extend([p1, p2])

        # TODO maybe choose children ordering according to a heuristic
        if visualize:
            self.visualize()
        return children

    def goal_line_check(self, test_pose, start_pt, goal_pt):
        """
        Tests whether the test pose is past the goal line, which is defined as the
        line passing through goal_pt that is perpendicular to the vector from start
        to goal.
        """
        goalVect = (goal_pt[0] - start_pt[0], goal_pt[1] - start_pt[1])
        testVect = (test_pose[0] - start_pt[0], test_pose[1] - start_pt[1])
        progVect = (testVect[0] - goalVect[0], testVect[1] - goalVect[1])
        progress = progVect[0] * goalVect[0] + progVect[1] * goalVect[1]
        return (progress > 0 or utils.distance(test_pose[0:2], goal_pt) < 0.1)

    def BFS(self, root, goal_pt, visualize=False, with_dubins=False):
        self.display_tree = []

        # Store nodes in a min heap.
        heap = [(root.end_pose[0], root)]

        starttime = time.time()
        timeout = 1.0

        while len(heap) != 0 and (time.time() - starttime) < timeout:

            # Gets the node with LOWEST cost.
            _, node = heapq.heappop(heap)
            if not node.discovered:  # This check is probably unnecessary.

                # If feasible path exists from this point onwards, returns goal = (goal_x, node.end_pose[1], 0.).
                if with_dubins:
                    dubins_path, path_length = self.generate_and_check_dubins_curve(
                        node.end_pose, goal_pt)
                    if dubins_path is not None:
                        if visualize:
                            for p1, p2 in zip(dubins_path, dubins_path[1:]):
                                self.display_tree.extend([p1, p2])
                            self.visualize()  # Show the tree.
                        return True, (node,
                                      dubins_path), path_length + node.cost

                # Alternatively, if the pose has passed the goal line, return success.
                if self.goal_line_check(node.end_pose, self.current_pose,
                                        goal_pt):
                    return True, (node, []), node.cost

                node.discovered = True
                for child in self.generate_children(node, visualize=visualize):
                    dist_to_goal = utils.distance(
                        child.end_pose,
                        goal_pt)  # Cost = euclidean distance to goal.
                    heapq.heappush(heap, (dist_to_goal, child))

        if (time.time() - starttime) >= timeout:
            print 'Timed out'
            _, node = heapq.heappop(heap)
            return True, (node, []), node.cost

        # Ran out nodes to try.
        print 'Ran out of nodes'
        return False, (None, None), None

    def DFS(self, root, goal):
        # self.visualize()
        print "DFS level"
        root.discovered = True
        # if feasible path exists from this point onwards, returns
        dubins_path, path_lengths = self.generate_and_check_dubins_curve(
            root.end_pose, goal)
        if dubins_path is not None:
            print "Path to goal found"
            for p1, p2 in zip(dubins_path, dubins_path[1:]):
                self.display_tree.extend([p1, p2])
            self.visualize()
            return True, (root, dubins_path)

        for child in self.generate_children(root):
            if not child.discovered:
                done, answer = self.DFS(child, goal)
                if done:
                    return answer

        return False, (None, None)

    def visualize(self, duration=0.0, should_publish=True):
        """
        Display the tree.
        """
        red, green = (1., 0., 0.), (0., 1., 0.)
        for (pub, linelist, color) in [(self.graph_pub, self.display_tree, red)
                                       ]:
            # (self.path_pub, self.display_path, green)]:
            marker = Marker()
            marker.header = utils.make_header("/map")
            marker.ns = 'visualization' + "/trajectory"
            marker.id = 101
            marker.type = 5  # Line list.
            marker.lifetime = rospy.Duration.from_sec(duration)
            if should_publish:
                marker.action = 0
                marker.scale.x = 0.1
                marker.scale.y = 0.1
                marker.scale.z = 0.1
                marker.color.r = color[0]  #1.0
                marker.color.g = color[1]  #0.0
                marker.color.b = color[2]  #0.0
                marker.color.a = 0.5

                for p in linelist:
                    pt = Point32(p[0], p[1], 0)
                    marker.points.append(pt)
            else:
                marker.action = 2

            pub.publish(marker)
示例#16
0
def controller(self):
    try:
        #TODO: get correct topic to publish to
        pub = rospy.Publisher("/cmd_vel_mux/input/navi", Twist, queue_size=10)
        tf_buffer = tf2_ros.Buffer()
        tf_listener = tf2_ros.TransformListener(tf_buffer)
        time.sleep(1)
        vel_msg = Twist()

    except (rospy.ROSInterruptException, tf2_ros.LookupException,
            tf2_ros.ConnectivityException, tf2_ros.ExtrapolationException):
        rospy.loginfo("")

    r = rospy.Rate(20)

    occupancy_grid = OccupancyGrid()
    occupancy_grid.Initialize()

    grids_traversed = []
    rot_angle = 0.5 * math.pi

    while not rospy.is_shutdown():
        try:
            tb_tf_pos = tf_buffer.lookup_transform("world", "tb",
                                                   rospy.Time(0))
            tb_pos = np.array([
                tb_tf_pos.transform.translation.x,
                tb_tf_pos.transform.translation.y
            ])
            tb_grid = occupancy_grid.getGrid(
                tb_pos)  # tb grid number [x y] from occupancy_grid
            tb_grid = tb_grid.tolist()

        except (rospy.ROSInterruptException, tf2_ros.LookupException,
                tf2_ros.ConnectivityException, tf2_ros.ExtrapolationException):
            rospy.loginfo("")

        except Exception as e:
            print(e)

        if len(grids_traversed) == 5:
            current_angle = 0

            vel_msg.linear.x = 0
            vel_msg.linear.y = 0
            vel_msg.linear.z = 0
            vel_msg.angular.x = 0
            vel_msg.angular.y = 0
            vel_msg.angular.z = 1
            t0 = rospy.Time.now().to_sec()
            while (current_angle < rot_angle):
                pub.publish(vel_msg)
                t1 = rospy.Time.now().to_sec()
                current_angle = t1 - t0

            vel_msg.angular.z = 0  #stop rotation
            pub.publish(vel_msg)
            del grids_traversed[:]

        elif tb_grid in grids_traversed:
            vel_msg.linear.x = 0.5
            vel_msg.linear.y = 0
            vel_msg.linear.z = 0
            vel_msg.angular.x = 0
            vel_msg.angular.y = 0
            vel_msg.angular.z = 0
            pub.publish(vel_msg)

        else:
            grids_traversed.append(tb_grid)
            vel_msg.linear.x = 0.5
            vel_msg.linear.y = 0
            vel_msg.linear.z = 0
            vel_msg.angular.x = 0
            vel_msg.angular.y = 0
            vel_msg.angular.z = 0
            pub.publish(vel_msg)