Skip to content

Commit fc5eec2

Browse files
committed
feat: yam example
1 parent d925858 commit fc5eec2

3 files changed

Lines changed: 130 additions & 2 deletions

File tree

‎docs/extensions/rcs_yam.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,6 @@ The i2rt driver runs its PD control loop in a background thread. With
5555
limits and gripper stroke of the hardware.
5656

5757
See `extensions/rcs_yam/README.md` for the full extension documentation and
58-
`extensions/rcs_yam/src/rcs_yam/scripts/test_robot.py` for a bring-up script.
58+
`extensions/rcs_yam/src/rcs_yam/scripts/test_robot.py` for a bring-up script. For a maintained
59+
example, see `examples/yam/yam_env_cartesian_control.py`, which moves the TCP forward and backward in
60+
synchronous Cartesian mode in simulation or on hardware.
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import logging
2+
3+
import gymnasium as gym
4+
import numpy as np
5+
from rcs._core.common import RobotPlatform
6+
from rcs._core.sim import SimConfig
7+
from rcs.envs.base import (
8+
ControlMode,
9+
CoverWrapper,
10+
GripperWrapper,
11+
RelativeActionSpace,
12+
RelativeTo,
13+
RobotWrapper,
14+
SimEnv,
15+
)
16+
from rcs.envs.configs import EmptyWorldYam
17+
from rcs.envs.sim import GripperWrapperSim, RobotSimWrapper
18+
19+
import rcs
20+
from rcs import sim
21+
22+
logger = logging.getLogger(__name__)
23+
logger.setLevel(logging.INFO)
24+
25+
"""
26+
This script demonstrates Cartesian position control of the YAM arm in synchronous mode. The arm
27+
first moves to its home pose, ramped rather than snapped, and then moves 1cm forward and backward
28+
along the base x axis in a loop. Every step goes through inverse kinematics, so the printed TCP
29+
positions tracking the commanded ones show that IK works.
30+
31+
To control a real YAM arm, install the rcs_yam extension (`pip install -ve extensions/rcs_yam`),
32+
bring up its CAN interface (`sudo ip link set can0 up type can bitrate 1000000`) and set
33+
ROBOT_INSTANCE to RobotPlatform.HARDWARE. Note that the linear_4310 gripper calibrates on startup
34+
and drives its fingers to both end stops.
35+
"""
36+
37+
ROBOT_INSTANCE = RobotPlatform.SIMULATION # Change to RobotPlatform.HARDWARE for the real arm
38+
CAN_CHANNEL = "can0"
39+
40+
STEP_SIZE = 0.01 # meters per step
41+
STEPS_PER_LEG = 5 # steps forward before reversing
42+
CYCLES = 3
43+
44+
45+
def main():
46+
env_rel: gym.Env
47+
if ROBOT_INSTANCE == RobotPlatform.HARDWARE:
48+
from rcs_yam.configs import DefaultYamHardwareEnv
49+
50+
env_creator = DefaultYamHardwareEnv()
51+
env_creator.channel = CAN_CHANNEL
52+
hw_cfg = env_creator.config()
53+
hw_cfg.control_mode = ControlMode.CARTESIAN_TQuat
54+
# Synchronous mode: every command returns once the arm has reached its target.
55+
hw_cfg.robot_cfg.async_control = False
56+
# Homing interpolates over this duration instead of stepping to the home pose.
57+
hw_cfg.robot_cfg.move_home_duration = 3.0
58+
hw_cfg.max_relative_movement = (0.05, np.deg2rad(5))
59+
hw_cfg.relative_to = RelativeTo.LAST_STEP
60+
env_rel = env_creator.create_env(hw_cfg)
61+
input("the arm is going to move, press enter whenever you are ready")
62+
else:
63+
scene = EmptyWorldYam()
64+
sim_cfg_data = scene.prefixed_cfg(scene.config())
65+
yam = scene.lead_robot_name(sim_cfg_data)
66+
67+
robot_cfg = sim_cfg_data.robot_cfgs[yam]
68+
gripper_cfg = sim_cfg_data.gripper_cfgs[yam] # type: ignore[index]
69+
# Synchronous mode: the simulation steps until the commanded pose is reached.
70+
sim_cfg = SimConfig(
71+
realtime=False,
72+
async_control=False,
73+
)
74+
75+
mjmodel = scene.create_model(sim_cfg_data)
76+
simulation = sim.Sim(mjmodel, sim_cfg)
77+
78+
kinematic_model_path, attachment_site = scene.kinematics_cfg(sim_cfg_data)[yam]
79+
ik = rcs.common.Pin(
80+
kinematic_model_path,
81+
attachment_site,
82+
)
83+
84+
robot = rcs.sim.SimRobot(simulation, ik, robot_cfg)
85+
env_rel = SimEnv(simulation)
86+
env_rel = RobotWrapper(env_rel, robot, ControlMode.CARTESIAN_TQuat)
87+
88+
gripper = sim.SimGripper(simulation, gripper_cfg)
89+
env_rel = GripperWrapper(env_rel, gripper)
90+
91+
env_rel = RobotSimWrapper(env_rel)
92+
env_rel = GripperWrapperSim(env_rel)
93+
94+
env_rel = RelativeActionSpace(
95+
env_rel,
96+
max_mov=(0.05, np.deg2rad(5)),
97+
relative_to=RelativeTo.LAST_STEP,
98+
)
99+
env_rel = CoverWrapper(env_rel)
100+
env_rel.get_wrapper_attr("sim").open_gui()
101+
102+
# Homing happens on reset, driving the joints to the home pose.
103+
env_rel.reset()
104+
105+
robot_api = env_rel.get_wrapper_attr("robot")
106+
print(f"home TCP: {np.round(robot_api.get_cartesian_position().translation(), 4)}")
107+
108+
for _ in range(CYCLES):
109+
for direction in (1.0, -1.0):
110+
for _ in range(STEPS_PER_LEG):
111+
before = robot_api.get_cartesian_position().translation()
112+
# Relative to the current pose: move along the base x axis, keep the orientation.
113+
act = {"tquat": [direction * STEP_SIZE, 0, 0, 0, 0, 0, 1.0], "gripper": [1]}
114+
env_rel.step(act)
115+
after = robot_api.get_cartesian_position().translation()
116+
print(
117+
f"commanded {direction * STEP_SIZE:+.3f} m in x: "
118+
f"TCP {np.round(before, 4)} -> {np.round(after, 4)}, "
119+
f"tracking error {np.linalg.norm(after - (before + np.array([direction * STEP_SIZE, 0, 0]))):.4f} m"
120+
)
121+
122+
123+
if __name__ == "__main__":
124+
main()

‎extensions/rcs_yam/README.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ gripper.grasp()
113113
robot.close()
114114
```
115115

116-
See `src/rcs_yam/scripts/test_robot.py` for a complete bring-up script covering both modes.
116+
See `src/rcs_yam/scripts/test_robot.py` for a complete bring-up script covering both modes, and
117+
[examples/yam/yam_env_cartesian_control.py](../../examples/yam/yam_env_cartesian_control.py) for a
118+
maintained Cartesian control example that runs in simulation and on hardware.
117119

118120
## Bimanual setups
119121

0 commit comments

Comments
 (0)