Program Listing for File moveit_example.hpp

Return to documentation for file (include/iiqka_moveit_example/moveit_example.hpp)

// Copyright 2022 Áron Svastits
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef IIQKA_MOVEIT_EXAMPLE__MOVEIT_EXAMPLE_HPP_
#define IIQKA_MOVEIT_EXAMPLE__MOVEIT_EXAMPLE_HPP_

#include <math.h>

#include <memory>
#include <string>
#include <vector>

#include "geometry_msgs/msg/vector3.hpp"
#include "moveit/move_group_interface/move_group_interface.h"
#include "moveit/planning_scene_interface/planning_scene_interface.h"
#include "moveit_msgs/msg/collision_object.hpp"
#include "moveit_visual_tools/moveit_visual_tools.h"
#include "rclcpp/rclcpp.hpp"

class MoveitExample : public rclcpp::Node
{
public:
  MoveitExample() : rclcpp::Node("moveit_example") {}

  void initialize()
  {
    move_group_interface_ = std::make_shared<moveit::planning_interface::MoveGroupInterface>(
      shared_from_this(), PLANNING_GROUP);

    moveit_visual_tools_ = std::make_shared<moveit_visual_tools::MoveItVisualTools>(
      shared_from_this(), "world", rviz_visual_tools::RVIZ_MARKER_TOPIC,
      move_group_interface_->getRobotModel());

    moveit_visual_tools_->deleteAllMarkers();
    moveit_visual_tools_->loadRemoteControl();
    moveit_visual_tools_->trigger();

    planning_scene_diff_publisher_ =
      this->create_publisher<moveit_msgs::msg::PlanningScene>("planning_scene", 10);

    move_group_interface_->setMaxVelocityScalingFactor(0.1);
    move_group_interface_->setMaxAccelerationScalingFactor(0.1);
  }

  moveit_msgs::msg::RobotTrajectory::SharedPtr drawCircle()
  {
    std::vector<geometry_msgs::msg::Pose> waypoints;
    moveit_msgs::msg::RobotTrajectory trajectory;
    geometry_msgs::msg::Pose msg;

    // circle facing forward
    msg.orientation.x = 0.0;
    msg.orientation.y = sqrt(2) / 2;
    msg.orientation.z = 0.0;
    msg.orientation.w = sqrt(2) / 2;
    msg.position.x = 0.4;
    // Define waypoints in a circle
    for (int i = 0; i < 63; i++)
    {
      msg.position.y = -0.2 + sin(0.1 * i) * 0.15;
      msg.position.z = 0.4 + cos(0.1 * i) * 0.15;
      waypoints.push_back(msg);
    }

    RCLCPP_INFO(LOGGER, "Start planning");
    double fraction =
      move_group_interface_->computeCartesianPath(waypoints, 0.005, 0.0, trajectory);
    RCLCPP_INFO(LOGGER, "Planning done!");

    if (fraction < 1)
    {
      RCLCPP_ERROR(LOGGER, "Could not compute trajectory through all waypoints!");
      return nullptr;
    }
    else
    {
      return std::make_shared<moveit_msgs::msg::RobotTrajectory>(trajectory);
    }
  }

  moveit_msgs::msg::RobotTrajectory::SharedPtr planToPoint(
    const Eigen::Isometry3d & pose,
    const std::string & planning_pipeline = "pilz_industrial_motion_planner",
    const std::string & planner_id = "PTP")
  {
    // Create planning request using pilz industrial motion planner
    move_group_interface_->setPlanningPipelineId(planning_pipeline);
    move_group_interface_->setPlannerId(planner_id);
    move_group_interface_->setPoseTarget(pose);

    moveit::planning_interface::MoveGroupInterface::Plan plan;
    RCLCPP_INFO(LOGGER, "Sending planning request");
    if (!move_group_interface_->plan(plan))
    {
      RCLCPP_INFO(LOGGER, "Planning failed");
      return nullptr;
    }
    else
    {
      RCLCPP_INFO(LOGGER, "Planning successful");
      return std::make_shared<moveit_msgs::msg::RobotTrajectory>(plan.trajectory_);
    }
  }

  moveit_msgs::msg::RobotTrajectory::SharedPtr planToPosition(const std::vector<double> & joint_pos)
  {
    move_group_interface_->setJointValueTarget(joint_pos);

    moveit::planning_interface::MoveGroupInterface::Plan plan;
    RCLCPP_INFO(LOGGER, "Sending planning request");
    if (!move_group_interface_->plan(plan))
    {
      RCLCPP_INFO(LOGGER, "Planning failed");
      return nullptr;
    }
    else
    {
      RCLCPP_INFO(LOGGER, "Planning successful");
      return std::make_shared<moveit_msgs::msg::RobotTrajectory>(plan.trajectory_);
    }
  }

