コード例 #1
0
ファイル: joints.py プロジェクト: stpulleyking/phobos
def createJoint(joint, linkobj=None):
    """Adds joint data to 'link' object.

    Args:
        joint (dict): dictionary containing the joint definition
        linkobj (bpy.types.Object): the obj of phobostype 'link' that receives the joint

    Returns:

    """
    # add joint information
    if not linkobj:
        linkobj = sUtils.getObjectByName(joint['child'])
        if isinstance(linkobj, list):
            log(
                "Could not identify object to define joint '{0}'.".format(
                    joint['name']), 'ERROR')
            return
    if joint['name'] != linkobj.name:
        linkobj['joint/name'] = joint['name']
    # get hold of object
    bUtils.toggleLayer(list(linkobj.layers).index(True),
                       True)  # any layer containing the object
    sUtils.selectObjects([linkobj], clear=True, active=0)

    # set axis
    if 'axis' in joint:
        if mathutils.Vector(tuple(joint['axis'])).length == 0.:
            log('Axis of joint {0} is of zero length: '.format(joint['name']),
                'ERROR')
        else:
            bpy.ops.object.mode_set(mode='EDIT')
            editbone = linkobj.data.edit_bones[0]
            length = editbone.length
            axis = mathutils.Vector(tuple(joint['axis']))
            editbone.tail = editbone.head + axis.normalized() * length

    # add constraints
    for param in ['effort', 'velocity']:
        try:
            if 'limits' in joint:
                linkobj['joint/max' + param] = joint['limits'][param]
        except KeyError:
            log("Joint limits incomplete for joint {0}".format(joint['name']),
                'ERROR')
    try:
        lower = joint['limits']['lower']
        upper = joint['limits']['upper']
    except KeyError:
        lower = 0.0
        upper = 0.0
    setJointConstraints(linkobj, joint['type'], lower, upper)
    for prop in joint:
        if prop.startswith('$'):
            for tag in joint[prop]:
                linkobj['joint/' + prop[1:] + '/' + tag] = joint[prop][tag]
コード例 #2
0
ファイル: robotdictionary.py プロジェクト: bmagyar/phobos
def buildRobotDictionary():
    """Builds a python dictionary representation of a Blender robot model for export and inspection."""
    objectlist = bpy.context.selected_objects
    #notifications, faulty_objects = robotupdate.updateModel(bpy.context.selected_objects)
    #print(notifications)
    robot = {'links': {},
            'joints': {},
            'sensors': {},
            'motors': {},
            'controllers': {},
            'materials': {},
            'groups': {},
            'chains': {},
            'lights': {}
            }
    #save timestamped version of model
    robot["date"] = datetime.now().strftime("%Y%m%d_%H:%M")
    root = selectionUtils.getRoot(bpy.context.selected_objects[0])
    if root.phobostype != 'link':
        raise Exception("Found no 'link' object as root of the robot model.")
    else:
        if 'modelname' in root:
            robot['modelname'] = root["modelname"]
        else:
            robot['modelname'] = 'unnamed_robot'

    # digest all the links to derive link and joint information
    print('\nParsing links, joints and motors...')
    for obj in bpy.context.selected_objects:
        if obj.phobostype == 'link':
            link, joint, motor = deriveKinematics(obj)
            robot['links'][namingUtils.getObjectName(obj, phobostype="link")] = link  # it's important that this is really the object's name
            if joint:  # joint can be None if link is a root
                robot['joints'][joint['name']] = joint
            if motor:
                robot['motors'][joint['name']] = motor
            obj.select = False

    # add inertial information to link
    print('\n\nParsing inertials...')
    for l in robot['links']:
        #link = bpy.data.objects[l] NEW NAMING!
        link = selectionUtils.getObjectByName(l)[0] if selectionUtils.getObjectByName(l) is not None else "ERROR!"
        inertials = selectionUtils.getImmediateChildren(link, ['inertial'])
        if len(inertials) == 1:
            props, parent = deriveDictEntry(inertials[0])
            if not (props is None or parent is None):  # this may be the case if there is inertia information missing
                robot['links'][namingUtils.getObjectName(parent)]['inertial'] = props
            inertials[0].select = False
        elif len(inertials) > 1:
            for i in inertials:
                if namingUtils.getObjectName(i, phobostype="inertial") == 'inertial_' + l:
                    props, parent = deriveDictEntry(i)
                    robot['links'][namingUtils.getObjectName(parent, phobostype="link")]['inertial'] = props
            # FIXME: this has to be re-implemented
            #if linkinertial == None:
            #    mass, com, inertia = inertia.fuseInertiaData(inertials)
            #    parent = inertials[0].parent
            #    matrix_local = mathutils.Matrix.Translation(mathutils.Vector(com))
            #    pose = {}
            #    pose['matrix'] = [list(vector) for vector in list(matrix_local)]
            #    pose['translation'] = list(matrix_local.to_translation())
            #    pose['rotation_euler'] = list(matrix_local.to_euler())
            #    pose['rotation_quaternion'] = list(matrix_local.to_quaternion())
            #    props = {'mass': mass, 'pose': pose, 'inertia': inertia}
            #    robot['links'][parent.name]['inertial'] = props
            for i in inertials:
                i.select = False

    # complete link information by parsing visuals and collision objects
    print('\n\nParsing visual and collision (approximation) objects...')
    for obj in bpy.context.selected_objects:
        print("Parsing object " + namingUtils.getObjectName(obj))
        if obj.phobostype in ['visual', 'collision']:
            props, parent = deriveDictEntry(obj)
            robot['links'][namingUtils.getObjectName(parent, phobostype="link")][obj.phobostype][namingUtils.getObjectName(obj, phobostype=obj.phobostype)] = props
            obj.select = False
        elif obj.phobostype == 'approxsphere':
            props, parent = deriveDictEntry(obj)
            robot['links'][namingUtils.getObjectName(parent)]['approxcollision'].append(props)
            obj.select = False

    # combine collision information for links
    for linkname in robot['links']:
        link = robot['links'][linkname]
        bitmask = 0
        for collname in link['collision']:
            try:
                bitmask = bitmask | link['collision'][collname]['bitmask']
            except KeyError:
                pass
        link['collision_bitmask'] = bitmask

    # parse sensors and controllers
    print('\n\nParsing sensors and controllers...')
    for obj in bpy.context.selected_objects:
        if obj.phobostype in ['sensor', 'controller']:
            robot[obj.phobostype+'s'][namingUtils.getObjectName(obj)] = deriveDictEntry(obj)
            obj.select = False

    # parse materials
    print('\n\nParsing materials...')
    robot['materials'] = collectMaterials(objectlist)
    for obj in objectlist:
        if obj.phobostype == 'visual' and len(obj.data.materials) > 0:
            mat = obj.data.materials[0]
            if not namingUtils.getObjectName(mat) in robot['materials']:
                robot['materials'][namingUtils.getObjectName(mat)] = deriveMaterial(mat) #this should actually never happen
            robot['links'][namingUtils.getObjectName(obj.parent)]['visual'][namingUtils.getObjectName(obj, phobostype="visual")]['material'] = namingUtils.getObjectName(mat)

    # gather information on groups of objects
    print('\n\nParsing groups...')
    for group in bpy.data.groups:  # TODO: get rid of the "data" part
        if len(group.objects) > 0 and namingUtils.getObjectName(group) != "RigidBodyWorld":
            robot['groups'][namingUtils.getObjectName(group)] = deriveGroupEntry(group)

    # gather information on chains of objects
    print('\n\nParsing chains...')
    chains = []
    for obj in bpy.data.objects:
        if obj.phobostype == 'link' and 'endChain' in obj:
            chains.extend(deriveChainEntry(obj))
    for chain in chains:
        robot['chains'][chain['name']] = chain

    # gather information on global lights
    print('\n\nParsing lights...')
    for obj in bpy.context.selected_objects:
        if obj.phobostype == 'light':
            robot['lights'][namingUtils.getObjectName(obj)] = deriveLight(obj)

    robot['poses'] = deriveStoredPoses()

    #shorten numbers in dictionary to n decimalPlaces and return it
    print('\n\nRounding numbers...')
    epsilon = 10**(-bpy.data.worlds[0].decimalPlaces)  # TODO: implement this separately
    return generalUtils.epsilonToZero(robot, epsilon, bpy.data.worlds[0].decimalPlaces)
コード例 #3
0
ファイル: joints.py プロジェクト: Amudtogal/phobos
def createJoint(joint, linkobj=None, links=None):
    """Adds joint data to a link object.
    
    If the linkobj is not specified, it is derived from the **child** entry in the joint (object is
    searched in the current scene). This only works if the search for the child yields a single
    object. Alternatively, it is possible to provide the model dictionary of links. In this case,
    the link object is searched in the dictionary (make sure the **object** keys of the dictionary
    are set properly).
    
    These entries are mandatory for the dictionary:
    
    |   **name**: name of the joint
    
    These entries are optional:
    
    |   **axis**: tuple which specifies the axis of the editbone
    |   **limits**: limits of the joint movement
    |       **lower**: lower limit (defaults to 0.)
    |       **upper**: upper limit (defaults to 0.)
    |       **effort**: maximum effort for the joint
    |       **velocity**: maximum velocity for the joint
    
    Furthermore any generic properties, prepended by a ``$`` will be added as custom properties to
    the joint. E.g. ``$test/etc`` would be put to joint/test/etc. However, these properties are
    extracted only in the first layer of hierarchy.

    Args:
      joint(dict): dictionary containing the joint definition
      linkobj(bpy.types.Object, optional): link object receiving joint (Default value = None)
      links(dict, optional): model dictionary of links (Default value = None)

    Returns:
      None: None

    """
    # try deriving link object from joint['child']
    if not linkobj:
        # link dictionary provided -> search for child link object
        if (
            links
            and 'child' in joint
            and joint['child'] in links
            and 'object' in links[joint['child']]
        ):
            linkobj = links[joint['child']]['object']
        # search for child link in scene
        else:
            linkobj = sUtils.getObjectByName(joint['child'])
            if isinstance(linkobj, list):
                log(
                    "Could not identify object to define joint '{0}'.".format(joint['name']),
                    'ERROR',
                )
                return

    # make sure the proper joint name is kept
    if joint['name'] != linkobj.name:
        linkobj['joint/name'] = joint['name']

    # select the link object
    bUtils.toggleLayer(list(linkobj.layers).index(True), True)
    sUtils.selectObjects([linkobj], clear=True, active=0)

    # set axis
    if 'axis' in joint:
        if mathutils.Vector(tuple(joint['axis'])).length == 0.:
            log('Axis of joint {0} is of zero length: '.format(joint['name']), 'ERROR')
        else:
            bpy.ops.object.mode_set(mode='EDIT')
            editbone = linkobj.data.edit_bones[0]
            length = editbone.length
            axis = mathutils.Vector(tuple(joint['axis']))
            editbone.tail = editbone.head + axis.normalized() * length

    # add constraints to the joint
    if 'limits' in joint:
        for param in ['effort', 'velocity']:
            if param in joint['limits']:
                linkobj['joint/max' + param] = joint['limits'][param]
            else:
                log(
                    "Joint limits incomplete for joint {}. Missing {}.".format(
                        joint['name'], param
                    ),
                    'ERROR',
                )

        if all(elem in joint['limits'] for elem in ['lower', 'upper']):
            lower = joint['limits']['lower']
            upper = joint['limits']['upper']
        else:
            log("Joint limits upper/lower is missing! Defaulted to [-1e-5, 1e-5].", 'WARNING')
            lower = -1e-5
            upper = 1e-5
    else:
        log("Joint limits upper/lower is missing! Defaulted both to [-1e-5, 1e-5].", 'WARNING')
        lower = -1e-5
        upper = 1e-5
    setJointConstraints(linkobj, joint['type'], lower, upper)

    # add generic properties
    for prop in joint:
        if prop.startswith('$'):
            for tag in joint[prop]:
                linkobj['joint/' + prop[1:] + '/' + tag] = joint[prop][tag]
    log("Assigned joint information to {}.".format(linkobj.name), 'DEBUG')
