Replies: 5 comments 5 replies
-
I'm not sure if I know what I'm talking about, but would introducing a concept like reference-counting or worker pools be useful? Specifically in the context of tasks/functions that can run concurrently, but have limited slots. E.g. A robot has 3 arms that can do some arm related task In those cases the system could wait for all the tasks to be done (how would this be described?), or move on to the next step as each task is done (ala the I understand that the current system is sufficient to describe such a scenario (by listing the appropriate properties and mutating that property to help with reference-counting), but this seems like a common enough occurrence that it might be useful to add a block-type just for it? |
Beta Was this translation helpful? Give feedback.
-
I found a couple of resources that look like they'd be relevant? It's not exactly event-graphs governing stateful activities, but state machines are pretty close (even if they just model the system's state as opposed to the state of individual activities.)
The rest of my notes here will be a little bit more tentative, since they're just initial thoughts and I'm not too familiar with this domain. I was reading the post again, and was wondering if you were thinking of microservice architectures when you mentioned "event-driven architecture" (EDA)? If that's the case, then the event-graph devised so far could be interpreted as a series of stateful microservices, connected by events. In which case the following posts might be useful: When I was reading those resources, I realized that events in the microservice architecture encapsulate state (that is: an event producer ensures that everything that a prospective consumer needs to process the event is captured in the event.) Doing it via the events is an alternative that could be better than having consumers query the state of a producer, and producers directly mutating the state of a consumer, I think (there'd be less back and forth, albeit at the cost of increased event message size?) |
Beta Was this translation helpful? Give feedback.
-
I'm just leaving notes here but, it might be worth exploring execution and deadlock prevention in the system. Given the type of DSL we are building and the fact that realistic robot deployments will execute slower than OS processes and we likely know the total amount of resources being spent there are numerous algorithms we could apply before hand to ensure that the system does not go into a deadlock. |
Beta Was this translation helpful? Give feedback.
-
How is the progress of this project? |
Beta Was this translation helpful? Give feedback.
-
Any progress on the project? I would love to hear/help if needed. |
Beta Was this translation helpful? Give feedback.
-
With the introduction of open-rmf/rmf_task#39 which followed this discussion, RMF allows users to compose tasks that can be nested sequences of activities. This added a great deal of customizability to RMF's task system, but we recognize that real world needs will not always fit into this narrow task description structure.
While the last revision of the task system was a big step forward, it was never meant to be the final design. Its limitations were known at the time that it was designed, and those limitations were strategically chosen to allow us to cover the most broadly critical needs in the most reasonable amount of time.
This discussion will try to flesh out a design for the next revision of RMF's task system. My hope is to design a task framework that's general enough that we will not need another major revision after this (but feature additions and implementation improvements are always expected). Specifically, I'd like to address these requirements which were intentionally excluded from that last revision:
I'll start with defining some of the elements that I think would be useful for an event graph framework. The following picture was exported from this Figma project:
Additionally we'll want a way to encapsulate these graphs for the sake of reusability, hierarchy (nesting event graphs inside of event graphs), and clean design. We'll refer to an encapsulated event graph as an "Activity", borrowing terminology from the UML standard. Since we want to be able to nest Activities inside of Activities, an Activity can declare the Triggers, Mutators, Queries, Properties, and Events that it exposes to any parent Activity that wants to use it, much like a public API.
Here is example of what a Delivery Activity Diagram might look like. In this diagram, the pick up and drop off behaviors will be retried up to 3 times each if they fail for some reason.
Here is an example of what a multi-robot "Vacuum and then Mop" activity could look like. Additionally it has queries to decide to cancel everything if a deadline is reached.
Building on the previous example, here is an example of a task that runs a list of sub-tasks simultaneously using a
for_each
block. Thefor_each
block manages multiple instances of a single event graph simultaneously and takes care of synchronizing its inner event graph instances with the parent graph.Note that I've embedded comments in all of the examples. I won't repeat the content of the comments here, so I recommend reading through those inside Figma itself for a deeper understanding of the ideas.
These examples should not be taken as a finalized design, but rather as the starting point for a design discussion. I believe there will be many many details to flesh out over the coming months, and these drawings are just meant to establish a base line and reference point for discussion.
Besides discussing the ideas that I've laid out so far, here's what I would recommend for next steps:
1. Decide the data types that are supported for messages
For the data types, I would like to take inspiration from Rust and support the following types:
List<T>
: Homogeneous collection of data with unnamed elementsOption<T>
: Specialized variant that can containSome(T)
orNone
Result<T, E>
: Specialized variant that can containOk(T)
orErr(E)
. Recommended output for afinished
event.Property<T>
: Reference to some Property of type TMobile
is a trait for objects that can be commanded to move, thenMobileAgent: Mobile
is a resource type declaration for a resource with theMobile
trait.2. Determine what block types should be supported (and how to support custom third-party blocks)
In the examples that I've provided I've defined these block types:
start
) to parent event graphsless
,equal
, andgreater
branch.continue
until the limit is reached, then emitsbreak
.if_match
: Triggersthen
if every input matches their specified patterns. The message forthen
can use data from the patterns in its data mapping. If any input does not match its pattern,else
will be triggered. The message forelse
can only use the raw input types.for_each
: Takes in aList<T>
trigger, queries, and a event graph frame. For eachT
in the list runs its inner event graph by sendingT
to the inner event graph's trigger block.3. Serialization format for all of the above
We'll need a way to serialize all the event graph data so that it can be transmitted and saved to disc.
While JSON isn't exactly my favorite serialization format, it does have the benefit of extremely widespread support across the web and virtually all programming languages. It also allows us to use
json-schema
to describe and validate the structure of the serialization.4. GUI for drawing the event graphs
For this concept to be useful, a user-friendly GUI is critical. The best possible solution for this would be one that we could use in both a web browser and in the "traffic editor" tool, which would imply implementing it in Rust, which can compile to WASM.
However, I've had a difficult time finding Rust tools/frameworks to help with drawing graphs. In general the Rust ecosystem is still somewhat nascent when it comes to GUI development. Meanwhile there are many tools in the JavaScript ecosystem suitable for drawing graphs. To prevent requirement this from being a blocker for too long we could consider implementing a first version of the event graph drawer in JavaScript using an existing framework while we have a parallel effort to implement a final version in Rust, most likely using Bevy.With some guidance from the Bevy community, I've learned about egui_node_graph which looks like it may be suitable for our initial needs. We should try out that library as a first step, and maybe iterate on it if it has any gaps that we can reasonably fill in.
5. Implementation of event graph execution
Since RMF is migrating to Rust for the sake of code quality and robustness, we'll need to implement the event graph execution framework in Rust. I expect this is going to be the most challenging undertaking and will require its own deeper technical discussion.
6. Modeling of event graphs for task planners
In order for the task bidding system to work, fleet adapters need to be able to reason about tasks based on models. Since event graphs may involve run time variables that cannot be predicted by a model, we may need a way to embed hints inside of the event graphs to indicate the likely paths. For example, adding some decoration to the graph to indicate which branch is likely to be chosen at a split or how many times an iterator is likely to repeat.
Other topics for discussion
Artwork and UI design
I am not an artist, so it would be great to get feedback and suggestions on the UI elements in the example drawings. Feedback and suggestions may include completely redesigning everything to better fit the 21st century.
Terminology / Vocabulary / Soundness
If there are better words to use to describe any of the concepts that I'm using, please do share. Also please bring up any important concepts or requirements that I may be overlooking.
Also if anyone knows of relevant literature from graph theory and/or event-driven architecture research, please let us know so we can get the most out of existing research in the field.
Beta Was this translation helpful? Give feedback.
All reactions