class Run:
    def __init__(self, factory):
        """Constructor.

        Args:
            factory (factory.FactoryCreate)
        """
        self.create = factory.create_create()
        self.time = factory.create_time_helper()
        self.servo = factory.create_servo()
        self.sonar = factory.create_sonar()
        # Add the IP-address of your computer here if you run on the robot
        self.virtual_create = factory.create_virtual_create()
        self.odometry = odometry.Odometry()
        self.particle_filter = ParticleFilter()

    def sense(self):
        dist = self.sonar.get_distance()
        self.particle_filter.sense(dist)
        return dist

    def turn(self, deltaTheta):
        start = self.odometry.theta
        s = np.sign(deltaTheta)
        self.create.drive_direct(s * 100, s * -100)
        goalStart = deltaTheta + self.odometry.theta
        goalEnd = deltaTheta + self.odometry.theta + s * np.pi / 12
        while True:
            theta = self.odometry.theta
            while s * theta < s * start:
                theta += s * 2 * np.pi
            if s * goalStart <= s * theta <= s * goalEnd:
                break
            self.update_odom()

        self.create.drive_direct(0, 0)
        self.particle_filter.turn(self.odometry.theta - start)

    def update_odom(self):
        state = self.create.update()
        if state is not None:
            self.odometry.update(state.leftEncoderCounts,
                                 state.rightEncoderCounts)
        self.time.sleep(.01)

    def forward(self, distance):
        start_x = self.odometry.x
        start_y = self.odometry.y
        dist_now = lambda: np.sqrt((start_x - self.odometry.x)**2 +
                                   (start_y - self.odometry.y)**2)
        s = np.sign(distance)
        self.create.drive_direct(s * 100, s * 100)
        while dist_now() < np.abs(distance):
            self.update_odom()
        self.create.drive_direct(0, 0)
        self.particle_filter.forward(dist_now())

    def run(self):
        self.create.start()
        self.create.safe()

        self.create.start_stream([
            create2.Sensor.LeftEncoderCounts,
            create2.Sensor.RightEncoderCounts,
        ])
        self.update_odom()

        self.particle_filter.draw(self.virtual_create)
        while True:
            b = self.virtual_create.get_last_button()
            if b == self.virtual_create.Button.MoveForward:
                print("Forward pressed!")
                self.forward(0.25)
            elif b == self.virtual_create.Button.TurnLeft:
                print("Turn Left pressed!")
                self.turn(np.pi / 6.)
            elif b == self.virtual_create.Button.TurnRight:
                print("Turn Right pressed!")
                self.turn(-np.pi / 6.)
            elif b == self.virtual_create.Button.Sense:
                self.sense()
                print("Sense pressed!")

            if b is not None:
                self.particle_filter.draw(self.virtual_create)

            self.time.sleep(0.01)
