Пример #1
0
 def __init__(self, lm, rm, cs: ColorSensor, odometry: Odometry,
              communication: Communication):
     #  values
     self.mode = PilotModes.FOLLOW_LINE
     self.vertex = None
     self.path = None
     self.position = (0, 0, 0)
     self.color = None
     self.rbd = None
     self.touch = False
     self.counter = 0
     self.status = 'free'
     # motors
     self.lm = lm
     self.rm = rm
     # controllers, classes
     self.cs = cs
     self.odometry = odometry
     self.planet = communication.planet
     self.communication = communication
     self.mixer = MotorMixer(BASE_SPEED, SPEED_MIN, SPEED_MAX)
     self.mc = MotorController(K_P, K_I, K_D, I_MAX, SETPOINT)
     self.events = EventList()
     self.events.add(EventNames.TARGET_REACHED)
     EventRegistry.instance().register_event_handler(
         EventNames.COLOR, self.set_color)
     EventRegistry.instance().register_event_handler(
         EventNames.TOUCH, self.set_touch)
     EventRegistry.instance().register_event_handler(
         EventNames.POSITION, self.set_position)
     pass
Пример #2
0
 def __init__(self):
     self.dx = 0
     self.dy = 0
     self.x = 0
     self.y = 0
     self.heading = 0
     self.events = EventList()
     self.events.add(EventNames.POSITION)
     self.prev_mpos = (0, 0)
     pass
Пример #3
0
 def __init__(self, graph, start, target):
     super().__init__(graph)
     self.start = start
     self.target = target
     self.unSettledNodes = []
     self.predecessors = {}
     self.events = EventList()
     self.events.add(EventNames.SHORTEST_PATH)
     self.start_time = time.time()
     pass
Пример #4
0
class TouchSensor:
    def __init__(self):
        self.ts1 = ev3.TouchSensor('in2')
        self.ts2 = ev3.TouchSensor('in3')
        self.events = EventList()
        self.events.add(EventNames.TOUCH)

    def read_in(self):
        value = self.ts1.value() or self.ts2.value()
        self.events.set(EventNames.TOUCH, value)
        return value
Пример #5
0
 def __init__(self):
     super().__init__({}, {})
     self.shortest_path = None
     self.shortest_path_counter = 0
     self.shortest_path_running = False
     self.curr_vertex = None
     self.curr_path = None
     self.target = None
     self.mode = PilotModes.EXPLORE
     self.paths = {}
     self.events = EventList()
     self.events.add(EventNames.EXPLORATION_FINISHED)
     EventRegistry.instance().register_event_handler(
         EventNames.SHORTEST_PATH, self.set_shortest_path)
     pass
Пример #6
0
class ColorSensor:
    def __init__(self):
        self.cs = ev3.ColorSensor('in1')
        self.cs.mode = 'RGB-RAW'
        self.events = EventList()
        self.events.add(EventNames.COLOR)

    def read_in(self):
        value = self.cs.bin_data('hhh')
        self.events.set(EventNames.COLOR, value)
        return value

    def get_rgb(self):
        return self.cs.bin_data('hhh')

    def get_greyscale(self):
        value = self.get_rgb()
        return (value[0] + value[1] + value[2]) / 3
