-
Notifications
You must be signed in to change notification settings - Fork 525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TrajectoryController: Use desired state to calculate hold trajectory #297
TrajectoryController: Use desired state to calculate hold trajectory #297
Conversation
By looking at the plot and some experience with robots using this I think you are onto something. We do have however a policy to add tests to every issue we encounter and then the fix for it. This makes sure that a newly discovered problem will stay fixed. Could you please reproduce the issue within a test? Without your fix the test should fail. You can measure the jerk you mentioned. |
I can confirm these jump movements in certain cases with the Schunk arms, but I haven't found out why. In I think the fix is correct. The last command should be kept in order to prevent jumps. To further understand the effect and to provide a proper test: |
I've added a testcase. Please Review and comment on the code / test. New Plots from the testcase run with This PR is the same as #176 and #177; we only searched the issues and thus opened a duplicate PR, sorry for that. |
Reviewing the old discussions using the desired state might lead to problems as well. As a compromise the hold target could get capped by the max. allowed tracking error.
The test looks good, but I haven't tried it yet. The |
@ipa-mdl I'm not aware of all use-cases, where ros_controllers is used. But sending out desired values to an underlying HW-interface (can be PID or any other control), I don't see any point in jumping from a The main point of this PR is, that while a joint is moving, the Adolfo-rt suggests in a comment, to preserve the old behaviour, if |
See pull request for fix/jerk_on_stop for detailed description. This commit adds a delay subscriber to rrbot to emulate a hardware controller with dead time. The jump backwards in the actual position is observed in joint_trajectory_controller_test by extending the stateCB. The new testCase fails, if the velocity of the actual position is negative although motion should only be forwards.
0eca54b
to
9bc9fe7
Compare
I've changed the test case accordingly.
|
@bmagyar What do you think? Could this be merged? Should I preserve the old behaviour for stop_time=0?
|
@@ -755,12 +762,14 @@ setHoldPosition(const ros::Time& time, RealtimeGoalHandlePtr gh) | |||
const unsigned int n_joints = joints_.size(); | |||
for (unsigned int i = 0; i < n_joints; ++i) | |||
{ | |||
hold_start_state_.position[0] = joints_[i].getPosition(); | |||
hold_start_state_.velocity[0] = joints_[i].getVelocity(); | |||
// If there is a time delay in the system it is better to use calculate the hold trajectory starting from the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"better to use calculate the hold trajectory"
@jschleicher Yes, please preserve that behaviour. Also, I know this request is pretty blunt, but can you think of more ways to add tests for your fix? One could be to ensure that old behaviour is preserved. |
Yes, I'll add that. Thanks for the review. |
Adding a topic to rrbot to set an upper bound allows to test the actual position after setHoldPosition() has been called.
old behaviour for stop_trajectory_duration==0
8a9e3db
to
e717d26
Compare
|
I've added the requested test case, please review again. |
@@ -138,6 +138,13 @@ starting(const ros::Time& time) | |||
time_data.uptime = ros::Time(0.0); | |||
time_data_.initRT(time_data); | |||
|
|||
// Initialize the desired_state with the current state on startup |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not change the behavior, it gets overwritten in update
anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exactly: It gets overwritten on the next update(). But starting
calls setHoldPosition
three lines later and reads the desired_state (if stop_trajectory_duration_ != 0
), so we have to initialize it beforehand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I have just written this for clarification/justfication during the review :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After reading through the dicussions in #144 again, the consensus was that the stop_trajectory_duration
option is not ideal..
I think adding a parameter/flag might be better to not break existing behavior.
However, the code and the tests look good.
hold_start_state_.position[0] = joints_[i].getPosition(); | ||
hold_start_state_.velocity[0] = 0.0; | ||
hold_start_state_.acceleration[0] = 0.0; | ||
(*hold_trajectory_ptr_)[i].front().init(time.toSec(), hold_start_state_, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: start_time
could be used as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep.
The desired state is not aligned to the hardware resolution (the current state should be), so commanding the desired state might result in small alternating motions. Perhaps we should command the current state (joint-wise) if commanding the desired state would change the direction of motion. |
The So with regard to the non-RT timing, it might make sense to set a 2 segment trajectory:
Not sure if this really makes a difference.. |
As discussed with @jschleicher directly, this PR fixes a bug and the new behavior should be the default. If legacy users rely on the old behavior, it can be enabled by setting |
From the plots and the Line 469 in e5a6c5a
So the hold trajectory is (using this PR) calculated starting from |
@@ -35,5 +35,5 @@ | |||
<test test-name="joint_trajectory_controller_test" | |||
pkg="joint_trajectory_controller" | |||
type="joint_trajectory_controller_test" | |||
time-limit="85.0"/> | |||
time-limit="95.0"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the additional test takes some more seconds. I think, some "sleep" in the old tests aren't really needed, I'll try to optimize a bit to stay at 85 seconds here.
type="joint_trajectory_controller_test" | ||
time-limit="85.0"/> | ||
type="joint_trajectory_controller_vel_test" | ||
time-limit="120.0"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is "rebase" on develop, picked the change from there to avoid merge conflicts.
Guys, I think you are very close (or there already) to the source of #144 . I looked at it now, I think the approach is good and I've changed my stance on the question of the flag: we should put this by default. BTW I experience this jerk every time I switch from the gravity compensation controller on As this is more of a major change, allow me to come back to this again later this week. |
* use start_time variable in setHoldPosition * doxygen documentation in header file * drop sleep() in testcases in favor of waiting for PREEMPTED/SUCCEEDED state to speedup the tests a bit and stay below the former timeout of 85s
@ipa-mdl you may merge when ready. |
@jschleicher, regarding the timing: I guess for most users this should not be an issue because the stop trajectory duration should be big enough anyway for practical reasons. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please let me know if you want change anything w.r.t. the timing.
However, I am ready to merge this as-is.
Are you okay with squash-merging?
If not, please rebase accordingly, especially the last commit.
Yes, please squash-merge. |
Finally 🎉 |
Thanks guys for the effort! |
The current state is used for calculating the hold-trajectory, that results in a jump in the desired position. The time delay originating from the canopen communication leads to a desired position that is already in the past.
Below the effect can be clearly seen by comparing the trajectories (plotted from the CAN traces).
It can be clearly seen that the desired trajectory switches the sign of the velocity. This results in a jerk of the respective drive. If the speed is high and/or the stop_time is reduced this effect increases.
I would also argue that this behavior causes mechanical stress in the robot.
Any opinions?
Noticed with Schunk LWA4p