ruckig

Motion Generation for Robots and Machines. Real-time. Jerk-constrained. Time-optimal.

https://github.com/pantor/ruckig

Science Score: 64.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
    Found CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
    Links to: arxiv.org
  • Committers with academic emails
    2 of 16 committers (12.5%) from academic institutions
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (17.3%) to scientific vocabulary

Keywords

jerk-constrained motion-planning optimal-control robot-arm robotics time-optimal trajectory-generation
Last synced: 6 months ago · JSON representation ·

Repository

Motion Generation for Robots and Machines. Real-time. Jerk-constrained. Time-optimal.

Basic Info
  • Host: GitHub
  • Owner: pantor
  • License: mit
  • Language: C++
  • Default Branch: main
  • Homepage: https://ruckig.com
  • Size: 3.5 MB
Statistics
  • Stars: 919
  • Watchers: 33
  • Forks: 204
  • Open Issues: 33
  • Releases: 17
Topics
jerk-constrained motion-planning optimal-control robot-arm robotics time-optimal trajectory-generation
Created about 5 years ago · Last pushed 8 months ago
Metadata Files
Readme Changelog License Citation

README.md

Ruckig

Instantaneous Motion Generation for Robots and Machines.

CI Issues Releases MIT

Ruckig generates trajectories on-the-fly, allowing robots and machines to react instantaneously to sensor input. Ruckig calculates a trajectory to a target waypoint (with position, velocity, and acceleration) starting from any initial state limited by velocity, acceleration, and jerk constraints. Besides the target state, Ruckig allows to define intermediate positions for waypoint following. For state-to-state motions, Ruckig guarantees a time-optimal solution. With intermediate waypoints, Ruckig calculates the path and its time parametrization jointly, resulting in significantly faster trajectories compared to traditional methods.

More information can be found at ruckig.com and in the corresponding paper Jerk-limited Real-time Trajectory Generation with Arbitrary Target States, accepted for the Robotics: Science and Systems (RSS), 2021 conference.

Installation

Ruckig has no dependencies (except for testing). To build Ruckig using CMake, just run

bash mkdir -p build cd build cmake -DCMAKE_BUILD_TYPE=Release .. make

To install Ruckig in a system-wide directory, you can either use (sudo) make install or install it as debian package using cpack by running

bash cpack sudo dpkg -i ruckig*.deb

An example of using Ruckig in your CMake project is given by examples/CMakeLists.txt. However, you can also include Ruckig as a directory within your project and call add_subdirectory(ruckig) in your parent CMakeLists.txt.

Ruckig is also available as a Python module, in particular for development or debugging purposes. The Ruckig Community Version can be installed from PyPI via bash pip install ruckig When using CMake, the Python module can be built using the BUILD_PYTHON_MODULE flag. If you're only interested in the Python module (and not in the C++ library), you can build and install Ruckig via pip install ..

Tutorial

Furthermore, we will explain the basics to get started with online generated trajectories within your application. There is also a collection of examples that guide you through the most important features of Ruckig. A time-optimal trajectory for a single degree of freedom is shown in the figure below. We also added plots of the resulting trajectories for all examples. Let's get started!

Trajectory Profile

Waypoint-based Trajectory Generation

Ruckig provides three main interface classes: the Ruckig, the InputParameter, and the OutputParameter class.

First, you'll need to create a Ruckig instance with the number of DoFs as a template parameter, and the control cycle (e.g. in seconds) in the constructor.

.cpp Ruckig<6> ruckig {0.001}; // Number DoFs; control cycle in [s]

The input type has 3 blocks of data: the current state, the target state and the corresponding kinematic limits.

```.cpp InputParameter<6> input; // Number DoFs input.currentposition = {0.2, ...}; input.currentvelocity = {0.1, ...}; input.currentacceleration = {0.1, ...}; input.targetposition = {0.5, ...}; input.targetvelocity = {-0.1, ...}; input.targetacceleration = {0.2, ...}; input.maxvelocity = {0.4, ...}; input.maxacceleration = {1.0, ...}; input.max_jerk = {4.0, ...};

OutputParameter<6> output; // Number DoFs ```

