Skip to content
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

Using a ReactiveSequence with asynch condition #875

Open
AndyZe opened this issue Sep 29, 2024 · 7 comments
Open

Using a ReactiveSequence with asynch condition #875

AndyZe opened this issue Sep 29, 2024 · 7 comments

Comments

@AndyZe
Copy link
Contributor

AndyZe commented Sep 29, 2024

TLDR: don't use an asynch action for the condition in a ReactiveSequence.

I have a simple ReactiveSequence like this. It's very similar to the example here:

    <!-- Keep running DummyStatefulAction as long as the monitors are good -->
    <ReactiveSequence>
        <CheckJointVelocityMonitor1/>  <!-- Inherits from BT::RosServiceNode -->
        <DummyStatefulAction/>            <!-- A long-running asynch action -->
    </ReactiveSequence>

The prints when this BT is executing are:

CheckJointVelocityMonitor1 returning SUCCESS  // This BT node always returns success
Starting DummyStatefulAction                                // This is expected, it comes from .onStart(), which returns BT::NodeStatus::RUNNING
DummyStatefulAction halted!                                  // I don't understand where the halt comes from
CheckJointVelocityMonitor1 returning SUCCESS
Starting DummyStatefulAction
DummyStatefulAction halted!
CheckJointVelocityMonitor1 returning SUCCESS
Starting DummyStatefulAction
DummyStatefulAction halted!
CheckJointVelocityMonitor1 returning SUCCESS
Starting DummyStatefulAction
DummyStatefulAction halted!
  ... loop continues

CheckJointVelocityMonitor1 always returns SUCCESS. I've verified with print statements. DummyStatefulAction appears to be ticked once and returns RUNNING, then it gets halted. I don't understand why it gets halted. (Edit: it gets halted because it returns RUNNING.)

Here's the declaration for DummyStatefulAction, which inherits from BT::StatefulActionNode.

class DummyStatefulAction : public BT::StatefulActionNode
{
public:
  DummyStatefulAction(const std::string& name, const BT::NodeConfiguration& config) : StatefulActionNode(name, config)
  {
  }

  static BT::PortsList providedPorts();

  BT::NodeStatus onStart() override;

  BT::NodeStatus onRunning() override;

  void onHalted() override;
};

Here's the definition for DummyStatefulAction. It only returns RUNNING, never SUCCESS or FAILURE.

BT::NodeStatus DummyStatefulAction::onStart()
{
  std::cerr << "Starting DummyStatefulAction" << std::endl;
  return BT::NodeStatus::RUNNING;
}

BT::NodeStatus DummyStatefulAction::onRunning()
{
  std::cerr << "Running DummyStatefulAction" << std::endl;
  return BT::NodeStatus::RUNNING;
}

void DummyStatefulAction::onHalted()
{
  std::cerr << "DummyStatefulAction halted!" << std::endl;
}
@AndyZe
Copy link
Contributor Author

AndyZe commented Sep 29, 2024

I think it must be something related to <CheckJointVelocityMonitor1/> since, if I repalce it with <AlwaysSuccess/>, everything is fine. Like this:

    <ReactiveSequence>
        <!-- CheckJointVelocityMonitor1/ -->
        <AlwaysSuccess/>
        <DummyStatefulAction/>
    </ReactiveSequence>

CheckJointVelocityMonitor1 inherits from BT::RosServiceNode:

class TriggerService : public BT::RosServiceNode<std_srvs::srv::Trigger>
{
public:
  TriggerService() = delete;

  explicit TriggerService(const std::string& name, const BT::NodeConfig& conf, const BT::RosNodeParams& params)
    : RosServiceNode<Trigger>(name, conf, params)
  {
  }

  static BT::PortsList providedPorts()
  {
    return providedBasicPorts({});
  }

  bool setRequest(Trigger::Request::SharedPtr& request) override;

  BT::NodeStatus onResponseReceived(const Trigger::Response::SharedPtr& response) override;

  BT::NodeStatus onFailure(BT::ServiceNodeErrorCode error) override;
};

I'll work on getting a minimal example.

@AndyZe AndyZe changed the title Simple example with ReactiveSequence doesn't seem to work, halted unexpectedly Simple example with ReactiveSequence & BT::RosServiceNode gets halted unexpectedly Sep 29, 2024
@AndyZe
Copy link
Contributor Author

AndyZe commented Sep 29, 2024

With some more print statement debugging, I see the trouble is that the RosServiceNode is getting halted with every other call to tick()?!

response received: 1
Starting DummyStatefulAction
Ticking RosServiceNode
DummyStatefulAction halted!
Ticking RosServiceNode
response received: 1
Starting DummyStatefulAction
Ticking RosServiceNode
DummyStatefulAction halted!
Ticking RosServiceNode
response received: 1
Starting DummyStatefulAction
Ticking RosServiceNode
DummyStatefulAction halted!
Ticking RosServiceNode
response received: 1
Starting DummyStatefulAction

@AndyZe
Copy link
Contributor Author

AndyZe commented Sep 29, 2024

Well, I can achieve the result I want by hacking the source code of bt_service_node.hpp to block until the service returns, within the tick() function.

It would be nice if the BT could block while the service node is running but I don't see a way to do that.

@AndyZe
Copy link
Contributor Author

AndyZe commented Sep 29, 2024

I can make a PR to check the node is synchronous during parsing, if you want. Or maybe just add a parameter to make BT::RosServiceNode block. Or is there an easier way?

@AndyZe
Copy link
Contributor Author

AndyZe commented Sep 29, 2024

You know what, it doesn't matter for my immediate application. I'll use a topic listener instead and check the timestamp of the latest message. Still curious if there was a better way to do this, though.

@AndyZe AndyZe changed the title Simple example with ReactiveSequence & BT::RosServiceNode gets halted unexpectedly Simple ReactiveSequence & BT::RosServiceNode gets halted unexpectedly Sep 29, 2024
@Aglargil
Copy link
Contributor

With some more print statement debugging, I see the trouble is that the RosServiceNode is getting halted with every other call to tick()?!通过进一步调试打印语句,我发现问题出在每调用一次tick() 时,RosServiceNode 就会停止一次!

response received: 1
Starting DummyStatefulAction
Ticking RosServiceNode
DummyStatefulAction halted!
Ticking RosServiceNode
response received: 1
Starting DummyStatefulAction
Ticking RosServiceNode
DummyStatefulAction halted!
Ticking RosServiceNode
response received: 1
Starting DummyStatefulAction
Ticking RosServiceNode
DummyStatefulAction halted!
Ticking RosServiceNode
response received: 1
Starting DummyStatefulAction

Yes, in ReactiveSequence, when a child node of the current tick returns RUNNING, it halt the other child nodes

// reset the previous children, to make sure that they are
// in IDLE state the next time we tick them
for(size_t i = 0; i < childrenCount(); i++)
{
if(i != index)
{
haltChild(i);
}
}

@AndyZe
Copy link
Contributor Author

AndyZe commented Sep 30, 2024

Yeah, the root cause was using an asynch node for the condition. It was dumb now that I think about it, but also not really clear in the docs.

@AndyZe AndyZe changed the title Simple ReactiveSequence & BT::RosServiceNode gets halted unexpectedly Using a ReactiveSequence with asynch condition Oct 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants