def loadPose(modelname, posename): """ Load and apply a robot's stored pose. :param modelname: The model's name. :type modelname: str. :param posename: The name the pose is stored under. :type posename: str. :return Nothing. """ load_file = bUtils.readTextFile(modelname + '::poses') if load_file == '': log('No poses stored.', 'ERROR', 'loadPose') return poses = yaml.load(load_file) try: pose = poses[posename] prev_mode = bpy.context.mode bpy.ops.object.mode_set(mode='POSE') for obj in sUtils.getObjectsByPhobostypes(['link']): if nUtils.getObjectName(obj, 'joint') in pose['joints']: obj.pose.bones['Bone'].rotation_mode = 'XYZ' obj.pose.bones['Bone'].rotation_euler.y = pose['joints'][nUtils.getObjectName(obj, 'joint')] bpy.ops.object.mode_set(mode=prev_mode) except KeyError: log('No pose with name ' + posename + ' stored for model ' + modelname, 'ERROR', "loadPose")
def storePose(modelname, posename): """ Stores the current pose of all of a robot's selected joints. Existing poses of the same name will be overwritten. :param modelname: The robot the pose belongs to. :type modelname: str. :param posename: The name the pose will be stored under. :type posename: str. :return: Nothing. """ rootlink = None for root in sUtils.getRoots(): if root['modelname'] == modelname: rootlink = root if rootlink: filename = modelname + '::poses' posedict = yaml.load(bUtils.readTextFile(filename)) if not posedict: posedict = {posename: {'name': posename, 'joints': {}}} else: posedict[posename] = {'name': posename, 'joints': {}} bpy.ops.object.mode_set(mode='POSE') links = sUtils.getChildren(rootlink, ('link',), True, False) for link in (link for link in links if 'joint/type' in link and link['joint/type'] not in ['fixed', 'floating']): link.pose.bones['Bone'].rotation_mode = 'XYZ' posedict[posename]['joints'][nUtils.getObjectName(link, 'joint')] = link.pose.bones['Bone'].rotation_euler.y bUtils.updateTextFile(filename, yaml.dump(posedict, default_flow_style=False)) else: log("No model root could be found to store the pose for", "ERROR", "storePose")
def storePose(robot_name, pose_name): """ Store the current pose of all of a robot's selected links. Existing poses of the same name will be overwritten. :param robot_name: The robot the pose belongs to. :type robot_name: str. :param pose_name: The name the pose will be stored under. :type pose_name: str. :return: Nothing. """ file_name = 'robot_poses_' + robot_name load_file = blenderUtils.readTextFile(file_name) if load_file == '': poses = {} else: poses = yaml.load(load_file) new_pose = {} prev_mode = bpy.context.mode bpy.ops.object.mode_set(mode='POSE') for root in selectionUtils.getRoots(): if root['modelname'] == robot_name: links = selectionUtils.getChildren(root) for link in links: if link.select and link.phobostype == 'link': link.pose.bones['Bone'].rotation_mode = 'XYZ' new_pose[namingUtils.getObjectName(link, 'joint')] = link.pose.bones['Bone'].rotation_euler.y bpy.ops.object.mode_set(mode=prev_mode) poses[pose_name] = new_pose blenderUtils.updateTextFile(file_name, yaml.dump(poses))
def storePose(modelname, posename): """ Stores the current pose of all of a robot's selected joints. Existing poses of the same name will be overwritten. :param modelname: The robot the pose belongs to. :type modelname: str. :param posename: The name the pose will be stored under. :type posename: str. :return: Nothing. """ rootlink = None for root in sUtils.getRoots(): if root['modelname'] == modelname: rootlink = root if rootlink: filename = modelname + '::poses' posedict = yaml.load(bUtils.readTextFile(filename)) if not posedict: posedict = {posename: {'name': posename, 'joints': {}}} else: posedict[posename] = {'name': posename, 'joints': {}} bpy.ops.object.mode_set(mode='POSE') links = sUtils.getChildren(rootlink, ('link', ), True, False) for link in (link for link in links if 'joint/type' in link and link['joint/type'] not in ['fixed', 'floating']): link.pose.bones['Bone'].rotation_mode = 'XYZ' posedict[posename]['joints'][nUtils.getObjectName( link, 'joint')] = link.pose.bones['Bone'].rotation_euler.y bUtils.updateTextFile(filename, yaml.dump(posedict, default_flow_style=False)) else: log("No model root could be found to store the pose for", "ERROR")
def storePose(robot_name, pose_name): """ Store the current pose of all of a robot's selected links. Existing poses of the same name will be overwritten. :param robot_name: The robot the pose belongs to. :type robot_name: str. :param pose_name: The name the pose will be stored under. :type pose_name: str. :return: Nothing. """ file_name = 'robot_poses_' + robot_name load_file = blenderUtils.readTextFile(file_name) if load_file == '': poses = {} else: poses = yaml.load(load_file) new_pose = {} prev_mode = bpy.context.mode bpy.ops.object.mode_set(mode='POSE') for root in selectionUtils.getRoots(): if root['modelname'] == robot_name: links = selectionUtils.getChildren(root) for link in links: if link.select and link.phobostype == 'link': link.pose.bones['Bone'].rotation_mode = 'XYZ' new_pose[namingUtils.getObjectName( link, 'joint')] = link.pose.bones['Bone'].rotation_euler.y bpy.ops.object.mode_set(mode=prev_mode) poses[pose_name] = new_pose blenderUtils.updateTextFile(file_name, yaml.dump(poses))
def loadPose(modelname, posename): """ Load and apply a robot's stored pose. :param modelname: The model's name. :type modelname: str. :param posename: The name the pose is stored under. :type posename: str. :return Nothing. """ load_file = bUtils.readTextFile(modelname + '::poses') if load_file == '': log('No poses stored.', 'ERROR') return poses = yaml.load(load_file) try: pose = poses[posename] prev_mode = bpy.context.mode bpy.ops.object.mode_set(mode='POSE') for obj in sUtils.getObjectsByPhobostypes(['link']): if nUtils.getObjectName(obj, 'joint') in pose['joints']: obj.pose.bones['Bone'].rotation_mode = 'XYZ' obj.pose.bones['Bone'].rotation_euler.y = float( pose['joints'][nUtils.getObjectName(obj, 'joint')]) bpy.ops.object.mode_set(mode=prev_mode) except KeyError: log('No pose with name ' + posename + ' stored for model ' + modelname, 'ERROR')
def storePose(root, posename): """Stores the current pose of all of a model's selected joints. Existing poses of the same name will be overwritten. Args: root(bpy_types.Object): root of the model the pose belongs to posename(str): name the pose will be stored under Returns: : Nothing. """ if root: filename = nUtils.getModelName(root) + '::poses' posedict = json.loads(bUtils.readTextFile(filename)) if not posedict: posedict = {posename: {'name': posename, 'joints': {}}} else: posedict[posename] = {'name': posename, 'joints': {}} links = sUtils.getChildren(root, ('link', ), True, False) sUtils.selectObjects([root] + links, clear=True, active=0) bpy.ops.object.mode_set(mode='POSE') for link in (link for link in links if 'joint/type' in link and link['joint/type'] not in ['fixed', 'floating']): link.pose.bones['Bone'].rotation_mode = 'XYZ' posedict[posename]['joints'][nUtils.getObjectName( link, 'joint')] = link.pose.bones['Bone'].rotation_euler.y bpy.ops.object.mode_set(mode='OBJECT') posedict = gUtils.roundFloatsInDict( posedict, ioUtils.getExpSettings().decimalPlaces) bUtils.updateTextFile(filename, json.dumps(posedict)) else: log("No model root provided to store the pose for", "ERROR")
def loadPose(modelname, posename): """Load and apply a robot's stored pose. :param modelname: the model's name :type modelname: str :param posename: the name the pose is stored under :type posename: str """ load_file = bUtils.readTextFile(modelname + '::poses') if load_file == '': log('No poses stored.', 'ERROR') return loadedposes = yaml.load(load_file) if posename not in loadedposes: log('No pose with name ' + posename + ' stored for model ' + modelname, 'ERROR') return prev_mode = bpy.context.mode pose = loadedposes[posename] # apply rotations to all joints defined by the pose try: bpy.ops.object.mode_set(mode='POSE') for obj in sUtils.getObjectsByPhobostypes(['link']): if nUtils.getObjectName(obj, 'joint') in pose['joints']: obj.pose.bones['Bone'].rotation_mode = 'XYZ' obj.pose.bones['Bone'].rotation_euler.y = float( pose['joints'][nUtils.getObjectName(obj, 'joint')]) except KeyError as error: log("Could not apply the pose: " + str(error), 'ERROR') finally: # restore previous mode bpy.ops.object.mode_set(mode=prev_mode)
def deriveTextData(modelname): """ Collect additional data stored for a specific model. :param modelname: Name of the model for which data should be derived. :return: A dictionary containing additional data. """ datadict = {} datatextfiles = [ text for text in bpy.data.texts if text.name.startswith(modelname + '::') ] for text in datatextfiles: try: dataname = text.name.split('::')[-1] except IndexError: log("Possibly invalidly named model data text file: " + modelname, "WARNING") try: data = yaml.load(bUtils.readTextFile(text.name)) except yaml.scanner.ScannerError: log("Invalid formatting of data file: " + dataname, "ERROR") if data: datadict[dataname] = data return datadict
def getPoses(modelname): """ Get the names of the poses that have been stored for a robot. :param modelname: The model's name. :return: A list containing the poses' names. """ load_file = bUtils.readTextFile(modelname + '::poses') if load_file == '': return [] poses = yaml.load(load_file) return poses.keys()
def get_poses(robot_name): """ Get the names of the poses that have been stored for a robot. :param robot_name: The robot's name. :return: A list containing the poses' names. """ load_file = blenderUtils.readTextFile('robot_poses_' + robot_name) if load_file == '': return [] poses = yaml.load(load_file) return poses.keys()
def deriveStoredPoses(): """ """ poses_file = blenderUtils.readTextFile('robot_poses') if poses_file == '': return {} poses = yaml.load(poses_file) pose_dict = {} for pose in poses: new_pose = {} new_pose['name'] = pose new_pose['joints'] = poses[pose] pose_dict[pose] = new_pose return pose_dict
def getPoses(modelname): """Get the names of the poses that have been stored for a robot. Args: modelname: The model's name. Returns: : A list containing the poses' names. """ load_file = bUtils.readTextFile(modelname + '::poses') if load_file == '': return [] poses = json.loads(load_file) return poses.keys()
def storePose(pose_name): load_file = blenderUtils.readTextFile('robot_poses') if load_file == '': poses = {} else: poses = yaml.load(load_file) new_pose = {} prev_mode = bpy.context.mode bpy.ops.object.mode_set(mode='POSE') for obj in selectionUtils.returnObjectList('link'): obj.pose.bones['Bone'].rotation_mode = 'XYZ' new_pose[namingUtils.getObjectName(obj, 'joint')] = obj.pose.bones['Bone'].rotation_euler.y bpy.ops.object.mode_set(mode=prev_mode) poses[pose_name] = new_pose blenderUtils.updateTextFile('robot_poses', yaml.dump(poses))
def loadPose(pose_name): load_file = blenderUtils.readTextFile('robot_poses') if load_file == '': log('No poses stored.', 'ERROR') return poses = yaml.load(load_file) if pose_name in poses: prev_mode = bpy.context.mode bpy.ops.object.mode_set(mode='POSE') for obj in selectionUtils.returnObjectList('link'): if namingUtils.getObjectName(obj, 'joint') in poses[pose_name]: obj.pose.bones['Bone'].rotation_mode = 'XYZ' obj.pose.bones['Bone'].rotation_euler.y = poses[pose_name][namingUtils.getObjectName(obj, 'joint')] bpy.ops.object.mode_set(mode=prev_mode) else: log('No pose with name ' + pose_name + ' stored.', 'ERROR')
def deriveTextData(modelname): """ Collect additional data stored for a specific model. :param modelname: Name of the model for which data should be derived. :return: A dictionary containing additional data. """ datadict = {} datatextfiles = [text for text in bpy.data.texts if text.name.startswith(modelname+'::')] for text in datatextfiles: try: dataname = text.name.split('::')[-1] except IndexError: log("Possibly invalidly named model data text file: " + modelname, "WARNING", "deriveTextData") try: data = yaml.load(bUtils.readTextFile(text.name)) except yaml.scanner.ScannerError: log("Invalid formatting of data file: " + dataname, "ERROR", "deriveTextData") if data: datadict[dataname] = data return datadict
def loadPose(robot_name, pose_name): """ Load and apply a robot's stored pose. :param robot_name: The robot's name. :type robot_name: str. :param pose_name: The name the pose is stored under. :type pose_name: str. :return Nothing. """ load_file = blenderUtils.readTextFile('robot_poses_' + robot_name) if load_file == '': log('No poses stored.', 'ERROR') return poses = yaml.load(load_file) if pose_name in poses: prev_mode = bpy.context.mode bpy.ops.object.mode_set(mode='POSE') for obj in selectionUtils.returnObjectList('link'): if namingUtils.getObjectName(obj, 'joint') in poses[pose_name]: obj.pose.bones['Bone'].rotation_mode = 'XYZ' obj.pose.bones['Bone'].rotation_euler.y = poses[pose_name][namingUtils.getObjectName(obj, 'joint')] bpy.ops.object.mode_set(mode=prev_mode)
def storePose(root, posename): """Stores the current pose of all of a model's selected joints. Existing poses of the same name will be overwritten. Args: root(bpy_types.Object): root of the model the pose belongs to posename(str): name the pose will be stored under Returns: : Nothing. """ if root: filename = nUtils.getModelName(root) + '::poses' posedict = yaml.load(bUtils.readTextFile(filename)) if not posedict: posedict = {posename: {'name': posename, 'joints': {}}} else: posedict[posename] = {'name': posename, 'joints': {}} links = sUtils.getChildren(root, ('link',), True, False) sUtils.selectObjects([root] + links, clear=True, active=0) bpy.ops.object.mode_set(mode='POSE') for link in ( link for link in links if 'joint/type' in link and link['joint/type'] not in ['fixed', 'floating'] ): link.pose.bones['Bone'].rotation_mode = 'XYZ' posedict[posename]['joints'][nUtils.getObjectName(link, 'joint')] = link.pose.bones[ 'Bone' ].rotation_euler.y bpy.ops.object.mode_set(mode='OBJECT') posedict = gUtils.roundFloatsInDict(posedict, ioUtils.getExpSettings().decimalPlaces) bUtils.updateTextFile(filename, yaml.dump(posedict, default_flow_style=False)) else: log("No model root provided to store the pose for", "ERROR")
def loadPose(modelname, posename): """Load and apply a robot's stored pose. Args: modelname(str): the model's name posename(str): the name the pose is stored under Returns: """ load_file = bUtils.readTextFile(modelname + '::poses') if load_file == '': log('No poses stored.', 'ERROR') return loadedposes = yaml.load(load_file) if posename not in loadedposes: log('No pose with name ' + posename + ' stored for model ' + modelname, 'ERROR') return prev_mode = bpy.context.mode pose = loadedposes[posename] # apply rotations to all joints defined by the pose try: bpy.ops.object.mode_set(mode='POSE') for obj in sUtils.getObjectsByPhobostypes(['link']): if nUtils.getObjectName(obj, 'joint') in pose['joints']: obj.pose.bones['Bone'].rotation_mode = 'XYZ' obj.pose.bones['Bone'].rotation_euler.y = float( pose['joints'][nUtils.getObjectName(obj, 'joint')] ) except KeyError as error: log("Could not apply the pose: " + str(error), 'ERROR') finally: # restore previous mode bpy.ops.object.mode_set(mode=prev_mode)
def deriveStoredPoses(): """ Collect the poses that have been stored for the scene's robots. :return: A dictionary containing the poses. """ poses_dict = {} for text in bpy.data.texts: file_name = text.name if file_name.startswith('robot_poses_'): robot_name = file_name[len('robot_poses_'):] poses_file = blenderUtils.readTextFile(file_name) if poses_file == '': poses_dict[robot_name] = {} break poses = yaml.load(poses_file) pose_dict = {} for pose in poses: new_pose = {} new_pose['name'] = pose new_pose['joints'] = poses[pose] pose_dict[pose] = new_pose poses_dict[robot_name] = pose_dict return poses_dict
def loadPose(robot_name, pose_name): """ Load and apply a robot's stored pose. :param robot_name: The robot's name. :type robot_name: str. :param pose_name: The name the pose is stored under. :type pose_name: str. :return Nothing. """ load_file = blenderUtils.readTextFile('robot_poses_' + robot_name) if load_file == '': log('No poses stored.', 'ERROR') return poses = yaml.load(load_file) if pose_name in poses: prev_mode = bpy.context.mode bpy.ops.object.mode_set(mode='POSE') for obj in selectionUtils.returnObjectList('link'): if namingUtils.getObjectName(obj, 'joint') in poses[pose_name]: obj.pose.bones['Bone'].rotation_mode = 'XYZ' obj.pose.bones['Bone'].rotation_euler.y = poses[pose_name][ namingUtils.getObjectName(obj, 'joint')] bpy.ops.object.mode_set(mode=prev_mode)
def deriveModelDictionary(root, name='', objectlist=[]): """Returns a dictionary representation of a Phobos model. If name is not specified, it overrides the modelname in the root. If the modelname is not defined at all, 'unnamed' will be used instead. Args: root(bpy_types.Object): root object of the model name(str, optional): name for the derived model (Default value = '') objectlist(list: bpy_types.Object): objects to derive the model from objectlist: (Default value = []) Returns: """ if root.phobostype not in ['link', 'submodel']: log(root.name + " is no valid 'link' or 'submodel' object.", "ERROR") return None # define model name if name: modelname = name elif 'model/name' in root: modelname = root['model/name'] else: modelname = 'unnamed' # define model version if 'model/version' in root: modelversion = root['model/version'] else: modelversion = 'undefined' modeldescription = bUtils.readTextFile('README.md') model = { 'links': {}, 'joints': {}, 'sensors': {}, 'motors': {}, 'controllers': {}, 'materials': {}, 'meshes': {}, 'lights': {}, 'groups': {}, 'chains': {}, 'date': datetime.now().strftime("%Y%m%d_%H:%M"), 'name': modelname, 'version': modelversion, 'description': modeldescription, } log( "Creating dictionary for model '" + modelname + "' with root '" + root.name + "'.", 'INFO', prefix="\n", ) # create tuples of objects belonging to model if not objectlist: objectlist = sUtils.getChildren( root, selected_only=ioUtils.getExpSettings().selectedOnly, include_hidden=False ) linklist = [link for link in objectlist if link.phobostype == 'link'] # digest all the links to derive link and joint information log("Parsing links, joints and motors... " + (str(len(linklist))) + " total.", "INFO") for link in linklist: # parse link information (including inertia) model['links'][nUtils.getObjectName(link, 'link')] = deriveLink( link, logging=True, objectlist=objectlist ) # parse joint and motor information if sUtils.getEffectiveParent(link): # joint may be None if link is a root # to prevent confusion links are always defining also joints jointdict = deriveJoint(link, logging=True, adjust=True) log(" Setting joint type '{}' for link.".format(jointdict['type']), 'DEBUG') # first check if we have motor information in the joint properties # if so they can be extended/overwritten by motor objects later on if '$motor' in jointdict: motordict = jointdict['$motor'] # at least we need a type property if 'type' in motordict: # if no name is given derive it from the joint if not 'name' in motordict: motordict["name"] = jointdict['name'] model['motors'][motordict['name']] = motordict # link the joint by name: motordict['joint'] = jointdict['name'] del jointdict['$motor'] model['joints'][jointdict['name']] = jointdict for mot in [child for child in link.children if child.phobostype == 'motor']: motordict = motormodel.deriveMotor(mot, jointdict) # motor may be None if no motor is attached if motordict: log(" Added motor {} to link.".format(motordict['name']), 'DEBUG') if motordict['name'] in model["motors"]: model['motors'][motordict['name']].update(motordict) else: model['motors'][motordict['name']] = motordict # parse sensors and controllers sencons = [obj for obj in objectlist if obj.phobostype in ['sensor', 'controller']] log("Parsing sensors and controllers... {} total.".format(len(sencons)), 'INFO') for obj in sencons: props = deriveDictEntry(obj, names=True, objectlist=objectlist) model[obj.phobostype + 's'][nUtils.getObjectName(obj)] = props # parse materials log("Parsing materials...", 'INFO') model['materials'] = collectMaterials(objectlist) for obj in objectlist: if obj.phobostype == 'visual': mat = obj.active_material if mat: if mat.name not in model['materials']: model['materials'][mat.name] = deriveMaterial(mat) linkname = nUtils.getObjectName( sUtils.getEffectiveParent(obj, ignore_selection=bool(objectlist)) ) model['links'][linkname]['visual'][nUtils.getObjectName(obj)][ 'material' ] = mat.name # identify unique meshes log("Parsing meshes...", "INFO") for obj in objectlist: try: if ( (obj.phobostype == 'visual' or obj.phobostype == 'collision') and (obj['geometry/type'] == 'mesh') and (obj.data.name not in model['meshes']) ): model['meshes'][obj.data.name] = obj #todo2.9: for lod in obj.lod_levels: # if lod.object.data.name not in model['meshes']: # model['meshes'][lod.object.data.name] = lod.object except KeyError: log("Undefined geometry type in object " + obj.name, "ERROR") # gather information on groups of objects log("Parsing groups...", 'INFO') #todo2.9: TODO: get rid of the "data" part and check for relation to robot # for group in bpy.data.groups: # # skip empty groups # if not group.objects: # continue # # handle submodel groups separately from other groups # if 'submodeltype' in group.keys(): # continue # # TODO create code to derive Submodels # # model['submodels'] = deriveSubmodel(group) # elif nUtils.getObjectName(group, 'group') != "RigidBodyWorld": # model['groups'][nUtils.getObjectName(group, 'group')] = deriveGroupEntry(group) # gather information on chains of objects log("Parsing chains...", "INFO") chains = [] for obj in objectlist: if obj.phobostype == 'link' and 'endChain' in obj: chains.extend(deriveChainEntry(obj)) for chain in chains: model['chains'][chain['name']] = chain # gather information on lights log("Parsing lights...", "INFO") for obj in objectlist: if obj.phobostype == 'light': model['lights'][nUtils.getObjectName(obj)] = deriveLight(obj) # gather submechanism information from links log("Parsing submechanisms...", "INFO") def getSubmechanisms(link): """ Args: link: Returns: """ if 'submechanism/name' in link.keys(): submech = { 'type': link['submechanism/type'], 'contextual_name': link['submechanism/name'], 'name': link['submechanism/subtype'] if 'submechanism/subtype' in link else link['submechanism/type'], 'jointnames_independent': [ nUtils.getObjectName(j, 'joint') for j in link['submechanism/independent'] ], 'jointnames_spanningtree': [ nUtils.getObjectName(j, 'joint') for j in link['submechanism/spanningtree'] ], 'jointnames_active': [ nUtils.getObjectName(j, 'joint') for j in link['submechanism/active'] ], # TODO: this should work in almost all cases, still a bit of a hack: 'file_path': '../submechanisms/urdf/' + link['submechanism/name'] + '.urdf', } log(' ' + submech['contextual_name'], 'DEBUG') else: submech = None mechanisms = [submech] if submech else [] for c in link.children: if c.phobostype in ['link', 'interface'] and c in objectlist: mechanisms.extend(getSubmechanisms(c)) return mechanisms model['submechanisms'] = getSubmechanisms(root) # add additional data to model model.update(deriveTextData(model['name'])) # shorten numbers in dictionary to n decimalPlaces and return it log("Rounding numbers to {} digits.".format(ioUtils.getExpSettings().decimalPlaces), 'INFO') model = roundFloatsInDict(model, ioUtils.getExpSettings().decimalPlaces) log("Sorting objects.", 'DEBUG') model = sortListsInDict(model) return model