  moveit_msgs::msg::RobotTrajectory::SharedPtr planToPointUntilSuccess(
    const Eigen::Isometry3d & pose,
    const std::string & planning_pipeline = "pilz_industrial_motion_planner",
    const std::string & planner_id = "PTP")
  {
    // Create planning request using given motion planner
    move_group_interface_->setPlanningPipelineId(planning_pipeline);
    move_group_interface_->setPlannerId(planner_id);
    move_group_interface_->setPoseTarget(pose);

    moveit::planning_interface::MoveGroupInterface::Plan plan;
    RCLCPP_INFO(LOGGER, "Sending planning request");
    moveit::core::MoveItErrorCode err_code;
    auto start = std::chrono::high_resolution_clock::now();
    do
    {
      RCLCPP_INFO(LOGGER, "Planning ...");
      err_code = move_group_interface_->plan(plan);
    } while (err_code != moveit::core::MoveItErrorCode::SUCCESS);
    auto stop = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
    RCLCPP_INFO(LOGGER, "Planning successful after %li ms", duration.count());
    return std::make_shared<moveit_msgs::msg::RobotTrajectory>(plan.trajectory_);
  }

  void AddObject(const moveit_msgs::msg::CollisionObject & object)
  {
    moveit_msgs::msg::PlanningScene planning_scene;
    planning_scene.name = "scene";
    planning_scene.world.collision_objects.push_back(object);
    planning_scene.is_diff = true;
    planning_scene_diff_publisher_->publish(planning_scene);
  }

  void addRobotPlatform()
  {
    moveit_msgs::msg::CollisionObject collision_object;
    collision_object.header.frame_id = move_group_interface_->getPlanningFrame();
    collision_object.id = "robot_stand";
    shape_msgs::msg::SolidPrimitive primitive;
    primitive.type = primitive.BOX;
    primitive.dimensions.resize(3);
    primitive.dimensions[primitive.BOX_X] = 0.5;
    primitive.dimensions[primitive.BOX_Y] = 0.5;
    primitive.dimensions[primitive.BOX_Z] = 1.2;

    // Define a pose for the box (specified relative to frame_id).
    geometry_msgs::msg::Pose stand_pose1;
    stand_pose1.orientation.w = 1.0;
    stand_pose1.position.x = 0.0;
    stand_pose1.position.y = 0.0;
    stand_pose1.position.z = -0.6;

    collision_object.primitives.push_back(primitive);
    collision_object.primitive_poses.push_back(stand_pose1);
    collision_object.operation = collision_object.ADD;

    AddObject(collision_object);
  }

  void addCollisionBox(
    const geometry_msgs::msg::Vector3 & position, const geometry_msgs::msg::Vector3 & size)
  {
    moveit_msgs::msg::CollisionObject collision_object;
    collision_object.header.frame_id = move_group_interface_->getPlanningFrame();
    collision_object.id = "collision_box";
    shape_msgs::msg::SolidPrimitive primitive;
    primitive.type = primitive.BOX;
    primitive.dimensions.resize(3);
    primitive.dimensions[primitive.BOX_X] = size.x;
    primitive.dimensions[primitive.BOX_Y] = size.y;
    primitive.dimensions[primitive.BOX_Z] = size.z;

    // Define a pose for the box (specified relative to frame_id).
    geometry_msgs::msg::Pose stand_pose;
    stand_pose.orientation.w = 1.0;
    stand_pose.position.x = position.x;
    stand_pose.position.y = position.y;
    stand_pose.position.z = position.z;

    collision_object.primitives.push_back(primitive);
    collision_object.primitive_poses.push_back(stand_pose);
    collision_object.operation = collision_object.ADD;

    AddObject(collision_object);
  }

