class ClosestWaypointSubscriber(EventLoop):
    def __init__(self, name, host, port):
        super(ClosestWaypointSubscriber, self).__init__()

        self.autowareSubscribeTopic = Topic()
        self.autowareSubscribeTopic.set_id(name)
        self.autowareSubscribeTopic.set_root(Autoware.TOPIC.SUBSCRIBE)
        self.autowareSubscribeTopic.set_message(autoware_message)

        self.__previous_time = time()
        self.__period = 1.0  # [sec]

        self.connect(host, port)
        self.set_main_loop(rospy.spin)

        rospy.init_node("ams_closest_waypoint_subscriber", anonymous=True)
        self.__ROSSubscriber = message_filters.Subscriber(
            Autoware.ROSTOPIC.SUBSCRIBE, Int32)
        self.__ROSSubscriber.registerCallback(self.on_message_from_ros,
                                              self.publish)

    def on_message_from_ros(self, messageData, publish):
        current_time = time()
        if self.__period < current_time - self.__previous_time:
            self.__previous_time += (1 + int(
                (current_time - self.__previous_time) /
                self.__period)) * self.__period

            message = self.autowareSubscribeTopic.get_template(
            )["closest_waypoint"]
            message["index"] = messageData.data
            payload = self.autowareSubscribeTopic.serialize(message)
            publish(self.autowareSubscribeTopic.private + "/closest_waypoint",
                    payload)
Esempio n. 2
0
def request_fleet_relations():
    topic = Topic()
    topic.set_root(FleetManager.TOPIC.SUBSCRIBE)
    topic.set_message(fleet_manager_message)
    message = topic.get_template()
    message["action"] = FleetManager.ACTION.PUBLISH_RELATIONS
    mqtt.publish(topic.root, topic.serialize(message))
    return api_response(code=200, message={"result": "requested"})
Esempio n. 3
0
class SimBusFleet(FleetManager):

    CONST = SIM_BUS_FLEET

    def __init__(self, _id, name, waypoint, arrow, route, spot):
        super().__init__(_id, name, waypoint, arrow, route)

        self.waypoint = waypoint
        self.arrow = arrow
        self.route = route
        self.spot = spot
        self.relation = Relation()
        self.__bus_routes = {}
        self.__bus_schedules = {}

        self.bus_parkable_spots = self.spot.get_spots_of_target_group(
            Target.new_node_target(SimBus))

        self.vehicle_statuses = self.manager.dict()
        self.vehicle_statuses_lock = self.manager.Lock()

        self.vehicle_schedules = {}
        self.vehicle_last_indices = {}
        self.bus_schedules = {}
        self.bus_stop_spots = {}
        self.state_machines = {}

        self.__topicPubVehicleSchedules = Topic()
        self.__topicPubVehicleSchedules.set_categories(
            FleetManager.CONST.TOPIC.CATEGORIES.SCHEDULES)

        self.__topicSubVehicleStatus = Topic()
        self.__topicSubVehicleStatus.set_targets(
            Target.new_target(None, SIM_BUS.NODE_NAME), None)
        self.__topicSubVehicleStatus.set_categories(
            Vehicle.CONST.TOPIC.CATEGORIES.STATUS)
        self.__topicSubVehicleStatus.set_message(VehicleStatus)
        self.set_subscriber(self.__topicSubVehicleStatus,
                            self.update_vehicle_status)

    def __publish_vehicle_schedules(self, vehicle_id, payload):
        self.__topicPubVehicleSchedules.set_targets(
            self.target, Target.new_target(vehicle_id, SIM_BUS.NODE_NAME))
        self.publish(self.__topicPubVehicleSchedules, payload)

    def set_bus_schedules(self, bus_schedules):
        self.__bus_schedules = bus_schedules
        for bus_schedules_id in self.__bus_schedules:
            self.relation.add_relation(
                Target.new_target(bus_schedules_id,
                                  SIM_BUS_FLEET.TARGET_GROUP.BUS_SCHEDULES),
                Target.new_target(None, SIM_BUS.NODE_NAME))

    def update_vehicle_status(self, _client, _userdata, topic, payload):
        self.vehicle_statuses_lock.acquire()
        vehicle_id = self.__topicSubVehicleStatus.get_from_id(topic)
        vehicle_status = self.__topicSubVehicleStatus.unserialize(payload)
        self.vehicle_statuses[vehicle_id] = vehicle_status
        self.vehicle_statuses_lock.release()

    def update_vehicle_schedules(self, vehicle_statuses):
        for vehicle_id, vehicle_status in vehicle_statuses.items():
            if vehicle_id not in self.vehicle_schedules:
                self.vehicle_schedules[vehicle_id] = [vehicle_status.schedule]
            else:
                while self.vehicle_schedules[vehicle_id][
                        0].id != vehicle_status.schedule.id:
                    self.vehicle_schedules[vehicle_id].pop(0)

    def update_relation(self, target_bus_schedule, vehicle_id):
        self.relation.remove_relation(
            target_bus_schedule, Target.new_target(None, SIM_BUS.NODE_NAME))
        self.relation.add_relation(
            target_bus_schedule,
            Target.new_target(vehicle_id, SIM_BUS.NODE_NAME))

    def get_unassigned_bus_schedule_target(self):
        targets = Target.new_targets(
            self.relation.get_related(
                Target.new_target(None, SIM_BUS.NODE_NAME)))
        if len(targets) == 0:
            return None
        return targets[0]

    def get_assigned_bus_schedule_target(self, target_vehicle):
        return self.relation.get_related(target_vehicle)[0]

    def get_to_circular_route(self, start_waypoint_id, start_arrow_code,
                              bus_schedules_id):
        start_point = {
            "arrow_code": start_arrow_code,
            "waypoint_id": start_waypoint_id
        }
        goal_points = []
        for branch_index, branch in enumerate(
                self.__bus_schedules[bus_schedules_id]):
            for part_index, schedule in enumerate(branch.common):
                if schedule.event == SIM_BUS.EVENT.MOVE_TO_SELECT_POINT:
                    goal_point = {
                        "goal_id":
                        ",".join(map(str,
                                     [branch_index, "common", part_index])),
                        "waypoint_id":
                        schedule.route.start_waypoint_id,
                        "arrow_code":
                        schedule.route.arrow_codes[0],
                        # "waypoint_id": schedule.route.goal_waypoint_id,
                        # "arrow_code": schedule.route.arrow_codes[-1],
                    }
                    if goal_point not in goal_points:
                        goal_points.append(goal_point)
        shortest_routes = self.route.get_shortest_routes(start_point,
                                                         goal_points,
                                                         reverse=False)
        to_circular_route = min(shortest_routes.items(),
                                key=lambda x: x[1]["cost"])[1]
        to_circular_route.pop("cost")
        branch_index, part_type, part_index = to_circular_route.pop(
            "goal_id").split(",")
        return to_circular_route, int(branch_index), part_type, int(part_index)

    def get_move_to_circular_route_schedule(self, target_vehicle,
                                            target_bus_schedule, start_time):
        vehicle_status = self.vehicle_statuses[target_vehicle.id]
        to_circular_route, branch_index, part_type, part_index = \
            self.get_to_circular_route(
                vehicle_status.location.waypoint_id, vehicle_status.location.arrow_code, target_bus_schedule.id)

        return Schedule.new_schedule(
                [target_vehicle], SIM_BUS.EVENT.MOVE_TO_CIRCULAR_ROUTE, start_time, start_time + 1000,
                to_circular_route),\
            branch_index, part_type, part_index

    def get_move_to_branch_point_schedules(self, target_vehicle,
                                           target_bus_schedule, start_time,
                                           branch_index, part_type,
                                           part_index):
        bus_schedule = self.__bus_schedules[target_bus_schedule.id]
        schedules = []
        if part_type in ["main", "sub"]:
            for i in range(part_index,
                           len(bus_schedule[branch_index][part_type])):
                targets = [target_vehicle]
                if bus_schedule[branch_index][part_type][
                        i].targets is not None:
                    targets.extend(
                        bus_schedule[branch_index][part_type][i].targets)
                schedules.append(
                    Schedule.new_schedule(
                        targets,
                        bus_schedule[branch_index][part_type][i].event,
                        start_time, start_time + 1000,
                        bus_schedule[branch_index][part_type][i].route))
                start_time += 1000
            branch_index = (branch_index +
                            1) * (branch_index + 1 < len(bus_schedule))
            part_type = "common"
            part_index = 0

        if part_type == "common":
            for i in range(part_index,
                           len(bus_schedule[branch_index][part_type])):
                targets = [target_vehicle]
                if bus_schedule[branch_index][part_type][
                        i].targets is not None:
                    targets.extend(
                        bus_schedule[branch_index][part_type][i].targets)
                schedules.append(
                    Schedule.new_schedule(
                        targets,
                        bus_schedule[branch_index][part_type][i].event,
                        start_time, start_time + 1000,
                        bus_schedule[branch_index][part_type][i].route))
                start_time += 1000
                if bus_schedule[branch_index][part_type][
                        i].event == SIM_BUS.EVENT.MOVE_TO_BRANCH_POINT:
                    part_index = i
                    break
        return schedules, branch_index, part_type, part_index

    def get_move_to_branch_point_via_bus_stop_schedules(
            self, target_vehicle, target_bus_schedule, start_time,
            branch_index):
        bus_schedule = self.__bus_schedules[target_bus_schedule.id]
        schedules = []
        for i in range(0, len(bus_schedule[branch_index].sub)):
            targets = [target_vehicle]
            if bus_schedule[branch_index].sub[i].targets is not None:
                targets.extend(bus_schedule[branch_index].sub[i].targets)
            schedules.append(
                Schedule.new_schedule(targets,
                                      bus_schedule[branch_index].sub[i].event,
                                      start_time, start_time + 5,
                                      bus_schedule[branch_index].sub[i].route))
            start_time += 1000
        branch_index = (branch_index +
                        1) * (branch_index + 1 < len(bus_schedule))

        part_index = 0
        for i in range(len(bus_schedule[branch_index].common)):
            targets = [target_vehicle]
            if bus_schedule[branch_index].common[i].targets is not None:
                targets.extend(bus_schedule[branch_index].common[i].targets)
            schedules.append(
                Schedule.new_schedule(
                    targets, bus_schedule[branch_index].common[i].event,
                    start_time, start_time + 1000,
                    bus_schedule[branch_index].common[i].route))
            start_time += 1000
            if bus_schedule[branch_index].common[
                    i].event == SIM_BUS.EVENT.MOVE_TO_BRANCH_POINT:
                part_index = i
                break
        return schedules, branch_index, "common", part_index

    @staticmethod
    def get_event_renamed_schedules(schedules):
        event_renamed_schedules = deepcopy(schedules)
        for i, schedule in enumerate(event_renamed_schedules):
            if schedule.event in [
                    SIM_BUS.EVENT.MOVE_TO_CIRCULAR_ROUTE,
                    SIM_BUS.EVENT.MOVE_TO_SELECT_POINT,
                    SIM_BUS.EVENT.MOVE_TO_BRANCH_POINT,
                    SIM_BUS.EVENT.MOVE_TO_BUS_STOP,
                    SIM_BUS.EVENT.MOVE_TO_JUNCTION,
                    SIM_BUS.EVENT.MOVE_TO_PARKING,
            ]:
                event_renamed_schedules[i].event = SIM_BUS.TRIGGER.MOVE
            elif schedule.event in [
                    SIM_BUS.EVENT.STOP_TO_TAKE_UP,
                    SIM_BUS.EVENT.STOP_TO_DISCHARGE,
                    SIM_BUS.EVENT.STOP_TO_DISCHARGE_AND_TAKE_UP,
                    SIM_BUS.EVENT.STOP_TO_PARKING
            ]:
                event_renamed_schedules[i].event = SIM_BUS.TRIGGER.STOP
            elif schedule.event in []:
                event_renamed_schedules[
                    i].event = SIM_BUS.TRIGGER.REQUEST_SCHEDULES
        return event_renamed_schedules

    def get_state_machine(
            self, initial_state=SIM_BUS_FLEET.STATE.WAITING_FOR_BUS_STAND_BY):
        machine = StateMachine(
            states=list(SIM_BUS_FLEET.STATE),
            initial=initial_state,
        )
        machine.add_transitions([
            {
                "trigger":
                SIM_BUS_FLEET.TRIGGER.ASSIGN_BUS_SCHEDULES,
                "source":
                SIM_BUS_FLEET.STATE.WAITING_FOR_BUS_STAND_BY,
                "dest":
                SIM_BUS_FLEET.STATE.WAITING_FOR_SCHEDULES_REQUEST,
                "conditions": [
                    self.
                    condition_schedules_length_and_publish_new_bus_schedules
                ]
            },
            {
                "trigger":
                SIM_BUS_FLEET.TRIGGER.SEND_THROUGH_SCHEDULES,
                "source":
                SIM_BUS_FLEET.STATE.WAITING_FOR_SCHEDULES_REQUEST,
                "dest":
                SIM_BUS_FLEET.STATE.WAITING_FOR_SCHEDULES_REQUEST,
                "conditions":
                [self.condition_vehicle_state_and_publish_through_schedules]
            },
            {
                "trigger":
                SIM_BUS_FLEET.TRIGGER.SEND_VIA_SCHEDULES,
                "source":
                SIM_BUS_FLEET.STATE.WAITING_FOR_SCHEDULES_REQUEST,
                "dest":
                SIM_BUS_FLEET.STATE.WAITING_FOR_SCHEDULES_REQUEST,
                "conditions":
                [self.condition_vehicle_state_and_publish_via_schedules]
            },
        ])
        return machine

    def condition_schedules_length(self, vehicle_id, expected_length):
        return len(self.vehicle_schedules[vehicle_id]) == expected_length

    @staticmethod
    def condition_vehicle_state(vehicle_status, expected_state):
        return vehicle_status.state == expected_state

    def after_change_state_update_last_indices(self, vehicle_id, branch_index,
                                               part_type, part_index):
        self.vehicle_last_indices[vehicle_id] = {
            "branch_index": branch_index,
            "part_type": part_type,
            "part_index": part_index
        }
        return True

    def after_change_state_publish_schedules(self, vehicle_id):
        event_renamed_schedules = self.get_event_renamed_schedules(
            self.vehicle_schedules[vehicle_id])
        payload = self.__topicPubVehicleSchedules.serialize(
            event_renamed_schedules)
        self.__publish_vehicle_schedules(vehicle_id, payload)
        return True

    def after_change_state_publish_new_bus_schedules(self, current_time,
                                                     vehicle_id):
        target_vehicle = Target.new_target(vehicle_id, SIM_BUS.NODE_NAME)
        target_bus_schedule = self.get_unassigned_bus_schedule_target()

        vehicle_schedules = []
        start_time = current_time

        move_to_circular_route_schedule, branch_index, part_type, part_index = \
            self.get_move_to_circular_route_schedule(
                target_vehicle, target_bus_schedule, start_time)
        vehicle_schedules = \
            Schedule.get_merged_schedules(vehicle_schedules, [move_to_circular_route_schedule])
        start_time = vehicle_schedules[-1].period.end

        move_to_branch_point_schedules, branch_index, part_type, part_index = \
            self.get_move_to_branch_point_schedules(
                target_vehicle, target_bus_schedule, start_time, branch_index, part_type, part_index)
        vehicle_schedules = \
            Schedule.get_merged_schedules(vehicle_schedules, move_to_branch_point_schedules)

        self.vehicle_schedules[vehicle_id][0].period.end = current_time
        self.vehicle_schedules[vehicle_id] = \
            Schedule.get_merged_schedules(self.vehicle_schedules[vehicle_id], vehicle_schedules)

        self.update_relation(target_bus_schedule, vehicle_id)

        self.after_change_state_update_last_indices(vehicle_id, branch_index,
                                                    part_type, part_index)
        self.after_change_state_publish_schedules(vehicle_id)
        return True

    def after_change_state_publish_through_schedules(self, vehicle_id):
        target_vehicle = Target.new_target(vehicle_id, SIM_BUS.NODE_NAME)
        target_bus_schedule = self.get_assigned_bus_schedule_target(
            target_vehicle)
        move_to_branch_point_schedules, branch_index, part_type, part_index = \
            self.get_move_to_branch_point_schedules(
                target_vehicle, target_bus_schedule, self.vehicle_schedules[vehicle_id][-1].period.end,
                self.vehicle_last_indices[vehicle_id]["branch_index"], "main", 0)

        self.vehicle_schedules[vehicle_id] = Schedule.get_merged_schedules(
            self.vehicle_schedules[vehicle_id], move_to_branch_point_schedules)

        self.after_change_state_update_last_indices(vehicle_id, branch_index,
                                                    part_type, part_index)
        self.after_change_state_publish_schedules(vehicle_id)
        return True

    def after_change_state_publish_via_schedules(self, vehicle_id):
        target_vehicle = Target.new_target(vehicle_id, SIM_BUS.NODE_NAME)
        target_bus_schedule = self.get_assigned_bus_schedule_target(
            target_vehicle)
        move_to_branch_point_via_bus_stop_schedules, branch_index, part_type, part_index = \
            self.get_move_to_branch_point_via_bus_stop_schedules(
                target_vehicle, target_bus_schedule, self.vehicle_schedules[vehicle_id][-1].period.end,
                self.vehicle_last_indices[vehicle_id]["branch_index"])

        self.vehicle_schedules[vehicle_id] = Schedule.get_merged_schedules(
            self.vehicle_schedules[vehicle_id],
            move_to_branch_point_via_bus_stop_schedules)

        self.after_change_state_update_last_indices(vehicle_id, branch_index,
                                                    part_type, part_index)
        self.after_change_state_publish_schedules(vehicle_id)
        return True

    def condition_schedules_length_and_publish_new_bus_schedules(
            self, current_time, vehicle_id):
        if self.condition_schedules_length(vehicle_id, 1):
            self.after_change_state_publish_new_bus_schedules(
                current_time, vehicle_id)
            return True
        return False

    def condition_vehicle_state_and_publish_through_schedules(
            self, vehicle_id, vehicle_status, expected_state):
        if self.condition_vehicle_state(vehicle_status, expected_state):
            if self.condition_schedules_length(vehicle_id, 1):
                self.after_change_state_publish_through_schedules(vehicle_id)
                return True
        return False

    def condition_vehicle_state_and_publish_via_schedules(
            self, vehicle_id, vehicle_status, expected_state):
        if self.condition_vehicle_state(vehicle_status, expected_state):
            if self.condition_schedules_length(vehicle_id, 1):
                self.after_change_state_publish_via_schedules(vehicle_id)
                return True
        return False

    def get_vehicle_statuses_and_lock(self):
        self.vehicle_statuses_lock.acquire()
        return deepcopy(self.vehicle_statuses)

    def set_vehicle_statuses_and_unlock(self, vehicle_statuses):
        self.vehicle_statuses.clear()
        self.vehicle_statuses.update(vehicle_statuses)
        self.vehicle_statuses_lock.release()

    def update_status(self):
        vehicle_statuses = self.get_vehicle_statuses_and_lock()

        self.update_vehicle_schedules(vehicle_statuses)

        self.update_state_machines(vehicle_statuses)

        self.set_vehicle_statuses_and_unlock(vehicle_statuses)

    def update_state_machines(self, vehicle_statuses):
        current_time = time()

        for vehicle_id, vehicle_status in vehicle_statuses.items():
            if vehicle_id not in self.state_machines:
                self.state_machines[vehicle_id] = self.get_state_machine()

            vehicle_state = self.state_machines[vehicle_id].state

            if vehicle_state == SIM_BUS_FLEET.STATE.WAITING_FOR_BUS_STAND_BY:
                self.state_machines[vehicle_id].send_circular_route_schedules(
                    current_time, vehicle_id)
            elif vehicle_state == SIM_BUS_FLEET.STATE.WAITING_FOR_SCHEDULES_REQUEST:
                if not self.state_machines[vehicle_id].send_through_schedules(
                        vehicle_id, vehicle_status,
                        SIM_BUS.STATE.REQUEST_THROUGH_SCHEDULES):
                    self.state_machines[vehicle_id].send_via_schedules(
                        vehicle_id, vehicle_status,
                        SIM_BUS.STATE.REQUEST_VIA_SCHEDULES)
