예제 #1
0
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
예제 #2
0
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
예제 #3
0
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)
예제 #4
0
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.')
예제 #5
0
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)
예제 #6
0
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
예제 #7
0
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