|
| 1 | +#!/usr/bin/env python |
| 2 | + |
| 3 | +from __future__ import print_function |
| 4 | + |
| 5 | +import rospy |
| 6 | + |
| 7 | +import time |
| 8 | +import sys |
| 9 | +import copy |
| 10 | +import math |
| 11 | +import moveit_commander |
| 12 | +import actionlib |
| 13 | + |
| 14 | +import moveit_msgs.msg |
| 15 | + |
| 16 | +from niryo_one_msgs.msg import RobotMoveAction, ToolCommand, TrajectoryPlan |
| 17 | +from niryo_one_msgs.msg import RobotMoveGoal |
| 18 | + |
| 19 | +from moveit_msgs.msg import Constraints, JointConstraint, PositionConstraint, OrientationConstraint, BoundingVolume |
| 20 | +from sensor_msgs.msg import JointState |
| 21 | +from moveit_msgs.msg import RobotState |
| 22 | +import geometry_msgs.msg |
| 23 | +from geometry_msgs.msg import Quaternion, Pose |
| 24 | +from std_msgs.msg import String |
| 25 | +from moveit_commander.conversions import pose_to_list |
| 26 | + |
| 27 | +from niryo_moveit.srv import MoverServiceRequest |
| 28 | + |
| 29 | +joint_names = ['joint_1', 'joint_2', 'joint_3', 'joint_4', 'joint_5', 'joint_6'] |
| 30 | + |
| 31 | +# Gripper parameters |
| 32 | +OPEN_COMMAND = 1 |
| 33 | +CLOSE_COMMAND = 2 |
| 34 | +GRIPPER_SPEED = 100 |
| 35 | + |
| 36 | +# IDs used to determine which values in a RobotMoveGoal message to execute |
| 37 | +TOOL_ID = 11 |
| 38 | +TOOL_COMMAND_ID = 6 |
| 39 | +TRAJECTORY_COMMAND_ID = 7 |
| 40 | + |
| 41 | +PICK_PLACE_HEIGHT_OFFSET = 0.065 |
| 42 | + |
| 43 | +# Between Melodic and Noetic, the return type of plan() changed. moveit_commander has no __version__ variable, so checking the python version as a proxy |
| 44 | +if sys.version_info >= (3, 0): |
| 45 | + def planCompat(plan): |
| 46 | + return plan[1] |
| 47 | +else: |
| 48 | + def planCompat(plan): |
| 49 | + return plan |
| 50 | + |
| 51 | +""" |
| 52 | + Given the start angles of the robot, plan a trajectory that ends at the destination pose. |
| 53 | +""" |
| 54 | +def plan_trajectory(move_group, destination_pose, start_joint_angles): |
| 55 | + current_joint_state = JointState() |
| 56 | + current_joint_state.name = joint_names |
| 57 | + current_joint_state.position = start_joint_angles |
| 58 | + |
| 59 | + moveit_robot_state = RobotState() |
| 60 | + moveit_robot_state.joint_state = current_joint_state |
| 61 | + move_group.set_start_state(moveit_robot_state) |
| 62 | + |
| 63 | + move_group.set_pose_target(destination_pose) |
| 64 | + |
| 65 | + if not move_group.plan(): |
| 66 | + exception_str = """ |
| 67 | + Trajectory could not be planned for a destination of {}\n with starting joint angles {}. |
| 68 | + Please make sure target and destination are reachable by the robot. |
| 69 | + """.format(destination_pose, start_joint_angles) |
| 70 | + raise Exception(exception_str) |
| 71 | + |
| 72 | + trajectory_plan = TrajectoryPlan() |
| 73 | + trajectory_plan.trajectory = planCompat(move_group.plan()) |
| 74 | + |
| 75 | + return trajectory_plan |
| 76 | + |
| 77 | + |
| 78 | +def send_trajectory_goal(client, trajectory): |
| 79 | + |
| 80 | + # Build the goal |
| 81 | + goal = RobotMoveGoal() |
| 82 | + goal.cmd.Trajectory = trajectory |
| 83 | + goal.cmd.cmd_type = TRAJECTORY_COMMAND_ID |
| 84 | + |
| 85 | + client.send_goal(goal) |
| 86 | + client.wait_for_result() |
| 87 | + |
| 88 | + return |
| 89 | + |
| 90 | +def send_tool_goal(client, gripper_command): |
| 91 | + tool_command = ToolCommand() |
| 92 | + tool_command.tool_id = TOOL_ID |
| 93 | + tool_command.cmd_type = gripper_command |
| 94 | + tool_command.gripper_open_speed = GRIPPER_SPEED |
| 95 | + tool_command.gripper_close_speed = GRIPPER_SPEED |
| 96 | + |
| 97 | + goal = RobotMoveGoal() |
| 98 | + goal.cmd.tool_cmd = tool_command |
| 99 | + goal.cmd.cmd_type = TOOL_COMMAND_ID |
| 100 | + |
| 101 | + client.send_goal(goal) |
| 102 | + client.wait_for_result() |
| 103 | + |
| 104 | + return |
| 105 | + |
| 106 | + |
| 107 | +""" |
| 108 | + Creates a pick and place plan using the four states below. |
| 109 | + |
| 110 | + 1. Pre Grasp - position gripper directly above target object |
| 111 | + 2. Grasp - lower gripper so that fingers are on either side of object |
| 112 | + 3. Pick Up - raise gripper back to the pre grasp position |
| 113 | + 4. Place - move gripper to desired placement position |
| 114 | +
|
| 115 | + Gripper behaviour is handled outside of this trajectory planning. |
| 116 | + - Gripper close occurs after 'grasp' position has been achieved |
| 117 | + - Gripper open occurs after 'place' position has been achieved |
| 118 | +
|
| 119 | + https://github.com/ros-planning/moveit/blob/master/moveit_commander/src/moveit_commander/move_group.py |
| 120 | +""" |
| 121 | +def plan_pick_and_place(req): |
| 122 | + print("Starting planning....") |
| 123 | + client = actionlib.SimpleActionClient('niryo_one/commander/robot_action', RobotMoveAction) |
| 124 | + client.wait_for_server() |
| 125 | + |
| 126 | + group_name = "arm" |
| 127 | + move_group = moveit_commander.MoveGroupCommander(group_name) |
| 128 | + |
| 129 | + current_robot_joint_configuration = [ |
| 130 | + math.radians(req.joints_input.joint_00), |
| 131 | + math.radians(req.joints_input.joint_01), |
| 132 | + math.radians(req.joints_input.joint_02), |
| 133 | + math.radians(req.joints_input.joint_03), |
| 134 | + math.radians(req.joints_input.joint_04), |
| 135 | + math.radians(req.joints_input.joint_05), |
| 136 | + ] |
| 137 | + |
| 138 | + # Pre grasp - position gripper directly above target object |
| 139 | + pre_grasp_pose = plan_trajectory(move_group, req.pick_pose, current_robot_joint_configuration) |
| 140 | + |
| 141 | + previous_ending_joint_angles = pre_grasp_pose.trajectory.joint_trajectory.points[-1].positions |
| 142 | + send_trajectory_goal(client, pre_grasp_pose) |
| 143 | + |
| 144 | + # Grasp - lower gripper so that fingers are on either side of object |
| 145 | + pick_pose = copy.deepcopy(req.pick_pose) |
| 146 | + pick_pose.position.z -= PICK_PLACE_HEIGHT_OFFSET # Static value coming from Unity, TODO: pass along with request |
| 147 | + grasp_pose = plan_trajectory(move_group, pick_pose, previous_ending_joint_angles) |
| 148 | + |
| 149 | + previous_ending_joint_angles = grasp_pose.trajectory.joint_trajectory.points[-1].positions |
| 150 | + send_trajectory_goal(client, grasp_pose) |
| 151 | + send_tool_goal(client, CLOSE_COMMAND) |
| 152 | + |
| 153 | + # Pick Up - raise gripper back to the pre grasp position |
| 154 | + pick_up_pose = plan_trajectory(move_group, req.pick_pose, previous_ending_joint_angles) |
| 155 | + previous_ending_joint_angles = pick_up_pose.trajectory.joint_trajectory.points[-1].positions |
| 156 | + send_trajectory_goal(client, pick_up_pose) |
| 157 | + |
| 158 | + # Place - move gripper to desired placement position |
| 159 | + pre_place_pose = plan_trajectory(move_group, req.place_pose, previous_ending_joint_angles) |
| 160 | + previous_ending_joint_angles = pre_place_pose.trajectory.joint_trajectory.points[-1].positions |
| 161 | + send_trajectory_goal(client, pre_place_pose) |
| 162 | + |
| 163 | + # Gently Place object |
| 164 | + place_pose = copy.deepcopy(req.place_pose) |
| 165 | + place_pose.position.z -= PICK_PLACE_HEIGHT_OFFSET # Static value coming from Unity, TODO: pass along with request |
| 166 | + place_traj = plan_trajectory(move_group, place_pose, previous_ending_joint_angles) |
| 167 | + previous_ending_joint_angles = place_traj.trajectory.joint_trajectory.points[-1].positions |
| 168 | + send_trajectory_goal(client, place_traj) |
| 169 | + send_tool_goal(client, OPEN_COMMAND) |
| 170 | + |
| 171 | + # Reset robot at pre place pose pose |
| 172 | + post_place_traj = plan_trajectory(move_group, req.place_pose, previous_ending_joint_angles) |
| 173 | + send_trajectory_goal(client, post_place_traj) |
| 174 | + |
| 175 | + print("Finished executing action.") |
| 176 | + |
| 177 | +def listener(): |
| 178 | + rospy.init_node('sim_real_pnp', anonymous=True) |
| 179 | + |
| 180 | + rospy.Subscriber("sim_real_pnp", MoverServiceRequest, plan_pick_and_place) |
| 181 | + |
| 182 | + rospy.spin() |
| 183 | + |
| 184 | +if __name__ == '__main__': |
| 185 | + listener() |
0 commit comments