-
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
Add velocity feedforward term to velocity HardwareInterfaceAdapter #227
Add velocity feedforward term to velocity HardwareInterfaceAdapter #227
Conversation
3c7fafa
to
d02dd6d
Compare
Nice catch! First, could you please add some unit tests of expected outcomes? That is a good base to start a discussion on. Also adding @ipa-fxm for further thoughts |
I'd be glad to, but I'm honestly not quite sure of what the tests should look like. Only thing I can think of is making this feedforward term optional, using a parameter, and to include a test which compares the evolution of the velocity-based trajectory controller with and without the feedforward term. This would require adding a An additional benefit would be that adding a What do you think? Any better ideas @bmagyar, @ipa-fxm, anyone? |
I just opened PR #228, duplicating the tests for the velocity-based joint trajectory controller, as a basis for testing this PR. Any thoughts on how the tests for the (optional) feedforward term should look like? And BTW, what's the nice thing to do with this PR? Rebase the only commit on top of #228 and reopen? Not quite comfortable with the rules of etiquette here yet 😅 |
Sorry Miguel for the delay. Duplicating all that test code may not be the best solution. I mean 1000 lines of duplication are kinda hard to maintain :) Any comments on this, @efernandez ? I'm going to be quite busy this week but will try to get back next week, feel free to ping me. |
I'm not an expert in control. My understanding is that with this the PID actually works on the state error, which is good. Since I'm not sure of the side effects of this, I'd feel more comfortable if you could provide a param to enable/disable the feedforward term, and set it to false by default to keep previous behaviour; regarding the default value, I honestly don't have a strong opinion. Indeed, I really like that the PIDs can have smaller values and actually work on the state error, which I think it makes more sense. |
Sorry, guys, for the delay.
Totally agree with this, but I was a bit confused by how the I just commited to #228 with what I hope is a better solution for the tests, which duplicates no code at all, and just requires duplicating the controller configuration and test launchfile. Let me know what you think, @bmagyar.
I also thought about this and think it's a reasonable solution. Regarding the default value, I would be inclined to make it enabled by default at some point, but I understand if you want to leave that for future releases in order to avoid messing with working setups. I'll give this a go, @efernandez. |
d02dd6d
to
b292feb
Compare
Hi guys, just changed the velocity feedforward term to be enabled or disabled based on a parameter named I also rebased on top of #228, even though it hasn't been merged yet. I'm sorry if this causes any inconveniences. Since #228 does not contain the velocity feedforward term, though, there's no specific test to validate it. Can you think of any additional test that can be added to validate this specific addition? |
Our common practice is to have one (perhaps one set of) explicit test(s) for each parameter we add. This makes sure that branch testing is somewhat achieved. |
b292feb
to
c3e0988
Compare
I finally managed to add a dedicated test for the velocity feedforward optional term! What I did is:
Thoughts? 1 If you wonder about the place where I inserted the new test, I put it there because I initially added it at the end and this assertion was always failing. Moving it before the tolerance checking tests made it work flawlessly, so I guess there's some side effect from the latter two tests. I haven't had time to figure out what happens, though. |
I don't understand what's going on with the tests. They:
Any ideas? Can anyone else please try? |
The current test set is very sensitive to timing and processor load. That's why we have configured travis to run only one test at a time. However, this approach does not fix the timing issues, but reduces the number of occurrences. In addition I am not 100% sure that we really limit the number of jobs properly. Right now I am runnign the tests of the current master and your PR locally with Update: Tests passed locally for multiple times. |
|
Also, if this happens to be finally merged, is there any chance the changes are backported to indigo? Not sure about the compatibility policy that's followed around here. |
@@ -213,7 +216,7 @@ class HardwareInterfaceAdapter<hardware_interface::VelocityJointInterface, State | |||
// Update PIDs | |||
for (unsigned int i = 0; i < n_joints; ++i) | |||
{ | |||
const double command = pids_[i]->computeCommand(state_error.position[i], state_error.velocity[i], period); | |||
const double command = (desired_state.velocity[i] * use_velocity_ff_) + pids_[i]->computeCommand(state_error.position[i], state_error.velocity[i], period); |
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 line multiplies a boolean with a double. value.
I would prefer a velocity_ff
param, which defaults to 0.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 it the unconventional double * bool
multiplication which you don't like or is it restricting the range of values to effectively 0
and 1
? If its the multiplication I can always reformulate in a conditional statement.
I ask because I can't think of any reasonable case where feedforward gains other than 0
or 1
make sense. Can you?
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.
I am not sure if that really made sense, but we used 0.9 for the Care-O-bot 3 arms (pre-ros_control
stack).
I don't see a reason to restrict it to either 0.0
or 1.0
, but I am no contoller expert.
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.
Me neither. I had always assumed that the feedforward was either there or not, but let's assume whoever put the 0.9
in the COB knew what he was doing and make the parameter a double.
Then, what would you suggest for values greater than 1.0
? Should we raise some warning and clamp, just raise a warning or do nothing altogether?
Travis runs
|
Thanks for your work on this @miguelprada . I can't join in the review discussion at the moment but I'd like to comment on the note about Indigo. Personally I'd like to eventually freeze Indigo and only allow bugfixes but we can discuss small and controlled features to be added if there's a big demand. |
I'm not sure about the demand, but there's a specific reason I think it would be nice to have this in indigo. The Adding this patch to the indigo branch would allow reducing the gains in the default configuration for the |
…y_controllers::JointTrajectoryController.
…it for the EffortJointInterface as well.
c3e0988
to
906b85d
Compare
Just added a new commit making the parameter a As I was on it, I also added the optional feedforward available for the Also, I thought it made more sense to be able to set a different value of the feedforward gain for each joint, so I changed how the parameter is read as well. One missing thing would be to add tests for the Thoughts, anyone? EDIT: I also rebased on top of current |
Thumbs up for the rebase! |
And yet another failed test which I'm unable to reproduce locally 😓 The failed test case seems to be different each time, though. Not sure what to do about this, to be honest. |
It's all about timing, hard to reproduce..
I would suggest to ignore it for now, unless all jobs fail.. |
Are you waiting for any additional input from me? Maybe I'm missing something, but I think all existing comments have been addressed. It would be a nice Xmas present to finally get this merged so I can stop including |
@@ -277,6 +286,13 @@ class HardwareInterfaceAdapter<hardware_interface::EffortJointInterface, State> | |||
} | |||
} | |||
|
|||
// Load velocity feedforward gains from parameter server |
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.
Can this be reused somehow?
It's the same as in line 185..
FF-enabled base class?
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.
In fact, most code is duplicated between the VelocityJointInterface
and the EffortJointInterface
adapters. I'll refactor into a common base class for these specializations.
@@ -35,5 +35,6 @@ | |||
<test test-name="joint_trajectory_controller_test" | |||
pkg="joint_trajectory_controller" | |||
type="joint_trajectory_controller_test" | |||
time-limit="85.0"/> | |||
time-limit="85.0" | |||
args="--gtest_filter=-JointTrajectoryControllerTest.jointVelocityFeedForward"/> |
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.
Why do you exclude this test?
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.
I guess this test file is for the position interface only?
Since the code gets built twice anyway, It could be an option to add macro switch to emphasize that this test won't get run for the
At least a comment should be added.
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.
I guess this test file is for the position interface only?
Exactly.
Since the code gets built twice anyway
Yeah, not very happy about this either. I'll see if I can come up with some way to only build them once.
And I'll add some comment anyways.
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.
I'll see if I can come up with some way to only build them once.
Something like
target_compile_definitions(joint_trajectory_controller_vel_test PRIVATE TEST_VELOCITY_FF=1)
would justify somehow to build it twice ;)
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.
IMHO building it twice is not too bad.
Building it just once would require (?) to:
- move tests (without FF) into a library
- expose text fixture class as header (in test directory)
- add source file for the main function
add_rostest_gtest
with main, linked to libadd_rostest_gtest
with main + ff-test, linked to lib
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.
Finally went for the #ifdef TEST_VELOCITY_FF
check. Is it more or less what you had in mind, @ipa-mdl ?
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.
Finally went for the #ifdef TEST_VELOCITY_FF check. Is it more or less what you had in mind,
It's exactly what I had in mind :D
I won't have sleepless nights over building some tests twice :)
Just make sure we test all we need to. Me or Mathias can merge this once
finished.
|
Most code in Velocity and EffortJointInterface specializations of HardwareInterfaceAdapter was shared and has been refactored into a common base class.
@@ -981,6 +981,9 @@ TEST_F(JointTrajectoryControllerTest, ignorePartiallyOldActionTraj) | |||
} | |||
|
|||
// Velocity FF parameter /////////////////////////////////////////////////////////////////////////////////////////////// | |||
// This test will only be built and run for the VelocityJointInterface-based version of the JointTrajectoryController | |||
|
|||
#ifdef TEST_VELOCITY_FF |
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 consider #if TEST_VELOCITY_FF
to handle TEST_VELOCITY_FF=0
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.
Just noticed this comment. Updated.
Thanks for the refactoring! Somehow the joint trajectory controller have become unstable with the last commit. |
In those cases the adapter closes a loop by computing their commands based on the desired state and the state error. This is not the case for the rest of the adapter specializations.
Which one? The one modifying the tests or the refactor? I must admit I just run the tests locally and pushed when I saw that they passed 😳 I'll play with it locally a bit. |
I see, this makes sense!
79bf8d1. I have restarted 537.2. 537.3 failed as well, but with a different errror |
Thanks for the update! i have restarted all test jobs, which failed for unrelated errors :-/. |
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.
Thanks a lot for your patience!
This is definitely ready for merge now.
I will wait some time (a couple of days?) for others to review it as well.
No hurries. What's a couple of days compared with a year an a half I've been dragging this along 😉 |
ho ho ho 🎅 |
In the current implementation of the
VelocityJointInterface
specialization forHardwareInterfaceAdapter
, a velocity command for the joint will only be generated (by the PID) in the presence of tracking error, therefore perfect tracking can never be achieved.Adding a velocity feedforward term unloads much of the burden from the PID, which only needs to correct for the position and velocity drift that may appear if (when) the robot does not perfectly follow the generated commands. This should allow to improve the controller's performance even decreasing the PID gains significantly, therefore improving also the controller's stability.
I'm not 100% sure of the effects of this change in configurations where the PIDs have been tuned to carry all the load of tracking the velocity reference. I'm inclined to believe that nothing bad will happen, although some tests or some sound theoretical proof would be nice to have in this respect.