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,
88 const auto& group_name =
89 servo_params.active_subgroup.empty() ? servo_params.move_group_name : servo_params.active_subgroup;
92 Eigen::VectorXd joint_position_delta(joint_names.size());
93 Eigen::VectorXd velocities(joint_names.size());
96 bool names_valid =
true;
98 for (
size_t i = 0; i < command.
names.size(); ++i)
100 auto it = std::find(joint_names.begin(), joint_names.end(), command.
names[i]);
101 if (it != std::end(joint_names))
103 velocities[std::distance(joint_names.begin(), it)] = command.
velocities[i];
107 RCLCPP_WARN_STREAM(getLogger(),
"Invalid joint name: " << command.
names[i]);
114 if (names_valid && velocity_valid)
116 joint_position_delta = velocities * servo_params.publish_period;
117 if (servo_params.command_in_type ==
"unitless")
119 joint_position_delta *= servo_params.scale.joint;
127 RCLCPP_WARN_STREAM(getLogger(),
128 "Invalid joint names in joint jog command. Either you're sending commands for a joint "
129 "that is not part of the move group or certain joints cannot be moved because a "
130 "subgroup is active and they are not part of it.");
134 RCLCPP_WARN_STREAM(getLogger(),
"Invalid velocity values in joint jog command");
138 if (!servo_params.active_subgroup.empty() && servo_params.active_subgroup != servo_params.move_group_name)
140 return std::make_pair(status, createMoveGroupDelta(joint_position_delta, robot_state, servo_params,
141 joint_name_group_index_map));
144 return std::make_pair(status, joint_position_delta);
148 const servo::Params& servo_params,
const std::string& planning_frame,
152 const int num_joints =
153 robot_state->getJointModelGroup(servo_params.move_group_name)->getActiveJointModelNames().size();
154 Eigen::VectorXd joint_position_delta(num_joints);
155 Eigen::Vector<double, 6> cartesian_position_delta;
158 const bool is_planning_frame = (command.
frame_id == planning_frame);
159 const bool is_zero = command.
velocities.isZero();
160 if (!is_zero && is_planning_frame && valid_command)
163 cartesian_position_delta = command.
velocities * servo_params.publish_period;
167 if (servo_params.command_in_type ==
"unitless")
169 cartesian_position_delta.head<3>() *= servo_params.scale.linear;
170 cartesian_position_delta.tail<3>() *= servo_params.scale.rotational;
172 else if (servo_params.command_in_type ==
"speed_units")
174 if (servo_params.scale.linear > 0.0)
176 const auto linear_speed_scale = command.
velocities.head<3>().norm() / servo_params.scale.linear;
177 if (linear_speed_scale > 1.0)
179 cartesian_position_delta.head<3>() /= linear_speed_scale;
182 if (servo_params.scale.rotational > 0.0)
184 const auto angular_speed_scale = command.
velocities.tail<3>().norm() / servo_params.scale.rotational;
185 if (angular_speed_scale > 1.0)
187 cartesian_position_delta.tail<3>() /= angular_speed_scale;
193 const auto delta_result =
194 jointDeltaFromIK(cartesian_position_delta, robot_state, servo_params, joint_name_group_index_map);
195 status = delta_result.first;
198 joint_position_delta = delta_result.second;
200 const auto singularity_scaling_info =
205 status = singularity_scaling_info.second;
207 joint_position_delta *= singularity_scaling_info.first;
213 joint_position_delta.setZero();
220 RCLCPP_ERROR_STREAM(getLogger(),
"Invalid twist command.");
222 if (!is_planning_frame)
224 RCLCPP_ERROR_STREAM(getLogger(),
"Command frame is: " << command.
frame_id <<
", expected: " << planning_frame);
227 return std::make_pair(status, joint_position_delta);
231 const servo::Params& servo_params,
const std::string& planning_frame,
232 const std::string& ee_frame,
236 const int num_joints =
237 robot_state->getJointModelGroup(servo_params.move_group_name)->getActiveJointModelNames().size();
238 Eigen::VectorXd joint_position_delta(num_joints);
241 const bool is_planning_frame = (command.
frame_id == planning_frame);
243 if (valid_command && is_planning_frame)
245 Eigen::Vector<double, 6> cartesian_position_delta;
248 const Eigen::Isometry3d ee_pose{ robot_state->getGlobalLinkTransform(planning_frame).inverse() *
249 robot_state->getGlobalLinkTransform(ee_frame) };
250 const Eigen::Quaterniond q_current(ee_pose.rotation());
251 Eigen::Quaterniond q_target(command.
pose.rotation());
252 Eigen::Vector3d translation_error = command.
pose.translation() - ee_pose.translation();
255 if (servo_params.scale.linear > 0.0)
257 const auto linear_speed_scale =
258 (translation_error.norm() / servo_params.publish_period) / servo_params.scale.linear;
259 if (linear_speed_scale > 1.0)
261 translation_error /= linear_speed_scale;
264 if (servo_params.scale.rotational > 0.0)
266 const auto angular_speed_scale =
267 (std::abs(q_target.angularDistance(q_current)) / servo_params.publish_period) / servo_params.scale.rotational;
268 if (angular_speed_scale > 1.0)
270 q_target = q_current.slerp(1.0 / angular_speed_scale, q_target);
275 const auto angle_axis_error = Eigen::AngleAxisd(q_target * q_current.inverse());
276 cartesian_position_delta.head<3>() = translation_error;
277 cartesian_position_delta.tail<3>() = angle_axis_error.axis() * angle_axis_error.angle();
280 const auto delta_result =
281 jointDeltaFromIK(cartesian_position_delta, robot_state, servo_params, joint_name_group_index_map);
282 status = delta_result.first;
285 joint_position_delta = delta_result.second;
287 const auto singularity_scaling_info =
292 status = singularity_scaling_info.second;
294 joint_position_delta *= singularity_scaling_info.first;
303 RCLCPP_WARN_STREAM(getLogger(),
"Invalid pose command.");
305 if (!is_planning_frame)
307 RCLCPP_WARN_STREAM(getLogger(),
"Command frame is: " << command.
frame_id <<
" expected: " << planning_frame);
310 return std::make_pair(status, joint_position_delta);
314 const moveit::core::RobotStatePtr& robot_state,
const servo::Params& servo_params,
317 const auto& group_name =
318 servo_params.active_subgroup.empty() ? servo_params.move_group_name : servo_params.active_subgroup;
321 std::vector<double> current_joint_positions;
322 robot_state->copyJointGroupPositions(joint_model_group, current_joint_positions);
324 Eigen::VectorXd delta_theta(current_joint_positions.size());
327 const kinematics::KinematicsBaseConstPtr ik_solver = joint_model_group->
getSolverInstance();
328 bool ik_solver_supports_group =
true;
331 ik_solver_supports_group = ik_solver->supportsGroup(joint_model_group);
332 if (!ik_solver_supports_group)
335 RCLCPP_ERROR_STREAM(getLogger(),
"Loaded IK plugin does not support group " << joint_model_group->
getName());
339 if (ik_solver && ik_solver_supports_group)
341 const Eigen::Isometry3d base_to_tip_frame_transform =
342 robot_state->getGlobalLinkTransform(ik_solver->getBaseFrame()).inverse() *
343 robot_state->getGlobalLinkTransform(ik_solver->getTipFrame());
345 const geometry_msgs::msg::Pose next_pose =
349 std::vector<double> solution;
350 solution.reserve(current_joint_positions.size());
351 moveit_msgs::msg::MoveItErrorCodes err;
354 if (ik_solver->searchPositionIK(next_pose, current_joint_positions, servo_params.publish_period / 2.0, solution,
358 for (
size_t i = 0; i < current_joint_positions.size(); ++i)
360 delta_theta[i] = solution.at(i) - current_joint_positions.at(i);
366 RCLCPP_WARN_STREAM(getLogger(),
"Could not find IK solution for requested motion, got error code " << err.val);
372 const Eigen::MatrixXd jacobian = robot_state->getJacobian(joint_model_group);
373 const Eigen::JacobiSVD<Eigen::MatrixXd> svd =
374 Eigen::JacobiSVD<Eigen::MatrixXd>(jacobian, Eigen::ComputeThinU | Eigen::ComputeThinV);
375 const Eigen::MatrixXd matrix_s = svd.singularValues().asDiagonal();
376 const Eigen::MatrixXd pseudo_inverse = svd.matrixV() * matrix_s.inverse() * svd.matrixU().transpose();
378 delta_theta = pseudo_inverse * cartesian_position_delta;
381 if (!servo_params.active_subgroup.empty() && servo_params.active_subgroup != servo_params.move_group_name)
383 return std::make_pair(status,
384 createMoveGroupDelta(delta_theta, robot_state, servo_params, joint_name_group_index_map));
387 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