moveit2_tutorials icon indicating copy to clipboard operation
moveit2_tutorials copied to clipboard

why using rosrun?

Open devika-dudo opened this issue 6 months ago • 9 comments

in the documentation on creating ikfast plugin for custom robot, we use a docker image since openrave requires it so are we running the rosrun command inside the docker or inside humble if yes how is it possible ---- also will i have to move my urdf files including the meshes to the docker to create the plugin this documentation seems vague i am having difficulty in understanding this , please help i have been stuck in this for weeks---or are there any other good 5dof plugins available? cant use trac ik since i am in ros2 humble

devika-dudo avatar Jun 02 '25 18:06 devika-dudo

I would recommend adding a link to what documentation/tutorial you are even referencing

mikeferguson avatar Jun 02 '25 19:06 mikeferguson

cant use trac ik since i am in ros2 humble

Not sure it'll help, but you might be able to build it from source using this branch.

gavanderhoorn avatar Jun 02 '25 19:06 gavanderhoorn

But see

IMG-20250603-WA0001.jpg

See it doesn't have a humble branch

devika-dudo avatar Jun 02 '25 19:06 devika-dudo

Also https://moveit.picknik.ai/humble/doc/examples/ikfast/ikfast_tutorial.html this is the documentation I am referring to

devika-dudo avatar Jun 02 '25 19:06 devika-dudo

No need for giant screenshots.

See it doesn't have a humble branch

no, that's why I linked to the jazzy branch. Until recently, I've built the rolling branch to use it with Humble. So there's a chance the jazzy branch works for you.

gavanderhoorn avatar Jun 02 '25 19:06 gavanderhoorn

Also https://moveit.picknik.ai/humble/doc/examples/ikfast/ikfast_tutorial.html this is the documentation I am referring to

That does not appear to have been ported to ROS 2 (hence the rosrun). If the docs aren't ported, I'm also not sure the state of the IKFast in Humble either. I will note that the docs have been ported in the latest branch - https://moveit.picknik.ai/main/doc/examples/ikfast/ikfast_tutorial.html - you might find some helpful information there

mikeferguson avatar Jun 02 '25 19:06 mikeferguson

No need for giant screenshots.

See it doesn't have a humble branch

no, that's why I linked to the jazzy branch. Until recently, I've built the rolling branch to use it with Humble. So there's a chance the jazzy branch works for you.

ok i will try and inform

devika-dudo avatar Jun 02 '25 19:06 devika-dudo

Also https://moveit.picknik.ai/humble/doc/examples/ikfast/ikfast_tutorial.html this is the documentation I am referring to

That does not appear to have been ported to ROS 2 (hence the rosrun). If the docs aren't ported, I'm also not sure the state of the IKFast in Humble either. I will note that the docs have been ported in the latest branch - https://moveit.picknik.ai/main/doc/examples/ikfast/ikfast_tutorial.html - you might find some helpful information there

thanks for the reply, i will try using the TranslationDirection5D and update the results

devika-dudo avatar Jun 02 '25 19:06 devika-dudo

