Moveit代码 集合(2)Planning Scene(规划场景)

PlanningScene类提供了用于碰撞检测(checkCollision)和约束检查(checkConstraint)的主要接口。

通过RobotModel或URDF,SRDF可以轻松设置PlanningScene类,但是这种实例化PlanningScene对象的方法是不推荐的。PlanningSceneMonitor是推荐的利用来自机器人关节和传感器的数据创建和维护当前规划场景的方法。本例程只作为展示。

1.初始化ros节点,创建多线程并开始:

  ros::init(argc, argv, "panda_arm_kinematics");
  ros::AsyncSpinner spinner(1);
  spinner.start();

2.加载机器人模型,创建机器人模型对象,创建Planning_Scene类


  robot_model_loader::RobotModelLoader robot_model_loader("robot_description");
  const moveit::core::RobotModelPtr& kinematic_model = robot_model_loader.getModel();
  planning_scene::PlanningScene planning_scene(kinematic_model);//通过机器人模型创建PlanningScene类

3.碰撞检测(Collision Checking)

3.1自碰撞检测(self-collision checking)

collision_detection::CollisionRequest collision_request;//创建碰撞请求类,内含碰撞检测所需的参数,如对机器人哪个部件进行检测等,若参数为空,则为完整机器人
collision_detection::CollisionResult collision_result;//创建碰撞结果类,内含碰撞检测所有结果,如果不作特殊说明,仅有二值化的检测结果,即是否存在碰撞
planning_scene.checkSelfCollision(collision_request, collision_result);//对planning_scene对象做自碰撞检测,检测对象(机器人)为kinematic_model
ROS_INFO_STREAM("Test 1: Current state is " << (collision_result.collision ? "in" : "not in") << " self collision");//输出collision_result中的检测结果

3.2改变机器人状态再次检测

/*获取planning_scene当前机器人状态,创建机器人状态(robotstate)对象current_state(robotmodel类不能修改,robotstate类可以修改),创建的是& current_state,因此对current_state修改时,planning_scene中的机器人状态也被修改了,因此后面碰撞检测时是对设置为随机状态的机器人进行碰撞检测*/
moveit::core::RobotState& current_state = planning_scene.getCurrentStateNonConst();
current_state.setToRandomPositions();//将当前状态设为随机值
collision_result.clear();//重新检测碰撞之前,一般要清空碰撞检测结果
planning_scene.checkSelfCollision(collision_request, collision_result);//对设置为随机状态的机器人进行自碰撞检测,检测对象为完整的及其ir
ROS_INFO_STREAM("Test 2: Current state is " << (collision_result.collision ? "in" : "not in") << " self collision");//输出检测结果

