Zum Inhalt

SimulationProgram

A simulation program.

It's holding a list of instructions and reference to its parent if applicable. Also takes note of the current robot position and cube state.

Attributes:

Name Type Description
name str

the name of the simulation program for logging purposes

parent Optional[SimulationProgram]

the parent simulation program for building a tree-like structure

initial_cube_state CubeState

the cube state in the beginning of the program when no intruction has been carried out

initial_robot_joints List[float]

the angle of each robot joint before the simulation should start

collision_checking_result Optional[SimulationResult]

the result of the path simulation (including collision checking) through RoboDK

append_instruction(self, instruction, recalculate_resulting_cube_state=True)

Appends a given instruction to the end of the program.

Parameters:

Name Type Description Default
instruction SimulationInstruction

the instruction to append

required
recalculate_resulting_cube_state bool

flag, indicating whether to immediately recalculate the resulting cube state or post pone it to the next access

True
Source code in core/manipulator/SimulationProgram.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
def append_instruction(self, instruction: SimulationInstruction, recalculate_resulting_cube_state: bool = True):
    """Appends a given instruction to the end of the program.

    Args:
        instruction: the instruction to append
        recalculate_resulting_cube_state: flag, indicating whether to immediately recalculate the resulting cube state or post pone it to the next access
    """

    assert isinstance(instruction, SimulationInstruction)

    if recalculate_resulting_cube_state:
        self._resulting_cube_state = instruction.apply_to_cube_state(self.resulting_cube_state())
    else:
        self._resulting_cube_state = None

    self.instructions.append(instruction)
    logger.debug('{}: Added {}'.format(self.name, instruction))

append_instructions(self, instructions, recalculate_resulting_cube_state=True)

Appends a given set of instructions to the end of the program.

Parameters:

Name Type Description Default
instructions List[core.manipulator.SimulationInstruction.SimulationInstruction]

the instructions to append

required
recalculate_resulting_cube_state bool

flag, indicating whether to immediately recalculate the resulting cube state or post pone it to the next access

True
Source code in core/manipulator/SimulationProgram.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def append_instructions(self, instructions: List[SimulationInstruction], recalculate_resulting_cube_state: bool = True):
    """Appends a given set of instructions to the end of the program.

    Args:
        instructions: the instructions to append
        recalculate_resulting_cube_state: flag, indicating whether to immediately recalculate the resulting cube state or post pone it to the next access
    """

    assert isinstance(instructions, list)
    if len(instructions) < 0:
        return

    for instruction in instructions:
        assert isinstance(instruction, SimulationInstruction)
        logger.debug('{}: Added {}'.format(self.name, instruction))

    if recalculate_resulting_cube_state:
        state = self.resulting_cube_state()
        for instruction in instructions:
            state = instruction.apply_to_cube_state(state)
        self._resulting_cube_state = state
    else:
        self._resulting_cube_state = None

    self.instructions += instructions

create_follow_up(self, name)

Creates a follow-up program.

The newly created simulation program has this program as its parent and the resulting robot position as its initial robot position.

Parameters:

Name Type Description Default
name str

the name of the follow-up program

required

Returns:

Type Description
SimulationProgram

the follow-up

Source code in core/manipulator/SimulationProgram.py
109
110
111
112
113
114
115
116
117
118
119
120
121
def create_follow_up(self, name: str) -> 'SimulationProgram':
    """Creates a follow-up program.

    The newly created simulation program has this program as its parent
    and the resulting robot position as its initial robot position.

    Args:
        name: the name of the follow-up program

    Returns:
        the follow-up
    """
    return SimulationProgram(name, parent=self, initial_robot_joints=self.final_robot_position())

execute(self)

Executes the program through python including all parent instructions.

