示例#1
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()