moveit2
The MoveIt Motion Planning Framework for ROS 2.
pose_tracking_test.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2020, PickNik Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of PickNik Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Andy Zelenak
36  Desc: Test of tracking toward a pose
37 */
38 
39 // C++
40 #include <string>
41 #include <thread>
42 
43 // ROS
44 #include <rclcpp/rclcpp.hpp>
45 
46 // Testing
47 #include <gtest/gtest.h>
48 
49 // Servo
53 
54 static const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit_servo.pose_tracking_test");
55 
56 static constexpr double TRANSLATION_TOLERANCE = 0.01; // meters
57 static constexpr double ROTATION_TOLERANCE = 0.1; // quaternion
58 
59 namespace moveit_servo
60 {
61 class PoseTrackingFixture : public ::testing::Test
62 {
63 public:
64  void SetUp() override
65  {
66  executor_->add_node(node_);
67  executor_thread_ = std::thread([this]() { this->executor_->spin(); });
68 
70  ;
71  if (servo_parameters_ == nullptr)
72  {
73  RCLCPP_FATAL(LOGGER, "Could not get servo parameters!");
74  exit(EXIT_FAILURE);
75  }
76 
77  // store test constants as shared pointer to constant struct
78  {
79  auto test_parameters = std::make_shared<struct TestParameters>();
80  test_parameters->publish_hz = 2.0 / servo_parameters_->incoming_command_timeout;
81  test_parameters->publish_period = 1.0 / test_parameters->publish_hz;
82  test_parameters->timeout_iterations = 10 * test_parameters->publish_hz;
83  test_parameters_ = test_parameters;
84  }
85 
86  // Load the planning scene monitor
87  if (!planning_scene_monitor_->getPlanningScene())
88  {
89  RCLCPP_ERROR_STREAM(LOGGER, "Error in setting up the PlanningSceneMonitor.");
90  exit(EXIT_FAILURE);
91  }
92 
93  planning_scene_monitor_->providePlanningSceneService();
94  planning_scene_monitor_->startSceneMonitor();
95  planning_scene_monitor_->startWorldGeometryMonitor(
98  false /* skip octomap monitor */);
99  planning_scene_monitor_->startStateMonitor(servo_parameters_->joint_topic);
101 
102  // Wait for Planning Scene Monitor to setup
103  if (!planning_scene_monitor_->waitForCurrentRobotState(node_->now(), 5.0 /* seconds */))
104  {
105  RCLCPP_ERROR_STREAM(LOGGER, "Error waiting for current robot state in PlanningSceneMonitor.");
106  exit(EXIT_FAILURE);
107  }
108 
109  tracker_ = std::make_shared<moveit_servo::PoseTracking>(node_, servo_parameters_, planning_scene_monitor_);
110 
111  // Tolerance for pose seeking
112  translation_tolerance_ << TRANSLATION_TOLERANCE, TRANSLATION_TOLERANCE, TRANSLATION_TOLERANCE;
113  }
114 
116  : node_(std::make_shared<rclcpp::Node>("pose_tracking_testing"))
117  , executor_(std::make_shared<rclcpp::executors::SingleThreadedExecutor>())
119  std::make_shared<planning_scene_monitor::PlanningSceneMonitor>(node_, "robot_description"))
120  {
121  // Init ROS interfaces
122  // Publishers
123  target_pose_pub_ = node_->create_publisher<geometry_msgs::msg::PoseStamped>("target_pose", 1);
124  }
125 
126  void TearDown() override
127  {
128  executor_->cancel();
129  if (executor_thread_.joinable())
130  executor_thread_.join();
131  }
132 
133 protected:
134  rclcpp::Node::SharedPtr node_;
135  rclcpp::Executor::SharedPtr executor_;
136  std::thread executor_thread_;
137 
139  planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor_;
140 
142  {
143  double publish_hz;
146  };
147  std::shared_ptr<const struct TestParameters> test_parameters_;
148 
150 
152  rclcpp::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr target_pose_pub_;
153 }; // class PoseTrackingFixture
154 
155 // Check for commands going out to ros_control
156 TEST_F(PoseTrackingFixture, OutgoingMsgTest)
157 {
158  // halt Servoing when first msg to ros_control is received
159  // and test some conditions
160  trajectory_msgs::msg::JointTrajectory last_received_msg;
161  std::function<void(const trajectory_msgs::msg::JointTrajectory::ConstSharedPtr)> traj_callback =
162  [&/* this */](const trajectory_msgs::msg::JointTrajectory::ConstSharedPtr& msg) {
163  EXPECT_EQ(msg->header.frame_id, "panda_link0");
164 
165  // Exact joint positions may vary based on IK solver
166  // so check that the EE transform is as expected
167  moveit::core::RobotStatePtr temp_state(planning_scene_monitor_->getStateMonitor()->getCurrentState());
168  const std::string group_name = "panda_arm";
169  // copyJointGroupPositions can't take a const vector, make a copy
170  std::vector<double> positions(msg->points[0].positions);
171  temp_state->copyJointGroupPositions(group_name, positions);
172  Eigen::Isometry3d hand_tf = temp_state->getFrameTransform("panda_hand");
173 
174  moveit::core::RobotStatePtr test_state(planning_scene_monitor_->getStateMonitor()->getCurrentState());
175  std::vector<double> test_positions = { 0, -0.785, 0, -2.360, 0, 1.571, 0.758 };
176  test_state->copyJointGroupPositions(group_name, test_positions);
177  Eigen::Isometry3d test_hand_tf = test_state->getFrameTransform("panda_hand");
178 
179  double precision = 0.02; // Hilbert-Schmidt norm
180  EXPECT_TRUE(test_hand_tf.isApprox(hand_tf, precision));
181 
182  this->tracker_->stopMotion();
183  return;
184  };
185  auto traj_sub = node_->create_subscription<trajectory_msgs::msg::JointTrajectory>(
186  "/panda_arm_controller/joint_trajectory", rclcpp::SystemDefaultsQoS(), traj_callback);
187 
188  geometry_msgs::msg::PoseStamped target_pose;
189  target_pose.header.frame_id = "panda_link4";
190  target_pose.header.stamp = node_->now();
191  target_pose.pose.position.x = 0.2;
192  target_pose.pose.position.y = 0.2;
193  target_pose.pose.position.z = 0.2;
194  target_pose.pose.orientation.w = 1;
195 
196  // Republish the target pose in a new thread, as if the target is moving
197  std::thread target_pub_thread([&] {
198  size_t msg_count = 0;
199  rclcpp::WallRate loop_rate(50);
200  while (++msg_count < 100)
201  {
202  target_pose_pub_->publish(target_pose);
203  loop_rate.sleep();
204  }
205  });
206 
207  // resetTargetPose() can be used to clear the target pose and wait for a new one, e.g. when moving between multiple waypoints
208  tracker_->resetTargetPose();
209 
210  tracker_->moveToPose(translation_tolerance_, ROTATION_TOLERANCE, 1 /* target pose timeout */);
211 
212  target_pub_thread.join();
213 }
214 
215 } // namespace moveit_servo
216 
217 int main(int argc, char** argv)
218 {
219  rclcpp::init(argc, argv);
220  ::testing::InitGoogleTest(&argc, argv);
221 
222  int result = RUN_ALL_TESTS();
223  rclcpp::shutdown();
224  return result;
225 }
std::shared_ptr< const struct TestParameters > test_parameters_
rclcpp::Executor::SharedPtr executor_
rclcpp::Publisher< geometry_msgs::msg::PoseStamped >::SharedPtr target_pose_pub_
moveit_servo::PoseTrackingPtr tracker_
moveit_servo::ServoParameters::SharedConstPtr servo_parameters_
planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor_
static const std::string DEFAULT_COLLISION_OBJECT_TOPIC
The name of the topic used by default for receiving collision objects in the world.
Vec3fX< details::Vec3Data< double > > Vector3d
Definition: fcl_compat.h:89
std::shared_ptr< PoseTracking > PoseTrackingPtr
TEST_F(PoseTrackingFixture, OutgoingMsgTest)
const rclcpp::Logger LOGGER
Definition: async_test.h:31
int main(int argc, char **argv)
std::shared_ptr< const ServoParameters > SharedConstPtr
static SharedConstPtr makeServoParameters(const rclcpp::Node::SharedPtr &node, const std::string &ns="moveit_servo", bool dynamic_parameters=true)