box_stacking_example.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 # coding: utf-8
3 
4 import rospy
5 import math
6 import sys
7 
8 from visualization_msgs.msg import Marker, MarkerArray
9 from geometry_msgs.msg import Pose
10 
11 # for NeckYawPitch
12 import actionlib
13 from control_msgs.msg import (
14  FollowJointTrajectoryAction,
15  FollowJointTrajectoryGoal,
16  JointTrajectoryControllerState
17 )
18 from trajectory_msgs.msg import JointTrajectoryPoint
19 
20 # for Stacker
21 import moveit_commander
22 import actionlib
23 from tf.transformations import quaternion_from_euler
24 from control_msgs.msg import GripperCommandAction, GripperCommandGoal
25 
26 
27 class NeckYawPitch(object):
28  def __init__(self):
29  self._client = actionlib.SimpleActionClient("/sciurus17/controller3/neck_controller/follow_joint_trajectory",
30  FollowJointTrajectoryAction)
31  self._client.wait_for_server(rospy.Duration(5.0))
32  if not self._client.wait_for_server(rospy.Duration(5.0)):
33  rospy.logerr("Action Server Not Found")
34  rospy.signal_shutdown("Action Server not found")
35  sys.exit(1)
36 
37 
38  def set_angle(self, yaw_angle, pitch_angle, goal_secs=1.0e-9):
39  # 首を指定角度に動かす
40  goal = FollowJointTrajectoryGoal()
41  goal.trajectory.joint_names = ["neck_yaw_joint", "neck_pitch_joint"]
42 
43  yawpoint = JointTrajectoryPoint()
44  yawpoint.positions.append(yaw_angle)
45  yawpoint.positions.append(pitch_angle)
46  yawpoint.time_from_start = rospy.Duration(goal_secs)
47  goal.trajectory.points.append(yawpoint)
48 
49  self._client.send_goal(goal)
50  self._client.wait_for_result(rospy.Duration(0.1))
51  return self._client.get_result()
52 
53 
54 class Stacker(object):
55  _RIGHT_ARM = 1
56  _LEFT_ARM = 2
57  # グリッパの開閉度
58  _GRIPPER_OPEN = 0.8
59  _GRIPPER_CLOSE = 0.42
60 
61  def __init__(self):
62  self._markers = MarkerArray()
63 
64  self._marker_sub = rospy.Subscriber("/sciurus17/example/markers",
65  MarkerArray, self._markers_callback, queue_size=1)
66 
67  self._right_arm = moveit_commander.MoveGroupCommander("r_arm_waist_group")
68  self._right_arm.set_max_velocity_scaling_factor(0.1)
69  self._right_gripper = actionlib.SimpleActionClient("/sciurus17/controller1/right_hand_controller/gripper_cmd", GripperCommandAction)
70  self._right_gripper.wait_for_server()
71 
72  self._left_arm = moveit_commander.MoveGroupCommander("l_arm_waist_group")
73  self._left_arm.set_max_velocity_scaling_factor(0.1)
74  self._left_gripper = actionlib.SimpleActionClient("/sciurus17/controller2/left_hand_controller/gripper_cmd", GripperCommandAction)
75  self._left_gripper.wait_for_server()
76 
77  self._gripper_goal = GripperCommandGoal()
78  self._gripper_goal.command.max_effort = 2.0
79 
80  # アームとグリッパー姿勢の初期化
81  self.initialize_arms()
82 
83  self._current_arm = None
84 
85 
86  def _markers_callback(self, msg):
87  self._markers = msg
88 
89  def get_num_of_markers(self):
90  return len(self._markers.markers)
91 
93  # 一番高さが低いオブジェクトのPoseを返す
94 
95  lowest_z = 1000
96  lowest_pose = Pose()
97 
98  for marker in self._markers.markers:
99  if marker.pose.position.z < lowest_z:
100  # marker.pose.position は箱の中心座標を表す
101  lowest_pose = marker.pose
102  lowest_z = marker.pose.position.z
103  lowest_pose.position.z += marker.scale.z * 0.5 # 箱の大きさ分高さを加算する
104 
105  return lowest_pose
106 
108  # 一番高さが高いオブジェクトのPoseを返す
109 
110  highest_z = 0
111  highest_pose = Pose()
112 
113  for marker in self._markers.markers:
114  if marker.pose.position.z > highest_z:
115  # marker.pose.position は箱の中心座標を表す
116  highest_pose = marker.pose
117  highest_z = marker.pose.position.z
118  highest_pose.position.z += marker.scale.z * 0.5 # 箱の大きさ分高さを加算する
119 
120  return highest_pose
121 
122 
123  def _move_arm(self, current_arm, target_pose):
124  if current_arm == self._RIGHT_ARM:
125  # 手先を下に向ける
126  q = quaternion_from_euler(3.14/2.0, 0.0, 0.0)
127  target_pose.orientation.x = q[0]
128  target_pose.orientation.y = q[1]
129  target_pose.orientation.z = q[2]
130  target_pose.orientation.w = q[3]
131  self._right_arm.set_pose_target(target_pose)
132  return self._right_arm.go()
133  elif current_arm == self._LEFT_ARM:
134  # 手先を下に向ける
135  q = quaternion_from_euler(-3.14/2.0, 0.0, 0.0)
136  target_pose.orientation.x = q[0]
137  target_pose.orientation.y = q[1]
138  target_pose.orientation.z = q[2]
139  target_pose.orientation.w = q[3]
140  self._left_arm.set_pose_target(target_pose)
141  return self._left_arm.go()
142  else:
143  return False
144 
145 
146  def _move_arm_to_init_pose(self, current_arm):
147  if current_arm == self._RIGHT_ARM:
148  self._right_arm.set_named_target("r_arm_waist_init_pose")
149  return self._right_arm.go()
150  elif current_arm == self._LEFT_ARM:
151  self._left_arm.set_named_target("l_arm_waist_init_pose")
152  return self._left_arm.go()
153  else:
154  return False
155 
156 
157  def _open_gripper(self, current_arm):
158  if current_arm == self._RIGHT_ARM:
159  self._gripper_goal.command.position = self._GRIPPER_OPEN
160  self._right_gripper.send_goal(self._gripper_goal)
161  return self._right_gripper.wait_for_result(rospy.Duration(1.0))
162  elif current_arm == self._LEFT_ARM:
163  self._gripper_goal.command.position = -self._GRIPPER_OPEN
164  self._left_gripper.send_goal(self._gripper_goal)
165  return self._left_gripper.wait_for_result(rospy.Duration(1.0))
166  else:
167  return False
168 
169 
170  def _close_gripper(self, current_arm):
171  if current_arm == self._RIGHT_ARM:
172  self._gripper_goal.command.position = self._GRIPPER_CLOSE
173  self._right_gripper.send_goal(self._gripper_goal)
174  elif current_arm == self._LEFT_ARM:
175  self._gripper_goal.command.position = -self._GRIPPER_CLOSE
176  self._left_gripper.send_goal(self._gripper_goal)
177  else:
178  return False
179 
180 
181  def initialize_arms(self):
184  self._open_gripper(self._RIGHT_ARM)
185  self._open_gripper(self._LEFT_ARM)
186 
187 
188  def pick_up(self, check_result):
189  # 一番高さが低いオブジェクトを持ち上げる
190  rospy.loginfo("PICK UP")
191  result = True
192  self._current_arm = None # 制御対象を初期化
193 
194  # オブジェクトがなければ終了
195  rospy.sleep(1.0)
196  if self.get_num_of_markers() == 0:
197  rospy.logwarn("NO OBJECTS")
198  return False
199 
200  object_pose = self._get_lowest_object_pose()
201 
202  # オブジェクトの位置によって左右のどちらの手で取るかを判定する
203  if object_pose.position.y < 0:
204  self._current_arm = self._RIGHT_ARM
205  rospy.loginfo("Set right arm")
206  else:
207  self._current_arm = self._LEFT_ARM
208  rospy.loginfo("Set left arm")
209 
210  # 念の為手を広げる
211  self._open_gripper(self._current_arm)
212 
213  # Z軸方向のオフセット meters
214  APPROACH_OFFSET = 0.10
215  PREPARE_OFFSET = 0.06
216  LEAVE_OFFSET = 0.10
217 
218  # 目標手先姿勢の生成
219  target_pose = Pose()
220  target_pose.position.x = object_pose.position.x
221  target_pose.position.y = object_pose.position.y
222  target_pose.position.z = object_pose.position.z
223 
224  # 掴む準備をする
225  target_pose.position.z = object_pose.position.z + APPROACH_OFFSET
226  if self._move_arm(self._current_arm, target_pose) is False and check_result:
227  rospy.logwarn("Approach failed")
228  result = False
229 
230  else:
231  rospy.sleep(1.0)
232  # ハンドを下げる
233  target_pose.position.z = object_pose.position.z + PREPARE_OFFSET
234  if self._move_arm(self._current_arm, target_pose) is False and check_result:
235  rospy.logwarn("Preparation grasping failed")
236  result = False
237 
238  else:
239  rospy.sleep(1.0)
240  # つかむ
241  if self._close_gripper(self._current_arm) is False and check_result:
242  rospy.logwarn("Grasping failed")
243  result = False
244 
245  rospy.sleep(1.0)
246  # ハンドを上げる
247  target_pose.position.z = object_pose.position.z + LEAVE_OFFSET
248  self._move_arm(self._current_arm, target_pose)
249 
250 
251  if result is False:
252  rospy.sleep(1.0)
253  # 失敗したときは安全のため手を広げる
254  self._open_gripper(self._current_arm)
255 
256  rospy.sleep(1.0)
257  # 初期位置に戻る
259 
260  return result
261 
262 
263  def place_on(self, check_result, target_x=0.3, target_y=0):
264  # 座標x,yにオブジェクトを配置する
265  rospy.loginfo("PLACE on :" + str(target_x) + ", " + str(target_y))
266  result = True
267 
268  # 制御アームが設定されているかチェック
269  if self._current_arm is None:
270  rospy.logwarn("NO ARM SELECTED")
271  return False
272 
273  # Z軸方向のオフセット meters
274  APPROACH_OFFSET = 0.14
275  PREPARE_OFFSET = 0.10
276  LEAVE_OFFSET = 0.14
277 
278  # 目標手先姿勢の生成
279  target_pose = Pose()
280  target_pose.position.x = target_x
281  target_pose.position.y = target_y
282  target_pose.position.z = 0.0
283 
284  # 置く準備をする
285  target_pose.position.z = APPROACH_OFFSET
286  if self._move_arm(self._current_arm, target_pose) is False and check_result:
287  rospy.logwarn("Approach failed")
288  result = False
289  else:
290  rospy.sleep(1.0)
291  # ハンドを下げる
292  target_pose.position.z = PREPARE_OFFSET
293  if self._move_arm(self._current_arm, target_pose) is False and check_result:
294  rospy.logwarn("Preparation release failed")
295  result = False
296  else:
297  rospy.sleep(1.0)
298  # はなす
299  self._open_gripper(self._current_arm)
300  # ハンドを上げる
301  target_pose.position.z = LEAVE_OFFSET
302  self._move_arm(self._current_arm, target_pose)
303 
304  if result is False:
305  rospy.sleep(1.0)
306  # 失敗したときは安全のため手を広げる
307  self._open_gripper(self._current_arm)
308 
309  rospy.sleep(1.0)
310  # 初期位置に戻る
312 
313  return result
314 
315 
316  def place_on_highest_object(self, check_result):
317  # 一番高さが高いオブジェクトの上に配置する
318  rospy.loginfo("PLACE ON HIGHEST OBJECT")
319  result = True
320 
321  # 制御アームが設定されているかチェック
322  if self._current_arm is None:
323  rospy.logwarn("NO ARM SELECTED")
324  return False
325 
326  # オブジェクトが他になければデフォルト位置に置く
327  rospy.sleep(1.0)
328  if self.get_num_of_markers() == 0:
329  rospy.logwarn("NO OBJECTS")
330  return self.place_on(check_result)
331 
332  object_pose = self._get_highest_object_pose()
333 
334  # Z軸方向のオフセット meters
335  APPROACH_OFFSET = 0.15
336  PREPARE_OFFSET = 0.11
337  LEAVE_OFFSET = 0.15
338 
339  # 目標手先姿勢の生成
340  target_pose = Pose()
341  target_pose.position.x = object_pose.position.x
342  target_pose.position.y = object_pose.position.y
343  target_pose.position.z = object_pose.position.z
344 
345  # 置く準備をする
346  target_pose.position.z = object_pose.position.z + APPROACH_OFFSET
347  if self._move_arm(self._current_arm, target_pose) is False and check_result:
348  rospy.logwarn("Approach failed")
349  result = False
350  else:
351  rospy.sleep(1.0)
352  # ハンドを下げる
353  target_pose.position.z = object_pose.position.z + PREPARE_OFFSET
354  if self._move_arm(self._current_arm, target_pose) is False and check_result:
355  rospy.logwarn("Preparation release failed")
356  result = False
357  else:
358  rospy.sleep(1.0)
359  # はなす
360  self._open_gripper(self._current_arm)
361  # ハンドを上げる
362  target_pose.position.z = object_pose.position.z + LEAVE_OFFSET
363  self._move_arm(self._current_arm, target_pose)
364 
365  if result is False:
366  rospy.sleep(1.0)
367  # 失敗したときは安全のため手を広げる
368  self._open_gripper(self._current_arm)
369 
370  rospy.sleep(1.0)
371  # 初期位置に戻る
373 
374  return result
375 
376 
378  # 首の角度を戻す
379  neck.set_angle(math.radians(0), math.radians(0), 3.0)
380  # 両腕を初期位置に戻す
381  stacker.initialize_arms()
382 
383 
384 def main():
385  r = rospy.Rate(60)
386 
387  rospy.on_shutdown(hook_shutdown)
388 
389  # 首の初期角度 degree
390  INITIAL_YAW_ANGLE = 0
391  INITIAL_PITCH_ANGLE = -70
392  # 首を下に傾けてテーブル上のものを見る
393  neck.set_angle(math.radians(INITIAL_YAW_ANGLE), math.radians(INITIAL_PITCH_ANGLE))
394 
395  # 動作モード
396  PICKING_MODE = 0
397  PLACE_MODE = 1
398  current_mode = PICKING_MODE
399 
400  # 箱の配置位置 meter
401  PLACE_X = 0.3
402  PLACE_Y = 0.0
403 
404  # アームとグリッパが正しく動いたかチェックする
405  CHECK_RESULT = True
406 
407  while not rospy.is_shutdown():
408  # ピッキングモード or プレースモードで分岐
409  if current_mode == PICKING_MODE:
410  # マーカの個数を取得
411  if stacker.get_num_of_markers() > 0:
412  # マーカがあれば、1番高さが低いオブジェクトを掴み上げる
413  if stacker.pick_up(CHECK_RESULT) is False:
414  rospy.logwarn("PickUp Failed")
415  else:
416  rospy.loginfo("PickUp Succeeded")
417  current_mode = PLACE_MODE
418  else:
419  rospy.loginfo("NO MARKERS")
420  rospy.sleep(1.0)
421 
422  elif current_mode == PLACE_MODE:
423  # マーカの個数を取得
424  if stacker.get_num_of_markers() == 0:
425  # マーカがなければ、指定位置に配置
426  if stacker.place_on(CHECK_RESULT, PLACE_X, PLACE_Y) is False:
427  rospy.logwarn("Place Failed")
428  else:
429  rospy.loginfo("Place Succeeded")
430 
431  else:
432  # マーカがあれば、一番高い位置にあるオブジェクトの上に配置
433  if stacker.place_on_highest_object(CHECK_RESULT) is False:
434  rospy.logwarn("Place Failed")
435  else:
436  rospy.loginfo("Place Succeeded")
437 
438  # モードを変更
439  current_mode = PICKING_MODE
440 
441  r.sleep()
442 
443 
444 if __name__ == '__main__':
445  rospy.init_node("box_stacking_example")
446 
447  neck = NeckYawPitch()
448  stacker = Stacker()
449 
450  main()
451 
def _move_arm_to_init_pose(self, current_arm)
def pick_up(self, check_result)
def place_on(self, check_result, target_x=0.3, target_y=0)
def _close_gripper(self, current_arm)
def _open_gripper(self, current_arm)
def set_angle(self, yaw_angle, pitch_angle, goal_secs=1.0e-9)
def place_on_highest_object(self, check_result)
def _move_arm(self, current_arm, target_pose)


sciurus17_examples
Author(s): Daisuke Sato , Hiroyuki Nomura
autogenerated on Sun Oct 2 2022 02:21:39