cyberglove_mapper.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 Minimizes the mapping matrix using a simplex algorithm
00020 
00021 @author: Ugo Cupcic
00022 @contact: ugo@shadowrobot.com, contact@shadowrobot.com
00023 """
00024 
00025 import roslib
00026 
00027 import rospy
00028 from scipy.optimize import fmin
00029 from cyberglove_library import Cyberglove
00030 
00031 
00032 class MappingConfiguration:
00033 
00034     def __init__(self, glove_data=[], hand_data=[], description=""):
00035         self.glove_data = glove_data
00036         self.hand_data = hand_data
00037         self.description = description
00038 
00039     def copy(self):
00040         tmp = MappingConfiguration(
00041             self.glove_data, self.hand_data, self.description)
00042         return tmp
00043 
00044 
00045 class MappingMinimizer:
00046 
00047     def __init__(self, verbose=1):
00048         rospy.init_node("cyberglove_mapper_minimizer")
00049         # connect to the cyberglove
00050         self.cyberglove = Cyberglove()
00051 
00052         self.verbose = verbose
00053 
00054         glove_sensors = [
00055             "G_ThumbRotate", "G_ThumbMPJ", "G_ThumbIJ", "G_ThumbAb", "G_IndexMPJ", "G_IndexPIJ",
00056             "G_IndexDIJ", "G_MiddleMPJ", "G_MiddlePIJ", "G_MiddleDIJ", "G_MiddleIndexAb", "G_RingMPJ",
00057             "G_RingPIJ", "G_RingDIJ", "G_RingMiddleAb", "G_PinkieMPJ", "G_PinkiePIJ", "G_PinkieDIJ",
00058                          "G_PinkieRingAb", "G_PalmArch", "G_WristPitch", "G_WristYaw"]
00059 
00060         index = 0
00061         self.glove_name_index_map = {}
00062         for sensor in glove_sensors:
00063             self.glove_name_index_map[sensor] = index
00064             index += 1
00065 
00066         # fill the table containing all the joints
00067         hand_joints = [
00068             "TH1", "TH2", "TH3", "TH4", "TH5", "FF0", "FF3", "FF4", "MF0", "MF3", "MF4", "RF0", "RF3", "RF4", "LF0",
00069             "LF3", "LF4", "LF5", "WR1", "WR2"]
00070 
00071         index = 0
00072         self.hand_name_index_map = {}
00073         for sensor in hand_joints:
00074             self.hand_name_index_map[sensor] = index
00075             index += 1
00076 
00077         self.thumb_glove = {"G_ThumbRotate": 0,
00078                             "G_ThumbMPJ":    1,
00079                             "G_ThumbAb":     2}
00080 
00081         self.thumb_hand = {"TH2":           0,
00082                            "TH4":           1,
00083                            "TH5":           2}
00084 
00085         self.configurations = []
00086         self.initialise_configurations()
00087 
00088         self.simplex_iteration_index = 0
00089 
00090         if(self.verbose == 1):
00091             for conf in self.configurations:
00092                 print "-------"
00093                 print conf.description
00094                 print conf.glove_data
00095                 print conf.hand_data
00096             print "-------"
00097             print ""
00098 
00099         self.minerror = 1000000
00100         self.maxerror = 0
00101 
00102     def initialise_configurations(self):
00103         configuration = MappingConfiguration()
00104 
00105         #
00106         # First configuration
00107         configuration.description = "All fingers and thumb are curved maximum in a punch form ... "
00108         configuration.glove_data = []
00109         # corresponding data for the hand
00110         configuration.hand_data = [[30.0, 52.0, 5.0],
00111                                    [30.0, 43.0, 0.0],
00112                                    [30.0, 68.0, 16.0]
00113                                    ]
00114 
00115         self.configurations.append(configuration.copy())
00116 
00117         #
00118         # Second configuration
00119         configuration.description = "Thumb touching first finger tip ... "
00120         configuration.glove_data = []
00121         # corresponding data for the hand
00122         configuration.hand_data = [[30.0, 54.0, -5.0],
00123                                    [19.0, 58.0, 28.0]]
00124 
00125         self.configurations.append(configuration.copy())
00126 
00127         #
00128         # Third configuration
00129         configuration.description = "Thumb touching middle finger tip ... "
00130         configuration.glove_data = []
00131         # corresponding data for the hand
00132         configuration.hand_data = [[30.0, 64.0, 9.0],
00133                                    [1.0, 68.0, 29.0]]
00134 
00135         self.configurations.append(configuration.copy())
00136 
00137         #
00138         # Fourth configuration
00139         configuration.description = "Thumb touching ring finger tip ... "
00140         configuration.glove_data = []
00141         # corresponding data for the hand
00142         configuration.hand_data = [[30.0, 75.0, 19.0],
00143                                    [1.0, 75.0, 42.0]]
00144 
00145         self.configurations.append(configuration.copy())
00146 
00147         #
00148         # Fifth configuration
00149         configuration.description = "Thumb touching little finger tip ... "
00150         configuration.glove_data = []
00151         # corresponding data for the hand
00152         configuration.hand_data = [[30.0, 75.0, 3.0],
00153                                    [1.0, 75.0, 35.0]]
00154 
00155         self.configurations.append(configuration.copy())
00156 
00157         #
00158         # Sixth configuration
00159         configuration.description = "Thumb touching all the finger tips ... "
00160         configuration.glove_data = []
00161         # corresponding data for the hand
00162         configuration.hand_data = [[-30.0, 75.0, 60.0],
00163                                    [-7.0, 63.0, 60.0]]
00164 
00165         self.configurations.append(configuration.copy())
00166 
00167         #
00168         # Seventh configuration
00169         configuration.description = "hand flat, thumb relaxed along the fingers "
00170         configuration.glove_data = []
00171         # corresponding data for the hand
00172         configuration.hand_data = [[0.0, 0.0, -60.0]]
00173 
00174         self.configurations.append(configuration.copy())
00175 
00176         #
00177         # Eigth configuration
00178         configuration.description = "hand flat, thumb opened "
00179         configuration.glove_data = []
00180         # corresponding data for the hand
00181         configuration.hand_data = [[0.0, 75.0, -60.0]]
00182 
00183         self.configurations.append(configuration.copy())
00184 
00185     def evaluation_function(self, matrix):
00186         """
00187         The error is computed by adding the square error for each configuration.
00188         """
00189         error = 0
00190 
00191         # rebuild the matrix as a matrix, not a vector (the implementation of
00192         # the simplex in scipy works on vectors
00193         matrix_tmp = []
00194         for i in range(len(self.thumb_glove)):
00195             line = []
00196             for j in range(len(self.thumb_hand)):
00197                 line.append(matrix[i * len(self.thumb_hand) + j])
00198             matrix_tmp.append(line)
00199 
00200         matrix = matrix_tmp
00201         computed_vector_hand = []
00202 
00203         for config in self.configurations:
00204             # get the hand vectors from the glove data
00205             for vec_glove in config.glove_data:
00206                 computed_vector_hand.append(self.multiply(vec_glove, matrix))
00207 
00208             # compute the square error
00209             for vec_comp, vec_hand in zip(computed_vector_hand, config.hand_data):
00210                 for computed_hand_data in vec_comp:
00211                     for hand_data in vec_hand:
00212                         error += (computed_hand_data - hand_data) * (
00213                             computed_hand_data - hand_data)
00214 
00215         if self.verbose == 1:
00216             print "error: " + str(error)
00217 
00218         if error < self.minerror:
00219             self.minerror = error
00220 
00221         if error > self.maxerror:
00222             self.maxerror = error
00223 
00224         return error
00225 
00226     def multiply(self, vector_glove, matrix):
00227         """
00228         multiply the vector by the matrix. Returns a vector.
00229         """
00230         vector_hand = []
00231         index_col = 0
00232         print vector_glove
00233         print matrix
00234         for glove_data in vector_glove:
00235             data = 0
00236             for line in matrix:
00237                 data += (glove_data * line[index_col])
00238             vector_hand.append(data)
00239             index_col += 1
00240 
00241         return vector_hand
00242 
00243     def callback(self, xk):
00244         """
00245         Function called at each iteration
00246         """
00247         self.simplex_iteration_index += 1
00248         if self.simplex_iteration_index % 50 == 0:
00249             print "-------------------------"
00250             print "iteration number: " + str(self.simplex_iteration_index)
00251             # print xk
00252 
00253     def minimize(self):
00254         start = []
00255         for i in range(0, len(self.thumb_hand)):
00256             line = []
00257             for j in range(0, len(self.thumb_glove)):
00258                 line.append(0.1)
00259             start.append(line)
00260 
00261         xopt = fmin(self.evaluation_function, start,
00262                     callback=self.callback, maxiter=5000)
00263 
00264         # rebuild the result as a matrix, not a vector (the implementation of
00265         # the simplex in scipy works on vectors
00266         output = []
00267         for i in range(len(self.thumb_glove)):
00268             line = []
00269             for j in range(len(self.thumb_hand)):
00270                 line.append(xopt[i * len(self.thumb_hand) + j])
00271             output.append(line)
00272 
00273         print "min error: " + str(self.minerror)
00274         print "max error: " + str(self.maxerror)
00275 
00276         return output
00277 
00278     def write_full_mapping(self, output_path="../../../param/GloveToHandMappings"):
00279         """
00280         Writes the mapping matrix to a file:
00281         the glove values are the lines, the hand values are the columns
00282         """
00283 
00284         # initialise the matrix with 0s
00285         mapping_matrix = []
00286         for i in range(0, len(self.glove_name_index_map)):
00287             line = []
00288             for j in range(0, len(self.hand_name_index_map)):
00289                 line.append(0.0)
00290             mapping_matrix.append(line)
00291 
00292         # TH3 is always 0, RF4 as well
00293         # fill the matrix with the known values + th1 (all except the thumb)
00294         mapping_matrix[self.glove_name_index_map["G_IndexDIJ"]][
00295             self.hand_name_index_map["FF0"]] = 1.0
00296         mapping_matrix[self.glove_name_index_map["G_IndexPIJ"]][
00297             self.hand_name_index_map["FF0"]] = 1.0
00298         mapping_matrix[self.glove_name_index_map["G_IndexMPJ"]][
00299             self.hand_name_index_map["FF3"]] = 1.0
00300         mapping_matrix[self.glove_name_index_map["G_MiddleIndexAb"]][
00301             self.hand_name_index_map["FF4"]] = -1.0
00302 
00303         mapping_matrix[self.glove_name_index_map["G_MiddleDIJ"]][
00304             self.hand_name_index_map["MF0"]] = 1.0
00305         mapping_matrix[self.glove_name_index_map["G_MiddlePIJ"]][
00306             self.hand_name_index_map["MF0"]] = 1.0
00307         mapping_matrix[self.glove_name_index_map["G_MiddleMPJ"]][
00308             self.hand_name_index_map["MF3"]] = 1.0
00309         mapping_matrix[self.glove_name_index_map["G_RingMiddleAb"]][
00310             self.hand_name_index_map["MF4"]] = -1.0
00311 
00312         mapping_matrix[self.glove_name_index_map["G_RingDIJ"]][
00313             self.hand_name_index_map["RF0"]] = 1.0
00314         mapping_matrix[self.glove_name_index_map["G_RingPIJ"]][
00315             self.hand_name_index_map["RF0"]] = 1.0
00316         mapping_matrix[self.glove_name_index_map["G_RingMPJ"]][
00317             self.hand_name_index_map["RF3"]] = 1.0
00318 
00319         mapping_matrix[self.glove_name_index_map["G_PinkieDIJ"]][
00320             self.hand_name_index_map["LF0"]] = 1.0
00321         mapping_matrix[self.glove_name_index_map["G_PinkiePIJ"]][
00322             self.hand_name_index_map["LF0"]] = 1.0
00323         mapping_matrix[self.glove_name_index_map["G_PinkieMPJ"]][
00324             self.hand_name_index_map["LF3"]] = 1.0
00325         mapping_matrix[self.glove_name_index_map["G_PinkieRingAb"]][
00326             self.hand_name_index_map["LF4"]] = -1.0
00327         mapping_matrix[self.glove_name_index_map["G_PalmArch"]][
00328             self.hand_name_index_map["LF5"]] = 1.0
00329 
00330         mapping_matrix[self.glove_name_index_map["G_WristPitch"]][
00331             self.hand_name_index_map["WR1"]] = 1.0
00332         mapping_matrix[self.glove_name_index_map["G_WristYaw"]][
00333             self.hand_name_index_map["WR2"]] = 1.0
00334 
00335         mapping_matrix[self.glove_name_index_map["G_ThumbIJ"]][
00336             self.hand_name_index_map["TH1"]] = 1.0
00337 
00338         # mapping_matrix[self.glove_name_index_map["G_ThumbAb"]][self.hand_name_index_map["TH4"]] = 1.0
00339         # mapping_matrix[self.glove_name_index_map["G_ThumbRotate"]][self.hand_name_index_map["TH5"]] = 1.0
00340         # mapping_matrix[self.glove_name_index_map["G_ThumbMPJ"]][self.hand_name_index_map["TH2"]]
00341         # = 1.0
00342 
00343         # compute the best mapping for the thumb except th1
00344         thumb_mapping = self.minimize()
00345 
00346         # fill the matrix with the thumb values computed with the simplex
00347         for glove_name in self.thumb_glove.keys():
00348             for hand_name in self.thumb_hand.keys():
00349                 # indexes in the computed thumb mapping matrix
00350                 tmp_index_glove = self.thumb_glove[glove_name]
00351                 tmp_index_hand = self.thumb_hand[hand_name]
00352 
00353                 # retrieve the mapping value for those sensors
00354                 mapping_value = thumb_mapping[tmp_index_glove][tmp_index_hand]
00355 
00356                 # indexes for the whole mapping matrix
00357                 final_index_glove = self.glove_name_index_map[glove_name]
00358                 final_index_hand = self.hand_name_index_map[hand_name]
00359 
00360                 # update matrix
00361                 mapping_matrix[final_index_glove][
00362                     final_index_hand] = mapping_value
00363                 # write the matrix to a file
00364         file = open(output_path, "w")
00365         for line in mapping_matrix:
00366             for col in line:
00367                 file.write(" " + str(col))
00368             file.write("\n")
00369 
00370         file.close()
00371 
00372     def record(self, config):
00373         for i in range(0, 2):
00374             raw_input(str(i) + ": " + config.description)
00375             vector_data = [0] * len(self.thumb_glove)
00376             for sensor_name in self.thumb_glove.keys():
00377                 data = self.cyberglove.read_calibrated_average_value(
00378                     sensor_name)
00379                 vector_data[self.thumb_glove[sensor_name]] = data
00380             config.glove_data.append(vector_data)
00381 
00382         if(self.verbose == 1):
00383             print "read values:"
00384             print config.glove_data
00385 
00386 
00387 #
00388 # MAIN    #
00389 #
00390 def main():
00391     cyber_mapper = MappingMinimizer()
00392 
00393     for config in cyber_mapper.configurations:
00394         cyber_mapper.record(config)
00395 
00396     cyber_mapper.write_full_mapping()
00397 
00398     return 0
00399 
00400 
00401 # start the script
00402 if __name__ == "__main__":
00403     main()


sr_gui_cyberglove_calibrator
Author(s): Ugo Cupcic
autogenerated on Thu Jun 6 2019 21:13:53