コード例 #4
0
def createJoint(joint, linkobj=None, links=None):
    """Adds joint data to a link object.
    
    If the linkobj is not specified, it is derived from the **child** entry in the joint (object is
    searched in the current scene). This only works if the search for the child yields a single
    object. Alternatively, it is possible to provide the model dictionary of links. In this case,
    the link object is searched in the dictionary (make sure the **object** keys of the dictionary
    are set properly).
    
    These entries are mandatory for the dictionary:
    
    |   **name**: name of the joint
    
    These entries are optional:
    
    |   **axis**: tuple which specifies the axis of the editbone
    |   **limits**: limits of the joint movement
    |       **lower**: lower limit (defaults to 0.)
    |       **upper**: upper limit (defaults to 0.)
    |       **effort**: maximum effort for the joint
    |       **velocity**: maximum velocity for the joint
    
    Furthermore any generic properties, prepended by a ``$`` will be added as custom properties to
    the joint. E.g. ``$test/etc`` would be put to joint/test/etc. However, these properties are
    extracted only in the first layer of hierarchy.

    Args:
      joint(dict): dictionary containing the joint definition
      linkobj(bpy.types.Object, optional): link object receiving joint (Default value = None)
      links(dict, optional): model dictionary of links (Default value = None)

    Returns:
      None: None

    """
    # try deriving link object from joint['child']
    if not linkobj:
        # link dictionary provided -> search for child link object
        if (links and 'child' in joint and joint['child'] in links
                and 'object' in links[joint['child']]):
            linkobj = links[joint['child']]['object']
        # search for child link in scene
        else:
            linkobj = sUtils.getObjectByName(joint['child'])
            if isinstance(linkobj, list):
                log(
                    "Could not identify object to define joint '{0}'.".format(
                        joint['name']),
                    'ERROR',
                )
                return

    # make sure the proper joint name is kept
    if joint['name'] != linkobj.name:
        linkobj['joint/name'] = joint['name']

    # select the link object
    bUtils.toggleLayer(list(linkobj.layers).index(True), True)
    sUtils.selectObjects([linkobj], clear=True, active=0)

    # set axis
    if 'axis' in joint:
        if mathutils.Vector(tuple(joint['axis'])).length == 0.:
            log('Axis of joint {0} is of zero length: '.format(joint['name']),
                'ERROR')
        else:
            bpy.ops.object.mode_set(mode='EDIT')
            editbone = linkobj.data.edit_bones[0]
            length = editbone.length
            axis = mathutils.Vector(tuple(joint['axis']))
            editbone.tail = editbone.head + axis.normalized() * length

    # add constraints to the joint
    if 'limits' in joint:
        for param in ['effort', 'velocity']:
            if param in joint['limits']:
                linkobj['joint/max' + param] = joint['limits'][param]
            else:
                log(
                    "Joint limits incomplete for joint {}. Missing {}.".format(
                        joint['name'], param),
                    'ERROR',
                )

        if all(elem in joint['limits'] for elem in ['lower', 'upper']):
            lower = joint['limits']['lower']
            upper = joint['limits']['upper']
        else:
            log(
                "Joint limits upper/lower is missing! Defaulted to [-1e-5, 1e-5].",
                'WARNING')
            lower = -1e-5
            upper = 1e-5
    else:
        log(
            "Joint limits upper/lower is missing! Defaulted both to [-1e-5, 1e-5].",
            'WARNING')
        lower = -1e-5
        upper = 1e-5
    setJointConstraints(linkobj, joint['type'], lower, upper)

    # add generic properties
    for prop in joint:
        if prop.startswith('$'):
            for tag in joint[prop]:
                linkobj['joint/' + prop[1:] + '/' + tag] = joint[prop][tag]
    log("Assigned joint information to {}.".format(linkobj.name), 'DEBUG')
