25 from QtCore
import Qt, QEvent, QObject, pyqtSignal
29 from QtWidgets
import *
30 from math
import degrees
31 from copy
import deepcopy
33 from cyberglove_calibrer
import *
34 from cyberglove_mapper
import *
37 from std_srvs.srv
import Empty
41 rootPath = os.path.join(
42 rospkg.RosPack().get_path(
'sr_gui_cyberglove_calibrator'))
48 self.setFrameShape(QFrame.HLine)
49 self.setFrameShadow(QFrame.Sunken)
55 self.setFrameShape(QFrame.VLine)
56 self.setFrameShadow(QFrame.Sunken)
61 Adjustment for one calibration point 64 button = QPushButton(text)
65 button.clicked.connect(
lambda: self.
_change_raw(amount))
66 button.setMaximumSize(40, 40)
69 def __init__(self, index, raw, calibrated, button_callback=lambda x, y: x):
70 super(SrGuiCyberglovePointTweaker, self).
__init__()
71 self.setLayout(QGridLayout())
72 self.layout().setVerticalSpacing(25)
88 self.layout().addWidget(up1, 0, 1)
89 self.layout().addWidget(up2, 0, 2)
90 self.layout().addWidget(up3, 0, 3)
91 self.layout().addWidget(down1, 1, 1)
92 self.layout().addWidget(down2, 1, 2)
93 self.layout().addWidget(down3, 1, 3)
111 self._raw_value_label.setText(
"%.4f (Raw)" % self.
_raw_value)
116 Calibrator for one joint, expecting linear calibrations between two or more points. 119 update_gui = pyqtSignal()
121 def __init__(self, joint_name, calibration_changed_callback, calibration_points, tweak_callback):
122 super(SrGuiCybergloveJointTweaker, self).
__init__()
128 self._calibration_points.sort(key=
lambda p: p[1])
130 self.setLayout(QHBoxLayout())
131 self.layout().addWidget(self.
_get_labels(joint_name))
136 self.layout().addStretch()
142 self.
_timer = rospy.Timer(rospy.Duration(0.05),
lambda x: self.update_gui.emit())
146 picture.setPixmap(QPixmap(rootPath +
'/images/%s.jpg' % joint_name))
150 labels = QtWidgets.QWidget()
151 labels.setLayout(QVBoxLayout())
152 labels.layout().addWidget(QLabel(joint_name))
163 points = QtWidgets.QWidget()
164 points.setLayout(QHBoxLayout())
166 points_and_display = QtWidgets.QWidget()
167 points_and_display.setLayout(QVBoxLayout())
168 points_and_display.layout().setSpacing(30)
170 for n, point
in enumerate(calibration_points):
172 if n < len(calibration_points) - 1:
173 points.layout().addWidget(
QVLine())
176 self._progress_bar.setTextVisible(
False)
177 self._progress_bar.setRange(0, 1000)
180 points_and_display.layout().addWidget(points)
182 return points_and_display
192 Split the sensor range into (number of cal points - 1) windows. Treat each window as a separate linear 193 interpolation, so progress bar shows which calibration points are controlling the current value. 200 position = min(position, max_calibration)
205 range_per_window = (self._progress_bar.maximum() - self._progress_bar.minimum()) / number_of_windows
207 lower_bound = min_calibration
208 upper_bound = max_calibration
219 position_in_window = (position - lower_bound)/(upper_bound - lower_bound)
220 value = (window_index + position_in_window) * range_per_window
222 self._progress_bar.setValue(value)
227 self._calibrated_value_label.setText(
"%10.4f (Calibrated)" % self.
_calibrated_value)
228 self._raw_value_label.setText(
"%10.4f (Raw)" % self.
_raw_value)
230 except RuntimeError
as e:
233 if "has been deleted" not in str(e):
234 rospy.logerr(
"Runtime error while updating gui: %s" % str(e))
243 The plugin used to tweak glove calibrations. 245 name =
"Cyberglove Calibration Tweaker" 248 self.
_raw_listner = rospy.Subscriber(
"/rh_cyberglove/raw/joint_states",
254 if calibration
is None:
258 for entry
in calibration:
263 for n, joint
in enumerate(msg.name):
265 value = msg.position[n]
269 for n, joint
in enumerate(msg.name):
271 value = msg.position[n]
279 if calibration
is None:
287 if context
is not None:
288 context.add_widget(self.
_widget)
294 top = QtWidgets.QWidget()
297 scroll = QScrollArea()
298 scroll.setWidget(top)
299 scroll.setWidgetResizable(
True)
301 self._top_layout.addWidget(scroll)
303 self._top_layout.addWidget(QtWidgets.QWidget())
317 joint_tweaker.set_raw_value(0)
318 joint_tweaker.set_calibrated_value(0)
320 self._joints_layout.addWidget(joint_tweaker)
326 if rospy.has_param(
'rh_cyberglove/cyberglove_joint_number'):
327 self.
nb_sensors = rospy.get_param(
'rh_cyberglove/cyberglove_joint_number')
332 self._joint_names.sort()
335 super(SrGuiCybergloveTweaker, self).
__init__(context)
336 self.setObjectName(
'SrGuiCybergloveTweaker')
338 rospkg.RosPack().get_path(
'sr_visualization_icons'),
'/icons')
348 self._widget.setWindowTitle(
'Cyberglove Calibration Tweaker')
353 btn_frame = QtWidgets.QFrame()
354 btn_layout = QtWidgets.QHBoxLayout()
355 btn_layout.setSpacing(25)
357 btn_save = QtWidgets.QPushButton()
358 btn_save.setText(
"&Save")
359 btn_save.setToolTip(
"Save the current calibration")
360 btn_save.setIcon(QtGui.QIcon(rootPath +
'/images/icons/save.png'))
362 btn_layout.addWidget(btn_save)
364 btn_load = QtWidgets.QPushButton()
365 btn_load.setText(
"&Load")
366 btn_load.setToolTip(
"Load a Glove calibration")
367 btn_load.setIcon(QtGui.QIcon(rootPath +
'/images/icons/load.png'))
368 btn_layout.addWidget(btn_load)
370 btn_frame.setLayout(btn_layout)
372 btn_reset = QtWidgets.QPushButton()
373 btn_reset.setText(
"&Reset")
374 btn_reset.setToolTip(
"Reset to original/last loaded calibration.")
375 btn_reset.setIcon(QtGui.QIcon(rootPath +
'/images/icons/load.png'))
376 btn_layout.addWidget(btn_reset)
378 btn_frame.setLayout(btn_layout)
380 self._top_layout.addWidget(btn_frame)
383 layout.removeWidget(widget)
399 (file_name, dummy) = QtWidgets.QFileDialog.getSaveFileName(
400 self.
_widget,
'Save Calibration',
'')
404 text = [
"{'cyberglove_calibration': ["]
408 text.append(
"['%s', %s]," % (name, calibration_string))
412 with open(file_name,
"w")
as output_file:
414 output_file.write(line +
"\n")
415 except Exception
as e:
417 QtWidgets.QMessageBox.information(
418 self.
_widget,
"Calibration saving failed!",
"Saving loading failed: %s" % str(e),
419 QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
422 (file_name, dummy) = QtWidgets.QFileDialog.getOpenFileName(
423 self.
_widget,
'Open Calibration',
'')
427 if self._calibrer.load_calib(str(file_name)) == 0:
428 QtWidgets.QMessageBox.information(
429 self.
_widget,
"Calibration successfully loaded",
"Calibration successfully loaded.",
430 QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
439 QtWidgets.QMessageBox.information(
440 self.
_widget,
"Calibration loading failed",
"Calibration loading failed",
441 QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
443 if __name__ ==
'__main__':
445 rospy.init_node(
"test_gui")
446 app = QApplication(sys.argv)
448 window._widget.show()
449 sys.exit(app.exec_())
def set_raw_value(self, value)
def _get_calibration_from_parameter(self, calibration=None)
def _load_calibration(self)
def _set_progress_bar(self)
def _set_calibrated_value(self, value)
def _get_labels(self, joint_name)
def _reset_calibration(self)
def _raw_callback(self, msg)
def _reset_tweakers(self)
def _delete_widget(self, layout, widget)
def _tweak_callback(self, joint, calibration)
def _output_calibration_to_parameter(self, calibration=None)
def _calibrated_callback(self, msg)
def _get_points_and_display(self, calibration_points)
def _save_calibration(self)
def _make_listeners(self)
def _make_widget(self, context)
def _change_raw(self, amount)
def _get_picture(self, joint_name)
def __init__(self, context)
def _get_button(self, text, amount)
def set_calibrated_value(self, value)
def _add_tweakers_to_widget(self)
def __init__(self, joint_name, calibration_changed_callback, calibration_points, tweak_callback)
def _set_raw_value(self, value)
def _point_change_callback(self, index, value)