121    const std::vector<geometry_msgs::msg::PoseStamped> & waypoints,
 
  126    if (waypoints.empty())
 
  136      result.
errorMessage = 
"ClMoveit2z client not available";
 
  148        "[CpJointSpaceTrajectoryPlanner] Getting current state for trajectory planning");
 
  149      auto currentState = moveGroup->getCurrentState(100);
 
  152        result.
errorMessage = 
"Failed to get current robot state";
 
  159      std::string groupName = options.groupName.value_or(moveGroup->getName());
 
  160      std::string tipLink = options.tipLink.value_or(moveGroup->getEndEffectorLink());
 
  163        getLogger(), 
"[CpJointSpaceTrajectoryPlanner] Planning for group '%s' with tip link '%s'",
 
  164        groupName.c_str(), tipLink.c_str());
 
  167      auto jointNames = currentState->getJointModelGroup(groupName)->getActiveJointModelNames();
 
  170      std::vector<double> jointPositions;
 
  171      currentState->copyJointGroupPositions(groupName, jointPositions);
 
  173      std::vector<std::vector<double>> trajectory;
 
  174      std::vector<rclcpp::Duration> trajectoryTimeStamps;
 
  176      trajectory.push_back(jointPositions);
 
  177      trajectoryTimeStamps.push_back(rclcpp::Duration(0s));
 
  180      auto & first = waypoints.front();
 
  181      rclcpp::Time referenceTime(first.header.stamp);
 
  184      int ikAttemptsRemaining = options.ikAttempts;
 
  185      for (
size_t k = 0; k < waypoints.size(); k++)
 
  187        auto & pose = waypoints[k];
 
  190        auto req = std::make_shared<moveit_msgs::srv::GetPositionIK::Request>();
 
  191        req->ik_request.ik_link_name = tipLink;
 
  192        req->ik_request.robot_state.joint_state.name = jointNames;
 
  193        req->ik_request.robot_state.joint_state.position = jointPositions;
 
  194        req->ik_request.group_name = groupName;
 
  195        req->ik_request.avoid_collisions = options.avoidCollisions;
 
  196        req->ik_request.pose_stamped = pose;
 
  199          getLogger(), 
"[CpJointSpaceTrajectoryPlanner] Computing IK for waypoint %lu/%lu", k + 1,
 
  203        auto resFuture = 
ikClient_->async_send_request(req);
 
  204        auto status = resFuture.wait_for(options.ikTimeout);
 
  206        if (status != std::future_status::ready)
 
  208          result.
errorMessage = 
"IK service timeout at waypoint " + std::to_string(k);
 
  215        auto res = resFuture.get();
 
  216        auto & prevTrajPoint = trajectory.back();
 
  219        for (
size_t j = 0; j < res->solution.joint_state.position.size(); j++)
 
  221          auto & jointName = res->solution.joint_state.name[j];
 
  222          auto it = std::find(jointNames.begin(), jointNames.end(), jointName);
 
  223          if (it != jointNames.end())
 
  225            int index = std::distance(jointNames.begin(), it);
 
  226            jointPositions[index] = res->solution.joint_state.position[j];
 
  231        bool shouldCheck = k > 0 || !options.allowInitialDiscontinuity;
 
  232        int discontinuityJointIndex = -1;
 
  233        double discontinuityDelta = -1;
 
  237          for (
size_t jointIndex = 0; jointIndex < jointPositions.size(); jointIndex++)
 
  239            double deltaJoint = jointPositions[jointIndex] - prevTrajPoint[jointIndex];
 
  240            if (fabs(deltaJoint) > options.maxJointDiscontinuity)
 
  242              discontinuityDelta = deltaJoint;
 
  243              discontinuityJointIndex = jointIndex;
 
  250        if (ikAttemptsRemaining > 0 && discontinuityJointIndex != -1)
 
  254          ikAttemptsRemaining--;
 
  257            "[CpJointSpaceTrajectoryPlanner] IK discontinuity detected, retrying (%d attempts " 
  259            ikAttemptsRemaining);
 
  265          if (ikAttemptsRemaining == 0 && discontinuityJointIndex != -1)
 
  271              "[CpJointSpaceTrajectoryPlanner] Joint discontinuity at waypoint %lu: joint '%s' " 
  273              k, jointNames[discontinuityJointIndex].c_str(), discontinuityDelta);
 
  279                "[CpJointSpaceTrajectoryPlanner] Initial posture discontinuity detected");
 
  284          ikAttemptsRemaining = options.ikAttempts;
 
  287          trajectory.push_back(jointPositions);
 
  288          rclcpp::Duration durationFromStart = rclcpp::Time(pose.header.stamp) - referenceTime;
 
  289          trajectoryTimeStamps.push_back(durationFromStart);
 
  294      result.
trajectory.joint_trajectory.joint_names = jointNames;
 
  297      for (
size_t i = 1; i < trajectory.size(); i++)
 
  299        trajectory_msgs::msg::JointTrajectoryPoint jp;
 
  300        jp.positions = trajectory[i];
 
  301        jp.time_from_start = trajectoryTimeStamps[i];
 
  302        result.
trajectory.joint_trajectory.points.push_back(jp);
 
  316          result.
errorMessage = 
"Joint trajectory discontinuity detected";
 
  327          "[CpJointSpaceTrajectoryPlanner] Successfully computed trajectory with %lu points",
 
  328          result.
trajectory.joint_trajectory.points.size());
 
  331    catch (
const std::exception & e)
 
  334      result.
errorMessage = std::string(
"Exception during trajectory planning: ") + e.what();