Exemplo n.º 1
0
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))
Exemplo n.º 2
0
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))