Esempio n. 4
0
class SimCar(Vehicle):

    CONST = SIM_CAR

    def __init__(self,
                 _id,
                 name,
                 waypoint,
                 arrow,
                 route,
                 intersection,
                 dt=1.0):
        super().__init__(_id, name, waypoint, arrow, route, dt=dt)

        self.state_machine = self.get_state_machine()
        self.velocity = None

        self.traffic_signals = self.manager.dict()
        self.traffic_signals_lock = self.manager.Lock()
        self.other_vehicle_locations = self.manager.dict()
        self.other_vehicle_locations_lock = self.manager.Lock()
        self.intersection = intersection

        self.__topicPubLocation = Topic()
        self.__topicPubLocation.set_targets(
            Target.new_target(self.target.id, SIM_CAR.NODE_NAME))
        self.__topicPubLocation.set_categories(
            SIM_CAR.TOPIC.CATEGORIES.LOCATION)

        self.__topicSubStatus = Topic()
        self.__topicSubStatus.set_targets(
            Target.new_target(None, SIM_CAR.NODE_NAME), None)
        self.__topicSubStatus.set_categories(SIM_CAR.TOPIC.CATEGORIES.LOCATION)
        self.__topicSubStatus.set_message(Location)
        self.set_subscriber(self.__topicSubStatus,
                            self.update_other_vehicle_locations)

        self.__topicSubTrafficSignalStatus = Topic()
        self.__topicSubTrafficSignalStatus.set_targets(
            Target.new_target(None, TRAFFIC_SIGNAL.NODE_NAME), None)
        self.__topicSubTrafficSignalStatus.set_categories(
            TRAFFIC_SIGNAL.TOPIC.CATEGORIES.STATUS)
        self.__topicSubTrafficSignalStatus.set_message(TrafficSignalStatus)
        self.set_subscriber(self.__topicSubTrafficSignalStatus,
                            self.update_traffic_signals)

    def set_velocity(self, velocity):
        self.velocity = velocity

    def publish_location(self):
        self.status.location.geohash = self.waypoint.get_geohash(
            self.status.location.waypoint_id)
        payload = self.__topicPubLocation.serialize(self.status.location)
        self.publish(self.__topicPubLocation, payload)

    def update_traffic_signals(self, _client, _user_data, _topic, payload):
        # todo: localize
        traffic_signal_status = self.__topicSubTrafficSignalStatus.unserialize(
            payload)

        self.traffic_signals_lock.acquire()
        self.traffic_signals[
            traffic_signal_status.route_code] = traffic_signal_status
        self.traffic_signals_lock.release()

    def update_other_vehicle_locations(self, _client, _user_data, topic,
                                       payload):
        # todo: localize
        from_id = Topic.get_from_id(topic)
        if self.target.id != from_id:
            self.other_vehicle_locations_lock.acquire()
            self.other_vehicle_locations[
                from_id] = self.__topicSubStatus.unserialize(payload)
            self.other_vehicle_locations_lock.release()

    def get_monitored_route(self, distance=100.0):
        if distance <= 0:
            return None
        arrow_codes = self.status.schedule.route.arrow_codes
        arrow_codes = arrow_codes[arrow_codes.index(self.status.location.
                                                    arrow_code):]
        route = Route.new_route(
            self.status.location.waypoint_id,
            self.arrow.get_waypoint_ids(
                self.status.schedule.route.arrow_codes[-1])[-1], arrow_codes)
        return self.route.get_sliced_route(route, distance)

    def get_distance_from_preceding_vehicle(self, monitored_route):
        self.other_vehicle_locations_lock.acquire()
        other_vehicle_locations = deepcopy(self.other_vehicle_locations)
        self.other_vehicle_locations_lock.release()

        monitored_waypoint_ids = self.route.get_waypoint_ids(monitored_route)
        distance_from_preceding_vehicle = SIM_CAR.FLOAT_MAX
        if self.status.location.arrow_code is not None and 0 < len(
                other_vehicle_locations):
            other_vehicles_waypoint_ids = list(
                map(lambda x: x.waypoint_id, other_vehicle_locations.values()))
            for i, monitored_waypoint_id in enumerate(monitored_waypoint_ids):
                if monitored_waypoint_id in other_vehicles_waypoint_ids:
                    distance_from_preceding_vehicle = \
                        self.route.get_distance_of_waypoints(monitored_waypoint_ids[:i+1])
                    break
        if distance_from_preceding_vehicle < SIM_CAR.FLOAT_MAX:
            logger.info("distance_from_preceding_vehicle {}[m]".format(
                distance_from_preceding_vehicle))
        return distance_from_preceding_vehicle

    def get_distance_from_stopline(self, monitored_route):
        monitored_arrow_codes = monitored_route.arrow_codes
        distance_from_stopline = SIM_CAR.FLOAT_MAX

        self.traffic_signals_lock.acquire()
        traffic_signals = deepcopy(self.traffic_signals)
        self.traffic_signals_lock.release()

        not_green_traffic_signal_route_codes = list(
            map(
                lambda x: x.route_code,
                filter(
                    lambda x: x.state in
                    [TRAFFIC_SIGNAL.STATE.YELLOW, TRAFFIC_SIGNAL.STATE.RED],
                    traffic_signals.values())))

        new_monitored_route = None
        for i, monitored_arrow_code in enumerate(monitored_arrow_codes):
            for not_green_traffic_signal_route_code in not_green_traffic_signal_route_codes:
                if monitored_arrow_code in not_green_traffic_signal_route_code:
                    not_green_traffic_signal_route = Route.decode_route_code(
                        not_green_traffic_signal_route_code)
                    if monitored_arrow_code == not_green_traffic_signal_route.arrow_codes[
                            0]:
                        waypoint_ids = self.arrow.get_waypoint_ids(
                            monitored_arrow_code)
                        if self.status.location.waypoint_id not in waypoint_ids or \
                                waypoint_ids.index(self.status.location.waypoint_id) <= waypoint_ids.index(
                                    not_green_traffic_signal_route.start_waypoint_id):
                            new_monitored_route = Route.new_route(
                                monitored_route.start_waypoint_id,
                                not_green_traffic_signal_route.
                                start_waypoint_id,
                                monitored_arrow_codes[:i + 1])
                            break
            if new_monitored_route is not None:
                break

        if new_monitored_route is not None:
            distance_from_stopline = self.route.get_route_length(
                new_monitored_route)

        if distance_from_stopline < SIM_CAR.FLOAT_MAX:
            logger.info(
                "distance_from_stopline {}[m]".format(distance_from_stopline))
        return distance_from_stopline

    def __get_movable_distance(self):
        monitored_route = self.get_monitored_route()
        if monitored_route is None:
            return 0.0
        distance_from_preceding_vehicle = self.get_distance_from_preceding_vehicle(
            monitored_route)
        movable_distance = distance_from_preceding_vehicle - SIM_CAR.LOWER_INTER_VEHICLE_DISTANCE

        monitored_route = self.get_monitored_route(movable_distance)
        if monitored_route is None:
            return 0.0
        distance_from_stopline = self.get_distance_from_stopline(
            monitored_route)
        movable_distance = min(
            movable_distance, distance_from_stopline -
            SIM_CAR.LOWER_INTER_TRAFFIC_SIGNAL_DISTANCE)

        return movable_distance

    def update_pose(self):
        movable_distance = self.__get_movable_distance()
        delta_distance = min(self.velocity * self.dt, movable_distance)
        if 0.0 < delta_distance:
            self.np_position, self.status.pose.orientation.rpy.yaw,\
                self.status.location.arrow_code, self.status.location.waypoint_id = \
                self.get_next_pose(delta_distance, self.status.schedule.route)
        self.publish_location()

    def update_route(self):
        index = self.status.schedule.route.arrow_codes.index(
            self.status.location.arrow_code)
        self.status.schedule.route.arrow_codes[:] = self.status.schedule.route.arrow_codes[
            index:]
        self.status.schedule.route.start_waypoint_id = self.status.location.waypoint_id

    def update_velocity(self):
        speed_limit = self.waypoint.get_speed_limit(
            self.status.location.waypoint_id)
        if self.velocity < speed_limit:
            self.velocity += min(SIM_CAR.ACCELERATION_MAX * self.dt,
                                 speed_limit - self.velocity)
        elif speed_limit < self.velocity:
            self.velocity = speed_limit
        return

    def get_next_pose(self, delta_distance, route):
        position, waypoint_id, arrow_code = self.route.get_moved_position(
            self.np_position, delta_distance, route)
        yaw = self.arrow.get_yaw(arrow_code, waypoint_id)
        return position, yaw, arrow_code, waypoint_id

    def update_pose_to_route_start(self):
        self.status.location.waypoint_id = self.status.schedule.route.start_waypoint_id
        self.status.location.arrow_code = self.status.schedule.route.arrow_codes[
            0]
        self.np_position = self.waypoint.get_np_position(
            self.status.location.waypoint_id)
        self.status.pose.orientation.rpy.yaw = \
            self.arrow.get_yaw(self.status.location.arrow_code, self.status.location.waypoint_id)
        self.velocity = 0.0

    def get_state_machine(self, initial_state=SIM_CAR.STATE.STOP):
        machine = StateMachine(
            states=list(SIM_CAR.STATE),
            initial=initial_state,
        )
        machine.add_transitions([{
            "trigger":
            SIM_CAR.TRIGGER.MOVE,
            "source":
            SIM_CAR.STATE.STOP,
            "dest":
            SIM_CAR.STATE.MOVE,
            "conditions": [self.after_state_change_update_schedules]
        }, {
            "trigger":
            SIM_CAR.TRIGGER.MOVE,
            "source":
            SIM_CAR.STATE.MOVE,
            "dest":
            SIM_CAR.STATE.MOVE,
            "conditions": [self.condition_achieved_and_update_schedules]
        }, {
            "trigger":
            SIM_CAR.TRIGGER.STOP,
            "source":
            SIM_CAR.STATE.MOVE,
            "dest":
            SIM_CAR.STATE.STOP,
            "conditions": [self.condition_achieved_and_update_schedules]
        }])
        return machine

    def condition_achieved(self):
        return self.status.location.waypoint_id == self.status.schedule.route.goal_waypoint_id

    def condition_time_limit(self, current_time):
        return self.status.schedule.period.end < current_time

    def after_state_change_update_schedules(self, current_time, schedules):
        schedules[:] = self.get_next_schedules(schedules, current_time)
        self.update_pose_to_route_start()
        return True

    def condition_achieved_and_update_schedules(self, current_time, schedules):
        if self.condition_achieved():
            self.after_state_change_update_schedules(current_time, schedules)
            return True
        return False

    def condition_time_limit_and_update_schedules(self, current_time,
                                                  schedules):
        if self.condition_time_limit(current_time):
            self.after_state_change_update_schedules(current_time, schedules)
            return True
        return False

    def update_status(self):
        schedules = self.get_schedules_and_lock()

        if self.state_machine.state == SIM_CAR.STATE.MOVE:
            self.update_pose()
            self.update_route()
            self.update_velocity()

        if 1 < len(schedules):
            current_time = time()
            next_event = schedules[1].event

            if next_event == SIM_CAR.TRIGGER.MOVE:
                self.state_machine.move(current_time, schedules)
            elif next_event == SIM_CAR.TRIGGER.STOP:
                self.state_machine.stop(current_time, schedules)
            else:
                pass

        self.set_schedules_and_unlock(schedules)
Esempio n. 5
0
class User(EventLoop):
    class TOPIC(object):
        PUBLISH = "pubUser"
        SUBSCRIBE = "subUser"

    class STATE(object):
        LOGIN = "******"
        WAITING = "waiting"
        GETTING_ON = "gettingOn"
        GOT_ON = "gotOn"
        MOVING = "moving"
        GETTING_OUT = "gettingOut"
        GOT_OUT = "gotOut"

    class ACTION(object):
        WAIT = "wait"
        GET_ON = "getOn"
        GET_OUT = "getOut"

    class EVENT(object):
        MOVE_VEHICLE = "moveVehicle"

    def __init__(self, name, waypoint, dt=1.0):
        super().__init__()

        self.topicUserPublish = Topic()
        self.topicUserPublish.set_id(self.event_loop_id)
        self.topicUserPublish.set_root(User.TOPIC.PUBLISH)
        self.topicUserPublish.set_message(user_message)

        self.topicUserSubscribe = Topic()
        self.topicUserSubscribe.set_id(self.event_loop_id)
        self.topicUserSubscribe.set_root(User.TOPIC.SUBSCRIBE)
        self.topicUserSubscribe.set_message(user_message)

        self.name = name
        self.id = self.event_loop_id
        self.state = User.STATE.LOGIN
        self.event = None
        self.action = None
        self.dt = dt
        self.__start_waypoint_id = None
        self.__goal_waypoint_id = None
        self.__vehicleID = None

        self.__waypoint = waypoint

        self.add_on_message_function(self.update_action)
        self.add_on_message_function(self.update_event)

        self.set_subscriber(self.topicUserSubscribe.private + "/schedules")
        self.set_subscriber(self.topicUserSubscribe.private + "/event")
        self.set_main_loop(self.__main_loop)

    def publish_status(self):
        message = self.topicUserPublish.get_template()
        message["name"] = self.name
        message["state"] = self.state
        message["event"] = self.event
        message["schedules"][0]["action"] = self.action
        message["schedules"][0]["start"][
            "waypoint_id"] = self.__start_waypoint_id
        message["schedules"][0]["goal"][
            "waypoint_id"] = self.__goal_waypoint_id
        payload = self.topicUserPublish.serialize(message)
        self.publish(self.topicUserPublish.private, payload)

    def set_waypoint_at_random(self, waypoint_ids=None):
        if waypoint_ids is None:
            waypoint_ids = self.__waypoint.get_waypoint_ids()
        start_waypoint_id = random.choice(waypoint_ids)
        waypoint_ids.remove(start_waypoint_id)
        goal_waypoint_id = random.choice(waypoint_ids)
        self.set_waypoint(start_waypoint_id, goal_waypoint_id)

    def set_waypoint(self, start_waypoint_id, goal_waypoint_id):
        self.set_start_waypoint(start_waypoint_id)
        self.set_goal_waypoint(goal_waypoint_id)

    def set_start_waypoint(self, start_waypoint_id):
        self.__start_waypoint_id = start_waypoint_id

    def set_goal_waypoint(self, goal_waypoint_id):
        self.__goal_waypoint_id = goal_waypoint_id

    def update_action(self, _client, _userdata, topic, payload):
        # print(topic)
        if topic == self.topicUserSubscribe.private + "/schedules":
            message = self.topicUserSubscribe.unserialize(payload)
            self.action = message["schedules"][0]["action"]

    def update_event(self, _client, _userdata, topic, payload):
        if topic == self.topicUserSubscribe.private + "/event":
            message = self.topicUserSubscribe.unserialize(payload)
            self.event = message["event"]

    def update_status(self):
        # print(self.state, self.event, self.action)
        if self.state == User.STATE.LOGIN:
            if self.action == User.ACTION.WAIT:
                self.state = User.STATE.WAITING
                self.action = None
        elif self.state == User.STATE.WAITING:
            if self.action == User.ACTION.GET_ON:
                self.state = User.STATE.GETTING_ON
                self.action = None
        elif self.state == User.STATE.GETTING_ON:
            self.state = User.STATE.GOT_ON
        elif self.state == User.STATE.GOT_ON:
            if self.event == User.EVENT.MOVE_VEHICLE:
                self.state = User.STATE.MOVING
                self.event = None
        elif self.state == User.STATE.MOVING:
            if self.action == User.ACTION.GET_OUT:
                self.state = User.STATE.GETTING_OUT
                self.action = None
        elif self.state == User.STATE.GETTING_OUT:
            self.state = User.STATE.GOT_OUT

    def __main_loop(self):
        self.publish_status()
        while self.state != User.STATE.GOT_OUT:
            sleep(self.dt)
            self.update_status()
            self.publish_status()
        sleep(2)
Esempio n. 6
0
    traffic_signal = TrafficSignal(
        _id=args.id if args.id is not None else str(uuid()),
        route_code=args.route_code)
    process = Process(target=traffic_signal.start, args=[args.host, args.port])
    process.start()

    if args.cycle is not None:
        sleep(5)
        # print("publish cycles")
        topicCycle = Topic()
        topicCycle.set_targets(
            Target.new_target(None, "TrafficSignalCycleSetter"),
            traffic_signal.target)
        topicCycle.set_categories(TrafficSignal.CONST.TOPIC.CATEGORIES.CYCLE)
        mqtt_client.publish(topicCycle.get_path(),
                            topicCycle.serialize(json.loads(args.cycle)))

    if args.schedules is not None:
        sleep(5)
        # print("publish schedules")
        topicSchedules = Topic()
        topicSchedules.set_targets(
            Target.new_target(None, "TrafficSignalSchedulesSetter"),
            traffic_signal.target)
        topicSchedules.set_categories(
            TrafficSignal.CONST.TOPIC.CATEGORIES.SCHEDULES)
        mqtt_client.publish(
            topicSchedules.get_path(),
            topicSchedules.serialize(json.loads(args.schedules)))

    # print("wait join")
Esempio n. 7
0
class EventLoop(object):
    KEEP_ALIVE = 60

    class TOPIC(object):
        PUBLISH = "pub_event_loop"
        SUBSCRIBE = "sub_event_loop"

    def __init__(self, _id=None):
        self.event_loop_id = _id
        if _id is None:
            self.event_loop_id = str(uuid())

        self.__subscribeTopic = Topic()
        self.__subscribeTopic.set_id(self.event_loop_id)
        self.__subscribeTopic.set_root(EventLoop.TOPIC.SUBSCRIBE)
        self.__subscribeTopic.set_message(event_loop_message)

        self.__publishTopic = Topic()
        self.__publishTopic.set_id(self.event_loop_id)
        self.__publishTopic.set_root(EventLoop.TOPIC.PUBLISH)
        self.__publishTopic.set_message(event_loop_message)

        self.__subscribers = {}
        self.__publishers = {}
        self.__client = None
        self.__main_loop = None
        self.__pid = os.getpid()
        self.set_subscriber(self.__subscribeTopic.private)
        self.__on_message_functions = []
        self.__user_data = None
        self.__user_will = None

    def __del__(self):
        if self.__client is not None:
            message = self.__publishTopic.get_template()
            message["action"] = "disconnect"
            message["pid"] = self.__pid
            payload = self.__publishTopic.serialize(message)
            self.publish(self.__publishTopic.private, payload)

            self.__client.disconnect()

    def set_subscriber(self, topic):
        self.__subscribers[str(uuid())] = {"topic": topic}

    def set_user_data(self, user_data):
        self.__user_data = user_data

    def add_on_message_function(self, on_message_function):
        self.__on_message_functions.append(on_message_function)

    def set_main_loop(self, main_loop):
        self.__main_loop = main_loop

    def set_will(self, topic, payload):
        self.__user_will = {"topic": topic, "payload": payload}

    def publish(self, topic, payload, qos=0, retain=False):
        # payload = self.__subscribeTopic.serialize(message)
        self.__client.publish(topic, payload=payload, qos=qos, retain=retain)

    def __on_message(self, client, userdata, message_data):
        payload = message_data.payload.decode("utf-8")
        if self.__subscribeTopic.root in message_data.topic and \
                self.__subscribeTopic.get_id(message_data.topic) == self.event_loop_id:
            message = self.__subscribeTopic.unserialize(payload)
            if message["action"] == "start":
                print(self.__subscribeTopic.root, message)
            if message["action"] == "kill":
                print(self.__subscribeTopic.root, message)
                self.end()
            if message["action"] == "check":
                print(self.__subscribeTopic.root, message)
                self.__check()
        for onMessageFunction in self.__on_message_functions:
            onMessageFunction(client, userdata, message_data.topic, payload)
        return True

    def connect(self, host, port):
        self.__client = mqtt.Client(protocol=mqtt.MQTTv311,
                                    userdata=self.__user_data)

        will = self.__user_will
        print(will)
        if will is None:
            message = self.__publishTopic.get_template()
            message["action"] = "will"
            message["pid"] = self.__pid
            payload = self.__publishTopic.serialize(message)
            will = {"topic": self.__publishTopic.private, "payload": payload}
        self.__client.will_set(will["topic"],
                               payload=will["payload"],
                               qos=2,
                               retain=False)

        self.__client.on_message = self.__on_message
        self.__client.connect(host=host,
                              port=port,
                              keepalive=EventLoop.KEEP_ALIVE)

    def start(self, host="localhost", port=1883):
        self.connect(host, port)

        for subscriber in self.__subscribers.values():
            self.__client.subscribe(subscriber["topic"])

        message = self.__publishTopic.get_template()
        message["time"] = str(int(time()))
        message["action"] = "start"
        message["pid"] = self.__pid
        payload = self.__publishTopic.serialize(message)
        self.publish(self.__publishTopic.private, payload)

        if self.__main_loop is None:
            self.__client.loop_forever()
        else:
            self.__client.loop_start()
            self.__main_loop()

    def end(self):
        self.__client.loop_stop()
        self.__client.disconnect()
        os.kill(self.__pid, SIGKILL)

    def __check(self):
        # todo: main_loop zombie
        message = self.__publishTopic.get_template()
        message["time"] = str(int(time()))
        message["action"] = "ok"
        message["pid"] = self.__pid
        payload = self.__publishTopic.serialize(message)
        self.publish(self.__publishTopic.private, payload)

    def get_pid(self):
        return self.__pid
Esempio n. 8
0
class TrafficSignal(EventLoop):

    CONST = TRAFFIC_SIGNAL

    def __init__(self,
                 _id,
                 route_code,
                 state=TRAFFIC_SIGNAL.STATE.UNKNOWN,
                 processing_cycle=1.0):
        super().__init__(_id)

        self.route_code = route_code
        self.state = state

        self.schedules = []
        self.cycle = None
        self.__processing_cycle = processing_cycle
        self.__check_time = time()
        self.__publish_flag = False

        self.__topicPubStatus = Topic()
        self.__topicPubStatus.set_targets(self.target)
        self.__topicPubStatus.set_categories(
            TRAFFIC_SIGNAL.TOPIC.CATEGORIES.STATUS)

        self.__topicSubSchedules = Topic()
        self.__topicSubSchedules.set_targets(None, self.target)
        self.__topicSubSchedules.set_categories(
            TRAFFIC_SIGNAL.TOPIC.CATEGORIES.SCHEDULES)
        self.__topicSubSchedules.set_message(Schedules)
        self.set_subscriber(self.__topicSubSchedules, self.update_schedules)

        self.__topicSubCycle = Topic()
        self.__topicSubCycle.set_targets(None, self.target)
        self.__topicSubCycle.set_categories(
            TRAFFIC_SIGNAL.TOPIC.CATEGORIES.CYCLE)
        self.__topicSubCycle.set_message(Cycle)
        self.set_subscriber(self.__topicSubCycle, self.update_cycle)

        self.set_main_loop(self.__main_loop)

    @staticmethod
    def get_status(route_code, state):
        return Status.new_data(route_code=route_code, time=time(), state=state)

    def publish_status(self):
        status = TrafficSignal.get_status(self.route_code, self.state)
        payload = self.__topicPubStatus.serialize(status)
        self.publish(self.__topicPubStatus, payload)

    def update_schedules(self, _client, _userdata, _topic, payload):
        self.schedules = self.__topicSubSchedules.unserialize(payload)
        self.__publish_flag = True

    def update_cycle(self, _client, _userdata, _topic, payload):
        self.cycle = self.__topicSubCycle.unserialize(payload)
        self.__publish_flag = True

    def __update_schedules(self):
        current_time = time()
        schedules = []
        if self.route_code in self.schedules:
            schedules = list(
                filter(lambda x: current_time <= x.period.end, self.schedules))

        if self.cycle is not None:
            if len(schedules) < 3:
                if len(schedules) == 0:
                    start_time = current_time
                else:
                    start_time = schedules[-1].period.end
                schedules.append(
                    Schedule.get_schedule_from_cycle([self.target], self.cycle,
                                                     start_time))
        self.schedules = schedules

    def update_status(self):
        if len(self.schedules) == 0:
            if self.state is not None:
                self.state = TRAFFIC_SIGNAL.STATE.UNKNOWN
                self.__publish_flag = True
        else:
            state = self.schedules[0].event
            if self.state != state:
                self.state = state
                self.__publish_flag = True

    def update_check_time(self):
        self.__check_time = time() + TRAFFIC_SIGNAL.LOWER_LIMIT_RATE
        if 0 < len(self.schedules):
            self.__check_time = min(self.__check_time,
                                    self.schedules[0].period.end)

    def __main_loop(self):
        while True:
            if self.__check_time <= time():
                self.__update_schedules()
                self.update_status()
                self.update_check_time()

            if self.__publish_flag:
                self.publish_status()
                self.__check_time = time()
                self.__publish_flag = False

            sleep(self.__processing_cycle)
Esempio n. 9
0
class FleetManager(EventLoop):

    CONST = FLEET_MANAGER

    def __init__(self, _id, name, waypoint, arrow, route, dt=3.0):
        super().__init__(_id)

        self.status = FleetStatus.new_data(name=name,
                                           time=time(),
                                           state=FLEET_MANAGER.STATE.LOG_IN,
                                           relations={})

        self.waypoint = waypoint
        self.arrow = arrow
        self.route = route
        self.relation = Relation()
        self.traffic_signals = self.manager.dict()
        self.state_machine = None
        self.dt = dt

        self.__pubTopicStatus = Topic()
        self.__pubTopicStatus.set_targets(self.target)
        self.__pubTopicStatus.set_categories(
            FLEET_MANAGER.TOPIC.CATEGORIES.STATUS)

        self.__topicSubTrafficSignalStatus = Topic()
        self.__topicSubTrafficSignalStatus.set_targets(
            Target.new_target(None, TRAFFIC_SIGNAL.NODE_NAME), None)
        self.__topicSubTrafficSignalStatus.set_categories(
            TRAFFIC_SIGNAL.TOPIC.CATEGORIES.STATUS)
        self.__topicSubTrafficSignalStatus.set_message(TrafficSignalStatus)
        self.set_subscriber(self.__topicSubTrafficSignalStatus,
                            self.update_traffic_signal_status)

        self.set_main_loop(self.__main_loop)

    def publish_status(self):
        self.status.relations = dict(
            map(
                lambda key:
                (Target.get_code(key),
                 list(map(Target.get_code, self.relation.get_related(key)))),
                self.relation.get_keys()))
        payload = self.__pubTopicStatus.serialize(self.status)
        self.publish(self.__pubTopicStatus, payload)

    def update_traffic_signal_status(self, _client, _userdata, _topic,
                                     payload):
        traffic_signal = self.__topicSubTrafficSignalStatus.unserialize(
            payload)
        self.traffic_signals[traffic_signal["route_code"]] = traffic_signal

    def update_status(self):
        return

    def __main_loop(self):

        while self.status.state != FLEET_MANAGER.STATE.LOG_OUT:
            sleep(self.dt)
            self.update_status()
            self.publish_status()

        return True
