Giter VIP home page Giter VIP logo

Comments (4)

markpol avatar markpol commented on July 1, 2024 1

I solved this by extending the LoopDecorator to return early on RUNNING results in addition to FAILURE as well as by only having it wrap a single Task rather than the Sequence that I used above.

import BehaviorTree, {
  FAILURE,
  Introspector,
  RunCallback,
  RUNNING,
  Sequence,
  StatusWithState,
  SUCCESS,
  Task,
} from "behaviortree"
import { LoopDecorator } from "behaviortree/lib/decorators"
import { RunResult } from "behaviortree/lib/types"

class InterruptableLoopDecorator extends LoopDecorator {
  nodeType = "InterruptableLoopDecorator"

  decorate(run: RunCallback) {
    let i = 0
    let result: RunResult = FAILURE
    while (i++ < this.config.loop) {
      result = run()
      if (result === FAILURE) return FAILURE
      if (result === RUNNING) return RUNNING
    }
    return result
  }
}

const actionQueue = [() => 1, () => 2, () => 3, () => 4, () => 5]

const testActionsTree = new BehaviorTree({
  tree: new Sequence({
    nodes: [
      new Task({
        name: "populateQueue",
        run: (b) => {
          b.queuedActions = [...actionQueue]
          console.log("Queued items:" + b.queuedActions.length)
          return SUCCESS
        },
      }),
      new InterruptableLoopDecorator({
        node: new Task({
          name: "executeItem",
          run: (b) => {
            b.currentAction = b.queuedActions.shift()
            if (b.currentAction) {
              const actionResult = b.currentAction()
              console.log("Executed item:", actionResult)
              if (actionResult === 3) {
                return RUNNING
              }
              return SUCCESS
            }
            return FAILURE
          },
        }),
      }),
    ],
  }),
  blackboard: {
    queuedActions: [],
    currentAction: undefined,
  },
})

const introspector = new Introspector()
testActionsTree.step({ introspector })
console.log("lastresult 1: ", JSON.stringify(introspector.lastResult, null, 2))
if ((testActionsTree.lastResult as StatusWithState)?.total === RUNNING) {
  testActionsTree.step({ introspector })
  console.log("lastresult 2: ", JSON.stringify(introspector.lastResult, null, 2))
}

which now outputs:

npx ts-node --project tsconfig.test.json test-tree.ts                                                                                                                                                               
Queued items:5
Executed item: 1
Executed item: 2
Executed item: 3
lastresult 1:  {
  "children": [
    {
      "name": "populateQueue",
      "result": true
    },
    {
      "children": [
        {
          "name": "executeItem",
          "result": true
        },
        {
          "name": "executeItem",
          "result": true
        },
        {
          "name": "executeItem"
        }
      ]
    }
  ]
}
Executed item: 4
Executed item: 5
lastresult 2:  {
  "result": false,
  "children": [
    {
      "result": false,
      "children": [
        {
          "name": "executeItem",
          "result": true
        },
        {
          "name": "executeItem",
          "result": true
        },
        {
          "name": "executeItem",
          "result": false
        }
      ]
    }
  ]
}

Thanks again!

from behaviortree.js.

Calamari avatar Calamari commented on July 1, 2024

Hello @markpol.

Glad you like it. And also good to here that someone is trying out the typescript version. I think I should put it down as official release soon, since I haven't heared any typescript related problems yet. And it is pretty old by now :-D

But to your question/use case: That is an interesting one. It definitely sounds that you are misusing the sequence node for something it ain’t meant to do since it does not have a sequence of nodes to care for – since it is only dynamically done in the blackboards –, right?.
As far as I understand your problem, you need a new kind of node, that runs through the list in the blackboard, and can therefore remember where it left off.

Does your sequence have any real children?

from behaviortree.js.

markpol avatar markpol commented on July 1, 2024

Hi @Calamari,

Thanks for the quick reply. Here is some simplified code that perhaps better describes what I'm trying to do:

import BehaviorTree, { FAILURE, Introspector, RUNNING, Sequence, SUCCESS, Task } from "behaviortree"
import { LoopDecorator } from "behaviortree/lib/decorators"

const actionQueue = [() => 1, () => 2, () => 3, () => 4, () => 5]

const testActionsTree = new BehaviorTree({
  tree: new Sequence({
    nodes: [
      new Task({
        name: "populateQueue",
        run: (b) => {
          b.queuedActions = [...actionQueue]
          console.log("Queued items:" + b.queuedActions.length)
          return SUCCESS
        },
      }),
      new LoopDecorator({
        node: new Sequence({
          nodes: [
            new Task({
              name: "shiftItem",
              run: (b) => {
                b.currentAction = b.queuedActions.shift()
                if (b.currentAction) {
                  console.log("Picked item:", actionQueue.length - b.queuedActions.length)
                  return SUCCESS
                }
                return FAILURE
              },
            }),
            new Task({
              name: "processItem",
              run: (b) => {
                const actionResult = b.currentAction()
                console.log("Executed item:", actionResult)
                return actionResult === 3 ? RUNNING : SUCCESS
              },
            }),
          ],
        }),
      }),
    ],
  }),
  blackboard: {
    queuedActions: [],
    currentAction: undefined,
  },
})
const introspector = new Introspector()
testActionsTree.step({ introspector })
console.log("lastresult: ", JSON.stringify(introspector.lastResult, null, 2))
testActionsTree.step({ introspector })

and the output:

npx ts-node --project tsconfig.test.json test-tree.ts                                                                                                                                                                             ─╯
Queued items: 5
Picked item: 1
Executed item: 1
Picked item: 2
Executed item: 2
Picked item: 3
Executed item: 3
Picked item: 4
Executed item: 4
Picked item: 5
Executed item: 5
lastresult:  {
  "result": false,
  "children": [
    {
      "name": "populateQueue",
      "result": true
    },
    {
      "result": false,
      "children": [
        {
          "result": true,
          "children": [
            {
              "name": "shiftItem",
              "result": true
            },
            {
              "name": "processItem",
              "result": true
            }
          ]
        },
        {
          "result": true,
          "children": [
            {
              "name": "shiftItem",
              "result": true
            },
            {
              "name": "processItem",
              "result": true
            }
          ]
        },
        {
          "children": [
            {
              "name": "shiftItem",
              "result": true
            },
            {
              "name": "processItem"
            }
          ]
        },
        {
          "result": true,
          "children": [
            {
              "name": "shiftItem",
              "result": true
            },
            {
              "name": "processItem",
              "result": true
            }
          ]
        },
        {
          "result": true,
          "children": [
            {
              "name": "shiftItem",
              "result": true
            },
            {
              "name": "processItem",
              "result": true
            }
          ]
        },
        {
          "result": false,
          "children": [
            {
              "name": "shiftItem",
              "result": false
            }
          ]
        }
      ]
    }
  ]
}
Queued items: 5
Picked item: 1
Executed item: 1
Picked item: 2
Executed item: 2
Picked item: 3
Executed item: 3
Picked item: 4
Executed item: 4
Picked item: 5
Executed item: 5

So ideally, i would want the tree to stop at action 3 where RUNNING is returned in the processItem task. Then be able to continue afterwards with actions 4 and 5 by calling step() on the tree again. I hope this makes more sense.

I might be able to get the desired result by introducing more state in the blackboard but wasn't sure if there's a better approach.

from behaviortree.js.

Calamari avatar Calamari commented on July 1, 2024

Nice, thanks for sharing. It is an interesting use case. Maybe useful for people to know about.

from behaviortree.js.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.