예제 #1
0
def newQuarticBezier(connectnode, targetnode, T, reverse=False):
    if reverse:
        end_acc = connectnode.next_traj.acc(0)

        p4 = connectnode.pos
        p3 = -T/4 * connectnode.vel + p4
        p2 = T**2/12 * end_acc + 2*p3 - p4
        p0 = targetnode.pos
        p1 = T/4 * targetnode.vel + p0

        # Ad-hoc fix?
        p2 = Vec3(p2.x, p2.y, (p0.z + p4.z) / 2)
    else:
        start_acc = connectnode.prev_traj.acc(connectnode.prev_traj.T)

        p0 = connectnode.pos
        p1 = T/4 * connectnode.vel + p0
        p2 = T**2/12 * start_acc + 2*p1 - p0
        p4 = targetnode.pos
        p3 = -T/4 * targetnode.vel + p4

        # Ad-hoc fix?
        p2 = Vec3(p2.x, p2.y, (p0.z + p4.z) / 2)

    return Bezier([p0, p1, p2, p3, p4], T)
예제 #2
0
    def create_waypoints(self, gates):
        # Get start pose from tf tree
        start_pose = newPoseStamped(0, 0, 0, 0, 0, 0, self.base_frame)
        start_pose = self.tf_buff.transform(start_pose, 'map',
                                            rospy.Duration(0.2))

        roll, pitch, yaw = euler_from_quaternion(
            (start_pose.pose.orientation.x, start_pose.pose.orientation.y,
             start_pose.pose.orientation.z, start_pose.pose.orientation.w))
        # Start creating waypoints
        start_wp = Waypoint('start', start_pose.pose.position.x,
                            start_pose.pose.position.y,
                            start_pose.pose.position.z, 0.0, 0.0, 0.0, yaw)

        # Waypoints in front of and after each gate
        waypoints = [start_wp]
        for gate in self.map.gates:
            before_wp, after_wp = self.gate_to_waypoints(gate)
            waypoints.extend([before_wp, after_wp])

        # Last waypoint 0.5 m after last gate
        yaw = self.map.gates[-1]['heading'] * math.pi / 180
        normal = Vec3(math.cos(yaw), math.sin(yaw), 0.0)
        pos = self.map.gates[-1]['position'] + 0.5 * normal
        vel = Vec3(0.0, 0.0, 0.0)
        last_wp = Waypoint('final', pos.x, pos.y, pos.z, vel.x, vel.y, vel.z,
                           0.0)
        waypoints.append(last_wp)

        return waypoints
예제 #3
0
def create_map(map_data, type='grid'):
    """Create map object dictionary map_dict."""

    # Access map parameters through ros
    coll_rad = rospy.get_param(rospy.get_namespace() +
                               'crazyflie/collision_radius')
    resolution = rospy.get_param(rospy.get_namespace() + 'map/resolution')
    off_ground = rospy.get_param(rospy.get_namespace() + 'map/gate_off_ground')
    side_margin = rospy.get_param(rospy.get_namespace() +
                                  'map/gate_side_margin')

    z_min = 0.2
    z_max = 1.0
    # airspace_min = Vec3(*map_data['airspace']['min'])
    airspace_min = Vec3(map_data['airspace']['min'][0],
                        map_data['airspace']['min'][1], z_min)
    # airspace_max = Vec3(*map_data['airspace']['max'])
    airspace_max = Vec3(map_data['airspace']['max'][0],
                        map_data['airspace']['max'][1], z_max)

    # Convert obstacle to point cloud with finer resolution than map representation
    points = set()
    for wall in map_data['walls']:
        points = points.union(
            plane_to_points(wall['plane'], resolution, coll_rad))
    for gate in map_data['gates']:
        points = points.union(
            gate_to_points(gate, resolution, coll_rad, map_data['gate_size'],
                           off_ground, side_margin, airspace_max.z))
    points = {
        point
        for point in points if (airspace_min <= point <= airspace_max)
    }

    # Adjust gate position to middle of gate for later convenience
    for gate in map_data['gates']:
        gate['width'] = map_data['gate_size'][0]
        gate['height'] = map_data['gate_size'][1]
        gate['position'] = Vec3(gate['position'][0], gate['position'][1],
                                off_ground + gate['height'] / 2)

    # Create map of specified by type
    if type == 'kd':
        map = Kdmap(points, map_data['gates'], map_data['markers'],
                    airspace_min, airspace_max, resolution)
    elif type == 'octo':
        map = Octomap(points, map_data['gates'], map_data['markers'],
                      airspace_min, airspace_max, resolution)
    else:
        map = Gridmap(points, map_data['gates'], map_data['markers'],
                      airspace_min, airspace_max, resolution)

    # Publish map shapes to rviz
    if rospy.get_param(rospy.get_name() + '/use_rviz'):
        publish_map_to_rviz(map, points)

    return map
