petrikosk / rsruckig

Rust port of Ruckig trajectory generator
https://ruckig.com
MIT License
5 stars 4 forks source link

Unexpected phase-synchronization behavior when DoF velocities have different signs #7

Closed coljnr9 closed 4 months ago

coljnr9 commented 4 months ago

First of all, great port and nice API, thanks for your work on this!

I'm working with offline generation of constant-acceleration moves. When different DoFs move in opposite directions, it seems like the TargetCalculator can't produce phase-synchronized paths.

With these limits

input.synchronization = Synchronization::Phase;
input.max_velocity = daov_stack![1.0, 1000.0];
input.max_acceleration = daov_stack![10.0, 1000.0];

I see the behavior I expect when two DoFs move in the same direction

input.current_position = daov_stack![0.0, 0.0];
input.target_position = daov_stack![1.0, 2.0];

However, when the targets require moving in different directions, the phase-synchronization is not maintained

input.current_position = daov_stack![1.0, 0.0];
input.target_position = daov_stack![0.0, 2.0];

Is this unexpected, or have I done something wrong in my input?

Here is a relatively minimal test

Test code ``` rust // Passes #[test] fn test_matched_signs() { let mut otg = Ruckig::<2, ThrowErrorHandler>::new(None, 0.01); let mut input = InputParameter::new(None); input.synchronization = Synchronization::Phase; // DOF0 will have positive velocity, moving from 0.0 -> 1.0 // DOF1 will have positive velocity, moving from 0.0 -> 2.0 input.current_position = daov_stack![0.0, 0.0]; input.target_position = daov_stack![1.0, 2.0]; // Start and end at standstill input.current_velocity = daov_stack![0.0, 0.0]; input.target_velocity = daov_stack![0.0, 0.0]; // Limits input.max_velocity = daov_stack![1.0, 1000.0]; input.max_acceleration = daov_stack![10.0, 1000.0]; let mut trajectory = Trajectory::new(None); let result = otg .calculate(&input, &mut trajectory) .expect("This trajectory is solvable."); let profiles = trajectory.get_profiles().get(0).unwrap(); let dof0_profile = profiles.get(0).unwrap(); let dof1_profile = profiles.get(1).unwrap(); assert_eq!(dof0_profile.t, dof1_profile.t); } // Fails #[test] fn test_mixed_signs() { let mut otg = Ruckig::<2, ThrowErrorHandler>::new(None, 0.01); let mut input = InputParameter::new(None); input.synchronization = Synchronization::Phase; // DOF0 will have negative velocity, moving from 1.0 -> 0.0 // DOF1 will have positive velocity, moving from 0.0 -> 2.0 input.current_position = daov_stack![1.0, 0.0]; input.target_position = daov_stack![0.0, 2.0]; // ^^^^ // Start and end at standstill input.current_velocity = daov_stack![0.0, 0.0]; input.target_velocity = daov_stack![0.0, 0.0]; // Limits input.max_velocity = daov_stack![1.0, 1000.0]; input.max_acceleration = daov_stack![10.0, 1000.0]; let mut trajectory = Trajectory::new(None); let result = otg .calculate(&input, &mut trajectory) .expect("This trajectory is solvable."); let profiles = trajectory.get_profiles().get(0).unwrap(); let dof0_profile = profiles.get(0).unwrap(); let dof1_profile = profiles.get(1).unwrap(); assert_eq!(dof0_profile.t, dof1_profile.t); } ``` ``` bash running 1 test test tests::test_mixed_signs ... FAILED failures: ---- tests::test_mixed_signs stdout ---- thread 'tests::test_mixed_signs' panicked at src/main.rs:289:9: assertion `left == right` failed left: [0.1, 0.9, 0.1, 0.0, 0.0, 0.0, 0.0] right: [0.0018211970533701383, 1.0963576058932598, 0.0018211970533701383, 0.0, 0.0, 0.0, 0.0] note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: tests::test_mixed_signs test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 1 filtered out; finished in 7.41s ```
petrikosk commented 4 months ago

Thank you for pointing out the issue. I am happy to hear you have found this library useful.

I ran your test against original C++ version of Ruckig and it passed. The underlying issue was in profile.rs file. Please see the latest commit

Problem is fixed and the test passes.

coljnr9 commented 4 months ago

Awesome, thanks!