If you only want to have a acceleration-constrained trajectory, you can also omit the max_jerk as well as the current and target_acceleration value. Given all input and output resources, we can iterate over the trajectory at each discrete time step. For most applications, this loop must run within a real-time thread and controls the actual hardware.

```.cpp while (ruckig.update(input, output) == Result::Working) { // Make use of the new state here! // e.g. robot->setJointPositions(output.new_position);

output.passtoinput(input); // Don't forget this! } ```

Within the control loop, you need to update the current state of the input parameter according to the calculated trajectory. Therefore, the pass_to_input method copies the new kinematic state of the output to the current kinematic state of the input parameter. If (in the next step) the current state is not the expected, pre-calculated trajectory, Ruckig will calculate a new trajectory based on the novel input. When the trajectory has reached the target state, the update function will return Result::Finished.

Intermediate Waypoints

The Ruckig Community Version includes built-in support for intermediate waypoints, using our cloud API for remote calculation. Of course, the Ruckig Pro version is fully local. To allocate the necessary memory for a variable number of waypoints beforehand, we need to pass the maximum number of waypoints to Ruckig via .cpp Ruckig<6> ruckig {0.001, 8}; InputParameter<6> input {8}; OutputParameter<6> output {8}; The InputParameter class takes the number of waypoints as an optional input, however usually you will fill in the values (and therefore reserve its memory) yourself. Then you're ready to set intermediate via points by .cpp input.intermediate_positions = { {0.2, ...}, {0.8, ...}, }; As soon as at least one intermediate positions is given, the Ruckig Community Version switches to the mentioned (of course, non real-time capable) cloud API. If you require real-time calculation on your own hardware, please contact us for the Ruckig Pro Version.

When using intermediate positions, both the underlying motion planning problem as well as its calculation changes significantly. In particular, there are some fundamental limitations for jerk-limited online trajectory generation regarding the usage of waypoints. Please find more information about these limitations here, and in general we recommend to use .cpp input.intermediate_positions = ruckig.filter_intermediate_positions(input.intermediate_positions, {0.1, ...}); to filter waypoints according to a (high) threshold distance. Setting interruptcalculationduration makes sure to be real-time capable by refining the solution in the next control invocation. Note that this is a soft interruption of the calculation. Currently, no minimum or discrete durations are supported when using intermediate positions.

Input Parameter

To go into more detail, the InputParameter type has following members:

```.cpp using Vector = std::array; // By default

Vector currentposition; Vector currentvelocity; // Initialized to zero Vector current_acceleration; // Initialized to zero

std::vector intermediate_positions; // (only in Pro Version)

Vector targetposition; Vector targetvelocity; // Initialized to zero Vector target_acceleration; // Initialized to zero

Vector maxvelocity; Vector maxacceleration; Vector max_jerk; // Initialized to infinity

std::optional minvelocity; // If not given, the negative maximum velocity will be used. std::optional minacceleration; // If not given, the negative maximum acceleration will be used.

std::optional minposition; // (only in Pro Version) std::optional maxposition; // (only in Pro Version)

std::array enabled; // Initialized to true std::optional minimumduration; std::optional interruptcalculation_duration; // [µs], (only in Pro Version)

ControlInterface controlinterface; // The default position interface controls the full kinematic state. Synchronization synchronization; // Synchronization behavior of multiple DoFs DurationDiscretization durationdiscretization; // Whether the duration should be a discrete multiple of the control cycle (off by default)

std::optional> perdofcontrolinterface; // Sets the control interface for each DoF individually, overwrites global controlinterface std::optional> perdofsynchronization; // Sets the synchronization for each DoF individually, overwrites global synchronization ```

