Skip to content

Commit 1809015

Browse files
authored
feat: Variable Impedance Controller (#74)
* feat: expose variable stiffness interface and add example Add runtime Cartesian stiffness control to crisp_py, matching the C++ controller's target_stiffness topic (Float64MultiArray with 6 elements). Changes: - RobotConfig: add target_stiffness_topic field - Robot: create stiffness publisher and set_stiffness() method - Robot.reset_targets: document that stiffness is intentionally not reset - examples/21_variable_stiffness.py: demo high/medium/low stiffness switching * fix: update variable stiffness example with actual working parameters Use k_pos=900, k_rot=45 as high stiffness (matching actual controller config), and adjust medium values accordingly. * fix: remove variable_stiffness.enabled param set from example The subscriber is now always created, so no need to enable it at runtime. --------- Co-authored-by: domrachev03 <domrachev03@users.noreply.github.com>
1 parent 49b1665 commit 1809015

3 files changed

Lines changed: 72 additions & 0 deletions

File tree

crisp_py/robot/robot.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from rclpy.qos import qos_profile_sensor_data, qos_profile_system_default
1616
from scipy.spatial.transform import Rotation, Slerp
1717
from sensor_msgs.msg import JointState
18+
from std_msgs.msg import Float64MultiArray
1819

1920
from crisp_py.config.path import find_config, list_configs_in_folder
2021
from crisp_py.control.controller_switcher import ControllerSwitcherClient
@@ -105,6 +106,9 @@ def __init__(
105106
self._target_wrench_publisher = self.node.create_publisher(
106107
WrenchStamped, "target_wrench", qos_profile_system_default
107108
)
109+
self._target_stiffness_publisher = self.node.create_publisher(
110+
Float64MultiArray, self.config.target_stiffness_topic, qos_profile_system_default
111+
)
108112
self._target_joint_publisher = self.node.create_publisher(
109113
JointState, self.config.target_joint_topic, qos_profile_system_default
110114
)
@@ -363,6 +367,8 @@ def reset_targets(self):
363367
self._target_pose = None
364368
self._target_joint = None
365369
self._target_wrench = None
370+
# Note: stiffness is NOT reset here because it is latched by the controller
371+
# and should persist across target resets
366372

367373
def wait_until_ready(self, timeout: float = 10.0, check_frequency: float = 10.0):
368374
"""Wait until the robot is ready for operation.
@@ -470,6 +476,33 @@ def set_target_wrench(
470476

471477
self._target_wrench = {"force": np.array(force), "torque": np.array(torque)}
472478

479+
def set_stiffness(
480+
self,
481+
translational: List | NDArray | None = None,
482+
rotational: List | NDArray | None = None,
483+
) -> None:
484+
"""Set the Cartesian stiffness for the impedance controller via topic.
485+
486+
This publishes a stiffness update to the controller's variable stiffness topic.
487+
The value is latched by the controller -- it persists until a new value is published.
488+
Requires the controller parameter variable_stiffness.enabled to be true.
489+
490+
Args:
491+
translational: Stiffness values [kx, ky, kz] for position. If None, zeros are used.
492+
rotational: Stiffness values [krx, kry, krz] for orientation. If None, zeros are used.
493+
"""
494+
if translational is None:
495+
translational = [0.0, 0.0, 0.0]
496+
if rotational is None:
497+
rotational = [0.0, 0.0, 0.0]
498+
499+
assert len(translational) == 3, "Translational stiffness must be a 3D vector"
500+
assert len(rotational) == 3, "Rotational stiffness must be a 3D vector"
501+
502+
msg = Float64MultiArray()
503+
msg.data = list(translational) + list(rotational)
504+
self._target_stiffness_publisher.publish(msg)
505+
473506
def _wrench_to_wrench_msg(self, wrench: dict) -> WrenchStamped:
474507
"""Convert a wrench dictionary to a ROS WrenchStamped message.
475508

crisp_py/robot/robot_config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class RobotConfig:
2323
cartesian_impedance_controller_name (str): Name of the Cartesian impedance controller
2424
target_pose_topic (str): Topic name for publishing target poses
2525
target_joint_topic (str): Topic name for publishing target joint states
26+
target_stiffness_topic (str): Topic name for publishing target stiffness
2627
current_pose_topic (str): Topic name for subscribing to current poses
2728
current_joint_topic (str): Topic name for subscribing to current joint states
2829
publish_frequency (float): Frequency for publishing control commands
@@ -46,6 +47,7 @@ class RobotConfig:
4647

4748
target_pose_topic: str = "target_pose"
4849
target_joint_topic: str = "target_joint"
50+
target_stiffness_topic: str = "target_stiffness"
4951
current_pose_topic: str = "current_pose"
5052
current_joint_topic: str = "joint_states"
5153
current_twist_topic: str = "current_twist"

examples/21_variable_stiffness.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Example demonstrating runtime variable stiffness for the Cartesian impedance controller.
2+
3+
This script shows how to change the impedance stiffness at runtime using the
4+
variable stiffness topic. The robot maintains its current position while the
5+
stiffness is changed from high to medium to low.
6+
7+
Requirements:
8+
- The cartesian impedance controller must be active
9+
"""
10+
11+
from crisp_py.robot import make_robot
12+
13+
robot = make_robot("fr3")
14+
robot.wait_until_ready()
15+
16+
# Switch to cartesian impedance controller
17+
robot.controller_switcher_client.switch_controller("cartesian_impedance_controller")
18+
19+
print("Robot ready. Maintaining current position.")
20+
print()
21+
22+
# High stiffness (current working values)
23+
print("Setting HIGH stiffness: translational=[900, 900, 900], rotational=[45, 45, 45]")
24+
robot.set_stiffness(translational=[900.0, 900.0, 900.0], rotational=[45.0, 45.0, 45.0])
25+
input("Press Enter to switch to MEDIUM stiffness...")
26+
27+
# Medium stiffness
28+
print("Setting MEDIUM stiffness: translational=[300, 300, 300], rotational=[15, 15, 15]")
29+
robot.set_stiffness(translational=[300.0, 300.0, 300.0], rotational=[15.0, 15.0, 15.0])
30+
input("Press Enter to switch to LOW stiffness...")
31+
32+
# Low stiffness
33+
print("Setting LOW stiffness: translational=[50, 50, 50], rotational=[5, 5, 5]")
34+
robot.set_stiffness(translational=[50.0, 50.0, 50.0], rotational=[5.0, 5.0, 5.0])
35+
input("Press Enter to exit...")
36+
37+
robot.shutdown()

0 commit comments

Comments
 (0)