Keys in msg

Most of the DDS vendors support the idea of a primary key in their message structures. Have we discussed enabling that from the ROS msg format? What are the issues here? A “key” keyword seems fairly straightforward.

1 Like

We’ve discussed it before, but it’s largely seen as overlapping in functionality with topic namespaces.

If you have a use case that is made possible with keys, then that would be interesting to hear about it.

However, there are quite a few little details for implementing the key field which are not straightforward to me, like:

  • each vendor has its own way of defining them
  • dealing with key fields in nested messages
  • use of them has to be made visible from all of the ROS tools

Probably other things I cannot even think of now. So unless there is a big use case which is not possible with namespaced topics, I think we’d probably not expose it.

I just found this discussion when looking for keyed topic support. At Houston Mechatronics we have been using a long ago branched version of ROS2. We are now moving to Ardent and saw that keys still aren’t there. We use keys for several different things. One of the things we have implemented is a parameter server purely in DDS which uses keyed topics so there is only one Parameter topic. The key is the name of the parameter and the value is in the other part of the topic data. This gives us great flexibility with the underlying DDS software because it handles the history. If I put my history at keeping only 1 the DDS vendor software we are using (RTI) will intelligently give me the last of each instance of the key. I only need to worry about one topic, but I can get all of the latest values and nothing else.

RTI at least has suggested using keyed topics as one of the primary ways to efficiently use DDS in numerous parts of our system. We’ve had to fork rosidl and rosidl_dds to have this DDS feature on our end. It supports the RTI version of keys in IDLs, but something similar could likely be extended for the other vendor solutions if they differ.

Using keys for this use case has one drawback. Keys are not “introspectable” without receiving the actual data. You can’t answer the question what parameters exists - without actually receiving all the parameter values first.

So if you would like to implement a user interface which should show the name of all parameters you can’t do that efficiently. Imagine some parameters contain large data but the user only wants to see the names of all parameters and then decides to get only the “small” value of one of the parameters.

We’ve been talking at length to RTI about this topic as well as some of the other vendors, and they suggested two concrete ways of using keys in ROS 2:

  • using keys implicitly under the hood to make our topics which have namespaces more efficient (sharing data readers and writers between otherwise unrelated subscriptions and publishers)
  • exposing the feature to users like yourself so you can choose to use keys in specific situations

For the first point, I think we decided that this would be very difficult to do correctly and efficiently. There are a lot of technical points as to why, but @dirk-thomas alluded to one which is that keys are not part of discovery, so something like rostopic list becomes a lot less useful.

In the end, we imagined a new feature that DDS could have which provides the performance benefits of instances which you get when using keyed fields on a topic, but without having to have the key itself in the message definition. This new kind of key is something between keys and partitions, or another imperfect analogy is partitions which create instances. This is by no means a sure thing to happen, and even if it did we’d have to wait on the DDS standard to add it and adopt it. But what I took away from it is that: keys are not ideal in all cases and we would love to use instances to reduce overhead and discovery traffic but not at the expense of requiring key fields in our messages.

For the second point, there’s no reason (as long as we’re not using keys under the hood) that we could not allow users to use keys in their own way, perhaps in the way you described. The only hesitation we had was that this is a sophisticated feature, which really ties our API to DDS much more strongly. To be clear, we don’t intend to support anything other than DDS for the foreseeable future, but we did take a lot of care to insulate our robot specific code from the communication system underneath. Perhaps this is not a realistic abstraction, but in our reference implementation of ROS 2 we’re trying to provide it. Therefore, we’re (or at least I am) wary of taking more and more complicated features into our middleware abstraction layer (rmw, see: GitHub - ros2/rmw: The ROS Middleware (rmw) Interface.). It’s not a deal breaker for key fields as a feature of ROS 2, but a consideration we have.


To disagree or correct my self, I previously said:

I can now express a use case where keys would be much more efficient, which is the case of the parameter events topic.

I’m speaking here about parameters as described for ROS 2, see: Parameter API design in ROS, where they are decentralized and owned by nodes, and there is no “special” centralized parameter server. Global parameters are realized with a node that has a conventional name (like global_parameter_server) and accepts all changes.

So, every node publishes to the “parameter event topic” anytime a parameter it owns is changed (CRUD), then a tool can subscribe to the topic and monitor all changes to the parameter system.

Now, this could either be “every node publishes to the same /parameter_events topic” or “every node publishes to its own ~/parameter_events topic”. The benefit of the first is that a tool that wants to monitor all changes only needs to subscribe to one topic (this is the same use case as rosout, many producers, one consumer of all producers). However, if you want to monitor one node, or only a few nodes, then you need to receive all the data and discard what you don’t want, which is inefficient. For that use case, the second option is better, since you can subscribe to only the nodes you want to monitor, but is very inefficient if you want to monitor them all, because you need to subscribe to N topics, where N is the number of nodes with parameters.

This is a perfect case where keys are optimal, because it gives granularity but also efficiency when doing a mass subscription. However, I think simply exposing the keyed fields feature would allow us to do this, we don’t need to put it under the hood of our namespaced topics. Also, after thinking about it a lot, and looking for common patterns in ROS 1 which would benefit from keys, I come up with very few. Some of them are important, but I don’t get the feeling that it would be a feature that could be applied all over the place to strict benefit. But that last part is just my opinion.

