Example #1
0
    def post(self):
        """
        Clients report runtime status.

        The client must PUT a json object which can be converted to
        runtime_status_pb2.RuntimeStatus.
        """
        try:
            new_status = json_format.ParseDict(
                flask.request.get_json(), runtime_status_pb2.RuntimeStatus())
        except Exception as e:
            error_msg = 'RuntimeStatusApi: Cannot parse given data "{}"'.format(
                flask.request.get_json())
            glog.error(error_msg)
            return error_msg, httplib.BAD_REQUEST

        # Merge status.
        glog.info('RuntimeStatusApi: Put status:\n{}'.format(new_status))
        cur_status = runtime_status.RuntimeStatus
        for module in new_status.modules:
            cur_status.get_module(module.name).MergeFrom(module)
        for hardware in new_status.hardware:
            cur_status.get_hardware(hardware.name).MergeFrom(hardware)
        cur_status.get_tools().MergeFrom(new_status.tools)

        cur_status.broadcast_status_if_changed()
        return 'OK', httplib.OK
Example #2
0
    def report_hardware_status(hardware_status_list):
        """Report hardware status to HMI."""
        status_pb = runtime_status_pb2.RuntimeStatus()
        for hardware_status in hardware_status_list:
            status_pb.hardware.add().MergeFrom(hardware_status)

        json_dict = json_format.MessageToDict(status_pb, False, True)
        try:
            req = requests.post(
                gflags.FLAGS.hmi_runtime_status_api, json=json_dict)
            glog.info('Put HardwareStatus: {}'.format(req.json()))
        except Exception as e:
            glog.error('Failed to put HardwareStatus: {}'.format(e))
Example #3
0
    def update(cls, status_json):
        """Update runtime status."""
        new_status = json_format.ParseDict(status_json,
                                           runtime_status_pb2.RuntimeStatus())
        # Merge status.
        Config.log.debug('RuntimeStatus: Update status:\n%s', str(new_status))
        for module in new_status.modules:
            cls.get_module(module.name).MergeFrom(module)
        for hardware in new_status.hardware:
            cls.get_hardware(hardware.name).MergeFrom(hardware)
        cls.get_tools().MergeFrom(new_status.tools)

        cls.broadcast_status_if_changed()
Example #4
0
    def __init__(self, record_file, speedmultiplier, completepath, replan):
        """Init player."""
        self.firstvalid = False
        self.logger = Logger.get_logger(tag="RtkPlayer")
        self.logger.info("Load record file from: %s" % record_file)
        try:
            file_handler = open(record_file, 'r')
        except:
            self.logger.error("Cannot find file: " + record_file)
            file_handler.close()
            sys.exit(0)

        self.data = genfromtxt(file_handler, delimiter=',', names=True)
        file_handler.close()

        self.localization = localization_pb2.LocalizationEstimate()
        self.chassis = chassis_pb2.Chassis()
        self.padmsg = pad_msg_pb2.PadMessage()
        self.localization_received = False
        self.chassis_received = False

        self.planning_pub = rospy.Publisher('/apollo/planning',
                                            planning_pb2.ADCTrajectory,
                                            queue_size=1)

        self.speedmultiplier = speedmultiplier / 100
        self.terminating = False
        self.sequence_num = 0

        b, a = signal.butter(6, 0.05, 'low')
        self.data['acceleration'] = signal.filtfilt(b, a,
                                                    self.data['acceleration'])

        self.start = 0
        self.end = 0
        self.closestpoint = 0
        self.automode = False

        self.replan = (replan == 't')
        self.completepath = (completepath == 't')

        self.estop = False

        # Report status to HMI.
        status_pb = runtime_status_pb2.RuntimeStatus()
        status_pb.tools.planning_ready = True
        hmi_status_helper.HMIStatusHelper.report_status(status_pb)

        self.logger.info("Planning Ready")