Пример #7
0
class Planet(Graph):
    def __init__(self):
        super().__init__({}, {})
        self.shortest_path = None
        self.shortest_path_counter = 0
        self.shortest_path_running = False
        self.curr_vertex = None
        self.curr_path = None
        self.target = None
        self.mode = PilotModes.EXPLORE
        self.paths = {}
        self.events = EventList()
        self.events.add(EventNames.EXPLORATION_FINISHED)
        EventRegistry.instance().register_event_handler(
            EventNames.SHORTEST_PATH, self.set_shortest_path)
        pass

    # ---------
    # GRAPH MANIPULATION
    # ---------
    def add_edge(self, start: Path, end: Path, length: float, flag):
        edge_to = Edge(start.source, end.source, start.direction,
                       end.direction, length)
        edge_from = Edge(end.source, start.source, end.direction,
                         start.direction, length)
        if flag or (edge_from.id not in self.edges
                    and edge_to.id not in self.edges):
            if start.id in self.paths:
                print('deleting path: ', self.paths[start.id])
                del self.paths[start.id]
            if end.id in self.paths:
                print('deleting path: ', self.paths[end.id])
                del self.paths[end.id]
            self.edges[edge_from.id] = edge_from
            self.edges[edge_to.id] = edge_to
            return edge_to
        else:
            return None

    def add_vertex(self, position: Tuple[int, int]):
        vertex = Vertex(position)
        # if vertex.id not in self.vertexes:
        self.vertexes[vertex.id] = vertex
        return vertex
        # else:
        #     return None

    def add_path(self, source: Vertex, direction: Direction):
        path = Path(source, direction)
        if path.id not in self.paths:
            self.paths[path.id] = path
            print('new path: ' + str(path))
            return path
        else:
            return None

    def vertex_exists(self, position):
        for vertex in self.vertexes.values():
            if vertex.position == position:
                return vertex
        return False

    # ---------
    # SETTER
    # ---------
    def set_shortest_path(self, sp):
        self.shortest_path = sp
        self.shortest_path_counter = 0
        pass

    def set_curr_vertex(self, vertex):
        self.curr_vertex = vertex
        pass

    def set_target_mode(self):
        print('TARGET MODE')
        self.mode = PilotModes.TARGET
        pass

    def set_target(self, target):
        self.target = target
        print('target saved!')
        pass

    # ---------
    # GETTER
    # ---------
    def get_paths(self):
        return self.paths

    def get_shortest_path(self, end: Vertex):
        self.shortest_path_counter = 0
        sp = ShortestPath(self, self.curr_vertex, end)
        sp.run()
        pass

    def get_next_path(self):
        print(self.mode, self.mode == PilotModes.TARGET)
        if self.mode == PilotModes.EXPLORE:
            # depth first
            if self.curr_vertex:
                paths = list(self.paths.values())
                print('paths left:')
                for path in paths:
                    print(path)
                for path in self.paths.values():
                    if self.curr_vertex.equals(path.source):
                        self.curr_path = path
                        print('next path: ', self.curr_path)
                        return self.curr_path
                if paths.__len__() > 0:
                    path = paths[0]
                    if not self.shortest_path_running:
                        self.get_shortest_path(path.source)
                        self.shortest_path_running = True
                    if self.shortest_path \
                            and self.shortest_path.__len__() > 0 \
                            and self.shortest_path_counter < self.shortest_path.__len__():
                        edge = self.shortest_path[self.shortest_path_counter]
                        self.shortest_path_counter += 1
                        self.curr_path = Path(edge.start, edge.start_direction)
                        print(
                            'next path: ', self.curr_path,
                            ' sp_counter = ' + str(self.shortest_path_counter))
                        return self.curr_path
                else:
                    self.events.set(EventNames.EXPLORATION_FINISHED, True)
                    return False
        if self.mode == PilotModes.TARGET:
            print('shortest path is:')
            if self.shortest_path.__len__() > 0:
                for edge in self.shortest_path:
                    print(edge)
                edge = self.shortest_path[self.shortest_path_counter]
                self.shortest_path_counter += 1
                self.curr_path = Path(edge.start, edge.start_direction)
                print('next path: ', self.curr_path,
                      ' sp_counter = ' + str(self.shortest_path_counter))
                return self.curr_path
            else:
                print('shortest path not working or target not reachable!')
                return False
        else:
            return False
Пример #8
0
 def __init__(self):
     self.cs = ev3.ColorSensor('in1')
     self.cs.mode = 'RGB-RAW'
     self.events = EventList()
     self.events.add(EventNames.COLOR)
