机器人和机器的瞬时运动生成。
项目描述
鲁基格
机器人和机器的瞬时运动生成。
Ruckig 即时生成轨迹,允许机器人和机器对传感器输入做出即时反应。Ruckig 从受速度、加速度和加加速度限制的任何初始状态开始计算到目标航路点的轨迹(包括位置、速度和加速度) 。除了目标状态,Ruckig 还允许定义航点跟踪的中间位置。对于状态到状态的运动,Ruckig 保证时间最优的解决方案。Ruckig 使用中间航路点联合计算路径及其时间参数化,与传统方法相比,轨迹明显更快。
更多信息可以在ruckig.com和相应的论文Jerk-limited Real-time Trajectory Generation with Arbitrary Target States中找到,该论文已被2021 年机器人学:科学与系统 (RSS)会议接受。
安装
Ruckig 没有依赖项(测试除外)。要使用 CMake 构建 Ruckig,只需运行
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make
要将 Ruckig 安装在系统范围的目录中,请使用(sudo) make install
. 在 CMake 项目中使用 Ruckig 的示例由examples/CMakeLists.txt
. 但是,您也可以将 Ruckig 作为目录包含在您的项目中并调用add_subdirectory(ruckig)
您的 parent CMakeLists.txt
。要为中间航点启用在线 APIBUILD_ONLINE_CLIENT
,只需将标志传递给 CMake。
Ruckig 也可用作 Python 模块,特别是用于开发或调试目的。Ruckig社区版可以通过PyPI安装
pip install ruckig
使用 CMake 时,可以使用BUILD_PYTHON_MODULE
标志构建 Python 模块。如果您只对 Python 模块(而不是 C++ 库)感兴趣,您可以通过pip install .
.
教程
此外,我们将解释在您的应用程序中开始使用在线生成轨迹的基础知识。还有一系列示例可指导您了解 Ruckig 最重要的功能。下图显示了单自由度的时间最优轨迹。我们还为所有示例的结果轨迹添加了图。让我们开始吧!
基于航点的轨迹生成
Ruckig 提供三个主要接口类:Ruckig、InputParameter和OutputParameter类。
首先,您需要创建一个Ruckig 实例,其中DoF 的数量作为模板参数,并在构造函数中控制周期(例如以秒为单位)。
Ruckig<6> ruckig {0.001}; // Number DoFs; control cycle in [s]
输入类型有 3 个数据块:当前状态、目标状态和相应的运动学限制。
InputParameter<6> input; // Number DoFs
input.current_position = {0.2, ...};
input.current_velocity = {0.1, ...};
input.current_acceleration = {0.1, ...};
input.target_position = {0.5, ...};
input.target_velocity = {-0.1, ...};
input.target_acceleration = {0.2, ...};
input.max_velocity = {0.4, ...};
input.max_acceleration = {1.0, ...};
input.max_jerk = {4.0, ...};
OutputParameter<6> output; // Number DoFs
给定所有输入和输出资源,我们可以在每个离散时间步上迭代轨迹。对于大多数应用程序,此循环必须在实时线程中运行并控制实际硬件。
while (ruckig.update(input, output) == Result::Working) {
// Make use of the new state here!
// e.g. robot->setJointPositions(output.new_position);
output.pass_to_input(input); // Don't forget this!
}
在控制回路内,您需要根据计算出的轨迹更新输入参数的当前状态。因此,该pass_to_input
方法将输出的新运动学状态复制到输入参数的当前运动学状态。如果(在下一步中)当前状态不是预期的、预先计算的轨迹,Ruckig 将根据新的输入计算新的轨迹。当轨迹达到目标状态时,update
函数将返回Result::Finished
。
中间航点
Ruckig 社区版现在通过远程 API支持中间航路点。确保-DBUILD_ONLINE_CLIENT=ON
在编译时将其包含为 CMake 标志 - PyPI Python 版本应该开箱即用。为了预先为可变数量的航点分配必要的内存,我们需要将最大数量的航点传递给 Ruckig
Ruckig<6> otg {0.001, 8};
InputParameter<6> input {8};
OutputParameter<6> output {8};
该类InputParameter
将航点的数量作为可选输入,但通常您将自己填写值(并因此保留其内存)。然后你就可以通过点设置中间了
input.intermediate_positions = {
{0.2, ...},
{0.8, ...},
};
只要给出了至少一个中间位置,Ruckig 社区版就会切换到提到的(当然,非实时的)远程 API。如果您需要在自己的硬件上进行实时计算,我们参考Ruckig Pro 版本。
当使用中间位置时,潜在的运动规划问题及其计算都会发生显着变化。特别是,在航路点的使用方面,Jerk-limited 在线轨迹生成存在一些基本限制。请在此处找到有关这些限制的更多信息,通常我们建议使用
input.intermediate_positions = otg.filter_intermediate_positions(input.intermediate_positions, {0.1, ...});
根据(高)阈值距离过滤航点。设置interrupt_calculation_duration通过在下一次控制调用中优化解决方案来确保具有实时能力。请注意,这是计算的软中断。目前,使用中间位置时不支持最小或离散持续时间。
输入参数
更详细地说,InputParameter类型具有以下成员:
using Vector = std::array<double, DOFs>; // By default
Vector current_position;
Vector current_velocity; // Initialized to zero
Vector current_acceleration; // Initialized to zero
std::vector<Vector> intermediate_positions; // (only in Pro Version)
Vector target_position;
Vector target_velocity; // Initialized to zero
Vector target_acceleration; // Initialized to zero
Vector max_velocity;
Vector max_acceleration;
Vector max_jerk;
std::optional<Vector> min_velocity; // If not given, the negative maximum velocity will be used.
std::optional<Vector> min_acceleration; // If not given, the negative maximum acceleration will be used.
std::optional<Vector> min_position; // (only in Pro Version)
std::optional<Vector> max_position; // (only in Pro Version)
std::array<bool, DOFs> enabled; // Initialized to true
std::optional<double> minimum_duration;
std::optional<double> interrupt_calculation_duration; // [µs], (only in Pro Version)
ControlInterface control_interface; // The default position interface controls the full kinematic state.
Synchronization synchronization; // Synchronization behavior of multiple DoFs
DurationDiscretization duration_discretization; // Whether the duration should be a discrete multiple of the control cycle (off by default)
std::optional<Vector<ControlInterface>> per_dof_control_interface; // Sets the control interface for each DoF individually, overwrites global control_interface
std::optional<Vector<Synchronization>> per_dof_synchronization; // Sets the synchronization for each DoF individually, overwrites global synchronization
除了当前状态、目标状态和约束之外,Ruckig 还允许进行一些更高级的设置:
- 可以指定最小速度和加速度 - 这些应该是负数。如果没有给出,将使用负的最大速度或加速度(类似于加加速度限制)。例如,这在对人类具有不同速度限制的人类机器人协作设置中可能很有用。或者,在不同的移动坐标系之间切换时,例如从传送带上拾取。
- 您可以覆盖全局运动学限制以分别使用例如指定两个航路点之间的每个部分的限制
per_section_max_velocity
。 - 如果 DoF 未启用,则在计算中将被忽略。Ruckig 将为这些自由度输出具有恒定加速度的轨迹。
- 可以选择指定最小持续时间。请注意,Ruckig 不能保证准确的轨迹,而只能保证轨迹的最短持续时间。
- 控制界面(位置或速度控制)可以轻松切换。例如,可以使用速度接口轻松实现停止轨迹或视觉伺服。
- 实现了不同的同步行为(即阶段、时间或无同步)。相位同步导致直线运动。
- 轨迹持续时间可能被限制为控制周期的倍数。这样,可以在控制循环执行时达到准确的状态。
我们参考命名空间内枚举的API 文档ruckig
以获取所有可用选项。
输入验证
为了在实际计算步骤之前检查 Ruckig 是否能够生成轨迹,
ruckig.validate_input(input, check_current_state_within_limits=false, check_target_state_within_limits=true);
// returns boolean
false
如果输入无效则返回。两个布尔参数检查当前或目标状态是否在限制范围内。检查包括一个典型的 jerk-limited 轨迹生成捕获:当当前状态处于最大速度时,任何正加速度都将不可避免地导致未来时间步的速度违规。一般来说,这个条件是满足的
Abs(acceleration) <= Sqrt(2 * max_jerk * (max_velocity - Abs(velocity))).
如果两个参数都设置为 true,则计算出的轨迹保证在其整个持续时间内都在运动学限制内。另外,请注意,由于数字原因,输入存在范围限制,有关详细信息,请参见下文。
结果类型
Ruckig 类的update
函数返回一个指示算法当前状态的 Result 类型。这可以是工作,如果轨迹已经完成,或者如果在计算过程中出现问题,则为错误类型。结果类型可以作为标准整数进行比较。
状态 | 错误代码 |
---|---|
在职的 | 0 |
完成的 | 1 |
错误 | -1 |
错误无效输入 | -100 |
错误轨迹持续时间 | -101 |
错误位置限制 | -102 |
错误执行时间计算 | -110 |
错误同步计算 | -111 |
输出参数
输出类包括新的运动状态和整体轨迹。
Vector new_position;
Vector new_velocity;
Vector new_acceleration;
Trajectory trajectory; // The current trajectory
double time; // The current, auto-incremented time. Reset to 0 at a new calculation.
size_t new_section; // Index of the section between two (possibly filtered) intermediate positions.
bool did_section_change; // Was a new section reached in the last cycle?
bool new_calculation; // Whether a new calculation was performed in the last cycle
bool was_calculation_interrupted; // Was the trajectory calculation interrupted? (only in Pro Version)
double calculation_duration; // Duration of the calculation in the last cycle [µs]
此外,轨迹类具有一系列有用的参数和方法。
double duration; // Duration of the trajectory
std::array<double, DOFs> independent_min_durations; // Time-optimal profile for each independent DoF
<...> at_time(double time); // Get the kinematic state of the trajectory at a given time
<...> get_position_extrema(); // Returns information about the position extrema and their times
同样,我们参考API 文档以获取确切的签名。
离线计算
Ruckig 还支持计算轨迹的离线方法:
result = ruckig.calculate(input, trajectory);
仅使用此方法时,Ruckig
构造函数不需要控制循环作为参数。
追踪界面
当跟随具有位置、速度、加速度和加加速度限制的任意信号时,直接的方法是将当前状态传递给 Ruckig 的目标状态。但是,由于生成的轨迹需要时间才能赶上,这种方法总是会落后于信号。跟踪接口通过提前预测(例如默认为恒定加速度)解决了这个问题,因此能够以时间最优的方式非常密切地跟踪信号。这对于(一般)跟踪、机器人伺服或轨迹后处理应用程序可能非常有帮助。
要使用跟踪接口,请构造
Trackig<1> otg {0.01}; // control cycle
并通过以下方式设置当前状态以及运动学约束
input.current_position = {0.0};
input.current_velocity = {0.0};
input.current_acceleration = {0.0};
input.max_velocity = {0.8};
input.max_acceleration = {2.0};
input.max_jerk = {5.0};
然后,我们可以在实时控制回路中以在线方式跟踪信号
for (double t = 0; t < 10.0; t += otg.delta_time) {
auto target_state = signal(t); // signal returns position, velocity, and acceleration
auto res = otg.update(target_state, input, output);
// Make use of the smooth target motion here (e.g. output.new_position)
output.pass_to_input(input);
}
请在此处找到完整的示例。该功能也可以离线方式使用,例如当预先知道整个信号时。在这里,我们称
smooth_trajectory = otg.calculate_trajectory(target_states, input);
将轨迹作为std::vector
目标状态的 a 的方法。Ruckig Pro 版本中提供了跟踪界面。
动态自由度数
到目前为止,我们已经将 DoF 的数量作为模板参数告诉了 Ruckig。如果在编译时不知道 DoF 的数量,可以将模板参数设置为ruckig::DynamicDOFs
并将 DoF 传递给构造函数:
Ruckig<DynamicDOFs> otg {6, 0.001};
InputParameter<DynamicDOFs> input {6};
OutputParameter<DynamicDOFs> output {6};
但是,我们建议尽可能保留模板参数:首先,它具有百分之几的性能优势。其次,它便于实时编程,因为它更容易处理内存分配。使用动态自由度时,请确保预先分配所有向量的内存。
自定义向量类型
Ruckig 支持自定义矢量类型,使与您的代码的接口更加容易和灵活。最重要的是,您只需在 Ruckig 之前包含 Eigen(3.4 或更高版本)即可切换到Eigen Vectors
#include <Eigen/Core> // Version 3.4 or later
#include <ruckig/ruckig.hpp>
然后使用ruckig::EigenVector
参数调用构造函数。
Ruckig<6, EigenVector> otg {0.001};
InputParameter<6, EigenVector> input;
OutputParameter<6, EigenVector> output;
现在 Ruckig API 的每个输入和输出(例如current_position
、new_position
或max_jerk
)都是 Eigen 类型!要定义完全自定义的向量类型,您可以将 C++模板模板参数传递给构造函数。此模板模板参数需要满足一系列模板参数和方法:
template<class Type, size_t DOFs>
struct MinimalVector {
Type operator[](size_t i) const; // Array [] getter
Type& operator[](size_t i); // Array [] setter
size_t size() const; // Current size
bool operator==(const MinimalVector<T, DOFs>& rhs) const; // Equal comparison operator
// Only required in combination with DynamicDOFs, e.g. to allocate memory
void resize(size_t size);
};
注意DynamicDOFs
对应于DOFs = 0
。我们提供了一系列示例,用于将 Ruckig 与(10) Eigen、(11) 自定义向量类型和(12) 具有动态 DoF 数量的自定义类型一起使用。
测试和数值稳定性
当前的测试套件验证了超过 5.000.000.000 条随机轨迹。对于最终位置和最终速度在 范围内1e-8
、最终加速度在 范围内1e-10
以及速度、加速度和加加速度限制在 范围内的数值误差,测试数值的准确性1e-12
。这些是绝对值 - 我们建议调整您的输入,以便这些与您所需的系统精度相对应。例如,对于大多数现实世界的系统,我们建议使用输入值[m]
(而不是 eg [mm]
),因为1e-8m
对于实际轨迹生成来说足够精确。此外,所有运动学限制都应低于1e12
。最大支持的轨迹持续时间是7e3
,这对于大多数寻求时间最优性的应用程序来说应该足够了。请注意,Ruckig 也会输出此范围之外的值,但不能保证正确性。
基准
我们发现,对于状态到状态的运动,Ruckig 的速度是 Reflexxes Type IV 的两倍多,并且非常适合低至 250 微秒的控制周期。Ruckig社区版通常是Reflexxes Type IV库的更强大和开源的替代品。事实上,Ruckig 是第一款针对任意目标状态的 Type V 轨迹生成器,甚至支持方向速度和加速度限制,同时速度更快。
对于具有中间航路点的轨迹,我们将 Ruckig 与Toppra进行比较,Toppra是用于机器人运动规划的最先进的库。Ruckig 能够将轨迹持续时间平均提高约 10%,因为路径规划和时间参数化是联合计算的。此外,Ruckig 具有实时能力并支持 jerk-constraints。
发展
Ruckig 是用 C++17 编写的。它在以下版本ubuntu-latest
上macos-latest
不断测试windows-latest
- Doctest v2.4(仅用于测试)
- Pybind11 v2.9(仅适用于python wrapper)
如果您仍然需要使用 C++11,您可以通过调用sh scripts/patch-c++11.sh
. 请注意,这将导致性能下降几个百分点。此外,不支持 Python 模块。
使用者
Ruckig 被全球数百个研究实验室、公司和开源项目使用,包括:
- MoveIt 2用于轨迹生成。
- CoppeliaSim从 4.3 版开始。
- Struckig,Ruckig 到结构化文本 (ST - IEC61131-3) 的端口,用于 PLC。
- Frankx用于控制 Franka Emika 机械臂。
- 和许多其他人!
引文
@article{berscheid2021jerk,
title={Jerk-limited Real-time Trajectory Generation with Arbitrary Target States},
author={Berscheid, Lars and Kr{\"o}ger, Torsten},
journal={Robotics: Science and Systems XVII},
year={2021}
}
项目详情
下载文件
下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。