timor.configuration_search.LiuIterator ====================================== .. py:module:: timor.configuration_search.LiuIterator Classes ------- .. autoapisummary:: timor.configuration_search.LiuIterator.Indices timor.configuration_search.LiuIterator.Science2019 Functions --------- .. autoapisummary:: timor.configuration_search.LiuIterator.alphanumeric_sort_db Module Contents --------------- .. py:class:: Indices Wrapper to collect the current state/module indexed when iterating over a library .. py:attribute:: base :type: int .. py:attribute:: eef :type: int .. py:attribute:: joints :type: int .. py:attribute:: links :type: numpy.ndarray .. py:attribute:: valid_joint_combination_id :type: int .. py:class:: Science2019(db, min_dof = 0, max_dof = 6, min_links_between_joints = 0, max_links_between_joints = 3, max_links_before_first_joint = 0, max_links_after_last_joint = 0) .. autoapi-inheritance-diagram:: timor.configuration_search.LiuIterator.Science2019 :parts: 1 :private-bases: This iterator returns assemblies according to the criteria defined in the paper: "Effortless creation of safe robots from timor.Modules through self-programming and self-verification" by M. Althoff, A. Giusti, S.B. Liu, A.Pereira, https://mediatum.ub.tum.de/doc/1506779/gy8gyea2c5vyn65ely4bnzom6.Althoff-2019-ScienceRobotics.pdf Iteration happens in a depth-first manner, iterating over links the fastest, then joint combinations, then end-effectors and slowest over bases. This class is named after the author who initially came up with the idea of the here implemented search space reduction, Stefan Liu. The following constraints reduce the search space of possible assemblies: - The robot is a serial chain of modules. Every module has a proximal (=female) and a distal (=male) connector. - A maximum number of degrees of freedom (default: 6) - There are never two joints mounted directly after one another - There is a maximum of three static links in between two joints - The first module must be a joint module (this is not explicitly mentioned in the paper but can be derived from the modules they used) - The last module before the end-effector must be a joint. This can theoretically be relaxed in the future. This implementation of the LiuIterator allows for a bit more flexibility than the one mentioned in the paper: :param db: The database to build the assembly from. To work properly, every module in the db should clearly belong to one of the four categories {base, joint module, link module, end-effector}. Sane behavior for databases with multi-joint or other complex modules is not guaranteed :param min_dof: The minimum number of joints in the robot. :param max_dof: The maximum number of joints in the robot. The end-effector is not counted as a degree of freedom. Changing the default from 6 to another value would mean to differ from the paper. Other than the method from the referenced paper, min_dof is not implicitly equal to max_dof. :param min_links_between_joints: The minimum number of links between two joints in an assembly. :param max_links_between_joints: The maximum number of links between two joints. Default 3 is from Liu paper. :param max_links_before_first_joint: The maximum number of links between a base and the first joint. :param max_links_after_last_joint: The maximum number of links between the last joint and the end-effector. .. py:attribute:: __class_getitem__ .. py:method:: __iter__() Iterators are self-iterable: https://peps.python.org/pep-0234/ .. py:method:: __len__() Calculates and returns the total number of possible assemblies created by this iterator. .. py:method:: __next__() Iterate over: - Bases - Joints+Links - End-Effectors in a depth first manner. Really rough estimation: 0.2ms per call on 1 processor :raises: StopIteration .. py:attribute:: __slots__ :value: () .. py:method:: __subclasshook__(C) :classmethod: .. py:method:: _check_db_valid() Performs some sanity checks on the given db to validate made assumptions on its structure. Those are: - There's at least one base, joint link and end-effector [crucial] - All modules are connectable [not necessary, but instantiating two iterators would be preferred if not] - Every link and joint module has a distal/male and a proximal/female part [crucial] - All bases connect to adjacent modules using the same connector/interface [rp] - All end effectors connect to adjacent modules using the same connector/interface [rp] rp = "relaxation possible but adaption of class methods necessary" .. py:attribute:: _current_joint_combination :type: Tuple[str, Ellipsis] .. py:attribute:: _current_num_joint_combinations :type: int .. py:attribute:: _current_num_joint_modules :type: int .. py:attribute:: _db :type: timor.Module.ModulesDB .. py:method:: _extract_connections() Maps modules to possible connecting modules Note: this unidirectional extraction of possible connections is possible because this class works with the crucial simplification that we have unidirectional modules with a distal and proximal part! :return: For each module in the DB, extracts which modules can follow .. py:method:: _extract_eef_distance() :abstractmethod: For each module, calculates the "shortest path" to the end effector, :return: .. py:method:: _identify_augmented_base_eef() Extracts all possible "augmented" bases and end effectors. What we do here is defining an extended base and extended end-effector. Every possible combination of base and attached links as well as every possible combination of static links and end-effector is extracted and will be treated as a different base/eef "module" from here on. :return: A tuple of two tuples. The first tuple contains all possible combinations of base and attached links. The second tuple contains all possible combinations of static links and end-effector. .. py:method:: _identify_base_chain_eef() For all augmented bases, end-effectors, returns a mapping to functional joint combinations in between .. py:method:: _identify_joint_combinations() :return: A tuple with all possible (allowed) combinations of joints, ordered from base to eef .. py:method:: _identify_link_combinations() Extracts possible tuples of links as they could be built in an assembly. Note: Without any filters, this will generate sum_over_0_max_in_between_links [num_different_links^max_links_between_joints] combinations (which may become infeasible large in max_links_between_joints is not chosen carefully). Even with filters, this can grow rapidly! :return: A tuple with all possible (allowed) combinations of links that can be in between two joints .. py:method:: _identify_links_between_joints() Enumerates all possible combinations of links in between two joints Returns a mapping from every possible combination of parent and child joint to link combinations that can be in between. :return: A mapping from (parent_joint_id, child_joint_id) to a tuple of tuples, each of which contains between one and max_links_between_joints integers that index the classes link modules .. py:method:: _increment_base() Iterates over bases. Does not raise StopIteration, this needs to be done in the __next__ method! .. py:method:: _increment_end_effector() Iterates over end effectors available .. py:method:: _increment_joint_combination() Iterates over joint combinations available .. py:method:: _increment_link_combination(idx) Iterates over link combinations available .. py:method:: _increment_state() Call after every iteration to return the next element when calling __next__ the next time .. py:attribute:: _state :type: Indices .. py:attribute:: augmented_bases :type: Tuple[Tuple[str, Ellipsis], Ellipsis] :value: () .. py:attribute:: augmented_end_effectors :type: Tuple[Tuple[str, Ellipsis], Ellipsis] :value: () .. py:attribute:: bases :type: Tuple[timor.Module.AtomicModule] .. py:property:: current_base :type: Tuple[str, Ellipsis] Utility property to return the IDs of the currently used augmented base .. py:property:: current_eef :type: Tuple[str, Ellipsis] Utility property to return the IDs of the currently used augmented end-effector .. py:property:: db :type: timor.Module.ModulesDB Wrapper property to avoid resetting the db .. py:attribute:: end_effectors :type: Tuple[timor.Module.AtomicModule] .. py:attribute:: joint_combinations :type: Tuple[Tuple[str, Ellipsis], Ellipsis] .. py:attribute:: joint_combinations_for_base_eef :type: Dict[Tuple[str, str], Tuple[int]] .. py:attribute:: joints :type: Tuple[timor.Module.AtomicModule] .. py:attribute:: link_combinations :type: Tuple[Tuple[str, Ellipsis], Ellipsis] .. py:attribute:: links :type: Tuple[timor.Module.AtomicModule] .. py:attribute:: links_between_joints :type: Dict[Tuple[str, str], Tuple[Tuple[int, Ellipsis], Ellipsis]] .. py:attribute:: max_dof :type: int .. py:attribute:: max_links_after_last_joint :value: 0 .. py:attribute:: max_links_before_first_joint :value: 0 .. py:attribute:: max_links_between_joints :type: int .. py:attribute:: min_dof :type: int .. py:attribute:: min_links_between_joints :type: int .. py:attribute:: module_connects :type: Dict[str, Tuple[str, Ellipsis]] .. py:method:: reset() Resets the indices used to iterate over modules. .. py:property:: state :type: Indices Implementation as property necessary to define abstractmethod .. py:property:: valid_joint_combinations :type: Tuple[int] Returns a tuple of integers indexing the self.joint_combinations attribute. This tuple contains only these indices that are valid for the current combination of base and end-effector. .. py:function:: alphanumeric_sort_db(db) Helper method to sort a module db alphabetically