[ros-users] [Discourse.ros.org] [Next Generation ROS] Design By Contract

Geoffrey Biggs ros.discourse at gmail.com
Wed Aug 9 01:09:19 UTC 2017



I have often put some thought into providing such an idea over the years, but I've never come close to putting in enough effort to actually do it. :slight_smile: I'd love to see such work move forward so I'm happy to see someone putting in the work!

Having said that, I think that it would be a major effort to achieve for ROS 1, but quite doable for ROS 2 because many of the things you want to establish as the "contract" for a data-flow-based software component can be implemented using the DDS QoS policies. It would need some thought put into how and where to specify the contracts and then how to translate that into QoS settings. On from that things get more complicated. DDS provides facilities to be informed when a QoS policy has been violated, but how to respond to that is probably going to be very application specific. (In classical Eiffel-style DbC, the contracts are essentially asserts that raise exceptions when violated at run time.)

[quote="fkromer, post:1, topic:2405"]
* if node is topic publisher (postcondition checks)
  * (guaranteed topic publish rate)
[/quote]

This can be done using the DDS `DEADLINE` QoS policy.

[quote="fkromer, post:1, topic:2405"]
  * guaranteed topic message type values
[/quote]

This could be done in the message IDL and an assert in the topic publish API. There has been occasional talk in ROS 2 discussions of adding allowable ranges to the IDL, but I don't think it's gone anywhere. However if it is going to be node specific it would probably be better done purely in the topic publish API, with a node declaring when it sets up the publisher what allowable ranges the message can hold. This would be fine for run-time checks, but it would make it a lot harder to check contracts statically than having them in the IDL. I think that the need for a unique message definition for every node would be too prohibitive to put contracts in there, though. Other than perhaps things that everyone agrees are sensible for that particular message.

[quote="fkromer, post:1, topic:2405"]
* if node is topic subscriber (precondition checks)
  * (expected topic reception rate)
[/quote]

This can also be done using the DDS `DEADLINE` QoS policy.

[quote="fkromer, post:1, topic:2405"]
  * expected topic message type values
[/quote]

Same comment as for the publishing side above.

[quote="fkromer, post:1, topic:2405"]
* if node is service server
  * (guaranteed service response time) (postcondition check)
[/quote]

`DEADLINE` QoS policy again.

[quote="fkromer, post:1, topic:2405"]
  * expected service request message type values (precondition check)
  * guaranteed service response message type values (postcondition check)
[/quote]

Now we're getting close to Eiffel-style DbC. These can be done now by putting asserts in your service callback, but what you really want is a way to notify the caller that there was a problem fulfilling the service call due to a contract violation. This would probably require extending the way services are implemented.

The RPC over DDS specification, which was finally published in April this year and hopefully the OSRF's DDS vendors will rapidly support, does not provide any QoS policies specific to services (only ways to specify existing QoS policies on a per-interface level). Therefore ROS2 would need to decide how to deal with contract violations themselves.

[quote="fkromer, post:1, topic:2405"]
* if node is service client
  * guaranteed service request message type values (postcondition check)
  * expected service response message type values (precondition check)
[/quote]

Same as above.

[quote="fkromer, post:1, topic:2405"]
* if node is action server
  * (guaranteed feedback transmission delay after goal request has been received) (postcondition check)
  * (guaranteed result transmission delay after goal request has been received) (postcondition check)
  * expected action goal message type values (precondition check)
  * guaranteed action feedback message type values (postcondition check)
  * guaranteed action result message type values (postcondition check)
* if node is action client
  * (expected feedback message delay after goal request has been transmitted) (precondition check)
  * (expected goal message delay after goal request has been transmitted) (precondition check)
  * guaranteed action goal message type values (postcondition check)
  * expected action feedback message type values (precondition check)
  * expected action result message type values (precondition check)
[/quote]

Again same as above.

So the things that you are requesting are doable in ROS 2 using a combination of the `DEADLINE` QoS policy and adding some features to the API for specifying pre- and postconditions. I do not think it would be a huge level of work, but there would need to be a focus on how the API will work to make it clear what is happening, and making sure that the performance is both minimal and zero-able (i.e. all checks can be turned off).

[quote="facontidavide, post:2, topic:2405"]
The more I learn modern C++, more I realize that the best contracts can be usually implemented using strong types.
[/quote]

Design by contract encompasses more than can be specified using strong types. It includes the behaviour of the function called. Even in a language where functions strictly have no side effect, there are parts of this that cannot be expressed by ensuring the types are correct, unless every function takes and returns types unique to that function that exactly define its input and output spaces. For functions that do have side effects (such as class methods) and situations where the side effects are the whole point (many service calls and many data-flow-based nodes), types will not cover everything you want to check.

[quote="facontidavide, post:2, topic:2405"]
I am in favour of using something similar to boost::units in ROS messages, some kind of metadata attached to the topic itself that is NOT transmitted every time and is immutable.
[/quote]

I think that this would be a useful feature. Adding units to data is a powerful way to catch a common class of potentially fatal errors, and it can be done in a way that has minimal impact on performance.





---
[Visit Topic](https://discourse.ros.org/t/design-by-contract/2405/3) or reply to this email to respond.




More information about the ros-users mailing list