haptic_mpc_util.py
Go to the documentation of this file.
00001 #   Copyright 2013 Georgia Tech Research Corporation
00002 #
00003 #   Licensed under the Apache License, Version 2.0 (the "License");
00004 #   you may not use this file except in compliance with the License.
00005 #   You may obtain a copy of the License at
00006 #
00007 #     http://www.apache.org/licenses/LICENSE-2.0
00008 #
00009 #   Unless required by applicable law or agreed to in writing, software
00010 #   distributed under the License is distributed on an "AS IS" BASIS,
00011 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 #   See the License for the specific language governing permissions and
00013 #   limitations under the License.
00014 #
00015 #  http://healthcare-robotics.com/
00016 
00017 ## @package hrl_haptic_mpc
00018 #
00019 # @author Jeff Hawke
00020 # @version 0.1
00021 # @copyright Apache 2.0
00022 
00023 # Useful utility functions used by the Haptic MPC controller and associated nodes.
00024 # Functions generally are used to reformat data structures.
00025 
00026 import numpy as np
00027 import hrl_lib.transforms as tr
00028 import hrl_lib.util as ut
00029 import decimal as dec
00030 
00031 
00032 ## Return a taxel array message data as lists (formats it nicely for iteration).
00033 # @param ta_msg TaxelArray message object
00034 # @retval locations_list List of taxel locations, specified as numpy matrices: [x,y,z].T
00035 # @retval normals_list List of normal vectors, specified as numpy matrices: [x,y,z].T
00036 # @retval values_list List of force (or distance) magnitudes, specified as numpy matrices: [x,y,z].T
00037 # @retval joints_list List of taxel locations, specified as numpy matrices: [x,y,z].T
00038 def getTaxelArrayDataAsLists(ta_msg):
00039   normals_list = []
00040   locations_list = []
00041   values_list = []
00042   joints_list = []
00043   for i in range(0, len(ta_msg.normals_x)):
00044     normal_vector = np.matrix([ta_msg.normals_x[i], ta_msg.normals_y[i], ta_msg.normals_z[i]]).T
00045     normals_list.append(normal_vector)
00046     point_vector = np.matrix([ta_msg.centers_x[i], ta_msg.centers_y[i], ta_msg.centers_z[i]]).T
00047     locations_list.append(point_vector)
00048     values_vector = np.matrix([ta_msg.values_x[i], ta_msg.values_y[i], ta_msg.values_z[i]]).T
00049     values_list.append(values_vector)
00050     joints_list.append(ta_msg.link_names[i])
00051   return locations_list, normals_list, values_list, joints_list
00052 
00053 ## Return a taxel array normal vector data as a list (formats it nicely for iteration).
00054 # @param ta_msg TaxelArray message object
00055 # @retval normals_list List of normal vectors, specified as numpy matrices: [x,y,z].T
00056 def getNormalsFromTaxelArray(ta_msg):
00057   normals_list = []
00058   for i in range(0, len(ta_msg.normals_x)):
00059     normal_vector = np.matrix([ta_msg.normals_x[i], ta_msg.normals_y[i], ta_msg.normals_z[i]]).T
00060     normals_list.append(normal_vector)  
00061   return normals_list
00062 
00063 ## Return a taxel array force location vector data as a list (formats it nicely for iteration).
00064 # @param ta_msg TaxelArray message object
00065 # @retval locations_list List of contact locations, specified as numpy matrices: [x,y,z].T
00066 def getLocationsFromTaxelArray(ta_msg):
00067   points_list = []
00068   for i in range(0, len(ta_msg.centers_x)):
00069     point_vector = np.matrix([ta_msg.centers_x[i], ta_msg.centers_y[i], ta_msg.centers_z[i]]).T
00070     points_list.append(point_vector)
00071   return points_list
00072 
00073 ## Return a taxel array force magnitude vector data as a list (formats it nicely for iteration).
00074 # @param ta_msg TaxelArray message object
00075 # @retval values_list List of taxel values (eg, force or proximity), specified as numpy matrices: [x,y,z].T
00076 def getValuesFromTaxelArray(ta_msg):
00077   values_list = []
00078   for i in range(0, len(ta_msg.values_x)):
00079     values_vector = np.matrix([ta_msg.values_x[i], ta_msg.values_y[i], ta_msg.values_z[i]]).T
00080     values_list.append(values_vector)
00081   return values_list
00082 
00083 ## Return a taxel array force magnitude vector data as a list (formats it nicely for iteration).
00084 # @param ta_msg_list A list of TaxelArray message objects.
00085 # @retval locations_list List of taxel locations, specified as numpy matrices: [x,y,z].T
00086 # @retval normals_list List of normal vectors, specified as numpy matrices: [x,y,z].T
00087 # @retval values_list List of force (or distance) magnitudes, specified as numpy matrices: [x,y,z].T
00088 # @retval joints_list List of taxel locations, specified as numpy matrices: [x,y,z].T
00089 def getAllTaxelArrayDataAsLists(ta_msg_list):
00090   locations_list = []
00091   normals_list = []
00092   values_list = []
00093   joints_list = []
00094   for taxel_array in ta_msg_list:
00095     ll, nl, vl, jl = getTaxelArrayDataAsLists(taxel_array)
00096     locations_list.extend(ll)
00097     normals_list.extend(nl)
00098     values_list.extend(vl)
00099     joints_list.extend(jl)
00100   return locations_list, normals_list, values_list, joints_list
00101 
00102 
00103 ## Return a taxel array force magnitude vector data as a list (formats it nicely for iteration).
00104 # @param ta_msg_list A list of TaxelArray message objects.
00105 # @retval locations_list List of taxel locations, specified as numpy matrices: [x,y,z].T
00106 def getLocations(ta_msg_list):
00107   locations_list = []
00108   for taxel_array in ta_msg_list:
00109     ll = getLocationsFromTaxelArray(taxel_array)
00110     locations_list.extend(ll)
00111   return locations_list
00112 
00113 ## Return a taxel array force magnitude vector data as a list (formats it nicely for iteration).
00114 # @param ta_msg_list A list of TaxelArray message objects.
00115 # @retval values_list List of force (or distance) magnitudes, specified as numpy matrices: [x,y,z].T
00116 def getValues(ta_msg_list, force = True, distance = False):
00117   values_list = []
00118   for taxel_array in ta_msg_list:
00119     vl = getValuesFromTaxelArray(taxel_array)
00120     values_list.extend(vl)
00121   return values_list
00122 
00123 ## Return a taxel array force magnitude vector data as a list (formats it nicely for iteration).
00124 # @param ta_msg_list A list of TaxelArray message objects.
00125 # @retval normals_list List of normal vectors, specified as numpy matrices: [x,y,z].T
00126 def getNormals(ta_msg_list):
00127   normals_list = []
00128   for taxel_array in ta_msg_list:
00129     nl = getNormalsFromTaxelArray(taxel_array)
00130     normals_list.extend(nl)
00131   return normals_list
00132 
00133 ## Return a skew matrix as a numpy matrix given an vector (n=3) input.
00134 # @param vec List of length 3
00135 # @return 3x3 numpy skew matrix
00136 def getSkewMatrix(vec):
00137     return np.matrix([[0, -vec[2], vec[1]],
00138                       [vec[2], 0, -vec[0]], 
00139                       [-vec[1], vec[0], 0]])
00140 
00141 
00142 
00143 ## Interpolate a step towards the given goal orientation.
00144 # @param q_h_orient The current hand orientation as a quaternion in list form: [x,y,z,w]
00145 # @param q_g_orient The current goal orientation as a quaternion in list form: [x,y,z,w]
00146 # @return Desired change in orientation as a delta
00147 # @todo clean this up so it doesn't use the "step" multiplier
00148 def goalOrientationInQuat(q_h_orient, q_g_orient, max_ang_step):
00149   ang = ut.quat_angle(q_h_orient, q_g_orient)
00150 
00151   ang_mag = abs(ang)
00152   step_fraction = 0.001
00153   if step_fraction * ang_mag > max_ang_step:
00154     # this is pretty much always true, can clean up the code.
00155     step_fraction = max_ang_step / ang_mag
00156 
00157   interp_q_goal = tr.tft.quaternion_slerp(q_h_orient, q_g_orient, step_fraction)
00158   delta_q_des = tr.tft.quaternion_multiply(interp_q_goal, tr.tft.quaternion_inverse(q_h_orient))
00159 
00160   return np.matrix(delta_q_des[0:3]).T
00161 
00162 ## Return a skew matrix as a numpy matrix given an vector (n=3) input.
00163 # Identical to getSkewMatrix - needs to be cleaned up.
00164 # @param vec List of length 3
00165 # @return 3x3 numpy skew matrix
00166 def get_skew_matrix(vec):
00167   return np.matrix([[0, -vec[2], vec[1]],
00168                     [vec[2], 0, -vec[0]], 
00169                     [-vec[1], vec[0], 0]])
00170 
00171 ## Sets up options for an optparse.OptionParser. These parameters are used across multiple classes - eg, robot haptic state publisher, arm trajectory generator, etc
00172 # @param p optparse.OptionParser object
00173 def initialiseOptParser(p):
00174   p.add_option('--ignore_skin', '--is', action='store_true', dest='ignore_skin',
00175                help='ignore feedback from tactile skin')
00176   p.add_option('--orientation', '-o', action='store_true', dest='orientation',
00177                help='try to go to commanded orientation in addition to position')
00178   p.add_option('--robot', '-r', action='store', dest='robot',
00179                help='robot name: cody, cody5dof, pr2, sim3, sim3_nolim, sim3_with_hand, simcody')
00180   p.add_option('--sensor', '-s', action='store', dest='sensor',
00181                help='sensor type: meka_sensor, fabric_sensor, hil, ignore')
00182   p.add_option('--use_wrist_joints', action='store_true', dest='use_wrist_joints',
00183                help='use wrist joints (Cody ONLY)')
00184   p.add_option('--arm_to_use', '-a', action='store', dest='arm', type='string',
00185                help='which arm to use (l, r)', default=None)
00186   p.add_option('--start_test', action='store_true', dest='start_test',
00187                help='makes cody move to specified jep if true')
00188 
00189 ## Takes an optparse.OptionParser as an input, and returns a valid opt structure (or flags an error).
00190 # @param p optparse.OptionParser object
00191 # @return Validated options from parsed input.
00192 def getValidInput(p):
00193   opt, args = p.parse_args()
00194   # Validate input options
00195   valid_robots = ['cody', 'cody5dof', 'pr2', 'sim3', 'sim3_nolim', 'sim3_with_hand', 'simcody', 'crona']
00196   valid_sensors = ['meka', 'fabric', 'hil', 'none', 'pps', 'sim']
00197 
00198   if opt.robot and opt.robot not in valid_robots:
00199     p.error("Must specify a valid robot type: -r %s" % str(valid_robots))
00200   if opt.sensor and opt.sensor not in valid_sensors:
00201     p.error("Must specify a valid sensor type: -s %s" % str(valid_sensors))
00202   if opt.robot and opt.sensor and opt.robot == 'pr2' and (opt.sensor == 'meka' or opt.sensor == 'hil'):
00203     p.error("Invalid sensor for the PR2 [meka, hil]. Valid options: -s [fabric, pps, none]")  
00204   return opt
00205 
00206 ## Get number of decimal points in a float.
00207 # @param float_value The number being evaluated for the number of decimal places
00208 def getNumDecimalPlaces(float_value):
00209   return abs(dec.Decimal(str(float_value)).as_tuple().exponent)
00210 
00211 ## Rounds the value provided to the nearest 'unit'
00212 # @param value The number being rounded
00213 # @param unit The step size to round the value to.
00214 def divRound(value, unit):
00215   return round(round(value/unit)*unit, getNumDecimalPlaces(value))


hrl_haptic_mpc
Author(s): Jeff Hawke, Phillip Grice, Marc Killpack, Advait Jain. Advisor and Co-author: Prof. Charlie Kemp. Healthcare Robotics Lab, Georgia Tech
autogenerated on Wed Nov 27 2013 12:27:09