예제 #2
0
class Run:
    def __init__(self, factory):
        """Constructor.

        Args:
            factory (factory.FactoryCreate)
        """
        self.create = factory.create_create()
        self.time = factory.create_time_helper()
        self.servo = factory.create_servo()
        self.sonar = factory.create_sonar()
        # Add the IP-address of your computer here if you run on the robot
        self.virtual_create = factory.create_virtual_create()
        self.map = lab8_map.Map("lab8_map.json")

        self.odometry = Odometry()
        self.odometry.x = 1
        self.odometry.y = 0.5
        self.pidTheta = PIDController(300,
                                      5,
                                      50, [-10, 10], [-200, 200],
                                      is_angle=True)

        # constants
        self.base_speed = 100
        self.variance_sensor = 0.1
        self.variance_distance = 0.01
        self.variance_direction = 0.05
        self.world_width = 3.0  # the x
        self.world_height = 3.0  # the y
        self.travel_dist = 0.25
        self.min_dist_to_wall = self.travel_dist + 0.2
        self.min_dist_to_localize = 0.2
        self.min_theta_to_localize = math.pi / 4
        self.n_threshold = math.log(0.09)

        self.filter = ParticleFilter(self.virtual_create,
                                     self.variance_sensor,
                                     self.variance_distance,
                                     self.variance_direction,
                                     num_particles=100,
                                     world_width=self.world_width,
                                     world_height=self.world_height,
                                     input_map=self.map,
                                     n_threshold=self.n_threshold)

    def run(self):
        self.create.start()
        self.create.safe()

        # request sensors
        self.create.start_stream([
            create2.Sensor.LeftEncoderCounts,
            create2.Sensor.RightEncoderCounts,
        ])

        isLocalized = False
        angle_counter = 0

        # This is an example on how to detect that a button was pressed in V-REP
        while not isLocalized:
            self.draw_particles()

            # generate random num
            command = random.choice([c for c in Command])

            if command is Command.FORWARD:
                if self.sonar.get_distance() < self.min_dist_to_wall:
                    continue

                self.filter.move(0, self.travel_dist)

                # 100 mm/s = 0.1 m/s
                self.create.drive_direct(self.base_speed, self.base_speed)
                self.sleep(abs(self.travel_dist / 0.1))

                # stop
                self.create.drive_direct(0, 0)
            elif command is Command.TURN_LEFT:
                # turn_angle = math.pi / 2 + self.odometry.theta
                turn_angle = math.pi / 2 + angle_counter
                turn_angle %= 2 * math.pi
                angle_counter += math.pi / 2
                angle_counter %= 2 * math.pi

                self.filter.move(turn_angle, 0)

                # turn left by 90 degree
                self.go_to_angle(turn_angle)
            elif command is Command.TURN_RIGHT:
                # turn_angle = -math.pi / 2 + self.odometry.theta
                turn_angle = -math.pi / 2 + angle_counter
                turn_angle %= 2 * math.pi
                angle_counter -= math.pi / 2
                angle_counter %= 2 * math.pi

                self.filter.move(turn_angle, 0)

                # turn right by 90 degree
                self.go_to_angle(turn_angle)

            self.filter.sense(self.sonar.get_distance())

            # check if localized

            # distance between odometry and estimated positions
            dist_position_to_goal = math.sqrt(
                (self.odometry.x - self.filter.x)**2 +
                (self.odometry.y - self.filter.y)**2)
            diff_theta_to_goal = abs(self.odometry.theta - self.filter.theta)

            isLocalized = dist_position_to_goal < self.min_dist_to_localize and diff_theta_to_goal < self.min_theta_to_localize

    def go_to_angle(self, goal_theta):
        while abs(
                math.atan2(math.sin(goal_theta - self.odometry.theta),
                           math.cos(goal_theta - self.odometry.theta))) > 0.1:
            # print("Go TO: " + str(math.degrees(goal_theta)) + " " + str(math.degrees(self.odometry.theta)))
            output_theta = self.pidTheta.update(self.odometry.theta,
                                                goal_theta, self.time.time())
            self.create.drive_direct(int(+output_theta), int(-output_theta))
            self.sleep(0.01)

        self.create.drive_direct(0, 0)

    def sleep(self, time_in_sec):
        """Sleeps for the specified amount of time while keeping odometry up-to-date
        Args:
            time_in_sec (float): time to sleep in seconds
        """
        start = self.time.time()

        while True:
            state = self.create.update()
            if state is not None:
                self.odometry.update(state.leftEncoderCounts,
                                     state.rightEncoderCounts)
                # print("[{},{},{}]".format(self.odometry.x, self.odometry.y, math.degrees(self.odometry.theta)))
            t = self.time.time()
            if start + time_in_sec <= t:
                break

    def draw_particles(self):
        data = []

        # get position data from all particles
        for particle in self.filter.particles:
            data.extend([particle.x, particle.y, 0.1, particle.theta])

            # paint all particles in simulation
            self.virtual_create.set_point_cloud(data)
