joystick_example.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3 
4 import rospy
5 import moveit_commander
6 from geometry_msgs.msg import Vector3, Quaternion
7 import rosnode
8 from tf.transformations import quaternion_from_euler, euler_from_quaternion
9 
10 import math
11 from sensor_msgs.msg import Joy
12 from geometry_msgs.msg import Pose
13 from std_msgs.msg import UInt8
14 
15 
16 class JoyWrapper(object):
17  def __init__(self):
18  self._sub_joy = rospy.Subscriber("joy", Joy, self._callback_joy, queue_size=1)
19 
20  self._grip_updated = False
21  self._pose_updated = False
22  self._name_updated = False
23  self._preset_updated = False
24  self._do_shutdown = False # ジョイスティックによる終了操作フラグ
25 
26  self.TEACHING_NONE = 0
27  self.TEACHING_SAVE = 1
28  self.TEACHING_LOAD = 2
29  self.TEACHING_DELETE = 3
31 
32  # /rane_x7_examples/launch/joystick_example.launch でキー割り当てを変更する
33  self._BUTTON_SHUTDOWN_1 = rospy.get_param("~button_shutdown_1")
34  self._BUTTON_SHUTDOWN_2 = rospy.get_param("~button_shutdown_2")
35 
36  self._BUTTON_NAME_ENABLE = rospy.get_param("~button_name_enable")
37  self._BUTTON_NAME_HOME = rospy.get_param("~button_name_home")
38 
39  self._BUTTON_PRESET_ENABLE = rospy.get_param("~button_preset_enable")
40  self._BUTTON_PRESET_NO1 = rospy.get_param("~button_preset_no1")
41 
42  self._BUTTON_TEACHING_ENABLE = rospy.get_param("~button_teaching_enable")
43  self._BUTTON_TEACHING_SAVE = rospy.get_param("~button_teaching_save")
44  self._BUTTON_TEACHING_LOAD = rospy.get_param("~button_teaching_load")
45  self._BUTTON_TEACHING_DELETE = rospy.get_param("~button_teaching_delete")
46 
47  self._BUTTON_GRIP_ENABLE = rospy.get_param("~button_grip_enable")
48  self._AXIS_GRIPPER = rospy.get_param("~axis_gripper")
49 
50  self._BUTTON_POSI_ENABLE = rospy.get_param("~button_posi_enable")
51  self._BUTTON_RPY_ENABLE = rospy.get_param("~button_rpy_enable")
52  self._AXIS_POSITION_X = rospy.get_param("~axis_position_x")
53  self._AXIS_POSITION_Y = rospy.get_param("~axis_position_y")
54  self._AXIS_POSITION_Z = rospy.get_param("~axis_position_z")
55 
56  # 目標姿勢
57  self._target_gripper_joint_values = [0.0, 0.0]
58  self._target_arm_pose = Pose()
59  self._target_arm_rpy = Vector3()
60  self._target_name = "vertical"
61 
62  # ティーチング
64  self._teaching_index = 0
65 
66  def set_target_gripper(self, joint_values):
67  self._target_gripper_joint_values = joint_values
68 
69  def set_target_arm(self, pose):
70  self._target_arm_pose = pose
71  self._target_arm_rpy = self._orientation_to_rpy(pose.pose.orientation)
72 
73  def get_target_gripper(self):
75 
76  def get_target_arm(self):
77  return self._target_arm_pose
78 
79  def get_target_name(self):
80  return self._target_name
81 
82  def do_shutdown(self):
83  return self._do_shutdown
84 
86  self._grip_updated, flag = False, self._grip_updated
87  return flag
88 
90  self._pose_updated, flag = False, self._pose_updated
91  return flag
92 
94  self._name_updated, flag = False, self._name_updated
95  return flag
96 
98  self._preset_updated, flag = False, self._preset_updated
99  return flag
100 
102  self._teaching_flag, flag = self.TEACHING_NONE, self._teaching_flag
103  return flag
104 
105  def save_joint_values(self, arm, gripper):
106  # ティーチング
107  # アームの各関節角度と、グリッパー開閉角度を配列に保存する
108  rospy.loginfo("Teaching. Save")
109  self._teaching_joint_values.append([arm, gripper])
110 
111  def load_joint_values(self):
112  # ティーチング
113  # 保存した角度情報を返す
114  # 配列のインデックスが末尾まで来たら、インデックスを0に戻す
115  # 何も保存していない場合はFalseを返す
116  if self._teaching_joint_values:
117  rospy.loginfo("Teaching. Load")
118  joint_values = self._teaching_joint_values[self._teaching_index]
119  self._teaching_index += 1
120 
121  if self._teaching_index >= len(self._teaching_joint_values):
122  rospy.loginfo("Teaching. Index reset")
123  self._teaching_index = 0
124  return joint_values
125  else:
126  rospy.logwarn("Teaching. Joint Values is nothing")
127  return False
128 
130  # ティーチング
131  # 角度情報が格納された配列を初期化する
132  rospy.loginfo("Teaching. Delete")
133  self._teaching_joint_values = []
134 
135  def _orientation_to_rpy(self, orientation):
136  # クォータニオンをRPY(Role, Pitch, Yaw)に変換する
137  x = orientation.x
138  y = orientation.y
139  z = orientation.z
140  w = orientation.w
141 
142  e = euler_from_quaternion((x, y, z, w))
143  return Vector3(e[0], e[1], e[2])
144 
145  def _rpy_to_orientation(self, rpy):
146  # RPY(Role, Pitch, Yaw)をクォータニオンに変換する
147  q = quaternion_from_euler(rpy.x, rpy.y, rpy.z)
148  return Quaternion(q[0], q[1], q[2], q[3])
149 
150  def _callback_joy(self, msg):
151  # ジョイスティック信号用のコールバック関数
152  # ボタン入力に合わせてフラグと制御量を設定する
153 
154  # シャットダウン
155  if msg.buttons[self._BUTTON_SHUTDOWN_1] and msg.buttons[self._BUTTON_SHUTDOWN_2]:
156  self._do_shutdown = True
157  return
158 
159  # Group State
160  if msg.buttons[self._BUTTON_NAME_ENABLE]:
161  if msg.buttons[self._BUTTON_NAME_HOME]:
162  self._target_name = "home"
163  self._name_updated = True
164  return
165 
166  # PIDゲインプリセット
167  if msg.buttons[self._BUTTON_PRESET_ENABLE]:
168  if msg.buttons[self._BUTTON_PRESET_NO1]:
169  self._preset_updated = True
170  return
171 
172  # ティーチングフラグ
173  if msg.buttons[self._BUTTON_TEACHING_ENABLE]:
174  if msg.buttons[self._BUTTON_TEACHING_SAVE]:
175  self._teaching_flag = self.TEACHING_SAVE
176  elif msg.buttons[self._BUTTON_TEACHING_LOAD]:
177  self._teaching_flag = self.TEACHING_LOAD
178  elif msg.buttons[self._BUTTON_TEACHING_DELETE]:
179  self._teaching_flag = self.TEACHING_DELETE
180  return
181 
182  # グリッパー開閉
183  if msg.buttons[self._BUTTON_GRIP_ENABLE]:
184  # ジョイスティックを倒した量に合わせて、グリッパーを閉じる
185  grip_value = 1.0 - math.fabs(msg.axes[self._AXIS_GRIPPER])
186 
187  if not grip_value:
188  grip_value = 0.01
189 
190  self._target_gripper_joint_values = [grip_value, grip_value]
191  self._grip_updated = True
192  return
193 
194  # アーム姿勢(位置)変更
195  if msg.buttons[self._BUTTON_POSI_ENABLE]:
196  # ジョイスティックを倒した量に合わせて、目標姿勢を変える
197  # ジョイスティックの仕様に合わせて、符号を変えてください
198  self._target_arm_pose.pose.position.x -= msg.axes[self._AXIS_POSITION_X] * 0.1
199  self._target_arm_pose.pose.position.y += msg.axes[self._AXIS_POSITION_Y] * 0.1
200  self._target_arm_pose.pose.position.z += msg.axes[self._AXIS_POSITION_Z] * 0.1
201  self._pose_updated = True
202 
203  # アーム姿勢(角度)変更
204  if msg.buttons[self._BUTTON_RPY_ENABLE]:
205  # ジョイスティックを倒した量に合わせて、目標姿勢を変える
206  # ジョイスティックの仕様に合わせて、符号を変えてください
207  self._target_arm_rpy.x -= msg.axes[self._AXIS_POSITION_X] * math.pi * 0.1
208  self._target_arm_rpy.y += msg.axes[self._AXIS_POSITION_Y] * math.pi * 0.1
209  self._target_arm_rpy.z += msg.axes[self._AXIS_POSITION_Z] * math.pi * 0.1
210  self._target_arm_pose.pose.orientation = self._rpy_to_orientation(self._target_arm_rpy)
211  self._pose_updated = True
212 
213 
214 def preset_pid_gain(pid_gain_no):
215  # サーボモータのPIDゲインをプリセットする
216  # プリセットの内容はcrane_x7_control/scripts/preset_reconfigure.pyに書かれている
217  rospy.loginfo("PID Gain Preset. No." + str(pid_gain_no))
218  preset_no = UInt8()
219  preset_no.data = pid_gain_no
220  pub_preset.publish(preset_no)
221  rospy.sleep(1) # PIDゲインがセットされるまで待つ
222 
223 
224 def main():
225  arm = moveit_commander.MoveGroupCommander("arm")
226  arm.set_max_velocity_scaling_factor(0.5)
227  arm.set_max_acceleration_scaling_factor(1.0)
228  gripper = moveit_commander.MoveGroupCommander("gripper")
229 
230  PRESET_DEFAULT = 0
231  PRESET_FREE = 3
232  pid_gain_no = PRESET_DEFAULT
233 
234 
235  # 何かを掴んでいた時のためにハンドを開く
236  gripper.set_joint_value_target([0.9, 0.9])
237  gripper.go()
238 
239  # SRDFに定義されている"home"の姿勢にする
240  arm.set_named_target("home")
241  arm.go()
242 
243  # 現在のアーム姿勢を、目標姿勢にセットする
244  joy_wrapper.set_target_arm(arm.get_current_pose())
245  joy_wrapper.set_target_gripper(gripper.get_current_joint_values())
246 
247 
248  while joy_wrapper.do_shutdown() == False:
249  # グリッパーの角度を変更する
250  if joy_wrapper.get_and_reset_grip_update_flag():
251  gripper.set_joint_value_target(joy_wrapper.get_target_gripper())
252  gripper.go()
253 
254  # アームの姿勢を変更する
255  if joy_wrapper.get_and_reset_pose_update_flag():
256  arm.set_pose_target(joy_wrapper.get_target_arm())
257  if arm.go() == False:
258  # 現在のアーム姿勢を、目標姿勢にセットする
259  joy_wrapper.set_target_arm(arm.get_current_pose())
260 
261  # アームの姿勢をpose_group (home or vertical)に変更する
262  if joy_wrapper.get_and_reset_name_update_flag():
263  arm.set_named_target(joy_wrapper.get_target_name())
264  arm.go()
265  # 現在のアーム姿勢を、目標姿勢にセットする
266  joy_wrapper.set_target_arm(arm.get_current_pose())
267 
268  # アームのPIDゲインをプリセットする
269  if joy_wrapper.get_and_reset_preset_update_flag():
270  # PIDゲインを0:default, 1:Free に切り替える
271  if pid_gain_no == PRESET_DEFAULT:
272  pid_gain_no = PRESET_FREE
273  else:
274  pid_gain_no = PRESET_DEFAULT
275  # PIDゲインをdefaultに戻すと、目標姿勢に向かって急に動き出す
276  # 安全のため、現在のアームの姿勢を目標姿勢に変更する
277  arm.set_pose_target(arm.get_current_pose())
278  arm.go()
279  preset_pid_gain(pid_gain_no)
280  # 現在のアーム姿勢を、目標姿勢にセットする
281  joy_wrapper.set_target_arm(arm.get_current_pose())
282 
283  # ティーチング
284  teaching_flag = joy_wrapper.get_and_reset_teaching_flag()
285  if teaching_flag == joy_wrapper.TEACHING_SAVE:
286  # 現在のアーム姿勢、グリッパー角度を保存する
287  # アームの角度が制御範囲内にない場合、例外が発生する
288  try:
289  arm_joint_values = arm.get_current_joint_values()
290  gripper_joint_values = gripper.get_current_joint_values()
291 
292  arm.set_joint_value_target(arm_joint_values)
293  gripper.set_joint_value_target(gripper_joint_values)
294  joy_wrapper.save_joint_values(arm_joint_values, gripper_joint_values)
296  print("Error setting joint target. Is the target within bounds?")
297  elif teaching_flag == joy_wrapper.TEACHING_LOAD:
298  # 保存したアーム、グリッパー角度を取り出す
299  joint_values = joy_wrapper.load_joint_values()
300  if joint_values:
301  arm.set_joint_value_target(joint_values[0])
302  arm.go()
303  gripper.set_joint_value_target(joint_values[1])
304  gripper.go()
305  # 現在のアーム姿勢を、目標姿勢にセットする
306  joy_wrapper.set_target_arm(arm.get_current_pose())
307  joy_wrapper.set_target_gripper(gripper.get_current_joint_values())
308  elif teaching_flag == joy_wrapper.TEACHING_DELETE:
309  # 保存したアーム姿勢、グリッパー角度を削除する
310  joy_wrapper.delete_joint_values()
311 
312 
313  rospy.loginfo("Shutdown...")
314 
315  # SRDFに定義されている"vertical"の姿勢にする
316  arm.set_named_target("vertical")
317  arm.go()
318 
319 
320 if __name__ == '__main__':
321  rospy.init_node("joystick_example")
322 
323  joy_wrapper = JoyWrapper()
324 
325  # PIDゲインプリセット用のPublisher
326  pub_preset = rospy.Publisher("preset_gain_no", UInt8, queue_size=1)
327 
328  try:
329  if not rospy.is_shutdown():
330  main()
331  except rospy.ROSInterruptException:
332  pass
def set_target_gripper(self, joint_values)
def _orientation_to_rpy(self, orientation)
def save_joint_values(self, arm, gripper)
def preset_pid_gain(pid_gain_no)


crane_x7_examples
Author(s): Daisuke Sato , Hiroyuki Nomura
autogenerated on Mon Mar 1 2021 03:18:34