【MoveIt 2】直接通过 C++ API 使用 MoveIt : 时间参数化

MoveIt 目前主要是一个运动学运动规划框架 - 它规划关节或末端执行器的位置,但不规划速度或加速度。然而,MoveIt 确实利用后处理对运动学轨迹进行时间参数化,以获得速度和加速度值。下面我们解释了 MoveIt 这一部分涉及的设置和组件。

 速度控制 

 从文件 

默认情况下,MoveIt 将关节轨迹的关节速度和加速度限制设置为机器人 URDF 或 joint_limits.yaml 中允许的默认值。 joint_limits.yaml 是从设置助手生成的,最初是 URDF 中值的精确副本。然后,用户可以根据需要修改这些值,使其小于原始 URDF 值。如果需要特殊约束,可以使用键 max_position, min_position, max_velocity, max_acceleration, max_jerk 更改特定关节属性。可以使用键 has_velocity_limits, has_acceleration_limits, has_jerk_limits 打开或关闭关节限制。

 在运行时 

参数化运动轨迹的速度也可以在运行时修改为配置值中设置的最大速度和加速度的一部分,范围为 0-1 之间的值。要在每个运动计划的基础上更改速度,可以按照 MotionPlanRequest.msg 中描述的设置两个缩放因子。在 MoveIt MotionPlanning RViz 插件中也可以使用微调框来设置这两个因子。

时间参数化算法 

MoveIt 可以支持不同的算法来对运动轨迹进行后处理,以添加时间戳和速度/加速度值。目前,MoveIt 中只有一个选项:

  • 时间最优轨迹生成

    https://github.com/moveit/moveit2/blob/main/moveit_core/trajectory_processing/src/time_optimal_trajectory_generation.cpp

时间最优轨迹生成(TOTG)在 PR #809 和#1365 中引入。它生成具有非常平滑和连续速度曲线的轨迹。该方法基于将路径段拟合到原始轨迹,然后从优化路径中采样新的航点。这与严格的时间参数化方法不同,因为生成的航点可能在一定容差范围内偏离原始轨迹。因此,使用此方法时可能需要进行额外的碰撞检查。这是 MoveIt 2 中的默认设置。

https://github.com/moveit/moveit/pull/809

https://github.com/moveit/moveit/pull/1365

在本教程中记录了将时间参数化算法用作计划请求适配器的用法。https://moveit.picknik.ai/main/doc/examples/motion_planning_pipeline/motion_planning_pipeline_tutorial.html#using-a-planning-request-adapter

限加速度轨迹平滑 

一种时间参数化算法,如 TOTG,可以计算轨迹的速度和加速度,但没有一种时间参数化算法支持加加速度限制。这并不理想——轨迹上的大加加速度会导致运动不平稳或损坏硬件。作为进一步的后处理步骤,可以应用 Ruckig 加加速度限制平滑算法来限制轨迹上的关节加加速度。

要应用 Ruckig 平滑算法,应在 joint_limits.yaml 文件中定义加加速度限制。如果您未为任何关节指定加加速度限制,将应用合理的默认值并打印警告。

最后,将 Ruckig 平滑算法添加到规划请求适配器列表中(通常在 ompl_planning.yaml 中)。Ruckig 平滑算法应最后运行,因此将其放在列表顶部:

response_adapters:
  - default_planning_request_adapters/AddRuckigTrajectorySmoothing
  - default_planning_request_adapters/AddTimeOptimalParameterization
  ...
### 使用MoveIt2中的`move_group`接口进行C++开发 #### 初始化设置 为了使用 `move_group_interface` 进行操作,需要先初始化 ROS 2 节点并创建一个 `MoveGroupInterface` 对象。这一步骤确保了可以访问机器人模型以及配置文件中定义的各种参数[^1]。 ```cpp #include <rclcpp/rclcpp.hpp> #include <moveit/move_group_interface/move_group_interface.h> int main(int argc, char **argv) { rclcpp::init(argc, argv); // 创建ROS节点 auto node = std::make_shared<rclcpp::Node>("move_group_interface_tutorial"); // 实例化MoveGroupInterface对象 moveit::planning_interface::MoveGroupInterface move_group(node, "panda_arm"); ... } ``` #### 计划路径 通过调用 `plan()` 方法可以让 MoveIt 自动生成一条从当前位置到目标位置的安全路径。此过程涉及复杂的碰撞检测和优化算法以找到最优解[^2]。 ```cpp // 定义姿态目标 geometry_msgs::msg::Pose target_pose; target_pose.orientation.w = 1.0; target_pose.position.x = 0.28; target_pose.position.y = -0.7; target_pose.position.z = 1.0; // 设置目标姿态作为末端执行器的目标 move_group.setPoseTarget(target_pose); // 请求规划动作序列 moveit::planning_interface::MoveGroupInterface::Plan my_plan; bool success = (move_group.plan(my_plan) == moveit::core::MoveItErrorCode::SUCCESS); RCLCPP_INFO(LOGGER, "Planning %s!", success ? "success" : "failed"); ``` #### 执行计划 一旦成功获得了有效的运动方案,则可以通过 `execute()` 函数让实际硬件按照预定轨迹运行;如果是在仿真环境中测试的话则会模拟该过程。 ```cpp if(success){ bool executed_successfully = (move_group.execute(my_plan) == moveit::core::MoveItErrorCode::SUCCESS); RCLCPP_INFO(LOGGER, "Execution %s", executed_successfully ? "successful!" : "failed!"); } else { RCLCPP_ERROR(LOGGER,"Failed to plan path."); } ``` #### 处理多线程环境下的潜在问题 当涉及到异步回调或其他并发编程模式时需要注意避免因资源竞争而引发的死锁现象。对于某些特定场景可能还需要额外处理来防止程序长时间阻塞于等待响应的状态之中[^3]。 ```cpp auto future_result = move_group.asyncExecute(); std::future_status status = future_result.wait_for(std::chrono::seconds(5)); if(status != std::future_status::ready){ RCLCPP_WARN(LOGGER,"Timeout reached while waiting for execution result."); }else{ RCLCPP_INFO(LOGGER,"Action completed successfully."); } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值