Skip to content

Commit f2dbd33

Browse files
authored
Mpinol/simrealrebased (#107)
* Adding sim and real pnp files.
1 parent f2bae7a commit f2dbd33

13 files changed

Lines changed: 760 additions & 7 deletions

File tree

tutorials/pick_and_place/3_pick_and_place.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ Steps covered in this tutorial includes invoking a motion planning service in RO
6868

6969
> This is similar to the `SourceDestinationPublisher.Publish()` function, but with a few key differences. There is an added `pickPoseOffset` to the `pick` and `place_pose` `y` component. This is because the calculated trajectory to grasp the `target` object will hover slightly above the object before grasping it in order to avoid potentially colliding with the object. Additionally, this function calls `CurrentJointConfig()` to assign the `request.joints_input` instead of assigning the values individually.
7070

71-
> The `response.trajectories` are received in the `TrajectoryResponse()` callback, as defined in the `ros.SendServiceMessage` parameters. These trajectories are passed to `ExecuteTrajectories()` below:
71+
> The `response.trajectories` are received in the `TrajectoryResponse()` callback, as defined in the `ros.SendServiceMessage` parameters. These trajectories are passed to `ExecuteTrajectories()` and executed as a [coroutine](https://docs.unity3d.com/Manual/Coroutines.html):
7272
7373
```csharp
7474
private IEnumerator ExecuteTrajectories(MoverServiceResponse response)

tutorials/pick_and_place/4_pick_and_place.md

Lines changed: 347 additions & 0 deletions
Large diffs are not rendered by default.

tutorials/pick_and_place/README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ This tutorial is designed such that you do not need prior experience with Unity
1515
- [Part 0: ROS Setup](#part-0-ros-setup)
1616
- [Part 1: Create Unity scene with imported URDF](#part-1-create-unity-scene-with-imported-urdf)
1717
- [Part 2: ROS–Unity Integration](#part-2-rosunity-integration)
18-
- [Part 3: Pick-and-Place](#part-3-pick-and-place)
18+
- [Part 3: Pick-and-Place In Unity](#part-3-pick-and-place-in-unity)
19+
- [Part 4: Pick-and-Place on the Real Robot](#part-4-pick-and-place-on-the-real-robot)
1920

2021
## Requirements
2122

@@ -42,8 +43,14 @@ This part includes downloading and installing the Unity Editor, setting up a bas
4243

4344
This part covers creating a TCP connection between Unity and ROS, generating C# scripts from a ROS msg and srv files, and publishing to a ROS topic.
4445

45-
## [Part 3: Pick-and-Place](3_pick_and_place.md)
46+
## [Part 3: Pick-and-Place In Unity](3_pick_and_place.md)
4647

4748
<img src="img/0_pick_place.gif" width="400"/>
4849

49-
This part includes the preparation and setup necessary to run a pick-and-place task with known poses using MoveIt. Steps covered include creating and invoking a motion planning service in ROS, moving a Unity Articulation Body based on a calculated trajectory, and controlling a gripping tool to successfully grasp and drop an object.
50+
This part includes the preparation and setup necessary to run a pick-and-place task with known poses using MoveIt. Steps covered include creating and invoking a motion planning service in ROS, moving a Unity Articulation Body based on a calculated trajectory, and controlling a gripping tool to successfully grasp and drop an object.
51+
52+
## [Part 4: Pick-and-Place on the Real Robot](4_pick_and_place.md)
53+
54+
<img src="img/4_pick_and_place.gif" width="400"/>
55+
56+
This part is going to be a little different than the previous tutorials in that it will utilize a real Niryo One robot. We do not assume that everyone has access to a Niryo One outside of simulation. As such this tutorial should mostly be used as a reference for how to move from executing commands on a simulated robot to a real one.

tutorials/pick_and_place/ROS/src/niryo_moveit/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ catkin_install_python(PROGRAMS
3333
scripts/mover.py
3434
scripts/server_endpoint.py
3535
scripts/trajectory_subscriber.py
36+
scripts/sim_real_pnp.py
3637
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
3738
)
3839

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<launch>
2+
<rosparam file="$(find niryo_moveit)/config/params.yaml" command="load"/>
3+
<node name="server_endpoint" pkg="niryo_moveit" type="server_endpoint.py" args="--wait" output="screen" respawn="true" />
4+
<node name="sim_real_pnp" pkg="niryo_moveit" type="sim_real_pnp.py" args="--wait" output="screen"/>
5+
</launch>

tutorials/pick_and_place/ROS/src/niryo_moveit/scripts/server_endpoint.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
from ros_tcp_endpoint import TcpServer, RosPublisher, RosSubscriber, RosService
66
from niryo_moveit.msg import NiryoMoveitJoints, NiryoTrajectory
7-
from niryo_moveit.srv import MoverService
7+
from niryo_moveit.srv import MoverService, MoverServiceRequest
88

9+
from niryo_one_msgs.msg import RobotMoveActionGoal
910

1011
def main():
1112
ros_node_name = rospy.get_param("/TCP_NODE_NAME", 'TCPServer')
@@ -16,9 +17,10 @@ def main():
1617
tcp_server.start({
1718
'SourceDestination_input': RosPublisher('SourceDestination', NiryoMoveitJoints, queue_size=10),
1819
'NiryoTrajectory': RosSubscriber('NiryoTrajectory', NiryoTrajectory, tcp_server),
19-
'niryo_moveit': RosService('niryo_moveit', MoverService)
20+
'niryo_moveit': RosService('niryo_moveit', MoverService),
21+
'niryo_one/commander/robot_action/goal': RosSubscriber('niryo_one/commander/robot_action/goal', RobotMoveActionGoal, tcp_server),
22+
'sim_real_pnp': RosPublisher('sim_real_pnp', MoverServiceRequest)
2023
})
21-
2224
rospy.spin()
2325

2426

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
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

Comments
 (0)