6-DOF force-compliant motion control for Universal Robots with gravity compensation. See docs/dependencies.md for detailed package dependencies.
Clone dependencies:
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
git clone https://github.com/ajaygunalan/ur_simulation_gz.git
git clone https://github.com/ajaygunalan/ur_admittance_controller.gitInstall dependencies:
cd ~/ur_ws && rosdep install --from-paths src --ignore-src -r -yBuild simulation:
colcon build --packages-select ur_simulation_gz && source install/setup.bashBuild controller:
colcon build --packages-select ur_admittance_controller && source install/setup.bashLaunch robot:
ros2 launch ur_simulation_gz ur_sim_control.launch.py ur_type:=ur5eInitialize to equilibrium:
ros2 run ur_admittance_controller init_robotRun calibration (one-time):
ros2 run ur_admittance_controller wrench_calibration_nodeSwitch controller:
ros2 control switch_controllers --deactivate scaled_joint_trajectory_controller --activate forward_velocity_controllerStart wrench node:
ros2 run ur_admittance_controller wrench_nodeStart admittance node:
ros2 run ur_admittance_controller admittance_node[F/T Sensor] → [Wrench Node] → [Admittance Node] → [Robot]
↓ ↓ ↓
(Gravity Compensation) (M·ẍ+D·ẋ+K·x=F) (Velocity Commands)
- Init Robot: Moves to equilibrium, saves pose to config
- Wrench Calibration: Estimates gravity/bias parameters (LROM method)
- Wrench Node: Compensates F/T data for gravity and transforms to base frame
- Admittance Node: Implements admittance control law, outputs joint velocities
The controller implements: M·ẍ + D·ẋ + K·x = F
Where:
- F = External force (from wrench_node)
- x = Position error from equilibrium
- ẋ = Velocity
- ẍ = Acceleration
System Behavior:
-
Normal Operation (wrench_node running, F ≠ 0):
- Equation: M·ẍ + D·ẋ + K·x = F
- Behavior: Robot moves proportionally to applied force
- Equilibrium: Robot finds new position where K·x balances F
-
When wrench_node is OFF (F = 0):
- Equation becomes: M·ẍ + D·ẋ + K·x = 0
- Behavior: Pure spring-damper system
- Robot always returns to equilibrium position
-
Pure Admittance Mode (set K = 0):
- Equation: M·ẍ + D·ẋ = F
- Behavior: No position preference, robot drifts with force
- Warning: Robot won't return to any position
Quick Diagnostics:
# Check if force data exists (is wrench_node running?)
ros2 topic echo /netft/proc_probe_base --once
# Test pure admittance (removes position control)
ros2 param set /admittance_node admittance.stiffness '[0.0,0.0,0.0,0.0,0.0,0.0]'
# View current control parameters
ros2 param get /admittance_node admittance.stiffnessCheck if calibration is working:
# Raw sensor data (before compensation)
ros2 topic echo /netft/raw_sensor --once
# Expected: Force ~[0, 0, -9.8]N (gravity), Torque ~[0, 0, 0]Nm
# Processed sensor data (after compensation)
ros2 topic echo /netft/proc_sensor --once
# Expected: Force <1N all axes (gravity compensated), Torque <0.02NmWhat the values mean:
- Raw sensor: Shows gravity (~9.8N downward) plus any external forces
- Processed sensor: Should be near zero when no external force applied
- Good calibration: 90%+ gravity reduction (9.8N → <1N)
config/equilibrium.yaml- Robot equilibrium pose (generated by init_robot)config/wrench_calibration.yaml- Calibration parameters (generated by calibration)config/admittance_config.yaml- Control parameters (M/K/D matrices)
See docs/debugging.md for debugging with VS Code.