def exportSmurf(model, path): """This function exports a given model to a specific path as a smurf representation. Args: model(dict): The model you want to export. path: The path you want to save the smurf file *without file name!* Returns: """ collisiondata = deriveRefinedCollisionData(model) lodsettings = gatherLevelOfDetailSettings(model) exportdata = { 'state': False, # model['state'] != {}, # TODO: handle state 'materials': model['materials'] != {}, 'sensors': model['sensors'] != {}, 'motors': model['motors'] != {}, 'controllers': model['controllers'] != {}, 'collision': collisiondata != {}, 'visuals': lodsettings != {}, 'lights': model['lights'] != {}, 'submechanisms': model['submechanisms'] != [], } # create all filenames smurf_filename = model['name'] + ".smurf" filenames = { 'state': model['name'] + "_state.yml", 'materials': model['name'] + "_materials.yml", 'sensors': model['name'] + "_sensors.yml", 'motors': model['name'] + "_motors.yml", 'controllers': model['name'] + "_controllers.yml", 'collision': model['name'] + "_collision.yml", 'visuals': model['name'] + "_visuals.yml", 'lights': model['name'] + "_lights.yml", 'submechanisms': model['name'] + "_submechanisms.yml", } fileorder = [ 'collision', 'visuals', 'materials', 'motors', 'sensors', 'controllers', 'state', 'lights', 'submechanisms', ] urdf_path = '../urdf/' urdf_filename = model['name'] + '.urdf' # gather annotations and data from text files annotationdict = models.gatherAnnotations(model) # $mars annotated properties overwrite custom properties of objects for smurf if 'mars' in annotationdict: for category in annotationdict['mars']: for list_obj in annotationdict['mars'][category]: model[category + 's'][list_obj['name']].update(list_obj) del annotationdict['mars'] for category in annotationdict: # TODO use os.path? if category != 'sdf': filenames[category] = model['name'] + '_' + category + '.yml' fileorder.append(category) exportdata[category] = True customdatalist = [] for text in bpy.data.texts: if text.name.startswith(model['name'] + '::'): dataname = text.name.split('::')[-1] customdatalist.append(dataname) # TODO use os.path? filenames[dataname] = model['name'] + '_' + dataname + '.yml' fileorder.append(dataname) exportdata[dataname] = True infostring = ' definition SMURF file for "' + model[ 'name'] + '", ' + model["date"] + "\n\n" # write model information log("Writing SMURF model to " + smurf_filename, "INFO") # CHECK are these filepaths failsafe in Windows? modeldata = { "date": model["date"], "files": [urdf_path + urdf_filename] + [filenames[f] for f in fileorder if exportdata[f]], } # append custom data with open(os.path.join(path, smurf_filename), 'w') as op: op.write('# main SMURF file of model "' + model['name'] + '"\n') op.write('# created with Phobos ' + defs.version + ' - ' + defs.repository + '\n\n') op.write("SMURF version: " + defs.version + "\n") op.write("modelname: " + model['name'] + "\n") op.write(yaml.dump(modeldata, default_flow_style=False)) # TODO delete me? # #write semantics (SRDF information in YML format) # if export['semantics']: # with open(path + filenames['semantics'], 'w') as op: # op.write('#semantics'+infostring) # op.write("modelname: "+model['name']+'\n') # semantics = {} # if model['groups'] != {}: # semantics['groups'] = model['groups'] # if model['chains'] != {}: # semantics['chains'] = model['chains'] # op.write(yaml.dump(semantics, default_flow_style=False)) # for smurf, we parse the controller parameters into the motors for motor in model['motors']: motordict = model['motors'][motor] controllerparams = {} if 'controller' in motordict and motordict['controller'] in model[ 'controllers']: controllerparams = { key: value for key, value in model['controllers'][ motordict['controller']].items() if (key not in ['name', 'target']) } motordict.update(controllerparams) del motordict['controller'] else: log( "No controller assigned to motor {}!".format( motordict['name']), 'WARNING') # PID controlled motors get their min and max values from the joint limits if motordict['type'] == 'PID': try: joint = model['joints'][motordict['joint']] if 'limits' in joint: motordict['minValue'] = joint['limits']['lower'] motordict['maxValue'] = joint['limits']['upper'] except KeyError: log( "Missing data in motor {}! No limits given for type PID. Motor might be incomplete." .format(motordict['name']), "WARNING", ) # direct controllers are called generic_dc in mars elif motordict['type'] == 'direct': motordict['type'] = 'generic_dc' try: motordict['minValue'] = -motordict["maxSpeed"] motordict['maxValue'] = motordict["maxSpeed"] except KeyError: log( "Missing data in motor {}! No maxSpeed given for motor type direct. Motor might be incomplete." .format(motordict['name']), "WARNING", ) # TODO: implement everything but joints # write state (state information of all joints, sensor & motor activity etc.) if exportdata['state']: states = [] # gather all states for jointname in model['joints']: joint = model['joints'][jointname] # this should always be the case, but testing doesn't hurt if 'state' in joint: tmpstate = joint['state'].copy() tmpstate['name'] = jointname states.append(joint['state']) with open(os.path.join(path, filenames['state']), 'w') as op: op.write('#state' + infostring) op.write("modelname: " + model['name'] + '\n') # TODO am I still needed? op.write(yaml.dump(states)) # , default_flow_style=False)) # write materials, sensors, motors & controllers for data in ['materials', 'motors', 'sensors', 'controllers', 'lights']: if exportdata[data]: log("Writing {} to smurf file.".format(data), 'DEBUG') with open(os.path.join(path, filenames[data]), 'w') as op: op.write('#' + data + infostring) op.write( yaml.dump( sort_for_yaml_dump({data: list(model[data].values())}, data), default_flow_style=False, )) # write additional collision information if exportdata['collision']: with open(os.path.join(path, filenames['collision']), 'w') as op: op.write('#collision data' + infostring) # TODO delete me? # op.write(yaml.dump({'collision': list(bitmasks.values())}, default_flow_style=False)) op.write( yaml.dump( { 'collision': [ collisiondata[key] for key in sorted(collisiondata.keys()) ] }, default_flow_style=False, )) # write visual information (level of detail, ...) if exportdata['visuals']: with open(os.path.join(path, filenames['visuals']), 'w') as op: op.write('#visual data' + infostring) op.write( yaml.dump({'visuals': list(lodsettings.values())}, default_flow_style=False)) # write additional information for category in annotationdict.keys(): if category != 'sdf': if exportdata[category]: outstring = '#' + category + infostring for elementtype in annotationdict[category]: outstring += elementtype + ':\n' outstring += ( yaml.dump(annotationdict[category][elementtype], default_flow_style=False) + "\n") with open(os.path.join(path, filenames[category]), 'w') as op: op.write(outstring) # write custom data from textfiles for data in customdatalist: if exportdata[data]: with open(os.path.join(path, filenames[data]), 'w') as op: op.write('#' + data + infostring) op.write( yaml.dump({data: list(model[data].values())}, default_flow_style=False)) # write submechanisms if model['submechanisms']: with open(os.path.join(path, filenames['submechanisms']), 'w') as op: op.write('#submechanisms' + infostring) op.write(yaml.dump({'submechanisms': model['submechanisms'] })) # , default_flow_style=False))
def exportSmurf(model, path): """This function exports a given model to a specific path as a smurf representation. Args: model(dict): The model you want to export. path: The path you want to save the smurf file *without file name!* Returns: """ collisiondata = deriveRefinedCollisionData(model) lodsettings = gatherLevelOfDetailSettings(model) exportdata = { 'state': False, # model['state'] != {}, # TODO: handle state 'materials': model['materials'] != {}, 'sensors': model['sensors'] != {}, 'motors': model['motors'] != {}, 'controllers': model['controllers'] != {}, 'collision': collisiondata != {}, 'visuals': lodsettings != {}, 'lights': model['lights'] != {}, 'submechanisms': model['submechanisms'] != [], } # create all filenames smurf_filename = model['name'] + ".smurf" filenames = { 'state': model['name'] + "_state.yml", 'materials': model['name'] + "_materials.yml", 'sensors': model['name'] + "_sensors.yml", 'motors': model['name'] + "_motors.yml", 'controllers': model['name'] + "_controllers.yml", 'collision': model['name'] + "_collision.yml", 'visuals': model['name'] + "_visuals.yml", 'lights': model['name'] + "_lights.yml", 'submechanisms': model['name'] + "_submechanisms.yml", } fileorder = [ 'collision', 'visuals', 'materials', 'motors', 'sensors', 'controllers', 'state', 'lights', 'submechanisms', ] urdf_path = '../urdf/' urdf_filename = model['name'] + '.urdf' # gather annotations and data from text files annotationdict = models.gatherAnnotations(model) # $mars annotated properties overwrite custom properties of objects for smurf if 'mars' in annotationdict: for category in annotationdict['mars']: for list_obj in annotationdict['mars'][category]: model[category + 's'][list_obj['name']].update(list_obj) del annotationdict['mars'] for category in annotationdict: # TODO use os.path? if category != 'sdf': filenames[category] = model['name'] + '_' + category + '.yml' fileorder.append(category) exportdata[category] = True customdatalist = [] for text in bpy.data.texts: if text.name.startswith(model['name'] + '::'): dataname = text.name.split('::')[-1] customdatalist.append(dataname) # TODO use os.path? filenames[dataname] = model['name'] + '_' + dataname + '.yml' fileorder.append(dataname) exportdata[dataname] = True infostring = ' definition SMURF file for "' + model['name'] + '", ' + model["date"] + "\n\n" # write model information log("Writing SMURF model to " + smurf_filename, "INFO") # CHECK are these filepaths failsafe in Windows? modeldata = { "date": model["date"], "files": [urdf_path + urdf_filename] + [filenames[f] for f in fileorder if exportdata[f]], } # append custom data with open(os.path.join(path, smurf_filename), 'w') as op: op.write('# main SMURF file of model "' + model['name'] + '"\n') op.write('# created with Phobos ' + defs.version + ' - ' + defs.repository + '\n\n') op.write("SMURF version: " + defs.version + "\n") op.write("modelname: " + model['name'] + "\n") op.write(yaml.dump(modeldata, default_flow_style=False)) # TODO delete me? # #write semantics (SRDF information in YML format) # if export['semantics']: # with open(path + filenames['semantics'], 'w') as op: # op.write('#semantics'+infostring) # op.write("modelname: "+model['name']+'\n') # semantics = {} # if model['groups'] != {}: # semantics['groups'] = model['groups'] # if model['chains'] != {}: # semantics['chains'] = model['chains'] # op.write(yaml.dump(semantics, default_flow_style=False)) # for smurf, we parse the controller parameters into the motors for motor in model['motors']: motordict = model['motors'][motor] controllerparams = {} if motordict['controller'] in model['controllers']: controllerparams = { key: value for key, value in model['controllers'][motordict['controller']].items() if (key not in ['name', 'target']) } motordict.update(controllerparams) del motordict['controller'] else: log("No controller assigned to motor {}!".format(motordict['name']), 'WARNING') # PID controlled motors get their min and max values from the joint limits if motordict['type'] == 'PID': try: joint = model['joints'][motordict['joint']] if 'limits' in joint: motordict['minValue'] = joint['limits']['lower'] motordict['maxValue'] = joint['limits']['upper'] except KeyError: log( "Missing data in motor {}! Motor might be incomplete.".format( motordict['name'] ), "WARNING", ) # direct controllers are called generic_dc in mars elif motordict['type'] == 'direct': motordict['type'] = 'generic_dc' try: motordict['minValue'] = -1. * motordict["maxSpeed"] motordict['maxValue'] = motordict["maxSpeed"] except KeyError: log( "Missing data in motor {}! Motor might be incomplete.".format( motordict['name'] ), "WARNING", ) # TODO: implement everything but joints # write state (state information of all joints, sensor & motor activity etc.) if exportdata['state']: states = [] # gather all states for jointname in model['joints']: joint = model['joints'][jointname] # this should always be the case, but testing doesn't hurt if 'state' in joint: tmpstate = joint['state'].copy() tmpstate['name'] = jointname states.append(joint['state']) with open(os.path.join(path, filenames['state']), 'w') as op: op.write('#state' + infostring) op.write("modelname: " + model['name'] + '\n') # TODO am I still needed? op.write(yaml.dump(states)) # , default_flow_style=False)) if 'sensors' in exportdata: export_sensors = {} for sensorname, sensordata in model['sensors'].items(): export_sensors[sensorname] = parseSmurfSensor(sensordata) log("Writing {} to smurf file.".format('sensors'), 'DEBUG') with open(os.path.join(path, filenames['sensors']), 'w') as op: op.write('#' + 'sensors' + infostring) op.write( yaml.dump( sort_for_yaml_dump({'sensors': list(export_sensors.values())}, 'sensors'), default_flow_style=False, ) ) # TODO WRITE EXPORT FOR MOTOR and stuff # write materials, sensors, motors & controllers for data in ['materials', 'motors', 'controllers', 'lights']: if exportdata[data]: log("Writing {} to smurf file.".format(data), 'DEBUG') with open(os.path.join(path, filenames[data]), 'w') as op: op.write('#' + data + infostring) op.write( yaml.dump( sort_for_yaml_dump({data: list(model[data].values())}, data), default_flow_style=False, ) ) # write additional collision information if exportdata['collision']: with open(os.path.join(path, filenames['collision']), 'w') as op: op.write('#collision data' + infostring) # TODO delete me? # op.write(yaml.dump({'collision': list(bitmasks.values())}, default_flow_style=False)) op.write( yaml.dump( {'collision': [collisiondata[key] for key in sorted(collisiondata.keys())]}, default_flow_style=False, ) ) # write visual information (level of detail, ...) if exportdata['visuals']: with open(os.path.join(path, filenames['visuals']), 'w') as op: op.write('#visual data' + infostring) op.write(yaml.dump({'visuals': list(lodsettings.values())}, default_flow_style=False)) # write additional information for category in annotationdict.keys(): if category != 'sdf': if exportdata[category]: outstring = '#' + category + infostring for elementtype in annotationdict[category]: outstring += elementtype + ':\n' outstring += ( yaml.dump(annotationdict[category][elementtype], default_flow_style=False) + "\n" ) with open(os.path.join(path, filenames[category]), 'w') as op: op.write(outstring) # write custom data from textfiles for data in customdatalist: if exportdata[data]: with open(os.path.join(path, filenames[data]), 'w') as op: op.write('#' + data + infostring) op.write(yaml.dump({data: list(model[data].values())}, default_flow_style=False)) # write submechanisms if model['submechanisms']: with open(os.path.join(path, filenames['submechanisms']), 'w') as op: op.write('#submechanisms' + infostring) op.write( yaml.dump({'submechanisms': model['submechanisms']}) ) # , default_flow_style=False))