def saveConfig(self): """ Save the config object. Return True for successfully saved, False for not """ # TODO: check if the config is complete # the file name is default to be the config name with underscore if self.name == "": self.name = 'Untitled configuration' file_name = self.name.replace(' ', '_') # Add extension to the name file_name = file_name+'.config' # Add the path to the file name file_name = os.path.join(os.path.dirname(self.file_name), file_name) self.file_name = file_name data = {'General Config':{'Name':self.name}} # proposition mapping sensorMappingList = [] actuatorMappingList = [] for prop, fun in self.prop_mapping.iteritems(): if 'sensor' in fun.lower(): sensorMapping = prop + ' = ' + fun sensorMappingList.append(sensorMapping) elif 'actuator' in fun.lower(): actuatorMapping = prop + ' = ' + fun actuatorMappingList.append(actuatorMapping) else: logging.warning("Cannot recognize prop mapping: {}".format(prop+" = "+fun)) data['General Config']['Sensor_Proposition_Mapping'] = sensorMappingList data['General Config']['Actuator_Proposition_Mapping'] = actuatorMappingList data['General Config']['Main_Robot'] = self.main_robot data['General Config']['Initial_Truths'] = self.initial_truths data['General Config']['Region_Tags'] = json.dumps(self.region_tags) for i, robot in enumerate(self.robots): header = 'Robot'+str(i+1)+' Config' data[header] = {} data[header]['RobotName'] = robot.name data[header]['Type'] = robot.r_type data[header]['CalibrationMatrix'] = repr(robot.calibration_matrix) # TODO: change to string function try: for handler_type_name in ht.getAllHandlerTypeName(short_name = False): handler_type_class = ht.getHandlerTypeClass(handler_type_name) if handler_type_class in robot.handlers.keys(): data[header][handler_type_name] = robot.handlers[handler_type_class].toString() except AttributeError: logging.warning("Cannot save handlers for robot {}({}). Please make sure they are all successfully loaded. Aborting saving."\ .format(robot.name, robot.r_type)) return False comments = {"FILE_HEADER": "This is a configuration definition file in folder \"%s\".\n" % os.path.dirname(self.file_name)+ "Format details are described at the beginning of each section below.\n", "PoseHandler": "Input value for robot pose handler, refer to file inside the handlers/pose folder", "DriveHandler": "Input value for robot drive handler, refer to file inside the handlers/drive folder", "MotionControlHandler": "Input value for robot motion control handler, refer to file inside the handlers/motionControl folder", "LocomotionCommandHandler": "Input value for robot locomotion command handler, refer to file inside the handlers/robots/Type folder", "InitHandler": "Input value for robot init handler, refer to the init file inside the handlers/robots/Type folder", "SensorHandler": "Sensor handler file in robots/Type folder", "ActuatorHandler": "Actuator handler file in robots/Type folder", "RobotName": "Robot Name", "Type": "Robot type", "CalibrationMatrix": "3x3 matrix for converting coordinates, stored as lab->map", "Actuator_Proposition_Mapping": 'Mapping between actuator propositions and actuator handler functions', "Sensor_Proposition_Mapping": "Mapping between sensor propositions and sensor handler functions", "Name": 'Configuration name', "Main_Robot":'The name of the robot used for moving in this config', "Initial_Truths": "Initially true propositions", "Region_Tags": "Mapping from tag names to region groups, for quantification"} fileMethods.writeToFile(file_name, data, comments) return True
def fromData(self, robot_data, hsub): """ Given a dictionary of robot handler information, returns a robot object holding all the information The dictionary is in the format returned by the readFromFile function If the necessary handler of the robot is not specified or can't be loaded, return None """ # update robot name and type try: self.name = robot_data['RobotName'][0] except (KeyError, IndexError): raise ht.LoadingError("Cannot find robot name") self._setLoadFailureFlag() try: self.r_type = robot_data['Type'][0] except (KeyError, IndexError): raise ht.LoadingError("Cannot find robot type") self._setLoadFailureFlag() # update robot calibration matrix if 'CalibrationMatrix' in robot_data: self.calibration_matrix = self._getCalibrationMatrixFromString(''.join(robot_data['CalibrationMatrix'])) # load handler configs for key, val in robot_data.iteritems(): # Ignore config sections that aren't for handlers if not key.endswith('Handler'): continue # Find the intended type of the handler try: handler_type = ht.getHandlerTypeClass(key) except KeyError: logging.warning('Cannot recognize handler type {!r} for robot {}({})'.format(key, self.name, self.r_type)) self._setLoadFailureFlag() continue # Go through the handler listings for this type for handler_config_str in val: # Parse this line try: call_descriptors, _ = parseCallString(handler_config_str, mode="single") except SyntaxError: # This is an invalid handler config description logging.exception('Cannot recognize handler config description: \n \t {!r} \n \ for handler type {!r} of robot {}({})'.format(handler_config_str, key, self.name, self.r_type)) self._setLoadFailureFlag() continue # Figure out how to interpret the different parts of the CallDescriptor name if len(call_descriptors[0].name) == 3: robot_type, h_type, handler_name = call_descriptors[0].name # 3-part name is only valid for shared handlers if robot_type != 'share': raise SyntaxError("Name must be in form of 'share.<handler_type>.<handler_name>' or '<robot_type>.<handler_name>'") elif len(call_descriptors[0].name) == 2: robot_type, handler_name = call_descriptors[0].name h_type = None else: raise SyntaxError("Name must be in form of 'share.<handler_type>.<handler_name>' or '<robot_type>.<handler_name>'") # Check that this handler belongs to this robot (it's kind of redundant that the `robot_type` must be # specified if we're only going to let it be one value...) if (robot_type != 'share') and (robot_type.lower() != self.r_type.lower()): # this is a handler for a wrong robot logging.warning('The handler config description: \n \t {!r} \n \ is for robot {}, but is located in data for robot {}({})' \ .format(handler_config_str, robot_type, self.name, self.r_type)) self._setLoadFailureFlag() continue # if the description also specifies the handler type in it # we need to make sure it matches with the handler type we get from section name if h_type is not None: # get the handler type as class object try: handler_type_from_str = ht.getHandlerTypeClass(h_type) except KeyError: logging.warning('Cannot recognize handler type {!r} in config description: \n \t {!r} \n \ for robot {}({})'.format(h_type, handler_config_str, self.name, self.r_type)) self._setLoadFailureFlag() continue if handler_type_from_str != handler_type: # the handler type from the description does not match the one from section name logging.warning('Misplaced handler description: \n \t {!r} \n \ in handler type {!r} for robot {}({})' \ .format(handler_config_str, handler_type, self.name, self.r_type)) # we still want to put this handler config into the right type handler_type = handler_type_from_str if robot_type == 'share' and h_type is None: # This is a shared handler but no handler type information is given logging.warning('Handler type info missing for {!r} handler in config description: \n \t {!r} \n \ for robot {}({})'.format(robot_type, handler_config_str, self.name, self.r_type)) self._setLoadFailureFlag() continue # now let's get the handler config object based on the info we have got handler_config = hsub.getHandlerConfigDefault(robot_type, handler_type, handler_name) # make sure it successfully loaded if handler_config is None: self._setLoadFailureFlag() continue # load all parameter values and overwrite the ones in the __init__ method of default handler config object try: init_method_config = handler_config.getMethodByName('__init__') except ValueError: logging.warning('Cannot update default parameters of default handler config {!r}'.format(handler_config.name)) else: init_method_config.updateParaFromDict(call_descriptors[0].args) # if it is successfully fetched, we save it at the corresponding handler type of this robot if handler_type not in self.handlers: # This type of handler has not been loaded yet self.handlers[handler_type] = handler_config else: # This type of handler has been loaded, for now, we will NOT overwrite it with new entry # A warning will be shown logging.warning('Multiple handler configs are detected for handler type {!r} of robot {}({}). \ Will only load the first one.'.format(key, self.name, self.r_type)) break