  void addPalletObjects()
  {
    for (int k = 0; k < 3; k++)
    {
      for (int j = 0; j < 3; j++)
      {
        for (int i = 0; i < 3; i++)
        {
          moveit_msgs::msg::CollisionObject pallet_object;
          pallet_object.header.frame_id = move_group_interface_->getPlanningFrame();

          pallet_object.id = "pallet_" + std::to_string(9 * k + 3 * j + i);
          shape_msgs::msg::SolidPrimitive primitive;
          primitive.type = primitive.BOX;
          primitive.dimensions.resize(3);
          primitive.dimensions[primitive.BOX_X] = 0.097;
          primitive.dimensions[primitive.BOX_Y] = 0.097;
          primitive.dimensions[primitive.BOX_Z] = 0.097;

          // Define a pose for the box (specified relative to frame_id).
          geometry_msgs::msg::Pose stand_pose;
          stand_pose.orientation.w = 1.0;
          stand_pose.position.x = 0.3 + i * 0.1;
          stand_pose.position.y = -0.1 + j * 0.1;
          stand_pose.position.z = 0.3 - 0.1 * k;

          pallet_object.primitives.push_back(primitive);
          pallet_object.primitive_poses.push_back(stand_pose);
          pallet_object.operation = pallet_object.ADD;

          AddObject(pallet_object);
          std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
      }
    }
  }

  void AttachObject(const std::string & object_id)
  {
    moveit_msgs::msg::PlanningScene planning_scene;
    planning_scene.name = "scene";
    moveit_msgs::msg::AttachedCollisionObject attached_object;

    attached_object.link_name = "flange";
    attached_object.object.id = object_id;

    // Carry out the REMOVE + ATTACH operation
    RCLCPP_INFO(LOGGER, "Attaching the object to the hand and removing it from the world.");
    planning_scene.robot_state.attached_collision_objects.push_back(attached_object);
    planning_scene.robot_state.is_diff = true;
    planning_scene.is_diff = true;
    planning_scene_diff_publisher_->publish(planning_scene);
  }

  void DetachAndRemoveObject(const std::string & object_id)
  {
    moveit_msgs::msg::PlanningScene planning_scene;
    planning_scene.name = "scene";
    moveit_msgs::msg::AttachedCollisionObject attached_object;

    attached_object.link_name = "flange";
    attached_object.object.id = object_id;
    attached_object.object.operation = attached_object.object.REMOVE;

    // Carry out the DETACH operation
    RCLCPP_INFO(LOGGER, "Detaching the object from the hand");
    planning_scene.robot_state.attached_collision_objects.push_back(attached_object);
    planning_scene.robot_state.is_diff = true;
    planning_scene.world.collision_objects.push_back(attached_object.object);
    planning_scene.is_diff = true;
    planning_scene_diff_publisher_->publish(planning_scene);
  }

  void setOrientationConstraint(const geometry_msgs::msg::Quaternion & orientation)
  {
    moveit_msgs::msg::OrientationConstraint orientation_constraint;
    moveit_msgs::msg::Constraints constraints;
    orientation_constraint.header.frame_id = move_group_interface_->getPlanningFrame();
    orientation_constraint.link_name = move_group_interface_->getEndEffectorLink();
    orientation_constraint.orientation = orientation;
    orientation_constraint.absolute_x_axis_tolerance = 0.2;
    orientation_constraint.absolute_y_axis_tolerance = 0.2;
    orientation_constraint.absolute_z_axis_tolerance = 0.2;
    orientation_constraint.weight = 1.0;

    constraints.orientation_constraints.emplace_back(orientation_constraint);
    move_group_interface_->setPathConstraints(constraints);
  }

  void clearConstraints() { move_group_interface_->clearPathConstraints(); }

  void drawTrajectory(const moveit_msgs::msg::RobotTrajectory & trajectory)
  {
    moveit_visual_tools_->deleteAllMarkers();
    moveit_visual_tools_->publishTrajectoryLine(
      trajectory, moveit_visual_tools_->getRobotModel()->getJointModelGroup(PLANNING_GROUP));
  }

  void drawTitle(const std::string & text)
  {
    auto const text_pose = []
    {
      auto msg = Eigen::Isometry3d::Identity();
      msg.translation().z() = 1.0;
      return msg;
    }();
    moveit_visual_tools_->publishText(
      text_pose, text, rviz_visual_tools::RED, rviz_visual_tools::XXLARGE);
  }

  void addBreakPoint()
  {
    moveit_visual_tools_->trigger();
    moveit_visual_tools_->prompt("Press 'Next' in the RvizVisualToolsGui window to execute");
  }

  std::shared_ptr<moveit::planning_interface::MoveGroupInterface> moveGroupInterface()
  {
    return move_group_interface_;
  }

protected:
  std::shared_ptr<moveit::planning_interface::MoveGroupInterface> move_group_interface_;
  rclcpp::Publisher<moveit_msgs::msg::PlanningScene>::SharedPtr planning_scene_diff_publisher_;
  std::shared_ptr<moveit_visual_tools::MoveItVisualTools> moveit_visual_tools_;
  const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit_basic_plan");
  const std::string PLANNING_GROUP = "manipulator";
};

#endif  // IIQKA_MOVEIT_EXAMPLE__MOVEIT_EXAMPLE_HPP_