-
Notifications
You must be signed in to change notification settings - Fork 308
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
Fix exclusive hardware control mode switching on controller failed activation #1522
base: master
Are you sure you want to change the base?
Fix exclusive hardware control mode switching on controller failed activation #1522
Conversation
@firesurfer This PR has the fix that should solve your issue. If you can test it on your hardware and let us know, it would be great. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1522 +/- ##
==========================================
- Coverage 88.01% 87.96% -0.05%
==========================================
Files 121 124 +3
Lines 12412 12535 +123
Branches 1109 1117 +8
==========================================
+ Hits 10924 11027 +103
- Misses 1083 1099 +16
- Partials 405 409 +4
Flags with carried forward coverage won't be shown. Click here to find out more.
|
@saikishor Thanks a lot. Just for my understanding: If a controller fails activation now, a command mode switch is issued so that the hardware interface can release internally locked hardware? I try to test this patch with an iron based setup. |
@saikishor I just tested your PR and for me it didn't work so far. It could be that I did something wrong. What I did was:
When I activate the controller it fails as it should. But when I then try to load another controller I run into the same issue as before - the interfaces haven't been stopped. |
@firesurfer yes you are right! The hardware will be told to stop the interfaces that are started for the hardware that the controller needed. This should be good for the hardware component to internally release the locked control modes |
@firesurfer can you share the logs here?. Can you print something in your hardware interfaces to see if you receive the stop interfaces?. Basically, if your controller fails activation, it should immediately receive to release interfaces even before activating a new one. If you go over tests, I'm testing exactly the same |
@firesurfer for initial testing, maybe you can remove the installed dependencies and this might help. For me, after removing the installed dependencies, it worked |
So I removed the installed packages: Log while failing activation:
Log during activation of a
I added a log message in the I am not sure if perhaps rebasing on Iron broke something. |
Hello @firesurfer! It seems like you are not using the changes, because If you use the changes of this branch, your error should be like the following
ros2_control/controller_manager/src/controller_manager.cpp Lines 1509 to 1515 in 4a4d780
In your error log, it doesn't mention about the Releasing interfaces, so please crosscheck your setup. Thank you! |
@saikishor I made a mistake while rebasing onto iron. When I do it properly I run into a lots of conflicts. When I try to resolve them it doesn't compile anymore. Do you have an recommendations how to easily test this with an iron setup ? |
You should be able to compile the rolling stack (also this PR) on your iron distro directly. override should also work, no need to uninstall your binary install. (check with |
Thank you @christophfroehlich. Yes, you can do this. In case you continue to have issues, then try to just cherry-pick the last 2 commits of this PR (77e932e and 4a4d780) onto your iron branch |
@saikishor Thanks. Cherry-picking worked :) When I now have the controller failing I run into an endless loop of ros2control trying to activating the controller - failing - stopping the interfaces - starting them again - failing again...
But I can confirm. The interfaces are stopped!. |
@firesurfer I'm glad that the fix worked for you. If that's the case, do you mind reviewing this PR and approving it? |
@saikishor shouldn't be the issue of running into an endless loop of activation -> failing... be addressed first? |
@firesurfer I don't really see how there is an endless loop. CM never reactivates or tries if it is failing. Maybe the print you have added is printing many times, because you have this component per joint and it is trying to iterate over the HW components to do the prepare and perform switch. This is the behavior inside the Resource Manager and I'm not touching that part. EDIT: How many times does it print the |
@firesurfer I can confirm after testing it again on our setup that the fix works and there is no looping activation from the CM side. Thank you |
As I am seeing the activation failure message again and again (of the controller) I would say this is not just because of the printout in the hardware_interface. I had it running for like 10-20s before killing the process. I am wondering if that could be because I cherry-picked it on the iron branch? |
That would be strange to have this in the iron branch. Can you share some logs? EDIT: Can you also share how you are trying to activate this controller? |
@saikishor I just tested in a clean dockerized environment instead of my host installation and it seems to work fine. I will review and approve the PR then. |
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.
Looks fine to me. Maybe you want to address the comment about the additional scope in the controller_manager.
Awesome. I'm very glad that this fixed your issue! 👍 |
This pull request is in conflict. Could you fix it @saikishor? |
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.
Generally I am OK with this, but this calls for even more complex handling of things. And what I rather see as a variable and would put priority to is handling of error that happen when HW mode switching happens as those might have external uncontrollable factors. And controller should not fail on activation, or at least I don't thing that we should handle the both cases as it will be a hell to deal with all the variates of issues and all of that in the real-time sensitive part!
@firesurfer when thinking now more about your issue, I am interested, why your controller fails during activation? How it can be that is configures successfully, but fails on activation? This doesn't sound right.
@bmagyar and @saikishor I even vote that we fobid failing of controllers on activation because of keeping up with the real-time capabilities. This is the reason why we have configure in the first place. Allowing this, I forsee, as elaborated earlier, opening pandora box of funky management of stuff in the update
loop.
// interfaces | ||
if ( | ||
!command_interface_names.empty() && | ||
(!resource_manager_->prepare_command_mode_switch({}, command_interface_names) || |
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.
We should not call this method here, as we are in the RT (update) loop, and this method is declared ad non-realtime relevant in the hardware description, as it is usually called from the non-rt loop (service callback).
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 agree with you! I completely forgot that this is a non-RT method. We can do it at the end as you mentioned in the other comment
if ( | ||
!command_interface_names.empty() && | ||
(!resource_manager_->prepare_command_mode_switch({}, command_interface_names) || | ||
!resource_manager_->perform_command_mode_switch({}, command_interface_names))) |
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.
We have here a bit of a chicken-egg problem. Currently we don't switch controller if this command fails (see line 2112), and we react on an error in general and not an error of specific hardware. We will have to change this in the future, but not for now as it seems not be a problem.
Back to the topic...
I thinks that a cleaner soluation would be to gather all the command interfaces of controller that failed to start and then do only once call on this method, to poke arround HW as little as possible. In current implementation we are doing N-time check in M HW regaridng the interface, if we add this to the line 2136 then we will do only 1xM checks.
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 do as you said, to trigger for all failed controllers at the end!
@destogl As far as I am aware of the only place during the chain of "loading -> configuration -> activation" the In my case I need to make sure that multiple axes of the system are in a certain configuration otherwise the controller won't work / might even damage the system. I therefore strongly oppose the the suggestion to forbid a controller to fail during activation or do you have a better suggestion how to handle a controller that needs to check if the system is in the correct state? I think the workaround I wrote about in the entry post of #1487 is rather ugly. |
I see your point. However, the thing of failing or not is not in our hand with user controllers, moreover, the LifeCycleNode allows this kind of behavior. So, I think it is reasonable to have this fix. We can warn the users that if this situation arises, the realtimeness is not assured anymore. |
This pull request is in conflict. Could you fix it @saikishor? |
7755df0
to
fc2dfe3
Compare
fc2dfe3
to
f04b680
Compare
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 reported issue seams reasonable for me to fix, which LGTM except for some copy-paste remnants in the comments.
{ // Test starting the second controller when the first is running | ||
// Fails as they have the same command interface |
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.
{ // Test starting the second controller when the first is running | |
// Fails as they have the same command interface | |
{ | |
// Test starting the second controller, interfaces should have been released | |
// test_controller2 always successfully activates |
lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE, | ||
abstract_test_controller2.c->get_lifecycle_state().id()); | ||
|
||
{ // Test starting the first controller |
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.
{ // Test starting the first controller | |
{ | |
// Test starting the first controller | |
// test_controller1 activation always fails |
If the hardware supports only one active control mode at a time and when there is a failing controller activation, ros2_control is not propagating this information to the hardware, and the hardware might have the resource locked internally. This PR allows to solve such situations as explained in #1487 and #1486.
Fixes #1487
Closes #1492