예제 #4
0
    def set_yaw_gates(self, traj_msg, start_wp, traj):
        # Add yaw trajectory based on gates
        prev_yaw = (start_wp.yaw * 180 / math.pi) % 360
        i = 0
        # for gate in self.map.gates[]:
        for gate in self.map.gates[:-1]:
            wp1, wp2 = self.gate_to_waypoints(gate)

            # Loop until pre-gate waypoint
            pre_gate_pieces = []
            duration = 0
            while True:
                bezier = traj[i]
                piece = traj_msg.pieces[i]
                pre_gate_pieces.append(piece)
                duration += piece.duration.to_sec()
                i += 1

                wp_pos = Vec3(wp1.x, wp1.y, wp1.z)
                bz_pos = bezier.pos(-1)
                if wp_pos == bz_pos:
                    break

            # Calculate yawrate
            gate_yaw = gate['heading']
            if abs(gate_yaw - prev_yaw) <= 180:
                yawrate = (gate_yaw - prev_yaw) / duration
            else:
                yawrate = (360 + gate_yaw - prev_yaw) / duration

            # Turn yaw and yawrate into coefficients
            t = 0
            for piece in pre_gate_pieces:
                piece.poly_yaw[0] = prev_yaw + t * yawrate
                piece.poly_yaw[1] = yawrate
                t += piece.duration.to_sec()

            # Loop until post-gate waypoint
            t = 0
            while True:
                bezier = traj[i]
                piece = traj_msg.pieces[i]
                piece.poly_yaw[0] = gate_yaw
                t += piece.duration.to_sec()
                i += 1

                wp_pos = Vec3(wp2.x, wp2.y, wp2.z)
                bz_pos = bezier.pos(-1)
                if wp_pos == bz_pos:
                    break

            prev_yaw = gate_yaw

        # Set yaw values for after the last gate using escaped loop variables
        for piece in traj_msg.pieces[i - 1:]:
            piece.poly_yaw[0] = gate_yaw
예제 #5
0
    def get_gate_poses(self, gate):
        """Gets one pose before and one pose after gate."""
        theta = gate['heading'] * 2 * math.pi / 360
        normal = Vec3(math.cos(theta), math.sin(theta), 0.0)

        point1 = gate['position'] - self.wp_gate_dist * normal
        point2 = gate['position'] + self.wp_gate_dist * normal

        pose1 = PoseStamped()
        pose1.header.frame_id = 'map'
        (pose1.pose.position.x, pose1.pose.position.y,
         pose1.pose.position.z) = point1.x, point1.y, point1.z
        (pose1.pose.orientation.x, pose1.pose.orientation.y,
         pose1.pose.orientation.z,
         pose1.pose.orientation.w) = quaternion_from_euler(0.0, 0.0, theta)

        pose2 = PoseStamped()
        pose2.header.frame_id = 'map'
        (pose2.pose.position.x, pose2.pose.position.y,
         pose2.pose.position.z) = point2.x, point2.y, point2.z
        (pose2.pose.orientation.x, pose2.pose.orientation.y,
         pose2.pose.orientation.z,
         pose2.pose.orientation.w) = quaternion_from_euler(0.0, 0.0, theta)

        return [pose1, pose2]
예제 #6
0
    def goalnode_from_wp(wp):
        pos = Vec3(wp.x, wp.y, wp.z)
        vel = Vec3(wp.vx, wp.vy, wp.vz)
        acc = Vec3(0, 0, 0)

        T = 1
        p0 = pos
        p1 = T/2 * vel + p0
        p2 = T**2/2 * acc + 2*p1 - p0
        bezier = Bezier([p0, p1, p2], T)

        goalnode = RRTNode(pos, vel, wp.yaw)
        goalnode.set_next_link(None, bezier, update_cost=False)
        goalnode.cost_to_goal = 0

        return goalnode