3.3对部分杆件进行碰撞检测(未实现,github上提了issuse,目前无回复#769

collision_request.group_name = "panda_hand";//碰撞请求中group_name设置,对该杆件作碰撞检测,即该杆件与机器人其他部分的碰撞检测
current_state.setToRandomPositions();
collision_result.clear();
planning_scene.checkSelfCollision(collision_request, collision_result);
ROS_INFO_STREAM("Test 3: Current state is " << (collision_result.collision ? "in" : "not in") << " self collision");

3.4手动设置机器人状态,并检测是否满足机器人关节限制

std::vector<double> joint_values = { 0.0, 0.0, 0.0, -2.9, 0.0, 1.4, 0.0 };//创建关节值向量组,并赋值
const moveit::core::JointModelGroup* joint_model_group = current_state.getJointModelGroup("panda_arm");//创建joint_model_group对象,并采用当前机器人状态作为关节模型组
current_state.setJointGroupPositions(joint_model_group, joint_values);//设置机器人状态,将创建的关节值向量设置为当前机器人关节值
ROS_INFO_STREAM("Test 4: Current state is "
                << (current_state.satisfiesBounds(joint_model_group) ? "valid" : "not valid"));//检测当前关节值是否满足机器人限制,并输出

3.5接触信息输出

//输出接触状态需要对以下两个碰撞请求成员属性进行修改
collision_request.contacts = true;
collision_request.max_contacts = 1000;

collision_result.clear();//检测前清除之前检测结果
//进行自碰撞检测,注意,因为之前设置了collision_request.group_name为panda_hand,因此此处的检测仅为hand与机器人的碰撞检测
planning_scene.checkSelfCollision(collision_request, collision_result);
ROS_INFO_STREAM("Test 5: Current state is " << (collision_result.collision ? "in" : "not in") << " self collision");//输出碰撞检测信息
//建立输出接触状态的对象
collision_detection::CollisionResult::ContactMap::const_iterator it;
//循环输出接触状态
for (it = collision_result.contacts.begin(); it != collision_result.contacts.end(); ++it)
{
  ROS_INFO("Contact between: %s and %s", it->first.first.c_str(), it->first.second.c_str());
}

3.6修改允许碰撞矩阵(AllowedCollisionMatrix (ACM) )

ACM提供了允许忽略此处碰撞的机制(机器人自碰撞或者和环境的碰撞)

ollision_detection::AllowedCollisionMatrix acm = planning_scene.getAllowedCollisionMatrix();//创建ACM对象,对象为planning_scene下
moveit::core::RobotState copied_state = planning_scene.getCurrentState();//从当前状态,复制一个机器人状态

collision_detection::CollisionResult::ContactMap::const_iterator it2;//创建接触状态对象
//循环将当前发生碰撞的所有杆件设置为ACM成员
for (it2 = collision_result.contacts.begin(); it2 != collision_result.contacts.end(); ++it2)
{
  acm.setEntry(it2->first.first, it2->first.second, true);
}
collision_result.clear();//清除当前碰撞结果
//进行自碰撞检测,参数为:请求,结果,检测状态,acm
planning_scene.checkSelfCollision(collision_request, collision_result, copied_state, acm);
//输出碰撞结果
ROS_INFO_STREAM("Test 6: Current state is " << (collision_result.collision ? "in" : "not in") << " self collision");

3.7 完全碰撞检测(机器人自碰撞,机器人与环境碰撞),注意这要用机器人的填充版本,而非只有杆件的版本

collision_result.clear();
planning_scene.checkCollision(collision_request, collision_result, copied_state, acm);//完全检测,参数与上面一样
ROS_INFO_STREAM("Test 7: Current state is " << (collision_result.collision ? "in" : "not in") << " self collision");//输出检测结果

4.约束检测(Constraint Checking),分为两类,(1)机器人运动学约束(kinematic constraint):包括关节约束,位置约束,方向约束和可见性约束(?) (2)用户自定义约束

4.1 机器人运动学约束(kinematic constraint)

(1)创建目标约束

//创建表示末端执行器的字符串变量,赋值为关节模型组的最后一个元素,vector.back()为向量组最后一个元素
std::string end_effector_name = joint_model_group->getLinkModelNames().back();
//创建目标姿态,消息类型为geometry_msgs::PoseStamped
geometry_msgs::PoseStamped desired_pose;
//给目标姿态参数赋值,要求目标位姿保持w轴旋转1.0...
desired_pose.pose.orientation.w = 1.0;
desired_pose.pose.position.x = 0.3;
desired_pose.pose.position.y = -0.185;
desired_pose.pose.position.z = 0.5;
desired_pose.header.frame_id = "panda_link0";
/*创建目标约束,消息类型为moveit_msgs::Constraints,由kinematic_constraints::constructGoalConstraints函数确定值,施加约束的目标为end_effector_name,目标位姿约束为disired_pose
kinematic_constraints::constructGoalConstraints为表示运动学约束的表示和评估的命名空间*/
moveit_msgs::Constraints goal_constraint =
    kinematic_constraints::constructGoalConstraints(end_effector_name, desired_pose);

(2)检查是否满足约束

copied_state.setToRandomPositions();//将机器人状态设置为任意状态
copied_state.update();//更新机器人状态
bool constrained = planning_scene.isStateConstrained(copied_state, goal_constraint);//检查当前机器人状态是否满足前面设置的机器人运动学约束
ROS_INFO_STREAM("Test 8: Random state is " << (constrained ? "constrained" : "not constrained"));

(3)检查约束的另一种有效方法(更高效,有预处理)

//构造KinematicConstraintSet,用于预处理ros约束消息并设置以进行快速处理
kinematic_constraints::KinematicConstraintSet kinematic_constraint_set(kinematic_model);
//添加约束,参数为目标约束、
kinematic_constraint_set.add(goal_constraint, planning_scene.getTransforms());
//检查机器人状态是否满足约束
bool constrained_2 = planning_scene.isStateConstrained(copied_state, kinematic_constraint_set);
ROS_INFO_STREAM("Test 9: Random state is " << (constrained_2 ? "constrained" : "not constrained"));

(4)通过KinematicConstraintSet类,直接检查约束

kinematic_constraints::ConstraintEvaluationResult constraint_eval_result =
    kinematic_constraint_set.decide(copied_state);
ROS_INFO_STREAM("Test 10: Random state is " << (constraint_eval_result.satisfied ? "constrained" : "not constrained"));

4.2 用户定义约束(一个案例,用于检查joint1是否正角还是负角)

(1)函数定义

//定义一个函数,检查panda_joint1正负
bool stateFeasibilityTestExample(const moveit::core::RobotState& kinematic_state, bool /*verbose*/)
{
  const double* joint_values = kinematic_state.getJointPositions("panda_joint1");
  return (joint_values[0] > 0.0);
}

(2)将自定义函数指定给对象

//通过setStateFeasibilityPredicate函数,将用户定义的约束函数stateFeasibilityTestExample指定给planning_scene对象
planning_scene.setStateFeasibilityPredicate(stateFeasibilityTestExample);
//定义bool变量state_feasible,对状态可行性进行检测,检测的状态是copied_state
bool state_feasible = planning_scene.isStateFeasible(copied_state);
//检测,输出。若大于0,返回值为真,判断为feasible
ROS_INFO_STREAM("Test 11: Random state is " << (state_feasible ? "feasible" : "not feasible"));

/*在将用户约束函数制定给对象后,对对象进行isStateValid检测将会进行三个检测,碰撞检测,约束检测,用户自定义约束
三个参数分别为,要检测的机器人状态,运动学约束,机器人模型*/

bool state_valid = planning_scene.isStateValid(copied_state, kinematic_constraint_set, "panda_arm");
ROS_INFO_STREAM("Test 12: Random state is " << (state_valid ? "valid" : "not valid"));

<think>好的,用户的问题是关于解决MoveIt ROS规划场景接口中'/get_planning_scene'服务未被广播的问题。我需要仔细分析可能的原因并提供解决方案。首先,用户提到了引用中的内容,涉及UR3机械臂的配置和启动文件的问题,这可能与当前问题相关。 首先,我应该考虑服务未广播的常见原因。可能的原因包括节点未正确启动、服务名称不正确、依赖项缺失或配置错误。根据引用[2],用户之前遇到的问题是启动文件名称和配置的问题,比如需要指定正确的rviz配置文件。这可能暗示当前问题同样与启动文件或配置有关。 接下来,我需要检查用户是否正确启动了MoveGroup节点。根据MoveIt的文档,MoveGroup节点负责提供各种服务,包括规划场景。如果用户没有正确启动MoveGroup,服务自然不会存在。用户需要确认他们的启动文件是否包含了move_group节点的启动,比如通过move_group.launch文件。 另外,服务名称是否正确也很重要。用户提到的服务是'/get_planning_scene',但实际中MoveIt可能使用不同的服务名称。需要确认服务的确切名称,比如是否是'/move_group/get_planning_scene'。用户可以使用`rosservice list`命令来检查现有的服务名称。 然后,考虑规划场景是否正确初始化。如果规划场景模块未能正确初始化,服务可能无法注册。用户应该检查启动过程中的日志输出,查看是否有关于规划场景初始化的错误或警告信息。可能需要调整启动参数或配置文件来确保规划场景模块被正确加载。 依赖项也是一个可能的问题点。用户需要确认所有相关的ROS包都已正确安装,并且版本兼容。例如,moveit_ros_planning模块是否安装,或者是否存在版本冲突。使用`rosdep`检查依赖并安装缺失的包可能会有帮助。 此外,用户提到的引用[2]中关于UR3配置的问题,可能需要特别注意机器人的特定配置是否正确应用到当前项目中。例如,是否使用了正确的bringup文件,或者是否在MoveIt配置中正确指定了规划组和末端执行器。如果规划组设置不正确,可能导致服务无法正常广播。 最后,建议用户逐步排查:检查节点启动状态,确认服务名称是否存在,查看日志中的错误信息,验证配置文件和依赖项。如果问题依旧,可能需要查阅MoveIt的官方文档或社区寻求帮助,看看是否有已知的问题或解决方案。</think>要解决MoveIt ROS规划场景接口中`/get_planning_scene`服务未被广播的问题,可以按照以下步骤排查: --- ### **1. 确认节点启动状态** - **检查MoveGroup节点**:`/get_planning_scene`服务由`move_group`节点提供。确保已正确启动包含MoveIt配置的`move_group.launch`文件: ```bash roslaunch <your_robot_moveit_config> move_group.launch ``` 若未启动该节点,服务将无法广播[^1]。 --- ### **2. 验证服务名称** - **服务名称可能包含命名空间**:实际服务名称可能与预期不同。使用以下命令查看可用服务列表: ```bash rosservice list ``` 若服务显示为`/move_group/get_planning_scene`,则需在代码中使用完整名称调用[^2]。 --- ### **3. 检查规划场景初始化** - **确保规划场景模块加载**:在`move_group.launch`中检查是否启用了`allow_trajectory_execution`和`publish_monitored_planning_scene`参数: ```xml <param name="allow_trajectory_execution" value="true"/> <param name="publish_monitored_planning_scene" value="true"/> ``` 若配置错误会导致服务未注册。 --- ### **4. 依赖项验证** - **安装必要依赖**:确认已安装`moveit_ros_planning`和`moveit_ros_planning_interface`: ```bash sudo apt-get install ros-<distro>-moveit-ros-planning ``` --- ### **5. 配置问题排查** - **检查机器人URDF/SRDF配置**:引用[2]中提到的UR3配置问题表明,模型文件或规划组定义错误可能导致服务异常。确保: 1. MoveIt配置包中的`manipulator`规划组名称与代码中一致 2. 末端执行器(如`end effector`)在SRDF文件中正确定义 --- ### **6. 日志分析** - **查看节点输出日志**: ```bash rosconsole tail | grep "planning_scene" ``` 若出现`Failed to initialize planning scene`等错误,需重新生成MoveIt配置包。 --- ### **典型解决方案** ```python # 在代码中显式等待服务 rospy.wait_for_service('/move_group/get_planning_scene', timeout=10) get_planning_scene = rospy.ServiceProxy('/move_group/get_planning_scene', GetPlanningScene) response = get_planning_scene() ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值