def _get_settings_for_animation(robot): """ Get the animation parameters start frame, end frame, framerate, and total time in seconds from Maya. :return: """ start_frame = pm.intField("i_programStartFrame", query=True, value=True) end_frame = pm.intField("i_programEndFrame", query=True, value=True) framerate = mimic_utils.get_maya_framerate() # Define the animation time in seconds. animation_time_sec = ((end_frame) - start_frame) / framerate # Raise warning if end frame and start frame incompatible if end_frame <= start_frame: warning = 'End Frame must be larger than Start Frame' raise mimic_utils.MimicError(warning) # Raise warning if no keyframes are set closest_ik_key = mimic_utils.get_closest_ik_keyframe(robot, start_frame)[0] if not type(closest_ik_key) == float: warning = 'You must set an IK or FK keyframe to ensure ' \ 'proper evaluation when saving a program; ' \ 'no program written' raise mimic_utils.MimicError(warning) # All good, create output dictionary animation_settings = {'Start Frame': start_frame, 'End Frame': end_frame, 'Framerate': framerate, 'Animation Time (sec)': animation_time_sec} return animation_settings
def _get_settings_for_animation(robot): """ Get the animation parameters start frame, end frame, framerate, and total time in seconds from Maya. :return: """ start_frame = pm.intField("i_programStartFrame", query=True, value=True) end_frame = pm.intField("i_programEndFrame", query=True, value=True) framerate = mimic_utils.get_maya_framerate() # Define the animation time in seconds. animation_time_sec = ((end_frame) - start_frame) / framerate # Raise warning if end frame and start frame incompatible if end_frame <= start_frame: warning = 'End Frame must be larger than Start Frame' raise mimic_utils.MimicError(warning) # Create output dictionary animation_settings = { 'Start Frame': start_frame, 'End Frame': end_frame, 'Framerate': framerate, 'Animation Time (sec)': animation_time_sec } return animation_settings
def save_program(*args): """ Save the program. :return: """ # Do this first upon button click! _clear_output_window() _initialize_export_progress_bar() # Check program, commands, raise exception on failure program_settings = _get_settings() animation_settings = program_settings[1] start_frame = animation_settings['Start Frame'] pm.currentTime(start_frame) # Force evaluation of reconcile rotation to ensure proper export mimic_utils.reconcile_rotation(force_eval=True) command_dicts = _get_command_dicts(*program_settings) violation_exception, violation_warning = _check_command_dicts(command_dicts, *program_settings) # If we're sampling keyframes only, we assume it's for a post-processor # that's not time-dependent, and, therefore, we shouldn't raise exceptions # for limit violations postproc_settings = program_settings[2] using_keyframes_only = postproc_settings['Using Keyframes Only'] if not using_keyframes_only: if violation_exception: _initialize_export_progress_bar(is_on=False) pm.scrollField(OUTPUT_WINDOW_NAME, insertText='\n\nNO PROGRAM EXPORTED!', edit=True) pm.headsUpMessage('WARNINGS: No Program Exported; ' \ 'See Mimic output window for details') raise mimic_utils.MimicError('Limit violations found. ' \ 'No Program Exported. ' \ 'See Mimic output window for details.') # Continue to save program: _process_program(command_dicts, *program_settings) if violation_warning: if not using_keyframes_only: pm.headsUpMessage('Program exported with warnings; ' \ 'See Mimic output window for details') else: pm.headsUpMessage('Program exported successfuly; ' \ 'See Mimic output window for details') else: pm.headsUpMessage('Program exported successfuly; ' \ 'See Mimic output window for details') _initialize_export_progress_bar(is_on=False)
def analyze_program(*args): """ Check program parameters, raise exception on failure :return: """ # Do this first upon button click! _clear_output_window() _initialize_export_progress_bar() # Check program, commands, raise exception on failure program_settings = _get_settings() robot_name = program_settings[0] animation_settings = program_settings[1] start_frame = animation_settings['Start Frame'] pm.currentTime(start_frame) # Force evaluation of reconcile rotation to ensure proper export mimic_utils.reconcile_rotation(force_eval=True) command_dicts = _get_command_dicts(*program_settings) limit_data = mimic_utils.get_all_limits(robot_name) violation_exception, violation_warning = _check_command_dicts(command_dicts, *program_settings) _initialize_export_progress_bar(is_on=False) # If PyQtGraph imports correctly, we can run the analysis graphing utility # Likeliest cause of import failure is no or improper installation of numPy # See Mimic installation instructions for more details on installing numPy try: import pyqtgraph as pg analysis.run(robot_name, command_dicts, limit_data) except ImportError: pm.warning('MIMIC: Analysis module did not load successfully; ' \ 'analysis graphing feature disabled. ' \ 'Check that you have numPy installed properly; ' \ 'see Mimic installation instructions for more details') # If we're sampling keyframes only, we assume it's for a post-processor # that's not time-dependent, and, therefore, we shouldn't raise exceptions # for limit violations postproc_settings = program_settings[2] using_keyframes_only = postproc_settings['Using Keyframes Only'] if violation_exception and not using_keyframes_only: raise mimic_utils.MimicError('Limit violations found. ' \ 'See Mimic output window for details.')
def save_program(*args): """ Save the program. :return: """ # Do this first upon button click! _clear_output_window() _initialize_export_progress_bar() # Check program, commands, raise exception on failure program_settings = _get_settings() animation_settings = program_settings[1] start_frame = animation_settings['Start Frame'] pm.currentTime(start_frame) command_dicts = _get_command_dicts(*program_settings) violation_exception, violation_warning = _check_command_dicts( command_dicts, *program_settings) # If we're sampling keyframes only, we assume it's for a post-processor # that's not time-dependent, and, therefore, we shouldn't raise exceptions # for limit violations postproc_settings = program_settings[2] using_keyframes_only = postproc_settings['Using Keyframes Only'] if not using_keyframes_only: if violation_exception: _initialize_export_progress_bar(is_on=False) pm.scrollField(OUTPUT_WINDOW_NAME, insertText='\n\nNO PROGRAM EXPORTED!', edit=True) pm.headsUpMessage('WARNINGS: No Program Exported; ' \ 'See Mimic output window for details') raise mimic_utils.MimicError('Limit violations found. ' \ 'No Program Exported. ' \ 'See Mimic output window for details.') # If axis 2 and 3 are coupled (as they are with FANUC, for example), # Modify A3 accordingly before post-processing # Note: we need to do this after limit checking to get accurate derivatives robot_name = program_settings[0] robot = pm.ls(robot_name)[0] if mimic_utils.axes_coupled(robot): command_dicts = _couple_axes(command_dicts) # Continue to save program: _process_program(command_dicts, *program_settings) if violation_warning: if not using_keyframes_only: pm.headsUpMessage('Program exported with warnings; ' \ 'See Mimic output window for details') else: pm.headsUpMessage('Program exported successfuly; ' \ 'See Mimic output window for details') else: pm.headsUpMessage('Program exported successfuly; ' \ 'See Mimic output window for details') _initialize_export_progress_bar(is_on=False)
def _get_settings_for_postproc(robot): """ Get program settings from the Mimic UI. :return program_settings: dictionary """ # Get all important settings using_time_interval = pm.radioCollection('sample_rate_radio_collection', query=True, select=True) == 'rb_timeInterval' using_keyframes_only = not using_time_interval # TODO: Clever, but not expandable time_interval_value = pm.textField('t_timeBetweenSamples', query=True, text=True) time_interval_units = 'seconds' \ if pm.radioButtonGrp('time_unit_radio_group', query=True, sl=True) == 1 \ else 'frames' ignore_warnings = pm.checkBox('cb_ignoreWarnings', value=True, query=True) processor_type = pm.optionMenu('postProcessorList', query=True, value=True) output_directory = pm.textField('t_programDirectoryText', text=True, query=True) output_filename = pm.textField('t_outputFileName', text=True, query=True) template_filename = pm.textField('t_templateFileName', text=True, query=True) overwrite_option = pm.checkBox('cb_overwriteFile', value=True, query=True) # Get time interval in seconds animation_settings = _get_settings_for_animation(robot) framerate = animation_settings['Framerate'] if time_interval_units == 'seconds': sample_rate_sec = float(time_interval_value) else: # time_interval_units == 'frames' sample_rate_sec = float(time_interval_value) / float(framerate) time_interval_in_seconds = sample_rate_sec # Check for warnings if using_time_interval: # Confirm that the time interval is valid try: time_interval_value = float(time_interval_value) assert time_interval_value > 0 except ValueError: if time_interval_units == 'seconds': warning = 'Time interval must be a float' raise mimic_utils.MimicError(warning) else: # time_interval_units == 'frames' warning = 'Time interval must be a float' raise mimic_utils.MimicError(warning) except AssertionError: if time_interval_units == 'seconds': warning = 'Time interval must be greater than zero' raise mimic_utils.MimicError(warning) else: # time_interval_units = 'frames' warning = 'Time interval must be greater than zero' raise mimic_utils.MimicError(warning) # Check if the robot-postproc compatibility warning was triggered processor = postproc_setup.POST_PROCESSORS[processor_type]() warning = _check_robot_postproc_compatibility(robot, processor) if warning != '': if not ignore_warnings: raise mimic_utils.MimicError(warning) else: warning += '\n' pm.scrollField(OUTPUT_WINDOW_NAME, insertText=warning, edit=True) # Assign values to output dict postproc_settings = { 'Using Time Interval': using_time_interval, 'Using Keyframes Only': using_keyframes_only, 'Time Interval Value': time_interval_value, 'Time Interval Units': time_interval_units, 'Time Interval in Seconds': time_interval_in_seconds, 'Ignore Warnings': ignore_warnings, 'Processor Type': processor_type, 'Output Directory': output_directory, 'Output Filename': output_filename, 'Template Filename': template_filename, 'Overwrite Option': overwrite_option } return postproc_settings
def _sample_frame_get_pose(robot_name, frame): """ Get robot Pose from an animation frame. :param robot_name: Name of the robot :param frame: Frame to sample :return: """ # Set the time # TODO: Implement this in parent function pm.currentTime(frame) # tool_name = get_tool_name(robot_name) tool_name = mimic_utils.get_tool_ctrl_path(robot_name) try: # Try to grab the named tool tool_object = pm.ls(tool_name)[ 0] # Try to get tool, may raise an exception except IndexError: # No tool attached, use flange tool_name = mimic_utils.get_tcp_hdl_path(robot_name) # Local Base Frame controller (circle control at base of the robot). base_name = pm.ls(mimic_utils.get_local_ctrl_path(robot_name))[0] # Get name of the tcp and base world_matrix = '.worldMatrix' tcp_name_world_matrix = tool_name + world_matrix base_name_world_matrix = base_name + world_matrix # TRANSLATIONS # Get translation with respect to Maya's world frame tcp_translation = pm.xform(tool_name, query=True, rp=True, ws=True) base_translation = pm.xform(base_name, query=True, rp=True, ws=True) # ROTATIONS # Get TCP rotation with respect to Maya's world frame _tcp_matrix = pm.getAttr(tcp_name_world_matrix, time=frame) tcp_rotation = general_utils.matrix_get_rotations(_tcp_matrix) # Get Base rotation with respect to Maya's world frame _base_matrix = pm.getAttr(base_name_world_matrix, time=frame) base_rotation = general_utils.matrix_get_rotations(_base_matrix) # TRANSFORMATIONS # Compose 4x4 matrices using the rotation and translation from the above tcp_matrix_4x4 = general_utils.matrix_compose_4x4(tcp_rotation, tcp_translation) base_matrix_4x4 = general_utils.matrix_compose_4x4(base_rotation, base_translation) # Invert the base matrix base_matrix_4x4 = general_utils.matrix_get_inverse(base_matrix_4x4) # Get pose itself initial_pose_matrix = general_utils.matrix_multiply( base_matrix_4x4, tcp_matrix_4x4) # CONVERSIONS # Decompose the initial pose matrix initial_translation = general_utils.matrix_get_translation( initial_pose_matrix) initial_rotations = general_utils.matrix_get_rotations(initial_pose_matrix) # Rearrange from Maya CS (mcs) to Robot CS (rcs) indices = [2, 0, 1] new_translation = [initial_translation[i] * 10 for i in indices] # cm to mm new_rotation = [[initial_rotations[i][j] for j in indices] for i in indices] # Define rotation matrix and convert the rotations based robot type # Based on the orientation of the coordinate frame of the mounting flange # TODO: Integrate this with rigs, unclear and shouldn't be hardcoded robot_type = mimic_utils.get_robot_type(robot_name) if robot_type == 'ABB': conversion_rotation = [[0, 0, -1], [0, 1, 0], [1, 0, 0]] # elif robot_type == 'KUKA': # conversion_rotation = [ # [0, -1, 0], # [0, 0, 1], # [-1, 0, 0] # ] else: raise mimic_utils.MimicError( 'Robot type not supported for Pose movement') # Perform the conversion operation itself converted_rotation = general_utils.matrix_multiply(conversion_rotation, new_rotation) # Compose pose pose_matrix = general_utils.matrix_compose_4x4(converted_rotation, new_translation) # Decompose pose as expected for output pose = general_utils.matrix_decompose_4x4_completely(pose_matrix) return pose