WEBVTT 00:00.000 --> 00:16.000 All right, so let's say you switch to retinab and now you need to implement your behavior 00:16.000 --> 00:17.000 please. 00:17.000 --> 00:20.000 Probably below is going to present an option for that. 00:20.000 --> 00:21.000 Thank you very much. 00:21.000 --> 00:23.000 All right, yeah. 00:23.000 --> 00:25.000 Thank you for this nice transition. 00:25.000 --> 00:26.000 So I'm Robin. 00:26.000 --> 00:28.000 I'm from the Technical University in Downset. 00:29.000 --> 00:31.000 And I work mostly with aerial robotics. 00:31.000 --> 00:37.000 And for a few years ago, I started working with my master thesis, 00:37.000 --> 00:42.000 and I tried to develop an automated mission management tool 00:42.000 --> 00:44.000 for using it with PX4. 00:44.000 --> 00:47.000 And I tried to use behavior trees for this, 00:47.000 --> 00:49.000 and this is how this project is developed, 00:49.000 --> 00:52.000 because there was no real integration with Rust 00:52.000 --> 00:57.000 through that that allowed me to use it in PX4 as I wanted. 00:57.000 --> 01:02.000 So yeah, I don't have the time to explain to you 01:02.000 --> 01:07.000 what behavior trees are, but I was just giving you a small introduction. 01:07.000 --> 01:10.000 So why do we need something like behavior trees, 01:10.000 --> 01:11.000 or state machines? 01:11.000 --> 01:16.000 It basically gives us the possibility for intelligent robotics 01:16.000 --> 01:20.000 to implement decision-making logic and reactive mechanisms. 01:20.000 --> 01:23.000 And usually behavior trees, they promise, 01:23.000 --> 01:28.000 composability, modularity, and this reactivity that I spoke of. 01:28.000 --> 01:32.000 And it doesn't let us drown in this spaghetti logic 01:32.000 --> 01:35.000 that state machines usually do, 01:35.000 --> 01:39.000 because in state machines each state has a transition 01:39.000 --> 01:43.000 to another and the more states, the more suggestions you have. 01:43.000 --> 01:48.000 So this can get very complicated once your project scales. 01:48.000 --> 01:55.000 So I looked into the ecosystem, and I found that there's lots of frameworks 01:55.000 --> 01:58.000 or lots of implementations of behavior trees, 01:58.000 --> 02:02.000 and also some integrations into Rust. 02:02.000 --> 02:07.000 And I found that the Python integrations are usually a bit more usable 02:07.000 --> 02:10.000 than the C++ ones. 02:10.000 --> 02:16.000 But I wanted to have the deterministic timing of C++ 02:16.000 --> 02:20.000 and also the robustness in resource-constrained environments 02:20.000 --> 02:22.000 since I was working with drones. 02:22.000 --> 02:26.000 And this could become an issue when the future. 02:26.000 --> 02:29.000 So I decided to do this in C++, 02:29.000 --> 02:31.000 and there obviously there was behavior TCPP, 02:31.000 --> 02:34.000 and the video by now you should be very flattered 02:34.000 --> 02:40.000 since it's another default call at dev talk that mentions your work. 02:40.000 --> 02:45.000 And I tried to find different ways of integrating that into Rust 02:45.000 --> 02:48.000 and have two, for example, or behavior tree Rust. 02:48.000 --> 02:56.000 Since in my opinion, it wasn't quite fitting my needs to set us 02:56.000 --> 02:58.000 by me, basically. 02:58.000 --> 03:01.000 So I set basically three design goals. 03:01.000 --> 03:06.000 I wanted to develop a domain-agnostic development framework 03:06.000 --> 03:11.000 for behavior trees that allows us to do behavior-based control 03:11.000 --> 03:14.000 and automated planning, without depending on 03:14.000 --> 03:17.000 what we have to or something like this, for example. 03:17.000 --> 03:20.000 I also wanted to reduce the configuration overhead, 03:20.000 --> 03:23.000 that usually comes with C++ projects, 03:23.000 --> 03:26.000 and to lower the barrier to entry. 03:26.000 --> 03:29.000 And also I wanted to focus really on modularity and reusability 03:29.000 --> 03:33.000 since I wanted to be a generalized framework. 03:33.000 --> 03:36.000 Okay, so with this motivation out of the way, 03:36.000 --> 03:39.000 how does it work now in detail? 03:39.000 --> 03:43.000 So behavior trees would usually use in a robotics 03:43.000 --> 03:47.000 architecture like this, where you have your user domain with your notes, 03:47.000 --> 03:49.000 or I call it skills here. 03:49.000 --> 03:52.000 For example, this could be the easy-nav framework, 03:52.000 --> 03:56.000 and then you would have the behavior trees for orchestrating your skills, 03:56.000 --> 04:00.000 your functions of your robots, 04:00.000 --> 04:04.000 and behavior trees therefore represent policies or plans, 04:04.000 --> 04:08.000 and they use functions of the robot through clients 04:08.000 --> 04:11.000 or decolon notes with behavior trees. 04:13.000 --> 04:16.000 So I think for getting more into detail, 04:16.000 --> 04:18.000 we need like a little examples. 04:18.000 --> 04:21.000 So I created a little robot simulation 04:21.000 --> 04:24.000 that we're going to follow along here. 04:24.000 --> 04:28.000 We're going to use for explaining the behavior tree framework, 04:28.000 --> 04:31.000 and this robot exposes two interfaces. 04:31.000 --> 04:35.000 So one sensory interface for reading the position of the hand, 04:35.000 --> 04:41.000 the current position, and a actuator basically. 04:41.000 --> 04:44.000 So we can send velocity commands to the hand, 04:44.000 --> 04:47.000 so it moves to the left or to the right. 04:47.000 --> 04:51.000 And for creating a wave behavior now, 04:51.000 --> 04:54.000 what we do is to create the behavior, 04:54.000 --> 04:58.000 or the build request for the executor for the behavior. 04:58.000 --> 05:02.000 And for behavior tree CPP, it looks something like this, 05:02.000 --> 05:05.000 so we have an XML schema, 05:05.000 --> 05:09.000 and on the right, you see the visual representation of it. 05:09.000 --> 05:12.000 And the behavior in this case, it's pretty simple. 05:12.000 --> 05:15.000 We want to move to an end position for doing the wave, 05:15.000 --> 05:17.000 and maybe repeat it for once or twice, 05:17.000 --> 05:20.000 and then we want to move back to the center. 05:20.000 --> 05:23.000 So this is the first example I'm going to show you, 05:23.000 --> 05:26.000 and I'm going to show you how to implement it with RAPMS. 05:26.000 --> 05:28.000 So first of all, we need notes. 05:28.000 --> 05:30.000 Since all of the behavior trees, 05:30.000 --> 05:33.000 they are implemented or they use these notes 05:33.000 --> 05:36.000 that call the robot skills, 05:37.000 --> 05:40.000 and there's potentially lots of them. 05:40.000 --> 05:42.000 So we need a way to organize them. 05:42.000 --> 05:45.000 So we have a node manifest in RAPMS. 05:45.000 --> 05:48.000 It's basically just YAML configurations, 05:48.000 --> 05:51.000 where you specify a plugin, 05:51.000 --> 05:53.000 and then some other configurations. 05:53.000 --> 05:56.000 And for example, for this behavior, 05:56.000 --> 05:57.000 we have four notes. 05:57.000 --> 05:59.000 So we have move for the site, 05:59.000 --> 06:03.000 stop movement, and hand reach end position, and hand is centered. 06:03.000 --> 06:07.000 And you might have noticed that we reused 06:07.000 --> 06:10.000 this existing implementation of a velocity publisher, 06:10.000 --> 06:12.000 in this case, 06:12.000 --> 06:15.000 but by just configuring different ports, 06:15.000 --> 06:18.000 different default values for the velocity port, 06:18.000 --> 06:20.000 we give it a different semantic meaning. 06:20.000 --> 06:22.000 So we have two distinct notes, 06:22.000 --> 06:25.000 but we're reusing the C++ implementation, 06:25.000 --> 06:28.000 which allows us to really write as little code 06:28.000 --> 06:31.000 as we really need to write, 06:31.000 --> 06:33.000 and not just change a little thing, 06:33.000 --> 06:38.000 and we just have the same code and repeat ourselves. 06:38.000 --> 06:44.000 And this is also the case for the position interface. 06:44.000 --> 06:47.000 So with these notes, 06:47.000 --> 06:51.000 we need to go into our C-Mac list of our package, 06:51.000 --> 06:53.000 and it's a C++ project. 06:53.000 --> 06:57.000 We configure a C++ project with C-Mac, 06:58.000 --> 07:01.000 and it looks something like this with this framework. 07:01.000 --> 07:05.000 So first of all, we need to register our plugins, 07:05.000 --> 07:07.000 in a C-Mac all like that. 07:07.000 --> 07:10.000 Now, remember, we have two plugins, 07:10.000 --> 07:12.000 and in the second code block, 07:12.000 --> 07:14.000 you see that we link these plugins 07:14.000 --> 07:17.000 with the node manifests that I've showed you before. 07:17.000 --> 07:20.000 So this is where we do the mapping between 07:20.000 --> 07:22.000 the registration names of the notes, 07:22.000 --> 07:25.000 and the implementation that we want to use 07:26.000 --> 07:28.000 when we're calling these notes. 07:28.000 --> 07:31.000 So in this integration into C-Mac, 07:31.000 --> 07:33.000 we get some benefits out of it. 07:33.000 --> 07:34.000 So first of all, 07:34.000 --> 07:37.000 we register our configurations, 07:37.000 --> 07:38.000 workspace-wise, 07:38.000 --> 07:40.000 so we can reuse it in the future 07:40.000 --> 07:42.000 in our distributed workspaces, 07:42.000 --> 07:45.000 and we can do some compile-time validation checks 07:45.000 --> 07:48.000 that helps avoiding runtime errors 07:48.000 --> 07:50.000 that are usually harder to debug. 07:50.000 --> 07:54.000 And also it allows us to generate code automatically, 07:54.000 --> 07:58.000 for example the XML file for the node models 07:58.000 --> 08:02.000 that you usually use with visual editors, 08:02.000 --> 08:03.000 like Brut, 08:03.000 --> 08:06.000 and also in this very specific to our APMS, 08:06.000 --> 08:08.000 we generate a C++ header 08:08.000 --> 08:12.000 that we use with our together with our builder API. 08:12.000 --> 08:15.000 And I'm going to show you what exactly this is 08:15.000 --> 08:18.000 in the coming slides. 08:18.000 --> 08:20.000 So now we have the node manifest, 08:20.000 --> 08:21.000 we have the builder requests, 08:21.000 --> 08:25.000 so we're basically able to deploy the behavior 08:25.000 --> 08:27.000 by now. 08:27.000 --> 08:32.000 And for this we call another macro in the configuration file, 08:32.000 --> 08:35.000 where we just specify our build request, 08:35.000 --> 08:37.000 that is basically an XML file, 08:37.000 --> 08:39.000 and we give it an alias, 08:39.000 --> 08:42.000 and also we link to this behavior, 08:42.000 --> 08:44.000 or to this definition of the behavior, 08:44.000 --> 08:46.000 we link a specific node manifest, 08:46.000 --> 08:50.000 and we can do this both for doing the waving to the left, 08:50.000 --> 08:52.000 and the waving to the right. 08:52.000 --> 08:55.000 And don't need to redefine our behavior or something like this. 08:55.000 --> 08:57.000 We just switch out the nodes, 08:57.000 --> 08:59.000 and then we have a different behavior. 08:59.000 --> 09:03.000 So this is what's denoted by this side variable here. 09:03.000 --> 09:08.000 So we would do this called twice for once left and once right. 09:08.000 --> 09:12.000 And then also we basically with this configuration, 09:12.000 --> 09:15.000 we're able to just run this behavior 09:15.000 --> 09:18.000 with our unified CLI tool for running behaviors, 09:18.000 --> 09:21.000 and then we define the identity of the behavior we want to run, 09:21.000 --> 09:24.000 and we might also just define some blackboard values 09:24.000 --> 09:27.000 to give some variables to the behavior. 09:27.000 --> 09:29.000 And then it looks something like this. 09:29.000 --> 09:30.000 So we call this this command here, 09:30.000 --> 09:32.000 and the hand moves to the left, 09:32.000 --> 09:33.000 repeats its twice, 09:33.000 --> 09:36.000 and the same thing happens for doing it on the left. 09:36.000 --> 09:38.000 And then it looks something like this. 09:38.000 --> 09:42.000 So we call this this command here, 09:42.000 --> 09:44.000 and the hand moves to the left, 09:44.000 --> 09:46.000 repeats its twice, 09:46.000 --> 09:49.000 and the same thing happens for doing it to the right, 09:49.000 --> 09:54.000 and we just need to change a little namespace here. 09:54.000 --> 09:57.000 And we have two different, two very distinct behaviors, 09:57.000 --> 09:59.000 but using minimal code, 09:59.000 --> 10:01.000 minimal configuration, 10:01.000 --> 10:04.000 and minimal XML definition. 10:04.000 --> 10:09.000 Because we maximize the reusability through this framework. 10:09.000 --> 10:14.000 Okay, so by now I've shown you how you work with this framework, 10:14.000 --> 10:17.000 using the existing practices that you know, 10:17.000 --> 10:20.000 when you've tried behavior to CPP. 10:20.000 --> 10:23.000 But let me tell you, there's more to this framework 10:23.000 --> 10:25.000 than just to plain behavior trees. 10:25.000 --> 10:30.000 So it's just defining the behavior tree as an XML file. 10:30.000 --> 10:36.000 There's also the possibility to customize your behavior generation pipeline. 10:36.000 --> 10:41.000 And this basically needs us to understand what a behavior is. 10:41.000 --> 10:47.000 So in our IPMS, we're defining a behavior as a collection of components. 10:47.000 --> 10:51.000 So first of all, the most important component probably is a build request. 10:51.000 --> 10:54.000 So this is the XML definition I've showed you before. 10:54.000 --> 10:56.000 And then we have a build handler, 10:56.000 --> 11:01.000 and this is a very innovative approach, I'd say. 11:01.000 --> 11:08.000 So we are just going to find this component as the algorithm that is responsible for creating 11:08.000 --> 11:13.000 the run out of the executable behavior tree out of the build request. 11:13.000 --> 11:16.000 And this can be anything like depending on your use case, 11:16.000 --> 11:18.000 you just write your plugin, 11:18.000 --> 11:20.000 define a format for your build requests, 11:20.000 --> 11:26.000 and you create a behavior tree that fits your needs. 11:26.000 --> 11:30.000 So the idea of the build handler is interesting, 11:30.000 --> 11:32.000 so but why do we need it? 11:32.000 --> 11:37.000 Let's say we want to move the hand now twice to the left, twice to the right, 11:37.000 --> 11:38.000 and then once left, once right. 11:38.000 --> 11:42.000 So very specific behavior that we couldn't do with our current definition, 11:42.000 --> 11:45.000 because we would only wave left or right. 11:45.000 --> 11:50.000 And now you might say, obviously we can just rewrite our behavior, 11:50.000 --> 11:52.000 we could just quickly sketch a new behavior, 11:52.000 --> 11:54.000 it is not a big thing, 11:54.000 --> 11:56.000 but that's not really the cool thing to do. 11:56.000 --> 12:02.000 We want to automate this because potentially we want to kind of also integrate 12:03.000 --> 12:07.000 some variables for this build mechanism, 12:07.000 --> 12:11.000 and this doesn't solve probably potentially very beneficial 12:11.000 --> 12:16.000 if we automate this because of the future, 12:16.000 --> 12:19.000 because of scalability basically. 12:19.000 --> 12:21.000 And for this behavior now, 12:21.000 --> 12:27.000 I want to show you how to solve this by creating a new build handler. 12:27.000 --> 12:30.000 So we create also a new build request 12:30.000 --> 12:35.000 that specifies only the very interesting parts of the request. 12:35.000 --> 12:38.000 So only if you want to move left or right and when. 12:38.000 --> 12:42.000 So this is basically a sequence of characters with L&Rs. 12:42.000 --> 12:45.000 And this is what for what build build handler, 12:45.000 --> 12:49.000 and this is what build handler like this could look like. 12:49.000 --> 12:53.000 And you see here we just import or create a new behavior tree 12:53.000 --> 12:57.000 from our existing behaviors that we have in our workspace already. 12:58.000 --> 13:03.000 So in this case we import the behavior tree for moving to the end position, 13:03.000 --> 13:06.000 and we do this for both moving to the left and to the right, 13:06.000 --> 13:09.000 and then rename it, we rename it, 13:09.000 --> 13:13.000 and this is all happening through the tree build API. 13:13.000 --> 13:16.000 And in the second code blog we parse the build request 13:16.000 --> 13:18.000 that we give the build handler, 13:18.000 --> 13:21.000 and it generates the behavior tree, 13:21.000 --> 13:23.000 the corresponding behavior tree, 13:23.000 --> 13:27.000 automatically by just executing this for loop, 13:27.000 --> 13:32.000 and then inserting the subtries in the sequence 13:32.000 --> 13:35.000 where we're supposed to be. 13:35.000 --> 13:40.000 And then we're returning this tree and it can be executed by the executor. 13:40.000 --> 13:42.000 So this is the implementation, 13:42.000 --> 13:46.000 obviously we need to register this again with the configuration in CMake. 13:46.000 --> 13:49.000 So we call another macro just to register the build handler, 13:49.000 --> 13:53.000 so this is its name, and then we call the macro for registering a behavior. 13:53.000 --> 13:57.000 And now you might have noticed this says register behavior, 13:57.000 --> 13:59.000 the previous one said register trees. 13:59.000 --> 14:03.000 So this is a bit more of an abstract definition now, 14:03.000 --> 14:05.000 because it's not only a tree, 14:05.000 --> 14:07.000 it's a whole new definition of a behavior. 14:07.000 --> 14:11.000 Since we have a different format for the build request, 14:11.000 --> 14:15.000 and we want to handle this build request with a specific algorithm. 14:15.000 --> 14:17.000 So this is what we specify here. 14:17.000 --> 14:21.000 I'm just going to statically register the behavior definition here, 14:21.000 --> 14:25.000 the request, and link it with this builder. 14:25.000 --> 14:29.000 So the executor knows during runtime how to interpret this message. 14:29.000 --> 14:34.000 So we can run this behavior with the same CLI tool as I've shown you before. 14:34.000 --> 14:36.000 And this is what it looks like. 14:36.000 --> 14:40.000 You know, see there's lots of behaviors already in the workspace, 14:40.000 --> 14:43.000 also a custom one, and this one we're going to execute now. 14:43.000 --> 14:49.000 So it sends the builder request and the hand moves left, left, right, right, left, right. 14:49.000 --> 14:53.000 And you could also do this just dynamically. 14:53.000 --> 14:59.000 You could just load the build handler and send an arbitrary builder request 14:59.000 --> 15:01.000 that just respects the format. 15:01.000 --> 15:05.000 You have to find with this build handler and change the behavior 15:05.000 --> 15:11.000 that's been generated during runtime as you like in your application. 15:12.000 --> 15:14.000 And now you also have like this, this, 15:14.000 --> 15:19.000 the engine of reactivity that people usually want with behavior trees, 15:19.000 --> 15:25.000 because you could not only just hard code the reactivity in the behavior, 15:25.000 --> 15:31.000 but you can also just make the behavior generation reactive by itself. 15:31.000 --> 15:37.000 So the executor is basically, this is all unified within one executor note 15:37.000 --> 15:42.000 in this framework that just awaits these, 15:42.000 --> 15:46.000 well, these definitions, the components of the behavior definition. 15:46.000 --> 15:50.000 So they request handler and then entry point in the node manifest, 15:50.000 --> 15:56.000 optionally, and also is compliant with the rawst to action interface. 15:56.000 --> 16:01.000 And this is basically happening just like with standard rawst, 16:01.000 --> 16:06.000 there's only one command that you have to like run and this is like a standalone executable 16:06.000 --> 16:08.000 that doesn't require an F2. 16:08.000 --> 16:11.000 So is the main diagnostic solution, 16:11.000 --> 16:18.000 and yeah, you can start creating your own behavior definitions for use cases. 16:18.000 --> 16:22.000 Okay, so I'm coming to the answer of my talk now. 16:22.000 --> 16:27.000 I've officially also released this project with the rawst index. 16:27.000 --> 16:34.000 It's up for you to install it with as any other project that you install 16:34.000 --> 16:37.000 individually, and I encourage you to give it a try, 16:37.000 --> 16:40.000 and streamline your rawst to project. 16:40.000 --> 16:43.000 And also there's something interesting coming up. 16:43.000 --> 16:48.000 I'm actually working together with a group of students in my university, computer science students, 16:48.000 --> 16:53.000 and we're trying to create like a behavior management tool that is web-based. 16:53.000 --> 16:58.000 So we have all our behaviors that we've registered in our workspace, 16:58.000 --> 17:03.000 at hand, at a visualization in the browser, 17:03.000 --> 17:06.000 and we can run it as we like. 17:06.000 --> 17:11.000 So we have basically a remote mission manager always in the browser. 17:11.000 --> 17:15.000 If we want to manage our mission with behavior trees. 17:15.000 --> 17:20.000 Okay, thank you very much for this for your attention. 17:20.000 --> 17:24.000 And all the material or the code is on GitHub. 17:24.000 --> 17:28.000 Also there's extensive user guides for this project. 17:28.000 --> 17:31.000 And I found that the AI generated docs are actually also very helpful, 17:31.000 --> 17:34.000 especially if you pipe them into some LLMs. 17:34.000 --> 17:36.000 It's very interesting what's possible. 17:36.000 --> 17:38.000 Okay, thank you very much. 17:38.000 --> 17:51.000 I have plenty of time for questions, anybody? 17:51.000 --> 17:53.000 No, nobody. 17:53.000 --> 17:54.000 Anything online? 17:54.000 --> 17:55.000 No? 17:55.000 --> 17:59.000 Oh, there's one. 17:59.000 --> 18:01.000 Yeah, thanks for the presentation. 18:01.000 --> 18:05.000 So you mentioned that this is kind of integrated with the NAFER framework. 18:05.000 --> 18:06.000 No, it is not. 18:06.000 --> 18:07.000 It's not. 18:07.000 --> 18:08.000 It's not. 18:08.000 --> 18:10.000 But it's the main agnostic. 18:10.000 --> 18:16.000 Okay, I was wondering if it's also possible to use this for like the movement framework. 18:16.000 --> 18:22.000 Yeah, so well, I mean, the problem is that with NAF2, 18:22.000 --> 18:25.000 the implement of their own behavior executor. 18:25.000 --> 18:33.000 And it is not compatible with the way that like this executor works with the customization options 18:34.000 --> 18:39.000 and the modularity because it instantiates the behavior trees in a different way. 18:39.000 --> 18:48.000 So the problem here is that you cannot really reuse existing notes for your other projects. 18:48.000 --> 18:56.000 You should kind of, you must like create a custom bridge for these functionalities. 18:56.000 --> 18:58.000 Yeah. 18:59.000 --> 19:00.000 Anybody else? 19:00.000 --> 19:02.000 We have plenty of time. 19:11.000 --> 19:16.000 So your command line says that it's doing a build. 19:16.000 --> 19:19.000 So at run time you're doing code compilation. 19:19.000 --> 19:22.000 That's that right. 19:22.000 --> 19:27.000 Yeah, well, at run time we're doing the redundant code compilation. 19:27.000 --> 19:28.000 At run time. 19:28.000 --> 19:30.000 To what exactly are you referring? 19:30.000 --> 19:31.000 I might ask. 19:31.000 --> 19:36.000 So if you're building a custom behavior, you've got your custom behavior builder. 19:36.000 --> 19:37.000 Yeah. 19:37.000 --> 19:40.000 Are you, is that just running at run time? 19:40.000 --> 19:41.000 It's already compiled. 19:41.000 --> 19:43.000 Well, it's a plugin. 19:43.000 --> 19:48.000 It's a plugin that is loaded dynamically to the executor. 19:48.000 --> 19:53.000 So this code is loaded once you request to behavior to be started. 19:54.000 --> 19:57.000 And then the request for the behavior. 19:57.000 --> 20:03.000 So the definition of it, as it's a string, is given to this, to this algorithm. 20:03.000 --> 20:10.000 And then the algorithm generates the behavior that we can return to the executor and the executor executed. 20:10.000 --> 20:11.000 Got it. 20:11.000 --> 20:12.000 Thank you. 20:12.000 --> 20:15.000 So there's no compilation, but there's generation of the tree. 20:15.000 --> 20:16.000 I don't know. 20:16.000 --> 20:18.000 Maybe this was kind of misleading. 20:18.000 --> 20:19.000 No, no. 20:19.000 --> 20:20.000 I think I just misunderstood. 20:20.000 --> 20:22.000 I'd add a quick check as well. 20:22.000 --> 20:28.000 I think the answer is yes, but I wanted to check, which is, can you call the custom builders from other nodes? 20:28.000 --> 20:30.000 Yes. 20:30.000 --> 20:35.000 So you know, it's complying with the rust to action interface. 20:35.000 --> 20:39.000 And you see there's a field saying build handler. 20:39.000 --> 20:48.000 So if I understand the question correctly, you can just specify this build handler by your different way, by your other node. 20:48.000 --> 20:52.000 And give it to the executor and the executor loads it dynamically, as you'd like. 20:52.000 --> 20:53.000 Yeah. 20:53.000 --> 20:54.000 Thank you. 20:58.000 --> 21:02.000 All right, so if we have no more question, we do have. 21:02.000 --> 21:03.000 Okay. 21:03.000 --> 21:05.000 Thank you for the talk. 21:05.000 --> 21:09.000 I have a question regarding the durability. 21:09.000 --> 21:17.000 If we use a custom node, and we messed up the build of the node, 21:17.000 --> 21:21.000 how do we find what is the problem? 21:21.000 --> 21:27.000 Can we see the generated XML or a way to deliver it? 21:27.000 --> 21:28.000 Okay. 21:28.000 --> 21:29.000 Well, yeah. 21:29.000 --> 21:37.000 So I mean, if there's a problem with your implementation and it throws like a runtime error, and this is, 21:37.000 --> 21:44.000 I mean, obviously you have the source code in your project, but the model of it is generated. 21:44.000 --> 21:55.000 And you can see the XML representation of the model, but I'm not really sure if I understand the question correctly, 21:55.000 --> 22:01.000 because if it's a runtime error, then you have to debug it on your own, obviously. 22:01.000 --> 22:10.000 I cannot help you with this, but if you don't know how the node is actually expecting inputs or something, 22:10.000 --> 22:13.000 then there's a compatibility issue. 22:13.000 --> 22:16.000 This is what these node models are for. 22:16.000 --> 22:28.000 So they tell the behavior tree what inputs it allows, which arguments, and it's doing this building. 22:28.000 --> 22:32.000 It's also checking for compatibility issues. 22:32.000 --> 22:40.000 When you like insert nodes here in this builder API, it validates that it's compatible with one another. 22:40.000 --> 22:44.000 And it's the right plugin, which is loaded. 22:44.000 --> 22:50.000 So you don't have to do all this linking and this configuration management by your own. 22:50.000 --> 22:55.000 All right. 22:55.000 --> 22:59.000 Let's have a little bit longer break with about eight minutes until the next stop. 22:59.000 --> 23:09.000 Thank you so much.