Example #5
0
class RuntimeStatus(object):
    """Global runtime status."""

    pb_singleton = runtime_status_pb2.RuntimeStatus()
    pb_fingerprint = 0

    module_dict = {}
    hardware_dict = {}
    playable_duration = 0

    @classmethod
    def reset(cls, check_playable_file=False):
        """Reset runtime status to start."""
        cls.pb_singleton.Clear()
        cls.pb_fingerprint = 0
        cls.module_dict.clear()
        cls.hardware_dict.clear()

        tool_status = cls.get_tools()
        if check_playable_file and cls.stat_playable_duration() > 0:
            tool_status.recording_status = runtime_status_pb2.ToolStatus.RECORDING_FINISHED
            tool_status.playing_status = runtime_status_pb2.ToolStatus.PLAYING_READY_TO_CHECK
        else:
            tool_status.recording_status = runtime_status_pb2.ToolStatus.RECORDING_READY_TO_CHECK
            tool_status.playing_status = runtime_status_pb2.ToolStatus.PLAYING_NOT_READY
        cls._calculate()

    @classmethod
    def get_module(cls, module_name):
        """Get module status by name."""
        if cls.module_dict.get(module_name) is None:
            # Init module status for once.
            module_status = cls.pb_singleton.modules.add(name=module_name)
            cls.module_dict[module_name] = module_status
        return cls.module_dict[module_name]

    @classmethod
    def get_hardware(cls, hardware_name):
        """Get harware status by name."""
        if cls.hardware_dict.get(hardware_name) is None:
            # Init hardware status for once.
            hardware_status = cls.pb_singleton.hardware.add(name=hardware_name)
            cls.hardware_dict[hardware_name] = hardware_status
        return cls.hardware_dict[hardware_name]

    @classmethod
    def get_tools(cls):
        """Get tools status."""
        return cls.pb_singleton.tools

    @classmethod
    def status_json(cls):
        """Convert status to json dict."""
        def pb_to_json(pb, include_default_values=False):
            """Convert proto to json dict."""
            return json_format.MessageToDict(pb, include_default_values, True)

        def pb_dict_to_json(pb_dict):
            """Convert {key: value_pb} to {key, value_dict}."""
            return {
                key: pb_to_json(value_pb)
                for key, value_pb in pb_dict.iteritems()
            }

        return {
            'timestamp': cls._current_timestamp(),
            'modules': pb_dict_to_json(cls.module_dict),
            'hardware': pb_dict_to_json(cls.hardware_dict),
            'tools': pb_to_json(cls.pb_singleton.tools, True),
        }

    @classmethod
    def broadcast_status_if_changed(cls):
        """Broadcast status change."""
        cls._calculate()
        new_fingerprint = hash(str(cls.pb_singleton))
        if cls.pb_fingerprint != new_fingerprint:
            flask_socketio.emit('new_status',
                                cls.status_json(),
                                broadcast=True,
                                namespace='/runtime_status')
            cls.pb_fingerprint = new_fingerprint

    @classmethod
    def _calculate(cls):
        """Update runtime status fields which need to be calculated."""
        conf_pb = config.Config.get_pb()

        modules_and_hardware_ready = cls.are_all_modules_ready(
        ) and cls.are_all_hardware_ready()
        cls._calculate_recording_status(modules_and_hardware_ready)
        cls._calculate_playing_status(modules_and_hardware_ready)
        cls._calculate_guide_message()

    @classmethod
    def are_all_modules_ready(cls):
        """Check if all modules are ready."""
        for mod in config.Config.get_pb().modules:
            mod_status = cls.get_module(mod.name).status
            if mod_status != runtime_status_pb2.ModuleStatus.STARTED:
                return False
        return True

    @classmethod
    def are_all_hardware_ready(cls):
        """Check if all modules are ready."""
        for hw in config.Config.get_pb().hardware:
            hw_status = cls.get_hardware(hw.name).status
            if hw_status != int(runtime_status_pb2.HardwareStatus.OK):
                return False
        return True

    @classmethod
    def stat_playable_duration(cls):
        """Stat playable duration."""
        file_to_play = config.Config.get_realpath(gflags.FLAGS.file_to_play)
        if os.path.exists(file_to_play):
            with open(file_to_play, 'r') as f:
                kFreq = 100
                cls.playable_duration = sum([1 for line in f]) / kFreq
        else:
            cls.playable_duration = 0
        return cls.playable_duration

    @classmethod
    def _calculate_recording_status(cls, modules_and_hardware_ready):
        """Calculate recording status."""
        CHECKING = runtime_status_pb2.ToolStatus.RECORDING_CHECKING
        READY_TO_START = runtime_status_pb2.ToolStatus.RECORDING_READY_TO_START

        tool_status = cls.get_tools()
        recording_status = tool_status.recording_status
        if recording_status == CHECKING and modules_and_hardware_ready:
            tool_status.recording_status = READY_TO_START
        elif recording_status == READY_TO_START and not modules_and_hardware_ready:
            tool_status.recording_status = CHECKING

    @classmethod
    def _calculate_playing_status(cls, modules_and_hardware_ready):
        """Calculate playing status."""
        ToolStatus = runtime_status_pb2.ToolStatus
        tool_status = cls.get_tools()

        playing_status = tool_status.playing_status
        if tool_status.playing_status == ToolStatus.PLAYING_NOT_READY:
            if tool_status.recording_status == ToolStatus.RECORDING_FINISHED:
                if cls.playable_duration > 0:
                    tool_status.playing_status = ToolStatus.PLAYING_READY_TO_CHECK
                else:
                    glog.info(
                        'RuntimeStatus::_calculate_playing_status: No file to play'
                    )
        elif (playing_status == ToolStatus.PLAYING_CHECKING
              and modules_and_hardware_ready and tool_status.planning_ready):
            tool_status.playing_status = ToolStatus.PLAYING_READY_TO_START
            glog.info(
                'RuntimeStatus::_calculate_playing_status: All modules/hardware are ready'
            )
        elif playing_status == ToolStatus.PLAYING_READY_TO_START and not (
                modules_and_hardware_ready and tool_status.planning_ready):
            tool_status.playing_status = ToolStatus.PLAYING_CHECKING
            glog.info('RuntimeStatus::_calculate_playing_status: ' \
                      'Not all modules/hardware are ready')

    @classmethod
    def _calculate_guide_message(cls):
        """Update guide message according to status."""
        ToolStatus = runtime_status_pb2.ToolStatus
        tool_status = cls.get_tools()

        if tool_status.recording_status == ToolStatus.RECORDING_READY_TO_CHECK:
            tool_status.message = 'Before recording, you need to setup the system.'
        elif tool_status.recording_status == ToolStatus.RECORDING_CHECKING:
            tool_status.message = 'Waiting for modules and hardware.'
        elif tool_status.recording_status == ToolStatus.RECORDING_READY_TO_START:
            tool_status.message = 'Now you are ready to record.'
        elif (tool_status.recording_status == ToolStatus.RECORDING
              or tool_status.playing_status == ToolStatus.PLAYING):
            if not tool_status.message.isdigit():
                # The timestamp we started recording or playing.
                tool_status.message = str(cls._current_timestamp())
        elif (tool_status.recording_status == ToolStatus.RECORDING_FINISHED
              and tool_status.playing_status == ToolStatus.PLAYING_NOT_READY):
            tool_status.message = 'The recorded data/log/garage.csv is invalid.<br/>' \
                                  'Please fix, or simply try recording again by clicking "New".'
        elif tool_status.playing_status == ToolStatus.PLAYING_CHECKING:
            if tool_status.planning_ready:
                tool_status.message = 'Waiting for modules and hardware.'
            else:
                tool_status.message = 'Waiting for planning ready.'
        elif tool_status.playing_status == ToolStatus.PLAYING_READY_TO_CHECK:
            tool_status.message = '{}s of driving was recorded.<br/>' \
                                  'Before playing, please setup the system.' \
                                  .format(cls.playable_duration)
        elif tool_status.playing_status == ToolStatus.PLAYING_READY_TO_START:
            tool_status.message = 'Make sure the OPERATOR is ready! Now you are good to go.'
        else:
            tool_status.message = 'Something goes wrong.<br/>Please record again or RESET ALL.'

    @classmethod
    def _current_timestamp(cls):
        """Current timestamp in milliseconds."""
        return int(time.time() * 1000)
