Skip to content

Commit 67440a4

Browse files
jhanca-robotecaiayushgnviche033adamdbrw
committed
Rework the script; update README
Co-authored-by: Ayush Ghosh <[email protected]> Co-authored-by: Ian Chen <[email protected]> Co-authored-by: Adam Dąbrowski <[email protected]>
1 parent b788dcb commit 67440a4

File tree

3 files changed

+629
-3
lines changed

3 files changed

+629
-3
lines changed

README.md

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,41 @@
1+
# Simulation Interfaces Examples
2+
3+
## Sample script
4+
5+
This repository contains the example script using standardized simulation interfaces powering different simulation backends. The script implements the following scenario:
6+
1. Initialize simulation
7+
1.1. Load world (only if supported)
8+
1.2. Spawn and despawn an object
9+
1.3. Spawn two robots and multiple static objects
10+
2. Start the simulation
11+
2.1. Play and pause simulation
12+
2.2. Reset simulation to the initial state; move some objects
13+
2.3. Step simulation
14+
3. Loop the simulation
15+
3.1. Query the entity state of a robot
16+
3.2. Send target goals to a robot and move it around
17+
3.3. Move the robot once it had reached a certain pose
18+
3.4. Move the robotic arm to simulate pick and place
19+
4. Terminate the simulation (unload the world if supported)
20+
21+
The goal of this script is to demonstrate how to use the standardized simulation interfaces to control different simulation backends. Multiple parameters, such as robot speed, target poses, etc. are hardcoded for simplicity.
22+
23+
## Running the script
24+
25+
Run the simulator (Gazebo, Isaac Sim, or O3DE) and make sure the simulation interfaces are properly installed and sourced.
26+
Next, run the `warehouse_simulation_script.py` script with the desired backend flag.
27+
28+
| Simulator | flag |
29+
| --------- | ------------------------ |
30+
| Gazebo | `--sim-backend gazebo` |
31+
| Isaac Sim | `--sim-backend isaacsim` |
32+
| O3DE | `--sim-backend o3de` |
33+
34+
E.g. for Isaac Sim run:
35+
```shell
36+
python3 warehouse_simulation_script.py --sim-backend isaacsim
37+
```
38+
139
## Resources for simulation interfaces standard
240
See [the standard](https://github.com/ros-simulation/simulation_interfaces).
341

@@ -9,7 +47,5 @@ https://github.com/RobotecAI/q_simulation_interfaces
947

1048
### Robots
1149

12-
### Tutorial
13-
14-
### Other resources
50+
## Other resources
1551
ROSCon 2025 talk introducing the standard and resources

ur10_helpers.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
"""Helper functions for controlling UR10 robot arm across different simulation backends."""
2+
3+
import time
4+
from rclpy.node import Node
5+
6+
7+
def move_ur10_joints(node: Node, loop_iteration: int, sim_backend: str):
8+
"""Publish joint positions for UR10 for the given iteration.
9+
10+
Args:
11+
node: ROS2 node
12+
loop_iteration: Iteration number (0-2) to determine joint positions
13+
sim_backend: Simulation backend ("isaacsim", "o3de", or "gazebo")
14+
"""
15+
joint_positions_by_iteration = [
16+
[0.0, -1.5708, 1.5708, -1.5708, -1.5708, 0.0],
17+
[0.7854, -1.0472, 0.7854, -0.7854, -1.5708, 0.5236],
18+
[-0.5236, -2.0944, 2.0944, -2.0944, -1.5708, -0.7854],
19+
]
20+
joint_names = [
21+
"shoulder_pan_joint",
22+
"shoulder_lift_joint",
23+
"elbow_joint",
24+
"wrist_1_joint",
25+
"wrist_2_joint",
26+
"wrist_3_joint",
27+
]
28+
positions = joint_positions_by_iteration[loop_iteration]
29+
30+
if sim_backend == "isaacsim":
31+
move_ur10_joints_topic(node, joint_names, positions)
32+
elif sim_backend == "o3de":
33+
move_ur10_joints_action(node, joint_names, positions)
34+
elif sim_backend == "gazebo":
35+
move_ur10_joint_array_topic(node, positions)
36+
else:
37+
print(f"Unknown simulation backend: {sim_backend}")
38+
39+
40+
def move_ur10_joints_topic(node: Node, joint_names: list, positions: list):
41+
"""Move UR10 joints using JointState topic publisher.
42+
43+
Used for Isaac Sim backend.
44+
45+
Args:
46+
node: ROS2 node
47+
joint_names: List of joint names
48+
positions: List of joint positions (radians)
49+
"""
50+
from sensor_msgs.msg import JointState
51+
from std_msgs.msg import Header
52+
53+
ur10_joint_pub = node.create_publisher(JointState, "/joint_commands", 10)
54+
joint_cmd = JointState()
55+
joint_cmd.header = Header()
56+
joint_cmd.header.stamp = node.get_clock().now().to_msg()
57+
joint_cmd.name = joint_names
58+
joint_cmd.position = positions
59+
60+
for _ in range(10):
61+
ur10_joint_pub.publish(joint_cmd)
62+
time.sleep(0.2)
63+
64+
65+
def move_ur10_joint_array_topic(node: Node, positions: list):
66+
"""Move UR10 joints using Float64MultiArray publisher.
67+
68+
Used for Gazebo backend.
69+
70+
Args:
71+
node: ROS2 node
72+
positions: List of joint positions (radians)
73+
"""
74+
from std_msgs.msg import Float64MultiArray
75+
76+
ur10_joint_pub = node.create_publisher(Float64MultiArray, "/joint_commands", 10)
77+
joint_cmd = Float64MultiArray()
78+
joint_cmd.data = positions
79+
80+
for _ in range(10):
81+
ur10_joint_pub.publish(joint_cmd)
82+
time.sleep(0.2)
83+
84+
85+
def move_ur10_joints_action(node: Node, joint_names: list, positions: list):
86+
"""Move UR10 joints using FollowJointTrajectory action.
87+
88+
Used for O3DE backend.
89+
90+
Args:
91+
node: ROS2 node
92+
joint_names: List of joint names
93+
positions: List of joint positions (radians)
94+
"""
95+
import rclpy
96+
from rclpy.action import ActionClient
97+
from control_msgs.action import FollowJointTrajectory
98+
from control_msgs.msg import JointTolerance
99+
from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint
100+
from builtin_interfaces.msg import Duration
101+
102+
action_client = ActionClient(
103+
node,
104+
FollowJointTrajectory,
105+
"/joint_trajectory_controller/follow_joint_trajectory"
106+
)
107+
108+
while not action_client.wait_for_server(timeout_sec=1.0):
109+
print("Waiting for action server...")
110+
111+
# Build trajectory
112+
trajectory = JointTrajectory()
113+
trajectory.joint_names = joint_names
114+
115+
point = JointTrajectoryPoint()
116+
point.positions = positions
117+
point.velocities = [0.0] * len(joint_names)
118+
point.effort = [0.0] * len(joint_names)
119+
point.time_from_start = Duration(sec=1, nanosec=0)
120+
trajectory.points.append(point)
121+
122+
# Build goal with tolerances
123+
goal_tolerance = [JointTolerance(position=0.01) for _ in range(2)]
124+
goal_msg = FollowJointTrajectory.Goal()
125+
goal_msg.trajectory = trajectory
126+
goal_msg.goal_tolerance = goal_tolerance
127+
128+
# Send goal and wait for result
129+
future = action_client.send_goal_async(goal_msg)
130+
rclpy.spin_until_future_complete(node, future)
131+
132+
goal_handle = future.result()
133+
if not goal_handle.accepted:
134+
print("Goal rejected")
135+
return
136+
137+
result_future = goal_handle.get_result_async()
138+
rclpy.spin_until_future_complete(node, result_future)

0 commit comments

Comments
 (0)