RetryNode not respecting ticking frequency
Closed this issue · 4 comments
Describe the bug
version: 4.6.2
In the BT below, I would expect AlwaysFailure
to be ticked every 1000 ms however it's not the case, it's being ticked seemingly without any sleep. I suspect we are stuck in this loop but I'm not sure if this is intended or not
How to Reproduce*
#include "behaviortree_cpp/bt_factory.h"
#include <behaviortree_cpp/loggers/bt_cout_logger.h>
#include <iostream>
using namespace BT;
int main()
{
BehaviorTreeFactory factory;
const std::string xml_text = R"(
<root BTCPP_format="4">
<BehaviorTree ID="MainTree">
<RetryUntilSuccessful num_attempts="10">
<AlwaysFailure/>
</RetryUntilSuccessful>
</BehaviorTree>
</root>
)";
auto tree = factory.createTreeFromText(xml_text);
StdCoutLogger logger(tree);
std::cout << "Running the behavior tree:\n";
NodeStatus result = NodeStatus::RUNNING;
while (result == NodeStatus::RUNNING)
{
result = tree.tickOnce();
std::cout << "Tree Status: " << toStr(result) << "\n";
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
std::cout << "Behavior tree finished with status: "
<< toStr(result) << "\n";
return 0;
}
Result:
Running the behavior tree:
[1732787639.935]: RetryUntilSuccessful IDLE -> RUNNING
[1732787639.935]: AlwaysFailure IDLE -> FAILURE
[1732787639.935]: AlwaysFailure FAILURE -> IDLE
[1732787639.935]: AlwaysFailure IDLE -> FAILURE
[1732787639.935]: AlwaysFailure FAILURE -> IDLE
[1732787639.935]: AlwaysFailure IDLE -> FAILURE
[1732787639.935]: AlwaysFailure FAILURE -> IDLE
[1732787639.935]: AlwaysFailure IDLE -> FAILURE
[1732787639.935]: AlwaysFailure FAILURE -> IDLE
[1732787639.935]: AlwaysFailure IDLE -> FAILURE
[1732787639.935]: AlwaysFailure FAILURE -> IDLE
[1732787639.935]: AlwaysFailure IDLE -> FAILURE
[1732787639.935]: AlwaysFailure FAILURE -> IDLE
[1732787639.935]: AlwaysFailure IDLE -> FAILURE
[1732787639.935]: AlwaysFailure FAILURE -> IDLE
[1732787639.935]: AlwaysFailure IDLE -> FAILURE
[1732787639.935]: AlwaysFailure FAILURE -> IDLE
[1732787639.935]: AlwaysFailure IDLE -> FAILURE
[1732787639.935]: AlwaysFailure FAILURE -> IDLE
[1732787639.935]: AlwaysFailure IDLE -> FAILURE
[1732787639.935]: AlwaysFailure FAILURE -> IDLE
[1732787639.935]: RetryUntilSuccessful RUNNING -> FAILURE
[1732787639.935]: RetryUntilSuccessful FAILURE -> IDLE
Tree Status: FAILURE
Behavior tree finished with status: FAILURE
Another interesting similar case:
I changed tickOnce
to tickExactlyOnce
to avoid getting into the loop mentioned above and it behaves as expected. However, if I change the std::this_thread::sleep_for
to a tree.sleep
as shown below we get a similar behavior as above in which AlwaysFailure
is ticked without a sleep.
#include "behaviortree_cpp/bt_factory.h"
#include <behaviortree_cpp/loggers/bt_cout_logger.h>
#include <iostream>
using namespace BT;
int main()
{
BehaviorTreeFactory factory;
const std::string xml_text = R"(
<root BTCPP_format="4">
<BehaviorTree ID="MainTree">
<RetryUntilSuccessful num_attempts="10">
<AlwaysFailure/>
</RetryUntilSuccessful>
</BehaviorTree>
</root>
)";
auto tree = factory.createTreeFromText(xml_text);
StdCoutLogger logger(tree);
std::cout << "Running the behavior tree:\n";
NodeStatus result = NodeStatus::RUNNING;
while (result == NodeStatus::RUNNING)
{
result = tree.tickExactlyOnce();
std::cout << "Tree Status: " << toStr(result) << "\n";
std::chrono::milliseconds duration(1000);
tree.sleep(duration);
}
std::cout << "Behavior tree finished with status: "
<< toStr(result) << "\n";
return 0;
}
Running the behavior tree:
[1732788586.811]: RetryUntilSuccessful IDLE -> RUNNING
[1732788586.811]: AlwaysFailure IDLE -> FAILURE
[1732788586.811]: AlwaysFailure FAILURE -> IDLE
Tree Status: RUNNING
[1732788586.811]: AlwaysFailure IDLE -> FAILURE
[1732788586.811]: AlwaysFailure FAILURE -> IDLE
Tree Status: RUNNING
[1732788586.811]: AlwaysFailure IDLE -> FAILURE
[1732788586.811]: AlwaysFailure FAILURE -> IDLE
Tree Status: RUNNING
[1732788586.811]: AlwaysFailure IDLE -> FAILURE
[1732788586.811]: AlwaysFailure FAILURE -> IDLE
Tree Status: RUNNING
[1732788586.811]: AlwaysFailure IDLE -> FAILURE
[1732788586.811]: AlwaysFailure FAILURE -> IDLE
Tree Status: RUNNING
[1732788586.811]: AlwaysFailure IDLE -> FAILURE
[1732788586.811]: AlwaysFailure FAILURE -> IDLE
Tree Status: RUNNING
[1732788586.811]: AlwaysFailure IDLE -> FAILURE
[1732788586.811]: AlwaysFailure FAILURE -> IDLE
Tree Status: RUNNING
[1732788586.811]: AlwaysFailure IDLE -> FAILURE
[1732788586.811]: AlwaysFailure FAILURE -> IDLE
Tree Status: RUNNING
[1732788586.811]: AlwaysFailure IDLE -> FAILURE
[1732788586.811]: AlwaysFailure FAILURE -> IDLE
Tree Status: RUNNING
[1732788586.811]: AlwaysFailure IDLE -> FAILURE
[1732788586.811]: AlwaysFailure FAILURE -> IDLE
[1732788586.811]: RetryUntilSuccessful RUNNING -> FAILURE
[1732788586.811]: RetryUntilSuccessful FAILURE -> IDLE
Tree Status: FAILURE
Behavior tree finished with status: FAILURE
The interesting part is that here we get the print Tree Status: RUNNING
meaning that it's the tree.sleep
that gets preempted.
I think the bug originates from here, can you explain the logic behind calling emitWakeUpSignal
before returning RUNNING?
@SteveMacenski just FYI if someone ever reports it in Nav2. I think it also affects the RecoveryNode (not 100% sure though)
I think it is related to this: #723
The behavior is the intended one, i.e., it does not wait a tick to retry.
ok, thanks for investigating this and explaining it to others that may have the same problem. closing the issue now