Moveit! 学习 - Move Group(C++接口)

在MoveIt中,最简单的用户接口是MoveGroup类,提供了对于控制机器人的常用基本操作:

  • 设置关节角度或机器人姿态目标
  • 运动规划
  • 移动机器人
  • 添加物体到环境里/从环境移除
  • 将物体绑定到机器人上/从机器人上解绑

这个接口通过ROS主题、服务和操作与MoveGroup节点通信。

1.Running the Code

roslaunch panda_moveit_config demo.launch

运行launch 文件

roslaunch moveit_tutorials move_group_interface_tutorial.launch

【报错】

ERROR: cannot launch node of type [moveit_tutorials/move_group_interface_tutorial]: can't locate node [move_group_interface_tutorial] in package [moveit_tutorials]

【解析】
介个问题困扰了我很久。。。
首先,我有 catkin_ws 和 ws_moveit 两个工作区,可能是因为嵌套catkin工作区(即将工作区放入另一个工作区)。虽然它在技术上是可行的(确认catkin_make每个工作区都按预期运行),但不建议这样做,这会导致意想不到的结果。
【解决】
删除在ws_moveit中的build和devel文件夹,然后运行catkin_make,再次编译。
参考:https://answers.ros.org/question/251251/cant-locate-node-moveit_setup_assistant-in-package-moveit_setup_assistant/.

使用RvizVisualToolsGui面板,按下RvizVisualToolsGui面板中的Next按钮,或者在屏幕顶部的Tools面板中选择Key Tool,然后当RViz聚焦时按键盘上的N。
在这里插入图片描述
在这里插入图片描述

2.运行结果

教程中,对机械臂进行了以下几种控制:

  • 手臂运动到前方的目标姿态
  • 手臂运动到两侧的目标姿态
  • 手臂运动到一个新的目标姿态但维持末端执行器不动
  • 手臂按照一个给定的轨迹运动
  • 一个长方体物体添加到环境里
  • 手臂绕过物体到达新的目标姿态
  • 把物体固定到手臂上
  • 把物体从手臂上移除
  • 把物体从环境中移除

3.代码

完整代码路径:
/home/hjs/ws_moveit/src/moveit_tutorials/doc/move_group_interface/src/move_group_interface_tutorial.cpp

代码解析:

3.1 setup:

MoveIt!对称为“planning groups”的一组关节进行操作,并将它们存储在一个名为JointModelGroup的对象中。在整个MoveIt中!术语“planning groups”和“joint model group”可互换使用。

static const std::string PLANNING_GROUP = "panda_arm";

设置 MoveGroup 类(使用想要控制和规划的 planning group 的名字即可)

moveit::planning_interface::MoveGroupInterface move_group(PLANNING_GROUP);

使用PlanningSceneInterface类在“虚拟世界”场景中添加和删除碰撞对象:

moveit::planning_interface::PlanningSceneInterface planning_scene_interface;

为了提高性能,经常使用原始指针来引用planning group:

const robot_state::JointModelGroup* joint_model_group =
      move_group.getCurrentState()->getJointModelGroup(PLANNING_GROUP);

3.2 Visualization:

MoveItVisualTools包提供许多功能,在RViz中对于可视化对象、机器人和轨迹,和调试工具,比如脚本检查。

namespace rvt = rviz_visual_tools;
  moveit_visual_tools::MoveItVisualTools visual_tools("panda_link0");
  visual_tools.deleteAllMarkers();

远程控制是一种自省工具,允许用户通过RViz中的按钮和键盘快捷键逐步浏览高级脚本

visual_tools.loadRemoteControl();

RViz提供了多种类型的标记,在此演示中,使用文本,圆柱体和球体

Eigen::Affine3d text_pose = Eigen::Affine3d::Identity();
  text_pose.translation().z() = 1.75;
  visual_tools.publishText(text_pose, "MoveGroupInterface Demo", rvt::WHITE, rvt::XLARGE);

批量发布用于减少发送到RViz进行大型可视化的消息数量

visual_tools.trigger();

3.3 Getting Basic Information

打印机器人参考框架的名字:

ROS_INFO_NAMED("tutorial", "Reference frame: %s", move_group.getPlanningFrame().c_str());

打印末端执行器链接的名称:

ROS_INFO_NAMED("tutorial", "End effector link: %s", move_group.getEndEffectorLink().c_str());

3.4 start the demo

visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to start the demo");

3.5 Planning to a Pose goal

指定一个末端执行器的目标姿态,调用规划运动:

  geometry_msgs::Pose target_pose1;
  target_pose1.orientation.w = 1.0;
  target_pose1.position.x = 0.28;
  target_pose1.position.y = -0.2;
  target_pose1.position.z = 0.5;
  move_group.setPoseTarget(target_pose1);