Пример #9
0
class Odometry:
    def __init__(self):
        self.dx = 0
        self.dy = 0
        self.x = 0
        self.y = 0
        self.heading = 0
        self.events = EventList()
        self.events.add(EventNames.POSITION)
        self.prev_mpos = (0, 0)
        pass

    def calc_pos1(self, motor_position: Tuple[int, int]):
        # print(motor_position)
        lec = motor_position[0] - self.prev_mpos[0]
        rec = motor_position[1] - self.prev_mpos[1]
        displacement = (lec + rec) * ECF / 2
        rotation = (lec - rec) * ECF / TRACK
        # print(rotation)
        self.prev_mpos = motor_position
        self.dx = self.dx + displacement * math.sin(self.heading +
                                                    rotation / 2)
        self.dy = self.dy + displacement * math.cos(self.heading +
                                                    rotation / 2)
        self.heading = self.heading + rotation
        heading = Direction.format(Direction.to_deg(self.heading))
        # print(self.dx, self.dy, heading, Direction.str(heading, True))
        return self.x, self.y, self.heading

    def add_pos(self):
        self.x += round(self.dx / 50)
        self.y += round(self.dy / 50)
        heading = Direction.format(Direction.to_deg(self.heading))
        self.events.set(
            EventNames.POSITION,
            (self.x, self.y, heading, Direction.str(heading, True)))
        self.dx = 0
        self.dy = 0

    # ---------
    # SETTER
    # ---------
    def set_position(self, position):
        self.x = position[0]
        self.y = position[1]
        pass

    # ---------
    # GETTER
    # ---------
    def read_in(self, motor_position):
        # print('odometry calculated')
        return self.calc_pos1(motor_position)

    def get_direction(self):
        return self.heading

    def get_position(self):
        return self.x, self.y

    def get_vertex(self):
        return self.vertex