Source code in core/manipulator/SimulationProgram.py
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
def execute(self):
    """Executes the program through python including all parent instructions."""

    if self.has_parent:
        assert isinstance(self.parent, SimulationProgram)
        self.parent.execute()

    logger.info('Executing {} -> {} instructions to go.'.format(self.name, len(self.instructions)))

    follow_along_cube_state = self.initial_cube_state
    for instruction in self.instructions:
        if logger.isEnabledFor(logging.DEBUG):
            logger.info('\tExecuting {}.'.format(instruction.name))

            if isinstance(instruction, GripInstruction):
                logger.debug('\t\t from: {}'.format(str(follow_along_cube_state)))

            follow_along_cube_state = instruction.apply_to_cube_state(follow_along_cube_state)

            if isinstance(instruction, GripInstruction):
                logger.debug('\t\t to:   {}'.format(str(follow_along_cube_state)))

        instruction.execute()

final_robot_position(self)

Returns the robot joints after the program was run.

Returns:

Type Description
List[float]

the robot joints of the last MoveInstruction in the instruction list.

Source code in core/manipulator/SimulationProgram.py
159
160
161
162
163
164
165
166
167
168
169
170
def final_robot_position(self) -> List[float]:
    """Returns the robot joints after the program was run.

    Returns:
        the robot joints of the last `MoveInstruction` in the instruction list.
    """
    for i in range(len(self.instructions) - 1, -1, -1):
        instruction = self.instructions[i]
        if isinstance(instruction, MoveInstruction):
            return instruction.target.Joints().list()

    return self.initial_robot_joints

flattened_standalone(self, name)

Creates a standalone program.

All instructions including those of its parents are deepcopied and added to the standalone.

Parameters:

Name Type Description Default
name str

the name of the flattened program

required

Returns:

Type Description
SimulationProgram

the flattened program

Source code in core/manipulator/SimulationProgram.py
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
def flattened_standalone(self, name: str) -> 'SimulationProgram':
    """Creates a standalone program.

     All instructions including those of its parents are deepcopied and added to the standalone.

    Args:
        name: the name of the flattened program

    Returns:
        the flattened program
    """

    if not self.has_parent:
        copy = SimulationProgram(name, initial_cube_state=deepcopy(self.initial_cube_state), parent=None)
        copy.append_instructions(deepcopy(self.instructions))
        return copy

    flattened_standalone_program = self.parent.flattened_standalone(name)
    flattened_standalone_program.append_instructions(self.instructions)
    return flattened_standalone_program

get_unchecked_collision_checking_programs(self)

Returns all unchecked programs in the current hierarchy path (i.e. including unchecked parents).

Returns:

Type Description
List[SimulationProgram]

the unchecked programs

Source code in core/manipulator/SimulationProgram.py
172
173
174
175
176
177
178
179
180
181
182
183
184
185
def get_unchecked_collision_checking_programs(self) -> List['SimulationProgram']:
    """Returns all unchecked programs in the current hierarchy path (i.e. including unchecked parents).

    Returns:
        the unchecked programs
    """
    programs: List['SimulationProgram'] = []
    if self.has_parent:
        programs = self.parent.get_unchecked_collision_checking_programs()

    if not self.collision_check_is_done:
        programs.append(self)

    return programs

resulting_cube_state(self)

Calculates the state of the cube when the program was run.

Returns:

Type Description
CubeState

the resulting cube state

Source code in core/manipulator/SimulationProgram.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
def resulting_cube_state(self) -> CubeState:
    """Calculates the state of the cube when the program was run.

    Returns:
        the resulting cube state
    """

    if self._resulting_cube_state is None:
        state = self.initial_cube_state
        for instruction in self.instructions:
            state = instruction.apply_to_cube_state(state)
        self._resulting_cube_state = state

    return self._resulting_cube_state

RoboDKProgram

An interface to a RoboDK program.

This class can setup, collision check, execute and teardown a RoboDK program.

Attributes:

Name Type Description
simulation_program SimulationProgram

the simulation program to create in RoboDK

program_name str

the name of the program in the RoboDK item tree.

program Optional[robolink.Item]

the RoboDK program item

evaluate(self)