调用planner来计算计划并将其可视化(只是规划,还没有具体控制运动):

  moveit::planning_interface::MoveGroupInterface::Plan my_plan;

  bool success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS);

  ROS_INFO_NAMED("tutorial", "Visualizing plan 1 (pose goal) %s", success ? "" : "FAILED");

3.6 Visualizing plans

用RViz中的标记将计划可视化为一条线:

  ROS_INFO_NAMED("tutorial", "Visualizing plan 1 as trajectory line");
  visual_tools.publishAxisLabeled(target_pose1, "pose1");
  visual_tools.publishText(text_pose, "Pose Goal", rvt::WHITE, rvt::XLARGE);
  visual_tools.publishTrajectoryLine(my_plan.trajectory_, joint_model_group);
  visual_tools.trigger();
  visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo");

在这里插入图片描述

3.7 Moving to a pose goal

调用move()执行运动:

  /* Uncomment below line when working with a real robot */
  /* move_group.move(); */

是一个阻塞函数,需要控制器处于活动状态,并报告轨迹执行成功,注释掉因为是模拟,没有真正的硬件,调用的话会阻塞。

3.8 Planning to a joint-space goal

通过在关节空间定义一个目标的方式进行控制。旧的目标会被覆盖。

  • 创建一个引用当前robot状态的指针。RobotState是包含所有当前位置/速度/加速度数据的对象
moveit::core::RobotStatePtr current_state = move_group.getCurrentState();
  • 获取当前关节位置:
  std::vector<double> joint_group_positions;
  current_state->copyJointGroupPositions(joint_model_group, joint_group_positions);
  • 修改其中一个关节,规划新的关节空间目标,并将其可视化:
  joint_group_positions[0] = -1.0;  // radians
  move_group.setJointValueTarget(joint_group_positions);

  success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS);
  ROS_INFO_NAMED("tutorial", "Visualizing plan 2 (joint space goal) %s", success ? "" : "FAILED");
  • 在RViz中可视化:
  visual_tools.deleteAllMarkers();
  visual_tools.publishText(text_pose, "Joint Space Goal", rvt::WHITE, rvt::XLARGE);
  visual_tools.publishTrajectoryLine(my_plan.trajectory_, joint_model_group);
  visual_tools.trigger();
  visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo");

在这里插入图片描述

3.9 Planning with Path Constraints

  • 定义约束:
  moveit_msgs::OrientationConstraint ocm;
  ocm.link_name = "panda_link7";
  ocm.header.frame_id = "panda_link0";
  ocm.orientation.w = 1.0;
  ocm.absolute_x_axis_tolerance = 0.1;
  ocm.absolute_y_axis_tolerance = 0.1;
  ocm.absolute_z_axis_tolerance = 0.1;
  ocm.weight = 1.0;
  • 添加到指定规划组:
  moveit_msgs::Constraints test_constraints;
  test_constraints.orientation_constraints.push_back(ocm);
  move_group.setPathConstraints(test_constraints);
  • 下一步进行规划,再次使用之前定义的目标姿态target_pose1。给定一个新的起始姿态。(只有在当前状态已经满足路径约束时,此操作才有效)
  robot_state::RobotState start_state(*move_group.getCurrentState());
  geometry_msgs::Pose start_pose2;
  start_pose2.orientation.w = 1.0;
  start_pose2.position.x = 0.55;
  start_pose2.position.y = -0.05;
  start_pose2.position.z = 0.8;
  start_state.setFromIK(joint_model_group, start_pose2);
  move_group.setStartState(start_state);
  • 设置目标姿态:
  move_group.setPoseTarget(target_pose1);
  • 加入约束条件后规划会比较耗时,因为每次采样都需要调用逆运动求解。这里把规划时间增加到10秒,保证有足够的时间规划成功。
  move_group.setPlanningTime(10.0);

  success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS);
  ROS_INFO_NAMED("tutorial", "Visualizing plan 3 (constraints) %s", success ? "" : "FAILED");
  • 在rviz中显示:
  visual_tools.deleteAllMarkers();
  visual_tools.publishAxisLabeled(start_pose2, "start");
  visual_tools.publishAxisLabeled(target_pose1, "goal");
  visual_tools.publishText(text_pose, "Constrained Goal", rvt::WHITE, rvt::XLARGE);
  visual_tools.publishTrajectoryLine(my_plan.trajectory_, joint_model_group);
  visual_tools.trigger();
  visual_tools.prompt("next step");

