示例#1
0
class SLAM:
    def __init__(self):
        # GLOBAL VARIABLES
        self.P = np.eye(4)  # Pose

        self.k = np.array(
            [[640.0, 0, 640.0], [0, 480.0, 480.0], [0, 0, 1.0]],
            dtype=np.float32,
        )
        # ahmed dataset
        # self.k = np.array(
        #     [[827.0, 0.0, 638.0], [0.0, 826.0, 347], [0.0000, 0.0000, 1.0000]],
        #     dtype=np.float32,
        # )

        self.poses = [[0.0, 0.0, np.pi / 2]]  # initial pose
        self.trajectory = [np.array([0, 0, 0])]  # 3d trajectory
        self.tMats = [(np.zeros((3, 3)), np.zeros(
            (3, 1)))]  # Transformation Matrices (rmat, tvec)
        self.env_map = Map(62, 62)
        self._create_map(self.env_map)
        self.particle_filter = Localization(self.env_map)

    def _create_map(self, env_map):
        # store landmarks
        landmark_imgs = glob.glob("./train/*.jpg")
        crd = [(0, 62), (62, 62)]  # coordinates
        for idx, img in enumerate(landmark_imgs):
            img = cv.imread(img)

            croppedImg, _ = applyTranformations(img)
            # gray = cv.cvtColor(croppedImg, cv.COLOR_BGR2GRAY)
            # print(croppedImg.shape)
            kp, des = orb_extractor(croppedImg)
            env_map.add_landmark(
                Landmark(crd[idx][0], crd[idx][1], kp, des, 12))

    def process(self, images, depths, iterator):
        imgs_grey = [
            cv.cvtColor(images[0], cv.COLOR_BGR2GRAY),
            cv.cvtColor(images[1], cv.COLOR_BGR2GRAY),
        ]

        # Check if this frame should be dropped (blur/same)

        if drop_frame(imgs_grey):
            #print("Dropping the frame")
            print("Sharpening the frame")
            fm = cv.Laplacian(imgs_grey[1], cv.CV_64F).var()
            if fm < 40:
                kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
                im = cv.filter2D(imgs_grey[1], -1, kernel)  # sharp
                imgs_grey[1] = im

        # Part I. Features Extraction
        kp_list, des_list = extract_features(imgs_grey)

        # Part II. Feature Matching
        matches = match_features(des_list)
        is_main_filtered_m = True  # Filter matches
        if is_main_filtered_m:
            filtered_matches = filter_matches(matches)
            matches = filtered_matches

        # Removing Same frames
        smatches = sorted(matches, key=lambda x: x.distance)
        sdiff = sum([x.distance for x in smatches[:500]])
        if sdiff < 1000:
            print(f"\t->->Frame Filtered because isSame: {sdiff}")
            return

        # Part III. Trajectory Estimation
        # Essential Matrix or PNP
        # pnp_estimation || essential_matrix_estimation
        self.P, rmat, tvec = estimate_trajectory(matches, kp_list, self.k,
                                                 self.P, depths[1])
        # No motion estimation
        if np.isscalar(rmat):
            return
        # Compare same frame
        # prevRmat, prevTvec = self.tMats[-1]
        # if not np.allclose(rmat, prevRmat) and not np.allclose(tvec, prevTvec):
        self.tMats.append((rmat, tvec))
        new_trajectory = self.P[:3, 3]
        self.trajectory.append(new_trajectory * 2.95)
        self.poses.append(calc_robot_pose(self.P[:3, :3], self.P[:, 3] * 2.95))
        # else:
        #     print(f"\t->Frame Filtered because same TMat")
        #     return

        # Part IV. Localize
        last_pose = self.poses[-1]
        second_last_pose = self.poses[-2]
        print(f"Odometry:\n\t{[second_last_pose, last_pose]}")
        self.particle_filter.motion_update([second_last_pose, last_pose])
        if iterator % 5 == 0:
            print(">>>>> Updating Measurement")
            self.particle_filter.measurement_update(images[1], kp_list[1],
                                                    des_list[1], iterator)
            self.particle_filter.sample_particles()

        # Part V. Save Visualization plot
        visualize_data(self.env_map.plot_map, showPlot=False)
        visualize_data(
            self.particle_filter.plot_particles,
            clean_start=False,
            showPlot=False,
            figName=f"frame{iterator}",
        )

        # plt.cla()
        # npTraj = np.array(self.trajectory).T
        # visualize_trajectory(npTraj)
        # plt.savefig(f'dataviz/frame{iterator}.png')

    def get_trajectory(self):
        return np.array(self.trajectory).T

    def get_robot_poses(self):
        return self.poses
