ROS Driver Common Interface Standards

Are there standards for ROS drivers that describe common interfaces for various actuators and sensors that are independent of specific manufacturers and hardware? If so, where might those be found? If not, are there plans to create or adopt such standards or models? Debating standards is never fun, but the dream of having interoperable, interchangable driver packages is very compelling.

I have seen the Hardware Robot Information Model and it seems like a great idea. Is this being actively used by the community and maintained?

RobMoSys seems even more ambitious and general, but it appears that they do not yet have models for many hardware components.

Is there any agreement about using one of these or some other guidelines when writing driver packages so they are as interchangeable and interoperable as possible?

For example, I use lots of different motor drivers and controllers, each with its own API. I would like to write a ROS driver for each one and use the same interface for all of them. A general enough interface might work with stepper motors, motors with encoders, rotary actuators, linear actuators, etc, but even if the interface just removed the differences between manufacturers for the same type of motor that would be very useful. Has anyone worked out a common interface for such motors? Or does every ROS motor driver package have its own slightly different interface? What about other actuators and sensors? Thanks!

2 Likes

For sensors, I’d say by in large the defacto standard (and some of these messages have formal REPs on them) is the sensor_msgs format: https://github.com/ros/common_msgs/tree/jade-devel/sensor_msgs/msg. For any message in here, I expect a driver for a hardware provider to conform to these are far as they are possible (which is 95% of cases).

3 Likes

We saw in the past several manufacturers “customize” those message to meet their hardware. This in some cases broke interoperability and it’s what led to the creation of HRIM listed above. HRIM follows a MDE approach and while it builds on top of the standard ROS messages (including sensor_msgs), validates inteoperability through the use of models.

A similr use case motivated the creation of HRIM. IMHO, you definitely will benefit from using a model-driven engineering approach. Unfortunately, AFAIK, HRIM project is not supported by any entity/individual any further but you’re welcome to jump in and start maintaining it.

RobMosys is indeed ambitious and will turn interesting if executed appropriately. There’s a project that connects both RobMosys and HRIM you may want to check ROS-MDD – ROSIN and reach out for more information.

3 Likes

Indeed, one of the largest advantages of ROS is the standardization of manufacturer-independent interfaces (standard messages) that it provides. For example:

  • cameras publish sensor_msgs/Image and sensor_msgs/CameraInfo
  • motors publish sensor_msgs/JointState
  • robot arms provide the control_msgs/FollowJointTrajectoryAction
  • etc.

Some more things are standardized in the form of REPs.

1 Like

My 2cents here, regarding the model part, I will highlight my colleague @ipa-nhg work : https://github.com/ipa320/ros-model.