Пример #10
0
class Pilot:
    # this is the main driving class
    # simple or complex maneuvers (follow line, turn, stop, ...) are defined as methods
    # PILOT_MODE decides which maneuver is called in the main loop

    def __init__(self, lm, rm, cs: ColorSensor, odometry: Odometry,
                 communication: Communication):
        #  values
        self.mode = PilotModes.FOLLOW_LINE
        self.vertex = None
        self.path = None
        self.position = (0, 0, 0)
        self.color = None
        self.rbd = None
        self.touch = False
        self.counter = 0
        self.status = 'free'
        # motors
        self.lm = lm
        self.rm = rm
        # controllers, classes
        self.cs = cs
        self.odometry = odometry
        self.planet = communication.planet
        self.communication = communication
        self.mixer = MotorMixer(BASE_SPEED, SPEED_MIN, SPEED_MAX)
        self.mc = MotorController(K_P, K_I, K_D, I_MAX, SETPOINT)
        self.events = EventList()
        self.events.add(EventNames.TARGET_REACHED)
        EventRegistry.instance().register_event_handler(
            EventNames.COLOR, self.set_color)
        EventRegistry.instance().register_event_handler(
            EventNames.TOUCH, self.set_touch)
        EventRegistry.instance().register_event_handler(
            EventNames.POSITION, self.set_position)
        pass

    def run(self):
        if self.mode == PilotModes.FOLLOW_LINE or self.mode == PilotModes.FOLLOW_LINE_ODO:
            self.follow_line()
        elif self.mode == PilotModes.CHECK_ISC:
            self.check_isc()
        elif self.mode == PilotModes.CHOOSE_PATH:
            self.choose_path()
        elif self.mode == PilotModes.BLOCKED:
            self.blocked_path()
        pass

    # ---------
    # MANEUVERS
    # ---------
    def stop_motors(self):
        self.set_speed((0, 0))
        pass

    def follow_line(self):
        if self.color is not None:
            self.lm.command = 'run-direct'
            self.rm.command = 'run-direct'
            # calculate rudder from rgb mean
            rudder = self.mc.run(self.color)
            # divide the rudder speed on the motors
            speed = self.mixer.run(rudder)
            self.set_speed(speed)
            # print(speed)
        pass

    def blocked_path(self):
        self.stop_motors()
        self.status = 'blocked'
        time.sleep(0.3)
        print('path blocked.')
        self.lm.run_to_rel_pos(position_sp=-250,
                               speed_sp=200,
                               stop_action="hold")
        self.rm.run_to_rel_pos(position_sp=-250,
                               speed_sp=200,
                               stop_action="hold")
        self.wait(250, 200)
        self.turn_odo(90)
        self.lm.run_to_rel_pos(position_sp=60,
                               speed_sp=200,
                               stop_action="hold")
        self.rm.run_to_rel_pos(position_sp=60,
                               speed_sp=200,
                               stop_action="hold")
        self.wait(60, 200)
        self.turn_odo(90)
        self.mode = PilotModes.FOLLOW_LINE_ODO
        pass

    def turn_motor(self, motor, degrees):
        # turn by degrees
        p_sp = 5.7361 * degrees
        if motor is 'lm':
            self.lm.run_to_rel_pos(position_sp=p_sp,
                                   speed_sp=200,
                                   stop_action="hold")
        if motor is 'rm':
            self.rm.run_to_rel_pos(position_sp=p_sp,
                                   speed_sp=200,
                                   stop_action="hold")
        return p_sp

    def turn(self, degrees):
        # turn by degrees
        p_sp = 2.88 * degrees
        self.lm.run_to_rel_pos(position_sp=-p_sp,
                               speed_sp=200,
                               stop_action="hold")
        self.rm.run_to_rel_pos(position_sp=p_sp,
                               speed_sp=200,
                               stop_action="hold")
        print('Turning: ' + str(degrees) + ' degrees.')
        duration = abs(degrees) / 90 * 1.3
        time.sleep(duration)
        pass

    def turn_odo(self, degrees):
        # turn by degrees
        p_sp = 2.88 * degrees
        self.lm.run_to_rel_pos(position_sp=-p_sp,
                               speed_sp=200,
                               stop_action="hold")
        self.rm.run_to_rel_pos(position_sp=p_sp,
                               speed_sp=200,
                               stop_action="hold")
        print('Turning: ' + str(degrees) + ' degrees.')
        self.wait(p_sp, 200)
        # duration = abs(degrees) / 90 * 1.3
        # time.sleep(duration)
        pass

    def check_isc(self):
        print('check_isc()')
        self.stop_motors()
        self.odometry.add_pos()
        print(self.position)
        self.communication.start()
        if self.counter == 0:
            self.communication.send_ready()
        vertex = self.planet.vertex_exists(
            (self.position[0], self.position[1]))
        existing_vertex = bool(vertex)
        if not existing_vertex:
            vertex = self.planet.add_vertex(
                (self.position[0], self.position[1]))
        if vertex.equals(self.planet.target):
            self.events.set(EventNames.TARGET_REACHED, True)
        if self.counter != 0 and self.status == 'blocked':
            edge = self.planet.add_edge(self.planet.curr_path,
                                        self.planet.curr_path, -1, False)
            print('new edge: ', edge)
            self.communication.send_edge(edge, 'blocked')
        self.planet.set_curr_vertex(vertex)
        path = Path(vertex, (self.position[2] + Direction.SOUTH) % 360)
        if not existing_vertex:
            self.turn(-90)
            print('Turning: 362 degrees.')

        if self.counter != 0:
            self.planet.add_path(self.planet.curr_vertex, path.direction)
        if self.counter != 0 and self.status == 'free':
            edge = self.planet.add_edge(self.planet.curr_path, path, 0, False)
            print('new edge: ', edge)
            self.communication.send_edge(edge, 'free')
            time.sleep(1)

        if not existing_vertex:
            self.rm.position = 0
            target_pos = self.turn_motor('rm', 362)
            eighth = target_pos / 8
            while self.rm.position < target_pos - 10:
                # print(self.rm.position)
                gs = self.cs.get_greyscale()
                if gs < 100:
                    direction = self.position[2]
                    if target_pos - 7 * eighth <= self.rm.position <= target_pos - 5 * eighth:
                        direction += Direction.EAST
                        # print('right path detected: ' + str(direction))
                    elif target_pos - 5 * eighth <= self.rm.position <= target_pos - 3 * eighth:
                        direction += Direction.NORTH
                        # print('straight path detected: ' + str(direction))
                    elif target_pos - 3 * eighth <= self.rm.position <= target_pos - 1 * eighth:
                        direction += Direction.WEST
                        # print('left path detected: ' + str(direction))
                    else:
                        continue
                    direction = direction % 360
                    # print('path detected: ' + str(direction))
                    self.planet.add_path(self.planet.curr_vertex, direction)
                    time.sleep(0.5)
            self.turn(90)
            pass
        if self.status == 'blocked':
            self.status = 'free'
        self.counter += 1
        print('waiting for messages from server!')
        time.sleep(2)
        self.communication.stop()
        self.lm.command = 'reset'
        self.rm.command = 'reset'
        # self.stop_motors()
        # self.lm.position = 0
        # self.rm.position = 0
        self.odometry.prev_mpos = (0, 0)
        self.mode = PilotModes.CHOOSE_PATH
        pass

    def choose_path(self):
        print('choose_path()')
        self.stop_motors()
        path = self.planet.get_next_path()
        if path:
            turn_direction = self.position[2] - path.direction
            if turn_direction == 270:
                turn_direction = -90
            if turn_direction == -270:
                turn_direction = 90

            if turn_direction == -90:  # East (relative)
                self.lm.run_to_rel_pos(position_sp=60,
                                       speed_sp=200,
                                       stop_action="hold")
                self.rm.run_to_rel_pos(position_sp=60,
                                       speed_sp=200,
                                       stop_action="hold")
                self.wait(60, 200)
                self.turn_odo(turn_direction)
                self.lm.run_to_rel_pos(position_sp=75,
                                       speed_sp=200,
                                       stop_action="hold")
                self.rm.run_to_rel_pos(position_sp=75,
                                       speed_sp=200,
                                       stop_action="hold")
                self.wait(75, 200)
            elif turn_direction == 0:  # North (relative)
                self.lm.run_to_rel_pos(position_sp=150,
                                       speed_sp=200,
                                       stop_action="hold")
                self.rm.run_to_rel_pos(position_sp=150,
                                       speed_sp=200,
                                       stop_action="hold")
                self.wait(150, 200)
            elif turn_direction == 90:  # West (relative)
                self.lm.run_to_rel_pos(position_sp=110,
                                       speed_sp=200,
                                       stop_action="hold")
                self.rm.run_to_rel_pos(position_sp=110,
                                       speed_sp=200,
                                       stop_action="hold")
                self.wait(110, 200)
                self.turn_odo(turn_direction)
                self.lm.run_to_rel_pos(position_sp=90,
                                       speed_sp=200,
                                       stop_action="hold")
                self.rm.run_to_rel_pos(position_sp=90,
                                       speed_sp=200,
                                       stop_action="hold")
                self.wait(90, 200)
            elif turn_direction == 180 or turn_direction == -180:  # South (relative)
                self.lm.run_to_rel_pos(position_sp=80,
                                       speed_sp=200,
                                       stop_action="hold")
                self.rm.run_to_rel_pos(position_sp=80,
                                       speed_sp=200,
                                       stop_action="hold")
                self.wait(80, 200)
                self.turn_odo(90)
                self.lm.run_to_rel_pos(position_sp=50,
                                       speed_sp=200,
                                       stop_action="hold")
                self.rm.run_to_rel_pos(position_sp=50,
                                       speed_sp=200,
                                       stop_action="hold")
                self.wait(50, 200)
                self.turn_odo(90)
                self.lm.run_to_rel_pos(position_sp=90,
                                       speed_sp=200,
                                       stop_action="hold")
                self.rm.run_to_rel_pos(position_sp=90,
                                       speed_sp=200,
                                       stop_action="hold")
                self.wait(90, 200)

            time.sleep(1)

            self.mode = PilotModes.FOLLOW_LINE_ODO
        pass

    def wait(self, target_pos, speed):
        i = 5
        target_pos = abs(target_pos)
        dt = target_pos / speed + 0.5  # dt in s
        start = time.time()
        while time.time() - start <= dt:
            if i == 5:
                self.odometry.read_in((self.lm.position, self.rm.position))
                i = 0
            i += 1

    def test(self, value, value2):
        print('test()')
        self.lm.run_to_rel_pos(position_sp=value,
                               speed_sp=200,
                               stop_action="hold")
        self.rm.run_to_rel_pos(position_sp=value,
                               speed_sp=200,
                               stop_action="hold")
        time.sleep(0.5)
        self.turn(value2)
        pass

    # ---------
    # SETTER
    # ---------
    def set_position(self, value):
        # print(value)
        self.position = value

    def set_color(self, value):
        self.color = value
        self.rbd = value[0] - value[2]
        # gs = (value[0] + value[1] + value[2]) / 3
        # print('RBD: ' + str(self.rbd) + '  GS: ' + str(gs))
        if 90 <= self.rbd:  # red patch
            print('Patch: red')
            self.stop_motors()
            self.mode = PilotModes.CHECK_ISC
        elif self.rbd <= -65:  # blue patch
            print('Patch: blue')
            self.stop_motors()
            self.lm.run_to_rel_pos(position_sp=-35,
                                   speed_sp=180,
                                   stop_action="hold")
            time.sleep(0.1)
            self.mode = PilotModes.CHECK_ISC
        pass

    def set_mode(self, mode):
        self.mode = mode
        pass

    def set_touch(self, value):
        self.touch = value
        if value:
            print('touch: ', str(value))
            self.mode = PilotModes.BLOCKED
            ev3.Sound.beep()
        pass

    def set_speed(self, speed: Tuple[int, int]):
        self.lm.duty_cycle_sp = speed[0]
        self.rm.duty_cycle_sp = speed[1]
        pass

    # ---------
    # GETTER
    # ---------
    def get_position(self):
        return self.position

    def get_mode(self):
        return self.mode