Esempio n. 10
0
class EventLoop(object):

    CONST = EVENT_LOOP

    def __init__(self, _id):
        self.manager = Manager()

        self.event_loop_id = _id
        self.target = Target.new_target(self.event_loop_id,
                                        self.__class__.__name__)
        self.__subscribers = {}
        self.__subscribers_lock = self.manager.Lock()
        self.__publishers = {}
        self.__client = None
        self.__main_loop = None
        self.__pid = os.getpid()

        self.__topicPub = Topic()
        self.__topicPub.set_targets(
            Target.new_target(self.event_loop_id, EventLoop.__name__))
        self.__topicPub.set_categories(EVENT_LOOP.TOPIC.CATEGORIES.RESPONSE)

        self.__topicSub = Topic()
        self.__topicSub.set_targets(
            None, Target.new_target(self.event_loop_id, EventLoop.__name__))
        self.__topicSub.set_categories(EVENT_LOOP.TOPIC.CATEGORIES.REQUEST)
        self.__topicSub.set_message(EventLoopMessage)
        self.set_subscriber(self.__topicSub, self.on_event_loop_message)

        self.__user_data = None
        self.__user_will = None

    def __del__(self):
        if self.__client is not None:
            self.end()

    @staticmethod
    def get_message(event, pid):
        return EventLoopMessage.new_data(time=time(), event=event, pid=pid)

    def set_subscriber(self, topic, callback):
        self.__subscribers_lock.acquire()
        self.__subscribers[topic.get_path(use_wild_card=True)] = callback
        self.__subscribers_lock.release()

    def remove_subscriber(self, topic):
        self.__subscribers_lock.acquire()
        self.__subscribers.pop(topic.get_path(use_wild_card=True))
        self.__subscribers_lock.release()
        self.__client.unsubscribe(topic.get_path(use_wild_card=True))

    def set_user_data(self, user_data):
        self.__user_data = user_data

    def set_main_loop(self, main_loop):
        self.__main_loop = main_loop

    def set_will(self, topic, payload):
        self.__user_will = {"topic": topic, "payload": payload}

    def publish(self, topic, payload, qos=0, retain=False):
        self.__client.publish(topic.get_path(),
                              payload=payload,
                              qos=qos,
                              retain=retain)

    def subscribe(self):
        self.__subscribers_lock.acquire()
        subscribe_keys = deepcopy(list(self.__subscribers.keys()))
        self.__subscribers_lock.release()

        for topic in subscribe_keys:
            self.__client.subscribe(topic)

    def response(self, request_path, payload, qos=0, retain=False):
        response_topic = Topic()
        response_topic.set_fix_path(
            self.__topicPub.get_response_path(request_path))
        self.publish(response_topic, payload, qos, retain)

    def __on_connect(self, _client, _userdata, _flags, response_code):
        if response_code == 0:
            self.subscribe()
        else:
            logger.warning('connect status {0}'.format(response_code))

    def on_event_loop_message(self, _client, _userdata, topic, payload):
        event_loop_message = self.__topicSub.unserialize(payload)
        if event_loop_message.event == EVENT_LOOP.STATE.START:
            pass
        if event_loop_message.event == EVENT_LOOP.ACTION.KILL:
            self.end()
        if event_loop_message.event == EVENT_LOOP.ACTION.CHECK:
            self.__check(topic)

    def __on_message(self, client, userdata, message_data):
        try:
            payload = message_data.payload.decode("utf-8")
            self.__subscribers_lock.acquire()
            for subscriber_path, onMessageFunction in self.__subscribers.items(
            ):
                if Topic.is_path_matched(subscriber_path, message_data.topic):
                    onMessageFunction(client, userdata, message_data.topic,
                                      payload)
            self.__subscribers_lock.release()
        except KeyboardInterrupt:
            pass
        except:
            logger.error(traceback.format_exc())
        finally:
            return True

    def ssl_setting(self, ca_path, client_path, key_path):
        self.__client.tls_set(ca_path,
                              certfile=client_path,
                              keyfile=key_path,
                              tls_version=PROTOCOL_TLSv1_2)
        self.__client.tls_insecure_set(True)

    def connect(self,
                host,
                port,
                ca_path=None,
                client_path=None,
                key_path=None):
        self.__client = mqtt.Client(protocol=mqtt.MQTTv311,
                                    userdata=self.__user_data)

        if ca_path is not None and client_path is not None and key_path is not None:
            self.ssl_setting(ca_path, client_path, key_path)

        will = self.__user_will
        if will is None:
            event_loop_message = EventLoop.get_message(EVENT_LOOP.STATE.WILL,
                                                       self.__pid)
            payload = self.__topicPub.serialize(event_loop_message)
            will = {"topic": self.__topicPub.get_path(), "payload": payload}
        self.__client.will_set(will["topic"],
                               payload=will["payload"],
                               qos=2,
                               retain=False)

        self.__client.on_connect = self.__on_connect
        self.__client.on_message = self.__on_message
        self.__client.connect(host=host,
                              port=port,
                              keepalive=EVENT_LOOP.KEEP_ALIVE)

    def start(self,
              host="localhost",
              port=1883,
              ca_path=None,
              client_path=None,
              key_path=None):
        try:
            self.connect(host,
                         port,
                         ca_path=ca_path,
                         client_path=client_path,
                         key_path=key_path)

            event_loop_message = EventLoop.get_message(EVENT_LOOP.STATE.START,
                                                       self.__pid)
            payload = self.__topicPub.serialize(event_loop_message)
            self.publish(self.__topicPub, payload)

            if self.__main_loop is None:
                self.__client.loop_forever()
            else:
                self.__client.loop_start()
                self.__main_loop()
        except KeyboardInterrupt:
            pass
        except:
            logger.error(traceback.format_exc())
        else:
            pass
        finally:
            self.end()
            pass

    def end(self):
        event_loop_message = EventLoop.get_message(EVENT_LOOP.STATE.DISCONNECT,
                                                   self.__pid)
        payload = self.__topicPub.serialize(event_loop_message)
        self.publish(self.__topicPub, payload)

        if self.__main_loop is not None:
            self.__client.loop_stop()
        self.__client.disconnect()
        self.__client = None
        os.kill(self.__pid, SIGKILL)

    def __check(self, request_path):
        # todo: main_loop zombie
        event_loop_message = EventLoop.get_message(EVENT_LOOP.RESPONSE.OK,
                                                   self.__pid)
        payload = self.__topicPub.serialize(event_loop_message)
        self.response(request_path, payload)

    def get_pid(self):
        return self.__pid
Esempio n. 11
0
class SimTaxiFleet(FleetManager):

    CONST = SIM_TAXI_FLEET

    def __init__(self, _id, name, waypoint, arrow, route):
        super().__init__(_id, name, waypoint, arrow, route)

        self.waypoint = waypoint
        self.arrow = arrow
        self.route = route

        self.user_statuses = self.manager.dict()
        self.user_statuses_lock = self.manager.Lock()

        self.vehicle_statuses = self.manager.dict()
        self.vehicle_statuses_lock = self.manager.Lock()

        self.user_schedules = {}
        self.vehicle_schedules = {}
        self.state_machines = {}

        self.__topicPubUserSchedules = Topic()
        self.__topicPubUserSchedules.set_categories(
            FLEET_MANAGER.TOPIC.CATEGORIES.SCHEDULES)

        self.__topicPubVehicleSchedules = Topic()
        self.__topicPubVehicleSchedules.set_categories(
            FLEET_MANAGER.TOPIC.CATEGORIES.SCHEDULES)

        self.__topicSubUserStatus = Topic()
        self.__topicSubUserStatus.set_targets(
            Target.new_target(None, SIM_TAXI_USER.NODE_NAME), None)
        self.__topicSubUserStatus.set_categories(USER.TOPIC.CATEGORIES.STATUS)
        self.__topicSubUserStatus.set_message(UserStatus)
        self.set_subscriber(self.__topicSubUserStatus, self.update_user_status)

        self.__topicSubVehicleStatus = Topic()
        self.__topicSubVehicleStatus.set_targets(
            Target.new_target(None, SIM_TAXI.NODE_NAME), None)
        self.__topicSubVehicleStatus.set_categories(
            VEHICLE.TOPIC.CATEGORIES.STATUS)
        self.__topicSubVehicleStatus.set_message(VehicleStatus)
        self.set_subscriber(self.__topicSubVehicleStatus,
                            self.update_vehicle_status)

    def __publish_user_schedules(self, user_id, payload):
        self.__topicPubUserSchedules.set_targets(
            self.target, Target.new_target(user_id, SIM_TAXI_USER.NODE_NAME))
        self.publish(self.__topicPubUserSchedules, payload)

    def __publish_vehicle_schedules(self, vehicle_id, payload):
        self.__topicPubVehicleSchedules.set_targets(
            self.target, Target.new_target(vehicle_id, SIM_TAXI.NODE_NAME))
        self.publish(self.__topicPubVehicleSchedules, payload)

    def update_user_status(self, _client, _userdata, topic, payload):
        user_id = self.__topicSubUserStatus.get_from_id(topic)
        user_status = self.__topicSubUserStatus.unserialize(payload)

        self.user_statuses_lock.acquire()
        if user_id in self.user_statuses or user_status.state == USER.STATE.LOG_IN:
            self.user_statuses[user_id] = user_status
        self.user_statuses_lock.release()

    def update_vehicle_status(self, _client, _userdata, topic, payload):
        vehicle_id = self.__topicSubVehicleStatus.get_from_id(topic)
        vehicle_status = self.__topicSubVehicleStatus.unserialize(payload)

        self.vehicle_statuses_lock.acquire()
        self.vehicle_statuses[vehicle_id] = vehicle_status
        self.vehicle_statuses_lock.release()

    def update_user_schedules(self, user_statuses):
        for user_id, user_status in user_statuses.items():
            if user_id not in self.user_schedules:
                self.user_schedules[user_id] = [user_status.schedule]
            else:
                while self.user_schedules[user_id][
                        0].id != user_status.schedule.id:
                    self.user_schedules[user_id].pop(0)
                dif_time = user_status.schedule.period.start - self.user_schedules[
                    user_id][0].period.start
                self.user_schedules[user_id] = \
                    Schedule.get_shifted_schedules(self.user_schedules[user_id], dif_time)

    def update_vehicle_schedules(self, vehicle_statuses):
        for vehicle_id, vehicle_status in vehicle_statuses.items():
            if vehicle_id not in self.vehicle_schedules:
                self.vehicle_schedules[vehicle_id] = [vehicle_status.schedule]
            else:
                while self.vehicle_schedules[vehicle_id][
                        0].id != vehicle_status.schedule.id:
                    self.vehicle_schedules[vehicle_id].pop(0)
                dif_time = vehicle_status.schedule.period.start - self.vehicle_schedules[
                    vehicle_id][0].period.start
                self.vehicle_schedules[vehicle_id] = \
                    Schedule.get_shifted_schedules(self.vehicle_schedules[vehicle_id], dif_time)

    def get_dispatchable_vehicle_ids(self, user_status):
        dispatchable_vehicle_ids = list(
            filter(
                lambda x: self.waypoint.get_geohash(self.vehicle_schedules[x][
                    -1].route.goal_waypoint_id)[:SIM_TAXI_FLEET.
                                                DISPATCHABLE_GEOHASH_DIGIT] ==
                self.waypoint.get_geohash(user_status.trip_schedules[
                    0].route.start_waypoint_id)[:SIM_TAXI_FLEET.
                                                DISPATCHABLE_GEOHASH_DIGIT],
                self.vehicle_schedules.keys()))
        return dispatchable_vehicle_ids

    def get_user_request_schedules(self, user_id, current_time):
        user_request_schedule = Schedule.new_schedule(
            [Target.new_target(user_id, SIM_TAXI_USER.NODE_NAME)],
            SIM_TAXI_USER.TRIGGER.REQUEST,
            current_time,
            current_time + 1,
        )
        user_schedules = Schedule.get_merged_schedules(
            self.user_schedules[user_id], [user_request_schedule])
        return user_schedules

    def get_taxi_schedules(self, user_id, user_status, current_time):
        pickup_route, vehicle_id = self.get_pickup_route(user_status)
        if pickup_route is None:
            return None, None

        carry_route = self.get_carry_route(user_status)
        if carry_route is None:
            return None, None

        if self.vehicle_schedules[vehicle_id][
                -1].event == SIM_TAXI.STATE.STAND_BY:
            current_time = self.vehicle_schedules[vehicle_id][-1].period.start

        pickup_schedules, get_on_schedules = self.get_pickup_schedules(
            vehicle_id, user_id, pickup_route, current_time)

        carry_schedules, get_out_schedules = \
            self.get_carry_schedules(vehicle_id, user_id, carry_route, pickup_schedules[-1].period.end)

        deploy_schedules = self.get_deploy_schedules(
            vehicle_id, carry_route, carry_schedules[-1].period.end)

        vehicle_schedules = Schedule.get_merged_schedules(
            self.vehicle_schedules[vehicle_id],
            pickup_schedules + carry_schedules + deploy_schedules)

        user_schedules = Schedule.get_merged_schedules(
            self.user_schedules[user_id], get_on_schedules + get_out_schedules)
        return vehicle_id, vehicle_schedules, user_schedules

    def get_pickup_route(self, user_status):
        start_point = {
            "arrow_code": user_status.trip_schedules[0].route.arrow_codes[0],
            "waypoint_id":
            user_status.trip_schedules[0].route.start_waypoint_id,
        }
        vehicle_ids = self.get_dispatchable_vehicle_ids(user_status)
        if len(vehicle_ids) == 0:
            logger.warning("no dispatchable vehicles")
            return None, None

        goal_points = []
        for vehicle_id, goal_waypoint_id, goal_arrow_code in map(
                lambda x:
            (x, self.vehicle_schedules[x][-1].route.goal_waypoint_id, self.
             vehicle_schedules[x][-1].route.arrow_codes[-1]), vehicle_ids):
            goal_points.append({
                "goal_id": vehicle_id,
                "arrow_code": goal_arrow_code,
                "waypoint_id": goal_waypoint_id,
            })
        routes = self.route.get_shortest_routes(start_point,
                                                goal_points,
                                                reverse=True)
        if len(routes) == 0:
            logger.warning("no pickup_route")
            return None, None
        pickup_route = min(routes.items(),
                           key=lambda x: x[1]["cost"] + self.vehicle_schedules[
                               x[0]][-1].period.end)[1]
        vehicle_id = pickup_route.pop("goal_id")
        pickup_route.pop("cost")
        return pickup_route, vehicle_id

    def get_carry_route(self, user_status):
        start_point = {
            "arrow_code": user_status.trip_schedules[0].route.arrow_codes[0],
            "waypoint_id":
            user_status.trip_schedules[0].route.start_waypoint_id,
        }
        goal_points = [{
            "goal_id":
            None,
            "arrow_code":
            user_status.trip_schedules[0].route.arrow_codes[-1],
            "waypoint_id":
            user_status.trip_schedules[0].route.goal_waypoint_id,
        }]
        routes = self.route.get_shortest_routes(start_point,
                                                goal_points,
                                                reverse=False)
        if len(routes) == 0:
            logger.warning("cant carry_route")
            return None
        carry_route = routes[None]
        carry_route.pop("cost")
        carry_route.pop("goal_id")
        return carry_route

    def get_deploy_route(self):
        pass

    @staticmethod
    def get_pickup_schedules(vehicle_id, user_id, pickup_route, current_time):
        targets = [
            Target.new_target(vehicle_id, SIM_TAXI.NODE_NAME),
            Target.new_target(user_id, SIM_TAXI_USER.NODE_NAME)
        ]
        move_for_picking_up_schedule = Schedule.new_schedule(
            targets, SIM_TAXI.TRIGGER.MOVE, current_time, current_time + 1000,
            pickup_route)
        stop_for_picking_up_schedule = Schedule.new_schedule(
            targets, SIM_TAXI.TRIGGER.STOP, current_time + 1000,
            current_time + 1010,
            Route.new_point_route(pickup_route.goal_waypoint_id,
                                  pickup_route.arrow_codes[-1]))

        waiting_schedule = Schedule.new_schedule(
            targets, SIM_TAXI_USER.TRIGGER.WAIT, current_time,
            current_time + 1000,
            Route.new_point_route(pickup_route.goal_waypoint_id,
                                  pickup_route.arrow_codes[-1]))
        getting_on_schedule = Schedule.new_schedule(
            targets, SIM_TAXI_USER.TRIGGER.GET_ON, current_time + 1000,
            current_time + 1010,
            Route.new_point_route(pickup_route.goal_waypoint_id,
                                  pickup_route.arrow_codes[-1]))
        got_on_schedule = Schedule.new_schedule(
            targets, SIM_TAXI_USER.TRIGGER.GOT_ON, current_time + 1010,
            current_time + 1011,
            Route.new_point_route(pickup_route.goal_waypoint_id,
                                  pickup_route.arrow_codes[-1]))
        return [move_for_picking_up_schedule, stop_for_picking_up_schedule],\
               [waiting_schedule, getting_on_schedule, got_on_schedule]

    @staticmethod
    def get_carry_schedules(vehicle_id, user_id, carry_route, current_time):
        targets = [
            Target.new_target(vehicle_id, SIM_TAXI.NODE_NAME),
            Target.new_target(user_id, SIM_TAXI_USER.NODE_NAME)
        ]
        move_for_discharging_schedules = Schedule.new_schedule(
            targets, SIM_TAXI.TRIGGER.MOVE, current_time, current_time + 1010,
            carry_route)
        stop_for_discharging_schedules = Schedule.new_schedule(
            targets, SIM_TAXI.TRIGGER.STOP, current_time + 1010,
            current_time + 1020,
            Route.new_point_route(carry_route.goal_waypoint_id,
                                  carry_route.arrow_codes[-1]))

        move_schedule = Schedule.new_schedule(
            targets, SIM_TAXI_USER.TRIGGER.MOVE_VEHICLE, current_time,
            current_time + 1010, carry_route)
        getting_out_schedule = Schedule.new_schedule(
            targets, SIM_TAXI_USER.TRIGGER.GET_OUT, current_time + 1010,
            current_time + 1020,
            Route.new_point_route(carry_route.goal_waypoint_id,
                                  carry_route.arrow_codes[-1]))
        got_out_schedule = Schedule.new_schedule(
            [Target.new_target(user_id, SIM_TAXI_USER.NODE_NAME)],
            SIM_TAXI_USER.TRIGGER.GOT_OUT, current_time + 1020,
            current_time + 1021,
            Route.new_point_route(carry_route.goal_waypoint_id,
                                  carry_route.arrow_codes[-1]))
        log_out_schedule = Schedule.new_schedule(
            [Target.new_target(user_id, SIM_TAXI_USER.NODE_NAME)],
            USER.TRIGGER.LOG_OUT, current_time + 1021, current_time + 1022,
            Route.new_point_route(carry_route.goal_waypoint_id,
                                  carry_route.arrow_codes[-1]))
        return [move_for_discharging_schedules, stop_for_discharging_schedules],\
               [move_schedule, getting_out_schedule, got_out_schedule, log_out_schedule]

    @staticmethod
    def get_deploy_schedules(vehicle_id, carry_route, current_time):
        stand_by_schedules = Schedule.new_schedule(
            [
                Target.new_target(vehicle_id, SIM_TAXI.NODE_NAME),
            ], SIM_TAXI.TRIGGER.STAND_BY, current_time, current_time + 86400,
            Route.new_point_route(carry_route.goal_waypoint_id,
                                  carry_route.arrow_codes[-1]))
        return [stand_by_schedules]

    def get_state_machine(
            self, initial_state=SIM_TAXI_FLEET.STATE.WAITING_FOR_USER_LOG_IN):
        machine = StateMachine(
            states=list(SIM_TAXI_FLEET.STATE),
            initial=initial_state,
        )
        machine.add_transitions([
            {
                "trigger":
                SIM_TAXI_FLEET.TRIGGER.WAIT_USER_REQUEST,
                "source":
                SIM_TAXI_FLEET.STATE.WAITING_FOR_USER_LOG_IN,
                "dest":
                SIM_TAXI_FLEET.STATE.WAITING_FOR_USER_REQUEST,
                "conditions":
                [self.condition_user_state_and_publish_user_request_schedules]
            },
            {
                "trigger":
                SIM_TAXI_FLEET.TRIGGER.DISPATCH,
                "source":
                SIM_TAXI_FLEET.STATE.WAITING_FOR_USER_REQUEST,
                "dest":
                SIM_TAXI_FLEET.STATE.WAITING_FOR_TAXI_ARRIVE_AT_USER_LOCATION,
                "conditions":
                [self.condition_user_state_and_publish_new_taxi_schedules]
            },
            {
                "trigger":
                SIM_TAXI_FLEET.TRIGGER.NOTICE,
                "source":
                SIM_TAXI_FLEET.STATE.WAITING_FOR_TAXI_ARRIVE_AT_USER_LOCATION,
                "dest":
                SIM_TAXI_FLEET.STATE.WAITING_FOR_USER_GETTING_ON,
                "conditions":
                [self.condition_user_vehicle_state_and_publish_user_schedules]
            },
            {
                "trigger":
                SIM_TAXI_FLEET.TRIGGER.WAIT_TAXI_ARRIVAL,
                "source":
                SIM_TAXI_FLEET.STATE.WAITING_FOR_USER_GETTING_ON,
                "dest":
                SIM_TAXI_FLEET.STATE.
                WAITING_FOR_TAXI_ARRIVE_AT_USER_DESTINATION,
                "conditions":
                [self.condition_user_state_and_publish_updated_taxi_schedules]
            },
            {
                "trigger":
                SIM_TAXI_FLEET.TRIGGER.NOTICE,
                "source":
                SIM_TAXI_FLEET.STATE.
                WAITING_FOR_TAXI_ARRIVE_AT_USER_DESTINATION,
                "dest":
                SIM_TAXI_FLEET.STATE.WAITING_FOR_USER_GETTING_OUT,
                "conditions":
                [self.condition_user_vehicle_state_and_publish_user_schedules]
            },
        ])
        return machine

    def after_state_change_publish_user_schedules(self, user_id):
        self.__publish_user_schedules(
            user_id,
            self.__topicPubUserSchedules.serialize(
                self.user_schedules[user_id]))
        return True

    def after_state_change_publish_vehicle_schedules(self, vehicle_id):
        self.__publish_vehicle_schedules(
            vehicle_id,
            self.__topicPubVehicleSchedules.serialize(
                self.vehicle_schedules[vehicle_id]))
        return True

    def after_state_change_add_relation(self, user_id, vehicle_id):
        self.relation.add_relation(
            Target.new_target(vehicle_id, SIM_TAXI.NODE_NAME),
            Target.new_target(user_id, SIM_TAXI_USER.NODE_NAME))
        return True

    @staticmethod
    def condition_user_state(user_status, expected_state):
        return user_status.state == expected_state

    def condition_user_state_and_publish_user_request_schedules(
            self, user_id, user_status, excepted_state, current_time):
        if self.condition_user_state(user_status, excepted_state):
            self.user_schedules[user_id] = self.get_user_request_schedules(
                user_id, current_time)
            self.after_state_change_publish_user_schedules(user_id)
            return True
        return False

    def condition_user_state_and_publish_new_taxi_schedules(
            self, user_id, user_status, excepted_state, current_time):
        if self.condition_user_state(user_status, excepted_state):
            vehicle_id, vehicle_schedules, user_schedules = self.get_taxi_schedules(
                user_id, user_status, current_time)
            if vehicle_id is not None:
                self.vehicle_schedules[vehicle_id] = vehicle_schedules
                self.user_schedules[user_id] = user_schedules
                self.after_state_change_publish_vehicle_schedules(vehicle_id)
                self.after_state_change_publish_user_schedules(user_id)
                self.after_state_change_add_relation(user_id, vehicle_id)
                return True
        return False

    def condition_user_state_and_publish_updated_taxi_schedules(
            self, user_id, user_status, excepted_state, vehicle_id,
            current_time):
        if self.condition_user_state(user_status, excepted_state):
            self.user_schedules[user_id][0].period.end = current_time
            self.vehicle_schedules[vehicle_id][0].period.end = current_time
            self.after_state_change_publish_vehicle_schedules(vehicle_id)
            self.after_state_change_publish_user_schedules(user_id)
            return True
        return False

    @staticmethod
    def condition_user_vehicle_state(user_status, vehicle_status,
                                     expected_states):
        return [user_status.state, vehicle_status.state] == expected_states

    def condition_user_vehicle_state_and_publish_user_schedules(
            self, user_id, user_status, vehicle_status, expected_states,
            current_time):
        if self.condition_user_vehicle_state(user_status, vehicle_status,
                                             expected_states):
            self.user_schedules[user_id][0].period.end = current_time
            self.after_state_change_publish_user_schedules(user_id)
            return True
        return False

    def get_user_statuses_and_lock(self):
        self.user_statuses_lock.acquire()
        return deepcopy(self.user_statuses)

    def set_user_statuses_and_unlock(self, user_statuses):
        self.user_statuses.clear()
        self.user_statuses.update(user_statuses)
        self.user_statuses_lock.release()

    def get_vehicle_statuses_and_lock(self):
        self.vehicle_statuses_lock.acquire()
        return deepcopy(self.vehicle_statuses)

    def set_vehicle_statuses_and_unlock(self, vehicle_statuses):
        self.vehicle_statuses.clear()
        self.vehicle_statuses.update(vehicle_statuses)
        self.vehicle_statuses_lock.release()

    def cleanup_status(self, user_statuses):
        user_ids = []
        for user_id, user_status in user_statuses.items():
            if SIM_TAXI_FLEET.TIMEOUT < time() - user_status.time:
                user_ids.append(user_id)
        for user_id in user_ids:
            self.relation.remove_relations_of(
                Target.new_target(user_id, SIM_TAXI_USER.NODE_NAME))
            user_statuses.pop(user_id)
            self.user_schedules.pop(user_id)

    def update_status(self):
        user_statuses = self.get_user_statuses_and_lock()
        vehicle_statuses = self.get_vehicle_statuses_and_lock()

        self.update_user_schedules(user_statuses)
        self.update_vehicle_schedules(vehicle_statuses)
        self.cleanup_status(user_statuses)

        self.update_state_machines(user_statuses, vehicle_statuses)

        self.set_user_statuses_and_unlock(user_statuses)
        self.set_vehicle_statuses_and_unlock(vehicle_statuses)

    def update_state_machines(self, user_statuses, vehicle_statuses):
        current_time = time()

        remove_user_ids = []
        for user_id in user_statuses:
            if user_id not in self.state_machines:
                self.state_machines[user_id] = self.get_state_machine()

            user_status = user_statuses[user_id]
            target_vehicles = self.relation.get_related(
                Target.new_target(user_id, SIM_TAXI_USER.NODE_NAME))
            state = self.state_machines[user_id].state

            if len(target_vehicles) == 0:

                if state == SIM_TAXI_FLEET.STATE.WAITING_FOR_USER_LOG_IN:
                    self.state_machines[user_id].wait_user_request(
                        user_id, user_status, USER.STATE.LOG_IN, current_time)
                elif state == SIM_TAXI_FLEET.STATE.WAITING_FOR_USER_REQUEST:
                    self.state_machines[user_id].dispatch(
                        user_id, user_status, SIM_TAXI_USER.STATE.CALLING,
                        current_time)

            elif len(target_vehicles) == 1:
                vehicle_id = target_vehicles[0].id

                if user_id in map(
                        lambda x: x.id,
                        self.vehicle_schedules[vehicle_id][0].targets):
                    vehicle_status = vehicle_statuses[vehicle_id]

                    if state == SIM_TAXI_FLEET.STATE.WAITING_FOR_TAXI_ARRIVE_AT_USER_LOCATION:
                        self.state_machines[user_id].notice(
                            user_id, user_status, vehicle_status, [
                                SIM_TAXI_USER.STATE.WAITING,
                                SIM_TAXI.STATE.STOP_FOR_PICKING_UP
                            ], current_time)
                    elif state == SIM_TAXI_FLEET.STATE.WAITING_FOR_USER_GETTING_ON:
                        self.state_machines[user_id].wait_taxi_arrival(
                            user_id, user_status, SIM_TAXI_USER.STATE.GOT_ON,
                            vehicle_id, current_time)
                    elif state == SIM_TAXI_FLEET.STATE.WAITING_FOR_TAXI_ARRIVE_AT_USER_DESTINATION:
                        self.state_machines[user_id].notice(
                            user_id, user_status, vehicle_status, [
                                SIM_TAXI_USER.STATE.MOVING,
                                SIM_TAXI.STATE.STOP_FOR_DISCHARGING
                            ], current_time)
                    else:
                        pass
            else:
                logger.error(
                    pformat({"target_vehicles length": target_vehicles}))

            if state == SIM_TAXI_FLEET.STATE.WAITING_FOR_USER_GETTING_OUT:
                if user_status.state in [
                        SIM_TAXI_USER.STATE.GOT_OUT, USER.STATE.LOG_OUT
                ]:
                    remove_user_ids.append(user_id)

        for user_id in remove_user_ids:
            self.relation.remove_relations_of(
                Target.new_target(user_id, SIM_TAXI_USER.NODE_NAME))
            self.state_machines.pop(user_id)
            user_statuses.pop(user_id)
            self.user_schedules.pop(user_id)

        logger.info(
            pformat({
                "fleet":
                dict(
                    map(lambda x: (x[0], x[1].state),
                        self.state_machines.items())),
                "user":
                dict(map(lambda x: (x[0], x[1].state), user_statuses.items())),
                "vehicle":
                dict(
                    map(lambda x: (x[0], x[1].state),
                        vehicle_statuses.items())),
            }))
