def _print_violations(violation_dicts, limits, limit_type): """ Format and print limit violations. :param violation_dicts: A list of dicts of axis violations :param limits: A list of robot robot axes limits :param limit_type: Name string of the limit type :return: """ warning = '' warning_template = ' {0:>{time_padding}}{1:>{frame_padding}}{2:>{limit_padding}}{3:>{val_padding}}\n' padding = {'val_padding' : 13, 'limit_padding' : 10, 'time_padding' : 10, 'frame_padding' : 10} for axis_name in sorted(violation_dicts): warning += axis_name + " {} Warnings:\n".format(limit_type) axis_num = int(axis_name.split(' ')[-1]) - 1 # This is super hacky... should fix. warning += warning_template.format('Time', 'Frame', 'Limit', 'Actual', **padding) for violation in violation_dicts[axis_name]: if limits[axis_name]['Max Limit']: axis_limit = general_utils.num_to_str(limits[axis_name]['Max Limit'], precision=3) else: return warning += warning_template.format( general_utils.num_to_str(violation['Time Index'], precision=3), general_utils.num_to_str(violation['Frame'], precision=3), axis_limit, general_utils.num_to_str(violation[postproc.AXES][axis_num], precision=3), **padding) pm.scrollField(OUTPUT_WINDOW_NAME, insertText=warning, edit=True)
def _process_records_command(command, opts): """ Process records command. :param command: Command tuple :opts opts: UserOptions tuple :return: """ params = [] # Add timestamp timestamp_padding = 16 timestamp = general_utils.num_to_str(command.time_index, include_sign=True, padding=timestamp_padding) params.append(timestamp) # Add primary parameters padding = 14 if command.axes is not None: formatted_params = [ general_utils.num_to_str(axis, include_sign=True, padding=padding) for axis in command.axes ] params.extend(formatted_params) if command.external_axes is not None: external_axes = [ axis for axis in command.external_axes if axis is not None ] formatted_params = [ general_utils.num_to_str(axis, include_sign=True, padding=padding) for axis in external_axes ] params.extend(formatted_params) if command.digital_output is not None: digital_output = [ io for io in command.digital_output if io is not None ] bitfield = 0 for output in digital_output: bitfield |= output.value << int(output.identifier) formatted_params = "\t{}".format(bitfield) params.extend(formatted_params) template = ''.join([TEMPLATES[RECORDS] for _ in params]) # Structure and format data, command formatted_record = template.format(*params) return formatted_record
def _process_records_command(command, opts): """ Process records command. :param command: Command tuple :opts opts: UserOptions tuple :return: """ params = [] # Add timestamp if user option is selected if opts.Include_timestamp: timestamp = general_utils.num_to_str(command.time_index) params.append(timestamp) # Add primary parameters if command.axes is not None: formatted_params = [ general_utils.num_to_str(axis) for axis in command.axes ] params.extend(formatted_params) if command.external_axes is not None: external_axes = [ axis for axis in command.external_axes if axis is not None ] formatted_params = [ general_utils.num_to_str(axis) for axis in external_axes ] params.extend(formatted_params) if command.digital_output is not None: digital_output = [ io for io in command.digital_output if io is not None ] formatted_params = [ general_utils.num_to_str(io) for io in digital_output ] params.extend(formatted_params) # Structure and format data, command formatted_record = '\t'.join(param for param in params) return formatted_record
def _print_axis_stats(axis_stats, limit_type): """ Format and print axis statistics. :param axis_stats: A dict of axis statistics :param limit_type: Name string of the limit type :return: """ # TODO: This function is a mess. Should definitely be cleaned up, # but since this is all getting graphed anyway... # TODO: stop hardcoding num_axes num_axes = 6 axis_template = '>>> {0:>{axis_padding}} ' axis_padding = {'axis_padding' : 2} res = [None] * (num_axes + 1) # Header res[0] = axis_template.format('A', **axis_padding) for axis_index in range(num_axes): res[axis_index + 1] = axis_template.format(axis_index + 1, **axis_padding) # Min min_max_template = '{0:>{time_padding}}{1:>{frame_padding}}{2:>{val_padding}} |' min_max_padding = {'val_padding' : 13, 'time_padding' : 10, 'frame_padding' : 10} if axis_stats['min']: res[0] += min_max_template.format('Time', 'Frame', 'Min', **min_max_padding) for axis_index, command in enumerate(axis_stats['min']): res[axis_index+1] += min_max_template.format( general_utils.num_to_str(command['Time Index'], precision=3), general_utils.num_to_str(command['Frame'], precision=3), general_utils.num_to_str(command[postproc.AXES][axis_index], precision=3), **min_max_padding) # Max if axis_stats['max']: res[0] += min_max_template.format('Time', 'Frame', 'Max', **min_max_padding) for axis_index, command in enumerate(axis_stats['max']): res[axis_index+1] += min_max_template.format( general_utils.num_to_str(command['Time Index'], precision=3), general_utils.num_to_str(command['Frame'], precision=3), general_utils.num_to_str(command[postproc.AXES][axis_index], precision=3), **min_max_padding) # Avg avg_template = '{0:>{avg_padding}}' avg_padding = {'avg_padding' : 10} if axis_stats['avg']: res[0] += avg_template.format('Avg', **avg_padding) for axis_index, axis_avg in enumerate(axis_stats['avg']): res[axis_index+1] += avg_template.format( general_utils.num_to_str(axis_avg, precision=3), **avg_padding) # Formatting stats_str = '{} Stats:\n'.format(limit_type) + '\n'.join(res) + '\n' pm.scrollField(OUTPUT_WINDOW_NAME, insertText=stats_str, edit=True)
def _check_velocity_of_axes(robot, command_dicts, framerate): """ Check a list of commands for velocity errors. Construct string to return printable statement of all exceeded velocities for each axis; ex. range [0, 1, 2, 3] will be formatted '0-3'. :param robot: name string of the selected robot :param command_dicts: A list of list of robot axes :param framerate: Maya animation framerate (fps) :return: """ frames = [c['Frame'] for c in command_dicts] axes_at_each_frame = [c[postproc.AXES] for c in command_dicts] velocity_limits = mimic_utils.get_velocity_limits(robot) max_velocities = [0 for _ in range(6)] max_velocities_frames = [0 for _ in range(6)] violations = {} _previous_frame = 0 _previous_axes = [] for i in range(len(axes_at_each_frame)): # Get time and axes right now _current_frame = frames[i] _current_axes = axes_at_each_frame[i] if i > 0: # skip zeroth displacement_time = abs(_current_frame - _previous_frame) / framerate for j in range(len(_current_axes)): _previous_axis = _previous_axes[j] _current_axis = _current_axes[j] displacement = abs(_current_axis - _previous_axis) velocity = displacement / displacement_time # Record max velocities if velocity > max_velocities[j]: max_velocities[j] = velocity max_velocities_frames[j] = _current_frame # Check if a limit has been violated if velocity > velocity_limits[j]: # Add axis name to violations dict axis_name = 'Axis {}'.format(j + 1) if axis_name not in violations: violations[axis_name] = [] # Add time to violations dict violations[axis_name].append(_current_frame) _previous_frame = _current_frame _previous_axes = _current_axes # TODO: This is a hack! print 'Max velocities:' template_string = '>>> {0:>{padding1}}{1:>{padding2}}{2:>{padding3}}' print template_string.format('A', 'Velocity', 'Frame', padding1=2, padding2=10, padding3=10) for i in range(6): print template_string.format( i + 1, general_utils.num_to_str(max_velocities[i], precision=3), general_utils.num_to_str(max_velocities_frames[i], precision=3), padding1=2, padding2=10, padding3=10) # Format a warning warning_params = [] # Get axis keys in order axes = violations.keys() if axes: axes.sort() for axis_name in axes: # Check if the axis key has values times = violations[axis_name] time_ranges = general_utils.list_as_range_strings(times) time_ranges_formatted = '\n'.join('\t{}'.format(time_range) for time_range in time_ranges) warning_params.append(axis_name) warning_params.append(time_ranges_formatted) # Create warning warning = 'WARNING!\n' \ 'Velocity limits have been violated!\n' \ 'See the following frames:\n' warning_params.insert(0, warning) return '\n'.join(warning_params) + '\n', max_velocities else: return '', max_velocities
def _process_motion_command(command, opts): """ Process motion command. :param command: Command tuple :param opts: UserOptions tuple :return: """ motion_data_type = None motion_data = [] # empty data container # Interpret linear motion command if opts.Use_linear_motion: motion_type = MOVE_LIN if command.pose is not None: motion_data.extend(_convert_pose(command.pose)) if command.configuration is not None: if command.external_axes is not None: motion_data_type = E6POS external_axes = [axis if axis is not None else 0 for axis in command.external_axes] motion_data.extend(external_axes) else: motion_data_type = POS motion_data.extend(_convert_configuration(command.configuration)) else: motion_data_type = FRAME else: raise ValueError('Invalid command') # Interpret nonlinear motion command elif opts.Use_nonlinear_motion: if opts.Use_continuous_motion: motion_type = MOVE_CPTP else: motion_type = MOVE_PTP if command.axes is not None: motion_data.extend(command.axes) if command.external_axes is not None: motion_data_type = E6AXIS external_axes = [axis if axis is not None else 0 for axis in command.external_axes] motion_data.extend(external_axes) else: motion_data_type = AXIS elif command.pose is not None: motion_data_type = FRAME motion_data.extend(_convert_pose(command.pose)) else: raise ValueError('Invalid command') else: # User never supplied a motion type raise ValueError('Invalid motion type') # Format parameters into string motion_data = [general_utils.num_to_str(d, include_sign=False, precision=3) for d in motion_data] # Structure and format data, command formatted_motion_data = postproc.fill_template( motion_data, STRUCTURES[motion_data_type], TEMPLATES[motion_data_type]) formatted_motion = postproc.fill_template( formatted_motion_data, STRUCTURES[motion_type], TEMPLATES[motion_type]) return formatted_motion
def _process_motion_command(command, opts): # Implement in base class! """ Process motion command. :param command: Command tuple :param opts: UserOptions tuple :return: """ motion_type = None target_data_type = None target_data = [] # Interpret linear motion command if opts.Use_linear_motion: if command.pose is not None: motion_type = MOVE_L target_data_type = ROBTARGET pose = _convert_pose(command.pose) params = [ general_utils.num_to_str(p, include_sign=False, precision=3) for p in pose ] target_data.extend(params) if command.configuration is not None: configuration = _convert_configuration(command.configuration) params = [ general_utils.num_to_str(p, include_sign=False, precision=3, simplify_ints=True) for p in configuration ] target_data.extend(params) else: target_data.extend(rapid_config.DEFAULT_CONF) if command.external_axes is not None: external_axes = [ axis if axis is not None else '9E9' for axis in command.external_axes ] params = [ general_utils.num_to_str(p, include_sign=False, precision=3) for p in external_axes ] target_data.extend(params) else: target_data.extend(rapid_config.DEFAULT_EXAX) else: raise ValueError('Invalid command') # Interpret nonlinear motion command elif opts.Use_nonlinear_motion: if command.axes is not None: motion_type = MOVE_ABS_J target_data_type = JOINTTARGET axes = command.axes params = [ general_utils.num_to_str(p, include_sign=False, precision=3) for p in axes ] target_data.extend(params) if command.external_axes is not None: external_axes = [ axis if axis is not None else '9E9' for axis in command.external_axes ] params = [ general_utils.num_to_str(p, include_sign=False, precision=3) for p in external_axes ] target_data.extend(params) else: target_data.extend(rapid_config.DEFAULT_EXAX) elif command.pose is not None: motion_type = MOVE_J target_data_type = ROBTARGET pose = _convert_pose(command.pose) params = [ general_utils.num_to_str(p, include_sign=False, precision=3) for p in pose ] target_data.extend(params) if command.configuration is not None: configuration = _convert_configuration(command.configuration) params = [ general_utils.num_to_str(p, include_sign=False, precision=3, simplify_ints=True) for p in configuration ] target_data.extend(params) else: target_data.extend(rapid_config.DEFAULT_CONF) if command.external_axes is not None: external_axes = [ axis if axis is not None else '9E9' for axis in command.external_axes ] params = [ general_utils.num_to_str(p, include_sign=False, precision=3) for p in external_axes ] target_data.extend(params) else: target_data.extend(rapid_config.DEFAULT_EXAX) else: raise ValueError('Invalid command') else: # User never supplied a motion type raise ValueError('Invalid motion type') # Structure and format data, command formatted_target_data = postproc.fill_template( target_data, STRUCTURES[target_data_type], TEMPLATES[target_data_type]) if opts.Use_motion_as_variables: formatted_variable = postproc.fill_template(formatted_target_data, STRUCTURES[VARIABLE], TEMPLATES[VARIABLE]) return formatted_variable else: motion_data = [ motion_type, formatted_target_data, rapid_config.DEFAULT_SPEED, rapid_config.DEFAULT_ZONE, rapid_config.DEFAULT_TOOL, rapid_config.DEFAULT_WOBJ ] formatted_motion = postproc.fill_template(motion_data, STRUCTURES[MOVE], TEMPLATES[MOVE]) return formatted_motion