【MoveIt2】 Planning Scene ROS API

Planning Scene ROS API

在本教程中,我们将检查使用规划场景差异来执行两个操作:

在世界中添加和删除对象

在机器人上安装和拆卸物体

Ubuntu 虚拟机 VSCode界面

Running the code

打开两个终端。 在第一个 shell 中启动 RViz 并等待一切完成加载:

ros2 launch moveit2_tutorials move_group.launch.py

在第二个 shell 中,运行此演示的启动文件:

ros2 launch moveit2_tutorials planning_scene_ros_api_tutorial.launch.py

片刻之后,RViz 窗口应该会出现,看起来类似于可视化教程。 要完成每个演示步骤,请按屏幕底部 RvizVisualToolsGui 面板中的下一步按钮或选择屏幕顶部工具面板中的关键工具,然后在 RViz 聚焦时按键盘上的 N。

Expected Output

在 RViz 中,您应该能够看到以下内容:

对象出现在规划场景中。

物体附着在机器人上。

对象与机器人分离。

从规划场景中移除对象

planning_scene_ros_api_tutorial

完整代码:

#include <rclcpp/rclcpp.hpp>
#include <geometry_msgs/msg/pose.hpp>

// MoveIt
#include <moveit_msgs/msg/planning_scene.hpp>
#include <moveit_msgs/msg/attached_collision_object.hpp>
#include <moveit_msgs/srv/get_state_validity.hpp>
#include <moveit_msgs/msg/display_robot_state.hpp>
#include <moveit_msgs/srv/apply_planning_scene.hpp>

#include <moveit/robot_model_loader/robot_model_loader.h>
#include <moveit/robot_state/robot_state.h>
#include <moveit/robot_state/conversions.h>

/* #include <moveit_visual_tools/moveit_visual_tools.h>  This has not been ported to ros2 yet */
#include <rviz_visual_tools/rviz_visual_tools.hpp>
/* this is a standin for moveit_visual_tools prompt */
#include <moveit/macros/console_colors.h>

void prompt(const std::string& message)
{
  printf(MOVEIT_CONSOLE_COLOR_GREEN "\n%s" MOVEIT_CONSOLE_COLOR_RESET, message.c_str());
  fflush(stdout);
  while (std::cin.get() != '\n' && rclcpp::ok())
    ;
}
static const rclcpp::Logger LOGGER = rclcpp::get_logger("planning_scene_ros_api_tutorial");