Esempio n. 12
0
class FleetManager(EventLoop):
    class ACTION(object):
        PUBLISH_RELATIONS = "pub_relations"

    class TOPIC(object):
        PUBLISH = "pub_fleet_manager"
        SUBSCRIBE = "sub_fleet_manager"

    def __init__(self, waypoint, arrow, route):
        super().__init__()

        self.topicUserPublish = Topic()
        self.topicUserPublish.set_root(User.TOPIC.PUBLISH)
        self.topicUserPublish.set_message(user_message)

        self.topicUserSubscribe = Topic()
        self.topicUserSubscribe.set_root(User.TOPIC.SUBSCRIBE)
        self.topicUserSubscribe.set_message(user_message)

        self.topicVehiclePublish = Topic()
        self.topicVehiclePublish.set_root(Vehicle.TOPIC.PUBLISH)
        self.topicVehiclePublish.set_message(vehicle_message)

        self.topicVehicleSubscribe = Topic()
        self.topicVehicleSubscribe.set_root(Vehicle.TOPIC.SUBSCRIBE)
        self.topicVehicleSubscribe.set_message(vehicle_message)

        self.topicTrafficSignalPublish = Topic()
        self.topicTrafficSignalPublish.set_root(TrafficSignal.TOPIC.PUBLISH)
        self.topicTrafficSignalPublish.set_message(traffic_signal_message)

        self.topicFleetManagerPublish = Topic()
        self.topicFleetManagerPublish.set_id(self.event_loop_id)
        self.topicFleetManagerPublish.set_root(FleetManager.TOPIC.PUBLISH)
        self.topicFleetManagerPublish.set_message(fleet_manager_message)

        self.topicFleetManagerSubscribe = Topic()
        self.topicFleetManagerSubscribe.set_id(self.event_loop_id)
        self.topicFleetManagerSubscribe.set_root(FleetManager.TOPIC.SUBSCRIBE)
        self.topicFleetManagerSubscribe.set_message(fleet_manager_message)

        self.waypoint = waypoint
        self.arrow = arrow
        self.route = route

        self.users = {}
        self.vehicles = {}
        self.traffic_signals = {}
        self.relations = {}  # vehicle_id -> user_id, user_id -> vehicle_id

        self.add_on_message_function(self.update_user_status)
        self.add_on_message_function(self.update_vehicle_status)
        self.add_on_message_function(self.update_traffic_signal_status)
        self.add_on_message_function(self.response_request)

        self.set_subscriber(self.topicUserPublish.all)
        self.set_subscriber(self.topicVehiclePublish.all)
        self.set_subscriber(self.topicTrafficSignalPublish.all)
        self.set_subscriber(self.topicFleetManagerSubscribe.all)

    def update_user_status(self, _client, _userdata, topic, payload):
        # print("update_user_status", topic)
        if self.topicUserPublish.root in topic:
            user_id = self.topicUserPublish.get_id(topic)
            message = self.topicUserPublish.unserialize(payload)

            if message["state"] == User.STATE.LOGIN:
                # print("user", User.STATE.LOGIN)
                # todo: move to dispatcher class
                self.dispatch(user_id, message)
            elif message["state"] == User.STATE.WAITING:
                pass
                # print("user", User.STATE.WAITING)
            elif message["state"] == User.STATE.GETTING_ON:
                pass
                # print("user", User.STATE.GETTING_ON)
            elif message["state"] == User.STATE.GOT_ON:
                # print("user", User.STATE.GOT_ON)
                vehicle_id = self.relations[user_id]
                self.vehicles[vehicle_id]["schedules"][0][
                    "action"] = Vehicle.ACTION.MOVE
                payload = self.topicVehicleSubscribe.serialize(
                    {"schedules": self.vehicles[vehicle_id]["schedules"]})
                self.publish(
                    self.topicVehicleSubscribe.root + "/" + vehicle_id +
                    "/schedules", payload)
            elif message["state"] == User.STATE.MOVING:
                pass
                # print("user", User.STATE.MOVING)
            elif message["state"] == User.STATE.GETTING_OUT:
                pass
                # print("user", User.STATE.GETTING_OUT)
            elif message["state"] == User.STATE.GOT_OUT:
                pass
                # print("user", User.STATE.GOT_OUT)
            else:
                print("user", message["state"])

            self.users[user_id] = message

    def update_vehicle_status(self, _client, _userdata, topic, payload):
        if self.topicVehiclePublish.root in topic:
            vehicle_id = self.topicVehiclePublish.get_id(topic)
            message = self.topicVehiclePublish.unserialize(payload)
            # print("update_vehicle_status", topic, message["state"])

            if vehicle_id in self.relations:
                prev_state = self.vehicles[vehicle_id]["state"]
                if message["state"] == SimTaxi.STATE.MOVE_TO_USER:
                    # print("vehicle", SimTaxi.STATE.MOVE_TO_USER)
                    if prev_state == SimTaxi.STATE.STANDBY:
                        user_id = self.relations[vehicle_id]
                        self.users[user_id]["schedules"][0][
                            "action"] = User.ACTION.WAIT
                        self.publish(
                            self.topicUserSubscribe.root + "/" + user_id +
                            "/schedules",
                            self.topicUserSubscribe.serialize({
                                "schedules":
                                self.users[user_id]["schedules"]
                            }))
                elif message["state"] == SimTaxi.STATE.STOP_FOR_PICKING_UP:
                    # print("vehicle", SimTaxi.STATE.STOP_FOR_PICKING_UP)
                    if prev_state == SimTaxi.STATE.MOVE_TO_USER:
                        # print("vehicle", SimTaxi.STATE.STOP_FOR_PICKING_UP, SimTaxi.STATE.MOVE_TO_USER)
                        user_id = self.relations[vehicle_id]
                        self.users[user_id]["schedules"][0][
                            "action"] = User.ACTION.GET_ON
                        self.publish(
                            self.topicUserSubscribe.root + "/" + user_id +
                            "/schedules",
                            self.topicUserSubscribe.serialize({
                                "schedules":
                                self.users[user_id]["schedules"]
                            }))
                elif message[
                        "state"] == SimTaxi.STATE.MOVE_TO_USER_DESTINATION:
                    # print("vehicle", SimTaxi.STATE.MOVE_TO_USER_DESTINATION)
                    if prev_state == SimTaxi.STATE.STOP_FOR_PICKING_UP:
                        # print("vehicle", SimTaxi.STATE.MOVE_TO_USER_DESTINATION, SimTaxi.STATE.STOP_FOR_PICKING_UP)
                        user_id = self.relations[vehicle_id]
                        self.users[user_id]["schedules"][0][
                            "event"] = User.EVENT.MOVE_VEHICLE
                        self.publish(
                            self.topicUserSubscribe.root + "/" + user_id +
                            "/event",
                            self.topicUserSubscribe.serialize(
                                {"event": User.EVENT.MOVE_VEHICLE}))
                elif message["state"] == SimTaxi.STATE.STOP_FOR_DISCHARGING:
                    # print("vehicle", SimTaxi.STATE.STOP_FOR_DISCHARGING)
                    if prev_state == SimTaxi.STATE.MOVE_TO_USER_DESTINATION:
                        user_id = self.relations[vehicle_id]
                        self.users[user_id]["schedules"][0][
                            "action"] = User.ACTION.GET_OUT
                        self.publish(
                            self.topicUserSubscribe.root + "/" + user_id +
                            "/schedules",
                            self.topicUserSubscribe.serialize({
                                "schedules":
                                self.users[user_id]["schedules"]
                            }))
                elif message["state"] == SimTaxi.STATE.MOVE_TO_STANDBY:
                    pass
                    # print("vehicle", SimTaxi.STATE.MOVE_TO_STANDBY)
                elif message["state"] == SimTaxi.STATE.STANDBY:
                    pass
                    # print("vehicle", SimTaxi.STATE.STANDBY)
                else:
                    print("vehicle", message["state"])

            # vehicleSchedule = vehicle.pop("schedule")
            if vehicle_id not in self.vehicles:
                # print("set vehicle", vehicle_id, message["name"])
                self.vehicles[vehicle_id] = message
            else:
                # print("update vehicle", vehicle_id, message["name"])
                self.vehicles[vehicle_id].update(message)

    def update_traffic_signal_status(self, _client, _userdata, topic, payload):
        if self.topicTrafficSignalPublish.root in topic:
            message = self.topicTrafficSignalPublish.unserialize(payload)
            for route in message["routes"]:
                self.traffic_signals[route["route_code"]] = route

    def response_request(self, _client, _userdata, topic, payload):
        if self.topicFleetManagerSubscribe.root in topic:
            message = self.topicFleetManagerSubscribe.unserialize(payload)
            if message["action"] == FleetManager.ACTION.PUBLISH_RELATIONS:
                self.publish_relations()

    def get_dispatchable_vehicles(self):
        return dict(
            filter(lambda x: x[1]["state"] in [SimTaxi.STATE.STANDBY],
                   self.vehicles.items()))

    def dispatch(self, user_id, user_status):
        start_point = {
            "arrow_code":
            self.arrow.get_arrow_codes_from_waypoint_id(
                user_status["schedules"][0]["start"]["waypoint_id"])[0],
            "waypoint_id":
            user_status["schedules"][0]["start"]["waypoint_id"],
        }
        vehicles = self.get_dispatchable_vehicles()
        if len(vehicles) == 0:
            print("no dispatchable vehicles")
            return

        goal_points = []
        for vehicle_id, goal_waypoint_id in map(
                lambda x: (x[0], x[1]["location"]["waypoint_id"]),
                vehicles.items()):
            goal_points.append({
                "goal_id":
                vehicle_id,
                "arrow_code":
                self.arrow.get_arrow_codes_from_waypoint_id(goal_waypoint_id)
                [0],
                "waypoint_id":
                goal_waypoint_id,
            })
        routes = self.route.get_shortest_routes(start_point,
                                                goal_points,
                                                reverse=True)
        if len(routes) == 0:
            print("no pick_up_route")
            return
        pick_up_route = min(routes.items(), key=lambda x: x[1]["cost"])[1]

        vehicle_id = pick_up_route["goal_id"]

        start_point = {
            "arrow_code":
            self.arrow.get_arrow_codes_from_waypoint_id(
                user_status["schedules"][0]["start"]["waypoint_id"])[0],
            "waypoint_id":
            user_status["schedules"][0]["start"]["waypoint_id"],
        }
        goal_points = [{
            "goal_id":
            user_id,
            "arrow_code":
            self.arrow.get_arrow_codes_from_waypoint_id(
                user_status["schedules"][0]["goal"]["waypoint_id"])[0],
            "waypoint_id":
            user_status["schedules"][0]["goal"]["waypoint_id"],
        }]
        routes = self.route.get_shortest_routes(start_point,
                                                goal_points,
                                                reverse=False)
        if len(routes) == 0:
            print("cant carry_route")
            return
        carry_route = min(routes.items(), key=lambda x: x[1]["cost"])[1]

        current_time = time()
        vehicle_schedule = deepcopy(
            self.topicVehicleSubscribe.get_template()["schedules"][0])
        vehicle_schedule.update({
            "name": "pickup",
            "start_time": current_time,
            "duration": 1000,
            "action": Vehicle.ACTION.MOVE,
            "route": {
                "start": {
                    "waypoint_id": pick_up_route["goal_waypoint_id"],
                },
                "goal": {
                    "waypoint_id": pick_up_route["start_waypoint_id"],
                },
                "arrow_codes": pick_up_route["arrow_codes"],
            }
        })
        self.vehicles[vehicle_id]["schedules"].append(vehicle_schedule)

        vehicle_schedule = deepcopy(
            self.topicVehicleSubscribe.get_template()["schedules"][0])
        vehicle_schedule.update({
            "name": "takeOn",
            "start_time": current_time + 1000,
            "duration": 10,
            "action": Vehicle.ACTION.STOP,
        })
        self.vehicles[vehicle_id]["schedules"].append(vehicle_schedule)

        vehicle_schedule = deepcopy(
            self.topicVehicleSubscribe.get_template()["schedules"][0])
        vehicle_schedule.update({
            "name": "carry",
            "start_time": current_time + 1010,
            "duration": 1000,
            "action": Vehicle.ACTION.MOVE,
            "route": {
                "start": {
                    "waypoint_id": carry_route["start_waypoint_id"],
                },
                "goal": {
                    "waypoint_id": carry_route["goal_waypoint_id"],
                },
                "arrow_codes": carry_route["arrow_codes"],
            }
        })
        self.vehicles[vehicle_id]["schedules"].append(vehicle_schedule)

        vehicle_schedule = deepcopy(
            self.topicVehicleSubscribe.get_template()["schedules"][0])
        vehicle_schedule.update({
            "name": "discharge",
            "start_time": current_time + 2010,
            "duration": 10,
            "action": Vehicle.ACTION.STOP,
        })
        self.vehicles[vehicle_id]["schedules"].append(vehicle_schedule)

        vehicle_schedule = deepcopy(
            self.topicVehicleSubscribe.get_template()["schedules"][0])
        vehicle_schedule.update({
            "name": "standBy",
            "start_time": current_time + 2020,
            "duration": 86400,
            "action": SimTaxi.ACTION.STANDBY,
        })
        self.vehicles[vehicle_id]["schedules"].append(vehicle_schedule)

        payload = self.topicVehicleSubscribe.serialize(
            {"schedules": self.vehicles[vehicle_id]["schedules"]})
        self.publish(
            self.topicVehicleSubscribe.root + "/" + vehicle_id + "/schedules",
            payload)

        self.relations[user_id] = vehicle_id
        self.relations[vehicle_id] = user_id

        self.publish_relations()

    def publish_relations(self):
        message = self.topicFleetManagerPublish.get_template()
        message["time"] = time()
        message["relations"] = self.relations
        payload = self.topicFleetManagerPublish.serialize(message)
        self.publish(self.topicFleetManagerPublish.private, payload)
