pantor / ruckig

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

Disabling numerical constraints #139

Closed ethindp closed 1 year ago

ethindp commented 1 year ago

@pantor So... I know this is a C++-related question, but: I'd like to set the third template parameter of ruckig::ruckig to false. However, I cannot seem to do this without also setting a custom vector, which is something I don't want to do. Is there some way I can circumvent this problem? (This is why I'm no fan of C++ templates... They're an utter disaster and a total mess.)

pantor commented 1 year ago

I assume you are talking about the return_error_at_maximal_duration parameter, or did you meant the throw_error parameter?

With the latest release, the return_error_at_maximal_duration was removed and is true by default. The reason for this is that Ruckig can't guarantee a solution due to the numeric limitation of the double type if the trajectory is longer than 7e3. This is also stated in the Readme. The 'correct' way forward would be to normalize the kinematic limits so that this condition is fulfilled. Does that work for you use case?

ethindp commented 1 year ago

@pantor I believe it might... Can you explain how I would normalize the kinematic limits, given only a set of input parameters? Does the equation listed in the readme suffice? Would it be better to split a trajectory longer than 7e3 into multiple ones?

pantor commented 1 year ago

Hi @ethindp,

as mentioned, I want to keep the 7e3 parameter for numeric stability reasons. The recommended way to go around that limitation is to scale the InputParameter accordingly (basically changing the unit of time). For example,

inp = InputParameter(1)
inp.current_position = [0.0]
inp.current_velocity = [-100.0]
inp.current_acceleration = [0.0]
inp.target_position = [10000.0]
inp.target_velocity = [0.0]
inp.target_acceleration = [0.0]
inp.max_velocity = [1.0]
inp.max_acceleration = [1.0]
inp.max_jerk = [0.2]

will result in a trajectory that is 15355 long and will therefore output an error. By scaling the time with a factor of 5, so by multiplying the velocity by 5, the accelerations by 5^2, and the jerks by 5^3, we get the same trajectory just speed up by a factor of 5. Therefore,

inp = InputParameter(1)
inp.current_position = [0.0]
inp.current_velocity = [-100.0 * 5]
inp.current_acceleration = [0.0]
inp.target_position = [10000.0]
inp.target_velocity = [0.0]
inp.target_acceleration = [0.0]
inp.max_velocity = [1.0 * 5]
inp.max_acceleration = [1.0  * 5**2]
inp.max_jerk = [0.2 * 5**3]

has a duration of 3071 which is beneath the limit. You can then also scale the delta_time parameter to get the trajectory with original timing right again. This should also work for arbitrary trajectory durations.

Hope this helps!

ethindp commented 1 year ago

@pantor This does help! How do you calculate the scaling value? If I understand this correctly, the algorithm is something like:

  1. Let s be the computed scaling value. Let e be the index of each component of each vector. Let E be the element at index e.
  2. For each element in each vector, compute E*s**e.

Is this algorithm correct? Also, how would I scale the delta_time parameter? I don't remember seeing that parameter in either input or output parameters but maybe it got added and I missed it.