Sets up the program and performs a collision checking evaluation.

Returns:

Type Description
SimulationResult

the simulation result

Source code in core/manipulator/RoboDKProgram.py
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def evaluate(self) -> SimulationResult:
    """Sets up the program and performs a collision checking evaluation.

    Returns:
        the simulation result
    """

    self.setup()

    robot = RoboDKInterface.link.Item('', robolink.ITEM_TYPE_ROBOT)
    current_joints = robot.Joints()
    robot.setJoints(self.simulation_program.initial_robot_joints)
    result = self.program.Update(check_collisions=True)
    sim_result = SimulationResult(
        num_valid_instructions=result[0],
        time=result[1],
        distance=result[2],
        path_validity_percentage=result[3],
        message=result[4]
    )
    if sim_result.path_validity_percentage < 1:
        for pair in RoboDKInterface.link.CollisionPairs():
            logger.debug('Collision: | ' + ' | '.join(map(lambda item: item.Name(), pair[:2])))

    robot.setJoints(current_joints)
    return sim_result

execute(self, teardown_on_done=True)

Executes the program through RoboDK.

Source code in core/manipulator/RoboDKProgram.py
85
86
87
88
89
90
91
92
93
94
95
def execute(self, teardown_on_done: bool = True):
    """Executes the program through RoboDK."""

    result = self.evaluate()
    logger.debug('Running Program: {}'.format(result))
    self.program.RunProgram()

    if teardown_on_done:
        logger.debug('tearing down')
        self.teardown()
    return result

perform_remaining_collision_checks(simulation_program, program_name_prefix=None) classmethod

Performs collision checking on the untested portions of the given simulation program. The results of each simulation program will be set afterwards.

Source code in core/manipulator/RoboDKProgram.py
 97
 98
 99
100
101
102
103
104
105
106
107
@classmethod
def perform_remaining_collision_checks(cls, simulation_program: SimulationProgram, program_name_prefix: str = None):
    """Performs collision checking on the untested portions of the given simulation program.
    The results of each simulation program will be set afterwards.
    """
    programs_to_check = simulation_program.get_unchecked_collision_checking_programs()
    for program_to_check in programs_to_check:
        program = cls(program_to_check, f'{program_name_prefix}_{program_to_check.name}')
        result = program.evaluate()
        program.teardown()
        program_to_check.set_collision_checking_result(result)

setup(self)

Prepares the program for evaluation.

Creates a fresh RoboDK Program and adds the instructions of the simulation program to it.

Source code in core/manipulator/RoboDKProgram.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def setup(self):
    """Prepares the program for evaluation.

    Creates a fresh RoboDK Program and adds the instructions of the simulation program to it.
    """

    self.teardown()

    self.program = RoboDKInterface.link.AddProgram(self.program_name)
    if not self.program.Valid():
        self.teardown()
        raise ValueError('Couldnt create simulation program.')

    assert isinstance(self.program, robolink.Item)
    assert self.program.Valid()
    assert self.program.Type() == robolink.ITEM_TYPE_PROGRAM

    for instruction in self.simulation_program.instructions:
        instruction.add_to_program(self.program)

teardown(self)

Deletes the program from the RoboDK item tree.

Source code in core/manipulator/RoboDKProgram.py
48
49
50
51
52
53
54
55
56
def teardown(self):
    """Deletes the program from the RoboDK item tree."""

    program = self.program if self.program is not None else RoboDKInterface.link.Item(self.program_name)
    if program.Valid():
        assert program.Type() == robolink.ITEM_TYPE_PROGRAM
        program.Delete()

    self.program = None

SimulationResult

A container for simulation results.

It stores the evaluation results of a RoboDK program.

Attributes:

Name Type Description
num_valid_instructions int

the number of valid instructions

time float

the time in seconds needed for execution

distance float

the distance travelled in mm

path_validity_percentage float

the percentage of the path which can be followed without a collision

message str

a message given by RoboDK during the evaluation