Esempio n. 13
0
class Autoware(Vehicle):
    class ROSTOPIC(object):
        PUBLISH = "/based/lane_waypoints_array"
        SUBSCRIBE = "/closest_waypoint"

    class TOPIC(object):
        PUBLISH = "pub_autoware"
        SUBSCRIBE = "sub_autoware"

    def __init__(self,
                 name,
                 waypoint,
                 arrow,
                 route,
                 waypoint_id,
                 velocity,
                 schedules=None,
                 dt=1.0):
        super().__init__(name, waypoint, arrow, route, waypoint_id, velocity,
                         schedules, dt)

        self.name = name

        self.autowarePublishTopic = Topic()
        self.autowarePublishTopic.set_id(self.name)
        self.autowarePublishTopic.set_root(Autoware.TOPIC.PUBLISH)
        self.autowarePublishTopic.set_message(autoware_message)

        self.autowareSubscribeTopic = Topic()
        self.autowareSubscribeTopic.set_id(self.name)
        self.autowareSubscribeTopic.set_root(Autoware.TOPIC.SUBSCRIBE)
        self.autowareSubscribeTopic.set_message(autoware_message)

        self.pose_index = 0
        self.current_poses = []

        self.add_on_message_function(self.set_autoware_pose)
        self.set_subscriber(self.autowareSubscribeTopic.private +
                            "/closest_waypoint")

    def set_autoware_pose(self, _client, _userdata, topic, payload):
        if topic == self.autowareSubscribeTopic.private + "/closest_waypoint":
            message = self.autowareSubscribeTopic.unserialize(payload)
            if 0 <= message["index"] < len(self.current_poses):
                self.pose_index = message["index"]
                print(self.current_poses[self.pose_index])
                self.arrow_code = self.current_poses[
                    self.pose_index]["arrow_code"]
                self.waypoint_id = self.current_poses[
                    self.pose_index]["waypoint_id"]
                self.position = self.waypoint.get_position(self.waypoint_id)
                self.yaw = self.arrow.get_heading(self.arrow_code,
                                                  self.waypoint_id)
            else:
                print("Lost Autoware.")

    def set_autoware_waypoints(self):
        waypoints = []
        schedule = self.schedules[0]

        arrow_waypoint_array = self.route.get_arrow_waypoint_array({
            "start_waypoint_id":
            schedule["route"]["start"]["waypoint_id"],
            "goal_waypoint_id":
            schedule["route"]["goal"]["waypoint_id"],
            "arrow_codes":
            schedule["route"]["arrow_codes"]
        })
        for arrowWaypoint in arrow_waypoint_array:
            waypoint_id = arrowWaypoint["waypoint_id"]
            waypoints.append({
                "position":
                dict(
                    zip(["x", "y", "z"],
                        self.waypoint.get_position(waypoint_id))),
                "orientation":
                dict(
                    zip(["w", "x", "y", "z"],
                        axangle2quat([0, 0, 1],
                                     self.waypoint.get_yaw(waypoint_id)))),
                "velocity":
                2.0
            })
        if 0 < len(waypoints):
            num = min(10, len(waypoints))
            for i in range(num - 1, 0, -1):
                waypoints[-i]["velocity"] = (
                    i / num) * waypoints[-i - 1]["velocity"]
            self.current_poses = arrow_waypoint_array
            payload = self.autowarePublishTopic.serialize(waypoints)
            self.publish(self.autowarePublishTopic.private + "/waypoints",
                         payload)
Esempio n. 14
0
class Vehicle(EventLoop):

    class TOPIC(object):
        PUBLISH = "pub_vehicle"
        SUBSCRIBE = "sub_vehicle"

        class GEO(object):
            PUBLISH = "pub_geo_vehicle"
            SUBSCRIBE = "sub_geo_vehicle"

    class STATE(object):
        MOVE = "move"
        STOP = "stop"
        WILL = "will"

    class ACTION(object):
        MOVE = "move"
        STOP = "stop"

    def __init__(self, name, waypoint, arrow, route, waypoint_id, velocity, schedules=None, dt=1.0):
        super().__init__()

        self.topicVehiclePublish = Topic()
        self.topicVehiclePublish.set_id(self.event_loop_id)
        self.topicVehiclePublish.set_root(Vehicle.TOPIC.PUBLISH)
        self.topicVehiclePublish.set_message(vehicle_message)

        self.topicVehicleSubscribe = Topic()
        self.topicVehicleSubscribe.set_id(self.event_loop_id)
        self.topicVehicleSubscribe.set_root(Vehicle.TOPIC.SUBSCRIBE)
        self.topicVehicleSubscribe.set_message(vehicle_message)

        self.topicGeoVehiclePublish = Topic()
        self.topicGeoVehiclePublish.set_id(self.event_loop_id)
        self.topicGeoVehiclePublish.set_root(Vehicle.TOPIC.GEO.PUBLISH)
        self.topicGeoVehiclePublish.set_message(geo_vehicle_message)

        self.name = name
        self.state = Vehicle.STATE.STOP
        self.event = None
        self.action = None
        self.waypoint = waypoint
        self.arrow = arrow
        self.route = route
        self.waypoint_id = waypoint_id
        self.position = self.waypoint.get_position(self.waypoint_id)
        self.velocity = velocity
        self.schedules = schedules
        self.dt = dt

        self.arrow_code = self.arrow.get_arrow_codes_from_waypoint_id(waypoint_id)[0]
        self.position = self.waypoint.get_position(self.waypoint_id)
        self.yaw = self.arrow.get_heading(self.arrow_code, self.waypoint_id)

        self.add_on_message_function(self.update_schedules)
        self.add_on_message_function(self.update_event)
        self.set_subscriber(self.topicVehicleSubscribe.private+"/schedules")
        self.set_subscriber(self.topicVehicleSubscribe.private+"/event")
        self.set_main_loop(self.__main_loop)

    def publish_status(self):
        xyz = self.position.data[:]
        message = self.topicVehiclePublish.get_template()
        message["name"] = self.name
        message["state"] = self.state
        message["event"] = self.event
        message["location"]["waypoint_id"] = self.waypoint_id
        message["location"]["geohash"] = self.waypoint.get_geohash(self.waypoint_id)
        message["location"]["arrow_code"] = self.arrow_code
        message["pose"]["position"]["x"] = xyz[0]
        message["pose"]["position"]["y"] = xyz[1]
        message["pose"]["position"]["z"] = xyz[2]
        message["pose"]["orientation"]["yaw"] = self.yaw
        message["schedules"] = self.schedules
        payload = self.topicVehiclePublish.serialize(message)
        self.publish(self.topicVehiclePublish.private, payload)
        self.publish(
            self.topicGeoVehiclePublish.root+"/"+"/".join(self.waypoint.get_geohash(self.waypoint_id)),
            self.event_loop_id)

    def update_schedules(self, _client, _userdata, topic, payload):
        if topic == self.topicVehicleSubscribe.private+"/schedules":
            message = self.topicVehicleSubscribe.unserialize(payload)
            self.schedules = message["schedules"]

    def update_event(self, _client, _userdata, topic, payload):
        if topic == self.topicVehicleSubscribe.private+"/event":
            message = self.topicVehicleSubscribe.unserialize(payload)
            self.event = message["event"]

    def update_status(self):
        return

    def __main_loop(self):
        sleep(1)

        self.publish_status()

        while self.schedules is not None:
                sleep(self.dt)
                self.update_status()
                self.publish_status()

        return True
