-
Notifications
You must be signed in to change notification settings - Fork 106
Add three new anti-windup techniques and a Saturation feature #298
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
base: ros2-master
Are you sure you want to change the base?
Conversation
This pull request is in conflict. Could you fix it @ViktorCVS? |
d0feb10
to
bd7c8f0
Compare
@christophfroehlich, it appears that no reviewers have been assigned to this PR. Could you please help with that? If you have time, I'd appreciate it if you could also take a look at the changes. |
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.
Thx for this thorough PR, but it will need some time to properly review it
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## ros2-master #298 +/- ##
===============================================
+ Coverage 78.17% 80.24% +2.06%
===============================================
Files 30 30
Lines 1338 1655 +317
Branches 87 98 +11
===============================================
+ Hits 1046 1328 +282
- Misses 245 273 +28
- Partials 47 54 +7
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
@ViktorCVS could you please resolve the current conflicts? |
done |
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 the nice work including tests etc. Please fix the pre-commit errors, and only some minor comments in the code
Please add a deprecation notice to the code, as well as a warning on |
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.
For the future: Please don't force push to PRs because it makes it harder for reviewers to check the changes since the last review ;) The history does not have to be linear, because we squash that anyways.
We get closer to the finish line, but some of our comments haven't been addressed yet.
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.
The tests are failing now, can you have a look please?
5513ff0
to
55f3505
Compare
Refactor antiwindup strategy variable implementation replacing string usage with a dedicated enum improve type safety.
Use iszero(x) to compare cmd_ and cmd_unsat_
Can you take a look again, please? My Git didn't work without push with force, so I push the next commit with /f. |
I have a question about the migration steps: this PR was designed so that it doesn’t break existing implementations, but the next PR will actually remove the deprecated technique. Should I list the migration steps now? |
Why? Have you pulled the changes (after my merge via Github UI?). It maybe won't let you pull if you have uncommited changes, either commit them and do a
Let's add the migration notes before we remove it. We will release the changes, wait for the next sync, and then we can remove it. So users have one release cycle to see the deprecation warnings before any behavior changes are applied. |
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 again!
Could you please submit two follow-up PRs:
- One which updates the documentation, basically the summary of your initial message here. But you don't need to document the old behavior, just the result after the deprecation cleanup. Here you can add the migration notes.
- Another one cleaning up the deprecated code. You can draft it for now, and we will merge after the next sync to kilted/rolling.
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.
Oh, I see that the downstream PidController tests fail now. Can you have a look please and update ros-controls/ros2_controllers#1585?
Fixed |
Thanks. I see now that |
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.
@ViktorCVS Very good work
I've only one question, what will the bool antiwindup parameter be used for from now on?
if (antiwindup_strat == AntiwindupStrategy::NONE) | ||
{ | ||
std::cout << "Old anti-windup technique is deprecated. " | ||
"This option will be removed by the ROS 2 Kilted Kaiju release." |
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 option will be removed by the ROS 2 Kilted Kaiju release." | |
"This option will be removed after the ROS 2 Kilted Kaiju releases." |
Should it be after? @christophfroehlich
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'd like to remove things for kilted until we say we have "released" it. But not sure if we should backport this PR to jazzy for users having a chance to update it before they update the distro and ending in a broken setup.
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 would opt for backporting it as it comes with very nice features + easy transition
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.
it does not break API but ABI, and that's what I try to avoid :/
Thanks! Until I remove it, it will still maintain the old behavior. This PR just adds more options. I’ll open a follow-up PR today to remove it. |
In ros2_controllers? I agree. I’ll update the anti-windup parameter description accordingly. |
Should I wait for the merge? |
if (gains.antiwindup_strat_ == AntiwindupStrategy::BACK_CALCULATION && !is_zero(gains.i_gain_)) | ||
{ | ||
i_term_ += dt_s * (gains.i_gain_ * error + 1 / gains.trk_tc_ * (cmd_ - cmd_unsat_)); | ||
} | ||
else if (gains.antiwindup_strat_ == AntiwindupStrategy::CONDITIONAL_INTEGRATION) | ||
{ | ||
if (!(!iszero(cmd_unsat_ - cmd_) && error * cmd_unsat_ > 0)) | ||
{ | ||
i_term_ += dt_s * gains.i_gain_ * error; | ||
} | ||
} |
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 mean using gains.antiwindup_
here? How else can it be deactivated? Or is the plan to leave the NONE for this case?
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! if the user doesn’t want any anti-windup effect on the PID, they should set the value to “none"
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.
Then wouldn't it make sense to remove the Boolean parameter completely? Atleast from the new constructors, this way we won't break again in future. For backward compatibility, if the parameter is set, we can automatically override the internal anti windup type to None.
How does it sound?
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.
Removing the anti-windup parameter from the constructor that accepts multiple arguments would render it inaccessible to users. I suggest we preserve the existing functionality for this PR. What do you think?
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 would not use this parameter in the future, if there is the opportunity to use just the NONE instead. The only question is, how to gracefully transition/deprecate it? Can we add deprecated qualifier to constructor overloads, and just add the same ones without the antiwindup?
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.
Sorry for the delay. I agree; this will make it clearer what will be removed and help clean things up.
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.
What about moving this AntiwindupStrategy
as a non-optional arg of the methods, this should give us some flexibility. I think it makes sense to be explicitly set.
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.
the other overloads are here just for backward compatibility, whenever a new parameter was added. do you propose to deprecate+remove them all?
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.
@christophfroehlich I’ve been reviewing the code, and it seems that if we drop the bool antiwindup parameter from the full overload, we’ll lose any way to pass that flag while it still exists. The wrapper that takes only the bool currently forwards its value to the full overload. If the full overload no longer accepts that argument, there’s nowhere for it to go. Am I overlooking something?
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 not adding the future full-overload, and deprecating the current full-overload with the bool? You can use gcc pragmas to avoid deprecation warnings within our own code:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
<deprecated code..>
#pragma GCC diagnostic pop
Overview
This PR adds three new anti-windup techniques: back‑calculation, the conditioning technique, and conditional integration. It also adds a saturation feature for the PID output. New parameters have been introduced, and additional overloads have been implemented to ensure compatibility.
What was added/changed in this PR
About compatibility
The packages compile correctly and have passed the pre‑commit and colcon tests (packages with dependencies continue to show the same number of failures before and after my modifications). If the new parameters are not used, the package retains its old behavior.
About the older anti-windup technique
My plan, either by the end of this PR or in a subsequent one, is to completely remove the older anti‑windup technique that has been used so far. This method, which is a form of conditional integration, has several disadvantages:
Additionally, regardless of whether the 'antiwindup' parameter is set to true or false, the anti-windup technique is applied (using the same method with a different approach), so the user does not have the option to disable it.
About unit tests
I've added 10 new unit tests for the new features and updated the existing ones to accommodate the new parameters.
Related PR's
Important notes
These three techniques are common anti‑windup strategies used to mitigate the windup effect and are widely employed in control applications: back‑calculation [1], the conditioning technique [1,2], and conditional integration [1,3].
The default values for the tracking time constant are defined in [3,4] for back‑calculation and in [1] for the conditioning technique.
Both back‑calculation and the conditioning technique use forward Euler discretization; this may change before merging this PR.
Graphs
I tested it on ros2_control_demos to better illustrate this feature and test it on simulation to valide the equations. The tests were conducted using a modified version of Example 1: RRBot, which uses a PID controller instead of the default forward position controller. It was tested on Docker, Ubuntu Noble, and Jazzy.
PID values: p = 4.0, i = 25.0, d = 0.5; u_max = 13, u_min = -13; and the tracking time constant was left at its default value.
The standard response with a settling time (ts) of 5.2 seconds, the response affected by saturation, resulting in a settling time (ts_sat) of 8.6 seconds (+65.4% increase) and the response using the back-calculation technique, which improves performance with a settling time (ts_back) of 4.1 seconds (–21.2% decrease), even lower than the standard response.
Those figures compares three anti-windup methods applied to the step response, a zoomed-in view of the step response is provided here to clearly distinguish between the three anti-windup strategies. They are all very similar due to the system and PID values, but they may vary significantly between applications.
The standard control output, the control output affected by saturation, with a recovery time from saturation of 6.8s and the control output using the back-calculation technique, with a recovery time from saturation of 2s (-70.6%).
Those figures compares three control outputs using anti-windup methods, a zoomed-in view of the control output is provided here to clearly distinguish between the three anti-windup strategies. They are all very similar due to the system and PID values, but they may vary significantly between applications.
All the equations have been validated with these simulations, providing a feature with three techniques to address windup.
Final notes
I'm very open to any recommendations to improve this code.
References
[1] VISIOLI, A. Pratical PID Control. London: Springer-Verlag London Limited, 2006. 476 p.
[2] VRANCIC, D et al. Antiwindup, Bumpless, and Conditioned Transfer Techniques for PID Controllers. IEEE Control Systems Magazine, 1996. 16(4):48 - 57.
[3] BOHN, C.; ATHERTON, D. An analysis package comparing pid anti-windup strategies.
IEEE Control Systems Magazine, p. 34–40, 1995.
[4] ASTRöM, K.; HäGGLUND, T. PID Controllers: Theory, Design and Tuning. ISA Press.
Research Triangle Park, USA: Springer-Verlag London Limited, 1995. 343 p.