moveit2
The MoveIt Motion Planning Framework for ROS 2.
demo_pose.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * BSD 3-Clause License
3  *
4  * Copyright (c) 2023, 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 are met:
9  *
10  * * Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *******************************************************************************/
33 
34 /* Title : demo_pose.cpp
35  * Project : moveit_servo
36  * Created : 06/07/2023
37  * Author : V Mohammed Ibrahim
38  * Description : Example of controlling a robot through pose commands via the C++ API.
39  */
40 
41 #include <atomic>
42 #include <chrono>
43 #include <moveit_servo/servo.hpp>
45 #include <mutex>
46 #include <rclcpp/rclcpp.hpp>
47 #include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
48 #include <tf2_ros/transform_listener.h>
49 #include <moveit/utils/logger.hpp>
50 
51 using namespace moveit_servo;
52 
53 namespace
54 {
55 constexpr auto K_BASE_FRAME = "panda_link0";
56 constexpr auto K_TIP_FRAME = "panda_link8";
57 } // namespace
58 
59 int main(int argc, char* argv[])
60 {
61  rclcpp::init(argc, argv);
62 
63  // The servo object expects to get a ROS node.
64  const rclcpp::Node::SharedPtr demo_node = std::make_shared<rclcpp::Node>("moveit_servo_demo");
65  moveit::setNodeLoggerName(demo_node->get_name());
66 
67  // Get the servo parameters.
68  const std::string param_namespace = "moveit_servo";
69  const std::shared_ptr<const servo::ParamListener> servo_param_listener =
70  std::make_shared<const servo::ParamListener>(demo_node, param_namespace);
71  const servo::Params servo_params = servo_param_listener->get_params();
72 
73  // The publisher to send trajectory message to the robot controller.
74  rclcpp::Publisher<trajectory_msgs::msg::JointTrajectory>::SharedPtr trajectory_outgoing_cmd_pub =
75  demo_node->create_publisher<trajectory_msgs::msg::JointTrajectory>(servo_params.command_out_topic,
76  rclcpp::SystemDefaultsQoS());
77 
78  // Create the servo object
79  const planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor =
80  createPlanningSceneMonitor(demo_node, servo_params);
81  Servo servo = Servo(demo_node, servo_param_listener, planning_scene_monitor);
82 
83  // Helper function to get the current pose of a specified frame.
84  const auto get_current_pose = [](const std::string& target_frame, const moveit::core::RobotStatePtr& robot_state) {
85  return robot_state->getGlobalLinkTransform(target_frame);
86  };
87 
88  // Wait for some time, so that the planning scene is loaded in rviz.
89  // This is just for convenience, should not be used for sync in real application.
90  std::this_thread::sleep_for(std::chrono::seconds(3));
91 
92  // Get the robot state and joint model group info.
93  auto robot_state = planning_scene_monitor->getStateMonitor()->getCurrentState();
94  const moveit::core::JointModelGroup* joint_model_group =
95  robot_state->getJointModelGroup(servo_params.move_group_name);
96 
97  // Set the command type for servo.
99 
100  // The dynamically updated target pose.
101  PoseCommand target_pose;
102  target_pose.frame_id = K_BASE_FRAME;
103 
104  // Initializing the target pose as end effector pose, this can be any pose.
105  target_pose.pose = get_current_pose(K_TIP_FRAME, robot_state);
106 
107  // servo loop will exit upon reaching this pose.
108  Eigen::Isometry3d terminal_pose = target_pose.pose;
109  terminal_pose.rotate(Eigen::AngleAxisd(M_PI / 4, Eigen::Vector3d::UnitZ()));
110  terminal_pose.translate(Eigen::Vector3d(0.0, 0.0, -0.1));
111 
112  // The target pose (frame being tracked) moves by this step size each iteration.
113  Eigen::Vector3d linear_step_size{ 0.0, 0.0, -0.001 };
114  Eigen::AngleAxisd angular_step_size(0.01, Eigen::Vector3d::UnitZ());
115 
116  RCLCPP_INFO_STREAM(demo_node->get_logger(), servo.getStatusMessage());
117 
118  rclcpp::WallRate servo_rate(1 / servo_params.publish_period);
119 
120  // create command queue to build trajectory message and add current robot state
121  std::deque<KinematicState> joint_cmd_rolling_window;
122  KinematicState current_state = servo.getCurrentRobotState();
123  updateSlidingWindow(current_state, joint_cmd_rolling_window, servo_params.max_expected_latency, demo_node->now());
124 
125  bool satisfies_linear_tolerance = false;
126  bool satisfies_angular_tolerance = false;
127  bool stop_tracking = false;
128  while (!stop_tracking && rclcpp::ok())
129  {
130  // check if goal reached
131  target_pose.pose = get_current_pose(K_TIP_FRAME, robot_state);
132  satisfies_linear_tolerance |= target_pose.pose.translation().isApprox(terminal_pose.translation(),
133  servo_params.pose_tracking.linear_tolerance);
134  satisfies_angular_tolerance |=
135  target_pose.pose.rotation().isApprox(terminal_pose.rotation(), servo_params.pose_tracking.angular_tolerance);
136  stop_tracking = satisfies_linear_tolerance && satisfies_angular_tolerance;
137 
138  // Dynamically update the target pose.
139  if (!satisfies_linear_tolerance)
140  {
141  target_pose.pose.translate(linear_step_size);
142  }
143  if (!satisfies_angular_tolerance)
144  {
145  target_pose.pose.rotate(angular_step_size);
146  }
147 
148  // get next servo command
149  KinematicState joint_state = servo.getNextJointState(robot_state, target_pose);
150  StatusCode status = servo.getStatus();
151  if (status != StatusCode::INVALID)
152  {
153  updateSlidingWindow(joint_state, joint_cmd_rolling_window, servo_params.max_expected_latency, demo_node->now());
154  if (const auto msg = composeTrajectoryMessage(servo_params, joint_cmd_rolling_window))
155  {
156  trajectory_outgoing_cmd_pub->publish(msg.value());
157  }
158  if (!joint_cmd_rolling_window.empty())
159  {
160  robot_state->setJointGroupPositions(joint_model_group, joint_cmd_rolling_window.back().positions);
161  robot_state->setJointGroupVelocities(joint_model_group, joint_cmd_rolling_window.back().velocities);
162  }
163  }
164 
165  servo_rate.sleep();
166  }
167 
168  RCLCPP_INFO_STREAM(demo_node->get_logger(), "REACHED : " << stop_tracking);
169  RCLCPP_INFO(demo_node->get_logger(), "Exiting demo.");
170  rclcpp::shutdown();
171 }
void setCommandType(const CommandType &command_type)
Set the type of incoming servo command.
Definition: servo.cpp:335
std::string getStatusMessage() const
Get the message associated with the current servo status.
Definition: servo.cpp:325
KinematicState getCurrentRobotState() const
Get the current state of the robot as given by planning scene monitor.
Definition: servo.cpp:650
StatusCode getStatus() const
Get the current status of servo.
Definition: servo.cpp:320
KinematicState getNextJointState(const moveit::core::RobotStatePtr &robot_state, const ServoInput &command)
Computes the joint state required to follow the given command.
Definition: servo.cpp:473
int main(int argc, char *argv[])
Definition: demo_pose.cpp:59
Vec3fX< details::Vec3Data< double > > Vector3d
Definition: fcl_compat.h:89
std::optional< trajectory_msgs::msg::JointTrajectory > composeTrajectoryMessage(const servo::Params &servo_params, const std::deque< KinematicState > &joint_cmd_rolling_window)
Create a trajectory message from a rolling window queue of joint state commands. Method optionally re...
Definition: common.cpp:151
void updateSlidingWindow(KinematicState &next_joint_state, std::deque< KinematicState > &joint_cmd_rolling_window, double max_expected_latency, const rclcpp::Time &cur_time)
Adds a new joint state command to a queue containing commands over a time window. Also modifies the v...
Definition: common.cpp:203
planning_scene_monitor::PlanningSceneMonitorPtr createPlanningSceneMonitor(const rclcpp::Node::SharedPtr &node, const servo::Params &servo_params)
Creates the planning scene monitor used by servo.
Definition: common.cpp:458
void setNodeLoggerName(const std::string &name)
Call once after creating a node to initialize logging namespaces.
Definition: logger.cpp:73
Eigen::Isometry3d pose
Definition: datatypes.hpp:107