MAGIKS  1.1
Manipulator General Inverse Kinematic Solver
 All Classes Namespaces Files Functions Variables Pages
workspace.py
Go to the documentation of this file.
1 # BODY
2 ## @file: workspace.py
3 # @brief: This module provides a class containing methods and properties regarding the workspace of a manipulator.
4 # with their associated poses.
5 # @author Nima Ramezani Taghiabadi
6 #
7 # PhD Researcher
8 # Faculty of Engineering and Information Technology
9 # University of Technology Sydney (UTS)
10 # Broadway, Ultimo, NSW 2007, Australia
11 # Phone No. : 04 5027 4611
12 # Email(1) : nima.ramezani@gmail.com
13 # Email(2) : Nima.RamezaniTaghiabadi@uts.edu.au
14 # @version 2.0
15 #
16 # Last Revision: 11 January 2015
17 
18 import numpy,copy, pickle
19 
20 import general_python as genpy
21 import magiks.taskspace.endeffector as endlib
22 from math_tools.geometry import rotation
23 from packages.matej.artificial_intelligence.data_mining.kdtree import kdtree
24 
25 ## Use this function to load the workspace from a file.
26 # @param path_and_file_name A string specifying the full path and filename containing the workspace data
27 # @return An instance of class packages.nima.robotics.kinematics.task_space.workspace.Workspace()
28 def read_from_file(path_and_file_name):
29  FILE_DATA = open(path_and_file_name, "r")
30  work_space = pickle.load(FILE_DATA)
31  return work_space
32 
33 '''
34 key_dic = {
35  'NA' : 'Not Applicable',
36 
37  # Forward:
38  'RND' : 'Random',
39  'JSG' : 'Joint Space Grid',
40  'PCL' : 'Predefined Config List',
41  'NTP' : 'Nearest to Target Pose',
42  'NCC' : 'Nearest to Current Configuration',
43  'CLO' : 'Config List Order',
44 
45  # Inverse:
46  'Random' : 'RND',
47  'Nearest to Target Pose' : 'NTP',
48  'Nearest to Current Configuration' : 'NCC',
49 }
50 '''
51 
52 ## This class contains all the required settings of a workspace.
54  '''
55  '''
56  # all_search_criteria = ['Nearest to Target Pose', 'Nearest to Current Configuration', 'List Order']
57 
58  def __init__( self, creation_method = 'JSG', grid_resolution = 2, representation_of_orientation = 'angular_spherical', number_of_search_items = 1, number_of_configs = 10, search_criteria = 'Nearest to Target Pose'):
59 
60  '''
61  creation_method: Configuration Generation Method
62 
63  Possible methods are:
64 
65  'Joint Space Grid' (key = 'JSG'): Initial Configurations generated by FK computations of configs of a grid of jointspace
66  'Random' (key = 'RND'): Initial Configurations generated randomly (Additional time required only for generating random configurations)
67  'Constant Set' (key = 'CST'): Initial Configurations read from a list of Configurations corresponding to a "Constant Set of Poses" (No additional time required)
68  '''
69  self.creation_method = creation_method
70  # "number_of_intervals": determines the number of intervals, each joint takes in the jointspace grid
71  self.grid_resolution = grid_resolution
72  # e.g. 'vectorial_identity'
73  self.representation_of_orientation = representation_of_orientation
74  self.number_of_search_items = number_of_search_items
75  self.number_of_configs = number_of_configs
76  self.search_criteria = search_criteria
77 
78  self.read_workspace = False
79  self.write_workspace = False
80 
82 
84  if self.representation_of_orientation == 'angular_spherical':
85  return 'AngSph'
86  elif self.representation_of_orientation == 'vectorial_identity':
87  return 'VecIty'
88  elif self.representation_of_orientation == 'Rotation Matrix':
89  return 'RotMtx'
90  else:
91  assert False
92 
94  return self.search_criteria + str(self.number_of_search_items)
95 
96  def gen_key(self):
97 
98  if self.creation_method == 'JSGrid':
99  ns = str(self.grid_resolution)
100  else:
101  ns = str(self.number_of_configs)
102  return self.creation_method + ns
103 
104  def gen_file_name(self, manip_name):
105  return manip_name + '_' + self.gen_key() + '_' + self.represent_orient_key() + '.ws'
106 
107  def __str__(self):
108  s = "\n"
109  s += "Workspace Settings: " + "\n" + "\n"
110  s += "Creation Method: " + self.creation_method + "\n"
111  s += "Grid Resolution: " + str(self.grid_resolution) + "\n"
112  s += "Representation of Orientation: " + self.representation_of_orientation + "\n"
113  s += "Number of Configurations: " + str(self.number_of_configs) + "\n"
114  s += "Number of Search Items: " + str(self.number_of_search_items) + "\n"
115  s += "Search Criteria: " + self.search_criteria + "\n"
116 
117  return s
118 
119 
120 class Workspace(endlib.Endeffector):
121  '''
122  This class inherits DH parameters from class: "Manipulator_Geometry"
123  It contains pre-computed kinematic properties of a manipulator in a discretized grid of the jointspace.
124  These properties are in two equivalent lists named "config_list" and "pose_list"
125  '''
126 
127  def __init__( self, config_settings, geo_settings, end_settings, ws_settings):
128  '''
129  '''
130  super(Workspace, self).__init__(config_settings, geo_settings, end_settings)
131  self.ws_settings = ws_settings
132  # "config_list": List of configurations of a discretized jointspace grid. (Number of values for each joint is identified by property: "number_of_intervals")
133  # list length = (number_of_intervals ** DOF)
134  self.config_list = []
135  # "pose_list": A List of poses equivalent to "config_list". Each list element is a pose vector corresponding to its equivalent configuration in the "config_list"
136  self.pose_list = []
137  # "lower_pose" and "upper_pose" contain the lower and upper bounds of each element in the pose list
138  self.lower_pose = ()
139  self.upper_pose = ()
140 
141  # kd trees :
142  self.pose_tree = None
143 
144  # TODO (principally): distance function for rotational joints ?!
145  # ... for second use case ...
146  self.config_tree = None
147 
148  def create_random(self):
149  '''
150  Generate a number of random configs in the feasible range of the jointspace and computes the forward kinematic of each configuration.
151  The number of random points generated are determined by property: "self.ws_settings.number_of_configs"
152  The configurations are stored in property "self.config_list" and the corresponding poses are stored in property "self.pose_list"
153  A pose contains 3 elements for each position (reference_position) and 3 elements for each orientation (reference_orientation)
154 
155  A nun-redundant parametrization for orientation should be introduced by property "self.representation_of_orientation"
156  '''
157 
158  p = self.ws_settings.number_of_configs
159 
160  for i in range(0, p):
161  print 'Creating Workspace .... ' + str(i) + ' out of: ' + str (p)
162 
163  assert self.set_config(self.random_config())
164 
165  '''
166  for tp in self.task_point:
167  H = self.transfer_matrices()
168  ra = tp.position(H)
169  for j in range(0,3):
170  ef_pose += ra[j],
171  '''
172  ef_pose = self.pose_to_tuple('actual', self.ws_settings.representation_of_orientation)
173 
174  self.pose_list.append(ef_pose)
175  self.config_list.append(self.free_config(self.q))
176 
177  pose_set = set(self.pose_list)
178  config_tuple_list = [ tuple(c) for c in self.config_list ]
179  config_set = set(config_tuple_list)
180 
181  self.pose_tree = kdtree.KDTree.construct_from_data(list(pose_set))
182  self.config_tree = kdtree.KDTree.construct_from_data(list(config_set))
183 
184  def create_JSG(self):
185  '''
186  Generate a lattice in the jointspace and computes the forward kinematic of each configuration.
187  The feasible range of each jach joint is divided by "self.ws_settings.grid_resolution" + 1 intervals.
188  The configurations are sstored in property "self.config_list" and the corresponding poses are stored in property "self.pose_list"
189  A pose contains 3 elements for each position (reference_position) and 3 elements for each orientation (reference_orientation)
190 
191  A nun-redundant parametrization for orientation should be introduced by property "self.representation_of_orientation"
192 
193  '''
194 
195  p = self.ws_settings.grid_resolution ** self.config_settings.DOF
196  self.ws_settings.number_of_configs = p
197  '''
198  fwd_kin.take_to_grid_configuration(0, self.ws_settings.grid_resolution)
199  endeff.update(fwd_kin)
200 
201  for tp in endeff.reference_positions:
202  tp.ru = numpy.copy(tp.ra)
203  tp.rl = numpy.copy(tp.ra)
204  '''
205  for i in range(0, p):
206  print 'Creating Workspace .... ' + str(i) + ' out of: ' + str (p)
207 
208  assert self.set_config(self.grid_config(i, self.ws_settings.grid_resolution))
209  '''
210  for tp in self.task_point:
211  for j in range(0,3):
212  if (tp.ra[j] > tp.ru[j]):
213  tp.ru[j] = tp.ra[j]
214 
215  if (tp.ra[j] < tp.rl[j]):
216  tp.rl[j] = tp.ra[j]
217  '''
218  ef_pose = self.pose_to_tuple('actual', self.ws_settings.representation_of_orientation)
219 
220  self.pose_list.append(ef_pose)
221  self.config_list.append(self.free_config(self.q))
222  '''
223  self.lower_pose = ()
224  self.upper_pose = ()
225  for tp in endeff.reference_positions:
226  for j in range(0,3):
227  self.lower_pose += tp.rl[j],
228  self.upper_pose += tp.ru[j],
229  '''
230 
231  pose_set = set(self.pose_list)
232  config_tuple_list = [ tuple(c) for c in self.config_list ]
233  config_set = set(config_tuple_list)
234 
235  self.pose_tree = kdtree.KDTree.construct_from_data(list(pose_set))
236  self.config_tree = kdtree.KDTree.construct_from_data(list(config_set))
237 
238  self.file_name = self.ws_settings.gen_file_name(self.geo_settings.name)
239 
240  def create(self):
241  print "Workspace Creation Started. Creation Method: ",self.ws_settings.creation_method
242  if self.ws_settings.creation_method == 'JSG':
243  self.create_JSG()
244  elif self.ws_settings.creation_method == 'RND':
245  self.create_random()
246  elif self.ws_settings.creation_method == 'PCL':
247  if not self.ws_settings.predefined_config_list == None:
248  i = 0
249  p = len(self.ws_settings.predefined_config_list)
250  for q in self.ws_settings.predefined_config_list:
251  print 'Creating Workspace .... ' + str(i) + ' out of: ' + str (p)
252  qf = self.free_config(q)
253  assert self.set_config(qf)
254  self.config_list.append(qf)
255  ef_pose = self.pose_to_tuple('actual', self.ws_settings.representation_of_orientation)
256  self.pose_list.append(ef_pose)
257  self.ws_settings.number_of_configs = len(self.config_list)
258 
259  pose_set = set(self.pose_list)
260  config_tuple_list = [ tuple(c) for c in self.config_list ]
261  config_set = set(config_tuple_list)
262 
263  self.pose_tree = kdtree.KDTree.construct_from_data(list(pose_set))
264  self.config_tree = kdtree.KDTree.construct_from_data(list(config_set))
265  else:
266  assert False, genpy.err_str(__name__, self.__class__.__name__, 'create', 'predefined_config_list has not been set. Workspace can NOT be created !')
267  else:
268  assert False, genpy.err_str(__name__, self.__class__.__name__, 'create', self.ws_settings.creation_method+ ' is not a valid value for creation_method')
269 
270  def configs_nearest_to_pose(self, endeff):
271  '''
272  endeff contains the target pose
273 
274  Return a list of configurations which:
275  Their corresponding poses are closest to the target pose
276 
277  QUESTION : configs_nearest_to_target( EE, distance ? ) ??
278  '''
279  Ns = self.ws_settings.number_of_search_items
280  Nc = self.ws_settings.number_of_configs
281  assert Ns <= Nc
282 
283  #first find the 10 closest poses to target
284  target_pose = endeff.pose_to_tuple('desired', self.ws_settings.representation_of_orientation)
285  nearest_pose = self.pose_tree.query(query_point = target_pose, t = Ns)
286  nearest_config_list = []
287 
288  for pose in nearest_pose:
289  nearest_config_list.append(numpy.copy(self.config_list[self.pose_list.index(pose)]))
290 
291  return nearest_config_list
292 
293  def configs_nearest_to(self, current_q):
294 
295  '''
296  Return a list of configurations which:
297  Are closest to the starting configuration
298 
299  (second / online usecase : time coherence ... )
300  '''
301  if self.ws_settings.number_of_search_items == 0:
302  return []
303 
304  #first find the closest configurations to the current configuration
305  nearest_config_list = self.config_tree.query(query_point = current_q, t = self.ws_settings.number_of_search_items)
306 
307  return nearest_config_list
308 
309  def nearest_configs(self, ik):
310  if self.ws_settings.search_criteria == 'NTP': # (key: NTP) Initial Configuration: Nearest to Target Pose
311  nearest_config_list = self.configs_nearest_to_pose(ik)
312  elif self.ws_settings.search_criteria == 'NCC': # (key: NCC) Initial Configuration: Nearest to Current Configuration
313  nearest_config_list = self.configs_nearest_to(ik.free_config(ik.q))
314  elif self.ws_settings.search_criteria == 'CLO':
315  nearest_config_list = []
316  for i in range(self.ws_settings.number_of_search_items):
317  nearest_config_list.append(self.config_list[i])
318  else :
319  assert False, genpy.err_str(__name__, self.__class__.__name__, 'nearest_configs', self.ws_settings.search_criteria + ' is not a valid value for search_criteria')
320 
321  return nearest_config_list
322 
323  def write_to_file(self, path_and_file_name):
324  '''
325  Save the class in file specified by "self.file_name"
326  '''
327  FILE_DATA = open(path_and_file_name, "w")
328  pickle.dump(self, FILE_DATA)
329 
330 
331 
def read_from_file
Use this function to load the workspace from a file.
Definition: workspace.py:28
This class contains all the required settings of a workspace.
Definition: workspace.py:53