예제 #7
0
    def startnode_from_wp(wp):
        pos = Vec3(wp.x, wp.y, wp.z)
        vel = Vec3(wp.vx, wp.vy, wp.vz)
        acc = Vec3(0, 0, 0)

        T = 1
        p2 = pos
        p1 = -T/2 * vel + p2
        p0 = T**2/2 * acc + 2*p1 - p2
        bezier = Bezier([p0, p1, p2], T)

        startnode = RRTNode(pos, vel, wp.yaw)
        startnode.set_prev_link(None, bezier, update_cost=False)
        startnode.cost = 0

        return startnode
예제 #8
0
    def __init__(self, min, max, points, resolution):
        self.min = min
        self.max = max
        self.isleaf = False
        self.isfree = False
        self.isoccupied = False
        self.low_tree = None
        self.high_tree = None

        diag = self.max - self.min

        # No points, then we are done
        if not points:
            self.isleaf = True
            self.isfree = True
            return
        # Check if all dimensions are smaller than resolution
        elif diag <= Vec3(resolution, resolution, resolution):
            self.isleaf = True
            self.isoccupied = True
            return

        # Not a leaf so we have to actually do something
        (self.split_dim, self.split_value, low_points,
         high_points) = self.find_split(points, resolution)

        low_min = Vec3(*self.min)
        low_max_values = [self.max.x, self.max.y, self.max.z]
        low_max_values[self.split_dim] = self.split_value
        low_max = Vec3(*low_max_values)
        self.low_tree = Kdtree(low_min, low_max, low_points, resolution)

        high_min_values = [self.min.x, self.min.y, self.min.z]
        high_min_values[self.split_dim] = self.split_value
        high_min = Vec3(*high_min_values)
        high_max = Vec3(*self.max)
        self.high_tree = Kdtree(high_min, high_max, high_points, resolution)

        # Remove subtrees if both turn out to be occupied
        if self.low_tree.isoccupied and self.high_tree.isoccupied:
            self.low_tree = None
            self.high_tree = None
            self.isleaf = True
            self.isoccupied = True

        return
예제 #9
0
    def find_subtree_centers(self, center, size):
        directions = [
            Vec3(1, 1, 1),
            Vec3(-1, 1, 1),
            Vec3(-1, -1, 1),
            Vec3(1, -1, 1),
            Vec3(1, 1, -1),
            Vec3(-1, 1, -1),
            Vec3(-1, -1, -1),
            Vec3(1, -1, -1)
        ]

        return [center + direct * size / 4 for direct in directions]
예제 #10
0
    def steer(self, connectnode, targetnode, reverse=False):

        # Change distance of target 
        diff = targetnode.pos - connectnode.pos
        dist = abs(diff)
        if dist > self.max_step_len:
            direction = diff / dist
            pos = connectnode.pos + self.max_step_len * direction
            if self.map.query([pos]):
                return
            targetnode = RRTNode(pos, targetnode.vel, targetnode.yaw)

        for T in np.linspace(self.min_step_time, self.max_step_time, num=11):
            if reverse:
                bezier = Bezier.newPenticBezier(
                        targetnode.pos,
                        targetnode.vel,
                        Vec3(0, 0, 0),
                        connectnode.pos,
                        connectnode.vel,
                        connectnode.acc,
                        T
                )
                if self.check_bezier(bezier):
                    targetnode.set_next_link(connectnode, bezier)
                    return targetnode
            else:
                bezier = Bezier.newPenticBezier(
                        connectnode.pos,
                        connectnode.vel,
                        connectnode.acc,
                        targetnode.pos,
                        targetnode.vel,
                        Vec3(0, 0, 0),
                        T
                )
                if self.check_bezier(bezier):
                    targetnode.set_prev_link(connectnode, bezier)
                    return targetnode
        
        return
