pantor / ruckig

Motion Generation for Robots and Machines. Real-time. Jerk-constrained. Time-optimal.
https://ruckig.com
MIT License
734 stars 166 forks source link

Changing the constraints (ver_max, acc_max or jerk_max) to smaller value causes a suboptimal trajectory #17

Closed xiaodaxia-2008 closed 3 years ago

xiaodaxia-2008 commented 3 years ago

If the contraints are changed online, then the trajectory is not optimal as it should be. The following image shows the whole trajectory, at t = 2, max_velocity is reduces from 3 to 1, then the velocity goes to negative unexpectedly. image

On the other hand, if the velocity constraints increases, everything seems to be fine. image

You could reproduce with the following code:

import ruckig
from copy import copy
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

def WalkThroughTrajectory(otg, in_param, T):
    dof = otg.degrees_of_freedom
    out_param: ruckig.OutputParameter = ruckig.OutputParameter(dof)
    first_output = None
    ts = []
    xs = []
    dxs = []
    ddxs = []

    t = 0
    res = ruckig.Result.Working
    while res == ruckig.Result.Working:
        res = otg.update(in_param, out_param)
        in_param.current_position = out_param.new_position
        in_param.current_velocity = out_param.new_velocity
        in_param.current_acceleration = out_param.new_acceleration

        ts.append(t)
        xs.append(out_param.new_position)
        dxs.append(out_param.new_velocity)
        ddxs.append(out_param.new_acceleration)
        t += T
        if t > 2 and t < 2 + t:
            in_param.max_velocity = np.asarray([1, 1, 1.]) * 1.

        if not first_output:
            first_output = copy(out_param)

    return first_output, ts, xs, dxs, ddxs

if __name__ == '__main__':
    dof = 3
    in_param = ruckig.InputParameter(dof)
    in_param.current_position = [0, 0, 0]
    in_param.current_velocity = [0., 0, 0]
    in_param.current_acceleration = [0, 0, 0]
    in_param.target_position = [10, 0, 0]
    in_param.target_velocity = [0, 0, 0]
    in_param.target_acceleration = [0, 0, 0]
    in_param.max_velocity = [3, 3, 3]
    in_param.max_acceleration = [5, 5, 5]
    in_param.max_jerk = [10, 10, 10]

    T = 0.004
    otg = ruckig.Ruckig(dof, T)
    # otg = ruckig.Smoothie(dof, T)
    # otg = ruckig.Quintic(dof, T)

    first_output, ts, xs, dxs, ddxs = WalkThroughTrajectory(otg, in_param, T)

    print(
        f'Calculation duration: {first_output.calculation_duration:0.1f} [µs]')
    print(f'Trajectory duration: {first_output.trajectory.duration:0.4f} [s]')

    shape = (2, 2)

    plt.subplots_adjust(hspace=1)
    plt.subplot2grid(shape, loc=(0, 0))
    plt.plot(ts, xs)
    plt.legend(['$D_%i$' % i for i in range(dof)])
    plt.title("$x(t)$")

    plt.subplot2grid(shape, loc=(0, 1))
    plt.plot(ts, dxs)
    plt.legend(['$D_%i$' % i for i in range(dof)])
    plt.title("$\dot x(t)$")

    plt.subplot2grid(shape, loc=(1, 0))
    plt.plot(ts, ddxs)
    plt.legend(['$D_%i$' % i for i in range(dof)])
    plt.title("$\ddot x(t)$")

    xs = np.asarray(xs)
    plt.subplot2grid(shape, loc=(1, 1), projection='3d')
    plt.plot(*xs.T[:2])
    plt.legend(['$D_%i$' % i for i in range(dof)])
    plt.title("$x_1 x_2 x_3$")

    plt.show()
pantor commented 3 years ago

Hi @xiaodaxia-2008,

this is desired behaviour: Ruckig will first and foremost try to get the kinematic state within the allowed limits as fast as possible. Only then a time-optimal trajectory is calculated.

In your example, if the velocity wouldn't get negative in the top right figure, the trajectory would stay slightly longer above the velocity limit. If the velocity would decrease to +1 directly, a positive jerk would be necessary while the velocity would still be above its limits. I hope that clears up this issue.

However, we can think about a setting that disables the braking trajectory. I'm not sure how hard this would be to implement.

xiaodaxia-2008 commented 3 years ago

Thanks for your explanation. By using online trajectory filter, I have obtained the following expected result. But time synchronization for serveal dofs could not be done. By the way, I think it will be help to add current_jerk attribute to InputParameters if possible.

image

pantor commented 3 years ago

What do you mean by online trajectory filter exactly?

As the derivative of the jerk is not limited in Ruckig, the current jerk is not relevant for the calculated trajectory.

xiaodaxia-2008 commented 3 years ago

Please refer to Trajectory Planning for Automatic Machines and Robots chapter 4.6 Nonlinear Filters for Optimal Trajectory Planning. So the current jerk should always be max_jerk or -max_jerk ?!

pantor commented 3 years ago

Thanks for the link!

As there is no current jerk in ruckig, I'm not sure what you mean?

xiaodaxia-2008 commented 3 years ago

I think it is the 3rd derivative of the calculated trajectory. As the trajectory is at most polynomial of degree 3, so the jerk is constant at each segment.

oridong commented 2 years ago

Thanks for your explanation. By using online trajectory filter, I have obtained the following expected result. But time synchronization for serveal dofs could not be done. By the way, I think it will be help to add current_jerk attribute to InputParameters if possible.

image

could you send me this copy of the one using online trajectory filter. oridong@126.com