Modules purpose in transportation industry.
In today’s engineering world, the concept of modularization has many advantages. You have more freedom to change things when they break, they are easier to move or modify, they are easier to transport and, most importantly, you need to know less to handle them because they don’t have the complexity that a complete system would have. This is true for both hardware and software.
But this freedom comes at a cost.
Whenever we build a new module, we need to document and inform the components that talk with this new module about what its inputs and outputs are, and what kind of language it uses to communicate with the outer world.
Imagine it like a rendez-vous, where two spacecraft that have never met need to connect. Docking is possible only if the interfaces that the spacecraft expose are compatible.
In this article, you are going to see how we handle this modularization, its documentation, and its implementation from a software point of view.
The first challenge that we need to consider is documentation.
Because different teams build different components, we have to create documents that tell them how they can interact with certain components. This way, they don’t need to know how it works, they only need to know what parameters it needs and what it’s going to produce as outputs.
As you read in a previous article [1], one way of documenting could happen via Swagger but, even though Swagger is very useful to document web API and its endpoints, we need something that is more agnostic, so it can be used for different ways of communication, like message queuing.
HTTP APIs and queues are the main communication protocols that we use.
With HTTP, you can handle actions synchronously and data management on the web, like queries against a database.
Via queues, you are free to send information asynchronously between different components, so you don’t need to wait for their response.
Consider if you needed to log the information observed by a position indicator that measures the height of the elevator every 100ms.
The best way to handle this scenario would be by being able to send this data whenever you could. Then, the only thing that the software that retrieves data has to do is to send that information to an address, and then it can forget about it.
Since each software component is separate from the others, you will have to create an interface specific for each.
In the example above, there are events (like the indicator that detects a change in the height) that come from different applications located in different boards that send data to an Event Collector application located in a Control Board.
How do you document what the Event Collector accepts as input?
To solve this documentation challenge, we use interfaces written in YAML. YAML is a language, like JSON, that has a dictionary structure (key, value pair). One big advantage of YAML over JSON is being able to create anchors, useful to create more complex object definitions. This is the documentation of the IF-A.
In the "types" section, we document the type that the events can contain.
In the "messages" section, we define the structure of a message. In the example here, it says that there is an object EventMessageType that contains the name of the sender (like Position Indicator Board) and an array of bytes that contains the information.
It’s not recommended to use an int or a float for the data because the IF-A purpose is to accept all the possible events, even from other boards.
Even though now we are only sending a height inside the "data", we want the possibility to accept other information of different types from other boards, like dates or error messages. Because this information can vary – a lot – we also need to be sure to add other details inside the data object that help us decode the meaning of the single data.
After documentation, the remaining thing to do is to implement the interfaces.
A possible way to do that is to convert the YAML into a proto message [2] and then implement the message in both the sender (that will populate the object thanks to the structure given by the proto) and the receiver (so it will be able to read it).
Like the YAML, choosing protobuf messages has the advantage that they are technology agnostic, so we don’t need to write them in different ways depending on the language and they are ready to use.
This will be the protobuf implementation, present in both the Event Collector and the Position Indicator Software.
Even though the modularization of components comes with an upfront cost of defining standards and protocols, the benefits are well worth the effort.
In this way, engineers don’t need to work on a monolithic system, but can focus on only those components they need to change. The only thing they need to do is respect contracts between modules.
What we get in the end is hardware that is upgradable and software that is updatable. The only thing we need to do is to dock another compatible piece without the worry of potentially compromising the entire structure.
Find out more about Stefano on his LinkedIn page: https://www.linkedin.com/in/imsn/