Example #6
0
class RuntimeStatus(object):
    """Global runtime status."""

    pb_singleton = runtime_status_pb2.RuntimeStatus()
    pb_fingerprint = 0
    playable_duration = 0

    @classmethod
    def reset(cls, check_playable_file=False):
        """Reset runtime status to start."""
        cls.pb_singleton.Clear()
        cls.pb_fingerprint = 0

        tool_status = cls.get_tools()
        if check_playable_file and cls.stat_playable_duration() > 0:
            tool_status.recording_status = ToolStatus.RECORDING_FINISHED
            tool_status.playing_status = ToolStatus.PLAYING_READY_TO_CHECK
        else:
            tool_status.recording_status = ToolStatus.RECORDING_READY_TO_CHECK
            tool_status.playing_status = ToolStatus.PLAYING_NOT_READY
        cls._calculate()

    @classmethod
    def update(cls, status_json):
        """Update runtime status."""
        new_status = json_format.ParseDict(status_json,
                                           runtime_status_pb2.RuntimeStatus())
        # Merge status.
        Config.log.debug('RuntimeStatus: Update status:\n%s', str(new_status))
        for module in new_status.modules:
            cls.get_module(module.name).MergeFrom(module)
        for hardware in new_status.hardware:
            cls.get_hardware(hardware.name).MergeFrom(hardware)
        cls.get_tools().MergeFrom(new_status.tools)

        cls.broadcast_status_if_changed()

    @classmethod
    def get_module(cls, module_name):
        """Get module status by name."""
        mod = cls.__find_by_name(module_name, cls.pb_singleton.modules)
        # Init module status if not exist.
        return mod if mod else cls.pb_singleton.modules.add(name=module_name)

    @classmethod
    def get_hardware(cls, hardware_name):
        """Get hardware status by name."""
        hdw = cls.__find_by_name(hardware_name, cls.pb_singleton.hardware)
        # Init hardware status for once.
        return hdw if hdw else cls.pb_singleton.hardware.add(
            name=hardware_name)

    @classmethod
    def get_tools(cls):
        """Get tools status."""
        return cls.pb_singleton.tools

    @classmethod
    def status_json(cls):
        """Convert status to json dict."""
        json_dict = json_format.MessageToDict(cls.pb_singleton, True, True)
        # Inject current timestamp.
        json_dict['timestamp'] = cls._current_timestamp()
        return json_dict

    @classmethod
    def broadcast_status_if_changed(cls):
        """Broadcast status change."""
        cls._calculate()
        new_fingerprint = hash(str(cls.pb_singleton))
        if cls.pb_fingerprint != new_fingerprint:
            flask_socketio.emit('current_status',
                                cls.status_json(),
                                broadcast=True,
                                namespace='/io_frontend')
            cls.pb_fingerprint = new_fingerprint

    @classmethod
    def _calculate(cls):
        """Update runtime status fields which need to be calculated."""
        modules_and_hardware_ready = cls.are_record_replay_modules_ready(
        ) and cls.are_all_hardware_ready()
        cls._calculate_recording_status(modules_and_hardware_ready)
        cls._calculate_playing_status(modules_and_hardware_ready)
        cls._calculate_guide_message()

    @classmethod
    def are_record_replay_modules_ready(cls):
        """Check if all modules are ready."""
        for mod in Config.record_replay_required_modules:
            mod_status = cls.get_module(mod).status
            if mod_status != runtime_status_pb2.ModuleStatus.STARTED:
                return False
        return True

    @classmethod
    def are_all_hardware_ready(cls):
        """Check if all modules are ready."""
        for hw in Config.get_pb().hardware:
            hw_status = cls.get_hardware(hw.name).status
            if hw_status != int(runtime_status_pb2.HardwareStatus.OK):
                return False
        return True

    @classmethod
    def stat_playable_duration(cls):
        """Stat playable duration."""
        file_to_play = Config.get_realpath(gflags.FLAGS.file_to_play)
        if os.path.exists(file_to_play):
            with open(file_to_play, 'r') as f:
                kFreq = 100
                cls.playable_duration = sum([1 for _ in f]) / kFreq
        else:
            cls.playable_duration = 0
        return cls.playable_duration

    @classmethod
    def _calculate_recording_status(cls, modules_and_hardware_ready):
        """Calculate recording status."""
        tool_status = cls.get_tools()
        recording_status = tool_status.recording_status
        if (recording_status == ToolStatus.RECORDING_CHECKING
                and modules_and_hardware_ready):
            tool_status.recording_status = ToolStatus.RECORDING_READY_TO_START
        elif (recording_status == ToolStatus.RECORDING_READY_TO_START
              and not modules_and_hardware_ready):
            tool_status.recording_status = ToolStatus.RECORDING_CHECKING

    @classmethod
    def _calculate_playing_status(cls, modules_and_hardware_ready):
        """Calculate playing status."""
        tool_status = cls.get_tools()

        playing_status = tool_status.playing_status
        if tool_status.playing_status == ToolStatus.PLAYING_NOT_READY:
            if tool_status.recording_status == ToolStatus.RECORDING_FINISHED:
                if cls.playable_duration > 0:
                    tool_status.playing_status = \
                    ToolStatus.PLAYING_READY_TO_CHECK
                else:
                    Config.log.info(
                        'RuntimeStatus::_calculate_playing_status: '
                        'No file to play')
        elif (playing_status == ToolStatus.PLAYING_CHECKING
              and modules_and_hardware_ready and tool_status.planning_ready):
            tool_status.playing_status = ToolStatus.PLAYING_READY_TO_START
            Config.log.info('RuntimeStatus::_calculate_playing_status: '
                            'All modules/hardware are ready')
        elif playing_status == ToolStatus.PLAYING_READY_TO_START and not (
                modules_and_hardware_ready and tool_status.planning_ready):
            tool_status.playing_status = ToolStatus.PLAYING_CHECKING
            Config.log.info('RuntimeStatus::_calculate_playing_status: '
                            'Not all modules/hardware are ready')

    @classmethod
    def _calculate_guide_message(cls):
        """Update guide message according to status."""
        tool_status = cls.get_tools()

        if tool_status.recording_status == ToolStatus.RECORDING_READY_TO_CHECK:
            tool_status.message = 'Before recording, you need to setup the ' \
                                  'system.'
        elif tool_status.recording_status == ToolStatus.RECORDING_CHECKING:
            tool_status.message = 'Waiting for modules and hardware.'
        elif tool_status.recording_status == \
             ToolStatus.RECORDING_READY_TO_START:
            tool_status.message = 'Now you are ready to record.'
        elif (tool_status.recording_status == ToolStatus.RECORDING
              or tool_status.playing_status == ToolStatus.PLAYING):
            if not tool_status.message.isdigit():
                # The timestamp we started recording or playing.
                tool_status.message = str(cls._current_timestamp())
        elif (tool_status.recording_status == ToolStatus.RECORDING_FINISHED
              and tool_status.playing_status == ToolStatus.PLAYING_NOT_READY):
            tool_status.message = 'The recorded data/log/garage.csv is ' \
                                  'invalid.<br/>Please fix, or simply try ' \
                                  'recording again by clicking "New".'
        elif tool_status.playing_status == ToolStatus.PLAYING_CHECKING:
            if tool_status.planning_ready:
                tool_status.message = 'Waiting for modules and hardware.'
            else:
                tool_status.message = 'Waiting for planning ready.'
        elif tool_status.playing_status == ToolStatus.PLAYING_READY_TO_CHECK:
            tool_status.message = '{}s of driving was recorded.<br/>' \
                                  'Before playing, please setup the system.' \
                                  .format(cls.playable_duration)
        elif tool_status.playing_status == ToolStatus.PLAYING_READY_TO_START:
            tool_status.message = 'Make sure the OPERATOR is ready! ' \
                                  'Now you are good to go.'
        else:
            tool_status.message = 'Something goes wrong.<br/>' \
                                  'Please record again or RESET ALL.'

    @classmethod
    def _current_timestamp(cls):
        """Current timestamp in milliseconds."""
        return int(time.time() * 1000)

    @staticmethod
    def __find_by_name(name, value_list):
        """Find a value in list by name."""
        return next((value for value in value_list if value.name == name),
                    None)