moveit2
The MoveIt Motion Planning Framework for ROS 2.
common.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * BSD 3-Clause License
3  *
4  * Copyright (c) 2019, Los Alamos National Security, LLC
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 : utils.cpp
35  * Project : moveit_servo
36  * Created : 05/17/2023
37  * Author : Andy Zelenak, V Mohammed Ibrahim
38  */
39 
41 
42 namespace
43 {
44 // The threshold above which `override_velocity_scaling_factor` will be used instead of computing the scaling from joint bounds.
45 constexpr double SCALING_OVERRIDE_THRESHOLD = 0.01;
46 
47 // The angle threshold in radians below which a rotation will be considered the identity.
48 constexpr double MIN_ANGLE_THRESHOLD = 1E-16;
49 
50 // The publishing frequency for the planning scene monitor, in Hz.
51 constexpr double PLANNING_SCENE_PUBLISHING_FREQUENCY = 25.0;
52 } // namespace
53 
54 namespace moveit_servo
55 {
56 
57 std::optional<std::string> getIKSolverBaseFrame(const moveit::core::RobotStatePtr& robot_state,
58  const std::string& group_name)
59 {
60  const auto ik_solver = robot_state->getJointModelGroup(group_name)->getSolverInstance();
61 
62  if (ik_solver)
63  {
64  return ik_solver->getBaseFrame();
65  }
66  else
67  {
68  return std::nullopt;
69  }
70 }
71 
72 std::optional<std::string> getIKSolverTipFrame(const moveit::core::RobotStatePtr& robot_state,
73  const std::string& group_name)
74 {
75  const auto ik_solver = robot_state->getJointModelGroup(group_name)->getSolverInstance();
76 
77  if (ik_solver)
78  {
79  return ik_solver->getTipFrame();
80  }
81  else
82  {
83  return std::nullopt;
84  }
85 }
86 
87 bool isValidCommand(const Eigen::VectorXd& command)
88 {
89  // returns true only if there are no nan values.
90  return command.allFinite();
91 }
92 
93 bool isValidCommand(const Eigen::Isometry3d& command)
94 {
95  Eigen::Matrix3d identity, rotation;
96  identity.setIdentity();
97  rotation = command.linear();
98  // checks rotation, will fail if there is nan
99  const bool is_valid_rotation = rotation.allFinite() && identity.isApprox(rotation.inverse() * rotation);
100  // Command is not vald if there is Nan
101  const bool is_valid_translation = isValidCommand(command.translation());
102  return is_valid_rotation && is_valid_translation;
103 }
104 
105 bool isValidCommand(const TwistCommand& command)
106 {
107  return !command.frame_id.empty() && isValidCommand(command.velocities);
108 }
109 
110 bool isValidCommand(const PoseCommand& command)
111 {
112  return !command.frame_id.empty() && isValidCommand(command.pose);
113 }
114 
115 geometry_msgs::msg::Pose poseFromCartesianDelta(const Eigen::VectorXd& delta_x,
116  const Eigen::Isometry3d& base_to_tip_frame_transform)
117 {
118  // Get a transformation matrix with the desired position change
119  Eigen::Isometry3d tf_pos_delta(Eigen::Isometry3d::Identity());
120  tf_pos_delta.translate(Eigen::Vector3d(delta_x[0], delta_x[1], delta_x[2]));
121 
122  // Get a transformation matrix with desired orientation change
123  Eigen::Isometry3d tf_rot_delta(Eigen::Isometry3d::Identity());
124  const Eigen::Vector3d rot_vec = delta_x.block<3, 1>(3, 0, 3, 1);
125  double angle = rot_vec.norm();
126  if (angle > MIN_ANGLE_THRESHOLD)
127  {
128  const Eigen::Quaterniond q(Eigen::AngleAxisd(angle, rot_vec / angle).toRotationMatrix());
129  tf_rot_delta.rotate(q);
130  }
131 
132  // Find the new tip link position without newly applied rotation
133  const Eigen::Isometry3d tf_no_new_rot = tf_pos_delta * base_to_tip_frame_transform;
134 
135  // we want the rotation to be applied in the requested reference frame,
136  // but we want the rotation to be about the EE point in space, not the origin.
137  // So, we need to translate to origin, rotate, then translate back
138  // Given T = transformation matrix from origin -> EE point in space (translation component of tf_no_new_rot)
139  // and T' as the opposite transformation, EE point in space -> origin (translation only)
140  // apply final transformation as T * R * T' * tf_no_new_rot
141  Eigen::Isometry3d tf_neg_translation = Eigen::Isometry3d::Identity(); // T'
142  tf_neg_translation.translation() = -1 * tf_no_new_rot.translation();
143  Eigen::Isometry3d tf_pos_translation = Eigen::Isometry3d::Identity(); // T
144  tf_pos_translation.translation() = tf_no_new_rot.translation();
145 
146  // T * R * T' * tf_no_new_rot
147  return tf2::toMsg(tf_pos_translation * tf_rot_delta * tf_neg_translation * tf_no_new_rot);
148 }
149 
150 std::optional<trajectory_msgs::msg::JointTrajectory>
151 composeTrajectoryMessage(const servo::Params& servo_params, const std::deque<KinematicState>& joint_cmd_rolling_window)
152 {
153  if (joint_cmd_rolling_window.size() < MIN_POINTS_FOR_TRAJ_MSG)
154  {
155  return {};
156  }
157 
158  trajectory_msgs::msg::JointTrajectory joint_trajectory;
159 
160  joint_trajectory.joint_names = joint_cmd_rolling_window.front().joint_names;
161  joint_trajectory.points.reserve(joint_cmd_rolling_window.size() + 1);
162  joint_trajectory.header.stamp = joint_cmd_rolling_window.front().time_stamp;
163 
164  auto add_point = [servo_params](trajectory_msgs::msg::JointTrajectory& joint_trajectory, const KinematicState& state) {
165  trajectory_msgs::msg::JointTrajectoryPoint point;
166  size_t num_joints = state.positions.size();
167  point.positions.reserve(num_joints);
168  point.velocities.reserve(num_joints);
169  point.accelerations.reserve(num_joints);
170  if (servo_params.publish_joint_positions)
171  {
172  for (const auto& pos : state.positions)
173  {
174  point.positions.emplace_back(pos);
175  }
176  }
177  if (servo_params.publish_joint_velocities)
178  {
179  for (const auto& vel : state.velocities)
180  {
181  point.velocities.emplace_back(vel);
182  }
183  }
184  if (servo_params.publish_joint_accelerations)
185  {
186  for (const auto& acc : state.accelerations)
187  {
188  point.accelerations.emplace_back(acc);
189  }
190  }
191  point.time_from_start = state.time_stamp - joint_trajectory.header.stamp;
192  joint_trajectory.points.emplace_back(point);
193  };
194 
195  for (size_t i = 0; i < joint_cmd_rolling_window.size() - 1; ++i)
196  {
197  add_point(joint_trajectory, joint_cmd_rolling_window[i]);
198  }
199 
200  return joint_trajectory;
201 }
202 
203 void updateSlidingWindow(KinematicState& next_joint_state, std::deque<KinematicState>& joint_cmd_rolling_window,
204  double max_expected_latency, const rclcpp::Time& cur_time)
205 {
206  // remove commands older than current time minus the length of the sliding window
207  next_joint_state.time_stamp = cur_time + rclcpp::Duration::from_seconds(max_expected_latency);
208  const auto active_time_window = rclcpp::Duration::from_seconds(max_expected_latency);
209  while (!joint_cmd_rolling_window.empty() &&
210  joint_cmd_rolling_window.front().time_stamp < (cur_time - active_time_window))
211  {
212  joint_cmd_rolling_window.pop_front();
213  }
214 
215  // remove commands at end of window if timestamp is the same as current command
216  while (!joint_cmd_rolling_window.empty() && next_joint_state.time_stamp == joint_cmd_rolling_window.back().time_stamp)
217  {
218  joint_cmd_rolling_window.pop_back();
219  }
220 
221  // update velocity: the velocity has the potential to dramatically influence interpolation of splines and causes large
222  // overshooting. To alleviate this effect, the target velocity will be set to zero if the motion changes direction,
223  // otherwise, it will calculate the forward and backward finite difference velocities and choose the minimum.
224  if (joint_cmd_rolling_window.size() >= 2)
225  {
226  size_t num_points = joint_cmd_rolling_window.size();
227  auto& last_state = joint_cmd_rolling_window[num_points - 1];
228  auto& second_last_state = joint_cmd_rolling_window[num_points - 2];
229 
230  Eigen::VectorXd direction_1 = second_last_state.positions - last_state.positions;
231  Eigen::VectorXd direction_2 = next_joint_state.positions - last_state.positions;
232  Eigen::VectorXd signs = (direction_1.array().sign() - direction_2.array().sign()).round();
233  for (long i = 0; i < last_state.velocities.size(); ++i)
234  {
235  // check if the direction have changed. `signs` will either have -2, +2 meaning a flat line, -1, 1 meaning a
236  // rotated L shape, or 0 meaning a v-shape.
237  if (signs[i] == 0.0)
238  {
239  // direction changed
240  last_state.velocities[i] = 0;
241  }
242  else
243  {
244  const double delta_time_1 = (next_joint_state.time_stamp - last_state.time_stamp).seconds();
245  const double delta_time_2 = (last_state.time_stamp - second_last_state.time_stamp).seconds();
246  const auto velocity_1 = (next_joint_state.positions[i] - last_state.positions[i]) / delta_time_1;
247  const auto velocity_2 = (last_state.positions[i] - second_last_state.positions[i]) / delta_time_2;
248  last_state.velocities[i] = (std::abs(velocity_1) < std::abs(velocity_2)) ? velocity_1 : velocity_2;
249  }
250  next_joint_state.velocities[i] = last_state.velocities[i];
251  }
252  }
253 
254  // add next command
255  joint_cmd_rolling_window.push_back(next_joint_state);
256 }
257 
258 std_msgs::msg::Float64MultiArray composeMultiArrayMessage(const servo::Params& servo_params,
259  const KinematicState& joint_state)
260 {
261  std_msgs::msg::Float64MultiArray multi_array;
262  const size_t num_joints = joint_state.joint_names.size();
263  multi_array.data.resize(num_joints);
264  if (servo_params.publish_joint_positions)
265  {
266  for (size_t i = 0; i < num_joints; ++i)
267  {
268  multi_array.data[i] = joint_state.positions[i];
269  }
270  }
271  else if (servo_params.publish_joint_velocities)
272  {
273  for (size_t i = 0; i < num_joints; ++i)
274  {
275  multi_array.data[i] = joint_state.velocities[i];
276  }
277  }
278 
279  return multi_array;
280 }
281 
282 std::pair<double, StatusCode> velocityScalingFactorForSingularity(const moveit::core::RobotStatePtr& robot_state,
283  const Eigen::VectorXd& target_delta_x,
284  const servo::Params& servo_params)
285 {
286  // We need to send information back about if we are halting, moving away or towards the singularity.
287  StatusCode servo_status = StatusCode::NO_WARNING;
288 
289  const moveit::core::JointModelGroup* joint_model_group =
290  robot_state->getJointModelGroup(servo_params.move_group_name);
291 
292  // Get the thresholds.
293  const double lower_singularity_threshold = servo_params.lower_singularity_threshold;
294  const double hard_stop_singularity_threshold = servo_params.hard_stop_singularity_threshold;
295  const double leaving_singularity_threshold_multiplier = servo_params.leaving_singularity_threshold_multiplier;
296 
297  // Get size of total controllable dimensions.
298  const size_t dims = target_delta_x.size();
299 
300  // Get the current Jacobian and compute SVD
301  const Eigen::JacobiSVD<Eigen::MatrixXd> current_svd = Eigen::JacobiSVD<Eigen::MatrixXd>(
302  robot_state->getJacobian(joint_model_group), Eigen::ComputeThinU | Eigen::ComputeThinV);
303  const Eigen::MatrixXd matrix_s = current_svd.singularValues().asDiagonal();
304 
305  // Compute pseudo inverse
306  const Eigen::MatrixXd pseudo_inverse = current_svd.matrixV() * matrix_s.inverse() * current_svd.matrixU().transpose();
307 
308  // Get the singular vector corresponding to least singular value.
309  // This vector represents the least responsive dimension. By convention this is the last column of the matrix U.
310  // The sign of the singular vector from result of SVD is not reliable, so we need to do extra checking to make sure of
311  // the sign. See R. Bro, "Resolving the Sign Ambiguity in the Singular Value Decomposition".
312  Eigen::VectorXd vector_towards_singularity = current_svd.matrixU().col(dims - 1);
313 
314  // Compute the current condition number. The ratio of max and min singular values.
315  // By convention these are the first and last element of the diagonal.
316  const double current_condition_number = current_svd.singularValues()(0) / current_svd.singularValues()(dims - 1);
317 
318  // Take a small step in the direction of vector_towards_singularity
319  const Eigen::VectorXd delta_x = vector_towards_singularity * servo_params.singularity_step_scale;
320 
321  // Compute the new joint angles if we take the small step delta_x
322  Eigen::VectorXd next_joint_angles;
323  robot_state->copyJointGroupPositions(joint_model_group, next_joint_angles);
324  next_joint_angles += pseudo_inverse * delta_x;
325 
326  // Compute the Jacobian SVD for the new robot state.
327  robot_state->setJointGroupPositions(joint_model_group, next_joint_angles);
328  const Eigen::JacobiSVD<Eigen::MatrixXd> next_svd = Eigen::JacobiSVD<Eigen::MatrixXd>(
329  robot_state->getJacobian(joint_model_group), Eigen::ComputeThinU | Eigen::ComputeThinV);
330 
331  // Compute condition number for the new Jacobian.
332  const double next_condition_number = next_svd.singularValues()(0) / next_svd.singularValues()(dims - 1);
333 
334  // If the condition number has increased, we are moving towards singularity and the direction of the
335  // vector_towards_singularity is correct. If the condition number has decreased, it means the sign of
336  // vector_towards_singularity needs to be flipped.
337  if (next_condition_number <= current_condition_number)
338  {
339  vector_towards_singularity *= -1;
340  }
341 
342  // Double check the direction using dot product.
343  const bool moving_towards_singularity = vector_towards_singularity.dot(target_delta_x) > 0;
344 
345  // Compute upper condition variable threshold based on if we are moving towards or away from singularity.
346  // See https://github.com/ros-planning/moveit2/pull/620#issuecomment-1201418258 for visual explanation.
347  double upper_threshold;
348  if (moving_towards_singularity)
349  {
350  upper_threshold = hard_stop_singularity_threshold;
351  }
352  else
353  {
354  const double threshold_size = (hard_stop_singularity_threshold - lower_singularity_threshold);
355  upper_threshold = lower_singularity_threshold + (threshold_size * leaving_singularity_threshold_multiplier);
356  }
357 
358  // Compute the scale based on the current condition number.
359  double velocity_scale = 1.0;
360  const bool is_above_lower_limit = current_condition_number > lower_singularity_threshold;
361  const bool is_below_hard_stop_limit = current_condition_number < hard_stop_singularity_threshold;
362  if (is_above_lower_limit && is_below_hard_stop_limit)
363  {
364  velocity_scale -=
365  (current_condition_number - lower_singularity_threshold) / (upper_threshold - lower_singularity_threshold);
366 
367  servo_status = moving_towards_singularity ? StatusCode::DECELERATE_FOR_APPROACHING_SINGULARITY :
369  }
370  // If condition number has crossed hard stop limit, halt the robot.
371  else if (!is_below_hard_stop_limit)
372  {
373  servo_status = StatusCode::HALT_FOR_SINGULARITY;
374  velocity_scale = 0.0;
375  }
376 
377  return std::make_pair(velocity_scale, servo_status);
378 }
379 
380 double jointLimitVelocityScalingFactor(const Eigen::VectorXd& velocities,
381  const moveit::core::JointBoundsVector& joint_bounds, double scaling_override)
382 {
383  // If override value is close to zero, user is not overriding the scaling
384  double min_scaling_factor = scaling_override;
385  if (scaling_override < SCALING_OVERRIDE_THRESHOLD)
386  {
387  min_scaling_factor = 1.0; // Set to no scaling override.
388  }
389 
390  // Now get the scaling factor from joint velocity limits.
391  size_t idx = 0;
392  for (const auto& joint_bound : joint_bounds)
393  {
394  for (const auto& variable_bound : *joint_bound)
395  {
396  const auto& target_vel = velocities(idx);
397  if (variable_bound.velocity_bounded_ && target_vel != 0.0)
398  {
399  // Find the ratio of clamped velocity to original velocity
400  const auto bounded_vel = std::clamp(target_vel, variable_bound.min_velocity_, variable_bound.max_velocity_);
401  const auto joint_scaling_factor = bounded_vel / target_vel;
402  min_scaling_factor = std::min(min_scaling_factor, joint_scaling_factor);
403  }
404  ++idx;
405  }
406  }
407 
408  return min_scaling_factor;
409 }
410 
411 std::vector<int> jointsToHalt(const Eigen::VectorXd& positions, const Eigen::VectorXd& velocities,
412  const moveit::core::JointBoundsVector& joint_bounds, const std::vector<double>& margins)
413 {
414  std::vector<int> joint_idxs_to_halt;
415  for (size_t i = 0; i < joint_bounds.size(); i++)
416  {
417  const auto joint_bound = (joint_bounds[i])->front();
418  if (joint_bound.position_bounded_)
419  {
420  const bool negative_bound = velocities[i] < 0 && positions[i] < (joint_bound.min_position_ + margins[i]);
421  const bool positive_bound = velocities[i] > 0 && positions[i] > (joint_bound.max_position_ - margins[i]);
422  if (negative_bound || positive_bound)
423  {
424  joint_idxs_to_halt.push_back(i);
425  }
426  }
427  }
428  return joint_idxs_to_halt;
429 }
430 
432 geometry_msgs::msg::TransformStamped convertIsometryToTransform(const Eigen::Isometry3d& eigen_tf,
433  const std::string& parent_frame,
434  const std::string& child_frame)
435 {
436  geometry_msgs::msg::TransformStamped output = tf2::eigenToTransform(eigen_tf);
437  output.header.frame_id = parent_frame;
438  output.child_frame_id = child_frame;
439  return output;
440 }
441 
442 PoseCommand poseFromPoseStamped(const geometry_msgs::msg::PoseStamped& msg)
443 {
444  PoseCommand command;
445  command.frame_id = msg.header.frame_id;
446 
447  const Eigen::Vector3d translation(msg.pose.position.x, msg.pose.position.y, msg.pose.position.z);
448  const Eigen::Quaterniond rotation(msg.pose.orientation.w, msg.pose.orientation.x, msg.pose.orientation.y,
449  msg.pose.orientation.z);
450 
451  command.pose = Eigen::Isometry3d::Identity();
452  command.pose.translate(translation);
453  command.pose.linear() = rotation.normalized().toRotationMatrix();
454 
455  return command;
456 }
457 
458 planning_scene_monitor::PlanningSceneMonitorPtr createPlanningSceneMonitor(const rclcpp::Node::SharedPtr& node,
459  const servo::Params& servo_params)
460 {
461  // Can set robot_description name from parameters
462  std::string robot_description_name = "robot_description";
463  node->get_parameter_or("robot_description_name", robot_description_name, robot_description_name);
464 
465  // Set up planning_scene_monitor
466  auto planning_scene_monitor = std::make_shared<planning_scene_monitor::PlanningSceneMonitor>(
467  node, robot_description_name, "planning_scene_monitor");
468 
469  planning_scene_monitor->startStateMonitor(servo_params.joint_topic);
470  planning_scene_monitor->startSceneMonitor(servo_params.monitored_planning_scene_topic);
471  planning_scene_monitor->startWorldGeometryMonitor(
474  servo_params.check_octomap_collisions);
475 
476  if (servo_params.is_primary_planning_scene_monitor)
477  {
478  planning_scene_monitor->providePlanningSceneService();
479  }
480  else
481  {
482  planning_scene_monitor->requestPlanningSceneState();
483  }
484 
485  planning_scene_monitor->setPlanningScenePublishingFrequency(PLANNING_SCENE_PUBLISHING_FREQUENCY);
486  planning_scene_monitor->getStateMonitor()->enableCopyDynamics(true);
488  std::string(node->get_fully_qualified_name()) +
489  "/publish_planning_scene");
490 
491  return planning_scene_monitor;
492 }
493 
494 KinematicState extractRobotState(const moveit::core::RobotStatePtr& robot_state, const std::string& move_group_name)
495 {
496  const moveit::core::JointModelGroup* joint_model_group = robot_state->getJointModelGroup(move_group_name);
497  const auto joint_names = joint_model_group->getActiveJointModelNames();
498  KinematicState current_state(joint_names.size());
499  current_state.joint_names = joint_names;
500  robot_state->copyJointGroupPositions(joint_model_group, current_state.positions);
501  robot_state->copyJointGroupVelocities(joint_model_group, current_state.velocities);
502  robot_state->copyJointGroupAccelerations(joint_model_group, current_state.accelerations);
503 
504  return current_state;
505 }
506 
507 } // namespace moveit_servo
const std::vector< std::string > & getActiveJointModelNames() const
Get the names of the active joints in this group. These are the names of the joints returned by getJo...
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::vector< const JointModel::Bounds * > JointBoundsVector
std::optional< std::string > getIKSolverTipFrame(const moveit::core::RobotStatePtr &robot_state, const std::string &group_name)
Get the tip (end-effector) frame of the current active joint group or subgroup's IK solver.
Definition: common.cpp:72
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
geometry_msgs::msg::Pose poseFromCartesianDelta(const Eigen::VectorXd &delta_x, const Eigen::Isometry3d &base_to_tip_frame_transform)
Create a pose message for the provided change in Cartesian position.
Definition: common.cpp:115
std::pair< double, StatusCode > velocityScalingFactorForSingularity(const moveit::core::RobotStatePtr &robot_state, const Eigen::VectorXd &target_delta_x, const servo::Params &servo_params)
Computes scaling factor for velocity when the robot is near a singularity.
Definition: common.cpp:282
std::optional< std::string > getIKSolverBaseFrame(const moveit::core::RobotStatePtr &robot_state, const std::string &group_name)
Get the base frame of the current active joint group or subgroup's IK solver.
Definition: common.cpp:57
std::vector< int > jointsToHalt(const Eigen::VectorXd &positions, const Eigen::VectorXd &velocities, const moveit::core::JointBoundsVector &joint_bounds, const std::vector< double > &margins)
Finds the joints that are exceeding allowable position limits.
Definition: common.cpp:411
double jointLimitVelocityScalingFactor(const Eigen::VectorXd &velocities, const moveit::core::JointBoundsVector &joint_bounds, double scaling_override)
Apply velocity scaling based on joint limits. If the robot model does not have velocity limits define...
Definition: common.cpp:380
std_msgs::msg::Float64MultiArray composeMultiArrayMessage(const servo::Params &servo_params, const KinematicState &joint_state)
Create a Float64MultiArray message from given joint state.
Definition: common.cpp:258
bool isValidCommand(const Eigen::VectorXd &command)
Checks if a given VectorXd is a valid command.
Definition: common.cpp:87
geometry_msgs::msg::TransformStamped convertIsometryToTransform(const Eigen::Isometry3d &eigen_tf, const std::string &parent_frame, const std::string &child_frame)
Helper function for converting Eigen::Isometry3d to geometry_msgs/TransformStamped.
Definition: common.cpp:432
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
constexpr int MIN_POINTS_FOR_TRAJ_MSG
Definition: common.hpp:58
KinematicState extractRobotState(const moveit::core::RobotStatePtr &robot_state, const std::string &move_group_name)
Extract the state from a RobotStatePtr instance.
Definition: common.cpp:494
PoseCommand poseFromPoseStamped(const geometry_msgs::msg::PoseStamped &msg)
Convert a PoseStamped message to a Servo Pose.
Definition: common.cpp:442
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
std::vector< std::string > joint_names
Definition: datatypes.hpp:116
Eigen::VectorXd accelerations
Definition: datatypes.hpp:117
Eigen::VectorXd velocities
Definition: datatypes.hpp:117
Eigen::Isometry3d pose
Definition: datatypes.hpp:107
Eigen::Vector< double, 6 > velocities
Definition: datatypes.hpp:99