From 22ea4fffcb7021c12cc981115de8f2a58105f2a4 Mon Sep 17 00:00:00 2001 From: RoboticsYY Date: Wed, 18 Dec 2019 10:18:15 +0800 Subject: [PATCH 1/4] Add calibration_state parameter client --- .../handeye_dashboard/handeye_calibration.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/grasp_utils/handeye_dashboard/src/handeye_dashboard/handeye_calibration.py b/grasp_utils/handeye_dashboard/src/handeye_dashboard/handeye_calibration.py index 3462db8..79e9943 100644 --- a/grasp_utils/handeye_dashboard/src/handeye_dashboard/handeye_calibration.py +++ b/grasp_utils/handeye_dashboard/src/handeye_dashboard/handeye_calibration.py @@ -9,6 +9,9 @@ from handeye_tf_service.srv import HandeyeTF from ament_index_python.resources import get_resource +from rcl_interfaces.msg import Parameter, ParameterType, ParameterValue +from rcl_interfaces.srv import SetParameters + # Rqt widgets from rqt_gui_py.plugin import Plugin from python_qt_binding import QtCore @@ -71,6 +74,11 @@ def __init__(self, context): self.widget.setObjectName(self.PLUGIN_TITLE) self.widget.setWindowTitle(self.PLUGIN_TITLE) + # parameter + self.cli_param = self.node.create_client(SetParameters, '/grasp_modbus_server/set_parameters') + while not self.cli_param.wait_for_service(timeout_sec=1.0): + self.node.get_logger().info('service not available, waiting again...') + # Data self.Tsamples = [] @@ -313,6 +321,18 @@ def calibration(self): self.textedit.append("Failed to solve the hand-eye calibration.") def execution(self): + # Set calibration state to success + req = SetParameters.Request() + + param = Parameter() + param.name = "calibration_state" + param.value.type = ParameterType.PARAMETER_INTEGER + param.value.integer_value = 4 + req.parameters.append(param) + + future = self.cli_param.call_async(req) + rclpy.spin_until_future_complete(self.node, future) + # >>> Publish the camera-robot transform self.textedit.append('Publishing the camera TF ...') file_input = '/tmp/' + 'camera-robot.json' From 0f319f2d5eb0ad312c4d3df958212aa38d8e0175 Mon Sep 17 00:00:00 2001 From: RoboticsYY Date: Thu, 2 Jan 2020 18:11:54 +0800 Subject: [PATCH 2/4] Make robot interface shared --- grasp_utils/robot_interface/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grasp_utils/robot_interface/CMakeLists.txt b/grasp_utils/robot_interface/CMakeLists.txt index ab72528..7a1295e 100644 --- a/grasp_utils/robot_interface/CMakeLists.txt +++ b/grasp_utils/robot_interface/CMakeLists.txt @@ -69,7 +69,7 @@ set(${PROJECT_NAME}_SOURCES src/control_base.cpp src/control_ur.cpp ) -add_library(${PROJECT_NAME} ${${PROJECT_NAME}_SOURCES}) +add_library(${PROJECT_NAME} SHARED ${${PROJECT_NAME}_SOURCES}) ament_target_dependencies(${PROJECT_NAME} rclcpp sensor_msgs geometry_msgs tf2_ros) target_link_libraries(${PROJECT_NAME} ${ur_modern_driver_LIBRARIES}) From 15b0ee7f7d447b72301b34a0c8a582cdb1a979cb Mon Sep 17 00:00:00 2001 From: RoboticsYY Date: Thu, 2 Jan 2020 18:56:55 +0800 Subject: [PATCH 3/4] Add function to calculate approaching vectors along X and Y axes --- .../include/robot_interface/control_base.hpp | 5 +++-- .../robot_interface/src/control_base.cpp | 20 +++++++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/grasp_utils/robot_interface/include/robot_interface/control_base.hpp b/grasp_utils/robot_interface/include/robot_interface/control_base.hpp index e72b6fb..83867c1 100644 --- a/grasp_utils/robot_interface/include/robot_interface/control_base.hpp +++ b/grasp_utils/robot_interface/include/robot_interface/control_base.hpp @@ -300,12 +300,13 @@ class ArmControlBase: public rclcpp::Node void updateTFGoal(const geometry_msgs::msg::PoseStamped& pose_stamped); /** - * @brief This function is used to rotate a unit vector along z axis, i.e. (0, 0, 1) by the assigned rpy euler angles. + * @brief This function is used to rotate the three coordinate system axes by the assigned rpy euler angles. * @param alpha Rotation euler angle around X axis. * @param beta Rotation euler angle around Y axis. * @param gamma Rotation euler angle around Z axis. + * @return The rotated axes, dimension 3. */ - Eigen::Vector3d getUnitApproachVector(const double& alpha, const double& beta, const double& gamma); + std::vector getUnitApproachVectors(const double& alpha, const double& beta, const double& gamma); protected: /// Joint state publisher diff --git a/grasp_utils/robot_interface/src/control_base.cpp b/grasp_utils/robot_interface/src/control_base.cpp index 7233e3a..8415646 100644 --- a/grasp_utils/robot_interface/src/control_base.cpp +++ b/grasp_utils/robot_interface/src/control_base.cpp @@ -86,22 +86,30 @@ void ArmControlBase::toTcpPose(const Eigen::Isometry3d& pose, TcpPose& tcp_pose) tcp_pose.gamma = euler_angles[2]; } -Eigen::Vector3d ArmControlBase::getUnitApproachVector(const double& alpha, const double& beta, const double& gamma) +std::vector ArmControlBase::getUnitApproachVectors(const double& alpha, const double& beta, const double& gamma) { tf2::Quaternion q; q.setRPY(alpha, beta, gamma); tf2::Matrix3x3 r(q); - tf2::Vector3 approach_vector = r * tf2::Vector3(0, 0, 1); - approach_vector = approach_vector.normalize(); - return Eigen::Vector3d(approach_vector[0], approach_vector[1], approach_vector[2]); + // get approach_vectors along x, y, z axes + std::vector approach_vectors; + for (size_t i = 0; i < 3; i++) + { + tf2::Vector3 pre_rotation_vector(0, 0, 0); + pre_rotation_vector[i] = 1; + tf2::Vector3 post_rotation_vector = r * pre_rotation_vector; + post_rotation_vector = post_rotation_vector.normalize(); + approach_vectors.push_back(Eigen::Vector3d(post_rotation_vector[0], post_rotation_vector[1], post_rotation_vector[2])); + } + return approach_vectors; } bool ArmControlBase::pick(double x, double y, double z, double alpha, double beta, double gamma, double vel, double acc, double vel_scale, double approach) { - Eigen::Vector3d pre_grasp_origin = Eigen::Vector3d(x, y, z) - getUnitApproachVector(alpha, beta, gamma) * approach; + Eigen::Vector3d pre_grasp_origin = Eigen::Vector3d(x, y, z) - getUnitApproachVectors(alpha, beta, gamma)[2] * approach; Eigen::Isometry3d grasp, orientation, pre_grasp; orientation = Eigen::AngleAxisd(alpha, Eigen::Vector3d::UnitX()) @@ -146,7 +154,7 @@ bool ArmControlBase::place(double x, double y, double z, double alpha, double beta, double gamma, double vel, double acc, double vel_scale, double retract) { - Eigen::Vector3d pre_place_origin = Eigen::Vector3d(x, y, z) - getUnitApproachVector(alpha, beta, gamma) * retract; + Eigen::Vector3d pre_place_origin = Eigen::Vector3d(x, y, z) - getUnitApproachVectors(alpha, beta, gamma)[2] * retract; Eigen::Isometry3d place, orientation, pre_place; orientation = Eigen::AngleAxisd(alpha, Eigen::Vector3d::UnitX()) From bd556eeacbdc12bf94df027767c00ed0332e21c5 Mon Sep 17 00:00:00 2001 From: RoboticsYY Date: Thu, 9 Jan 2020 11:53:16 +0800 Subject: [PATCH 4/4] Add service connection icon to handeye_dashboard --- .../images/green_circle_icon.png | Bin 0 -> 23268 bytes .../images/red_circle_icon.png | Bin 0 -> 22608 bytes .../handeye_dashboard/handeye_calibration.py | 64 +++++++++++++----- 3 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 grasp_utils/handeye_dashboard/images/green_circle_icon.png create mode 100644 grasp_utils/handeye_dashboard/images/red_circle_icon.png diff --git a/grasp_utils/handeye_dashboard/images/green_circle_icon.png b/grasp_utils/handeye_dashboard/images/green_circle_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..eb194807bd1d6fe6f81affa5b886b98a7021f62c GIT binary patch literal 23268 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 XukO;)T{VDSt#aJO<7ka@aN2(Wh*FCT literal 0 HcmV?d00001 diff --git a/grasp_utils/handeye_dashboard/images/red_circle_icon.png b/grasp_utils/handeye_dashboard/images/red_circle_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..94f628cc18b68776b56fd117cc388d16671a3dc3 GIT binary patch literal 22608 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 literal 0 HcmV?d00001 diff --git a/grasp_utils/handeye_dashboard/src/handeye_dashboard/handeye_calibration.py b/grasp_utils/handeye_dashboard/src/handeye_dashboard/handeye_calibration.py index 79e9943..71c2e33 100644 --- a/grasp_utils/handeye_dashboard/src/handeye_dashboard/handeye_calibration.py +++ b/grasp_utils/handeye_dashboard/src/handeye_dashboard/handeye_calibration.py @@ -16,11 +16,10 @@ from rqt_gui_py.plugin import Plugin from python_qt_binding import QtCore from python_qt_binding.QtGui import QIcon, QImage, QPixmap, QStandardItem, \ - QIntValidator, QStandardItemModel + QPen, QBrush, QPainter, QIntValidator, QStandardItemModel from python_qt_binding.QtWidgets import (QComboBox, QAction, QToolBar, QStatusBar, - QLineEdit, QWidget, QVBoxLayout, - QLabel, QTextEdit, QFrame, - QHBoxLayout, QTreeView) + QLineEdit, QWidget, QVBoxLayout, QLabel, + QTextEdit, QFrame, QHBoxLayout, QTreeView) class bcolors: HEADER = '\033[95m' @@ -74,11 +73,6 @@ def __init__(self, context): self.widget.setObjectName(self.PLUGIN_TITLE) self.widget.setWindowTitle(self.PLUGIN_TITLE) - # parameter - self.cli_param = self.node.create_client(SetParameters, '/grasp_modbus_server/set_parameters') - while not self.cli_param.wait_for_service(timeout_sec=1.0): - self.node.get_logger().info('service not available, waiting again...') - # Data self.Tsamples = [] @@ -95,12 +89,27 @@ def __init__(self, context): 'Clear the record data.', self.widget) path = path_pkg + '/share/handeye_dashboard/images/UR5.png' self.execut_action = QAction(QIcon(QPixmap.fromImage(QImage(path))), - 'EStart the publishing the TF.', self.widget) + 'Start the publishing the TF.', self.widget) + self.path_red_icon = path_pkg + '/share/handeye_dashboard/images/red_circle_icon.png' + self.path_green_icon = path_pkg + '/share/handeye_dashboard/images/green_circle_icon.png' + self.parameter_action = QAction(QIcon(QPixmap.fromImage(QImage(self.path_red_icon))), + 'Connect to parameter service.', self.widget) + self.tf_action = QAction(QIcon(QPixmap.fromImage(QImage(self.path_red_icon))), + 'Connect to tf service.', self.widget) + self.toolbar = QToolBar() self.toolbar.addAction(self.snapshot_action) self.toolbar.addAction(self.calibrate_action) self.toolbar.addAction(self.clear_action) self.toolbar.addAction(self.execut_action) + self.parameter_label = QLabel(self.widget) + self.parameter_label.setText("Parameter service: ") + self.toolbar.addWidget(self.parameter_label) + self.toolbar.addAction(self.parameter_action) + self.tf_label = QLabel(self.widget) + self.tf_label.setText("tf service: ") + self.toolbar.addWidget(self.tf_label) + self.toolbar.addAction(self.tf_action) # Toolbar0 self.l0 = QLabel(self.widget) @@ -207,16 +216,37 @@ def __init__(self, context): self.calibrate_action.triggered.connect(self.calibration) self.clear_action.triggered.connect(self.clear) self.execut_action.triggered.connect(self.execution) + self.parameter_action.triggered.connect(self.parameter_connect) + self.tf_action.triggered.connect(self.tf_connect) # Package path self.path_pkg = path_pkg - # Set up TF - self.cli = self.node.create_client(HandeyeTF, 'handeye_tf_service') - while not self.cli.wait_for_service(timeout_sec=1.0): - self.node.get_logger().info('service not available, waiting again...') + # Set up TF service client + self.client_tf = self.node.create_client(HandeyeTF, 'handeye_tf_service') + self.tf_action.setIcon(QIcon(QPixmap.fromImage(QImage(self.path_red_icon))) \ + if not self.client_tf.wait_for_service(timeout_sec=0.5) \ + else QIcon(QPixmap.fromImage(QImage(self.path_green_icon)))) self.req = HandeyeTF.Request() + # Set up parameter service client + self.client_param = self.node.create_client(SetParameters, '/grasp_modbus_server/set_parameters') + self.parameter_action.setIcon(QIcon(QPixmap.fromImage(QImage(self.path_red_icon))) \ + if not self.client_param.wait_for_service(timeout_sec=0.5) \ + else QIcon(QPixmap.fromImage(QImage(self.path_green_icon)))) + + def tf_connect(self): + self.client_tf = self.node.create_client(HandeyeTF, 'handeye_tf_service') + self.tf_action.setIcon(QIcon(QPixmap.fromImage(QImage(self.path_red_icon))) \ + if not self.client_tf.wait_for_service(timeout_sec=0.5) \ + else QIcon(QPixmap.fromImage(QImage(self.path_green_icon)))) + + def parameter_connect(self): + self.client_param = self.node.create_client(SetParameters, '/grasp_modbus_server/set_parameters') + self.parameter_action.setIcon(QIcon(QPixmap.fromImage(QImage(self.path_red_icon))) \ + if not self.client_param.wait_for_service(timeout_sec=0.5) \ + else QIcon(QPixmap.fromImage(QImage(self.path_green_icon)))) + def clear(self): # >>> Clear the recorded samples self.textedit.append('Clearing the recorded data ...') @@ -229,7 +259,7 @@ def get_tf_transform(self, frame_id, child_frame_id): self.req.transform.child_frame_id = child_frame_id self.req.publish.data = False - future = self.cli.call_async(self.req) + future = self.client_tf.call_async(self.req) rclpy.spin_until_future_complete(self.node, future) transform = TransformStamped() @@ -247,7 +277,7 @@ def publish_tf_transform(self, transform_to_publish): self.req.publish.data = True self.req.transform = transform_to_publish - future = self.cli.call_async(self.req) + future = self.client_tf.call_async(self.req) rclpy.spin_until_future_complete(self.node, future) try: @@ -330,7 +360,7 @@ def execution(self): param.value.integer_value = 4 req.parameters.append(param) - future = self.cli_param.call_async(req) + future = self.client_param.call_async(req) rclpy.spin_until_future_complete(self.node, future) # >>> Publish the camera-robot transform