예제 #3
0
class Run:
    def __init__(self, factory):
        """Constructor.

        Args:
            factory (factory.FactoryCreate)
        """
        self.create = factory.create_create()
        self.time = factory.create_time_helper()
        self.servo = factory.create_servo()
        self.sonar = factory.create_sonar()
        # Add the IP-address of your computer here if you run on the robot
        self.virtual_create = factory.create_virtual_create()
        self.map = lab8_map.Map("lab8_map.json")

        self.odometry = Odometry()
        self.pidTheta = PIDController(300,
                                      5,
                                      50, [-10, 10], [-200, 200],
                                      is_angle=True)

        # constants
        self.base_speed = 100
        self.variance_sensor = 0.1
        self.variance_distance = 0.01
        self.variance_direction = 0.05
        self.world_width = 3.0  # the x
        self.world_height = 3.0  # the y

        self.filter = ParticleFilter(self.virtual_create,
                                     self.variance_sensor,
                                     self.variance_distance,
                                     self.variance_direction,
                                     num_particles=100,
                                     world_width=self.world_width,
                                     world_height=self.world_height)

    def run(self):
        # # This is an example on how to visualize the pose of our estimated position
        # # where our estimate is that the robot is at (x,y,z)=(0.5,0.5,0.1) with heading pi
        # self.virtual_create.set_pose((0.5, 0.5, 0.1), 0)
        #
        # # This is an example on how to show particles
        # # the format is x,y,z,theta,x,y,z,theta,...
        # data = [0.5, 0.5, 0.1, math.pi/2, 1.5, 1, 0.1, 0]
        # self.virtual_create.set_point_cloud(data)
        #
        # # This is an example on how to estimate the distance to a wall for the given
        # # map, assuming the robot is at (0, 0) and has heading math.pi
        # print(self.map.closest_distance((0.5,0.5), 0))
        #
        # # This is an example on how to detect that a button was pressed in V-REP
        # while True:
        #     b = self.virtual_create.get_last_button()
        #     if b == self.virtual_create.Button.MoveForward:
        #         print("Forward pressed!")
        #     elif b == self.virtual_create.Button.TurnLeft:
        #         print("Turn Left pressed!")
        #     elif b == self.virtual_create.Button.TurnRight:
        #         print("Turn Right pressed!")
        #     elif b == self.virtual_create.Button.Sense:
        #         print("Sense pressed!")
        #
        #     self.time.sleep(0.01)
        self.create.start()
        self.create.safe()

        # request sensors
        self.create.start_stream([
            create2.Sensor.LeftEncoderCounts,
            create2.Sensor.RightEncoderCounts,
        ])

        # This is an example on how to detect that a button was pressed in V-REP
        while True:
            self.draw_particles()

            b = self.virtual_create.get_last_button()
            if b == self.virtual_create.Button.MoveForward:
                self.filter.move(0, 0.5)

                # 100 mm/s = 0.1 m/s
                self.create.drive_direct(self.base_speed, self.base_speed)
                self.sleep(abs(0.5 / 0.1))

                # stop
                self.create.drive_direct(0, 0)
            elif b == self.virtual_create.Button.TurnLeft:
                turn_angle = math.pi / 2 + self.odometry.theta
                turn_angle %= 2 * math.pi

                self.filter.move(turn_angle, 0)

                # turn left by 90 degree
                self.go_to_angle(turn_angle)
            elif b == self.virtual_create.Button.TurnRight:
                turn_angle = -math.pi / 2 + self.odometry.theta
                turn_angle %= 2 * math.pi

                self.filter.move(turn_angle, 0)

                # turn right by 90 degree
                self.go_to_angle(turn_angle)
            elif b == self.virtual_create.Button.Sense:
                self.filter.sense(self.sonar.get_distance())

            self.sleep(0.01)

    def go_to_angle(self, goal_theta):
        while abs(
                math.atan2(math.sin(goal_theta - self.odometry.theta),
                           math.cos(goal_theta - self.odometry.theta))) > 0.01:
            print("Go TO: " + str(math.degrees(goal_theta)) + " " +
                  str(math.degrees(self.odometry.theta)))
            output_theta = self.pidTheta.update(self.odometry.theta,
                                                goal_theta, self.time.time())
            self.create.drive_direct(int(+output_theta), int(-output_theta))
            self.sleep(0.01)

        self.create.drive_direct(0, 0)

    def sleep(self, time_in_sec):
        """Sleeps for the specified amount of time while keeping odometry up-to-date
        Args:
            time_in_sec (float): time to sleep in seconds
        """
        start = self.time.time()
        while True:
            state = self.create.update()
            if state is not None:
                self.odometry.update(state.leftEncoderCounts,
                                     state.rightEncoderCounts)
                # print("[{},{},{}]".format(self.odometry.x, self.odometry.y, math.degrees(self.odometry.theta)))
            t = self.time.time()
            if start + time_in_sec <= t:
                break

    def draw_particles(self):
        data = []

        # get position data from all particles
        for particle in self.filter.particles:
            data.extend([particle.x, particle.y, 0.1, particle.theta])

            # paint all particles in simulation
            self.virtual_create.set_point_cloud(data)