HI, i tried using the trac_ik plugin but still my planning failed, i was using the movegroupinterface api for moving the end effector to a particular pose and orientation , since the arm is 5dof i set the yaw to a fixed 0 . so that i can give any pitch and yaw , is this a problem with the iksolver or am i feeding a 6dof pose to the solver ( so is the actual problem with my movegroupinterface's code? or am i trying to set a 6dof pose for a 5dof robotic arm ) if so how to set a 5dof pose so that planning wont get aborted this is my movegroupinterface node

 * @file hello_moveit_v2_5dof_constrained.cpp
 * @brief MoveIt 2 + ROS 2 code for a 5-DOF robot arm with proper constraints.
 *
 * For 5DOF robots, we use position targets + orientation constraints
 * instead of full 6DOF pose targets to avoid kinematic impossibilities.
 */
#include <geometry_msgs/msg/pose_stamped.hpp>
#include <geometry_msgs/msg/point_stamped.hpp>
#include <std_msgs/msg/float64_multi_array.hpp>
#include <memory>
#include <rclcpp/rclcpp.hpp>
#include <moveit/move_group_interface/move_group_interface.h>
#include <moveit/planning_scene_interface/planning_scene_interface.h>
#include <moveit_msgs/msg/constraints.hpp>
#include <moveit_msgs/msg/orientation_constraint.hpp>
#include <tf2/LinearMath/Quaternion.h>
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
#include <mutex>
class MoveIt5DOFController : public rclcpp::Node
{
public:
  MoveIt5DOFController() : Node("moveit_5dof_controller")
  {
    // Declare parameters
    this->declare_parameter("planning_pipeline", "ompl");
    this->declare_parameter("planner_id", "RRTConnectkConfigDefault");
    this->declare_parameter("planning_time", 10.0);
    this->declare_parameter("position_tolerance", 0.01);
    this->declare_parameter("orientation_tolerance", 0.2);  // More relaxed for 5DOF
    this->declare_parameter("max_velocity_scaling", 0.5);
    this->declare_parameter("max_acceleration_scaling", 0.5);
    this->declare_parameter("use_constraints", true);
    this->declare_parameter("constrain_orientation", true);
    RCLCPP_INFO(this->get_logger(), "MoveIt 5DOF Controller starting initialization...");
  }
  void initialize()
  {
    // Initialize MoveGroupInterface after construction
    arm_group_interface_ = std::make_unique<moveit::planning_interface::MoveGroupInterface>(
      shared_from_this(), "arm_group");
    // Configure planning parameters
    setupPlanningParameters();
    // Create subscribers for different input methods 
    // Method 1: Position-only target (recommended for 5DOF)
    position_subscriber_ = this->create_subscription<geometry_msgs::msg::PointStamped>(
      "/arm_position_command", 10,
      std::bind(&MoveIt5DOFController::positionCallback, this, std::placeholders::_1));
    // Method 2: Position + limited orientation (XYZ + Roll, Pitch)
    xyz_rp_subscriber_ = this->create_subscription<std_msgs::msg::Float64MultiArray>(
      "/arm_xyz_rp_command", 10,
      std::bind(&MoveIt5DOFController::xyzRpCallback, this, std::placeholders::_1));
    // Method 3: Full pose with constraints (for testing)
    pose_constrained_subscriber_ = this->create_subscription<geometry_msgs::msg::PoseStamped>(
      "/arm_pose_constrained_command", 10,
      std::bind(&MoveIt5DOFController::poseConstrainedCallback, this, std::placeholders::_1));
    // Method 4: Joint space control (always works)
    joint_subscriber_ = this->create_subscription<std_msgs::msg::Float64MultiArray>(
      "/arm_joint_command", 10,
      std::bind(&MoveIt5DOFController::jointCallback, this, std::placeholders::_1));
    RCLCPP_INFO(this->get_logger(), "MoveIt 5DOF Controller initialized");
    RCLCPP_INFO(this->get_logger(), "Available control methods:");
    RCLCPP_INFO(this->get_logger(), "  1. /arm_position_command (geometry_msgs/PointStamped) - Position only");
    RCLCPP_INFO(this->get_logger(), "  2. /arm_xyz_rp_command (Float64MultiArray) - [x,y,z,roll,pitch]");
    RCLCPP_INFO(this->get_logger(), "  3. /arm_pose_constrained_command (PoseStamped) - With orientation constraints");
    RCLCPP_INFO(this->get_logger(), "  4. /arm_joint_command (Float64MultiArray) - Joint angles");
  }
private:
  void setupPlanningParameters()
  {
    // Get parameters
    std::string planning_pipeline = this->get_parameter("planning_pipeline").as_string();
    std::string planner_id = this->get_parameter("planner_id").as_string();
    double planning_time = this->get_parameter("planning_time").as_double();
    double pos_tol = this->get_parameter("position_tolerance").as_double();
    double orient_tol = this->get_parameter("orientation_tolerance").as_double();
    double max_vel = this->get_parameter("max_velocity_scaling").as_double();
    double max_acc = this->get_parameter("max_acceleration_scaling").as_double();
    // Configure MoveGroupInterface
    arm_group_interface_->setPlanningPipelineId(planning_pipeline);
    arm_group_interface_->setPlannerId(planner_id);
    arm_group_interface_->setPlanningTime(planning_time);
    arm_group_interface_->setGoalPositionTolerance(pos_tol);
    arm_group_interface_->setGoalOrientationTolerance(orient_tol);
    arm_group_interface_->setMaxVelocityScalingFactor(max_vel);
    arm_group_interface_->setMaxAccelerationScalingFactor(max_acc);
    RCLCPP_INFO(this->get_logger(), "Planning configuration:");
    RCLCPP_INFO(this->get_logger(), "  Position tolerance: %.4f m", pos_tol);
    RCLCPP_INFO(this->get_logger(), "  Orientation tolerance: %.4f rad (%.1f°)", 
                orient_tol, orient_tol * 180.0 / M_PI);
    RCLCPP_INFO(this->get_logger(), "  Planning time: %.1f s", planning_time);
    // Clear any existing constraints
    arm_group_interface_->clearPathConstraints();
  }
  // Method 1: Position-only control (BEST for 5DOF)
  void positionCallback(const geometry_msgs::msg::PointStamped::SharedPtr msg)
  {
    std::lock_guard<std::mutex> lock(planning_mutex_);    
    RCLCPP_INFO(this->get_logger(), "Received position-only command:");
    RCLCPP_INFO(this->get_logger(), "  Target position: [%.3f, %.3f, %.3f]", 
                msg->point.x, msg->point.y, msg->point.z);
    // Clear constraints and use position target only
    arm_group_interface_->clearPathConstraints();
    arm_group_interface_->clearPoseTargets();
    // Set position target - let MoveIt choose orientation
    bool success = arm_group_interface_->setPositionTarget(
      msg->point.x, msg->point.y, msg->point.z);
    if (!success) {
      RCLCPP_ERROR(this->get_logger(), "Failed to set position target!");
      return;
    }
    executePlan("position target");
  }
  // Method 2: Position + Roll/Pitch (5DOF control)
  void xyzRpCallback(const std_msgs::msg::Float64MultiArray::SharedPtr msg)
  {
    std::lock_guard<std::mutex> lock(planning_mutex_);
    
    if (msg->data.size() != 5) {
      RCLCPP_ERROR(this->get_logger(), "Expected 5 values [x,y,z,roll,pitch], got %zu", 
                   msg->data.size());
      return;
    }
    double x = msg->data[0];
    double y = msg->data[1];
    double z = msg->data[2];
    double roll = msg->data[3];
    double pitch = msg->data[4];
    double yaw = 0.0; // Fixed or let MoveIt choose
    RCLCPP_INFO(this->get_logger(), "Received XYZ + Roll/Pitch command:");
    RCLCPP_INFO(this->get_logger(), "  Position: [%.3f, %.3f, %.3f]", x, y, z);
    RCLCPP_INFO(this->get_logger(), "  Orientation: roll=%.3f, pitch=%.3f (yaw=free)", roll, pitch);
    // Method 2A: Use orientation constraints
    if (this->get_parameter("use_constraints").as_bool()) {
      executeWithOrientationConstraints(x, y, z, roll, pitch);
    } 
    // Method 2B: Use approximate pose with relaxed tolerances
    else {
      executeWithApproximatePose(x, y, z, roll, pitch, yaw);
    }
  }
  // Method 3: Full pose with constraints
  void poseConstrainedCallback(const geometry_msgs::msg::PoseStamped::SharedPtr msg)
  {
    std::lock_guard<std::mutex> lock(planning_mutex_);
    RCLCPP_INFO(this->get_logger(), "Received constrained pose command");
    // Extract position
    double x = msg->pose.position.x;
    double y = msg->pose.position.y;
    double z = msg->pose.position.z;
    // Extract orientation
    tf2::Quaternion q;
    tf2::fromMsg(msg->pose.orientation, q);
    double roll, pitch, yaw;
    tf2::Matrix3x3(q).getRPY(roll, pitch, yaw);
    RCLCPP_INFO(this->get_logger(), "  Position: [%.3f, %.3f, %.3f]", x, y, z);
    RCLCPP_INFO(this->get_logger(), "  Orientation: [%.3f, %.3f, %.3f] (yaw may be ignored)", roll, pitch, yaw);
    executeWithOrientationConstraints(x, y, z, roll, pitch);
  }
  // Method 4: Direct joint control (always works)
  void jointCallback(const std_msgs::msg::Float64MultiArray::SharedPtr msg)
  {
    std::lock_guard<std::mutex> lock(planning_mutex_);
    if (msg->data.size() != 5) {
      RCLCPP_ERROR(this->get_logger(), "Expected 5 joint values, got %zu", msg->data.size());
      return;
    }
    RCLCPP_INFO(this->get_logger(), "Received joint command:");
    RCLCPP_INFO(this->get_logger(), "  Joints: [%.3f, %.3f, %.3f, %.3f, %.3f]", 
                msg->data[0], msg->data[1], msg->data[2], msg->data[3], msg->data[4]);
    arm_group_interface_->clearPathConstraints();
    arm_group_interface_->setJointValueTarget(msg->data);
    executePlan("joint target");
  }
  void executeWithOrientationConstraints(double x, double y, double z, double roll, double pitch)
  {
    // Clear previous constraints
    arm_group_interface_->clearPathConstraints();
    arm_group_interface_->clearPoseTargets();
    // Set position target
    arm_group_interface_->setPositionTarget(x, y, z);
    // Create orientation constraints for roll and pitch only
    moveit_msgs::msg::Constraints constraints;
    // Roll constraint
    moveit_msgs::msg::OrientationConstraint roll_constraint;
    roll_constraint.link_name = arm_group_interface_->getEndEffectorLink();
    roll_constraint.header.frame_id = arm_group_interface_->getPlanningFrame();
    tf2::Quaternion roll_q;
    roll_q.setRPY(roll, 0, 0);
    roll_constraint.orientation = tf2::toMsg(roll_q);
    roll_constraint.absolute_x_axis_tolerance = 0.1;  // Relaxed
    roll_constraint.absolute_y_axis_tolerance = 3.14; // Free
    roll_constraint.absolute_z_axis_tolerance = 3.14; // Free
    roll_constraint.weight = 1.0;
    // Pitch constraint
    moveit_msgs::msg::OrientationConstraint pitch_constraint;
    pitch_constraint.link_name = arm_group_interface_->getEndEffectorLink();
    pitch_constraint.header.frame_id = arm_group_interface_->getPlanningFrame();
    tf2::Quaternion pitch_q;
    pitch_q.setRPY(0, pitch, 0);
    pitch_constraint.orientation = tf2::toMsg(pitch_q);
    pitch_constraint.absolute_x_axis_tolerance = 3.14; // Free
    pitch_constraint.absolute_y_axis_tolerance = 0.1;  // Constrained
    pitch_constraint.absolute_z_axis_tolerance = 3.14; // Free
    pitch_constraint.weight = 1.0;
    constraints.orientation_constraints.push_back(roll_constraint);
    constraints.orientation_constraints.push_back(pitch_constraint);
    arm_group_interface_->setPathConstraints(constraints);
    executePlan("position + orientation constraints");
  }
  void executeWithApproximatePose(double x, double y, double z, double roll, double pitch, double yaw)
  {
    // Create pose with very relaxed orientation tolerance
    geometry_msgs::msg::PoseStamped target_pose;
    target_pose.header.frame_id = arm_group_interface_->getPlanningFrame();
    target_pose.header.stamp = this->now();
    target_pose.pose.position.x = x;
    target_pose.pose.position.y = y;
    target_pose.pose.position.z = z;
    tf2::Quaternion q;
    q.setRPY(roll, pitch, yaw);
    q.normalize();
    target_pose.pose.orientation = tf2::toMsg(q);
    arm_group_interface_->clearPathConstraints();
    // Set very relaxed orientation tolerance
    double original_orient_tol = this->get_parameter("orientation_tolerance").as_double();
    arm_group_interface_->setGoalOrientationTolerance(0.5); // Very relaxed
    bool success = arm_group_interface_->setPoseTarget(target_pose);
    if (!success) {
      RCLCPP_ERROR(this->get_logger(), "Failed to set pose target!");
      return;
    }
    executePlan("approximate pose");
    // Restore original tolerance
    arm_group_interface_->setGoalOrientationTolerance(original_orient_tol);
  }
  void executePlan(const std::string& method_name)
  {
    RCLCPP_INFO(this->get_logger(), "Planning motion using %s...", method_name.c_str());
    moveit::planning_interface::MoveGroupInterface::Plan plan;
    bool success = static_cast<bool>(arm_group_interface_->plan(plan));
    if (success) {
      RCLCPP_INFO(this->get_logger(), "Planning successful! Executing motion...");     
      auto execute_result = arm_group_interface_->execute(plan);
      if (execute_result == moveit::core::MoveItErrorCode::SUCCESS) {
        RCLCPP_INFO(this->get_logger(), "✅ Motion executed successfully!");
      } else {
        RCLCPP_ERROR(this->get_logger(), "❌ Motion execution failed!");
      }
    } else {
      RCLCPP_ERROR(this->get_logger(), "❌ Planning failed with %s", method_name.c_str());
      RCLCPP_ERROR(this->get_logger(), "Try one of these solutions:");
      RCLCPP_ERROR(this->get_logger(), "  1. Use position-only control (/arm_position_command)");
      RCLCPP_ERROR(this->get_logger(), "  2. Use joint space control (/arm_joint_command)");
      RCLCPP_ERROR(this->get_logger(), "  3. Increase orientation tolerance");
      RCLCPP_ERROR(this->get_logger(), "  4. Check if target is within workspace");
    }
    RCLCPP_INFO(this->get_logger(), "Ready for next command...");
  }
  std::unique_ptr<moveit::planning_interface::MoveGroupInterface> arm_group_interface_;
  rclcpp::Subscription<geometry_msgs::msg::PointStamped>::SharedPtr position_subscriber_;
  rclcpp::Subscription<std_msgs::msg::Float64MultiArray>::SharedPtr xyz_rp_subscriber_;
  rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr pose_constrained_subscriber_;
  rclcpp::Subscription<std_msgs::msg::Float64MultiArray>::SharedPtr joint_subscriber_;
  std::mutex planning_mutex_;
};
int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  auto node = std::make_shared<MoveIt5DOFController>();
  node->initialize();
  RCLCPP_INFO(node->get_logger(), "🤖 MoveIt 5DOF Controller ready!");
  RCLCPP_INFO(node->get_logger(), "");
  RCLCPP_INFO(node->get_logger(), "🎯 RECOMMENDED: Position-only control (works best for 5DOF):");
  RCLCPP_INFO(node->get_logger(), "  ros2 topic pub /arm_position_command geometry_msgs/PointStamped");
  RCLCPP_INFO(node->get_logger(), "  '{header: {frame_id: base_link}, point: {x: 0.3, y: 0.2, z: 0.4}}'");
  RCLCPP_INFO(node->get_logger(), "");
  RCLCPP_INFO(node->get_logger(), "🎯 Alternative: XYZ + Roll/Pitch (5DOF control):");
  RCLCPP_INFO(node->get_logger(), "  ros2 topic pub /arm_xyz_rp_command std_msgs/Float64MultiArray");
  RCLCPP_INFO(node->get_logger(), "  \"data: [0.3, 0.2, 0.4, 0.0, -0.785]\"");
  RCLCPP_INFO(node->get_logger(), "");
  RCLCPP_INFO(node->get_logger(), "🎯 Always works: Joint space control:");
  RCLCPP_INFO(node->get_logger(), "  ros2 topic pub /arm_joint_command std_msgs/Float64MultiArray");
  RCLCPP_INFO(node->get_logger(), "  \"data: [0.0, 0.5, -1.0, 0.5, 0.0]\"");
  RCLCPP_INFO(node->get_logger(), "");
  RCLCPP_INFO(node->get_logger(), "Press Ctrl+C to exit.");
  rclcpp::spin(node);
  rclcpp::shutdown();  
  return 0;
}

please help i searched online and found that some people are setting position_only_ik:True in the kinematics file, but doesnt that make the robot a 3dof one? but i want to set the roll and pitch too

please tell me if i have moved out of the scope of the issue --

devika-dudo avatar Jun 02 '25 20:06 devika-dudo