On top of the current state, target state, and constraints, Ruckig allows for a few more advanced settings: - A minimum velocity and acceleration can be specified - these should be a negative number. If they are not given, the negative maximum velocity or acceleration will be used (similar to the jerk limit). For example, this might be useful in human robot collaboration settings with a different velocity limit towards a human. Or, when switching between different moving coordinate frames like picking from a conveyer belt. - You can overwrite the global kinematic limits to specify limits for each section between two waypoints separately by using e.g. per_section_max_velocity. - If a DoF is not enabled, it will be ignored in the calculation. Ruckig will output a trajectory with constant acceleration for those DoFs. - A minimum duration can be optionally given. Note that Ruckig can not guarantee an exact, but only a minimum duration of the trajectory. - The control interface (position or velocity control) can be switched easily. For example, a stop trajectory or visual servoing can be easily implemented with the velocity interface. - Different synchronization behaviors (i.a. phase, time, or no synchonization) are implemented. Phase synchronization results in straight-line motions. - The trajectory duration might be constrained to a multiple of the control cycle. This way, the exact state can be reached at a control loop execution.

We refer to the API documentation of the enumerations within the ruckig namespace for all available options.

Input Validation

To check that Ruckig is able to generate a trajectory before the actual calculation step, .cpp ruckig.validate_input(input, check_current_state_within_limits=false, check_target_state_within_limits=true); // returns true or throws throws an error with a detailed reason if an input is not valid. You can also set the default template parameter to false via ruckig.validate_input<false>(...) to just return a boolean true or false. The two boolean arguments check that the current or target state are within the limits. The check includes a typical catch of jerk-limited trajectory generation: When the current state is at maximal velocity, any positive acceleration will inevitable lead to a velocity violation at a future timestep. In general, this condition is fulfilled when Abs(acceleration) <= Sqrt(2 * max_jerk * (max_velocity - Abs(velocity))). If both arguments are set to true, the calculated trajectory is guaranteed to be within the kinematic limits throughout its duration. Also, note that there are range constraints of the input due to numerical reasons, see below for more details.

Result Type

The update function of the Ruckig class returns a Result type that indicates the current state of the algorithm. This can either be working, finished if the trajectory has finished, or an error type if something went wrong during calculation. The result type can be compared as a standard integer.

State | Error Code ------------------------------- | ---------- Working | 0 Finished | 1 Error | -1 ErrorInvalidInput | -100 ErrorTrajectoryDuration | -101 ErrorPositionalLimits | -102 ErrorExecutionTimeCalculation | -110 ErrorSynchronizationCalculation | -111

Output Parameter

The output class includes the new kinematic state and the overall trajectory.

```.cpp Vector newposition; Vector newvelocity; Vector new_acceleration;

Trajectory trajectory; // The current trajectory double time; // The current, auto-incremented time. Reset to 0 at a new calculation.

sizet newsection; // Index of the section between two (possibly filtered) intermediate positions. bool didsectionchange; // Was a new section reached in the last cycle?

bool newcalculation; // Whether a new calculation was performed in the last cycle bool wascalculationinterrupted; // Was the trajectory calculation interrupted? (only in Pro Version) double calculationduration; // Duration of the calculation in the last cycle [µs] ``` Moreover, the trajectory class has a range of useful parameters and methods.

```.cpp double duration; // Duration of the trajectory std::array independentmindurations; // Time-optimal profile for each independent DoF

<...> attime(double time); // Get the kinematic state of the trajectory at a given time <...> getposition_extrema(); // Returns information about the position extrema and their times ``` Again, we refer to the API documentation for the exact signatures.

Offline Calculation