int main(int argc, char** argv)
{
  rclcpp::init(argc, argv);
  rclcpp::NodeOptions node_options;
  node_options.automatically_declare_parameters_from_overrides(true);
  auto node = rclcpp::Node::make_shared("planning_scene_ros_api_tutorial", node_options);

  rclcpp::executors::SingleThreadedExecutor executor;
  executor.add_node(node);
  std::thread([&executor]() { executor.spin(); }).detach();
  // BEGIN_TUTORIAL
  //
  // Visualization
  // ^^^^^^^^^^^^^
  // The package MoveItVisualTools provides many capabilities for visualizing objects, robots,
  // and trajectories in RViz as well as debugging tools such as step-by-step introspection of a script.
  rviz_visual_tools::RvizVisualTools visual_tools("panda_link0", "planning_scene_ros_api_tutorial", node);
  visual_tools.deleteAllMarkers();

  // ROS API
  // ^^^^^^^
  // The ROS API to the planning scene publisher is through a topic interface
  // using "diffs". A planning scene diff is the difference between the current
  // planning scene (maintained by the move_group node) and the new planning
  // scene desired by the user.
  //
  // Advertise the required topic
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // We create a publisher and wait for subscribers.
  // Note that this topic may need to be remapped in the launch file.
  rclcpp::Publisher<moveit_msgs::msg::PlanningScene>::SharedPtr planning_scene_diff_publisher =
      node->create_publisher<moveit_msgs::msg::PlanningScene>("planning_scene", 1);
  while (planning_scene_diff_publisher->get_subscription_count() < 1)
  {
    rclcpp::sleep_for(std::chrono::milliseconds(500));
  }
  prompt("Press 'Enter' to continue the demo");
  /* visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo"); */

  // Define the attached object message
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // We will use this message to add or
  // subtract the object from the world
  // and to attach the object to the robot.
  moveit_msgs::msg::AttachedCollisionObject attached_object;
  attached_object.link_name = "panda_hand";
  /* The header must contain a valid TF frame*/
  attached_object.object.header.frame_id = "panda_hand";
  /* The id of the object */
  attached_object.object.id = "box";

  /* A default pose */
  geometry_msgs::msg::Pose pose;
  pose.position.z = 0.11;
  pose.orientation.w = 1.0;

  /* Define a box to be attached */
  shape_msgs::msg::SolidPrimitive primitive;
  primitive.type = primitive.BOX;
  primitive.dimensions.resize(3);
  primitive.dimensions[0] = 0.075;
  primitive.dimensions[1] = 0.075;
  primitive.dimensions[2] = 0.075;

  attached_object.object.primitives.push_back(primitive);
  attached_object.object.primitive_poses.push_back(pose);

  // Note that attaching an object to the robot requires
  // the corresponding operation to be specified as an ADD operation.
  attached_object.object.operation = attached_object.object.ADD;

  // Since we are attaching the object to the robot hand to simulate picking up the object,
  // we want the collision checker to ignore collisions between the object and the robot hand.
  attached_object.touch_links = std::vector<std::string>{ "panda_hand", "panda_leftfinger", "panda_rightfinger" };

  // Add an object into the environment
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Add the object into the environment by adding it to
  // the set of collision objects in the "world" part of the
  // planning scene. Note that we are using only the "object"
  // field of the attached_object message here.
  RCLCPP_INFO(LOGGER, "Adding the object into the world at the location of the hand.");
  moveit_msgs::msg::PlanningScene planning_scene;
  planning_scene.world.collision_objects.push_back(attached_object.object);
  planning_scene.is_diff = true;
  planning_scene_diff_publisher->publish(planning_scene);
  prompt("Press 'Enter' to continue the demo");
  /* visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo"); */

  // Interlude: Synchronous vs Asynchronous updates
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // There are two separate mechanisms available to interact
  // with the move_group node using diffs:
  //
  // * Send a diff via a rosservice call and block until
  //   the diff is applied (synchronous update)
  // * Send a diff via a topic, continue even though the diff
  //   might not be applied yet (asynchronous update)
  //
  // While most of this tutorial uses the latter mechanism (given the long sleeps
  // inserted for visualization purposes asynchronous updates do not pose a problem),
  // it would be perfectly justified to replace the planning_scene_diff_publisher
  // by the following service client:
  rclcpp::Client<moveit_msgs::srv::ApplyPlanningScene>::SharedPtr planning_scene_diff_client =
      node->create_client<moveit_msgs::srv::ApplyPlanningScene>("apply_planning_scene");
  planning_scene_diff_client->wait_for_service();
  // and send the diffs to the planning scene via a service call:
  auto request = std::make_shared<moveit_msgs::srv::ApplyPlanningScene::Request>();
  request->scene = planning_scene;
  std::shared_future<std::shared_ptr<moveit_msgs::srv::ApplyPlanningScene_Response>> response_future;
  response_future = planning_scene_diff_client->async_send_request(request);

  // wait for the service to respond
  std::chrono::seconds wait_time(1);
  std::future_status fs = response_future.wait_for(wait_time);
  if (fs == std::future_status::timeout)
  {
    RCLCPP_ERROR(LOGGER, "Service timed out.");
  }
  else
  {
    std::shared_ptr<moveit_msgs::srv::ApplyPlanningScene_Response> planning_response;
    planning_response = response_future.get();
    if (planning_response->success)
    {
      RCLCPP_INFO(LOGGER, "Service successfully added object.");
    }
    else
    {
      RCLCPP_ERROR(LOGGER, "Service failed to add object.");
    }
  }

  // Note that this does not continue until we are sure the diff has been applied.
  //
  // Attach an object to the robot
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // When the robot picks up an object from the environment, we need to
  // "attach" the object to the robot so that any component dealing with
  // the robot model knows to account for the attached object, e.g. for
  // collision checking.
  //
  // Attaching an object requires two operations
  //  * Removing the original object from the environment
  //  * Attaching the object to the robot

  /* First, define the REMOVE object message*/
  moveit_msgs::msg::CollisionObject remove_object;
  remove_object.id = "box";
  remove_object.header.frame_id = "panda_hand";
  remove_object.operation = remove_object.REMOVE;

  // Note how we make sure that the diff message contains no other
  // attached objects or collisions objects by clearing those fields
  // first.
  /* Carry out the REMOVE + ATTACH operation */
  RCLCPP_INFO(LOGGER, "Attaching the object to the hand and removing it from the world.");
  planning_scene.world.collision_objects.clear();
  planning_scene.world.collision_objects.push_back(remove_object);
  planning_scene.robot_state.attached_collision_objects.push_back(attached_object);
  planning_scene.robot_state.is_diff = true;
  planning_scene_diff_publisher->publish(planning_scene);

  prompt("Press 'Enter' to continue the demo");
  /* visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo"); */

  // Detach an object from the robot
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Detaching an object from the robot requires two operations
  //  * Detaching the object from the robot
  //  * Re-introducing the object into the environment

  /* First, define the DETACH object message*/
  moveit_msgs::msg::AttachedCollisionObject detach_object;
  detach_object.object.id = "box";
  detach_object.link_name = "panda_hand";
  detach_object.object.operation = attached_object.object.REMOVE;

  // Note how we make sure that the diff message contains no other
  // attached objects or collisions objects by clearing those fields
  // first.
  /* Carry out the DETACH + ADD operation */
  RCLCPP_INFO(LOGGER, "Detaching the object from the robot and returning it to the world.");
  planning_scene.robot_state.attached_collision_objects.clear();
  planning_scene.robot_state.attached_collision_objects.push_back(detach_object);
  planning_scene.robot_state.is_diff = true;
  planning_scene.world.collision_objects.clear();
  planning_scene.world.collision_objects.push_back(attached_object.object);
  planning_scene.is_diff = true;
  planning_scene_diff_publisher->publish(planning_scene);

  prompt("Press 'Enter' to continue the demo");
  /* visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo"); */

  // Remove the object from the collision world
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Removing the object from the collision world just requires
  // using the remove object message defined earlier.
  // Note, also how we make sure that the diff message contains no other
  // attached objects or collisions objects by clearing those fields
  // first.
  RCLCPP_INFO(LOGGER, "Removing the object from the world.");
  planning_scene.robot_state.attached_collision_objects.clear();
  planning_scene.world.collision_objects.clear();
  planning_scene.world.collision_objects.push_back(remove_object);
  planning_scene_diff_publisher->publish(planning_scene);
  // END_TUTORIAL

  prompt("Press 'Enter' to end the demo");
  /* visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to end the demo"); */

  rclcpp::shutdown();
  return 0;
}

 参考:

http://moveit2_tutorials.picknik.ai/doc/planning_scene_ros_api/planning_scene_ros_api_tutorial.html

### ROS2 MoveIt2 和 Gazebo 联合仿真的配置指南 在 ROS2MoveIt2 中使用 Gazebo 进行仿真是一项常见的任务,它允许开发人员测试机械臂的运动规划和控制逻辑,而不依赖实际硬件。以下是关于如何设置 ROS2MoveIt2 和 Gazebo 的联合仿真的详细说明。 #### 1. 安装必要的软件包 为了完成此任务,需要安装以下核心组件: - `ros-<distro>-moveit`:提供 MoveIt2 功能。 - `ros-<distro>-gazebo-ros-pkgs`:用于集成 Gazebo 和 ROS2。 - `ros-<distro>-ros2-control`:负责硬件接口和控制器管理。 可以通过以下命令安装这些包(假设使用的发行版为 Humble)[^1]: ```bash sudo apt update && sudo apt install ros-humble-moveit ros-humble-gazebo-ros-pkgs ros-humble-ros2-control ``` --- #### 2. 创建机器人描述文件 (URDF/XACRO) 创建一个 URDF 文件来描述机器人的几何结构、惯性属性以及关节信息。如果需要更灵活的参数化配置,可以使用 Xacro 格式替代纯 URDF 文件。 示例 Xacro 文件 (`robot.xacro`) 可能如下所示: ```xml <?xml version="1.0"?> <robot name="my_robot" xmlns:xacro="http://www.ros.org/wiki/xacro"> <!-- Link definitions --> <link name="base_link"> <visual> <geometry> <box size="0.5 0.5 0.1"/> </geometry> </visual> </link> <!-- Joint definitions --> <joint name="arm_joint" type="revolute"> <parent link="base_link"/> <child link="arm_link"/> <axis xyz="0 0 1"/> <limit lower="-3.14" upper="3.14" effort="10" velocity="1"/> </joint> <!-- Additional links and joints can be added here --> <!-- Include Gazebo plugins --> <gazebo reference="base_link"> <material>Gazebo/Blue</material> </gazebo> </robot> ``` 注意,在 `<gazebo>` 标签下可以添加传感器插件或其他特定于 Gazebo 的配置选项[^2]。 --- #### 3. 配置 ros2_control 控制器 `ros2_control` 是连接 MoveIt2 和 Gazebo 的桥梁。为此,需编写一个 YAML 文件以定义控制器及其参数。 示例控制器配置文件 (`controller.yaml`) 如下: ```yaml controller_manager: ros__parameters: update_rate: 100 # Hz joint_state_broadcaster: ros__parameters: type: joint_state_broadcaster/JointStateBroadcaster forward_position_controller: ros__parameters: type: forward_command_controller/ForwardCommandController joints: - arm_joint ``` 在此配置中,`update_rate` 设置了控制器的刷新频率,而 `joints` 列表指定了受控的关节名称。 --- #### 4. 启动 Gazebo 并加载机器人模型 通过 Launch 文件启动 Gazebo,并加载之前定义的机器人模型。下面是一个简单的 Launch 文件示例: ```python from launch import LaunchDescription from launch_ros.actions import Node from launch.actions import ExecuteProcess, DeclareLaunchArgument from launch.substitutions import LaunchConfiguration def generate_launch_description(): use_sim_time = LaunchConfiguration('use_sim_time', default='true') return LaunchDescription([ DeclareLaunchArgument( 'use_sim_time', default_value='true', description='Use simulation (Gazebo) clock if true'), ExecuteProcess( cmd=['gazebo', '--verbose', '-s', 'libgazebo_ros_factory.so'], output='screen'), Node( package='robot_state_publisher', executable='robot_state_publisher', name='robot_state_publisher', parameters=[{'use_sim_time': use_sim_time}, {'robot_description': '<urdf>...</urdf>'}]), Node( package='controller_manager', executable='spawner.py', arguments=['joint_state_broadcaster']), Node( package='controller_manager', executable='spawner.py', arguments=['forward_position_controller']) ]) ``` 该脚本会启动 Gazebo、发布机器人状态并激活指定的控制器。 --- #### 5. 使用 MoveIt2 规划路径 最后一步是在 Rviz 中运行 MoveIt2 插件,以便可视化和交互式地规划机械臂的动作轨迹。这通常涉及以下几个步骤: - 加载 MoveIt2 配置包中的 SRDF 文件。 - 在 Rviz 中启用 Planning Scene 显示。 - 执行由 MoveIt2 计算得出的路径到目标位置。 可通过以下命令启动 MoveIt2 示范界面: ```bash ros2 launch moveit2_tutorials demo.launch.py ``` --- ### 注意事项 - 如果计划加入摄像头等传感器设备,则应在 Gazebo 模型中显式声明相应的插件。 - 确保所有节点的时间同步一致,尤其是在模拟环境中建议开启 `use_sim_time=true` 参数。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值