sr_hand_calibration_model.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # Copyright 2011 Shadow Robot Company Ltd.
00004 #
00005 # This program is free software: you can redistribute it and/or modify it
00006 # under the terms of the GNU General Public License as published by the Free
00007 # Software Foundation, either version 2 of the License, or (at your option)
00008 # any later version.
00009 #
00010 # This program is distributed in the hope that it will be useful, but WITHOUT
00011 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00013 # more details.
00014 #
00015 # You should have received a copy of the GNU General Public License along
00016 # with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 #
00018 
00019 import rospy
00020 
00021 from sr_robot_lib.etherCAT_hand_lib import EtherCAT_Hand_Lib
00022 from QtGui import QTreeWidgetItem, QTreeWidgetItemIterator, QColor, QIcon, QMessageBox
00023 from PyQt4.Qt import QTimer
00024 from PyQt4.QtCore import SIGNAL
00025 
00026 import yaml
00027 try:
00028     from yaml import CLoader as Loader, CDumper as Dumper
00029 except ImportError:
00030     from yaml import Loader, Dumper
00031 import os
00032 
00033 from collections import deque
00034 
00035 green = QColor(153, 231, 96)
00036 orange = QColor(247, 206, 134)
00037 red = QColor(236, 178, 178)
00038 
00039 
00040 class IndividualCalibration(QTreeWidgetItem):
00041 
00042     """
00043     Calibrate a single joint by raw and calibrated values
00044     Calibrated joints will appear as green
00045     or orange if calibrations are loaded from a file
00046     """
00047 
00048     def __init__(self, joint_name,
00049                  raw_value, calibrated_value,
00050                  parent_widget, tree_widget,
00051                  robot_lib):
00052         self.joint_name = joint_name
00053         self.raw_value = int(raw_value)
00054         self.calibrated_value = calibrated_value
00055         self.tree_widget = tree_widget
00056         self.robot_lib = robot_lib
00057 
00058         QTreeWidgetItem.__init__(self, parent_widget, [
00059                                  "", "", str(self.raw_value), str(self.calibrated_value)])
00060 
00061         for col in xrange(self.tree_widget.columnCount()):
00062             self.setBackgroundColor(col, QColor(red))
00063 
00064         self.tree_widget.addTopLevelItem(self)
00065 
00066         self.is_calibrated = False
00067 
00068     def remove(self):
00069         self.tree_widget.remove
00070 
00071     def calibrate(self):
00072         """
00073         Performs the joint calibration and sets background to green
00074         calibrate only the calibration lines, not the items for the fingers / joints / hand
00075         """
00076         self.raw_value = self.robot_lib.get_average_raw_value(
00077             self.joint_name, 100)
00078         self.setText(2, str(self.raw_value))
00079 
00080         for col in xrange(self.tree_widget.columnCount()):
00081             if self.text(2) != "":
00082                 self.setBackgroundColor(col, QColor(green))
00083 
00084         self.is_calibrated = True
00085 
00086     def set_is_loaded_calibration(self):
00087         """
00088         set the background to orange: those values are loaded
00089         from the file, not recalibrated
00090         """
00091         for col in xrange(self.tree_widget.columnCount()):
00092             if self.text(2) != "":
00093                 self.setBackgroundColor(col, QColor(orange))
00094 
00095         self.is_calibrated = True
00096 
00097     def get_calibration(self):
00098         return [self.raw_value, self.calibrated_value]
00099 
00100 
00101 class JointCalibration(QTreeWidgetItem):
00102 
00103     """
00104     Calibrate a single joint by calibrations list
00105     Also displays the current joint position in the GUI
00106     """
00107 
00108     nb_values_to_check = 5
00109 
00110     def __init__(self, joint_name,
00111                  calibrations,
00112                  parent_widget, tree_widget,
00113                  robot_lib):
00114         self.joint_name = joint_name
00115         self.tree_widget = tree_widget
00116         self.robot_lib = robot_lib
00117 
00118         self.calibrations = []
00119 
00120         self.last_raw_values = deque()
00121 
00122         QTreeWidgetItem.__init__(
00123             self, parent_widget, ["", joint_name, "", ""])
00124 
00125         for calibration in calibrations:
00126             self.calibrations.append(IndividualCalibration(joint_name,
00127                                                            calibration[0], calibration[1],
00128                                                            self, tree_widget, robot_lib))
00129 
00130         # display the current joint position in the GUI
00131         self.timer = QTimer()
00132         self.timer.start(200)
00133         tree_widget.addTopLevelItem(self)
00134         tree_widget.connect(
00135             self.timer, SIGNAL('timeout()'), self.update_joint_pos)
00136 
00137     def load_joint_calibration(self, new_calibrations):
00138         for calibration in self.calibrations:
00139             self.removeChild(calibration)
00140         self.calibrations = []
00141 
00142         for calibration in new_calibrations:
00143             new_calib = IndividualCalibration(self.joint_name,
00144                                               calibration[0], calibration[1],
00145                                               self, self.tree_widget, self.robot_lib)
00146             new_calib.set_is_loaded_calibration()
00147             self.calibrations.append(new_calib)
00148 
00149     def get_joint_calibration(self):
00150         config = []
00151         for calibration in self.calibrations:
00152             if calibration.is_calibrated:
00153                 config.append(calibration.get_calibration())
00154 
00155         if len(config) <= 1:
00156             # no config, or only one point
00157             # generating flat config
00158             config = [[0, 0.0], [1, 0.0]]
00159         return [self.joint_name, config]
00160 
00161     def update_joint_pos(self):
00162         """
00163         Update the joint position if there are enough nonequal values
00164         If the values are equal it can be assumed the sensor are not measuring properly
00165         """
00166         raw_value = self.robot_lib.get_raw_value(self.joint_name)
00167         self.setText(2, str(raw_value))
00168 
00169         # if the 5 last values are equal, then display a warning
00170         # as there's always some noise on the values
00171         self.last_raw_values.append(raw_value)
00172         if len(self.last_raw_values) > self.nb_values_to_check:
00173             self.last_raw_values.popleft()
00174 
00175             # only check if we have enough values
00176             all_equal = True
00177             last_data = self.last_raw_values[0]
00178             for data in self.last_raw_values:
00179                 if data != last_data:
00180                     all_equal = False
00181                     break
00182             if all_equal:
00183                 self.setIcon(
00184                     0, QIcon(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../icons/warn.gif')))
00185                 self.setToolTip(0, "No noise on the data for the last " + str(
00186                     self.nb_values_to_check) + " values, there could be a problem with the sensor.")
00187             else:
00188                 self.setIcon(0, QIcon())
00189                 self.setToolTip(0, "")
00190 
00191     def on_close(self):
00192         self.timer.stop()
00193 
00194 
00195 class FingerCalibration(QTreeWidgetItem):
00196 
00197     """
00198     calibrate all joints of a finger
00199     """
00200 
00201     def __init__(self, finger_name,
00202                  finger_joints,
00203                  parent_widget, tree_widget,
00204                  robot_lib):
00205 
00206         QTreeWidgetItem.__init__(
00207             self, parent_widget, [finger_name, "", "", ""])
00208 
00209         self.joints = []
00210         for joint in finger_joints:
00211             self.joints.append(JointCalibration(joint_name=joint[0],
00212                                                 calibrations=joint[1],
00213                                                 parent_widget=self,
00214                                                 tree_widget=tree_widget,
00215                                                 robot_lib=robot_lib))
00216 
00217         tree_widget.addTopLevelItem(self)
00218 
00219 
00220 class HandCalibration(QTreeWidgetItem):
00221 
00222     """
00223     calibrate all joints of all fingers of a hand
00224     """
00225     # TODO: Import this from an xml file?
00226     joint_map = {"First Finger": [["FFJ1", [[0.0, 0.0],
00227                                             [0.0, 22.5],
00228                                             [0.0, 45.0],
00229                                             [0.0, 67.5],
00230                                             [0.0, 90.0]]],
00231                                   ["FFJ2", [[0.0, 0.0],
00232                                             [0.0, 22.5],
00233                                             [0.0, 45.0],
00234                                             [0.0, 67.5],
00235                                             [0.0, 90.0]]],
00236                                   ["FFJ3", [[0.0, 0.0],
00237                                             [0.0, 22.5],
00238                                             [0.0, 45.0],
00239                                             [0.0, 67.5],
00240                                             [0.0, 90.0]]],
00241                                   ["FFJ4", [[0.0, -20.0],
00242                                             [0.0, -10.0],
00243                                             [0.0, 0.0],
00244                                             [0.0, 10.0],
00245                                             [0.0, 20.0]]]],
00246 
00247                  "Middle Finger": [["MFJ1", [[0.0, 0.0],
00248                                              [0.0, 22.5],
00249                                              [0.0, 45.0],
00250                                              [0.0, 67.5],
00251                                              [0.0, 90.0]]],
00252                                    ["MFJ2", [[0.0, 0.0],
00253                                              [0.0, 22.5],
00254                                              [0.0, 45.0],
00255                                              [0.0, 67.5],
00256                                              [0.0, 90.0]]],
00257                                    ["MFJ3", [[0.0, 0.0],
00258                                              [0.0, 22.5],
00259                                              [0.0, 45.0],
00260                                              [0.0, 67.5],
00261                                              [0.0, 90.0]]],
00262                                    ["MFJ4", [[0.0, -20.0],
00263                                              [0.0, -10.0],
00264                                              [0.0, 0.0],
00265                                              [0.0, 10.0],
00266                                              [0.0, 20.0]]]],
00267 
00268                  "Ring Finger": [["RFJ1", [[0.0, 0.0],
00269                                            [0.0, 22.5],
00270                                            [0.0, 45.0],
00271                                            [0.0, 67.5],
00272                                            [0.0, 90.0]]],
00273                                  ["RFJ2", [[0.0, 0.0],
00274                                            [0.0, 22.5],
00275                                            [0.0, 45.0],
00276                                            [0.0, 67.5],
00277                                            [0.0, 90.0]]],
00278                                  ["RFJ3", [[0.0, 0.0],
00279                                            [0.0, 22.5],
00280                                            [0.0, 45.0],
00281                                            [0.0, 67.5],
00282                                            [0.0, 90.0]]],
00283                                  ["RFJ4", [[0.0, -20.0],
00284                                            [0.0, -10.0],
00285                                            [0.0, 0.0],
00286                                            [0.0, 10.0],
00287                                            [0.0, 20.0]]]],
00288 
00289                  "Little Finger": [["LFJ1", [[0.0, 0.0],
00290                                              [0.0, 22.5],
00291                                              [0.0, 45.0],
00292                                              [0.0, 67.5],
00293                                              [0.0, 90.0]]],
00294                                    ["LFJ2", [[0.0, 0.0],
00295                                              [0.0, 22.5],
00296                                              [0.0, 45.0],
00297                                              [0.0, 67.5],
00298                                              [0.0, 90.0]]],
00299                                    ["LFJ3", [[0.0, 0.0],
00300                                              [0.0, 22.5],
00301                                              [0.0, 45.0],
00302                                              [0.0, 67.5],
00303                                              [0.0, 90.0]]],
00304                                    ["LFJ4", [[0.0, -20.0],
00305                                              [0.0, -10.0],
00306                                              [0.0, 0.0],
00307                                              [0.0, 10.0],
00308                                              [0.0, 20.0]]],
00309                                    ["LFJ5", [[0.0, 0.0],
00310                                              [0.0, 22.5],
00311                                              [0.0, 45.0],
00312                                              [0.0, 67.5],
00313                                              [0.0, 90.0]]]],
00314 
00315                  "Thumb": [["THJ1", [[0.0, 0.0],
00316                                      [0.0, 22.5],
00317                                      [0.0, 45.0],
00318                                      [0.0, 67.5],
00319                                      [0.0, 90.0]]],
00320                            ["THJ2", [[0.0, -40.0],
00321                                      [0.0, -20.0],
00322                                      [0.0, 0.0],
00323                                      [0.0, 20.0],
00324                                      [0.0, 40.0]]],
00325                            ["THJ3", [[0.0, -15.0],
00326                                      [0.0, 0.0],
00327                                      [0.0, 15.0]]],
00328                            ["THJ4", [[0.0, 0.0],
00329                                      [0.0, 22.5],
00330                                      [0.0, 45.0],
00331                                      [0.0, 67.5]]],
00332                            ["THJ5", [[0.0, -60.0],
00333                                      [0.0, -30.0],
00334                                      [0.0, 0.0],
00335                                      [0.0, 30.0],
00336                                      [0.0, 60.0]]]],
00337 
00338                  "Wrist": [["WRJ1", [[0.0, -45.0],
00339                                      [0.0, -22.5],
00340                                      [0.0, 0.0],
00341                                      [0.0, 15.0],
00342                                      [0.0, 30.0]]],
00343                            ["WRJ2", [[0.0, -30.0],
00344                                      [0.0, 0.0],
00345                                      [0.0, 10.0]]]]
00346                  }
00347 
00348     def __init__(self,
00349                  tree_widget,
00350                  progress_bar,
00351                  fingers=["First Finger", "Middle Finger",
00352                           "Ring Finger", "Little Finger",
00353                           "Thumb", "Wrist"]):
00354         self.fingers = []
00355         # this is set to False if the user doesn't want to continue
00356         # when there are no EtherCAT hand node currently running.
00357         self.is_active = True
00358 
00359         QTreeWidgetItem.__init__(self, ["Hand", "", "", ""])
00360 
00361         self.robot_lib = EtherCAT_Hand_Lib()
00362         if not self.robot_lib.activate():
00363             btn_pressed = QMessageBox.warning(
00364                 tree_widget, "Warning", "The EtherCAT Hand node doesn't seem to be running, or the debug topic is not"
00365                 " being published. Do you still want to continue? The calibration will be useless.",
00366                 buttons=QMessageBox.Ok | QMessageBox.Cancel)
00367 
00368             if btn_pressed == QMessageBox.Cancel:
00369                 self.is_active = False
00370 
00371         for finger in fingers:
00372             if finger in self.joint_map.keys():
00373                 self.fingers.append(FingerCalibration(finger,
00374                                                       self.joint_map[finger],
00375                                                       self, tree_widget,
00376                                                       self.robot_lib))
00377 
00378             else:
00379                 print finger, " not found in the calibration map"
00380 
00381         self.joint_0_calibration_index = 0
00382 
00383         self.progress_bar = progress_bar
00384 
00385         self.tree_widget = tree_widget
00386         self.tree_widget.addTopLevelItem(self)
00387         self.tree_widget.itemActivated.connect(self.calibrate_item)
00388 
00389     def unregister(self):
00390         it = QTreeWidgetItemIterator(self)
00391         while it.value():
00392             try:
00393                 it.value().on_close()
00394             except:
00395                 pass
00396             it += 1
00397 
00398         self.robot_lib.on_close()
00399 
00400     def calibrate_item(self, item):
00401         try:
00402             # only the IndividualCalibration have the calibrate method
00403             item.calibrate()
00404         except:
00405             pass
00406 
00407         self.progress()
00408 
00409         # select the next row by default
00410         self.tree_widget.setItemSelected(item, False)
00411         next_item = self.tree_widget.itemBelow(item)
00412         self.tree_widget.setItemSelected(next_item, True)
00413         self.tree_widget.setCurrentItem(next_item)
00414 
00415     def calibrate_joint0s(self, btn_joint_0s):
00416         joint0s = ["FFJ1", "FFJ2",
00417                    "MFJ1", "MFJ2",
00418                    "RFJ1", "RFJ2",
00419                    "LFJ1", "LFJ2"]
00420 
00421         it = QTreeWidgetItemIterator(self)
00422         while it.value():
00423             if it.value().text(1) in joint0s:
00424                 it += self.joint_0_calibration_index + 1
00425                 it.value().calibrate()
00426             it += 1
00427 
00428         self.joint_0_calibration_index += 1
00429         if self.joint_0_calibration_index == len(self.joint_map["First Finger"][0][1]):
00430             self.joint_0_calibration_index = 0
00431 
00432         # updating the btn text
00433         btn_joint_0s.setText(
00434             "Save all Joint 0s (angle = " +
00435             str(self.joint_map["First Finger"][0][1][self.joint_0_calibration_index][1]) + ")")
00436 
00437         self.progress()
00438 
00439     def progress(self):
00440         it = QTreeWidgetItemIterator(self)
00441         nb_of_items = 0
00442         nb_of_calibrated_items = 0
00443         while it.value():
00444             it += 1
00445             try:
00446                 if it.value().is_calibrated:
00447                     nb_of_calibrated_items += 1
00448                 nb_of_items += 1
00449             except:
00450                 pass
00451 
00452         self.progress_bar.setValue(
00453             int(float(nb_of_calibrated_items) / float(nb_of_items) * 100.0))
00454 
00455     def load(self, filepath):
00456         f = open(filepath, 'r')
00457         document = ""
00458         for line in f.readlines():
00459             document += line
00460         f.close()
00461         yaml_config = yaml.load(document)
00462 
00463         for joint in yaml_config["sr_calibrations"]:
00464             it = QTreeWidgetItemIterator(self)
00465             while it.value():
00466                 if it.value().text(1) == joint[0]:
00467                     it.value().load_joint_calibration(joint[1])
00468                 it += 1
00469 
00470     def save(self, filepath):
00471         yaml_config = {}
00472 
00473         joint_configs = []
00474         it = QTreeWidgetItemIterator(self)
00475         while it.value():
00476             try:
00477                 joint_configs.append(it.value().get_joint_calibration())
00478             except:
00479                 pass
00480             it += 1
00481 
00482         # this doesn't work as we'd like
00483         # yaml_config["sr_calibrations"] = joint_configs
00484         # full_config_to_write = yaml.dump(yaml_config,
00485         # default_flow_style=False)
00486         full_config_to_write = "{\'sr_calibrations\': [\n"
00487         for joint_config in joint_configs:
00488             full_config_to_write += "[\""
00489             full_config_to_write += joint_config[0] + "\", "
00490 
00491             # the etherCAT driver wants floats
00492             for index, calib in enumerate(joint_config[1]):
00493                 joint_config[1][index][0] = float(calib[0])
00494                 joint_config[1][index][1] = float(calib[1])
00495 
00496             full_config_to_write += str(joint_config[1])
00497             full_config_to_write += "], \n"
00498         full_config_to_write += "]}"
00499 
00500         f = open(filepath, 'w')
00501         f.write(full_config_to_write)
00502         f.close()
00503 
00504     def is_calibration_complete(self):
00505         it = QTreeWidgetItemIterator(self)
00506         while it.value():
00507             try:
00508                 if not it.value().is_calibrated:
00509                     return False
00510             except:
00511                 pass
00512             it += 1
00513 
00514         return True


sr_gui_hand_calibration
Author(s): Ugo Cupcic
autogenerated on Thu Jun 6 2019 21:13:44