Ruckig also supports an offline approach for calculating a trajectory: .cpp result = ruckig.calculate(input, trajectory); When only using this method, the Ruckig constructor does not need a control cycle (delta_time) as an argument. However if given, Ruckig supports stepping through the trajectory with .cpp while (ruckig.update(trajectory, output) == Result::Working) { // Make use of the new state here! // e.g. robot->setJointPositions(output.new_position); } starting from the current output.time (currently Ruckig Pro only).

Tracking Interface

When following an arbitrary signal with position, velocity, acceleration, and jerk-limitation, the straight forward way would be to pass the current state to Ruckig's target state. However, as the resulting trajectory will take time to catch up, this approach will always lag behind the signal. The tracking interface solves this problem by predicting ahead (e.g. with constant acceleration by default) and is therefore able to follow signals very closely in a time-optimal way. This might be very helpful for (general) tracking, robot servoing, or trajectory post-processing applications.

To use the tracking interface, construct .cpp Trackig<1> trackig {0.01}; // control cycle and set the current state as well as the kinematic constraints via .cpp 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}; Then, we can track a signal in an online manner within the real-time control loop ```.cpp for (double t = 0; t < 10.0; t += trackig.deltatime) { auto targetstate = signal(t); // signal returns position, velocity, and acceleration auto res = trackig.update(targetstate, input, output); // Make use of the smooth target motion here (e.g. output.newposition)

output.passtoinput(input); } Please find a complete example [here](https://github.com/pantor/ruckig/blob/main/examples/13_tracking.cpp). This functionality can also be used in an offline manner, e.g. when the entire signal is known beforehand. Here, we call the .cpp smoothtrajectory = trackig.calculatetrajectory(target_states, input); `` method with the trajectory given as astd::vector` of target states. The Tracking interface is available in the Ruckig Pro version.

Dynamic Number of Degrees of Freedom

So far, we have told Ruckig the number of DoFs as a template parameter. If you don't know the number of DoFs at compile-time, you can set the template parameter to ruckig::DynamicDOFs and pass the DoFs to the constructor:

.cpp Ruckig<DynamicDOFs> ruckig {6, 0.001}; InputParameter<DynamicDOFs> input {6}; OutputParameter<DynamicDOFs> output {6};

This switches the default Vector from the std::array to the dynamic std::vector type. However, we recommend to keep the template parameter when possible: First, it has a performance benefit of a few percent. Second, it is convenient for real-time programming due to its easier handling of memory allocations. When using dynamic degrees of freedom, make sure to allocate the memory of all vectors beforehand.

Custom Vector Types

Ruckig supports custom vector types to make interfacing with your code even easier and more flexible. Most importantly, you can switch to Eigen Vectors simply by including Eigen (3.4 or later) before Ruckig ```.cpp

include // Version 3.4 or later

include

and then call the constructors with the `ruckig::EigenVector` parameter. .cpp Ruckig<6, EigenVector> ruckig {0.001}; InputParameter<6, EigenVector> input; OutputParameter<6, EigenVector> output; Now every in- and output of Ruckig's API (such as `current_position`, `new_position` or `max_jerk`) are Eigen types! To define completely custom vector types, you can pass a C++ [template template parameter](https://en.cppreference.com/w/cpp/language/template_parameters) to the constructor. This template template parameter needs to fulfill a range of template arguments and methods: .cpp template struct MinimalVector { Type operator const; // Array [] getter Type& operator; // Array [] setter size_t size() const; // Current size bool operator==(const MinimalVector& rhs) const; // Equal comparison operator

// Only required in combination with DynamicDOFs, e.g. to allocate memory void resize(size_t size); }; `` Note thatDynamicDOFscorresponds toDOFs = 0`. We've included a range of examples for using Ruckig with (10) Eigen, (11) custom vector types, and (12) custom types with a dynamic number of DoFs.

Tests and Numerical Stability

The current test suite validates over 5.000.000.000 random trajectories as well as many additional edge cases. The numerical exactness is tested for the final position and final velocity to be within 1e-8, for the final acceleration to be within 1e-10, and for the velocity, acceleration and jerk limit to be within of a numerical error of 1e-12. These are absolute values - we suggest to scale your input so that these correspond to your required precision of the system. For example, for most real-world systems we suggest to use input values in [m] (instead of e.g. [mm]), as 1e-8m is sufficient precise for practical trajectory generation. Furthermore, all kinematic limits should be below 1e9. The maximal supported trajectory duration is 7e3. Note that Ruckig will also output values outside of this range, there is however no guarantee for correctness.

The Ruckig Pro version has additional tools to increase the numerical range and improve reliability. For example, theposition_scale and time_scale parameter of the Calculator class change the internal representation of the input parameters. ```.cpp Ruckig<1> ruckig; // Works also for Trackig

ruckig.calculator.positionscale = 1e2; // Scales all positions in the input parameters ruckig.calculator.timescale = 1e3; // Scale all times in the input parameters ``` This way, you can easily achieve the requirements above even for very high jerk limits or very long trajectories. Note that the scale parameters don't effect the resulting trajectory - they are for internal calculation only.

Benchmark

We find that Ruckig is more than twice as fast as Reflexxes Type IV for state-to-state motions and well-suited for control cycles as low as 250 microseconds. The Ruckig Community Version is in general a more powerful and open-source alternative to the Reflexxes Type IV library. In fact, Ruckig is the first Type V trajectory generator for arbitrary target states and even supports directional velocity and acceleration limits, while also being faster on top.

Benchmark

For trajectories with intermediate waypoints, we compare Ruckig to Toppra, a state-of-the-art library for robotic motion planning. Ruckig is able to improve the trajectory duration on average by around 10%, as the path planning and time parametrization are calculated jointly. Moreover, Ruckig is real-time capable and supports jerk-constraints.

Benchmark

Development

Ruckig is written in C++20. It is continuously tested on ubuntu-latest, macos-latest, and windows-latest against following versions:

  • Doctest v2.4 (only for testing)
  • Nanobind v2.7 (only for Python wrapper)

A C++17, C++11, and C++03 version of Ruckig is also available - please contact us if you're interested.

Used By

Ruckig is used by over hundred research labs, companies, and open-source projects worldwide, including: - MoveIt 2 for trajectory generation. - CoppeliaSim starting from version 4.3. - Fuzzy Logic Robotics - Gestalt Robotics - Struckig, a port of Ruckig to Structered Text (ST - IEC61131-3) for usage on PLCs. - Scanlab for controlling lasers. - Frankx for controlling the Franka Emika robot arm. - Wiredworks made a simple Kivy GUI application - and many others!

Citation

@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} }