예제 #11
0
def gate_to_points(gate, resolution, coll_rad, gate_size, off_ground,
                   side_margin, z_max):
    gate_width = gate_size[0]
    gate_height = gate_size[1]

    mid = Vec3(*gate['position'])

    theta = gate['heading'] * 2 * math.pi / 360
    normal = Vec3(math.cos(theta), math.sin(theta), 0.0)
    parallel = normal.cross(Vec3(0.0, 0.0, 1.0))

    # Create four planes to represent gate w.r.t. collision
    bottom_start = mid - parallel * (side_margin + gate_width / 2)
    bottom_stop = mid + parallel * (side_margin + gate_width / 2) + Vec3(
        0.0, 0.0, off_ground)
    bottom_plane = {'start': bottom_start, 'stop': bottom_stop}
    bottom_points = plane_to_points(bottom_plane, resolution, coll_rad)

    top_start = bottom_start + Vec3(0.0, 0.0, off_ground + gate_height)
    top_stop = bottom_stop + Vec3(0.0, 0.0, z_max - off_ground)
    top_plane = {'start': top_start, 'stop': top_stop}
    top_points = plane_to_points(top_plane, resolution, coll_rad)

    side1_start = mid - parallel * gate_width / 2 + Vec3(0.0, 0.0, off_ground)
    side1_stop = mid - parallel * (side_margin + gate_width / 2) + Vec3(
        0.0, 0.0, off_ground + gate_height)
    side1_plane = {'start': side1_start, 'stop': side1_stop}
    side1_points = plane_to_points(side1_plane, resolution, coll_rad)

    side2_start = mid + parallel * gate_width / 2 + Vec3(0.0, 0.0, off_ground)
    side2_stop = mid + parallel * (side_margin + gate_width / 2) + Vec3(
        0.0, 0.0, off_ground + gate_height)
    side2_plane = {'start': side2_start, 'stop': side2_stop}
    side2_points = plane_to_points(side2_plane, resolution, coll_rad)

    points = set()
    points = points.union(bottom_points)
    points = points.union(top_points)
    points = points.union(side1_points)
    points = points.union(side2_points)
    return points
예제 #12
0
def plane_to_points(plane, resolution, coll_rad):
    start = Vec3(*plane['start'])
    stop = Vec3(*plane['stop'])

    xyvec = Vec3(stop.x - start.x, stop.y - start.y,
                 0.0)  # Plane vector in (xy)-plane
    zvec = Vec3(0.0, 0.0, stop.z - start.z)  # Plane vector along (z)-axis
    cvec = zvec.cross(
        xyvec)  # Plane normal vector, used for (c)ollision map inflation

    xylen = abs(xyvec)
    zlen = abs(zvec)

    xyvec = xyvec.unit()
    zvec = zvec.unit()
    cvec = cvec.unit()

    nr_zsteps = round((zlen + 2 * coll_rad) / (resolution / 2) + 2)
    zlinspace = np.linspace(-coll_rad, zlen + coll_rad, nr_zsteps)

    nr_xysteps = round((xylen + 2 * coll_rad) / (resolution / 2) + 2)
    xylinspace = np.linspace(-coll_rad, xylen + coll_rad, nr_xysteps)

    nr_csteps = round(2 * coll_rad / (resolution / 2) + 2)
    clinspace = np.linspace(-coll_rad, coll_rad, nr_csteps)

    points = set()
    for z in zlinspace:
        zpart = z * zvec
        start_zpart = start + zpart
        for xy in xylinspace:
            xypart = xy * xyvec
            start_zxypart = start_zpart + xypart
            for c in clinspace:
                cpart = c * cvec
                point = start_zxypart + cpart
                points.add(point)

    return points
예제 #13
0
    def sample_configuration(self):

        # Sample position
        rand = np.random.rand(3)
        min = np.array(self.map.min)
        max = np.array(self.map.max)
        pos = Vec3(*(rand*max + (1-rand)*min))
        while self.map.query([pos]):
            rand = np.random.rand(3)
            min = np.array(self.map.min)
            max = np.array(self.map.max)
            pos = Vec3(*(rand*max + (1-rand)*min))

        # Sample velocity
        vel = Vec3(*(np.random.rand(3)))
        while abs(vel) > 1:
            vel = Vec3(*(np.random.rand(3)))
        vel *= self.vel_max
        
        # "Sample" yaw
        #yaw = np.random.rand() * 2*math.pi
        yaw = 0.0

        return RRTNode(pos, vel, yaw)