Пример #11
0
class ShortestPath(PathingAlgorithm.PathingAlgorithm):
    def __init__(self, graph, start, target):
        super().__init__(graph)
        self.start = start
        self.target = target
        self.unSettledNodes = []
        self.predecessors = {}
        self.events = EventList()
        self.events.add(EventNames.SHORTEST_PATH)
        self.start_time = time.time()
        pass

    def execute(self):
        self.distance[self.start.position] = 0
        self.unSettledNodes.append(self.start)

        while self.unSettledNodes.__len__() > 0:
            node = self.get_minimum(self.unSettledNodes)
            self.settledNodes.append(node)
            self.unSettledNodes.remove(node)
            self.find_minimal_distances(node)
            if time.time() - self.start_time >= 10:
                break
        return self

    def find_minimal_distances(self, node):
        adjacent_nodes = self.get_neighbors(node)
        for target in adjacent_nodes:
            if (self.get_shortest_distance(target) >
                    self.get_shortest_distance(node) +
                    self.get_distance(node, target)):
                self.distance[target.position] = self.get_shortest_distance(
                    node) + self.get_distance(node, target)
                self.predecessors[target.position] = node
                self.unSettledNodes.append(target)
        pass

    def get_path(self):
        vertexes = []
        step = self.target
        # check if a vertexes exists
        if self.predecessors.get(step.position) is None:
            return None
        vertexes.append(step)
        while self.predecessors.get(step.position):
            step = self.predecessors.get(step.position)
            vertexes.append(step)
        vertexes.append(self.start)
        vertexes.pop()
        vertexes.reverse()
        path = []
        length = vertexes.__len__() - 2
        if length > 0:
            for i in range(vertexes.__len__() - 1):
                if i >= 0:
                    for e in self.edges.values():
                        if vertexes[i].equals(
                                e.start) and vertexes[i + 1].equals(e.end):
                            path.append(e)

        return path

    def run(self):
        print('ShortestPath Thread started!')

        path = self.execute().get_path()
        self.events.set(EventNames.SHORTEST_PATH, path)
        print('ShortestPath Thread finished!')
        pass
Пример #12
0
 def __init__(self):
     self.ts1 = ev3.TouchSensor('in2')
     self.ts2 = ev3.TouchSensor('in3')
     self.events = EventList()
     self.events.add(EventNames.TOUCH)