Esempio n. 15
0
class Autoware(Vehicle):

    CONST = AUTOWARE

    def __init__(self, _id, name, waypoint, arrow, route, dt=0.5):
        super().__init__(_id, name, waypoint, arrow, route, dt=dt)

        self.upper_distance_from_stopline = AUTOWARE.DEFAULT_UPPER_DISTANCE_FROM_STOPLINE
        self.state_machine = self.get_state_machine()

        self.__map_match = MapMatch()
        self.__map_match.set_waypoint(self.waypoint)
        self.__map_match.set_arrow(self.arrow)

        self.ros_closest_waypoint = None
        self.ros_closest_waypoint_lock = self.manager.Lock()

        self.ros_current_pose = None
        self.ros_current_pose_lock = self.manager.Lock()

        self.ros_decisionmaker_states = None
        self.ros_decisionmaker_states_lock = self.manager.Lock()

        self.current_locations = []

        self.traffic_signals = self.manager.dict()
        self.traffic_signals_lock = self.manager.Lock()

        self.__previous_state_command = None

        self.__topicPubBasedLaneWaypointsArray = Topic()
        self.__topicPubBasedLaneWaypointsArray.set_targets(
            self.target, Target.new_target(self.target.id, AUTOWARE.TOPIC.ROS_NODE_NAME))
        self.__topicPubBasedLaneWaypointsArray.set_categories(AUTOWARE.TOPIC.CATEGORIES.BASED_LANE_WAYPOINTS_ARRAY)

        self.__topicPubStateCmd = Topic()
        self.__topicPubStateCmd.set_targets(
            self.target, Target.new_target(self.target.id, AUTOWARE.TOPIC.ROS_NODE_NAME))
        self.__topicPubStateCmd.set_categories(AUTOWARE.TOPIC.CATEGORIES.STATE_CMD)

        self.__topicPubLightColor = Topic()
        self.__topicPubLightColor.set_targets(
            self.target, Target.new_target(self.target.id, AUTOWARE.TOPIC.ROS_NODE_NAME))
        self.__topicPubLightColor.set_categories(AUTOWARE.TOPIC.CATEGORIES.LIGHT_COLOR)

        self.__topicSubCurrentPose = Topic()
        self.__topicSubCurrentPose.set_targets(
            Target.new_target(self.target.id, AUTOWARE.TOPIC.ROS_NODE_NAME), self.target)
        self.__topicSubCurrentPose.set_categories(AUTOWARE.TOPIC.CATEGORIES.CURRENT_POSE)
        self.__topicSubCurrentPose.set_message(ROSMessage.CurrentPose)
        self.set_subscriber(self.__topicSubCurrentPose, self.update_current_pose)

        self.__topicSubClosestWaypoint = Topic()
        self.__topicSubClosestWaypoint.set_targets(
            Target.new_target(self.target.id, AUTOWARE.TOPIC.ROS_NODE_NAME), self.target)
        self.__topicSubClosestWaypoint.set_categories(AUTOWARE.TOPIC.CATEGORIES.CLOSEST_WAYPOINT)
        self.__topicSubClosestWaypoint.set_message(ROSMessage.ClosestWaypoint)
        self.set_subscriber(self.__topicSubClosestWaypoint, self.update_closest_waypoint)

        self.__topicSubDecisionMakerStates = Topic()
        self.__topicSubDecisionMakerStates.set_targets(
            Target.new_target(self.target.id, AUTOWARE.TOPIC.ROS_NODE_NAME), self.target)
        self.__topicSubDecisionMakerStates.set_categories(AUTOWARE.TOPIC.CATEGORIES.DECISION_MAKER_STATES)
        self.__topicSubDecisionMakerStates.set_message(ROSMessage.DecisionMakerStates)
        self.set_subscriber(self.__topicSubDecisionMakerStates, self.update_decisionmaker_states)

        self.__topicSubTrafficSignalStatus = Topic()
        self.__topicSubTrafficSignalStatus.set_targets(Target.new_target(None, TRAFFIC_SIGNAL.NODE_NAME))
        self.__topicSubTrafficSignalStatus.set_categories(TRAFFIC_SIGNAL.TOPIC.CATEGORIES.STATUS)
        self.__topicSubTrafficSignalStatus.set_message(TrafficSignalStatus)
        self.set_subscriber(self.__topicSubTrafficSignalStatus, self.update_traffic_signals)

    def set_upper_distance_from_stopline(self, distance_from_stopline):
        self.upper_distance_from_stopline = distance_from_stopline

    def publish_lane_array(self, route):
        locations = self.route.get_locations(route)
        ros_lane_array = self.get_ros_lane_array_from_locations(locations)

        if ros_lane_array is not None:
            self.current_locations = locations
            payload = self.__topicPubBasedLaneWaypointsArray.serialize(ros_lane_array)
            self.publish(self.__topicPubBasedLaneWaypointsArray, payload)

    def publish_state_command(self, state_command):
        if True:
            payload = self.__topicPubStateCmd.serialize(state_command)
            self.__previous_state_command = state_command
            self.publish(self.__topicPubStateCmd, payload)

    def publish_init_state_command(self, decisionmaker_states):
        if decisionmaker_states.main_state != AUTOWARE.ROS.DECISION_MAKER_STATES.MAIN.INITIAL:
            state_command = ROSMessage.StateCommand.new_data()
            state_command.data = AUTOWARE.ROS.STATE_CMD.MAIN.INIT
            self.publish_state_command(state_command)

    def publish_drive_state_command(self, decisionmaker_states):
        if any([
            all([
                decisionmaker_states.main_state == AUTOWARE.ROS.DECISION_MAKER_STATES.MAIN.MISSION_COMPLETE,
                AUTOWARE.ROS.DECISION_MAKER_STATES.BEHAVIOR.WAIT_ORDERS in decisionmaker_states.behavior_state
            ]),
            decisionmaker_states.main_state == AUTOWARE.ROS.DECISION_MAKER_STATES.MAIN.INITIAL
        ]):
            state_command = ROSMessage.StateCommand.new_data()
            state_command.data = AUTOWARE.ROS.STATE_CMD.MAIN.DRIVE
            self.publish_state_command(state_command)

    def publish_stop_state_command(self, decisionmaker_states):
        if decisionmaker_states.acc_state != AUTOWARE.ROS.DECISION_MAKER_STATES.ACC.STOP:
            state_command = ROSMessage.StateCommand.new_data()
            state_command.data = AUTOWARE.ROS.STATE_CMD.SUB.STOP
            self.publish_state_command(state_command)

    def publish_light_color(self):
        monitored_route = self.get_monitored_route()
        if monitored_route is None:
            traffic_light = AUTOWARE.ROS.TRAFFIC_LIGHT.RED
        else:
            distance_from_stopline = self.get_distance_from_stopline(monitored_route)
            if distance_from_stopline <= self.upper_distance_from_stopline:
                traffic_light = AUTOWARE.ROS.TRAFFIC_LIGHT.RED
            else:
                traffic_light = AUTOWARE.ROS.TRAFFIC_LIGHT.GREEN
        header = ROSMessage.Header.get_template()
        header.stamp.secs = int(time())
        header.stamp.nsecs = int((time() - int(time())) * 1000000000)

        payload = self.__topicPubLightColor.serialize(ROSMessage.LightColor.new_data(
            header=header,
            traffic_light=traffic_light
        ))
        self.publish(self.__topicPubLightColor, payload)

    def update_current_pose(self, _client, _userdata, _topic, payload):
        self.ros_current_pose_lock.acquire()
        self.ros_current_pose = self.__topicSubCurrentPose.unserialize(payload)
        self.ros_current_pose_lock.release()

    def update_closest_waypoint(self, _client, _userdata, _topic, payload):
        self.ros_closest_waypoint_lock.acquire()
        self.ros_closest_waypoint = self.__topicSubClosestWaypoint.unserialize(payload)
        self.ros_closest_waypoint_lock.release()

    def update_decisionmaker_states(self, _client, _userdata, _topic, payload):
        self.ros_decisionmaker_states_lock.acquire()
        self.ros_decisionmaker_states = self.__topicSubDecisionMakerStates.unserialize(payload)
        self.ros_decisionmaker_states_lock.release()

    def update_traffic_signals(self, _client, _user_data, _topic, payload):
        # todo: localize
        traffic_signal_status = self.__topicSubTrafficSignalStatus.unserialize(payload)

        self.traffic_signals_lock.acquire()
        self.traffic_signals[traffic_signal_status.route_code] = traffic_signal_status
        self.traffic_signals_lock.release()

    @staticmethod
    def get_current_pose_from_ros_current_pose(ros_current_pose):
        return Pose.new_data(
            position=Position.new_data(**ros_current_pose.pose.position),
            orientation=Orientation.new_data(
                quaternion=Quaternion.new_data(**ros_current_pose.pose.orientation),
            )
        )

    def update_pose_from_current_pose(self):
        self.ros_current_pose_lock.acquire()
        ros_current_pose = deepcopy(self.ros_current_pose)
        self.ros_current_pose_lock.release()

        if ros_current_pose is not None:
            current_pose = Autoware.get_current_pose_from_ros_current_pose(ros_current_pose)
            self.set_location(
                self.__map_match.get_matched_location_on_arrows(current_pose, self.arrow.get_arrow_codes()))
            self.remove_subscriber(self.__topicSubCurrentPose)

    def update_pose_from_closest_arrow_waypoint(self):
        self.ros_closest_waypoint_lock.acquire()
        ros_closest_waypoint = deepcopy(self.ros_closest_waypoint)
        self.ros_closest_waypoint_lock.release()

        if ros_closest_waypoint is not None and \
                0 <= ros_closest_waypoint.data < len(self.current_locations):
            closest_location = self.current_locations[ros_closest_waypoint.data]
            self.set_waypoint_id_and_arrow_code(
                closest_location.waypoint_id, closest_location.arrow_code)

    def get_ros_lane_array_from_locations(self, locations):
        if 0 == len(locations):
            return None

        ros_lane_array = ROSMessage.LaneArray.new_data()
        ros_lane = ROSMessage.Lane.new_data()
        for location in locations:
            pose = self.waypoint.get_pose(location.waypoint_id)
            ros_waypoint = ROSMessage.Waypoint.new_data()
            ros_waypoint.pose.pose.position.x = pose.position.x
            ros_waypoint.pose.pose.position.y = pose.position.y
            ros_waypoint.pose.pose.position.z = pose.position.z

            ros_waypoint.pose.pose.orientation.z = pose.orientation.quaternion.z
            ros_waypoint.pose.pose.orientation.w = pose.orientation.quaternion.w

            ros_waypoint.twist.twist.linear.x = 0.2 * self.waypoint.get_speed_limit(location.waypoint_id)
            ros_lane.waypoints.append(ros_waypoint)

        ros_lane.header.stamp.secs = int(time()+1)
        ros_lane_array.lanes.append(ros_lane)
        return ros_lane_array

    get_distance_from_stopline = SimCar.get_distance_from_stopline

    get_monitored_route = SimCar.get_monitored_route

    def get_random_route(self):
        import random
        start_point = {
            "arrow_code": self.status.location.arrow_code,
            "waypoint_id": self.status.location.waypoint_id,
        }
        while True:
            while True:
                goal_arrow_code = random.choice(self.arrow.get_arrow_codes())
                goal_waypoint_id = random.choice(self.arrow.get_waypoint_ids(goal_arrow_code))
                if goal_waypoint_id != self.status.location.waypoint_id:
                    break

            goal_id = None
            goal_points = [{
                "goal_id": goal_id,
                "arrow_code": goal_arrow_code,
                "waypoint_id": goal_waypoint_id,
            }]

            shortest_routes = self.route.get_shortest_routes(start_point, goal_points, reverse=False)
            if 0 == len(shortest_routes):
                continue
            shortest_route = shortest_routes[goal_id]
            shortest_route.pop("cost")
            shortest_route.pop("goal_id")
            break

        return Route.new_route(self.status.location.waypoint_id, goal_waypoint_id, shortest_route.arrow_codes)

    def add_random_schedule(self, current_time, schedules):
        synchronize_route_schedule = Schedule.new_schedule(
            [self.target],
            AUTOWARE.TRIGGER.SYNCHRONIZE_ROUTE, current_time, current_time + 5,
            self.route.new_point_route(
                self.status.location.waypoint_id,
                self.status.location.arrow_code
            )
        )
        random_route = self.get_random_route()
        move_schedule = Schedule.new_schedule(
            [self.target],
            AUTOWARE.TRIGGER.MOVE, synchronize_route_schedule.period.end, synchronize_route_schedule.period.end + 100,
            random_route
        )
        stop_schedule = Schedule.new_schedule(
            [self.target],
            AUTOWARE.TRIGGER.STOP, move_schedule.period.end, move_schedule.period.end + 10,
            self.route.new_point_route(
                move_schedule.route.goal_waypoint_id,
                move_schedule.route.arrow_codes[-1]
            )
        )
        get_ready_schedule = Schedule.new_schedule(
            [self.target],
            AUTOWARE.TRIGGER.GET_READY, move_schedule.period.end, move_schedule.period.end + 1,
            self.route.new_point_route(
                move_schedule.route.goal_waypoint_id,
                move_schedule.route.arrow_codes[-1]
            )
        )
        reschedule_schedule = Schedule.new_schedule(
            [self.target],
            AUTOWARE.TRIGGER.SCHEDULE, move_schedule.period.end, move_schedule.period.end + 1,
            self.route.new_point_route(
                move_schedule.route.goal_waypoint_id,
                move_schedule.route.arrow_codes[-1]
            )
        )
        schedules[:] = Schedule.get_merged_schedules(
            schedules,
            [
                synchronize_route_schedule, move_schedule, stop_schedule, get_ready_schedule, reschedule_schedule
            ]
        )

    def get_state_machine(self, initial_state=AUTOWARE.STATE.LAUNCHED):
        machine = StateMachine(
            states=list(AUTOWARE.STATE),
            initial=initial_state,
        )
        machine.add_transitions([
            {
                "trigger": AUTOWARE.TRIGGER.ACTIVATE,
                "source": AUTOWARE.STATE.LAUNCHED, "dest": AUTOWARE.STATE.STAND_BY,
                "conditions": [self.condition_activated_and_update_schedules]
            },
            {
                "trigger": AUTOWARE.TRIGGER.SCHEDULE,
                "source": AUTOWARE.STATE.STAND_BY, "dest": AUTOWARE.STATE.SCHEDULE_UPDATED,
                "conditions": [self.condition_expected_schedules_length_and_update_schedules]
            },
            {
                "trigger": AUTOWARE.TRIGGER.SYNCHRONIZE_ROUTE,
                "source": AUTOWARE.STATE.SCHEDULE_UPDATED, "dest": AUTOWARE.STATE.READY_TO_MOVE,
                "conditions": [self.condition_route_synchronized_and_update_schedules]
            },
            {
                "trigger": AUTOWARE.TRIGGER.MOVE,
                "source": AUTOWARE.STATE.READY_TO_MOVE, "dest": AUTOWARE.STATE.MOVE,
                "conditions": [self.condition_decisionmaker_states_changed_to_drive_and_update_schedules]
            },
            {
                "trigger": AUTOWARE.TRIGGER.STOP,
                "source": AUTOWARE.STATE.MOVE, "dest": AUTOWARE.STATE.STOP,
                "conditions": [self.condition_achieved_and_update_schedules]
            },
            {
                "trigger": AUTOWARE.TRIGGER.GET_READY,
                "source": AUTOWARE.STATE.STOP, "dest": AUTOWARE.STATE.STAND_BY,
                "conditions": [self.condition_time_limit_devisionmaker_states_change_to_initial_and_update_schedules]
            },
        ])
        return machine

    def condition_activated(self, decisionmaker_states):
        return self.condition_location() and \
               self.condition_decisionmaker_states_changed_to_initial(decisionmaker_states)

    def condition_location(self):
        return self.status.location is not None

    @staticmethod
    def condition_decisionmaker_states_changed_to_initial(decisionmaker_states):
        if decisionmaker_states is not None:
            if decisionmaker_states.main_state == AUTOWARE.ROS.DECISION_MAKER_STATES.MAIN.INITIAL:
                return True

    @staticmethod
    def condition_expected_schedules_length(schedules, expected):
        return expected == len(schedules)

    condition_time_limit = SimCar.condition_time_limit

    @staticmethod
    def condition_decisionmaker_states_changed_to_mission_complete(decisionmaker_states):
        if decisionmaker_states is not None:
            if all([
                decisionmaker_states.main_state == AUTOWARE.ROS.DECISION_MAKER_STATES.MAIN.MISSION_COMPLETE,
                AUTOWARE.ROS.DECISION_MAKER_STATES.BEHAVIOR.WAIT_ORDERS in decisionmaker_states.behavior_state
            ]):
                return True
        return False

    def condition_route_synchronized(self, route):
        self.publish_lane_array(route)
        return True

    @staticmethod
    def condition_decisionmaker_states_changed_to_drive(decisionmaker_states):
        if decisionmaker_states is not None:
            if decisionmaker_states.main_state == AUTOWARE.ROS.DECISION_MAKER_STATES.MAIN.DRIVE:
                return True
        return False

    def after_state_change_update_schedules(self, current_time, schedules, _decisionmaker_states=None):
        schedules[:] = self.get_next_schedules(schedules, current_time)
        return True

    def after_state_change_publish_drive(self, decisionmaker_states):
        self.publish_drive_state_command(decisionmaker_states)

    def condition_activated_and_update_schedules(self, current_time, schedules):
        if self.condition_location():
            self.after_state_change_update_schedules(current_time, schedules)
            return True
        else:
            if not self.condition_location():
                self.update_pose_from_current_pose()
            return False

    def condition_expected_schedules_length_and_update_schedules(
            self, current_time, schedules, expected_schedules_length):
        if self.condition_expected_schedules_length(schedules, expected_schedules_length):
            self.after_state_change_update_schedules(current_time, schedules)
            return True
        else:
            self.add_random_schedule(current_time, schedules)
            return False

    def condition_route_synchronized_and_update_schedules(self, current_time, schedules):
        if self.condition_route_synchronized(schedules[2].route):
            self.after_state_change_update_schedules(current_time, schedules)
            return True
        else:
            return False

    def condition_decisionmaker_states_changed_to_drive_and_update_schedules(
            self, current_time, schedules, decisionmaker_states):
        if self.condition_decisionmaker_states_changed_to_drive(decisionmaker_states):
            self.after_state_change_update_schedules(current_time, schedules)
            return True
        else:
            self.publish_drive_state_command(decisionmaker_states)
            return False

    def condition_achieved_and_update_schedules(self, current_time, schedules, decisionmaker_states):
        if self.condition_decisionmaker_states_changed_to_mission_complete(decisionmaker_states):
            self.after_state_change_update_schedules(current_time, schedules)
            return True
        return False

    def condition_time_limit_devisionmaker_states_change_to_initial_and_update_schedules(
            self, current_time, schedules, decisionmaker_states):
        if self.condition_time_limit(current_time):
            if True:
                self.after_state_change_update_schedules(current_time, schedules)
                return True
            else:
                self.publish_drive_state_command(decisionmaker_states)
        return False

    def update_status(self):
        self.update_pose_from_closest_arrow_waypoint()
        if self.status.location is not None and self.status.state == AUTOWARE.STATE.MOVE:
            self.publish_light_color()

        schedules = self.get_schedules_and_lock()

        self.ros_decisionmaker_states_lock.acquire()
        decisionmaker_states = deepcopy(self.ros_decisionmaker_states)
        self.ros_decisionmaker_states_lock.release()

        current_time = time()
        next_event = schedules[1].event

        if next_event == AUTOWARE.TRIGGER.ACTIVATE:
            self.state_machine.activate(current_time, schedules)
        elif next_event == AUTOWARE.TRIGGER.SCHEDULE:
            self.state_machine.schedule(current_time, schedules, 7)
        elif next_event == AUTOWARE.TRIGGER.SYNCHRONIZE_ROUTE:
            self.state_machine.synchronize_route(current_time, schedules)
        elif next_event == AUTOWARE.TRIGGER.MOVE:
            self.state_machine.move(current_time, schedules, decisionmaker_states)
        elif next_event == AUTOWARE.TRIGGER.STOP:
            self.state_machine.stop(current_time, schedules, decisionmaker_states)
        elif next_event == AUTOWARE.TRIGGER.GET_READY:
            self.state_machine.get_ready(current_time, schedules, decisionmaker_states)

        self.set_schedules_and_unlock(schedules)
