60const Eigen::VectorXd createMoveGroupDelta(
const Eigen::VectorXd& sub_group_deltas,
61 const moveit::core::RobotStatePtr& robot_state,
62 const servo::Params& servo_params,
65 const auto& subgroup_joint_names =
66 robot_state->getJointModelGroup(servo_params.active_subgroup)->getActiveJointModelNames();
69 Eigen::VectorXd move_group_delta_theta = Eigen::VectorXd::Zero(
70 robot_state->getJointModelGroup(servo_params.move_group_name)->getActiveJointModelNames().size());
71 for (
size_t index = 0; index < subgroup_joint_names.size(); index++)
73 move_group_delta_theta[joint_name_group_index_map.at(subgroup_joint_names.at(index))] = sub_group_deltas[index];
75 return move_group_delta_theta;
83 const servo::Params& servo_params,
87 const auto& group_name =
88 servo_params.active_subgroup.empty() ? servo_params.move_group_name : servo_params.active_subgroup;
91 Eigen::VectorXd joint_position_delta(joint_names.size());
92 Eigen::VectorXd velocities(joint_names.size());
97 RCLCPP_WARN_STREAM(getLogger(),
"Invalid joint jog command. Each joint name must have one corresponding "
98 "velocity command. Received "
104 for (
size_t i = 0; i < command.
names.size(); ++i)
106 auto it = std::find(joint_names.begin(), joint_names.end(), command.
names[i]);
107 if (it != std::end(joint_names))
109 velocities[std::distance(joint_names.begin(), it)] = command.
velocities[i];
113 RCLCPP_WARN_STREAM(getLogger(),
"Invalid joint name: " << command.
names[i]
114 <<
"Either you're sending commands for a joint "
115 "that is not part of the move group or certain joints "
116 "cannot be moved because a "
117 "subgroup is active and they are not part of it.");
124 RCLCPP_WARN_STREAM(getLogger(),
"Invalid velocity values in joint jog command");
128 joint_position_delta = velocities * servo_params.publish_period;
129 if (servo_params.command_in_type ==
"unitless")
131 joint_position_delta *= servo_params.scale.joint;
134 if (!servo_params.active_subgroup.empty() && servo_params.active_subgroup != servo_params.move_group_name)
136 return std::make_pair(
StatusCode::NO_WARNING, createMoveGroupDelta(joint_position_delta, robot_state, servo_params,
137 joint_name_group_index_map));
144 const servo::Params& servo_params,
const std::string& planning_frame,
148 const int num_joints =
149 robot_state->getJointModelGroup(servo_params.move_group_name)->getActiveJointModelNames().size();
150 Eigen::VectorXd joint_position_delta(num_joints);
151 Eigen::Vector<double, 6> cartesian_position_delta;
153 if (command.
frame_id != planning_frame)
155 RCLCPP_WARN_STREAM(getLogger(),
"Command frame is: " << command.
frame_id <<
", expected: " << planning_frame);
161 RCLCPP_WARN_STREAM(getLogger(),
"Invalid twist command.");
167 joint_position_delta.setZero();
172 cartesian_position_delta = command.
velocities * servo_params.publish_period;
176 if (servo_params.command_in_type ==
"unitless")
178 cartesian_position_delta.head<3>() *= servo_params.scale.linear;
179 cartesian_position_delta.tail<3>() *= servo_params.scale.rotational;
181 else if (servo_params.command_in_type ==
"speed_units")
183 if (servo_params.scale.linear > 0.0)
185 const auto linear_speed_scale = command.
velocities.head<3>().norm() / servo_params.scale.linear;
186 if (linear_speed_scale > 1.0)
188 cartesian_position_delta.head<3>() /= linear_speed_scale;
191 if (servo_params.scale.rotational > 0.0)
193 const auto angular_speed_scale = command.
velocities.tail<3>().norm() / servo_params.scale.rotational;
194 if (angular_speed_scale > 1.0)
196 cartesian_position_delta.tail<3>() /= angular_speed_scale;
202 const auto delta_result =
203 jointDeltaFromIK(cartesian_position_delta, robot_state, servo_params, joint_name_group_index_map);
204 status = delta_result.first;
207 joint_position_delta = delta_result.second;
209 const auto singularity_scaling_info =
214 status = singularity_scaling_info.second;
216 joint_position_delta *= singularity_scaling_info.first;
221 return std::make_pair(status, joint_position_delta);
225 const servo::Params& servo_params,
const std::string& planning_frame,
226 const std::string& ee_frame,
230 const int num_joints =
231 robot_state->getJointModelGroup(servo_params.move_group_name)->getActiveJointModelNames().size();
232 Eigen::VectorXd joint_position_delta(num_joints);
236 RCLCPP_WARN_STREAM(getLogger(),
"Invalid pose command.");
240 if (command.
frame_id != planning_frame)
242 RCLCPP_WARN_STREAM(getLogger(),
"Command frame is: " << command.
frame_id <<
" expected: " << planning_frame);
246 Eigen::Vector<double, 6> cartesian_position_delta;
249 const Eigen::Isometry3d ee_pose{ robot_state->getGlobalLinkTransform(planning_frame).inverse() *
250 robot_state->getGlobalLinkTransform(ee_frame) };
251 const Eigen::Quaterniond q_current(ee_pose.rotation());
252 Eigen::Quaterniond q_target(command.
pose.rotation());
253 Eigen::Vector3d translation_error = command.
pose.translation() - ee_pose.translation();
256 if (servo_params.scale.linear > 0.0)
258 const auto linear_speed_scale =
259 (translation_error.norm() / servo_params.publish_period) / servo_params.scale.linear;
260 if (linear_speed_scale > 1.0)
262 translation_error /= linear_speed_scale;
265 if (servo_params.scale.rotational > 0.0)
267 const auto angular_speed_scale =
268 (std::abs(q_target.angularDistance(q_current)) / servo_params.publish_period) / servo_params.scale.rotational;
269 if (angular_speed_scale > 1.0)
271 q_target = q_current.slerp(1.0 / angular_speed_scale, q_target);
276 const auto angle_axis_error = Eigen::AngleAxisd(q_target * q_current.inverse());
277 cartesian_position_delta.head<3>() = translation_error;
278 cartesian_position_delta.tail<3>() = angle_axis_error.axis() * angle_axis_error.angle();
281 const auto delta_result =
282 jointDeltaFromIK(cartesian_position_delta, robot_state, servo_params, joint_name_group_index_map);
283 status = delta_result.first;
286 joint_position_delta = delta_result.second;
288 const auto singularity_scaling_info =
293 status = singularity_scaling_info.second;
295 joint_position_delta *= singularity_scaling_info.first;
298 return std::make_pair(status, joint_position_delta);
302 const moveit::core::RobotStatePtr& robot_state,
const servo::Params& servo_params,
305 const auto& group_name =
306 servo_params.active_subgroup.empty() ? servo_params.move_group_name : servo_params.active_subgroup;
309 std::vector<double> current_joint_positions;
310 robot_state->copyJointGroupPositions(joint_model_group, current_joint_positions);
312 Eigen::VectorXd delta_theta(current_joint_positions.size());
315 const kinematics::KinematicsBaseConstPtr ik_solver = joint_model_group->
getSolverInstance();
316 bool ik_solver_supports_group =
true;
319 ik_solver_supports_group = ik_solver->supportsGroup(joint_model_group);
320 if (!ik_solver_supports_group)
323 RCLCPP_ERROR_STREAM(getLogger(),
"Loaded IK plugin does not support group " << joint_model_group->
getName());
327 if (ik_solver && ik_solver_supports_group)
329 const Eigen::Isometry3d base_to_tip_frame_transform =
330 robot_state->getGlobalLinkTransform(ik_solver->getBaseFrame()).inverse() *
331 robot_state->getGlobalLinkTransform(ik_solver->getTipFrame());
333 const geometry_msgs::msg::Pose next_pose =
337 std::vector<double> solution;
338 solution.reserve(current_joint_positions.size());
339 moveit_msgs::msg::MoveItErrorCodes err;
342 if (ik_solver->searchPositionIK(next_pose, current_joint_positions, servo_params.publish_period / 2.0, solution,
346 for (
size_t i = 0; i < current_joint_positions.size(); ++i)
348 delta_theta[i] = solution.at(i) - current_joint_positions.at(i);
354 RCLCPP_WARN_STREAM(getLogger(),
"Could not find IK solution for requested motion, got error code " << err.val);
360 const Eigen::MatrixXd jacobian = robot_state->getJacobian(joint_model_group);
361 const Eigen::JacobiSVD<Eigen::MatrixXd> svd =
362 Eigen::JacobiSVD<Eigen::MatrixXd>(jacobian, Eigen::ComputeThinU | Eigen::ComputeThinV);
363 const Eigen::MatrixXd matrix_s = svd.singularValues().asDiagonal();
364 const Eigen::MatrixXd pseudo_inverse = svd.matrixV() * matrix_s.inverse() * svd.matrixU().transpose();
366 delta_theta = pseudo_inverse * cartesian_position_delta;
369 if (!servo_params.active_subgroup.empty() && servo_params.active_subgroup != servo_params.move_group_name)
371 return std::make_pair(status,
372 createMoveGroupDelta(delta_theta, robot_state, servo_params, joint_name_group_index_map));
375 return std::make_pair(status, delta_theta);
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...
const std::string & getName() const
Get the name of the joint group.
const kinematics::KinematicsBaseConstPtr getSolverInstance() const
rclcpp::Logger getLogger()
JointDeltaResult jointDeltaFromTwist(const TwistCommand &command, const moveit::core::RobotStatePtr &robot_state, const servo::Params &servo_params, const std::string &planning_frame, const JointNameToMoveGroupIndexMap &joint_name_group_index_map)
Compute the change in joint position for the given twist command.
const std::unordered_map< StatusCode, std::string > SERVO_STATUS_CODE_MAP({ { StatusCode::INVALID, "Invalid" }, { StatusCode::NO_WARNING, "No warnings" }, { StatusCode::DECELERATE_FOR_APPROACHING_SINGULARITY, "Moving closer to a singularity, decelerating" }, { StatusCode::HALT_FOR_SINGULARITY, "Very close to a singularity, emergency stop" }, { StatusCode::DECELERATE_FOR_LEAVING_SINGULARITY, "Moving away from a singularity, decelerating" }, { StatusCode::DECELERATE_FOR_COLLISION, "Close to a collision, decelerating" }, { StatusCode::HALT_FOR_COLLISION, "Collision detected, emergency stop" }, { StatusCode::JOINT_BOUND, "Close to a joint bound (position or velocity), halting" } })
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.
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.
JointDeltaResult jointDeltaFromJointJog(const JointJogCommand &command, const moveit::core::RobotStatePtr &robot_state, const servo::Params &servo_params, const JointNameToMoveGroupIndexMap &joint_name_group_index_map)
Compute the change in joint position for the given joint jog command.
bool isValidCommand(const Eigen::VectorXd &command)
Checks if a given VectorXd is a valid command.
JointDeltaResult jointDeltaFromIK(const Eigen::VectorXd &cartesian_position_delta, const moveit::core::RobotStatePtr &robot_state, const servo::Params &servo_params, const JointNameToMoveGroupIndexMap &joint_name_group_index_map)
Computes the required change in joint angles for given Cartesian change, using the robot's IK solver.
std::pair< StatusCode, Eigen::VectorXd > JointDeltaResult
JointDeltaResult jointDeltaFromPose(const PoseCommand &command, const moveit::core::RobotStatePtr &robot_state, const servo::Params &servo_params, const std::string &planning_frame, const std::string &ee_frame, const JointNameToMoveGroupIndexMap &joint_name_group_index_map)
Compute the change in joint position for the given pose command.
std::unordered_map< std::string, std::size_t > JointNameToMoveGroupIndexMap
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
A set of options for the kinematics solver.
bool return_approximate_solution
std::vector< std::string > names
std::vector< double > velocities
Eigen::Vector< double, 6 > velocities