Skip to content

Idiomatic way to loop tree logic #62

@samouwow

Description

@samouwow

Hi there,

I've been using forester for the last few days, nice work creating a library that's well documented with a full feature set.

My use case will involve re-running the same tree several times a second, and so it would be excellent for the library to support this in an efficient way. Crucially, I would like to avoid restarting the daemons each time the tree is re-run.

I've outlined a few potential designs for how this might be achieved below, roughly in order of usability I think they'd expose to the user:

  1. Expose API for forester_rs::runtime::forester::Forester to separate ticking the tree from cleaning up the tree, which could be done either by:
    1. Exposing a way to manually tick the tree (and so use forester less as a framework and more as a standalone behavior tree library), e.g.
    // Build the tree
    let mut forester = fb.build().unwrap();
    
    // Tick until Success or failure is reached
    let mut tick_result = forester_rs::runtime::TickResult::Running;
    while tick_result == forester_rs::runtime::TickResult::Running {
        tick_result = forester.tick().unwrap();
        // Do other jobs here...
    }
    
    // Shutdown the HTTP server and daemons
    forester.cleanup().unwrap();
    1. Store a flag in the Forester struct to avoid shutting down the HTTP server and daemons after run() returns (I think this would be the easiest to implement), e.g.
    // Disable automatic cleanup
    fb.use_manual_cleanup();
    
    // Build the tree
    let mut forester = fb.build().unwrap();
    
    // Run until failure is reached
    while forester.run().unwrap() == forester_rs::runtime::TickResult::Success {
        // Rerun the tree at 20Hz
        std::thread::sleep(std::time::Duration::from_millis(50));
    }
    
    // Shutdown the HTTP server and daemons
    forester.cleanup().unwrap();
  2. Implement a KeepRunningUntilFailure decorator, as implemented by BehaviorTree.CPP.
    1. This is my personal least favorite solutions, since the daemons will be terminated without any context of why the tree exited.
    2. This could work if it was combined with manual cleanup of daemons (like above) or perhaps if the result of forester.run() was made available to daemons.

I'm more than happy to contribute this change as a PR myself, I just wanted to collaborate on which method you thought would be most idiomatic for Forester. I'm personally in favour of 1.ii followed by 1.i.

I've also got a handful of minor improvements I've noted while using the library, if you're receptive to it I'm happy to submit these as PRs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions