Repository navigation
Payload-dependent arm sag during manipulation: URDF-based gravity compensation does not account for grasped objects #555
Replies: 3 comments
|
Discord: https://discord.com/channels/1339899404546740275/1527729227854516425/1527729227854516425 |
|
Would this be helpful as a reference: enactic/openarm_ros2#72 ? |
|
I run VLA policies on OpenArm too, and this pattern is expected with your setup. Here's what I'd do, in order. 1. Fix the unloaded feed-forward first ( With a global scale of 0.5, the PD loop is already holding half of the arm's own weight before any payload is added. Each joint then settles at an offset of roughly Δq ≈ τ_missing / kp. Rough numbers with your gains:
So the payload sits on top of an error that's already there. Rather than tuning 2. Add the payload to the feed-forward when the gripper closes (Q1) The sign-safe way is a Jacobian term rather than editing link inertias: Here In KDL, append a fixed TCP segment to the chain, use 3. Estimate After the lift, while the arm is near-static (|q̇| small), average the residual over ~0.3–0.5 s: Use the shoulder and elbow joints for this. They have the lever arm and the best signal-to-noise; the wrist DM4310 torque estimates are noisy. Clamp m̂ to a sane range, and reset it to 0 when the gripper opens. A point mass at the TCP is good enough for the 300–700 g wrenches. CoM offset matters much less than mass at these scales. 4. Gains (Q2) Raising wrist kp helps, but it fights a modelling error instead of removing it. With 15 Hz inference and 16-step chunks, stiffer wrists also make chunk boundaries more visible. I'd fix 1–3 first, then raise wrist kp moderately and re-tune kd toward critical damping (kd ≈ 2√(kp·I_eff)). Step it up while watching motor temperature and any oscillation at chunk switches. I wouldn't trust a single "safe" number across units. 5. Bimanual handover (Q4) Run the estimator independently per arm, and keep it running with a slow low-pass (~0.5 s) while both grippers are closed. Each arm's residual then tracks its own share of the load as it shifts, without assuming a fixed split. One more thing worth checking: if your XR teleop demos were recorded on a follower that also sagged, the actions in the dataset are leader poses. That means the policy has learned around the sag to some extent. After you add payload compensation, a short re-collection or fine-tune on a few heavy-object episodes may help. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
I am running VLA-based manipulation tasks on OpenArm hardware. The VLA predicts desired arm joint positions and gripper positions, while gravity compensation is calculated using KDL ChainDynParam from the robot’s URDF model.
This works correctly when the robot is unloaded or handling very lightweight objects. However, after the robot grasps a heavier object, one or more arm joints sag below their commanded positions.
Tasks tested
I observed the behavior across three VLA manipulation tasks.
The robot picks up a lightweight cube and places it at the target location.
For this task, the existing Pinocchio gravity compensation based on the URDF works reasonably well. There is no significant joint sag because the cube payload is small.
The robot transfers a rectangular box from one arm to the other.
During this task, noticeable sagging occurs while one arm is supporting the box. The behavior can also become more noticeable during the transfer because the payload distribution between the two arms changes.
The commanded joint positions remain approximately the same, but the measured joint positions drop under the additional load.
The robot picks up different steel wrenches weighing approximately 300–700 g and places them in a tray.
After grasping and lifting the wrench, the arm consistently sags. The amount of sag generally becomes more noticeable with the heavier payloads.
Setup / context
I'm running VLA-based (GR00T) manipulation on a bimanual OpenArm v10 hardware setup, on Ubuntu 24.04 with ROS 2 Jazzy, built on the OpenArm ROS 2 stack (
openarm_bringup,openarm_hardware,openarm_can,openarm_description).Control flow:
Gravity comp launch:
ros2 run controller_manager spawner \ right_joint_group_effort_controller left_joint_group_effort_controller \ -c /controller_manager ros2 run openarm_gravity_comp bimanual_gravity_comp_node --ros-args \ -p urdf_path:=$HOME/OPEN_ARM/urdf/v10_bimanual.urdf \ -p publish_effort:=True -p scale:=0.5 -p alpha:=1.0 -p ramp_time:=2.0 \ -p scale_joints:="[1.0,1.0,0.8,1.1,1.0,1.0,1.0]"Training data is collected by XR teleoperation (head + both wrist cameras) into a LeRobot-format bimanual dataset; the policy is trained on and deployed with
--fps 15 --action-horizon 0.15 --exec-steps 16 --rtc.The issue
This works correctly when the robot is unloaded or handling very lightweight objects. However, after the robot grasps a heavier object, one or more arm joints sag below their commanded positions. The commanded joint positions remain approximately the same, but the measured joint positions drop under the additional load. Since the gravity feed-forward is computed from the URDF alone, it knows nothing about the payload, and the PD position loop (especially the wrist joints with kp = 10) is too soft to absorb the extra torque.
Questions
Please let me know if you need more details about my setup (URDF, controller configs, recordings). Thanks in advance!
Can anyone guide me on my approach ? How should i do it ? what's my mistake here and how to solve it?
All reactions