segway_motion_calc.py
Go to the documentation of this file.
00001 #
00002 #
00003 # Copyright (c) 2010, Georgia Tech Research Corporation
00004 # All rights reserved.
00005 # 
00006 # Redistribution and use in source and binary forms, with or without
00007 # modification, are permitted provided that the following conditions are met:
00008 #     * Redistributions of source code must retain the above copyright
00009 #       notice, this list of conditions and the following disclaimer.
00010 #     * Redistributions in binary form must reproduce the above copyright
00011 #       notice, this list of conditions and the following disclaimer in the
00012 #       documentation and/or other materials provided with the distribution.
00013 #     * Neither the name of the Georgia Tech Research Corporation nor the
00014 #       names of its contributors may be used to endorse or promote products
00015 #       derived from this software without specific prior written permission.
00016 # 
00017 # THIS SOFTWARE IS PROVIDED BY GEORGIA TECH RESEARCH CORPORATION ''AS IS'' AND
00018 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00020 # DISCLAIMED. IN NO EVENT SHALL GEORGIA TECH BE LIABLE FOR ANY DIRECT, INDIRECT,
00021 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00022 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00023 # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00024 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
00025 # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00026 # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 #
00028 
00029 # \author Advait Jain (Healthcare Robotics Lab, Georgia Tech.)
00030 
00031 
00032 import roslib
00033 roslib.load_manifest('equilibrium_point_control')
00034 
00035 
00036 import numpy as np, math
00037 import scipy.optimize as so
00038 import scipy.ndimage as ni
00039 import matplotlib_util.util as mpu
00040 import hrl_lib.util as ut
00041 import hrl_lib.transforms as tr
00042 import hrl_hokuyo.hokuyo_processing as hp
00043 import mekabot.coord_frames as mcf
00044 import util as uto
00045 from opencv.highgui import *
00046 
00047 ##
00048 # @param pts - 2xN np matrix
00049 # @return r,theta (two 1D np arrays)
00050 def cartesian_to_polar(pts):
00051     r = ut.norm(pts).A1
00052     theta = np.arctan2(pts[1,:],pts[0,:]).A1
00053     return r,theta
00054 
00055 ##
00056 # @param r - 1D np array
00057 # @param theta - 1D np array (RADIANS)
00058 # @return 2xN np matrix of cartesian points
00059 def polar_to_cartesian(r,theta):
00060     x = r*np.cos(theta)
00061     y = r*np.sin(theta)
00062     return np.matrix(np.row_stack((x,y)))
00063 
00064 ##
00065 # mx,my,ma - motion of the robot
00066 # cx,cy - axis of mechanism in robot frame.
00067 # start_angle,end_angle - between 0 and 2*pi
00068 def point_contained(mx,my,ma,cx,cy,rad,pts,start_angle,end_angle,buffer):
00069     if abs(mx)>0.2 or abs(my)>0.2 or abs(ma)>math.radians(40):
00070 #        print 'too large a motion for point_contained'
00071         return np.array([[]])
00072     pts_t = pts + np.matrix([mx,my]).T
00073     pts_t = tr.Rz(-ma)[0:2,0:2]*pts_t
00074     r,t = cartesian_to_polar(pts_t-np.matrix([cx,cy]).T)
00075     t = np.mod(t,math.pi*2) # I want theta to be b/w 0 and 2pi
00076     if start_angle<end_angle:
00077         f = np.row_stack((r<rad+buffer,r>rad-buffer/2.,t<end_angle,t>start_angle))
00078     else:
00079         f = np.row_stack((r<rad+buffer,r>rad-buffer/2.,t<start_angle,t>end_angle))
00080     idxs = np.where(np.all(f,0))
00081 
00082     r_filt = r[idxs]
00083     t_filt = t[idxs]
00084     return polar_to_cartesian(r_filt,t_filt)+np.matrix([cx,cy]).T
00085 
00086 def optimize_position(cx,cy,rad,curr_pos,eq_pos,pts,bndry,start_angle,
00087                       end_angle,buffer,tangential_force):
00088     scale_x,scale_y,scale_a = 1.,1.,1.
00089     b = min(abs(tangential_force),60.)
00090     if end_angle>start_angle:
00091 #        min_alpha = math.radians(30)
00092         max_alpha = math.radians(90)
00093     else:
00094 #        min_alpha = math.radians(-150)
00095         max_alpha = math.radians(-90)
00096     min_alpha = max_alpha - math.radians(60-b*0.7)
00097 
00098     dist_moved_weight = 0.4 - 0.3*b/60.
00099     alpha_weight = 0.4+1.0*b/60.
00100     bndry_weight = 1.
00101     pts_in_weight = 1.
00102 
00103     print 'OPTIMIZE_POSITION'
00104     print 'start_angle:', math.degrees(start_angle)
00105     print 'end_angle:', math.degrees(end_angle)
00106     print 'tangential_force:', tangential_force
00107 
00108     def error_function(params):
00109         mx,my,ma = params[0],params[1],params[2]
00110         mx,my,ma = mx/scale_x,my/scale_y,ma/scale_a
00111         #x,y = params[0],params[1]
00112         pts_in = point_contained(mx,my,ma,cx,cy,rad,pts,
00113                                  start_angle,end_angle,buffer)
00114         p = tr.Rz(ma)*curr_pos-np.matrix([mx,my,0.]).T
00115         p_eq = tr.Rz(ma)*eq_pos-np.matrix([mx,my,0.]).T
00116 
00117         dist_moved = math.sqrt(mx*mx+my*my)+abs(ma)*0.2
00118         dist_bndry = dist_from_boundary(p_eq,bndry,pts)
00119         alpha = math.pi-(start_angle-ma)
00120 
00121         if alpha<min_alpha:
00122             alpha_cost = min_alpha-alpha
00123         elif alpha>max_alpha:
00124             alpha_cost = alpha-max_alpha
00125         else:
00126             alpha_cost = 0.
00127         alpha_cost = alpha_cost * alpha_weight
00128         move_cost = dist_moved * dist_moved_weight
00129         bndry_cost = dist_bndry * bndry_weight
00130         pts_in_cost = pts_in.shape[1]/1000. * pts_in_weight
00131 
00132 #        print '---------------------------------'
00133 #        print 'alpha:',math.degrees(alpha)
00134 #        print 'alpha_cost:',alpha_cost
00135 #        print 'mx,my:',mx,my
00136 #        print 'dist_moved:',dist_moved
00137 #        print 'dist_bndry:',dist_bndry
00138 #        print 'pts_in.shape[1]:',pts_in.shape[1]
00139 #        print 'move_cost:', move_cost
00140 #        print 'bndry_cost:',bndry_cost
00141 #        print 'pts_in_cost:',pts_in_cost
00142 
00143 #        return -pts_in.shape[1]+dist_moved - bndry_cost
00144         err = -pts_in_cost-bndry_cost+move_cost+alpha_cost
00145 #        print 'error function value:',err
00146         return err
00147 
00148     params_1 = [0.,0.,0.]
00149     res = so.fmin_bfgs(error_function,params_1,full_output=1)
00150 
00151     r,f = res[0],res[1]
00152 
00153 #    r,f,d = so.fmin_l_bfgs_b(error_function,params_1,approx_grad=True,
00154 #                             bounds=[(-0.1*scale_x,0.1*scale_x),
00155 #                                     (-0.1*scale_y,0.1*scale_y),
00156 #                              (-math.radians(15)*scale_a,
00157 #                                math.radians(15)*scale_a)],
00158 #                             m=10, factr=10000000.0,
00159 #                             pgtol=1.0000000000000001e-05,
00160 #                             epsilon=0.0001, iprint=-1,
00161 #                             maxfun=1000)
00162     opt_params = r
00163 #    print 'optimized value:',f
00164     mx,my,ma =  opt_params[0]/scale_x,opt_params[1]/scale_y,\
00165                 opt_params[2]/scale_a
00166     error_function(opt_params)
00167     return mx,my,ma
00168     #return opt_params[0],opt_params[1]
00169 
00170 ##
00171 # compute the boundary of the 2D points. Making assumptions about
00172 # the density of the points, tested with workspace_dict only.
00173 # @param pts - 2xN np matrix
00174 def compute_boundary(pts):
00175     npim1,nx,ny,br = hp.xy_map_to_np_image(pts,m_per_pixel=0.01,dilation_count=0,padding=10)
00176     npim1 = npim1/255
00177     npim = np.zeros(npim1.shape,dtype='int')
00178     npim[:,:] = npim1[:,:]
00179 
00180     connect_structure = np.empty((3,3),dtype='int')
00181     connect_structure[:,:] = 1
00182     erim = ni.binary_erosion(npim,connect_structure,iterations=1)
00183     bim = npim-erim
00184     tup = np.where(bim>0)
00185     bpts = np.row_stack((nx-tup[0],ny-tup[1]))*0.01 + br
00186 #    cvim = uto.np2cv(bim)
00187 #    cvSaveImage('boundary.png',cvim)
00188     return np.matrix(bpts)
00189 
00190 ##
00191 #return 2x1 vector from closest boundary point
00192 def vec_from_boundary(curr_pos,bndry):
00193     p = curr_pos[0:2,:]
00194     v = p-bndry
00195     min_idx = np.argmin(ut.norm(v))
00196     return v[:,min_idx]
00197 
00198 ##
00199 #return distance from boundary. (-ve if outside the boundary)
00200 # @param curr_pos - can be 3x1 np matrix
00201 # @param bndry - boundary (2xN np matrix)
00202 # @param pts - 2xN np matrix. pts whose boundary is bndry
00203 def dist_from_boundary(curr_pos,bndry,pts):
00204     mv = vec_from_boundary(curr_pos,bndry)
00205 #    spoly = sg.Polygon((bndry.T).tolist())
00206 #    spt = sg.Point(curr_pos[0,0],curr_pos[1,0])
00207     d = np.linalg.norm(mv)
00208 
00209     p = curr_pos[0:2,:]
00210     v = p-pts
00211     min_dist = np.min(ut.norm(v))
00212 #    print 'min_dist,d:',min_dist,d
00213 #    print 'min_dist >= d',min_dist >= d-0.001
00214     if min_dist >= d-0.001:
00215 #        print 'I predict outside workspace'
00216         d = -d
00217 
00218 #    if spoly.contains(spt) == False:
00219 #        print 'Shapely predicts outside workspace'
00220 #        d = -d
00221     return d
00222 
00223 ##
00224 # @param curr_pos - current location of end effector. 3x1 np matrix
00225 # @param bndry - workspace boundary. 2xN np matrix
00226 def close_to_boundary(curr_pos,bndry,pts,dist_thresh):
00227     min_dist = dist_from_boundary(curr_pos,bndry,pts)
00228     return min_dist <= dist_thresh
00229 
00230 def visualize_boundary():
00231     d = ut.load_pickle('../../pkls/workspace_dict_2009Sep03_010426.pkl')
00232     z = -0.23
00233     k = d.keys()
00234     k_idx = np.argmin(np.abs(np.array(k)-z))
00235     pts = d[k[k_idx]]
00236     bpts = compute_boundary(pts)
00237 
00238     cl_list = []
00239     for pt in pts.T:
00240         if close_to_boundary(pt.T,bpts,dist_thresh=0.05)==True:
00241             cl_list.append(pt.A1.tolist())
00242     clpts = np.matrix(cl_list).T
00243     print 'clpts.shape:', clpts.shape
00244 
00245     mpu.plot_yx(pts[1,:].A1,pts[0,:].A1,linewidth=0)
00246     mpu.plot_yx(clpts[1,:].A1,clpts[0,:].A1,linewidth=0,color='r')
00247     mpu.plot_yx(bpts[1,:].A1,bpts[0,:].A1,linewidth=0,color='y')
00248     mpu.show()
00249 
00250 
00251 ## transform from torso start to torso local frame.
00252 # @param pts - 3xN np matrix in ts coord frame.
00253 # @param x,y,a - motion of the segway (in the ms frame)
00254 # @return pts_tl
00255 def tlTts(pts_ts,x,y,a):
00256     pts_ms = mcf.mecanumTglobal(mcf.globalTtorso(pts_ts))
00257     v_org_ms = np.matrix([x,y,0.]).T
00258     pts_ml = tr.Rz(a)*(pts_ms-v_org_ms)
00259     pts_tl = mcf.torsoTglobal(mcf.globalTmecanum(pts_ml))
00260     return pts_tl
00261 
00262 ## transform from torso local to torso start frame.
00263 # @param pts - 3xN np matrix in tl coord frame.
00264 # @param x,y,a - motion of the segway (in the ms frame)
00265 # @return pts_ts
00266 def tsTtl(pts_tl,x,y,a):
00267     pts_ml = mcf.mecanumTglobal(mcf.globalTtorso(pts_tl))
00268     v_org_ms = np.matrix([x,y,0.]).T
00269     pts_ms = tr.Rz(-a) * pts_ml + v_org_ms
00270     pts_ts = mcf.torsoTglobal(mcf.globalTmecanum(pts_ms))
00271     return pts_ts
00272 
00273 ## rotate vector from torso local to torso start frame.
00274 # @param vecs_tl - 3xN np matrix in tl coord frame.
00275 # @param a - motion of the segway (in the ms frame)
00276 # @return vecs_ts
00277 def tsRtl(vecs_tl, a):
00278     vecs_ml = mcf.mecanumTglobal(mcf.globalTtorso(vecs_tl, True), True)
00279     vecs_ms = tr.Rz(-a) * vecs_ml
00280     vecs_ts = mcf.torsoTglobal(mcf.globalTmecanum(vecs_ms, True), True)
00281     return vecs_ts
00282 
00283 ## rotate vector from torso local to torso start frame.
00284 # @param vecs_tl - 3xN np matrix in tl coord frame.
00285 # @param a - motion of the segway (in the ms frame)
00286 # @return vecs_ts
00287 def tlRts(vecs_ts, a):
00288     vecs_ms = mcf.mecanumTglobal(mcf.globalTtorso(vecs_ts, True), True)
00289     vecs_ml = tr.Rz(a) * vecs_ms
00290     vecs_tl = mcf.torsoTglobal(mcf.globalTmecanum(vecs_ml, True), True)
00291     return vecs_tl
00292 
00293 
00294 def pts_within_dist(p,pts,min_dist,max_dist):
00295     v = p-pts
00296     d_arr = ut.norm(v).A1
00297     idxs = np.where(np.all(np.row_stack((d_arr<max_dist,d_arr>min_dist)),axis=0))
00298     pts_within = pts[:,idxs[0]]
00299     return pts_within
00300 
00301 
00302 ## apologies for the poor name. computes the translation of the torso
00303 # frame that move the eq pt away from closest boundary and rotate such
00304 # that local x axis is perp to mechanism returns 2x1 np matrix, angle
00305 def segway_motion_repulse(curr_pos_tl, eq_pt_tl,bndry, all_pts):
00306     bndry_dist_eq = dist_from_boundary(eq_pt_tl,bndry,all_pts) # signed
00307     bndry_dist_ee = dist_from_boundary(curr_pos_tl,bndry,all_pts) # signed
00308     if bndry_dist_ee < bndry_dist_eq:
00309         p = curr_pos_tl[0:2,:]
00310         bndry_dist = bndry_dist_ee
00311     else:
00312         p = eq_pt_tl[0:2,:]
00313         bndry_dist = bndry_dist_eq
00314 
00315 #    p = eq_pt_tl[0:2,:]
00316     pts_close = pts_within_dist(p,bndry,0.002,0.07)
00317     v = p-pts_close
00318     d_arr = ut.norm(v).A1
00319     v = v/d_arr
00320     v = v/d_arr # inverse distance weight
00321     resultant = v.sum(1)
00322     res_norm = np.linalg.norm(resultant)
00323     resultant = resultant/res_norm
00324     tvec = -resultant
00325 
00326     if bndry_dist < 0.:
00327         tvec = -tvec # eq pt was outside workspace polygon.
00328 
00329     if abs(bndry_dist)<0.01 or res_norm<0.01:
00330         # internal external test fails so falling back on
00331         # going to mean.
00332         m = all_pts.mean(1)
00333         tvec = m-p
00334         tvec = -tvec/np.linalg.norm(tvec)
00335 
00336     dist_move = 0.
00337     if bndry_dist > 0.05:
00338         dist_move = 0.
00339     else:
00340         dist_move = 1.
00341 
00342     tvec = tvec*dist_move # tvec is either a unit vec or zero vec.
00343     return tvec
00344 
00345 
00346 if __name__ == '__main__':
00347 
00348     #d = ut.load_pickle('workspace_dict_2009Sep03_221107.pkl')
00349     d = ut.load_pickle('../../pkls/workspace_dict_2009Sep05_200116.pkl')
00350     z = -0.23
00351     k = d.keys()
00352     k_idx = np.argmin(np.abs(np.array(k)-z))
00353     pts = d[k[k_idx]]
00354 #    visualize_boundary()
00355 
00356     for kk in k:
00357         pts = d[kk]
00358         bpts = compute_boundary(pts)
00359         cx,cy = 0.7,-0.6
00360         rad = 0.4
00361         
00362     #    pts_in = point_contained(cx,cy,0.,rad,pts,
00363     #                             start_angle=math.radians(140),
00364     #                             end_angle=math.radians(190))
00365         mpu.figure()
00366         mpu.plot_yx(pts[1,:].A1,pts[0,:].A1,linewidth=0)
00367         mpu.plot_yx(bpts[1,:].A1,bpts[0,:].A1,linewidth=0,color='y')
00368 #    mpu.plot_yx(pts_in[1,:].A1,pts_in[0,:].A1,linewidth=0,color='g')
00369 #    mpu.plot_yx([cy],[cx],linewidth=0,color='r')
00370     mpu.show()
00371 
00372 
00373 
00374 
00375 ### apologies for the poor name. computes the translation and rotation
00376 ## of the torso frame that move the eq pt away from closest boundary
00377 ## and rotate such that local x axis is perp to mechanism
00378 ## returns 2x1 np matrix, angle
00379 #def segway_motion_repulse(curr_pos_tl,cx_tl,cy_tl,cy_ts,start_pos_ts,
00380 #                          eq_pt_tl,bndry):
00381 #    vec_bndry = vec_from_boundary(eq_pt_tl,bndry)
00382 #    dist_boundary = np.linalg.norm(vec_bndry)
00383 #    vec_bndry = vec_bndry/dist_boundary
00384 #
00385 #    radial_vec_tl = curr_pos_tl[0:2]-np.matrix([cx_tl,cy_tl]).T
00386 #    radial_angle = math.atan2(radial_vec_tl[1,0],radial_vec_tl[0,0])
00387 #    if cy_ts<start_pos_ts[1,0]:
00388 #        err = radial_angle-math.pi/2
00389 #    else:
00390 #        err = radial_angle +math.pi/2
00391 #    
00392 #    a_torso = err
00393 #    dist_move = max(0.15-dist_boundary,0.)
00394 #    if dist_move < 0.04:
00395 #        dist_move = 0.
00396 #    hook_translation_tl = -vec_bndry*dist_move
00397 #
00398 ##    print 'vec_bndry:',vec_bndry.A1.tolist()
00399 ##    print 'dist_boundary:',dist_boundary
00400 #
00401 #    return hook_translation_tl,a_torso
00402 
00403 


2010_icra_epc_pull
Author(s): Advait Jain, Charles C. Kemp (Healthcare Robotics Lab, Georgia Tech)
autogenerated on Wed Nov 27 2013 12:14:43