2 Likes

I agree changing other ROS features to use keyed topics is a much larger undertaking. The only thing we are specifically looking for is the ability to create a msg file which will cause them to be generated at this point. RTI’s implementation looks for the (@)key at the end of the line, so realistically just passing along comments from a msg file to the IDL would make this work. For example, our msg file is below:

string<=512 key #//(@)key
string<=512 value

We made an update to basically pass this along so the IDL file now includes the following:

struct Parameter_
{

string<512> key_; (@)key
string<512> value_;

}; // struct Parameter_

This obviously doesn’t solve the problems with discovery that @dirk-thomas mentioned, but it allows the global parameter setup @wjwwood mentioned, which is how we are using it.

Dragging up an old thread, but I was curious about this part of your reply @wjwwood:

Without using keys, would this (ie: individual topics vs single topic with client-side filtering) not be something that could be worked-around (almost) by using content-based subscriptions?

Are keys still missing from ROS 2?

Even without ROS explicit support, a workaround to mark key fields in .msg definition (@key in a comment per field as mentioned above) and generating the corresponding typesupport will be great. The RMW can take care of everything.

Any information would be greatly appreciated.

AFAIK, keys are not supported in ROS 2, technically RMW. There has been some discussions brought up occasionally, but i do not know any development for this feature support.

referring to @gavanderhoorn 's comment above, which is 4 years old… :old_key:

We do support content-based subscriptions, depends on RMW implementation.

https://docs.ros.org/en/rolling/Tutorials/Demos/Content-Filtering-Subscription.html

using keys would bring more high-performance efficiency for filtering process since data object is distinguished by keys individually. i am not sure about your use case or requirement, but hope this could help.

Hi @superware ,

I have been an advocate for adding keys support on ROS2, as I think it improves a lot scalability. Could you tell us a little bit about your use case?

Hello @Jaime_Martin_Losa,

My use case is like any other use case which isn’t simple/naïve in terms of the different entities participating in domain.

For example, having a generic “manager” node and several “child” nodes each with a specific implementation, running on different hardware even. Messages have a sender identifier and sometimes target identifier, these must be keys to guarantee durability and reliability.

You wrote “it improves a lot scalability” and I couldn’t agree more, the above scenario MUST use keys. The irony is that most RMWs support keys for years, so ROS2 support for keys shouldn’t be complex since it’s mainly about telling the RMW that specific fields are keys (one bit per field!).

IMHO the ideal solution should be:

@key Identifier sender
@key Identifier target
uint8 mode
...

The RMW will simply handle the distribution internally, most of them are already doing it in non-ROS2 implementations with breeze.

As a workaround, I’m thinking to change typesupport generation to indicate key fields to the RMW by inspecting the field name, for example if the name ends with “_pk” then the “field is key” bit in the RMW will be enabled and the name normalized by removing the suffix. But this might be more complicated than simply supporting the above new .msg format.

Any thoughts?

Thanks!

This might be an ignorant question, but what functionality is exactly missing in the current implementation? As durability and reliability can be configured through the QoS settings?

@JRTG i think @superware wants to apply different QoS setting to keyed topic instances without having discovery cost. I guess that is where keys come in play.

@superware correct me if i got it wrong…

There are several improvements you can get in that scenario with keys:

1.- You avoid the proliferation of topics, improving the scalability: the discovery process takes fewer messages, and the memory used to store the remote endpoints is lower.

2.- You apply the QoS per key. Imagine you have several vehicles/robots, and you are sending the position. You also want to implement durability with keep_last=1 and transient local, so you send the latest published position to the late joiners. Currently, you would need to create a position topic per robot. You could think of creating a topic like this:

Identifier robot
long x
long y

But this won’t work, as keep_last=1 would store the latest published position, but just one of an arbitrary robot. But in DDS, if you use keys, and define your topic like this:

@key Identifier robot
long x
long y

Then, a transient local durability with keep_last=1, is storing the latest published position per @key Identifier , so the middleware is working for you.

Other QoS work the same way, so you can do the same as you do with multiple topics, just implementing keys, and on top of that, grouping topics with the same meaning in a single topic, simplifying a lot your application.

There are other many advantages, for example, you could create a content filter topic to get the positions of a subset of robots, just with a filter expression.

So, in a nutshell, you get:

  • Improved scalability and performance
  • Simpler and more elegant Information model
  • New powerful features.

And as @superware mentions, this is already available in any DDS implementation.

We are thinking of offering some support for this, at least for Fast DDS RMW.

3 Likes

What @Jaime_Martin_Losa said :slight_smile:

IMHO keys are a must, any workaround (history etc) is a hack.

We are thinking of offering some support for this, at least for Fast DDS RMW.

That’s great! What will it include? Is there a roadmap?

Hi, we are now discussing different alternatives, but you can count on this very soon.

@Jaime_Martin_Losa That’s really great news for ROS. Can you please share the alternatives?

We can expose the functionality as it is, but there was some discussion about if we need to use them under the hood for specific use cases such as parameters, or try to use them implementing a mechanism in the topic name…

Finally, we will start by exposing the functionality, that we have to do anyway.