Esempio n. 16
0
                "baseTime"]
            traffic_signal_cycle_message["period"] = cycle_set[group_name][
                "period"]
            traffic_signal_cycle_message["phases"] = cycle_set[group_name][
                "phases"]
            cycles[intersection_id].append(traffic_signal_cycle_message)

    sleep(1)

    print("publish routes")
    for intersection_id, traffic_signal in traffic_signals.items():
        # print(topicTrafficSignalSubscribe.root+"/"+traffic_signal["instance"].event_loop_id()+"/routes")
        mqtt_client.publish(
            topicTrafficSignalSubscribe.root + "/" +
            traffic_signal["instance"].event_loop_id + "/routes",
            topicTrafficSignalSubscribe.serialize(routes[intersection_id]))

    sleep(5)

    print("publish cycles")
    for intersection_id, traffic_signal in traffic_signals.items():
        # print(topicTrafficSignalSubscribe.root+"/"+traffic_signal["instance"].event_loop_id()+"/cycles")
        mqtt_client.publish(
            topicTrafficSignalSubscribe.root + "/" +
            traffic_signal["instance"].event_loop_id + "/cycles",
            topicTrafficSignalSubscribe.serialize(cycles[intersection_id]))

    sleep(5)

    print("publish schedules")
    mqtt_client.publish(
Esempio n. 17
0
class TrafficSignal(EventLoop):
    class STATE(object):
        GREEN = "green"
        YELLOW = "yellow"
        RED = "red"

    class TOPIC(object):
        PUBLISH = "pub_traffic_signal"
        SUBSCRIBE = "sub_traffic_signal"

    def __init__(self, name, processing_cycle=1.0):
        super().__init__()

        self.trafficSignalPublishTopic = Topic()
        self.trafficSignalPublishTopic.set_id(self.event_loop_id)
        self.trafficSignalPublishTopic.set_root(TrafficSignal.TOPIC.PUBLISH)
        self.trafficSignalPublishTopic.set_message(traffic_signal_message)

        self.trafficSignalSubscribeTopic = Topic()
        self.trafficSignalSubscribeTopic.set_id(self.event_loop_id)
        self.trafficSignalSubscribeTopic.set_root(
            TrafficSignal.TOPIC.SUBSCRIBE)
        self.trafficSignalSubscribeTopic.set_message(traffic_signal_message)

        self.name = name
        self.routes = {}
        self.schedules = {}
        self.cycles = {}
        self.__processing_cycle = processing_cycle
        self.__check_time = time()
        self.__publish_flag = False

        self.add_on_message_function(self.update_routes)
        self.add_on_message_function(self.update_schedules)
        self.add_on_message_function(self.update_cycles)
        self.set_subscriber(self.trafficSignalSubscribeTopic.private +
                            "/routes")
        self.set_subscriber(self.trafficSignalSubscribeTopic.private +
                            "/schedules")
        self.set_subscriber(self.trafficSignalSubscribeTopic.private +
                            "/cycles")
        self.set_main_loop(self.__main_loop)

    def publish_status(self):
        message = self.trafficSignalPublishTopic.get_template()
        message["name"] = self.name
        message["time"] = time()
        message["routes"] = list(self.routes.values())

        payload = self.trafficSignalPublishTopic.serialize(message)
        self.publish(self.trafficSignalPublishTopic.private, payload)

    def update_routes(self, _client, _userdata, topic, payload):
        if topic == self.trafficSignalSubscribeTopic.private + "/routes":
            routes = self.trafficSignalSubscribeTopic.unserialize(payload)
            self.routes = dict(map(lambda x: (x["route_code"], x), routes))
            self.__publish_flag = True

    def update_schedules(self, _client, _userdata, topic, payload):
        if topic == self.trafficSignalSubscribeTopic.private + "/schedules":
            schedules = self.trafficSignalSubscribeTopic.unserialize(payload)
            self.schedules = dict(
                map(lambda x: (x["route_code"], [x]), schedules))
            self.__publish_flag = True

    def update_cycles(self, _client, _userdata, topic, payload):
        if topic == self.trafficSignalSubscribeTopic.private + "/cycles":
            cycles = self.trafficSignalSubscribeTopic.unserialize(payload)
            for cycle in cycles:
                for route_code in cycle["route_codes"]:
                    self.cycles[route_code] = cycle
            self.__publish_flag = True

    @staticmethod
    def get_schedule_from_cycle(cycle, start_time):
        base_time = cycle["base_time"]
        period = cycle["period"]
        phase_time = (start_time - base_time) % period
        state = None
        end_time = start_time
        elapse_time = 0
        for phase in cycle["phases"]:
            elapse_time += phase["duration"]
            state = phase["state"]
            end_time = start_time + (elapse_time - phase_time)
            if phase_time < elapse_time:
                break

        schedule = {
            "state": state,
            "start_time": start_time,
            "duration": end_time - start_time,
        }
        return schedule

    def __update_schedules(self):
        current_time = time()
        for route_code, route in self.routes.items():
            route_schedules = []
            if route_code in self.schedules:
                route_schedules = list(
                    filter(
                        lambda x: current_time <= x["start_time"] + x[
                            "duration"], self.schedules[route_code]))

            if route_code in self.cycles:
                if len(route_schedules) < 3:
                    if len(route_schedules) == 0:
                        start_time = current_time
                    else:
                        start_time = route_schedules[-1][
                            "start_time"] + route_schedules[-1]["duration"]
                    route_schedules.append(
                        self.get_schedule_from_cycle(self.cycles[route_code],
                                                     start_time))

            self.schedules[route_code] = route_schedules

    def update_status(self):
        for route_code, route in self.routes.items():
            if len(self.schedules[route_code]) == 0:
                if route["state"] is not None:
                    self.routes[route_code]["state"] = None
                    self.__publish_flag = True
            else:
                current_schedule = self.schedules[route_code][0]
                state = current_schedule["state"]
                if route["state"] != state:
                    self.routes[route_code]["state"] = state
                    self.__publish_flag = True

    def update_check_time(self):
        if len(self.routes) == 0:
            return 1

        self.__check_time = time() + 600
        for route_schedules in self.schedules.values():
            if 0 < len(route_schedules):
                self.__check_time = min(
                    self.__check_time, route_schedules[0]["start_time"] +
                    route_schedules[0]["duration"])

    def __main_loop(self):
        while True:
            if self.__check_time <= time():
                self.__update_schedules()
                self.update_status()
                self.update_check_time()

            if self.__publish_flag:
                self.publish_status()
                self.__check_time = time()
                self.__publish_flag = False

            sleep(self.__processing_cycle)
Esempio n. 18
0
class User(EventLoop):

    CONST = USER

    def __init__(self, _id, name, dt=1.0):
        super().__init__(_id)

        self.status = UserStatus.new_data(
            name=name,
            time=time(),
            trip_schedules=None,
            state=USER.STATE.LOG_IN,
            schedule=None
        )

        self.state_machine = None
        self.dt = dt

        self.schedules = self.manager.list()
        self.schedules_lock = self.manager.Lock()

        self.__topicPubStatus = Topic()
        self.__topicPubStatus.set_targets(self.target)
        self.__topicPubStatus.set_categories(USER.TOPIC.CATEGORIES.STATUS)

        self.__topicSubSchedules = Topic()
        self.__topicSubSchedules.set_targets(None, self.target)
        self.__topicSubSchedules.set_categories(FLEET_MANAGER.TOPIC.CATEGORIES.SCHEDULES)
        self.__topicSubSchedules.set_message(Schedules)
        self.set_subscriber(self.__topicSubSchedules, self.update_schedules)

        self.set_main_loop(self.__main_loop)

    def set_trip_schedules(self, trip_schedules):
        self.status.trip_schedules = trip_schedules
        self.set_schedules([Schedule.new_schedule(
            targets=[self.target],
            event=USER.TRIGGER.LOG_IN,
            start_time=trip_schedules[0].period.start,
            end_time=trip_schedules[0].period.end
        )])

    def set_schedules(self, schedules):
        self.schedules_lock.acquire()
        self.schedules[:] = schedules
        self.status.schedule = deepcopy(self.schedules[0])
        self.schedules_lock.release()

    def publish_status(self):
        self.status.time = time()
        self.status.state = self.state_machine.state
        payload = self.__topicPubStatus.serialize(self.status)
        self.publish(self.__topicPubStatus, payload)

    def update_status_schedule(self):
        pass

    def update_schedules(self, _client, _userdata, _topic, payload):
        new_schedules = self.__topicSubSchedules.unserialize(payload)

        self.schedules_lock.acquire()
        index = list(map(lambda x: x.id, new_schedules)).index(self.schedules[0].id)
        self.schedules[:] = new_schedules[index:]
        self.update_status_schedule()
        self.schedules_lock.release()

    def get_next_schedules(self, schedules, current_time):
        schedules.pop(0)
        dif_time = current_time - schedules[0].period.start
        schedules = Schedule.get_shifted_schedules(schedules, dif_time)
        self.status.schedule = schedules[0]
        return schedules

    def condition_time_limit(self, current_time, _schedules):
        return self.status.schedule.period.end < current_time

    def after_state_change_update_schedules(self, current_time, schedules):
        schedules[:] = self.get_next_schedules(schedules, current_time)
        return True

    def after_state_change_update_time_limit(self, current_time, duration):
        self.status.schedule.period.start = current_time
        self.status.schedule.period.end = current_time + duration
        return True

    def condition_time_limit_and_update_schedules(self, current_time, schedules):
        if self.condition_time_limit(current_time, schedules):
            self.after_state_change_update_schedules(current_time, schedules)
            return True
        return False

    def get_schedules_and_lock(self):
        self.schedules_lock.acquire()
        return deepcopy(self.schedules)

    def set_schedules_and_unlock(self, schedules):
        self.schedules[:] = schedules
        self.schedules_lock.release()

    def update_status(self):
        schedules = self.get_schedules_and_lock()

        self.set_schedules_and_unlock(schedules)
        return

    def __main_loop(self):

        while self.status.state != USER.STATE.LOG_OUT:
            sleep(self.dt)
            self.update_status()
            self.publish_status()

        return True
Esempio n. 19
0
class Vehicle(EventLoop):

    CONST = VEHICLE

    def __init__(self, _id, name, waypoint, arrow, route, dt=1.0):
        super().__init__(_id)

        self.status = VehicleStatus.new_data(name=name,
                                             time=time(),
                                             state=VEHICLE.STATE.LOG_IN,
                                             schedule=None,
                                             location=None,
                                             pose=None)

        self.waypoint = waypoint
        self.arrow = arrow
        self.route = route
        self.state_machine = None
        self.np_position = None
        self.dt = dt

        self.schedules = self.manager.list()
        self.schedules_lock = self.manager.Lock()

        self.__topicPubStatus = Topic()
        self.__topicPubStatus.set_targets(self.target)
        self.__topicPubStatus.set_categories(VEHICLE.TOPIC.CATEGORIES.STATUS)

        self.__topicSubSchedules = Topic()
        self.__topicSubSchedules.set_targets(None, self.target)
        self.__topicSubSchedules.set_categories(
            FLEET_MANAGER.TOPIC.CATEGORIES.SCHEDULES)
        self.__topicSubSchedules.set_message(Schedules)
        self.set_subscriber(self.__topicSubSchedules, self.update_schedules)

        self.__topicPubGeotopic = Topic()
        self.__topicPubGeotopic.set_targets(self.target, None)

        self.set_main_loop(self.__main_loop)

    def set_waypoint_id_and_arrow_code(self, waypoint_id, arrow_code):
        self.set_location(
            Location.new_location(waypoint_id, arrow_code,
                                  self.waypoint.get_geohash(waypoint_id)))

    def set_location(self, location):
        self.status.location = location
        self.update_np_position()
        self.status.pose = Pose.new_data(
            position=Position.new_position_from_np_position(self.np_position),
            orientation=Orientation.new_data(rpy=Rpy.new_data(
                yaw=self.arrow.get_yaw(self.status.location.arrow_code,
                                       self.status.location.waypoint_id))))

    def update_np_position(self):
        self.np_position = self.waypoint.get_np_position(
            self.status.location.waypoint_id)

    def set_schedules(self, schedules):
        self.schedules[:] = schedules
        self.status.schedule = deepcopy(self.schedules[0])

    def publish_status(self):
        self.status.time = time()
        self.status.state = self.state_machine.state
        if self.status.location is not None:
            self.status.location.geohash = self.waypoint.get_geohash(
                self.status.location.waypoint_id)
        if self.np_position is not None:
            self.status.pose.position = Position.new_position_from_np_position(
                self.np_position)
        payload = self.__topicPubStatus.serialize(self.status)
        self.publish(self.__topicPubStatus, payload)

    def publish_geotopic(self):
        if self.status.location is not None:
            self.__topicPubGeotopic.set_categories(
                VEHICLE.TOPIC.CATEGORIES.GEOTOPIC +
                list(self.status.location.geohash))
            self.publish(self.__topicPubGeotopic,
                         self.__topicPubGeotopic.serialize(self.target))

    def update_status_schedule(self):
        pass

    def update_schedules(self, _client, _userdata, _topic, payload):
        new_schedules = self.__topicSubSchedules.unserialize(payload)
        index = list(map(lambda x: x.id,
                         new_schedules)).index(self.status.schedule.id)

        self.schedules_lock.acquire()
        self.schedules[:] = new_schedules[index:]
        self.update_status_schedule()
        self.schedules_lock.release()

    def get_next_schedules(self, schedules, current_time):
        schedules.pop(0)
        dif_time = current_time - schedules[0].period.start
        schedules = Schedule.get_shifted_schedules(schedules, dif_time)
        self.status.schedule = schedules[0]
        return schedules

    def get_schedules_and_lock(self):
        self.schedules_lock.acquire()
        return deepcopy(self.schedules)

    def set_schedules_and_unlock(self, schedules):
        self.schedules[:] = schedules
        self.schedules_lock.release()

    def update_status(self):
        schedules = self.get_schedules_and_lock()

        self.set_schedules_and_unlock(schedules)
        return

    def __main_loop(self):

        while self.status.state != VEHICLE.STATE.LOG_OUT:
            sleep(self.dt)
            self.update_status()
            self.publish_status()
            self.publish_geotopic()

        return True