예제 #14
0
    def gate_to_waypoints(self, gate):
        yaw = gate['heading'] * math.pi / 180
        normal = Vec3(math.cos(yaw), math.sin(yaw), 0.0)

        pre_pos = gate['position'] - self.wp_pre_gate_dist * normal
        post_pos = gate['position'] + self.wp_post_gate_dist * normal

        pre_vel = self.wp_gate_vel * normal
        post_vel = self.wp_gate_vel * normal

        pre_id = 'pre_gate_{}'.format(gate['id'])
        post_id = 'post_gate_{}'.format(gate['id'])

        pre_wp = Waypoint(pre_id, pre_pos.x, pre_pos.y, pre_pos.z, pre_vel.x,
                          pre_vel.y, pre_vel.z, 0.0)
        post_wp = Waypoint(post_id, post_pos.x, post_pos.y, post_pos.z,
                           post_vel.x, post_vel.y, post_vel.z, 0.0)

        return pre_wp, post_wp
예제 #15
0
def gridmap_to_msgs(map, id_gen):
    marker = Marker()
    marker.header.frame_id = 'map'
    marker.ns = 'collision_cubes'
    marker.id = next(id_gen)
    marker.type = Marker.CUBE_LIST
    marker.action = Marker.ADD
    marker.color.r = 1.0
    marker.color.g = 0.0
    marker.color.b = 0.0
    marker.color.a = 1.0
    marker.scale.x = map.resolution
    marker.scale.y = map.resolution
    marker.scale.z = map.resolution
    marker.points = []
    for xi in range(map.shape[0]):
        for yi in range(map.shape[1]):
            for zi in range(map.shape[2]):
                if map.grid[xi, yi, zi]:
                    p = Vec3(xi + 0.5, yi + 0.5,
                             zi + 0.5) * map.resolution + map.origin
                    marker.points.append(Point(x=p.x, y=p.y, z=p.z))

    return [marker]
예제 #16
0
    def __init__(self,
                 center,
                 size,
                 points,
                 max_depth,
                 bound_min=None,
                 bound_max=None):
        self.center = center
        self.size = size
        self.isleaf = False
        self.isfree = False
        self.isoccupied = False
        self.subtrees = []

        if bound_min is None:
            bound_min = -Vec3(float('Inf'), float('Inf'), float('Inf'))
        if bound_max is None:
            bound_max = Vec3(float('Inf'), float('Inf'), float('Inf'))

        tree_max = center + Vec3(size / 2, size / 2, size / 2)
        tree_min = center - Vec3(size / 2, size / 2, size / 2)

        if (not points) and (tree_min >= bound_min) and (tree_max <=
                                                         bound_max):
            self.isleaf = True
            self.isfree = True
        elif max_depth == 0:
            self.isleaf = True
            self.isoccupied = True
        elif tree_max.x <= bound_min.x or tree_max.y <= bound_min.y or tree_max.z <= bound_min.z:
            self.isleaf = True
            self.isoccupied = True
        elif tree_min.x >= bound_max.x or tree_min.y >= bound_max.y or tree_min.z >= bound_max.z:
            self.isleaf = True
            self.isoccupied = True
        else:
            centers = self.find_subtree_centers(self.center, self.size)
            points_per_octant = self.split_by_octant(points, self.center)
            diagonal = Vec3(size / 4, size / 4, size / 4)

            # Generate subtrees
            for subcenter, subpoints in zip(centers, points_per_octant):
                sub_bound_min = bound_min
                sub_bound_max = bound_max
                if subcenter - diagonal >= bound_min:
                    sub_bound_min = None
                if subcenter + diagonal <= bound_max:
                    sub_bound_max = None

                self.subtrees.append(
                    Octree(subcenter, size / 2, subpoints, max_depth - 1,
                           sub_bound_min, sub_bound_max))

            # Remove subtrees if all turn out to be occupied
            for subtree in self.subtrees:
                if not subtree.isoccupied:
                    break
            else:
                self.isleaf = True
                self.isoccupied = True
                self.subtrees = []

        assert not (self.isfree and self.isoccupied)

        return