EyeInHandCalibration.md
April 29, 2026 ยท View on GitHub
Optional Automatic Eye-in-Hand Stereo Calibration Routine for Manipulator (Arm) Payload
Collect Calibration
An optional custom Automatic Eye-in-Hand Stereo Calibration Routine for the arm is available for use in the spot_wrapper submodule, where the
output results can be used with ROS 2 for improved Depth to RGB correspondence for the hand cameras.
See the readme at /spot_wrapper/spot_wrapper/calibration/README.md for full instructions.
[Optional] Run the Calibrated Re-Publisher
The following command can be used to spin up a node to publish your newly calculated calibration. This was necessary before the release of Boston Dynamic's SDK 5.0.0 in order to use this calibration instead of the one saved on the robot hardware. While no longer necessary (SDK 5.0.0 allowed users to overwrite the robot's internal calibration), it is helpful for visualizing your new calibration for a quick sanity check.
Note
The default tag is default.
ros2 run spot_driver calibrated_reregistered_hand_camera_depth_publisher.py --tag=<TAG> --calibration_path\
<SAVED_CAL> --robot_name <ROBOT_NAMESPACE> --topic depth_registered/hand_custom_cal/image
You can treat the reregistered topic, (in the above example, <ROBOT_NAME>/depth_registered/hand_custom_cal/image)
as a drop in replacement by the registered image published by the default spot driver
(<ROBOT_NAME>/depth_registered/hand/image). The registered depth can be easily used in tools
like downstream, like Open3d, (see creating RGBD Images and creating color point clouds from RGBD Images), due to matching image dimensions and registration
to a shared frame.
Comparing Calibration Results Quick Sanity Check
You can validate calibration results by visualizing colored point clouds (i.e. RGBD registration results) in RViz.
First, collect a bag where there is a an object of a clearly different color in the foreground then that of the background.
ROBOT_NAME=<ROBOT_NAME> && \
ros2 bag record --output drop_in_test --topics /tf /tf_static \
/${ROBOT_NAME}/depth/hand/image /${ROBOT_NAME}/camera/hand/camera_info \
/${ROBOT_NAME}/joint_states /${ROBOT_NAME}/camera/hand/image \
/${ROBOT_NAME}/depth_registered/hand/image
To see what the default calibration looks like:
# In seperate terminals
ros2 bag play drop_in_test --loop
ROBOT_NAME=<ROBOT_NAME> && \
ros2 launch spot_driver point_cloud_xyzrgb.launch.py spot_name:=${ROBOT_NAME} camera:=hand
To see what the new calibration looks like:
# In seperate terminals
ROBOT_NAME=<ROBOT_NAME> && \
ros2 bag play drop_in_test --loop --topics /${ROBOT_NAME}/depth/hand/image \
/${ROBOT_NAME}/camera/hand/camera_info /${ROBOT_NAME}/joint_states \
/${ROBOT_NAME}/camera/hand/image /tf /tf_static
ROBOT_NAME=<ROBOT_NAME> && \
CALIBRATION_PATH=<CALIBRATION_PATH> && \
ros2 run spot_driver calibrated_reregistered_hand_camera_depth_publisher.py --robot_name ${ROBOT_NAME} \
--calibration_path ${CALIBRATION_PATH} --topic depth_registered/hand/image
ROBOT_NAME=<ROBOT_NAME> && \
ros2 launch spot_driver point_cloud_xyzrgb.launch.py spot_name:=${ROBOT_NAME} camera:=hand
RVIZ Setup for Sanity Check
Set global frame to be /<ROBOT_NAME>/hand
Add (bottom left) -> by topic ->
/<ROBOT_NAME>/depth_registered/hand/points -> ok
On the left pane, expand the PointCloud2 message. Expand Topic. Set History Policy to be Keep Last, Reliability Policy to be Best Effort, and Durability policy to be Volatile (select these from the dropdowns).