{"id":28061258,"url":"https://github.com/ifl-camp/easy_handeye","last_synced_at":"2025-05-12T09:55:11.027Z","repository":{"id":22132387,"uuid":"95383816","full_name":"IFL-CAMP/easy_handeye","owner":"IFL-CAMP","description":"Automated, hardware-independent Hand-Eye Calibration","archived":false,"fork":false,"pushed_at":"2023-08-03T17:26:40.000Z","size":7137,"stargazers_count":953,"open_issues_count":30,"forks_count":231,"subscribers_count":19,"default_branch":"master","last_synced_at":"2025-05-05T07:40:14.974Z","etag":null,"topics":["calibration","camera","hand-eye","hand-eye-calibration","robot","ros"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IFL-CAMP.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2017-06-25T20:22:05.000Z","updated_at":"2025-05-01T12:50:22.000Z","dependencies_parsed_at":"2024-02-03T12:48:00.785Z","dependency_job_id":null,"html_url":"https://github.com/IFL-CAMP/easy_handeye","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IFL-CAMP%2Feasy_handeye","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IFL-CAMP%2Feasy_handeye/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IFL-CAMP%2Feasy_handeye/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IFL-CAMP%2Feasy_handeye/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IFL-CAMP","download_url":"https://codeload.github.com/IFL-CAMP/easy_handeye/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253711968,"owners_count":21951670,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["calibration","camera","hand-eye","hand-eye-calibration","robot","ros"],"created_at":"2025-05-12T09:55:10.318Z","updated_at":"2025-05-12T09:55:11.007Z","avatar_url":"https://github.com/IFL-CAMP.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# easy_handeye: automated, hardware-independent Hand-Eye Calibration for ROS1\n\n\u003cimg src=\"docs/img/eye_on_base_ndi_pic.png\" width=\"345\"/\u003e \u003cimg src=\"docs/img/05_calibrated_rviz.png\" width=\"475\"/\u003e \n\n\nThis package provides functionality and a GUI to: \n- **sample** the robot position and tracking system output via `tf`,\n- **compute** the eye-on-base or eye-in-hand calibration matrix through the OpenCV library's Tsai-Lenz algorithm \nimplementation,\n- **store** the result of the calibration,\n- **publish** the result of the calibration procedure as a `tf` transform at each subsequent system startup,\n- (optional) automatically **move** a robot around a starting pose via `MoveIt!` to acquire the samples. \n\nThe intended result is to make it easy and straightforward to perform the calibration, and to keep it up-to-date throughout the system. \nTwo launch files are provided to be run, respectively to perform the calibration and check its result. \nA further launch file can be integrated into your own launch files, to make use of the result of the calibration in a transparent way: \nif the calibration is performed again, the updated result will be used without further action required.    \n\nYou can try out this software in a simulator, through the \n[easy_handeye_demo package](https://github.com/marcoesposito1988/easy_handeye_demo). This package also serves as an \nexample for integrating `easy_handeye` into your own launch scripts.\n\n**NOTE:** a (development) ROS2 version of this package is available [here](https://github.com/marcoesposito1988/easy_handeye2)\n\n## News\n- version 0.4.3\n    - documentation and bug fixes\n- version 0.4.2\n    - fixes for the freehand robot movement scenario\n- version 0.4.1\n    - fixed a bug that prevented loading and publishing the calibration - thanks to @lyh458!\n- version 0.4.0\n    - switched to OpenCV as a backend for the algorithm implementation \n    - added UI element to pick the calibration algorithm (Tsai-Lenz, Park, Horaud, Andreff, Daniilidis)\n- version 0.3.1\n    - restored compatibility with Melodic and Kinetic along with Noetic\n- version 0.3.0 \n    - ROS Noetic compatibility\n    - added \"evaluator\" GUI to evaluate the accuracy of the calibration while running `check_calibration.launch`\n \n\n## Use Cases\n\nIf you are unfamiliar with Tsai's hand-eye calibration [1], it can be used in two ways:\n\n- **eye-in-hand** to compute the static transform between the reference frames of\n  a robot's hand effector and that of a tracking system, e.g. the optical frame\n  of an RGB camera used to track AR markers. In this case, the camera is\n  mounted on the end-effector, and you place the visual target so that it is\n  fixed relative to the base of the robot; for example, you can place an AR marker on a table.\n- **eye-on-base** to compute the static transform from a robot's base to a tracking system, e.g. the\n  optical frame of a camera standing on a tripod next to the robot. In this case you can attach a marker,\n  e.g. an AR marker, to the end-effector of the robot.\n  \nA relevant example of an eye-on-base calibration is finding the position of an RGBD camera with respect to a robot for object collision avoidance, e.g. [with MoveIt!](http://docs.ros.org/indigo/api/moveit_tutorials/html/doc/pr2_tutorials/planning/src/doc/perception_configuration.html): an [example launch file](docs/example_launch/ur5_kinect_calibration.launch) is provided to perform this common task between an Universal Robot and a Kinect through aruco. eye-on-hand can be used for [vision-guided tasks](https://youtu.be/nBTflbxYGkI?t=24s).\n\nThe (arguably) best part is, that you do not have to care about the placement of the auxiliary marker\n(the one on the table in the eye-in-hand case, or on the robot in the eye-on-base case). The algorithm\nwill \"erase\" that transformation out, and only return the transformation you are interested in.\n\n\neye-on-base             |  eye-on-hand\n:-------------------------:|:-------------------------:\n![](docs/img/eye_on_base_aruco_pic.png)  |  ![](docs/img/eye_on_hand_aruco_pic.png)\n\n## Getting started\n\n- clone this repository into your catkin workspace:\n```\ncd ~/catkin_ws/src  # replace with path to your workspace\ngit clone https://github.com/IFL-CAMP/easy_handeye\n```\n\n- satisfy dependencies\n```\ncd ..  # now we are inside ~/catkin_ws\nrosdep install -iyr --from-paths src\n```\n\n- build\n```\ncatkin build\n```\n\n## Usage\n\nTwo launch files, one for computing and one for publishing the calibration respectively,\nare provided to be included in your own. The default arguments should be\noverridden to specify the correct tf reference frames, and to avoid conflicts when using\nmultiple calibrations at once.\n\nThe suggested integration is:\n- create a new `handeye_calibrate.launch` file, which includes the robot's and tracking system's launch files, as well as \n`easy_handeye`'s `calibrate.launch` as illustrated below in the next section \"Calibration\"\n- in each of your launch files where you need the result of the calibration, include `easy_handeye`'s `publish.launch` \nas illustrated below in the section \"Publishing\" \n\n### Calibration\n\nFor both use cases, you can either launch the `calibrate.launch`\nlaunch file, or you can include it in another launchfile as shown below. Either\nway, the launch file will bring up a calibration script. By default, the script will interactively ask you\nto accept or discard each sample. At the end, the parameters will be saved in a yaml file.\n\n#### eye-in-hand\n\n```xml\n\u003claunch\u003e\n  \u003c!-- (start your robot's MoveIt! stack, e.g. include its moveit_planning_execution.launch) --\u003e\n  \u003c!-- (start your tracking system's ROS driver) --\u003e\n\n  \u003cinclude file=\"$(find easy_handeye)/launch/calibrate.launch\"\u003e\n    \u003carg name=\"eye_on_hand\" value=\"true\"/\u003e\n\n    \u003c!-- you can choose any identifier, as long as you use the same for publishing the calibration --\u003e\n    \u003carg name=\"namespace_prefix\" value=\"my_eih_calib\"/\u003e\n\n    \u003c!-- fill in the following parameters according to your robot's published tf frames --\u003e\n    \u003carg name=\"robot_base_frame\" value=\"/base_link\"/\u003e\n    \u003carg name=\"robot_effector_frame\" value=\"/ee_link\"/\u003e\n\n    \u003c!-- fill in the following parameters according to your tracking system's published tf frames --\u003e\n    \u003carg name=\"tracking_base_frame\" value=\"/optical_origin\"/\u003e\n    \u003carg name=\"tracking_marker_frame\" value=\"/optical_target\"/\u003e\n  \u003c/include\u003e\n\u003c/launch\u003e\n```\n\n#### eye-on-base\n\n```xml\n\u003claunch\u003e\n  \u003c!-- (start your robot's MoveIt! stack, e.g. include its moveit_planning_execution.launch) --\u003e\n  \u003c!-- (start your tracking system's ROS driver) --\u003e\n\n  \u003cinclude file=\"$(find easy_handeye)/launch/calibrate.launch\"\u003e\n    \u003carg name=\"eye_on_hand\" value=\"false\"/\u003e\n    \u003carg name=\"namespace_prefix\" value=\"my_eob_calib\"/\u003e\n\n    \u003c!-- fill in the following parameters according to your robot's published tf frames --\u003e\n    \u003carg name=\"robot_base_frame\" value=\"/base_link\"/\u003e\n    \u003carg name=\"robot_effector_frame\" value=\"/ee_link\"/\u003e\n\n    \u003c!-- fill in the following parameters according to your tracking system's published tf frames --\u003e\n    \u003carg name=\"tracking_base_frame\" value=\"/optical_origin\"/\u003e\n    \u003carg name=\"tracking_marker_frame\" value=\"/optical_target\"/\u003e\n  \u003c/include\u003e\n\u003c/launch\u003e\n```\n\n\n#### Moving the robot\n\nA GUI for automatic robot movement is provided by the `rqt_easy_handeye` package. Please refer to [its documentation](rqt_easy_handeye/README.md).\n\nThis is optional, and can be disabled in both aforementioned cases with:\n```xml\n\u003claunch\u003e\n  \u003cinclude file=\"$(find easy_handeye)/launch/calibrate.launch\"\u003e\n      \u003c!-- other arguments, as described above... --\u003e\n      \n      \u003carg name=\"freehand_robot_movement\" value=\"true\" /\u003e\n  \u003c/include\u003e\n\u003c/launch\u003e\n```\n\nIt will then be the user's responsibility to make the robot publish its own pose into `tf`. Please check that the robot's pose is updated correctly in \nRViz before starting to acquire samples (the robot driver may not work while the teaching mode button is pressed, etc).\n\nThe same applies to the validity of the samples. For the calibration to be found reliably, the end effector must be rotated as much as possible \n(up to 90°) about each axis, in both directions. Translating the end effector is not necessary, but can't hurt either.\n\n\u003cimg src=\"docs/img/02_plan_movements.png\" width=\"345\"/\u003e \u003cimg src=\"docs/img/04_plan_show.png\" width=\"495\"/\u003e\n\n#### Tips for accuracy\n\nThe following tips are given in [1], paragraph 1.3.2.\n\n- Maximize rotation between poses.\n- Minimize the distance from the target to the camera of the tracking system.\n- Minimize the translation between poses.\n- Use redundant poses.\n- Calibrate the camera intrinsics if necessary / applicable.\n- Calibrate the robot if necessary / applicable.\n\n### Publishing\nThe `publish.launch` starts a node that publishes the transformation found during calibration in `tf`.\nThe parameters are automatically loaded from the yaml file, according to the specified namespace.\nFor convenience, you can include this file within your own launch script. You can include this file multiple times to \npublish many calibrations simultaneously; the following example publishes one eye-on-base and one eye-in-hand calibration:\n```xml\n\u003claunch\u003e\n  \u003c!-- (start your robot's MoveIt! stack, e.g. include its moveit_planning_execution.launch) --\u003e\n  \u003c!-- (start your tracking system's ROS driver) --\u003e\n\n  \u003cinclude file=\"$(find easy_handeye)/launch/publish.launch\"\u003e\n    \u003carg name=\"namespace_prefix\" value=\"my_eob_calib\"/\u003e \u003c!-- use the same namespace that you used during calibration! --\u003e\n  \u003c/include\u003e\n  \u003cinclude file=\"$(find easy_handeye)/launch/publish.launch\"\u003e\n    \u003carg name=\"namespace_prefix\" value=\"my_eih_calib\"/\u003e \u003c!-- use the same namespace that you used during calibration! --\u003e\n  \u003c/include\u003e\n\u003c/launch\u003e\n```\nYou can have any number of calibrations at once (provided you specify distinct namespaces). \nIf you perform again any calibration, you do not need to do anything: the next time you start the system, \nthe publisher will automatically fetch the latest information. You can also manually restart the publisher \nnodes (e.g. with `rqt_launch`), if you don't want to shut down the whole system.\n\n### FAQ\n#### Why is the calibration wrong?\nPlease check the [troubleshooting](docs/troubleshooting.md)\n\n#### How can I ...\n##### Calibrate an RGBD camera (e.g. Kinect, Xtion, ...) with a robot for automatic object collision avoidance with MoveIt! ?\nThis is a perfect example of an eye-on-base calibration. You can take a look at this [example launch file](docs/example_launch/ur5_kinect_calibration.launch) written for an UR5 and a Kinect via aruco_ros, or [example for LWR iiwa with Xtion/Kinect ](docs/example_launch/iiwa_kinect_xtion_calibration.launch).\n##### Disable the automatic robotic movements GUI?\nYou can pass the argument `freehand_robot_movement:=true` to `calibrate.launch`.\n##### Calibrate one robot against multiple tracking systems?\nYou can just override the `namespace` argument of `calibrate.launch` to be always different, such that they will never collide. Using the same `namespace` as argument to multiple inclusions of `publish.launch` will allow you to publish each calibration in `tf`.\n##### Find the transformation between the bases of two robots?\nYou could perform the eye-on-base calibration against the same tracking system, and concatenate the results.\n##### Find the transformation between two tracking systems?\nYou could perform the eye-on-base calibration against the same robot, and concatenate the results. This will work also if the tracking systems are completely different and do not use the same markers.\n\n## References\n\n[1] *Tsai, Roger Y., and Reimar K. Lenz. \"A new technique for fully autonomous\nand efficient 3D robotics hand/eye calibration.\" Robotics and Automation, IEEE\nTransactions on 5.3 (1989): 345-358.*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fifl-camp%2Feasy_handeye","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fifl-camp%2Feasy_handeye","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fifl-camp%2Feasy_handeye/lists"}