コード例 #5
0
def deriveMotor(obj, jointdict=None):
    """Derives motor information from an object.

    Args:
      obj(bpy_types.Object): Blender object to derive the motor from
      jointdict(dict, optional): phobos representation of the respective joint (Default value = None)

    Returns:
      : dict -- phobos representation of a motor

    """
    import phobos.model.models as models
    import phobos.model.controllers as controllermodel

    props = models.initObjectProperties(obj, phobostype='motor')

    # return None if no motor is attached (there will always be at least a name in the props)
    if len(props) < 2:
        return None

    # make sure the parent is a joint
    if not obj.parent or obj.parent.phobostype != 'link' or 'joint/type' not in obj.parent:
        log(
            "Can not derive motor from {}. Insufficient requirements from parent object!"
            .format(obj.name),
            'ERROR',
        )
        return None

    props['joint'] = nUtils.getObjectName(obj.parent, phobostype='joint')

    # todo: transfer joint limits to motor properties
    # check for a mimic motor
    for k in (obj.parent).keys():
        # Check for mimic motor
        if "mimic" in k:
            # Find the name
            mimic_driver = sUtils.getObjectByName(
                (obj.parent)['joint/mimic_joint'], phobostypes=['link'])
            c_motor = sUtils.getImmediateChildren(mimic_driver,
                                                  phobostypes=['motor'])
            props['mimic_motor'] = nUtils.getObjectName(c_motor[0],
                                                        phobostype='motor')
            props['mimic_multiplier'] = (obj.parent)['joint/mimic_multiplier']
            props['mimic_offset'] = (obj.parent)['joint/mimic_offset']
            break

    # try to derive the motor controller
    controllerobjs = [
        control for control in obj.children
        if control.phobostype == 'controller'
    ]
    if controllerobjs:
        controller = controllermodel.deriveController(controllerobjs[0])
    else:
        controller = None

    # assign the derived controller
    if controller:
        props['controller'] = controller['name']
    else:
        del props['controller']

    return props