The goal here is not to define a common standard, but to provide a nice tool to help/support modeling of ROS code. It uses static analyzer (https://github.com/git-afsantos/haros) to automatically generate the model of the code but also can be used to manually generate the model of your system / code.

Personally I use this tool to check that a driver follow some specification that I arbitrary established for another project.

2 Likes

@vmayoral I think you have a really good point about figuring out common models that build on top of the standard ROS messages. If we want to be able to swap one driver package for another, it is important to both be using the same messages and using them in the same way.

For example, if you look at these ROS motor controller driver packages it seems that most use standard ROS messages, but it does not appear that any of these packages use them in the exactly the same way so that one package cannot be swapped out for another without changes to the packages that interface with them.

ROS-MDD does look very promising, thank you for sharing that. Combining HRIM and RobMoSys does seem like a great idea if done well. I am curious about the best way to write ROS drivers until that work gets completed.

In the specific case of motor drivers, maybe the best approach is to use control_msgs for driver input and sensor_msgs for driver output and custom messages for anything else that does not quite fit until something better comes along.

5 Likes

From what I see, we have the “minimal” msg-based approach on the one end of the spectrum, and we have various model-based approaches on the other end of the spectrum.

On the one hand it appears obvious that “messages with comments” is an ad-hoc format and that something more formal would be great. On the other hand, I’m not seeing much adoption of model-based approaches.

To see why, it might be useful to look at what people are doing now, to cope with this. FWIW, the use-case that @peterpolidoro describes, where you have lots of different actuators and controllers – that’s not a common use-case in industry or research amongst ROS users. Most people I know try to standardize very quickly on a very limited set of controllers and platforms.

What’s more, most people don’t see a problem with this. They don’t standardize on motors to avoid the differences in interfaces. They do it, because it makes most sense for integration, performance and cost to do that.

This doesn’t mean the problem is irrelevant, just that most people are coping right now, and that any solution to the problem better be really use to use, very well supported with tools and implementations, and vendor-agnostic. Despite some promising starts, I would argue that both HRIM and RobMoSys are still quite far from that.

An interesting example of how this could look is CiA’s 402 series. It’s a very generic set of motor controller interfaces. Also quite widely implemented, though almost never fully.

2 Likes

Are there “best practices” for the topic/action types that a motor driver should use?

What I mean is something analogous to cameras. IMO, the best practices for a camera driver are clearly defined:

Is there something analogous for motor drivers? All I can think of is that the current motor position should probably be published as a sensor_msgs/JointState and not encoder ticks or similar. What about the input topics? Should it be a plugin for ros_control instead of a standalone node?

2 Likes

I’m always wondering whether this would standardise the ROS API of the “motor driver” or of the entities that are connected to those motors (ie: joints).

For joints we have JointState and FollowJointTrajectory to close the loop, but there is no concept of “motors” there, nor “motor drivers”.

There doesn’t necessarily need to be, but it’s important to recognise the difference I believe.

I’ve thought of this as a transparent bridge vs opaque proxy or facade difference.

I’m always wondering whether this would standardise the ROS API of the “motor driver” or of the entities that are connected to those motors (ie: joints).

Probably both, right?

I think that message definitions are not enough to define a driver interface. There are also different topic hierarchies that need to be agreed on to formulate a standard driver interface.
As @Martin_Guenther pointed out, there are accepted best practices for some device types that define a set of expected message types and topics. But these are not enforced and a node interacting with a camera cannot rely on this set of messages and their topic hierarchy.

Since ROS2, we have a unified API for ROS nodes and I think we should take this one step further and define device interfaces (as e.g. C++ abstract classes) that define all topics and message types a driver needs to provide. Any driver node would then inherit from this interface and implement it accordingly.

As an example, there could be an abstract C++ class CameraInterface that inherits from rclcpp::Node and defines methods for publishing and subscribing to the “best practice” topics and messages. Any ROS2 camera node would inherit from CameraInterface (instead of rclcpp::Node) and implement the interface.
Any node relying on a camera node could then assume a common interface.

3 Likes

True, my use-case is probably not very typical. I build robotics for scientists and each scientist has his or her own preferences for the sensors and actuators they want to use in their experiments. Very similar experimental pieces keep getting redeveloped over and over again because nothing can be shared and reused, wasting lots of development time and collaboration opportunities.

Instead of trying to convince all of the scientists to use the same sensors and actuators, which is never going to happen, I would love to have a set of really good common interfaces that make the specific choice of sensor or actuator manufacturer irrelevant. Then other experiment packages, like behavior trees or user interfaces or data processing nodes, do not care if they are exchanging messages with a Phidgets motor driver or a Zaber motor driver or whatever.

Even though other ROS users standardize on their own sensors and actuators and do not care about such flexibility, we could all benefit by being able to share and reuse ROS drivers and easily be able to swap one for another in the bigger ROS ecosystem. Instead of having something like 10 drivers with very similar, but incompatible interfaces.

I do not want to develop my own common interfaces and then try to convince the world to adopt them, that is as impossible as trying to convince everyone to use the same sensors and actuators. I am hoping that there are some common guidelines or models or something agreed upon by a group of people that would help me know what interfaces I should use with the ROS drivers I need to write.

1 Like

@christian

There are also different topic hierarchies that need to be agreed on to formulate a standard driver interface.

I do agree with you.

I think we should take this one step further and define device interfaces (as e.g. C++ abstract classes)

I believe that this is strongly required, if we actually think about the application framework. (though, not sure this is exactly in the scope of ROS)

1 Like

I’m honestly not sure that’s where we want to go with ROS. In ROS(2), the interface really is the messages, services, and actions; it’s not the C++ API. This is even more important when you think about alternate client libraries (like the Python, Javascript, Java, etc). So while defining these classes might be convenient, it doesn’t really scale across the different libraries that people want to use.

That being said, I agree that standardization at the message level would probably be valuable for more pieces of ROS. There are already REPs for a few other standardized messages, so I’ll suggest someone who is interested in this topic think about writing a (several?) REP and opening a PR against GitHub - ros-infrastructure/rep: ROS Enhancement Proposals to start the conversation there.

3 Likes

I did not meant to enforce a certain C++ API. The abstract C++ class was an example for an interface definition that could be implemented by C++ driver nodes. The same applies to the Java Interface or an abstract class in Python. May languages allow you to define some kind of interface.

I wanted to emphasise that message, action and service definitions alone do not define the “proper” interface to a node. Many nodes read/write to multiple topics. And especially for the camera the “standard” / “best practice interface” is more than just the sensor_msgs/Image. Similarly, TCP alone doesn’t allow you to browse the internet - you need to agree on multiple standard interfaces.

A C++/Python/Java/Rust driver node would need to inherit this interface and implement it. This would ensure that the same topic hierarchy and types are used. In the end, messages are just a hierarchical structure for POD low-level types. You could as well define a huge “camera” message that incorporates the message types of all topics and publish this on a single topic as the one-and-only interface. On the other hand, you could just send all the POD types on separate topics.

2 Likes

Indeed the messages alone do not define a full interface. But I agree with Chris that it’s better to focus on language independent definitions of the interfaces. And I agree that looking to the REP process is likely the best approach. There’s one example of adding semantics on top of messages in REP 138 for LaserScans and a new propsal for IMUs REP 145 And the TurtleBot’s main interfaces are defined in REP 119 And there’s also an in process for aerial vehicles REP 147 but we have many others that are less formally documented in the wiki, like move base

This is following the same sort of process as web interface specifications that you compare to where those are defined as messages and ordering and states required for communications. And specifically are completely language neutral. Then they can be implemented by a c++ webserver or a python web server and the other end doesn’t care what language the other side is implemented in just that the protocol is implemented as per the specification.

There seems to be some confusion about the interface definition using topics and messages as seen from the outside of a node, and the language-specific API that is used internally to implement the behaviour of a node.

The set of message definitions and their hierarchical structure is inherently language-neutral. All message/action/service definitions in ROS are using a language-independent description format.

What I am proposing is to define this structure in the same way as messages/etc. are define nowadays in ROS.
For example, the language-agnostic interface definition for a camera could look like:

topics:
  sensor_msgs/Image image_raw
  sensor_msgs/CameraInfo camera_info
services:
  sensor_msgs/SetCameraInfo set_camera_info
parameters:
  int fps
  string frame_id

And this interface could be translated into language-specific interfaces like C++ abstract classes, Java Interfaces, etc. in a similar way, as it is already done with messages and services now in ROS.

A driver node (in whichever language) would inherit from this generated language-specific interface (abstract class, etc.) and implement the behaviour. Of course, if you want to use that same language-agnostic interface in another language, you will have to write a generator in the same way, as you have to write a new generator for messages if you want to use them in Rust/Haskell/Lisp/etc.

The difference to the web interface is that the web uses a layered model, whereas such a driver interface would define the entire interface at once. However, both are language-neutral.

3 Likes

@christian
@clalancette
@tfoote

thanks for your insights,

what i really care is application portability which should be independent on drivers.

A driver node (in whichever language) would inherit from this generated language-specific interface (abstract class, etc.) and implement the behaviour.

so that i was thinking that this could be a way.

While this approach might be useful, it does have the significant drawback of that you end up enforcing on driver implementers not just the external interface (which you do want) but also the implementation design (which you often don’t).

You don’t want to enforce implementation design as a single-class node because that limits driver implementers from being able to compose multiple nodes to create a driver if that is best for their application. You also restrict the developer from adopting other implementation structures they may need for their application, such as to meet a safety requirement to a sufficient degree of reliability or to handle a distributed control system.

Another drawback is that it would make client libraries that much more complex to implement and maintain.

I think that your idea of an interface specification is useful (indeed, the concept is not new and is well-regarded), but for ROS what would be better than forcing everyone to generate their nodes from it would be a verification tool that confirms a node matches the interface it declares to implement. You could put this in the package.xml file and have automatic linters and record the results on https://index.ros.org.

I agree with Tully that a REP specification of interfaces is the best approach. Then we can build tools on top of that appropriate for different use cases, including a library of base classes for those who want them.

2 Likes

I agree with this. If you want to enforce such an interface on the implementation side, I don’t see another solution than forcing node creators to implement the interface.

Right. This is the de facto standard or “best practice” interface. But at the moment, there is no verification or check for standard compliance, e.g. like its done for DDS, that would allow someone who wants to build on top of camera drivers etc. to make sure that the camera post-processing node will work with any camera driver that claims to implement these standard/“best practices”.