Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grouping parameters #69

Open
yossioo opened this issue Mar 6, 2020 · 5 comments
Open

Grouping parameters #69

yossioo opened this issue Mar 6, 2020 · 5 comments
Labels
enhancement ros2 Specific to ROS 2 only

Comments

@yossioo
Copy link

yossioo commented Mar 6, 2020

Hello!

I am looking for a way to separate parameters in certain node to several groups, in a way similar to ROS1 functionality.

Defining the parameters in YAML file allows nesting parameters in subgroups, and these groups can be defined using dot in parameter names, e.g: node.declare_parameter("group_a.param_b")

I have created the example node to demonstrate the issue. https://gist.github.com/yossioo/c20d2966c9e27e57a3153d9ec176e896

I can see the declared parameters:

$ ros2 param list
/node_w_params:
  group_a.param_b
  group_a.param_c
  param_a
  use_sim_time

Checking the list of parameters shows that the prefixes are indeed recognized by ROS2:

$ ros2 service call /node_w_params/list_parameters rcl_interfaces/srv/ListParameters 
waiting for service to become available...
requester: making request: rcl_interfaces.srv.ListParameters_Request(prefixes=[], depth=0)

response:
rcl_interfaces.srv.ListParameters_Response(result=rcl_interfaces.msg.ListParametersResult(names=['use_sim_time', 'param_a', 'group_a.param_b', 'group_a.param_c'], prefixes=['group_a']))

And yet, the parameters are not grouped in the rqt_reconfigure interface and are simply presented in a single alphabetically ordered list.

Is there a proper way to define parameters so they will be displayed in groups?

@cottsay
Copy link
Member

cottsay commented Apr 23, 2020

I don't think groups are supported yet in rqt_reconfigure.

@cottsay cottsay added the ros2 Specific to ROS 2 only label Jun 12, 2020
@cottsay cottsay changed the title [ROS2] Grouping parameters Grouping parameters Jun 12, 2020
@Flova
Copy link
Contributor

Flova commented Jun 23, 2022

I would also look forward to this functionality. The question would be how they are displayed. The group name can be inferred pretty simple, but the type of grouping is not stored anywhere. I can imagine three main solutions for this:

  • Keep the layout as it is and just add some visual spacing as well as a label to separate the groups.
  • Do a hierarchy where the first level is e.g. a tab layout and the second level is something like the first point I mentioned. This might lead to weird layouts.
  • Encode the layout type in the group name with something like tab_vision_parameters which would lead to a tab with the label vision_parameters.

@authaldo
Copy link

authaldo commented May 4, 2023

Hi! Since we struggled with the missing grouping functionality in RQT, we wrote a small standalone application for modifying the parameters of nodes which displays the parameters as a tree: https://github.com/teamspatzenhirn/rig_reconfigure

The tool is also published as a separate package and can thus be installed via apt.
Currently, it doesn't provide all the features of rqt_reconfigure, but was at least for our use case sufficient.

@Sagexs
Copy link

Sagexs commented Jan 22, 2024

to get the following behavior
image

change the following lines from:

# def add_editor_widgets(self, parameters, descriptors):
#     for parameter, descriptor in zip(parameters, descriptors):
#         if parameter.type_ not in EDITOR_TYPES:
#             continue
#         logging.debug('Adding editor widget for {}'.format(parameter.name))
#         editor_widget = EDITOR_TYPES[parameter.type_](
#             self._param_client, parameter, descriptor
#         )
#         self._editor_widgets[parameter.name] = editor_widget
#         editor_widget.display(self.grid)

# def display(self, grid):
#     grid.addRow(self)

to:

def add_editor_widgets(self, parameters, descriptors):
        # Create a dictionary to store parameter editors grouped by prefix
        self.editor_groups = {}

        for parameter, descriptor in zip(parameters, descriptors):
            if parameter.type_ not in EDITOR_TYPES:
                continue

            # Get the prefix from the parameter name
            prefix = parameter.name.split('.')[0]
 
            if len(prefix) == len(parameter.name):
                prefix = 'other'
           
            if prefix not in self.editor_groups:
                # Create a new group if the prefix is not already in the dictionary
                group_box = QGroupBox(self)
                group_box.setLayout(QFormLayout())

   
                group_box.setTitle(prefix)
                group_box.setCheckable(True)  # Make the group collapsible
                group_box.setChecked(False)  # Initially, set the group as expanded
                group_box.toggled.connect(lambda state, prefix=prefix: self.group_toggled(state, prefix))
                self.grid.addRow(group_box)

                self.editor_groups[prefix] = {"group_box": group_box, "widgets": []}

            # Create the editor widget for the parameter
            logging.debug('Adding editor widget for {}'.format(parameter.name))
            editor_widget = EDITOR_TYPES[parameter.type_](
                self._param_client, parameter, descriptor
            )
            self._editor_widgets[parameter.name] = editor_widget
            editor_widget.display(self.editor_groups[prefix]["group_box"].layout())

            editor_widget._paramname_label.setVisible(self.editor_groups[prefix]["group_box"].isChecked())
            editor_widget.setVisible(self.editor_groups[prefix]["group_box"].isChecked())

            # Add the editor widget to the list of widgets in the group
            self.editor_groups[prefix]["widgets"].append(editor_widget)

    def group_toggled(self, state, prefix):
        # Handle the group box toggled event
        group_data = self.editor_groups[prefix]
        for widget in group_data["widgets"]:
            widget.setVisible(state)
            widget._paramname_label.setVisible(state)
           

    def display(self, grid):
        # Do not add the main widget to the grid here
        pass

like pkg above i also don't like that multiple parameters from diffrent nodes can be visible at the same time. I like this behavior more:

def _selection_changed_slot(self, selected, deselected):
        """
        Send "open ROS Node box" signal.

        ONLY IF the selected treenode is the terminal treenode.
        Receives args from signal QItemSelectionModel.selectionChanged.

        :param selected: All indexes where selected (could be multiple)
        :type selected: QItemSelection
        :type deselected: QItemSelection
        """
        # Getting the index where the user just selected. Should be single.
        if not selected.indexes() and not deselected.indexes():
            logging.error('Nothing selected? Not ideal to reach here')
            return

        index_current = None
        if selected.indexes():
            index_current = selected.indexes()[0]
        elif len(deselected.indexes()) == 1:
            # Setting length criteria as 1 is only a workaround, to avoid
            # Node boxes on right-hand side disappears when the filter key doesn't
            # match them.
            # Indeed, this workaround leaves another issue. Question for
            # permanent solution is asked here http://goo.gl/V4DT1
            index_current = deselected.indexes()[0]

        logging.debug('  - - - index_current={}'.format(index_current))

        rosnode_name_selected = RqtRosGraph.get_upper_grn(index_current, '')

        # If retrieved node name isn't in the list of all nodes.
        if rosnode_name_selected not in self._nodeitems.keys():
            # De-select the selected item.
            self.selectionModel.select(index_current,
                                    QItemSelectionModel.Deselect)
            return

        # Keep track of the previously selected index
        if hasattr(self, '_previous_selected_index'):
            # Hide the previously selected widget
            self._selection_deselected(self._previous_selected_index,
                                    self._previous_selected_node)

        # Show the currently selected widget
        try:
            self._selection_selected(index_current, rosnode_name_selected)
            self._previous_selected_index = index_current
            self._previous_selected_node = rosnode_name_selected
        except Exception as e:
            # TODO: print to sysmsg pane
            err_msg = 'Connection to node={} failed:\n{}'.format(
                rosnode_name_selected, e
            )
            import traceback
            traceback.print_exc()
            self._signal_msg.emit(err_msg)
            logging.error(err_msg)

@nicolas-cadart
Copy link

Any update for this grouping feature in rqt_configure? I am dealing with a lot of parameters for some nodes, and without the ability to correctly group and even hide/display them, setting parameters with ROS2 is quite cumbersome...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement ros2 Specific to ROS 2 only
Projects
None yet
Development

No branches or pull requests

6 participants