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
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))
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()
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")
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)
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)