advanced_controls.py
Go to the documentation of this file.
1 # Copyright (c) 2011, Dirk Thomas, TU Darmstadt
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions
6 # are met:
7 #
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following
12 # disclaimer in the documentation and/or other materials provided
13 # with the distribution.
14 # * Neither the name of the TU Darmstadt nor the names of its
15 # contributors may be used to endorse or promote products derived
16 # from this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 # POSSIBILITY OF SUCH DAMAGE.
30 
31 
32 import os
33 import rospy
34 import rospkg
35 
36 from time import sleep
37 
38 from qt_gui.plugin import Plugin
39 from python_qt_binding import loadUi
40 
41 from QtWidgets import QMessageBox, QWidget
42 from QtGui import QIcon
43 from controller_manager_msgs.srv import ListControllers
44 from controller_manager_msgs.srv import SwitchController, SwitchControllerRequest, LoadController
45 from sr_robot_msgs.srv import ChangeControlType
46 from sr_robot_msgs.msg import ControlType
47 from sr_utilities.hand_finder import HandFinder
48 
49 
51 
52  """
53  A rosgui plugin for loading the different controllers
54  """
55  ICON_DIR = os.path.join(
56  rospkg.RosPack().get_path('sr_visualization_icons'), 'icons')
57  CONTROLLER_ON_ICON = QIcon(os.path.join(ICON_DIR, 'green.png'))
58  CONTROLLER_OFF_ICON = QIcon(os.path.join(ICON_DIR, 'red.png'))
59 
61 
62  self.hand_ids = []
63  hand_joint_prefixes = []
64  # mapping is always in global ns
65  if rospy.has_param("/hand/mapping"):
66  hand_mapping = rospy.get_param("/hand/mapping")
67  for _, value in hand_mapping.items():
68  # if prefix matches the mapping, add this hand
69  # empty prefix means both hands
70  if self._prefix in value:
71  self.hand_ids.append(value)
72  else:
73  self.hand_ids.append("")
74 
75  if rospy.has_param("/hand/joint_prefix"):
76  hand_joint_prefix_mapping = rospy.get_param("/hand/joint_prefix")
77  for _, value in hand_joint_prefix_mapping.items():
78  # if prefix matches the mapping, add this hand
79  # empty prefix means both hands
80  if self._prefix in value:
81  hand_joint_prefixes.append(value)
82  if len(hand_joint_prefixes) == 0:
83  QMessageBox.warning(self._widget, "Warning",
84  "No hand found with prefix :" + self._prefix)
85  hand_joint_prefixes.append("")
86  else:
87  rospy.loginfo("no joint prefix found, not appending prefix")
88  hand_joint_prefixes.append("")
89 
90  joints = ["ffj0", "ffj3", "ffj4",
91  "mfj0", "mfj3", "mfj4",
92  "rfj0", "rfj3", "rfj4",
93  "lfj0", "lfj3", "lfj4", "lfj5",
94  "thj1", "thj2", "thj3", "thj4", "thj5",
95  "wrj1", "wrj2"]
96  self.controllers = {
97  "effort": [
98  "sh_{0}{1}_effort_controller".format(hand_joint_prefix, joint)
99  for joint in joints for hand_joint_prefix in
100  hand_joint_prefixes],
101  "position": [
102  "sh_{0}{1}_position_controller".format(hand_joint_prefix,
103  joint)
104  for joint in joints for hand_joint_prefix in
105  hand_joint_prefixes],
106  "mixed": [
107  "sh_{0}{1}_mixed_position_velocity_controller".format(
108  hand_joint_prefix, joint)
109  for joint in joints for hand_joint_prefix in
110  hand_joint_prefixes],
111  "velocity": [
112  "sh_{0}{1}_velocity_controller".format(
113  hand_joint_prefix, joint)
114  for joint in joints for hand_joint_prefix in
115  hand_joint_prefixes], "stop": []}
116 
118  cont for type_conts in self.controllers.itervalues()
119  for cont in type_conts]
120 
121  def __init__(self, context):
122  super(SrGuiAdvancedControls, self).__init__(context)
123  self.setObjectName('SrGuiAdvancedControls')
124 
125  self._publisher = None
126 
127  self._widget = QWidget()
128 
129  ui_file = os.path.join(
130  rospkg.RosPack().get_path('sr_gui_advanced_controls'), 'uis',
131  'SrAdvancedControls.ui')
132  loadUi(ui_file, self._widget)
133  self._widget.setObjectName('SrAdvancedControlsUI')
134  context.add_widget(self._widget)
135 
136  # setting the prefixes
137  self._hand_finder = HandFinder()
138  hand_parameters = self._hand_finder.get_hand_parameters()
139 
140  self._prefix = ""
141  for hand in hand_parameters.mapping:
142  self._widget.select_prefix.addItem(hand_parameters.mapping[hand])
143 
144  if not hand_parameters.mapping:
145  rospy.logerr("No hand detected")
146  QMessageBox.warning(
147  self._widget, "warning", "No hand is detected")
148  else:
149  self._widget.select_prefix.setCurrentIndex(0)
150  self._prefix = hand_parameters.mapping.values()[0]
151 
152  self._widget.select_prefix.currentIndexChanged['QString'].connect(
153  self.prefix_selected)
154 
155  self.populate_controllers()
156 
157  self.list_controllers = rospy.ServiceProxy(
158  'controller_manager/list_controllers', ListControllers)
159  self.switch_controllers = rospy.ServiceProxy(
160  'controller_manager/switch_controller', SwitchController)
161 
162  # Setting the initial state of the controller buttons
163  self._widget.btn_mixed.setIcon(self.CONTROLLER_OFF_ICON)
164  self._widget.btn_mixed.setChecked(False)
165  self._widget.btn_effort.setIcon(self.CONTROLLER_OFF_ICON)
166  self._widget.btn_effort.setChecked(False)
167  self._widget.btn_position.setIcon(self.CONTROLLER_OFF_ICON)
168  self._widget.btn_position.setChecked(False)
169  self._widget.btn_velocity.setIcon(self.CONTROLLER_OFF_ICON)
170  self._widget.btn_velocity.setChecked(False)
171 
172  # attaching the button press event to their actions
173  self._widget.btn_stop.pressed.connect(self.on_stop_ctrl_clicked_)
174  self._widget.btn_effort.pressed.connect(self.on_effort_ctrl_clicked_)
175  self._widget.btn_position.pressed.connect(
177  self._widget.btn_mixed.pressed.connect(self.on_mixed_ctrl_clicked_)
178  self._widget.btn_velocity.pressed.connect(
180 
181  # check the correct control box, depending on PWM_CONTROL env variable
182  if os.environ.get('PWM_CONTROL') in [None, '0']:
183  self._widget.radioButtonTorque.setChecked(True)
184  self._widget.radioButtonPWM.setChecked(False)
185  else:
186  self._widget.radioButtonTorque.setChecked(False)
187  self._widget.radioButtonPWM.setChecked(True)
188 
189  self._widget.radioButtonTorque.toggled.connect(
191  self._widget.radioButtonPWM.toggled.connect(
193 
195  """
196  Switch between FORCE, PWM modes
197  We only react to the currently ON radio button event
198  """
199  if checked:
200  change_type_msg = ChangeControlType()
201  if self._widget.radioButtonTorque.isChecked():
202  change_type_msg.control_type = ControlType.FORCE
203  rospy.loginfo("Change Control mode to FORCE")
204  else:
205  change_type_msg.control_type = ControlType.PWM
206  rospy.loginfo("Change Control mode to PWM")
207  self.change_force_ctrl_type(change_type_msg)
208 
210  """
211  Stop controller
212  """
213  self._widget.btn_stop.setEnabled(False)
214  self._widget.btn_mixed.setIcon(self.CONTROLLER_OFF_ICON)
215  self._widget.btn_mixed.setChecked(False)
216  self._widget.btn_effort.setIcon(self.CONTROLLER_OFF_ICON)
217  self._widget.btn_effort.setChecked(False)
218  self._widget.btn_position.setIcon(self.CONTROLLER_OFF_ICON)
219  self._widget.btn_position.setChecked(False)
220  self._widget.btn_velocity.setIcon(self.CONTROLLER_OFF_ICON)
221  self._widget.btn_velocity.setChecked(False)
222  self.change_ctrl("stop")
223  self._widget.btn_stop.setEnabled(True)
224 
226  """
227  Effort controller selected
228  """
229  self._widget.btn_effort.setEnabled(False)
230  if not self._widget.btn_effort.isChecked():
231  self._widget.btn_effort.setIcon(self.CONTROLLER_ON_ICON)
232  self._widget.btn_effort.setChecked(True)
233  self._widget.btn_position.setIcon(self.CONTROLLER_OFF_ICON)
234  self._widget.btn_position.setChecked(False)
235  self._widget.btn_mixed.setIcon(self.CONTROLLER_OFF_ICON)
236  self._widget.btn_mixed.setChecked(False)
237  self._widget.btn_velocity.setIcon(self.CONTROLLER_OFF_ICON)
238  self._widget.btn_velocity.setChecked(False)
239  rospy.loginfo("Effort checked: " + str(
240  self._widget.btn_effort.isChecked()))
241  self.change_ctrl("effort")
242  else:
243  self._widget.btn_effort.setIcon(self.CONTROLLER_OFF_ICON)
244  self._widget.btn_effort.setChecked(False)
245  rospy.loginfo("Effort checked: " + str(
246  self._widget.btn_effort.isChecked()))
247  self.change_ctrl("stop")
248  self._widget.btn_effort.setEnabled(True)
249 
251  """
252  Position controller selected
253  """
254  self._widget.btn_position.setEnabled(False)
255  if not self._widget.btn_position.isChecked():
256  self._widget.btn_position.setIcon(self.CONTROLLER_ON_ICON)
257  self._widget.btn_position.setChecked(True)
258  self._widget.btn_effort.setIcon(self.CONTROLLER_OFF_ICON)
259  self._widget.btn_effort.setChecked(False)
260  self._widget.btn_mixed.setIcon(self.CONTROLLER_OFF_ICON)
261  self._widget.btn_mixed.setChecked(False)
262  self._widget.btn_velocity.setIcon(self.CONTROLLER_OFF_ICON)
263  self._widget.btn_velocity.setChecked(False)
264  rospy.loginfo("Position checked: " +
265  str(self._widget.btn_position.isChecked()))
266  self.change_ctrl("position")
267  else:
268  self._widget.btn_position.setIcon(self.CONTROLLER_OFF_ICON)
269  self._widget.btn_position.setChecked(False)
270  rospy.loginfo("Position checked: " +
271  str(self._widget.btn_position.isChecked()))
272  self.change_ctrl("stop")
273  self._widget.btn_position.setEnabled(True)
274 
276  """
277  Mixed controller selected
278  """
279  self._widget.btn_mixed.setEnabled(False)
280  if not self._widget.btn_mixed.isChecked():
281  self._widget.btn_mixed.setIcon(self.CONTROLLER_ON_ICON)
282  self._widget.btn_mixed.setChecked(True)
283  self._widget.btn_effort.setIcon(self.CONTROLLER_OFF_ICON)
284  self._widget.btn_effort.setChecked(False)
285  self._widget.btn_position.setIcon(self.CONTROLLER_OFF_ICON)
286  self._widget.btn_position.setChecked(False)
287  self._widget.btn_velocity.setIcon(self.CONTROLLER_OFF_ICON)
288  self._widget.btn_velocity.setChecked(False)
289  rospy.loginfo("Mixed checked: " +
290  str(self._widget.btn_mixed.isChecked()))
291  self.change_ctrl("mixed")
292  else:
293  self._widget.btn_mixed.setIcon(self.CONTROLLER_OFF_ICON)
294  self._widget.btn_mixed.setChecked(False)
295  rospy.loginfo("Mixed checked: " +
296  str(self._widget.btn_mixed.isChecked()))
297  self.change_ctrl("stop")
298  self._widget.btn_mixed.setEnabled(True)
299 
301  """
302  Velocity controller selected
303  """
304  self._widget.btn_velocity.setEnabled(False)
305  if not self._widget.btn_velocity.isChecked():
306  self._widget.btn_velocity.setIcon(self.CONTROLLER_ON_ICON)
307  self._widget.btn_velocity.setChecked(True)
308  self._widget.btn_effort.setIcon(self.CONTROLLER_OFF_ICON)
309  self._widget.btn_effort.setChecked(False)
310  self._widget.btn_position.setIcon(self.CONTROLLER_OFF_ICON)
311  self._widget.btn_position.setChecked(False)
312  self._widget.btn_mixed.setIcon(self.CONTROLLER_OFF_ICON)
313  self._widget.btn_mixed.setChecked(False)
314  rospy.loginfo("Velocity checked: " +
315  str(self._widget.btn_velocity.isChecked()))
316  self.change_ctrl("velocity")
317  else:
318  self._widget.btn_velocity.setIcon(self.CONTROLLER_OFF_ICON)
319  self._widget.btn_velocity.setChecked(False)
320  rospy.loginfo("Velocity checked: " +
321  str(self._widget.btn_velocity.isChecked()))
322  self.change_ctrl("stop")
323  self._widget.btn_velocity.setEnabled(True)
324 
325  def change_ctrl(self, controller):
326  """
327  Switch the current controller
328  """
329  success = True
330 
331  try:
332  resp1 = self.list_controllers()
333  except rospy.ServiceException:
334  success = False
335 
336  if success:
337  controllers_to_stop = [
338  c.name for c in resp1.controller
339  if c.state == "running" and c.name in self.managed_controllers]
340  all_loaded_controllers = [c.name for c in resp1.controller]
341 
342  controllers_to_start = self.controllers[controller]
343 
344  load_controllers = None
345  for load_control in controllers_to_start:
346  if load_control not in all_loaded_controllers:
347  try:
348  load_controllers = rospy.ServiceProxy(
349  'controller_manager/load_controller',
350  LoadController)
351  resp1 = load_controllers(load_control)
352  if not resp1.ok:
353  success = False
354  except rospy.ServiceException:
355  success = False
356 
357  req = SwitchControllerRequest()
358  req.start_controllers = controllers_to_start
359  req.stop_controllers = controllers_to_stop
360  req.strictness = SwitchControllerRequest.BEST_EFFORT
361  # req.start_asap = False
362  # req.timeout = 0.0
363 
364  try:
365  resp1 = self.switch_controllers.call(req)
366  except rospy.ServiceException:
367  success = False
368 
369  if not resp1.ok:
370  success = False
371 
372  if not success:
373  rospy.logwarn(
374  "Failed to change some of the controllers. "
375  "This is normal if this is not a 5 finger hand.")
376 
377  def change_force_ctrl_type(self, chng_type_msg):
378  """
379  Calls the service (sr_hand_robot/change_control_type) that allows to
380  tell the driver (sr_robot_lib)
381  which type of force control has to be sent to the motor:
382  - torque demand (sr_robot_msgs::ControlType::FORCE)
383  - PWM (sr_robot_msgs::ControlType::PWM)
384  it will deactivate the Effort, Position, Mixed and Velocity buttons
385  for 3 secs to allow hardware controllers to be updated
386  """
387  success = True
388  for hand_id in self.hand_ids:
389  srv_path = 'sr_hand_robot/' + hand_id + '/change_control_type'
390  # remove double slash for empty hand_id
391  srv_path.replace("//", "/")
392  change_control_type = rospy.ServiceProxy(srv_path,
393  ChangeControlType)
394  try:
395  resp1 = change_control_type(chng_type_msg)
396  if resp1.result.control_type != chng_type_msg.control_type:
397  success = False
398  except rospy.ServiceException:
399  success = False
400 
401  # Disable buttons for 3 secs until motors change their parameters
402  self._widget.btn_effort.setEnabled(False)
403  self._widget.btn_position.setEnabled(False)
404  self._widget.btn_mixed.setEnabled(False)
405  self._widget.btn_velocity.setEnabled(False)
406  sleep(3)
407  self._widget.btn_effort.setEnabled(True)
408  self._widget.btn_position.setEnabled(True)
409  self._widget.btn_mixed.setEnabled(True)
410  self._widget.btn_velocity.setEnabled(True)
411 
412  if not success:
413  QMessageBox.warning(self._widget, "Warning",
414  "Failed to change the control type.")
415 
416  def prefix_selected(self, prefix):
417  self._prefix = prefix
418  self.populate_controllers()
419 
421  if self._publisher is not None:
422  self._publisher.unregister()
423  self._publisher = None
424 
425  def shutdown_plugin(self):
426  self._unregisterPublisher()
427 
428  def save_settings(self, global_settings, perspective_settings):
429  pass
430 
431  def restore_settings(self, global_settings, perspective_settings):
432  pass
def save_settings(self, global_settings, perspective_settings)
def restore_settings(self, global_settings, perspective_settings)


sr_gui_advanced_controls
Author(s): Ugo Cupcic
autogenerated on Mon Feb 28 2022 23:51:24