MoveIt!入门教程-Move Group接口
MoveIt!入门教程-Move Group接口
说明
- MoveIt主要的用户接口功能通过MoveGroup类实现
- 这个类提供简易方式去实现大部分功能,比如:设置关节或目标姿态,创建行为规划,移动机器人,在环境中增加对象或给机器人增加或减少对象。
使用
- 安装
- MoveGroup类的使用非常简单,只需提供你想去控制或规划的组名
moveit::planning_interface::MoveGroup group("right_arm");
- 我们使用PlanningSceneInterface类去直接处理.
moveit::planning_interface::PlanningSceneInterface planning_scene_interface;
- (可选)在Rviz中创建一个发布用于可视化规划.
ros::Publisher display_publisher = node_handle.advertise<moveit_msgs::DisplayTrajectory>("/move_group/display_planned_path", 1, true);
moveit_msgs::DisplayTrajectory display_trajectory;
- 获得基本信息
- 打印这个组的参考系的名称
ROS_INFO("Reference frame: %s", group.getPlanningFrame().c_str());
- 打印这个组的末端执行器的名称
ROS_INFO("Reference frame: %s", group.getEndEffectorLink().c_str());
- 规划一个姿态目标
- 我们为这个组计划一个动作,移动末端执行器到希望的姿态。
geometry_msgs::Pose target_pose1;
target_pose1.orientation.w = 1.0;
target_pose1.position.x = 0.28;
target_pose1.position.y = -0.7;
target_pose1.position.z = 1.0;
group.setPoseTarget(target_pose1);
- 现在,我们调用规划器去计算规划和可视化过程,注意:我们只是规划,不要求move_group去实际移动机器人。
moveit::planning_interface::MoveGroup::Plan my_plan;
bool success = group.plan(my_plan);
ROS_INFO("Visualizing plan 1 (pose goal) %s",success?"":"FAILED");
/* Sleep to give Rviz time to visualize the plan. */
sleep(5.0);
4. 可视化规划
- 我们可以在Rviz里可视化这个规划。这个不是必需的,因为group.plan()的调用使得上面的过程会自动完成。在明确发布计划有用的情况下,我们想去可视化之前创建的规划。
if (1)
{
ROS_INFO("Visualizing plan 1 (again)");
display_trajectory.trajectory_start = my_plan.start_state_;
display_trajectory.trajectory.push_back(my_plan.trajectory_);
display_publisher.publish(display_trajectory);
/* Sleep to give Rviz time to visualize the plan. */
sleep(5.0);
}
5. 移动到目标姿态
- 移动到一个姿势的目标是类似于上述步骤除了我们现在使用的move()功能。
- 请注意,我们已经设置了前面的姿势目标仍然是有效的,所以机器人将尝试移动到那个目标。
- 我们不会在本教程中使用该函数,因为它是一个阻塞函数,需要一个控制器是激活,执行后报告成功的轨迹。
/* Uncomment below line when working with a real robot*/
/* group.move() */
6. 规划到一个关节空间内的目标
- 现在规划一个到关节空间内的目标并向其移动。这个会替代之前设置的目标
- 首先获取指定组的当前关节的设置
std::vector<double> group_variable_values;
group.getCurrentState()->copyJointGroupPositions(group.getCurrentState()->getRobotModel()->getJointModelGroup(group.getName()), group_variable_values);
- 修改一个关节,规划到新的目标并可视化
group_variable_values[0] = -1.0;
group.setJointValueTarget(group_variable_values);
success = group.plan(my_plan);
ROS_INFO("Visualizing plan 2 (joint space goal) %s",success?"":"FAILED");
/* Sleep to give Rviz time to visualize the plan. */
sleep(5.0);
7. 路径约束规划
- 路径约束容易指定机器人的一个连接。为组指定路径约束和目标姿态。
- 首先定义路径约束
moveit_msgs::OrientationConstraint ocm;
ocm.link_name = "r_wrist_roll_link";
ocm.header.frame_id = "base_link";
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);
group.setPathConstraints(test_constraints);
- 我们将重用我们曾经有过的旧的目标,并规划它。
- 请注意,如果目前的状态已经满足路径约束。这就能开始工作,
- 因此,我们需要将启动状态设置为一个新的姿势。
robot_state::RobotState start_state(*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;
const robot_state::JointModelGroup *joint_model_group =
start_state.getJointModelGroup(group.getName());
start_state.setFromIK(joint_model_group, start_pose2);
group.setStartState(start_state);
- 我们规划从新的开始姿态移动到之前的目标姿态
group.setPoseTarget(target_pose1);
success = group.plan(my_plan);
ROS_INFO("Visualizing plan 3 (constraints) %s",success?"":"FAILED");
/* Sleep to give Rviz time to visualize the plan. */
sleep(10.0);
- 当做了路径约束时一定要清除它。
group.clearPathConstraints();
8. 笛卡尔路径
- 你可以计划一个笛卡尔路径通过直接为末端执行器指定航点列表。
- 请注意,我们是从新的开始状态。初始姿态(起始状态)不需要加入航点列表。
std::vector<geometry_msgs::Pose> waypoints;
geometry_msgs::Pose target_pose3 = start_pose2;
target_pose3.position.x += 0.2;
target_pose3.position.z += 0.2;
waypoints.push_back(target_pose3); // up and out
target_pose3.position.y -= 0.2;
waypoints.push_back(target_pose3); // left
target_pose3.position.z -= 0.2;
target_pose3.position.y += 0.2;
target_pose3.position.x -= 0.2;
waypoints.push_back(target_pose3); // down and right (back to start)
- 我们希望笛卡尔路径被内插在一个分辨率为1厘米,这就是为何在笛卡尔转换指定0.01作为最大值。我们指定跳阈值为0,实际上是禁用它。(没理解好留原文)We want the cartesian path to be interpolated at a resolution of 1 cm which is why we will specify 0.01 as the max step in cartesian translation. We will specify the jump threshold as 0.0, effectively disabling it.
moveit_msgs::RobotTrajectory trajectory;
double fraction = group.computeCartesianPath(waypoints,
0.01, // eef_step
0.0, // jump_threshold
trajectory);
ROS_INFO("Visualizing plan 4 (cartesian path) (%.2f%% acheived)",
fraction * 100.0);
/* Sleep to give Rviz time to visualize the plan. */
sleep(15.0);
9. 添加/删除对象和附着/分离对象
- 首先,我们将定义碰撞对象消息。
moveit_msgs::CollisionObject collision_object;
collision_object.header.frame_id = group.getPlanningFrame();
/* The id of the object is used to identify it. */
collision_object.id = "box1";
/* Define a box to add to the world. */
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;
/* A pose for the box (specified relative to frame_id) */
geometry_msgs::Pose box_pose;
box_pose.orientation.w = 1.0;
box_pose.position.x = 0.6;
box_pose.position.y = -0.4;
box_pose.position.z = 1.2;
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("Add an object into the world");
planning_scene_interface.addCollisionObjects(collision_objects);
/* Sleep so we have time to see the object in RViz */
sleep(2.0);
- 带有碰撞检测的规划是很慢的。让我们制定计划时间,以确保规划有足够的时间来计划。10秒应该是足够的。
group.setPlanningTime(10.0);
- 现在当我们计划一个轨迹,它将避免障碍
group.setStartState(*group.getCurrentState());
group.setPoseTarget(target_pose1);
success = group.plan(my_plan);
ROS_INFO("Visualizing plan 5 (pose goal move around box) %s",
success?"":"FAILED");
/* Sleep to give Rviz time to visualize the plan. */
sleep(10.0);
- 现在,让我们把碰撞物体附加到机器人上。
ROS_INFO("Attach the object to the robot");
group.attachObject(collision_object.id);
/* Sleep to give Rviz time to show the object attached (different color). */
sleep(4.0);
- 现在,让我们从机器人中分离碰撞物体。
ROS_INFO("Detach the object from the robot");
group.detachObject(collision_object.id);
/* Sleep to give Rviz time to show the object detached. */
sleep(4.0);
- 现在,让我们从世界上删除碰撞对象。
ROS_INFO("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);
/* Sleep to give Rviz time to show the object is no longer there. */
sleep(4.0);
10. 双手臂位姿
- 首先定义一个新组安置两个手臂。定义两个新的独立的姿态目标,分别是为每个末端执行器。
- 注意:我们会重用以上针对右臂的目标。
moveit::planning_interface::MoveGroup two_arms_group("arms");
two_arms_group.setPoseTarget(target_pose1, "r_wrist_roll_link");
geometry_msgs::Pose target_pose2;
target_pose2.orientation.w = 1.0;
target_pose2.position.x = 0.7;
target_pose2.position.y = 0.15;
target_pose2.position.z = 1.0;
two_arms_group.setPoseTarget(target_pose2, "l_wrist_roll_link");
- 规划并可视化
moveit::planning_interface::MoveGroup::Plan two_arms_plan;
two_arms_group.plan(two_arms_plan);
sleep(4.0);
11. 完整代码
- 完整代码可以这里找到。下载代码
12. 编译代码
13. launch文件
- 所有的launch文件在这
- 代码来自moveit_tutorials软件包(是你安装MoveIt的一部分),你可以编译和运行。
14. 启动代码
roslaunch moveit_tutorials move_group_interface_tutorial.launch
- 效果如下:
- 在窗口的底部的右侧部分的运动规划部分可以关闭,以获得更好的机器人视图。
15. 期望输出
- 在Rviz,我们应该能够看到下面的(会有一个延迟5-10秒之间每一步):
- 机器人移动右臂到右前方的姿态目标
- 重复上面的动作
- 机器人移动右臂到右边的连接目标
- 机器人移动右臂回到新的姿态目标并保持末端执行器水平
- 机器人沿着笛卡尔路径期望的路径移动右臂(三角形向上+向前,左,下+后)
- 盒子对象增加到右臂的右边。
- 机器人移动右臂到姿态目标,避开与盒子碰撞
- 该对象连接到手腕上(它的颜色将改变到紫色/橙色/绿色)
- 该对象是从手腕上脱离(它的颜色会变回绿色)
- 该对象被从环境中移除。
获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号