Owner

  • Name: Berscheid
  • Login: pantor
  • Kind: user
  • Location: Germany

Citation (CITATION.cff)

# YAML 1.2
---
cff-version: "1.2.0"
message: "If you use this software, please cite it using these metadata."
type: article
title: "Jerk-limited Real-time Trajectory Generation with Arbitrary Target States"
journal: "Robotics - Science and Systems (2021)"
url: "https://publikationen.bibliothek.kit.edu/1000136018"
doi: "10.15607/RSS.2021.XVII.015"
authors:
  - family-names: Berscheid
    given-names: Lars
  - family-names: "Kröger"
    given-names: Torsten
date-released: 2021-07-01
isbn: "978-0-9923747-7-8"
license: MIT
repository-code: "https://github.com/pantor/ruckig"
abstract: "We present Ruckig, an algorithm for Online Trajectory Generation (OTG) respecting third-order constraints and complete kinematic target states. Given any initial state of a system with multiple Degrees of Freedom (DoFs), Ruckig calculates a time-optimal trajectory to an arbitrary target state defined by its position, velocity, and acceleration limited by velocity, acceleration, and jerk constraints. The proposed algorithm and implementation allows three contributions: (1) To the best of our knowledge, we derive the first time-optimal OTG algorithm for arbitrary, multi-dimensional target states, in particular including non-zero target acceleration. (2) This is the first open-source prototype of time-optimal OTG with limited jerk and complete time synchronization for multiple DoFs. (3) Ruckig allows for directional velocity and acceleration limits, enabling robots to better use their dynamical resources. We evaluate the robustness and real-time capability of the proposed algorithm on a test suite with over 1,000,000,000 random trajectories as well as in real-world applications."

GitHub Events

Total
  • Create event: 1
  • Release event: 1
  • Issues event: 27
  • Watch event: 223
  • Delete event: 1
  • Issue comment event: 35
  • Push event: 20
  • Pull request event: 19
  • Fork event: 46
Last Year
  • Create event: 1
  • Release event: 1
  • Issues event: 27
  • Watch event: 223
  • Delete event: 1
  • Issue comment event: 35
  • Push event: 20
  • Pull request event: 19
  • Fork event: 46