示例#2
0
class Robot:
    def __init__(self, map, display):

        # environment inits
        self.landmarks = map["landmarks"]
        self.goals = map["goals"]
        self.currentGoal = 0
        self.currentPos = map["initial_position"]
        self.currentAngle = map["initial_angle"]

        self.num_particles = map["num_particles"]

        self.dist_per_frame = map["distance_per_frame"]
        self.rot_per_frame = math.radians(map["rotation_per_frame"])

        # noise stds
        self.move_std = map["noise"]["move_std"]
        self.rotate_std = map["noise"]["rotate_std"]

        # display init
        self.display = display
        self.cmd_msg = "Waiting for commands..."

        # localization
        self.localization = Localization(self.num_particles,
                                         map["dimensions"]["width"],
                                         map["dimensions"]["height"],
                                         map["noise"])

        #estimated positions
        self.estimatedPos, self.estimatedAngle = self.localization.estimate_position(
        )

    def move(self, distance):
        frames = int(distance / self.dist_per_frame)

        # movement to the calculated point
        for i in range(frames):
            # error is added at each frame
            dist_with_noise = self.dist_per_frame + np.random.randn(
            ) * self.move_std

            incx = math.cos(self.currentAngle) * dist_with_noise
            incy = math.sin(self.currentAngle) * dist_with_noise

            # motion update (robot and particles)
            self.currentPos = [
                self.currentPos[0] + incx, self.currentPos[1] + incy
            ]
            self.localization.motion_update(self.dist_per_frame, 0)
            self.estimatedPos, self.estimatedAngle = self.localization.estimate_position(
            )

            self.display.drawFrame(self)

        # sense and update
        self.localization.sensor_update(self.landmarks, self.currentPos,
                                        self.currentAngle)
        self.localization.resample()

        # estimate position
        self.estimatedPos, self.estimatedAngle = self.localization.estimate_position(
        )

    def rotate(self, angle):
        # calculate difference and direction of rotation
        if angle > self.estimatedAngle:
            if angle - self.estimatedAngle <= math.pi:
                dif_angle = angle - self.estimatedAngle
                dir_rot = 1
            else:
                dif_angle = 2 * math.pi - (angle - self.estimatedAngle)
                dir_rot = -1
        else:
            if self.estimatedAngle - angle <= math.pi:
                dif_angle = self.estimatedAngle - angle
                dir_rot = -1
            else:
                dif_angle = 2 * math.pi - (self.estimatedAngle - angle)
                dir_rot = 1

        frames = int(dif_angle / self.rot_per_frame)

        # rotation to calculated angle
        for i in range(frames):
            # add noise
            rot_with_noise = self.rot_per_frame + np.random.randn(
            ) * self.rotate_std

            # motion update
            self.currentAngle = self.currentAngle + rot_with_noise * dir_rot
            if self.currentAngle < 0:
                self.currentAngle = self.currentAngle + math.pi * 2
            if self.currentAngle >= math.pi * 2:
                self.currentAngle = self.currentAngle - math.pi * 2

            self.localization.motion_update(0, self.rot_per_frame * dir_rot)
            self.estimatedPos, self.estimatedAngle = self.localization.estimate_position(
            )

            self.display.drawFrame(self)

        # sense and update
        self.localization.sensor_update(self.landmarks, self.currentPos,
                                        self.currentAngle)
        self.localization.resample()

        # estimate position
        self.estimatedPos, self.estimatedAngle = self.localization.estimate_position(
        )

    def random_moves(self):
        self.cmd_msg = "Taking random moves..."

        rand_rot = np.random.uniform(0, 2 * math.pi)
        rand_dist = np.random.uniform(0, 100)
        self.rotate(rand_rot)
        self.move(rand_dist)

    # main execution loop
    def begin(self):

        while len(self.goals) > self.currentGoal:

            self.display.drawFrame(self)

            # check position
            difx = self.goals[self.currentGoal][0] - self.estimatedPos[0]
            dify = self.goals[self.currentGoal][1] - self.estimatedPos[1]

            if abs(difx) < 10 and abs(dify) < 10:
                print("Position reached, rotate to plant")
                orientated = False

                # rotate to plant
                while not orientated:
                    # get angle of orientation to plant
                    difx = self.landmarks[
                        self.currentGoal][0] - self.estimatedPos[0]
                    dify = self.landmarks[
                        self.currentGoal][1] - self.estimatedPos[1]

                    if difx != 0:
                        angle = math.atan(dify / difx)
                    else:
                        if dify < 0:
                            angle = -math.pi / 2
                        else:
                            angle = -math.pi / 2

                    # normalize angle between 0 and 2*pi
                    if difx < 0:
                        angle = math.pi + angle
                    if angle < 0:
                        angle = angle + math.pi * 2

                    self.cmd_msg = "Rotating to plant..."
                    self.rotate(angle)

                    if abs(self.estimatedAngle - angle) < math.pi / 50:
                        orientated = True

                print("Goal reached! Take photo.")
                self.cmd_msg = "Taking photo..."
                self.currentGoal += 1
            else:
                print("Move to goal")

                # rotate to position
                if difx != 0:
                    angle = math.atan(dify / difx)
                else:
                    if dify < 0:
                        angle = -math.pi / 2
                    else:
                        angle = -math.pi / 2

                # normalize angle between 0 and 2*pi
                if difx < 0:
                    angle = math.pi + angle
                if angle < 0:
                    angle = angle + math.pi * 2

                self.cmd_msg = "Rotating to goal..."
                self.rotate(angle)

                # move to position
                distance = math.sqrt(difx**2 + dify**2)

                # cut long distances to avoid big decompensation with the estimated position
                if distance > 100:
                    distance = 100

                self.cmd_msg = "Moving to goal..."
                self.move(distance)

    def finish(self):
        self.cmd_msg = "All goals achieved!"

        # wait 50 frames before closing window
        for i in range(50):
            self.display.drawFrame(self)

        self.display.finish()