在这里插入图片描述

  • 当完成路径约束时,一定要清除约束条件:
move_group.clearPathConstraints();
  • 因为设置了开始状态,所以必须在规划其它路径之前清除它:
move_group.setStartStateToCurrentState();

3.10 Cartesian Paths(笛卡尔路径)

通过给定一系列路径点来让末端执行器经过一个特定的路径:

  • 创建一个pose的vector,当前的机器人位置是在start_pose3,起始点不是必须加进数组里(这里加进去是为了可以在rviz中显示)
  geometry_msgs::Pose target_pose3 = move_group.getCurrentPose().pose;

  std::vector<geometry_msgs::Pose> waypoints;
  waypoints.push_back(target_pose3);

  target_pose3.position.z -= 0.2;
  waypoints.push_back(target_pose3);  // down

  target_pose3.position.y -= 0.2;
  waypoints.push_back(target_pose3);  // right

  target_pose3.position.z += 0.2;
  target_pose3.position.y += 0.2;
  target_pose3.position.x -= 0.2;
  waypoints.push_back(target_pose3);  // up and left
  • 笛卡尔运动经常需要较慢的动作,比如接近和后退的抓握运动。在这里,演示了如何通过每个关节的最大速度比例因子来降低机器人手臂的速度。注意这不是末端执行器的速度。
move_group.setMaxVelocityScalingFactor(0.1);
  • 调用computeCartesianPath(…)按一定步长插补得到一个plan。这里的步长eef_step设置为0.01,路径的分辨率就是1cm。跳动阈值jump_threshold设置为0.0将其禁用(控制真实机械臂时会有问题)。返回值是0.0~1.0之间的一个数值,表示成功规划了给定路径点的多少(1.0表示都能成功经过)。
  moveit_msgs::RobotTrajectory trajectory;
  const double jump_threshold = 0.0;
  const double eef_step = 0.01;
  double fraction = move_group.computeCartesianPath(waypoints, eef_step, jump_threshold, trajectory);
  ROS_INFO_NAMED("tutorial", "Visualizing plan 4 (Cartesian path) (%.2f%% acheived)", fraction * 100.0);
  • 在RViz中可视化该计划:
  visual_tools.deleteAllMarkers();
  visual_tools.publishText(text_pose, "Joint Space Goal", rvt::WHITE, rvt::XLARGE);
  visual_tools.publishPath(waypoints, rvt::LIME_GREEN, rvt::SMALL);
  for (std::size_t i = 0; i < waypoints.size(); ++i)
    visual_tools.publishAxisLabeled(waypoints[i], "pt" + std::to_string(i), rvt::SMALL);
  visual_tools.trigger();
  visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo");

在这里插入图片描述

3.11 Adding/Removing Objects and Attaching/Detaching Objects

(添加/删除对象和附加/分离对象)

  • 利用moveit_msgs::CollisionObject定义一个物体
  moveit_msgs::CollisionObject collision_object;
  collision_object.header.frame_id = move_group.getPlanningFrame();

设置一个id用于标识它:

  collision_object.id = "box1";
  • 定义一个立方体:
  shape_msgs::SolidPrimitive primitive;
  primitive.type = primitive.BOX;
  primitive.dimensions.resize(3);
  primitive.dimensions[0] = 0.4;
  primitive.dimensions[1] = 0.1;
  primitive.dimensions[2] = 0.4;
  • 为框定义一个位姿[指定相对于frame_id]
  geometry_msgs::Pose box_pose;
  box_pose.orientation.w = 1.0;
  box_pose.position.x = 0.4;
  box_pose.position.y = -0.2;
  box_pose.position.z = 1.0;

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

  std::vector<moveit_msgs::CollisionObject> collision_objects;
  collision_objects.push_back(collision_object);
  • 碰撞对象添加到世界
  ROS_INFO_NAMED("tutorial", "Add an object into the world");
  planning_scene_interface.addCollisionObjects(collision_objects);
  • 显示文本在RViz的状态
  visual_tools.publishText(text_pose, "Add object", rvt::WHITE, rvt::XLARGE);
  visual_tools.trigger();
  • 等待MoveGroup接收并处理collision对象消息:
visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to once the collision object appears in RViz");