Committers

Last synced: 9 months ago

All Time
  • Total Commits: 537
  • Total Committers: 16
  • Avg Commits per committer: 33.563
  • Development Distribution Score (DDS): 0.287
Past Year
  • Commits: 21
  • Committers: 3
  • Avg Commits per committer: 7.0
  • Development Distribution Score (DDS): 0.095
Top Committers
Name Email Commits
pantor l****d@o****e 383
Lars Berscheid l****d@k****u 133
Silvio Traversaro s****o@i****t 4
G.A. vd. Hoorn g****n@t****l 3
Michael Görner me@v****e 2
stefanbesler 1****r 2
Antoine Hoarau 7****u 1
Josh Polansky j****h@l****m 1
Konrad Leibrandt 1****s 1
Marco Boneberger 1****e 1
Mathis m****e@g****m 1
Matthias Seehauser s****a 1
Max Dhom 3****m 1
lpdon l****2@g****m 1
mosfet80 r****a@y****t 1
Vatan Aksoy Tezer v****n@p****i 1
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: 6 months ago

All Time
  • Total issues: 184
  • Total pull requests: 59
  • Average time to close issues: 20 days
  • Average time to close pull requests: 10 days
  • Total issue authors: 110
  • Total pull request authors: 24
  • Average comments per issue: 2.73
  • Average comments per pull request: 1.25
  • Merged pull requests: 31
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 29
  • Pull requests: 23
  • Average time to close issues: 5 days
  • Average time to close pull requests: 11 days
  • Issue authors: 22
  • Pull request authors: 8
  • Average comments per issue: 0.69
  • Average comments per pull request: 0.52
  • Merged pull requests: 5
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • AndyZe (13)
  • Danielxyz123 (12)
  • Ydaos (6)
  • Fubini2 (6)
  • fricher (5)
  • Linjackffy (5)
  • gavanderhoorn (4)
  • pantor (3)
  • ethindp (3)
  • mdhom (3)
  • isherman (3)
  • personal-fork-robot (3)
  • Blaise-wig (3)
  • stefanbesler (3)
  • grotius-cnc (3)
Pull Request Authors
  • mosfet80 (16)
  • pantor (6)
  • traversaro (4)
  • gavanderhoorn (3)
  • lpdon (3)
  • v4hn (3)
  • chibai (2)
  • hashb (2)
  • Levi-Armstrong (2)
  • jmirabel (2)
  • sciprosk (2)
  • Joshpolansky (2)
  • stefanbesler (2)
  • ahoarau (2)
  • fehimiltek (2)
Top Labels
Issue Labels
enhancement (20) bug (17) question (10) documentation (3) paper (2) help wanted (1) duplicate (1) bug-community (1)
Pull Request Labels

Packages

  • Total packages: 2
  • Total downloads:
    • pypi 15,298 last-month
  • Total docker downloads: 104
  • Total dependent packages: 1
    (may contain duplicates)
  • Total dependent repositories: 1
    (may contain duplicates)
  • Total versions: 37
  • Total maintainers: 1
pypi.org: ruckig

Instantaneous Motion Generation for Robots and Machines.

  • Versions: 21
  • Dependent Packages: 1
  • Dependent Repositories: 1
  • Downloads: 15,298 Last month
  • Docker Downloads: 104
Rankings
Docker downloads count: 2.7%
Dependent packages count: 4.8%
Downloads: 5.2%
Average: 8.6%
Dependent repos count: 21.6%
Maintainers (1)
Last synced: 6 months ago
proxy.golang.org: github.com/pantor/ruckig
  • Versions: 16
  • Dependent Packages: 0
  • Dependent Repositories: 0
Rankings
Dependent packages count: 9.0%
Average: 9.6%
Dependent repos count: 10.2%
Last synced: 6 months ago

Dependencies

.github/workflows/ci.yml actions
  • actions/checkout v3 composite
.github/workflows/publish.yml actions
  • RalfG/python-wheels-manylinux-build v0.6.0 composite
  • actions/checkout v3 composite
  • actions/setup-python v4 composite