dynamic_tuner.py
Go to the documentation of this file.
1 # from optimizer import optimizer
2 import sys
3 import numpy as np
4 from scipy import interpolate
5 import rospy
6 import dynamic_reconfigure.client
7 import rosbag
8 
9 from numbers import Number
10 import math
11 
12 from std_msgs.msg import String
13 
14 
15 import subprocess
16 import threading
17 
18 import re
19 import yaml
20 
21 from timeout import timeout
22 from optimizer import optimizer
23 
24 import os
25 
26 
27 SIM_PREFIX = ""
28 REAL_PREFIX = "/GROUND_TRUTH"
29 
30 
31 
32 
33 
34 def value_of(topic, msg, value):
35  if(not value.startswith(topic)):
36  return None
37 
38  tl = len(topic)
39 
40  attrs = value[tl:]
41  attrs = re.split("/|\[|\]", attrs)
42 
43  res = msg
44 
45  for attr in attrs:
46  if attr == "":
47  continue
48 
49  if "__iter__" in dir(res):
50  index = int(attr)
51  if index >= len(res):
52  return None
53  res = res[index]
54 
55  else:
56  if not hasattr(res, attr):
57  return None
58  res = getattr(res, attr)
59 
60  return res
61 
62 def combine(bag_a, bag_b, output_bag_file = 'combined.bag'):
63  print "[combining bags]"
64 
65  bag_c = rosbag.Bag(output_bag_file, 'w')
66 
67  for topic, msg, t in bag_a.read_messages():
68  bag_c.write(topic, msg, t)
69 
70  for topic, msg, t in bag_b.read_messages():
71  bag_c.write(topic, msg, t)
72 
73  bag_c.close()
74 
75  bag_c = rosbag.Bag(output_bag_file, 'r')
76 
77  return bag_c
78 
79 
80 def restamp(bag, output_bag_file = 'restamped.bag', values = [], prefix = "", start_signal = {}, end_signal = {}):
81  print "[restamping {0}]".format(prefix)
82  print values
83 
84  state = -1
85  if not start_signal:
86  state = 0
87 
88 
89  output = rosbag.Bag(output_bag_file, 'w')
90 
91 
92  zero = rospy.Duration(0.)
93 
94 
95  def check_signal(topic, msg, signal):
96 
97  for key, val in signal.items():
98  new_val = value_of(topic, msg, key)
99  if (val!=None and val == new_val) or (val == None and new_val != None):
100  # print("happened with", topic, msg, signal)
101  return True
102  # print("didnt happen with", topic, msg, signal)
103  return False
104 
105 
106  try:
107  for topic, msg, t in bag.read_messages():
108  # print(zero)
109 
110  if not any([ value.find(topic)>-1 for value in values]):
111  continue
112 
113  if(zero == rospy.Duration(0.)):
114  zero = t - rospy.Duration(0.1) # correct the delay
115  if state == -1:
116  if check_signal(topic, msg, start_signal):
117  zero = t - rospy.Duration(0.1) # correct the delay
118  state = 0
119  pass # START TO RESTAMP
120 
121  if state == 0:
122 
123  ### RESTAMPING
124  # print("#####", topic, msg, (t-zero).to_sec())
125  new_topic = "".join([prefix, topic])
126  # output.write(new_topic, msg, t-zero)
127  output.write(new_topic, msg, t-zero)
128 
129  if check_signal(topic, msg, end_signal):
130  state = 1
131  pass # STOP RESTAMP
132 
133  if state == 1:
134  break
135  finally:
136  output.close()
137 
138  output = rosbag.Bag(output_bag_file, 'r')
139 
140  return output
141 
142 
143 def read_value_vector(bag, value):
144  topics = bag.get_type_and_topic_info()[1].keys()
145  for topic in topics:
146  if value.startswith(topic):
147  data = []
148  stamps = []
149  for _, msg, t in bag.read_messages([topic]):
150  val = value_of(topic, msg, value)
151  data.append(val)
152  # stamps.append(msg.header.stamp.to_sec() if msg._has_header else t.to_sec())
153  stamps.append(t.to_sec())
154 
155  data = np.array(data)
156  stamps = np.array(stamps)
157  return data, stamps
158  return np.array([]), np.array([])
159 
160 
161 def interpobj(t, y):
162 
163  # TODO: handle the cases where its far from any point
164  # TODO: make it faster with binary search, dict or sth
165 
166  t = np.append([float("-inf")], t)
167  # y = np.append([None], y)
168 
169 
170  # TODO: rememeber to double check the correctness of delegate function
171  def f(t_new, t = t, y = y):
172 
173  if '__iter__' not in dir(t_new):
174  return y[max(i for i in range(len(t)) if t[i] <= t_new)]
175 
176  y_new = []
177  for tt in t_new:
178  index = max(i for i in range(len(t)) if t[i] <= tt)
179  if index == 0:
180  yy = None
181  else:
182  yy = y[index-1]
183  y_new.append(yy)
184 
185  y_new = np.array(y_new)
186  return y_new
187 
188  return f
189 
190 
191 def play_bag(bag_file, src, dst):
192  # play the messages from the topic <src> of the bag on the topic <dst>
193  # cmd = "rosbag play -d 2 --topics {0} --bags={1} {2}:={3}".format(src, bag_file, src, dst)
194 
195  cmd = ["rosbag", "play", "-d 2", "-r 0.8",
196  "--topics", src,
197  "--bags=", bag_file,
198  "{0}:={1}".format(src, dst)
199  ]
200 
201  FNULL = open(os.devnull, 'w')
202  return subprocess.Popen(cmd, stdout=FNULL, stderr=subprocess.STDOUT)
203 
204 def record_bag(output_bag, topics = [], duration = 10):
205  topics = " ".join(topics)
206  if topics == "":
207  topics = "--all"
208 
209  FNULL = open(os.devnull, 'w')
210  return subprocess.Popen(["rosbag", "record", topics,
211  "--duration={0}".format(duration),
212  "--output-name={0}".format(output_bag) ],
213  stdout=FNULL, stderr=subprocess.STDOUT)
214 
215 
216 def get_bag_info(bag):
217  if isinstance(bag, str):
218  bag = rosbag.Bag(bag, 'r')
219  return yaml.load(bag._get_yaml_info())
220 
221 def start_simulation(real_bag_file, sim_bag_file, src_topic, dst_topic, values = [] , start_signal={}, end_signal={}):
222  real_bag = rosbag.Bag(real_bag_file, 'r')
223  info = get_bag_info(real_bag)
224 
225  # @timeout(info["duration"] + 3 + 5)
226  # @timeout(3)
227 
228  duration = info["duration"] + 3
229  _timeout = int(duration + 2 + 120)
230 
231  print "DURATION is %d" % duration
232 
233  rec_proc = record_bag(sim_bag_file, duration = duration)
234  play_proc = play_bag(real_bag_file, src_topic, dst_topic)
235 
236  try:
237  @timeout(_timeout)
238  def wait():
239  is_playing = True
240  is_recording = True
241 
242  while is_playing or is_recording:
243  if rec_proc.poll() is not None and is_recording:
244  is_recording = False
245  print("[finished recording]")
246  # play_proc.wait()
247  if play_proc.poll() is not None and is_playing:
248  is_playing = False
249  print("[finished playing]")
250  # rec_proc.wait()
251  wait()
252  except:
253  e = sys.exc_info()[0]
254 
255  print("Something went wrong. Error: %s" % e)
256  print("Killing the play/record processes")
257 
258  if rec_proc.poll() is None:
259  rec_proc.kill()
260  if play_proc.poll() is None:
261  play_proc.kill()
262 
263  rec_proc.wait()
264  play_proc.wait()
265 
266  raise e
267 
268  finally:
269  if rec_proc.poll() is None:
270  rec_proc.kill()
271  if play_proc.poll() is None:
272  play_proc.kill()
273 
274  print("[finished simulation]")
275 
276 
277  sim_bag = rosbag.Bag(sim_bag_file, 'r')
278 
279  sim_bag = restamp(sim_bag, output_bag_file = 'sim-restamped.bag' , values = values, prefix = SIM_PREFIX, start_signal = start_signal, end_signal = end_signal)
280  real_bag = restamp(real_bag, output_bag_file = 'real-restamped.bag', values = values, prefix = REAL_PREFIX, start_signal = start_signal, end_signal = end_signal)
281 
282  combined_bag = combine(sim_bag, real_bag)
283 
284  return combined_bag
285 
286 
287 def resample(bag, value_list, resolution = 0.1):
288  datamap = {}
289 
290  # t_min = float("-inf")
291  # t_max = float("inf")
292 
293  t_min = float("inf")
294  t_max = float("-inf")
295 
296  for value in value_list:
297  print value, t_min, t_max
298 
299  _, t = read_value_vector(bag, value)
300 
301 
302 
303  print "\n\n\n"
304  print value
305  print t
306  print "\n\n\n"
307 
308  # t_min = max(t_min, min(t))
309  # t_max = min(t_max, max(t))
310 
311  t_min = min(t_min, min(t))
312  t_max = max(t_max, max(t))
313 
314 
315  print("###")
316  print t_min, t_max
317 
318  # rospy.sleep(5)
319 
320  for value in value_list:
321  y, t = read_value_vector(bag, value)
322 
323  print "reading {0}".format(value)
324  # print (y, t)
325 
326  dt = y.dtype
327 
328  if len(t)>1 and (dt == int or dt == float): # TODO: double check the correctness of type checking
329  f = interpolate.interp1d(t, y, axis = 0, fill_value = "extrapolate")
330  else:
331  f = interpobj(t,y)
332 
333 
334 
335  """
336  create a new time array
337  project the new samples
338  type cast back
339  """
340  t_new = np.arange(t_min, t_max, resolution)
341 
342  ndata = f(t_new)
343 
344  # print(t_new, ndata)
345 
346  ndata = ndata.astype(dt)
347 
348  datamap[value] = ndata
349 
350  return datamap
351 
352 
353 
354 # def plot_dual(config):
355 # if '/simulation/joint_states/position[2]' in config and '/simulation/joint_states/position[2]' in config:
356 # tmp = config['/simulation/joint_states/position[2]']
357 # config['/simulation/joint_states/position[2]'] = config['/simulation/joint_states/position[0]']
358 # config['/simulation/joint_states/position[0]'] = tmp
359 
360 # plt.clf()
361 
362 # config_sim = { key:val for key, val in config.items() if key.startswith("/simulation") }
363 # config_real = { key:val for key, val in config.items() if key.startswith("/real") }
364 # plot(config_sim)
365 # plot(config_real)
366 # plt.draw()
367 # plt.show()
368 
369 
370 # def plot(config, style = '-'):
371 
372 # plt.ion()
373 
374 # index = 1
375 # size = len(config.items())
376 
377 # keys = config.keys()
378 # if '/simulation/joint_states/position' in keys:
379 # keys.remove('/simulation/joint_states/position')
380 
381 # if '/real/joint_states/position' in keys:
382 # keys.remove('/real/joint_states/position')
383 # keys.sort()
384 
385 
386 # for key in keys:
387 
388 # val = config[key]
389 
390 # plt.subplot(math.ceil(size/2.), 2, index)
391 
392 # plt.plot(val, ls = style)#, hold=True)
393 # plt.ylabel(key)
394 # plt.xlabel('time')
395 
396 # index+=1
397 
398 # plt.pause(0.05)
399 
400 
402 
403 
404  _param_set = []
405  _value_set = []
406 
407  _real_bag_file = ''
408  _sim_bag_file = ''
409 
410  _src_topic = ''
411  _dst_topic = ''
412 
413  _start_signal = {}
414  _end_signal = {}
415 
416  _resolution = 0.1
417 
418  _objective = None
419 
420  _params_desc = {}
421 
422  _optimizer = None
423 
424 
425  # rospy.init_node('dyn_tuner')
426 
427  def __init__( self,
428  param_set,
429  value_set,
430  real_bag_file,
431  sim_bag_file,
432  src_topic,
433  dst_topic,
434  start_signal = {},
435  end_signal = {},
436  resolution = 0.1,
437  objective = None ):
438 
439  # set the default objective function using given value_list
440  # connect to param_list on the ddynamice reconfigure server
441  # connect the value collector to the value_list
442  # configure optimizer
443 
444  self._param_set = param_set
445  self._value_set = value_set
446 
447  self._real_bag_file = real_bag_file
448  self._sim_bag_file = sim_bag_file
449 
450  self._src_topic = src_topic
451  self._dst_topic = dst_topic
452 
453  self._start_signal = start_signal
454  self._end_signal = end_signal
455 
456  self._resolution = resolution
457 
458  self._objective = objective
459 
460  if type(self._param_set) == list:
462  else:
463  self._params_desc = self._param_set
464  self._optimizer = optimizer(self._params_desc, self._evaluate)
465 
466  if type(self._param_set) == list:
467  self._optimizer.set_params_config(self.read_default_config())
468 
469 
470 
471  pass
472 
473 
474  def tune_params(self, config = {}):
475  # call the optimizer
476  # if config:
477  # self._optimizer.set_params_config(config)
478  self._optimizer.optimize()
479  pass
480 
481 
482  def update_params(self, param_list):
483  # read through param_list to find configuration of the parameters
484  # set the parameters configuration on the optimizer
485 
486  nparams = {}
487 
488  for param, value in param_list.items():
489  if(param[-1] == '/'):
490  param = param[:-1]
491  index = param.rfind('/')
492  node_name = param[:index]
493  param_name = param[index+1:]
494 
495  if node_name not in nparams:
496  nparams[node_name] = {}
497 
498  nparams[node_name].update({param_name:value})
499 
500  # print nparams
501 
502  for node, config in nparams.items():
503  # print(node, config)
504 
505  service_name = node + "/set_parameters"
506  # print(service_name)
507 
508  # rospy.wait_for_service(service_name)
509 
510  client = dynamic_reconfigure.client.Client(node, timeout=30)#, config_callback=callback)
511  client.update_configuration(config)
512  # rospy.sleep(1.)
513 
514  pass
515 
517  config = {}
518  for param in self._param_set:
519  config[param] = rospy.get_param(param)
520  return config
521 
522 
523  def get_params_desc(self, param_list):
524 
525  nparams = {}
526  print param_list
527 
528  for param in param_list:
529  if(param[-1] == '/'):
530  param = param[:-1]
531  index = param.rfind('/')
532  node_name = param[:index]
533  param_name = param[index+1:]
534 
535  if node_name not in nparams:
536  nparams[node_name] = {}
537 
538  nparams[node_name].update({param_name:param})
539 
540  desc = {}
541 
542  for node, config in nparams.items():
543  # print(node, config)
544 
545  service_name = node + "/set_parameters"
546 
547  # print(service_name)
548 
549  # rospy.wait_for_service(service_name)
550  client = dynamic_reconfigure.client.Client(node, timeout=30)#, config_callback=callback)
551  desc_list = client.get_parameter_descriptions()
552 
553  for desc_item in desc_list:
554  param_name = desc_item['name']
555  if param_name in config:
556  desc.update({config[param_name]:desc_item})
557 
558  return desc
559 
560 
561  def _evaluate(self, config):
562  # return the evaluation value for given parameters
563  #
564  # update parameters
565  # run simulation
566  # record the bag
567  # compare with ground truth
568  # read the value_list
569  # return the evaluation
570 
571 
572 #############################################################
573 
574  self.update_params(config)
575  print "[parameters are updated]"
576 
578  self._sim_bag_file,
579  self._src_topic,
580  self._dst_topic,
581  values = self._value_set,
582  start_signal = self._start_signal,
583  end_signal = self._end_signal )
584 
585 
586  print "[resampling]"
587  value_map = resample(bag, self._value_set, resolution = self._resolution)
588  # print "\n\n\n"
589  # print value_map
590  # print "\n\n\n"
591 
592 
593  # value_map = config
594  # plot_dual(value_map)
595 
596  print "[calling objective function]"
597  res = self._objective(value_map)
598  print "[returning: {0}]".format(res)
599 
600  return res
601 
602 
603 
604 
605 
606 
607 
608 
609 
610 
611 
612 
613 
def get_params_desc(self, param_list)
def play_bag(bag_file, src, dst)
def resample(bag, value_list, resolution=0.1)
def start_simulation(real_bag_file, sim_bag_file, src_topic, dst_topic, values=[], start_signal={}, end_signal={})
def combine(bag_a, bag_b, output_bag_file='combined.bag')
def value_of(topic, msg, value)
def record_bag(output_bag, topics=[], duration=10)
def f(config, axis=0)
Definition: contact_run.py:81
def __init__(self, param_set, value_set, real_bag_file, sim_bag_file, src_topic, dst_topic, start_signal={}, end_signal={}, resolution=0.1, objective=None)
def read_value_vector(bag, value)
def timeout(seconds=10, error_message=os.strerror(errno.ETIME))
Definition: timeout.py:9
def restamp(bag, output_bag_file='restamped.bag', values=[], prefix="", start_signal={}, end_signal={})
def update_params(self, param_list)


dyn_tune
Author(s):
autogenerated on Mon Jun 10 2019 13:03:17