コード例 #6
0
ファイル: robotdictionary.py プロジェクト: liyingzhi/phobos
def buildRobotDictionary():
    """Builds a python dictionary representation of a Blender robot model for export and inspection.

    """
    objectlist = bpy.context.selected_objects
    #notifications, faulty_objects = robotupdate.updateModel(bpy.context.selected_objects)
    #print(notifications)
    robot = {
        'links': {},
        'joints': {},
        'sensors': {},
        'motors': {},
        'controllers': {},
        'materials': {},
        'groups': {},
        'chains': {},
        'lights': {}
    }
    #save timestamped version of model
    robot["date"] = datetime.now().strftime("%Y%m%d_%H:%M")
    root = selectionUtils.getRoot(bpy.context.selected_objects[0])
    if root.phobostype != 'link':
        raise Exception("Found no 'link' object as root of the robot model.")
    else:
        if 'modelname' in root:
            robot['modelname'] = root["modelname"]
        else:
            robot['modelname'] = 'unnamed_robot'

    # digest all the links to derive link and joint information
    print('\nParsing links, joints and motors...')
    for obj in bpy.context.selected_objects:
        if obj.phobostype == 'link':
            link, joint, motor = deriveKinematics(obj)
            robot['links'][namingUtils.getObjectName(
                obj, phobostype="link"
            )] = link  # it's important that this is really the object's name
            if joint:  # joint can be None if link is a root
                robot['joints'][joint['name']] = joint
            if motor:
                robot['motors'][joint['name']] = motor
            obj.select = False

    # add inertial information to link
    print('\n\nParsing inertials...')
    for l in robot['links']:
        #link = bpy.data.objects[l] NEW NAMING!
        link = selectionUtils.getObjectByName(
            l)[0] if selectionUtils.getObjectByName(
                l) is not None else "ERROR!"
        inertials = selectionUtils.getImmediateChildren(link, ['inertial'])
        if len(inertials) == 1:
            props, parent = deriveDictEntry(inertials[0])
            if not (
                    props is None or parent is None
            ):  # this may be the case if there is inertia information missing
                robot['links'][namingUtils.getObjectName(
                    parent)]['inertial'] = props
            inertials[0].select = False
        elif len(inertials) > 1:
            for i in inertials:
                if i.name == 'inertial_' + l:
                    props, parent = deriveDictEntry(i)
                    robot['links'][namingUtils.getObjectName(
                        parent, phobostype="link")]['inertial'] = props
            # FIXME: this has to be re-implemented
            #if linkinertial == None:
            #    mass, com, inertia = inertia.fuseInertiaData(inertials)
            #    parent = inertials[0].parent
            #    matrix_local = mathutils.Matrix.Translation(mathutils.Vector(com))
            #    pose = {}
            #    pose['matrix'] = [list(vector) for vector in list(matrix_local)]
            #    pose['translation'] = list(matrix_local.to_translation())
            #    pose['rotation_euler'] = list(matrix_local.to_euler())
            #    pose['rotation_quaternion'] = list(matrix_local.to_quaternion())
            #    props = {'mass': mass, 'pose': pose, 'inertia': inertia}
            #    robot['links'][parent.name]['inertial'] = props
            for i in inertials:
                i.select = False

    # complete link information by parsing visuals and collision objects
    print('\n\nParsing visual and collision (approximation) objects...')
    capsules_list = []
    for obj in bpy.context.selected_objects:
        print("Parsing object " + namingUtils.getObjectName(obj))
        if obj.phobostype in ['visual', 'collision']:
            props, parent = deriveDictEntry(obj)
            if all([
                    key in props for key in ['cylinder', 'sphere1', 'sphere2']
            ]):  # this is the case with simulated capsules
                capsules_list.append({
                    'link':
                    parent.name,
                    'name':
                    props['cylinder']['name'][:-len('_cylinder')],
                    'radius':
                    props['cylinder']['geometry']['radius'],
                    'length':
                    props['cylinder']['geometry']['length'] +
                    2 * props['cylinder']['geometry']['radius'],
                    #'bitmask': props['cylinder']['bitmask']
                })
                for key in props:
                    robot['links'][namingUtils.getObjectName(
                        parent,
                        phobostype="link")][obj.phobostype][key] = props[key]
            else:
                robot['links'][namingUtils.getObjectName(
                    parent, phobostype="link")][obj.phobostype][
                        namingUtils.getObjectName(
                            obj, phobostype=obj.phobostype)] = props
            obj.select = False
        elif obj.phobostype == 'approxsphere':
            props, parent = deriveDictEntry(obj)
            robot['links'][namingUtils.getObjectName(
                parent)]['approxcollision'].append(props)
            obj.select = False

    robot['capsules'] = capsules_list

    # combine collision information for links
    for linkname in robot['links']:
        link = robot['links'][linkname]
        bitmask = 0
        for collname in link['collision']:
            try:
                bitmask = bitmask | link['collision'][collname]['bitmask']
            except KeyError:
                pass
        link['collision_bitmask'] = bitmask

    # parse sensors and controllers
    print('\n\nParsing sensors and controllers...')
    for obj in bpy.context.selected_objects:
        if obj.phobostype in ['sensor', 'controller']:
            robot[obj.phobostype +
                  's'][namingUtils.getObjectName(obj)] = deriveDictEntry(obj)
            obj.select = False

    # parse materials
    print('\n\nParsing materials...')
    robot['materials'] = collectMaterials(objectlist)
    for obj in objectlist:
        if obj.phobostype == 'visual' and len(obj.data.materials) > 0:
            mat = obj.data.materials[0]
            if not namingUtils.getObjectName(mat) in robot['materials']:
                robot['materials'][namingUtils.getObjectName(
                    mat)] = deriveMaterial(
                        mat)  #this should actually never happen
            robot['links'][namingUtils.getObjectName(
                obj.parent)]['visual'][namingUtils.getObjectName(
                    obj, phobostype="visual"
                )]['material'] = namingUtils.getObjectName(mat)

    # gather information on groups of objects
    print('\n\nParsing groups...')
    for group in bpy.data.groups:  # TODO: get rid of the "data" part
        if len(group.objects) > 0 and namingUtils.getObjectName(
                group) != "RigidBodyWorld":
            robot['groups'][namingUtils.getObjectName(
                group)] = deriveGroupEntry(group)

    # gather information on chains of objects
    print('\n\nParsing chains...')
    chains = []
    for obj in bpy.data.objects:
        if obj.phobostype == 'link' and 'endChain' in obj:
            chains.extend(deriveChainEntry(obj))
    for chain in chains:
        robot['chains'][chain['name']] = chain

    # gather information on global lights
    print('\n\nParsing lights...')
    for obj in bpy.context.selected_objects:
        if obj.phobostype == 'light':
            robot['lights'][namingUtils.getObjectName(obj)] = deriveLight(obj)

    robot['poses'] = deriveStoredPoses()

    #shorten numbers in dictionary to n decimalPlaces and return it
    print('\n\nRounding numbers...')
    epsilon = 10**(-bpy.data.worlds[0].decimalPlaces
                   )  # TODO: implement this separately
    return generalUtils.epsilonToZero(robot, epsilon,
                                      bpy.data.worlds[0].decimalPlaces)