calibrate_pr2.py
Go to the documentation of this file.
1 #!/usr/bin/python
2 # Software License Agreement (BSD License)
3 #
4 # Copyright (c) 2008, Willow Garage, Inc.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 #
11 # * Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
13 # * Redistributions in binary form must reproduce the above
14 # copyright notice, this list of conditions and the following
15 # disclaimer in the documentation and/or other materials provided
16 # with the distribution.
17 # * Neither the name of the Willow Garage nor the names of its
18 # contributors may be used to endorse or promote products derived
19 # from this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 # POSSIBILITY OF SUCH DAMAGE.
33 #
34 
35 # Author: Wim Meeussen
36 # Calibrates the PR-2 in a safe sequence
37 
38 
39 import roslib
40 roslib.load_manifest('pr2_bringup')
41 import rospy
42 import getopt
43 import yaml
44 import sys
45 from std_msgs.msg import *
46 from pr2_mechanism_msgs.srv import LoadController, UnloadController, SwitchController, SwitchControllerRequest, ListControllers
47 from diagnostic_msgs.msg import DiagnosticArray, DiagnosticStatus, KeyValue
48 from pr2_controllers_msgs.srv import QueryCalibrationState
49 from std_msgs.msg import Bool
50 from std_srvs.srv import Empty
51 from sensor_msgs.msg import *
52 
53 
54 
55 calibration_params_namespace = "calibration_controllers"
56 load_controller = rospy.ServiceProxy('pr2_controller_manager/load_controller', LoadController)
57 unload_controller = rospy.ServiceProxy('pr2_controller_manager/unload_controller', UnloadController)
58 switch_controller = rospy.ServiceProxy('pr2_controller_manager/switch_controller', SwitchController)
59 list_controllers = rospy.ServiceProxy('pr2_controller_manager/list_controllers', ListControllers)
60 
61 hold_position = {'r_shoulder_pan': -0.7, 'l_shoulder_pan': 0.7, 'r_elbow_flex': -2.0,
62  'l_elbow_flex': -2.0, 'r_upper_arm_roll': 0.0, 'l_upper_arm_roll': 0.0,
63  'r_shoulder_lift': 1.0, 'l_shoulder_lift': 1.0}
64 
65 force_calibration = False
66 
67 def get_controller_name(joint_name):
68  return calibration_params_namespace+"/calibrate/cal_%s" % joint_name
69 
70 def set_force_calibration(joint_name):
71  rospy.set_param(calibration_params_namespace+"/calibrate/cal_%s/force_calibration" % joint_name, True)
72 
73 def get_holding_name(joint_name):
74  return "%s/hold/%s_position_controller" % (calibration_params_namespace, joint_name)
75 
76 def get_service_name(joint_name):
77  return '%s/is_calibrated'%get_controller_name(joint_name)
78 
79 global last_joint_states
80 last_joint_states = None
81 def joint_states_cb(msg):
82  global last_joint_states
83  last_joint_states = msg
84 rospy.Subscriber('joint_states', JointState, joint_states_cb)
85 
86 global motors_halted
87 motors_halted = None
88 def motor_state_cb(msg):
89  global motors_halted
90  motors_halted = msg.data
91  rospy.logdebug("motors halted = %d"%motors_halted)
92 rospy.Subscriber('pr2_ethercat/motors_halted', Bool, motor_state_cb)
93 
94 pub_diag = rospy.Publisher('/diagnostics', DiagnosticArray, queue_size=10)
95 def diagnostics(level, msg_short, msg_long):
96  if level == 0:
97  rospy.loginfo(msg_long)
98  elif level == 1:
99  rospy.logwarn(msg_long)
100  elif level == 2:
101  rospy.logerr(msg_long)
102  d = DiagnosticArray()
103  d.header.stamp = rospy.Time.now()
104  ds = DiagnosticStatus()
105  ds.level = level
106  ds.message = msg_long
107  ds.name = msg_short
108  d.status = [ds]
109  pub_diag.publish(d)
110 
111 
112 
114  def __init__(self, joint_name):
115  self.joint_name = joint_name
116  rospy.logdebug("Loading holding controller: %s" %get_holding_name(joint_name))
117  resp = load_controller(get_holding_name(joint_name))
118  if resp.ok:
119  rospy.logdebug("Starting holding controller for joint %s."%joint_name)
120  switch_controller([get_holding_name(joint_name)], [], SwitchControllerRequest.STRICT)
121  self.pub_cmd = rospy.Publisher("%s/command" %get_holding_name(joint_name), Float64, latch=True, queue_size=10)
122  else:
123  rospy.logerr("Failed to load holding controller for joint %s."%joint_name)
124  raise Exception('Failure to load holding controller')
125 
126  def __del__(self):
127  switch_controller([], [get_holding_name(self.joint_name)], SwitchControllerRequest.STRICT)
129  self.pub_cmd.unregister()
130 
131  def hold(self, position):
132  self.pub_cmd.publish(Float64(position))
133 
134 
135 
136 class StatusPub:
137  def __init__(self):
138  self.pub_status = rospy.Publisher('calibration_status', String, queue_size=10)
139  self.status = {}
140  self.status['active'] = []
141  self.status['done'] = []
142 
143  def publish(self, active=None):
144  if active:
145  self.status['active'] = active
146  else:
147  self.status['done'].extend(self.status['active'])
148  self.status['active'] = []
149 
150  str = "====\n"
151  str += "Calibrating: %s\n"%", ".join(self.status["active"])
152  str += "Calibrated: %s\n"%", ".join(self.status["done"])
153  self.pub_status.publish(str)
154 
155 
156 
158  def __init__(self, joints, status):
159  self.joints = []
161  self.services = {}
162  self.status = status
163 
164  # spawn calibration controllers for all joints
165  for j in joints:
166  rospy.logdebug("Loading controller: %s" %get_controller_name(j))
167  global force_calibration
168  if force_calibration:
171  if resp.ok:
172  # get service call to calibration controller to check calibration state
173  rospy.logdebug("Waiting for service: %s" %get_service_name(j))
174  rospy.wait_for_service(get_service_name(j))
175  self.services[j] = rospy.ServiceProxy(get_service_name(j), QueryCalibrationState)
176  self.joints.append(j)
177  else:
178  rospy.logerr("Failed to load calibration for joint %s. Skipping this joint"%j)
179 
180 
181  def __del__(self):
182  # stop controllers that were started
183  switch_controller([], [get_controller_name(j) for j in self.joints], SwitchControllerRequest.BEST_EFFORT)
184 
185  # kill controllers that were loaded
186  for j in self.joints:
188 
189  def is_calibrated(self):
190  # check if joints are calibrated
191  for j in self.joints:
192  if self.services[j]().is_calibrated:
193  rospy.logdebug("joint %s is already calibrated"%j)
194  else:
195  rospy.logdebug("joint %s needs to be calibrated"%j)
196  return False
197  return True
198 
199 
200  def calibrate(self):
201  # start all calibration controllers
202  rospy.logdebug("Start calibrating joints %s"%self.joints)
203  switch_controller([get_controller_name(j) for j in self.joints], [], SwitchControllerRequest.STRICT)
204 
205  # wait for joints to calibrate
206  self.status.publish(self.joints)
207  start_time = rospy.Time.now()
208  while not self.is_calibrated():
209  if motors_halted and motors_halted == 1:
210  diagnostics(2, 'Calibration on hold', 'Calibration is on hold because motors are halted. Enable the run-stop')
211  start_time = rospy.Time.now()
212  rospy.sleep(1.0)
213  elif rospy.Time.now() > start_time + rospy.Duration(30.0): # time for spine to go up is 29 seconds
214  diagnostics(2, 'Calibration stuck', 'Joint %s is taking a long time to calibrate. It might be stuck and need some human help'%self.joints)
215  rospy.sleep(1.0)
216  rospy.sleep(0.1)
217 
218  rospy.logdebug("Stop calibration controllers for joints %s"%self.joints)
219  switch_controller([], [get_controller_name(j) for j in self.joints], SwitchControllerRequest.BEST_EFFORT)
220 
221  # hold joints in place
222  rospy.logdebug("Loading holding controllers for joints %s"%self.joints)
223  self.hold_controllers = []
224  for j in self.joints:
225  if j in hold_position:
226  holder = HoldingController(j)
227  holder.hold(hold_position[j])
228  self.hold_controllers.append(holder)
229  self.status.publish()
230 
231 
232 
234  def __init__(self, sequence, status):
235  self.status = status
236 
237  # create CalibrateParallel for all groups in sequence
238  self.groups = []
239  for s in sequence:
240  self.groups.append(CalibrateParallel(s, status))
241 
242 
243  def is_calibrated(self):
244  # check if all groups in sequence are calibrated
245  for g in self.groups:
246  if not g.is_calibrated():
247  return False
248  return True
249 
250 
251  def calibrate(self):
252  # Check if this sequence needs calibration
253  if self.is_calibrated():
254  return True
255 
256  # calibrate all groups in sequence
257  for g in self.groups:
258  g.calibrate()
259 
260 
261 
262 
263 
264 
265 def main():
266  try:
267  rospy.init_node('calibration', anonymous=True, disable_signals=True)
268  calibration_start_time = rospy.Time.now()
269 
270  rospy.wait_for_service('pr2_controller_manager/load_controller')
271  rospy.wait_for_service('pr2_controller_manager/switch_controller')
272  rospy.wait_for_service('pr2_controller_manager/unload_controller')
273 
274 
275  # parse options
276  allowed_flags = ['alpha-casters', 'alpha-head', 'alpha2b-head', 'arms=', 'force_calibration', 'recalibrate']
277  opts, args = getopt.gnu_getopt(rospy.myargv(), 'h', allowed_flags)
278  caster_list = ['caster_fl', 'caster_fr', 'caster_bl', 'caster_br']
279  head_list = ['head_pan', 'head_tilt']
280  arms = 'auto'
281  recalibrate = False
282  global force_calibration
283  for o, a in opts:
284  if o == '-h':
285  rospy.loginfo("Flags:", ' '.join(['--'+f for f in allowed_flags]))
286  sys.exit(0)
287  elif o == '--alpha-casters':
288  caster_list = ['caster_fl_alpha2', 'caster_fr_alpha2', 'caster_bl_alpha2', 'caster_br_alpha2']
289  elif o == '--alpha-head':
290  head_list = ['head_pan_alpha2', 'head_tilt']
291  elif o == '--alpha2b-head':
292  head_list = ['head_pan_alpha2', 'head_tilt_alpha2b']
293  elif o == '--arms':
294  arms = a
295  elif o == '--force_calibration':
296  force_calibration = True
297  elif o == '--recalibrate':
298  recalibrate = True
299  force_calibration = True
300 
301  if arms not in ['both', 'none', 'left', 'right', 'auto']:
302  print('Arms must be "both", "none", "left", "right", or "auto"')
303  sys.exit(1)
304 
305  # load controller configuration
306  rospy.loginfo("Loading controller configuration on parameter server...")
307  pr2_controller_configuration_dir = roslib.packages.get_pkg_dir('pr2_controller_configuration')
308  calibration_yaml = '%s/pr2_calibration_controllers.yaml' % pr2_controller_configuration_dir
309  hold_yaml = '%s/pr2_joint_position_controllers.yaml' % pr2_controller_configuration_dir
310  if len(args) < 3:
311  rospy.loginfo("No yaml files specified for calibration and holding controllers, using defaults")
312  else:
313  calibration_yaml = args[1]
314  hold_yaml = args[2]
315  rospy.set_param(calibration_params_namespace+"/calibrate", yaml.load(open(calibration_yaml)))
316  rospy.set_param(calibration_params_namespace+"/hold", yaml.load(open(hold_yaml)))
317 
318  # status publishing
319  imustatus = True
320  joints_status = False
321  if not recalibrate:
322  pub_calibrated = rospy.Publisher('calibrated', Bool, latch=True, queue_size=10)
323  pub_calibrated.publish(False)
324  status = StatusPub()
325 
326  # Auto arm selection, determined based on which joints exist.
327  if arms == 'auto':
328  started_waiting = rospy.get_rostime()
329  global last_joint_states
330  while rospy.get_rostime() <= started_waiting + rospy.Duration(50.0):
331  if last_joint_states:
332  break
333  js = last_joint_states
334  if not js:
335  rospy.logwarn('Could not do auto arm selection because no joint state was received')
336  arms = 'both'
337  else:
338  if 'r_shoulder_pan_joint' in js.name and 'l_shoulder_pan_joint' in js.name:
339  arms = 'both'
340  elif 'r_shoulder_pan_joint' in js.name:
341  arms = 'right'
342  elif 'l_shoulder_pan_joint' in js.name:
343  arms = 'left'
344  else:
345  arms = 'none'
346  rospy.loginfo("Arm selection was set to \"auto\". Chose to calibrate using \"%s\"" % arms)
347 
348  # define calibration sequence objects
349  torso = CalibrateSequence([['torso_lift']], status)
350  gripper_list = []
351  arm_list = []
352  if arms == 'both':
353  arm_list = [['r_shoulder_pan', 'l_shoulder_pan'], ['r_elbow_flex', 'l_elbow_flex'],
354  ['r_upper_arm_roll', 'l_upper_arm_roll'], ['r_shoulder_lift', 'l_shoulder_lift'],
355  ['r_forearm_roll', 'r_wrist', 'l_forearm_roll', 'l_wrist']]
356  gripper_list = ['r_gripper', 'l_gripper']
357  if arms == 'left':
358  arm_list = [['l_shoulder_pan'], ['l_elbow_flex'], ['l_upper_arm_roll'], ['l_shoulder_lift'], ['l_forearm_roll', 'l_wrist']]
359  gripper_list = ['l_gripper']
360  if arms == 'right':
361  arm_list = [['r_shoulder_pan'], ['r_elbow_flex'], ['r_upper_arm_roll'], ['r_shoulder_lift'], ['r_forearm_roll', 'r_wrist']]
362  gripper_list = ['r_gripper']
363  arm = CalibrateSequence(arm_list, status)
364  gripper = CalibrateSequence([gripper_list], status)
365  head = CalibrateSequence([head_list, ['laser_tilt']], status)
366  caster = CalibrateSequence([caster_list], status)
367 
368  # if recalibrating, stop all running controllers first
369  if recalibrate:
370  controller_list = list_controllers()
371  def is_running(c) : return c[1]=='running'
372  running_controllers = [c[0] for c in filter(is_running, zip(controller_list.controllers, controller_list.state))]
373  print("Running controllers : ", running_controllers)
374  if not switch_controller([], running_controllers, SwitchControllerRequest.STRICT):
375  print("Failed to stop controllers")
376  sys.exit(1)
377 
378  # calibrate imu and torso
379  if not torso.is_calibrated():
380  rospy.loginfo('Calibrating imu')
381  status.publish(['imu'])
382  imu_calibrate_srv_name = 'torso_lift_imu/calibrate'
383  rospy.wait_for_service(imu_calibrate_srv_name)
384  imu_calibrate_srv = rospy.ServiceProxy(imu_calibrate_srv_name, Empty)
385  try:
386  imu_calibrate_srv()
387  status.publish()
388  # only calibrate torso when imu calibration succeeds
389  except:
390  imustatus = False
391  rospy.loginfo('Calibrating imu finished')
392  else:
393  rospy.loginfo('Not calibrating imu')
394 
395  # calibrate torso
396  torso.calibrate()
397 
398  # calibrate arms
399  torso_holder = None
400  if not arm.is_calibrated():
401  torso_holder = HoldingController('torso_lift')
402  torso_holder.hold(0.25)
403  rospy.sleep(5.0)
404  rospy.loginfo('Moving up spine to allow arms to calibrate')
405  arm.calibrate()
406  rospy.loginfo('Moving down spine after arm calibration')
407  torso_holder.hold(0.01)
408  rospy.sleep(20.0)
409 
410  # calibrate rest of robot
411  gripper.calibrate()
412  head.calibrate()
413  caster.calibrate()
414 
415  joints_status = True
416  status.publish()
417 
418  except Exception as e:
419  rospy.logerr("Calibration failed: %s" % str(e))
420 
421  finally:
422  rospy.loginfo("Bringing down calibration node")
423 
424  rospy.set_param(calibration_params_namespace, "")
425  del arm
426  del gripper
427  del torso
428  del torso_holder
429  del caster
430  del head
431 
432  if not imustatus and not joints_status:
433  rospy.logerr("Both mechanism and IMU calibration failed")
434  elif not joints_status:
435  rospy.logerr("IMU calibration complete, but mechanism calibration failed")
436  elif not imustatus:
437  rospy.logerr("Mechanism calibration complete, but IMU calibration failed.")
438  else:
439  rospy.loginfo('Calibration completed in %f sec' %(rospy.Time.now() - calibration_start_time).to_sec())
440 
441  if recalibrate:
442  if not switch_controller(running_controllers, [], SwitchControllerRequest.STRICT):
443  print("Could not start previously running controllers")
444 
445  if not recalibrate:
446  if joints_status:
447  pub_calibrated.publish(True)
448  rospy.spin()
449 
450 
451 if __name__ == '__main__': main()
def __init__(self, joint_name)
def set_force_calibration(joint_name)
def motor_state_cb(msg)
def __init__(self, joints, status)
def get_controller_name(joint_name)
def get_holding_name(joint_name)
def publish(self, active=None)
def __init__(self, sequence, status)
def joint_states_cb(msg)
def get_service_name(joint_name)
def diagnostics(level, msg_short, msg_long)


pr2_bringup
Author(s): Wim Meeussen
autogenerated on Tue Jun 1 2021 02:50:59