Skip to content

Commit 1f0dd5f

Browse files
committed
added teleop with placo only ik visualization with x7s example; added urdf visualization scripts; reorganized project folder structure
1 parent 9ca292d commit 1f0dd5f

File tree

13 files changed

+418
-106
lines changed

13 files changed

+418
-106
lines changed

README.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,29 +49,38 @@ The main dependencies are listed in the [`pyproject.toml`](pyproject.toml) file
4949
To run the teleoperation demo with a UR5e robot in MuJoCo simulation:
5050

5151
```bash
52-
python scripts/teleop_dual_ur5e_mujoco.py
52+
python scripts/simulation/teleop_dual_ur5e_mujoco.py
5353
```
54-
This script initializes the [`MujocoTeleopController`](teleop_demo_python/mujoco_teleop_controller.py) with the UR5e model and starts the teleoperation loop.
54+
This script initializes the [`MujocoTeleopController`](teleop_demo_python/simulation/mujoco_teleop_controller.py) with the UR5e model and starts the teleoperation loop.
55+
56+
### Running the Placo Visualization Demo
57+
58+
To run the teleoperation demo with a UR5e robot in Placo visualization:
59+
60+
```bash
61+
python scripts/simulation/teleop_x7s_placo.py
62+
```
63+
This script initializes the [`PlacoTeleopController`](teleop_demo_python/simulation/placo_teleop_controller.py) with the X7S robot and starts the teleoperation loop.
5564

5665
### Running the Hardware Demo (Dual UR Arms and Dynamixel Head)
5766

5867
To run the teleoperation demo with the physical dual UR arms and Dynamixel-based head:
5968

6069
1. **Normal Operation:**
6170
```bash
62-
python scripts/teleop_dual_ur5e_hardware.py
71+
python scripts/hardware/teleop_dual_ur5e_hardware.py
6372
```
6473
This script initializes the [`DynamixelHeadController`](teleop_demo_python/hardware/dynamixel.py) and [`DualArmURController`](teleop_demo_python/hardware/ur.py) and starts the teleoperation loops for both head tracking and arm control.
6574

6675
2. **Resetting Arm Positions:**
6776
If you need to reset the UR arms to their initial/home positions and initialize the robotiq grippers, you can run the script with the `--reset` flag:
6877
```bash
69-
python scripts/teleop_dual_ur5e_hardware.py --reset
78+
python scripts/hardware/teleop_dual_ur5e_hardware.py --reset
7079
```
7180
This will execute the reset procedure defined in the [`DualArmURController`](teleop_demo_python/hardware/ur.py) and then exit.
7281

7382
3. **Visualizing IK results:**
7483
To visualize the inverse kinematics solution with placo during teleoperation, run the script with the `--visualize_placo` flag.
7584
```bash
76-
python scripts/teleop_dual_ur5e_hardware.py --visualize_placo
85+
python scripts/hardware/teleop_dual_ur5e_hardware.py --visualize_placo
7786
```
File renamed without changes.

scripts/teleop_dual_ur5e_mujoco.py renamed to scripts/simulation/teleop_dual_ur5e_mujoco.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
import os
2-
from teleop_demo_python.mujoco_teleop_controller import (
2+
3+
from teleop_demo_python.simulation.mujoco_teleop_controller import (
34
MujocoTeleopController,
45
)
56
from teleop_demo_python.utils.path_utils import ASSET_PATH
67

78

89
def main():
9-
xml_path = os.path.join(
10-
ASSET_PATH, "universal_robots_ur5e/scene_dual_arm.xml"
11-
)
12-
robot_urdf_path = os.path.join(
13-
ASSET_PATH, "universal_robots_ur5e/dual_ur5e.urdf"
14-
)
10+
xml_path = os.path.join(ASSET_PATH, "universal_robots_ur5e/scene_dual_arm.xml")
11+
robot_urdf_path = os.path.join(ASSET_PATH, "universal_robots_ur5e/dual_ur5e.urdf")
1512

1613
config = {
1714
"right_hand": {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import os
2+
3+
from teleop_demo_python.simulation.placo_teleop_controller import (
4+
PlacoTeleopController,
5+
)
6+
from teleop_demo_python.utils.path_utils import ASSET_PATH
7+
8+
9+
def main():
10+
11+
# 14 dof: only arms
12+
# robot_urdf_path = os.path.join(ASSET_PATH, "X7S/X7S_arm_only.urdf")
13+
14+
# 17 dof: 2 arms, body tilting (joint2), head (joint3 and joint4)
15+
# robot_urdf_path = os.path.join(
16+
# ASSET_PATH, "X7S/X7S_fixed_vertical_no_gripper.urdf"
17+
# )
18+
19+
# 22 dof: all joints available
20+
robot_urdf_path = os.path.join(ASSET_PATH, "X7S/X7S.urdf")
21+
22+
config = {
23+
"right_hand": {
24+
"link_name": "link20",
25+
"pose_source": "right_controller",
26+
"control_trigger": "right_grip",
27+
},
28+
"left_hand": {
29+
"link_name": "link11",
30+
"pose_source": "left_controller",
31+
"control_trigger": "left_grip",
32+
},
33+
}
34+
35+
# Create and initialize the teleoperation controller
36+
controller = PlacoTeleopController(
37+
robot_urdf_path=robot_urdf_path,
38+
end_effector_config=config,
39+
scale_factor=1.5,
40+
)
41+
42+
# additional constraints hardcoded here for now
43+
joints_task = controller.solver.add_joints_task()
44+
joints_task.set_joints({joint: 0.0 for joint in controller.robot.joint_names()})
45+
joints_task.configure("joints_regularization", "soft", 5e-4)
46+
47+
if "joint2" in controller.robot.joint_names():
48+
controller.robot.set_joint_limits(
49+
"joint2", -0.5, 0.1
50+
) # to avoid excessive tilting of torso
51+
controller.solver.enable_velocity_limits(True)
52+
53+
controller.run()
54+
55+
56+
if __name__ == "__main__":
57+
main()

scripts/vis_mjcf.py renamed to scripts/visualization/vis_dual_ur5e_mjcf.py

File renamed without changes.

scripts/vis_urdf.py renamed to scripts/visualization/vis_dual_ur5e_urdf.py

File renamed without changes.

scripts/visualization/vis_urdf.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import argparse
2+
import webbrowser
3+
4+
import placo
5+
from placo_utils.visualization import robot_viz
6+
7+
8+
def main():
9+
parser = argparse.ArgumentParser(description="Visualize a URDF model using Placo and Meshcat.")
10+
parser.add_argument(
11+
"--urdf_path",
12+
type=str,
13+
help="Path to the URDF file to visualize.",
14+
)
15+
args = parser.parse_args()
16+
robot = placo.RobotWrapper(args.urdf_path)
17+
print(f"robot state: {robot.state.q}")
18+
print(f"robot state shape: {robot.state.q.shape}")
19+
# robot.state.q[:7] = np.array([0, 0, 0, 1, 0, 0, 0])
20+
# robot.state.q[7:] = 0.5 * np.ones(robot.state.q[7:].shape) # Set initial joint positions
21+
robot.update_kinematics()
22+
viz = robot_viz(robot)
23+
webbrowser.open(viz.viewer.url())
24+
25+
while True:
26+
robot.update_kinematics()
27+
viz.display(robot.state.q)
28+
29+
30+
if __name__ == "__main__":
31+
main()

teleop_demo_python/hardware/dual_arm_ur_controller.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,28 @@
3939
DEFAULT_DUAL_ARM_URDF_PATH = os.path.join(ASSET_PATH, "universal_robots_ur5e/dual_ur5e.urdf")
4040
DEFAULT_SCALE_FACTOR = 1.0
4141

42+
DEFAULT_END_EFFECTOR_CONFIG = {
43+
"left_arm": {
44+
"link_name": "left_tool0",
45+
"pose_source": "left_controller",
46+
"control_trigger": "left_grip",
47+
"gripper_trigger": "left_trigger",
48+
},
49+
"right_arm": {
50+
"link_name": "right_tool0",
51+
"pose_source": "right_controller",
52+
"control_trigger": "right_grip",
53+
"gripper_trigger": "right_trigger",
54+
},
55+
}
56+
4257

4358
class DualArmURController:
4459
def __init__(
4560
self,
4661
pico_client: PicoClient,
4762
robot_urdf_path: str = DEFAULT_DUAL_ARM_URDF_PATH, # Path to URDF for Placo
63+
end_effector_config: dict = DEFAULT_END_EFFECTOR_CONFIG,
4864
left_robot_ip: str = LEFT_ROBOT_IP,
4965
right_robot_ip: str = RIGHT_ROBOT_IP,
5066
left_initial_joint_deg: np.ndarray = LEFT_INITIAL_JOINT_DEG, # Use DEG for consistency
@@ -97,22 +113,7 @@ def __init__(
97113
self.solver.add_kinetic_energy_regularization_task(1e-6)
98114

99115
# Define end-effector configuration (adjust link names and pico sources as needed)
100-
self.end_effector_config = {
101-
"left_arm": {
102-
"link_name": "left_tool0",
103-
"pose_source": "left_controller",
104-
"control_trigger": "left_grip",
105-
"gripper_trigger": "left_trigger",
106-
"vis_target": "left_target",
107-
},
108-
"right_arm": {
109-
"link_name": "right_tool0",
110-
"pose_source": "right_controller",
111-
"control_trigger": "right_grip",
112-
"gripper_trigger": "right_trigger",
113-
"vis_target": "right_target",
114-
},
115-
}
116+
self.end_effector_config = end_effector_config
116117

117118
self.effector_task = {}
118119
self.init_ee_xyz = {}
@@ -157,7 +158,7 @@ def __init__(
157158
for name, config in self.end_effector_config.items():
158159
robot_frame_viz(self.placo_robot, config["link_name"])
159160
frame_viz(
160-
config["vis_target"],
161+
f"vis_target_{name}",
161162
self.effector_task[name].T_world_frame,
162163
)
163164

@@ -272,7 +273,7 @@ def calc_target_joint_position(self):
272273
for name, config in self.end_effector_config.items():
273274
robot_frame_viz(self.placo_robot, config["link_name"])
274275
frame_viz(
275-
f"target_{name}",
276+
f"vis_target_{name}",
276277
self.effector_task[name].T_world_frame,
277278
)
278279

0 commit comments

Comments
 (0)