在这里插入图片描述

  • 现在如果规划一个运动,其路径会避开这个物体:
  move_group.setStartState(*move_group.getCurrentState());
  geometry_msgs::Pose another_pose;
  another_pose.orientation.w = 1.0;
  another_pose.position.x = 0.4;
  another_pose.position.y = -0.4;
  another_pose.position.z = 0.9;
  move_group.setPoseTarget(another_pose);

  success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS);
  ROS_INFO_NAMED("tutorial", "Visualizing plan 5 (pose goal move around cuboid) %s", success ? "" : "FAILED");
  • rivz显示结果并提示下一步操作:
  visual_tools.deleteAllMarkers();
  visual_tools.publishText(text_pose, "Obstacle Goal", rvt::WHITE, rvt::XLARGE);
  visual_tools.publishTrajectoryLine(my_plan.trajectory_, joint_model_group);
  visual_tools.trigger();
  visual_tools.prompt("next step");

在这里插入图片描述

  • 把碰撞物体连接到机器人上:
  ROS_INFO_NAMED("tutorial", "Attach the object to the robot");
  move_group.attachObject(collision_object.id);
  • rivz显示结果并提示下一步操作:
  visual_tools.publishText(text_pose, "Object attached to robot", rvt::WHITE, rvt::XLARGE);
  visual_tools.trigger();

  /* Wait for MoveGroup to recieve and process the attached collision object message */
  visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to once the collision object attaches to the "
                      "robot");

在这里插入图片描述

  • 解绑物体:
  ROS_INFO_NAMED("tutorial", "Detach the object from the robot");
  move_group.detachObject(collision_object.id);
  • rivz显示结果并提示下一步操作:
  visual_tools.publishText(text_pose, "Object dettached from robot", rvt::WHITE, rvt::XLARGE);
  visual_tools.trigger();

  /* Wait for MoveGroup to recieve and process the attached collision object message */
  visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to once the collision object detaches to the "
                      "robot");

在这里插入图片描述

  • 从世界中移除碰撞对象:
  ROS_INFO_NAMED("tutorial", "Remove the object from the world");
  std::vector<std::string> object_ids;
  object_ids.push_back(collision_object.id);
  planning_scene_interface.removeCollisionObjects(object_ids);
  • rivz显示结果并提示下一步操作:
  visual_tools.publishText(text_pose, "Object removed", rvt::WHITE, rvt::XLARGE);
  visual_tools.trigger();

  /* Wait for MoveGroup to recieve and process the attached collision object message */
  visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to once the collision object disapears");

在这里插入图片描述

3.12 完整代码

代码链接

【参考资源】
官网
The move_group_interface

  • 5
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`move_group.MoveGroupCommander.retime_trajectory` 是 MoveIt 中 `MoveGroupCommander` 类的一个成员函数,用于重新计算规划轨迹的时间。具体用法如下: ```python retime_trajectory(self, planning_scene, trajectory, velocity_scaling_factor=1.0, acceleration_scaling_factor=1.0) ``` 函数参数: - `planning_scene`:规划场景,类型为 `moveit_msgs.msg.PlanningScene`。 - `trajectory`:需要重新计算时间的轨迹,类型为 `moveit_msgs.msg.RobotTrajectory`。 - `velocity_scaling_factor`:速度缩放因子,范围为 [0, 1],默认值为 1。 - `acceleration_scaling_factor`:加速度缩放因子,范围为 [0, 1],默认值为 1。 函数返回值: 重新计算时间后的轨迹,类型为 `moveit_msgs.msg.RobotTrajectory`。 使用示例: ```python import rospy import moveit_commander from moveit_msgs.msg import PlanningScene rospy.init_node('retime_trajectory_example', anonymous=True) robot = moveit_commander.RobotCommander() scene = moveit_commander.PlanningSceneInterface() group_name = "manipulator" move_group = moveit_commander.MoveGroupCommander(group_name) # 设置机械臂的允许误差值 move_group.set_goal_joint_tolerance(0.001) # 设置机械臂的运动速度和加速度 move_group.set_max_velocity_scaling_factor(0.5) move_group.set_max_acceleration_scaling_factor(0.5) # 获取当前的机械臂姿态 joint_goal = move_group.get_current_joint_values() # 设置机械臂目标位置 joint_goal[0] = 1.57 joint_goal[1] = -1.57 joint_goal[2] = 1.57 joint_goal[3] = -1.57 joint_goal[4] = 1.57 joint_goal[5] = 0.0 move_group.set_joint_value_target(joint_goal) # 进行运动规划 plan = move_group.plan() # 进行轨迹时间重新计算 scene_msg = PlanningScene() trajectory_msg = plan.joint_trajectory new_trajectory = move_group.retime_trajectory(scene_msg, trajectory_msg) # 执行新的轨迹 move_group.execute(new_trajectory) ``` 以上示例代码演示了如何使用 `retime_trajectory` 函数对机械臂运动轨迹的时间进行重新计算,使得机械臂的运动速度和加速度符合用户的要求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值