Below is a list of companies, research institutes and foundations that adopted, supported or contributed to Zenoh. If you cannot find your logo, please post a message on the Zenoh’s discord server and we’ll add it right away.
diff --git a/adopters/index.html b/adopters/index.html index 1799991c..5eb35b64 100644 --- a/adopters/index.html +++ b/adopters/index.html @@ -1,5 +1,5 @@
A very partial list of Zenoh adopters and supporters
Below is a list of companies, research institutes and foundations that adopted, supported or contributed to Zenoh. If you cannot find your logo, please post a message on the Zenoh’s discord server and we’ll add it right away.
1 January 2020
First of all we would like to take a moment to wish all of you a 2020 filled with joy, health, peace and success.
This year marks a very important landmark for us. After having kicked-off the Eclipse Edge Native working group, last December, we are bringing zenoh to Eclipse and are starting to work a Rust rewrite of the zenoh router. +
1 January 2020
First of all we would like to take a moment to wish all of you a 2020 filled with joy, health, peace and success.
This year marks a very important landmark for us. After having kicked-off the Eclipse Edge Native working group, last December, we are bringing zenoh to Eclipse and are starting to work a Rust rewrite of the zenoh router. As part for the rewrite we have just about to complete a review of the zenoh protocol and will be updating the specification accordingly in the weeks to come.
30 June 2020 -- Paris.
In our last blog we had announced a rewrite of zenoh in Rust. The wrote the first version of zenoh in OCaml, a super-neat ML-derived functional programming language. OCaml allowed us to experiment very quickly and have good performances. Yet, one of the major feedback we were receiving from the community was that few people knew this programming language and this was limiting contributions. Beside, we had the desire to make zenoh even faster and smaller. One obvious choice would have been to write the new version in C/C++, yet something we did not want to loose were the safety properties we enjoyed with OCaml. Additionally, if we had to leave our beloved OCaml, we did not want to completely give away high level abstractions. We also wanted to avoid languages that had a heavy runtime and a garbage collector. We had already looked at Rust back in 2015, but at the point we did not feel it was the right choice for us. The improvements introduced in the programming language with the 2018 edition along with the introduction at a language level async make Rust a perfect choice for zenoh.
As we were going for a rewrite, we took this opportunity to leverage the experience, user feedback and lesson learned from the first version of zenoh. We did some improvements at the protocol level as well as some reorganisation. The resulting stack is represented in the diagram below.
As you can see from this diagram, now zenoh is organised as two layers.
Implements a networking layer capable of running above a Data Link, Network or Transport Layer. zenoh-net provides primitives for efficient pub/sub and distributed queries. It supports fragmentation and ordered reliable delivery and provides a pluggable scouting abstraction for discovery. zenoh-net defines and builds upon a session protocol that provides abstractions for ordered best effort and reliable channels with unlimited MTU that are independent of the underlying layer.
zenoh-net supports peer-to-peer and routed communication as well as push and pull pub/sub along.
The zenoh layer provides a high level API for pub/sub and distributed queries. It deals with data representation encoding and transcoding and provides an implementation of geo-distributed storage and distributed computed values. zenoh natively supports a series of data encoding, such as JSON, Properties, Relational, Raw, etc., along with transcoding across supported formats. It also defines a canonical query syntax based on URIs syntax. +
30 June 2020 -- Paris.
In our last blog we had announced a rewrite of zenoh in Rust. The wrote the first version of zenoh in OCaml, a super-neat ML-derived functional programming language. OCaml allowed us to experiment very quickly and have good performances. Yet, one of the major feedback we were receiving from the community was that few people knew this programming language and this was limiting contributions. Beside, we had the desire to make zenoh even faster and smaller. One obvious choice would have been to write the new version in C/C++, yet something we did not want to loose were the safety properties we enjoyed with OCaml. Additionally, if we had to leave our beloved OCaml, we did not want to completely give away high level abstractions. We also wanted to avoid languages that had a heavy runtime and a garbage collector. We had already looked at Rust back in 2015, but at the point we did not feel it was the right choice for us. The improvements introduced in the programming language with the 2018 edition along with the introduction at a language level async make Rust a perfect choice for zenoh.
As we were going for a rewrite, we took this opportunity to leverage the experience, user feedback and lesson learned from the first version of zenoh. We did some improvements at the protocol level as well as some reorganisation. The resulting stack is represented in the diagram below.
As you can see from this diagram, now zenoh is organised as two layers.
Implements a networking layer capable of running above a Data Link, Network or Transport Layer. zenoh-net provides primitives for efficient pub/sub and distributed queries. It supports fragmentation and ordered reliable delivery and provides a pluggable scouting abstraction for discovery. zenoh-net defines and builds upon a session protocol that provides abstractions for ordered best effort and reliable channels with unlimited MTU that are independent of the underlying layer.
zenoh-net supports peer-to-peer and routed communication as well as push and pull pub/sub along.
The zenoh layer provides a high level API for pub/sub and distributed queries. It deals with data representation encoding and transcoding and provides an implementation of geo-distributed storage and distributed computed values. zenoh natively supports a series of data encoding, such as JSON, Properties, Relational, Raw, etc., along with transcoding across supported formats. It also defines a canonical query syntax based on URIs syntax. The zenoh layer also provides a storage back-end plug-in API to ease the integration of third parties storage technologies. Currently supported storage back-ends are Memory, MySQL, MariaDB, PostgreSQL, SQLite and InfluxDB By default the Geo-Distributed Storages work under eventual consistency. Stronger consistency can be implemented by user leveraging Quorum Mechanism
The upcoming version of zenoh comes with a few improvements and some new features. Specifically, you will see:
Major performance improvements. These performance improvements are a consequence of both using Rust and of some changes on packet scheduling.
Protocols improvements. We have reorganised the protocol to make it even simpler to port zenoh to different kinds of networks while exploiting network specific features. We have also added the ability to carry user provided attachments with both data and queries. These attachments can be used by zenoh applications to either extend the protocol, or for instance add user level security.
Generalised Peer-to-Peer and Client Communication. In the upcoming version of zenoh an application can decide at runtime to behave like a peer or a client. Peers route information between themselves and can also route on behalf of clients – in other terms peers can behave like routers. Peers-to-peer communication is supported for arbitrary connectivity graphs and supports cliques as a special case.
Closure-based Discovery. Discovery in zenoh is supported by the scouting protocol, in order to ease the deployment of system that wants to leverage a clique connectivity, for cases in which multicast is not avaiable, or desirable, we support now a clousure-based discovery. In other terms starting from a single peer, we can discover its closure, or in other terms the peers that can be reached directly or indirectly from this starting point.
Region-Based Routing The new version of zenoh supports region-based routing. As depicted in the diagram below, this really means two things, (1) routing information required to build and maintain our routing tables scales with the size of the region, and (2) each region can decide wether to route over an arbitrary connectivity graph of assume a clique. This approach to routing will greatly improve scalability and performance by allowing to use the most appropriate routing technique within a region. diff --git a/blog/2020-10-08-aithusa/index.html b/blog/2020-10-08-aithusa/index.html index 978a1ca4..e116763f 100644 --- a/blog/2020-10-08-aithusa/index.html +++ b/blog/2020-10-08-aithusa/index.html @@ -1,6 +1,6 @@
8 October 2020 -- Paris.
We have been waiting this very moment for several months. Months of patient +
8 October 2020 -- Paris.
We have been waiting this very moment for several months. Months of patient dedication, months of hard and creative work. Months in which each and every member of the zenoh team has made his and her best to give our little dragon all it needed to succed in the complicated world of Internet Scale Protocols.
Today, at about 11.00 Paris Time Zenoh Aithusa Hatched Out!
Aithusa is the code-name for the first release of our Rust-based zenoh infrastructure, diff --git a/blog/2021-03-23-discovery/index.html b/blog/2021-03-23-discovery/index.html index d417b223..fe8c0f6f 100644 --- a/blog/2021-03-23-discovery/index.html +++ b/blog/2021-03-23-discovery/index.html @@ -1,6 +1,6 @@
23 March 2021 -- Paris.
The amount of discovery traffic generated by ROS2 is a problem that has +
23 March 2021 -- Paris.
The amount of discovery traffic generated by ROS2 is a problem that has received an increasing attention in the community. The discovery overhead issue becomes extremely severe when running over wireless technologies, such as WiFi, and in particular in combination with more complex robots, robot diff --git a/blog/2021-04-28-ros2-integration/index.html b/blog/2021-04-28-ros2-integration/index.html index 166ed7ed..8b6790d3 100644 --- a/blog/2021-04-28-ros2-integration/index.html +++ b/blog/2021-04-28-ros2-integration/index.html @@ -1,6 +1,6 @@
28 April 2021 -- Paris.
In our previous blog we demonstrated how the zenoh bridge for DDS allows to (1) bridge DDS communications through zenoh, and (2) reduce by up to 99.97% the discovery traffic between the nodes.
The previous blog was focusing on demonstrating the advantages of using zenoh as the mean for ROS2-to-ROS2 communication over wireless technologies. In this blog, we’ll go one step further and will demonstrate how you can easily write native zenoh applications —meaning that has no dependencies on ROS2 — and seamlessly interact with ROS2 applications. Finally, we will show how you can extend your communication to Internet scale, allowing to cover all the typical cases for Robot-to-anything (R2X) communication.
The zenoh/DDS bridge is leveraging CycloneDDS to discover the DDS readers and writers declared by the ROS2 application. For each discovered DDS entity the bridge creates a mirror DDS-entity — in other terms it creates a reader when discovering a writer and vice-versa. Additionally, the bridge maps the DDS topics read and written by the discovered DDS entities on zenoh resources and performs the proper declarations.
As example, let’s consider the turtlesim package used in the ROS2 Tutorial:
/rosout
. As per ROS2 conventions this maps to a DDS Writer on topic rt/rosout
. Consequently, the zenoh/DDS bridge declares a DDS Reader on the same topic with matching QoS. This DDS Reader will receive all publications from the turtlesim on this topic and re-publish those on a zenoh resource having /rt/rosout
as a key./turtle1/cmd_vel
that maps as a DDS Reader on rt/turtle1/cmd_vel
. The zenoh/DDS bridge declares a DDS Writer on the same topic, and a zenoh subscriber for the key /rt/turtle1/cmd_vel
. This zenoh subscriber will receive all publications with this key from any zenoh application and re-publish those to DDS on topic rt/turtle1/cmd_vel
to be received by the ROS2 subscriber on /turtle1/cmd_vel
.You may have noticed that the zenoh/DDS bridge doesn’t need to be compiled with any ROS2 message definition. That is because the bridge doesn’t need to interpret the ROS2 messages. It just forwards the data payload as is. As a consequence a zenoh application that needs to publish/subscribe to ROS2 will need to encode/decode those messages.
For those who are curious about the details, the ROS2 messages are encoded for DDS following the OMG DDSI-RTPS specification (see §10) in CDR format (see §9.3). But fortunately, you usually don’t need to implement a CDR encoder/decoder, since there are libraries for this in most languages +
28 April 2021 -- Paris.
In our previous blog we demonstrated how the zenoh bridge for DDS allows to (1) bridge DDS communications through zenoh, and (2) reduce by up to 99.97% the discovery traffic between the nodes.
The previous blog was focusing on demonstrating the advantages of using zenoh as the mean for ROS2-to-ROS2 communication over wireless technologies. In this blog, we’ll go one step further and will demonstrate how you can easily write native zenoh applications —meaning that has no dependencies on ROS2 — and seamlessly interact with ROS2 applications. Finally, we will show how you can extend your communication to Internet scale, allowing to cover all the typical cases for Robot-to-anything (R2X) communication.
The zenoh/DDS bridge is leveraging CycloneDDS to discover the DDS readers and writers declared by the ROS2 application. For each discovered DDS entity the bridge creates a mirror DDS-entity — in other terms it creates a reader when discovering a writer and vice-versa. Additionally, the bridge maps the DDS topics read and written by the discovered DDS entities on zenoh resources and performs the proper declarations.
As example, let’s consider the turtlesim package used in the ROS2 Tutorial:
/rosout
. As per ROS2 conventions this maps to a DDS Writer on topic rt/rosout
. Consequently, the zenoh/DDS bridge declares a DDS Reader on the same topic with matching QoS. This DDS Reader will receive all publications from the turtlesim on this topic and re-publish those on a zenoh resource having /rt/rosout
as a key./turtle1/cmd_vel
that maps as a DDS Reader on rt/turtle1/cmd_vel
. The zenoh/DDS bridge declares a DDS Writer on the same topic, and a zenoh subscriber for the key /rt/turtle1/cmd_vel
. This zenoh subscriber will receive all publications with this key from any zenoh application and re-publish those to DDS on topic rt/turtle1/cmd_vel
to be received by the ROS2 subscriber on /turtle1/cmd_vel
.You may have noticed that the zenoh/DDS bridge doesn’t need to be compiled with any ROS2 message definition. That is because the bridge doesn’t need to interpret the ROS2 messages. It just forwards the data payload as is. As a consequence a zenoh application that needs to publish/subscribe to ROS2 will need to encode/decode those messages.
For those who are curious about the details, the ROS2 messages are encoded for DDS following the OMG DDSI-RTPS specification (see §10) in CDR format (see §9.3). But fortunately, you usually don’t need to implement a CDR encoder/decoder, since there are libraries for this in most languages (Python, Rust, C#, Javascript…)
OK, let’s do a zenoh “teleop” app in Python for a start. It will publish Twist messages to the turtlesim’s /turtle1/cmd_vel
Subscriber and subscribe to Log messages published by the turtlesim’s /rosout
Publisher.
All that you need is:
pip install eclipse-zenoh pycdr
Note: currently you need to build the zenoh/DDS bridge yourself. But we will provide pre-built binaries for main platforms soon. Once built, the zenoh-bridge-dds
executable is generated in the zenoh-plugin-dds/target/release
subdirectory.
Now:
Start the turtlesim on host 1:
ros2 run turtlesim turtlesim_node
Start the zenoh/DDS bridge on host 1:
RUST_LOG=info zenoh-bridge-dds -m peer
The RUST_LOG=info
environment variable is to activate the logs at “info” level. You should see such logs proving that the bridge discovered the turtlesim’s Publishers and Subscribers:
[2021-04-13T13:11:58Z INFO zenoh_bridge_dds] New route:
diff --git a/blog/2021-06-14-zenoh-reliability/index.html b/blog/2021-06-14-zenoh-reliability/index.html
index b6830a0b..eec7871b 100644
--- a/blog/2021-06-14-zenoh-reliability/index.html
+++ b/blog/2021-06-14-zenoh-reliability/index.html
@@ -1,6 +1,6 @@
Zenoh Reliability, Scalability and Congestion Control · Zenoh - pub/sub, geo distributed storage, query
- Zenoh Reliability, Scalability and Congestion Control
14 June 2021 -- Paris.
Providing many to many reliable communications over a wide area network is challenging. This may even be an understatement, as theoretically, even simple point to point reliable communication over asynchronous channels requires either infinite amount of memory or giving up progress… but guess what, many real systems can’t afford neither of those restrictions. Thus, trade-offs need to be made regarding reliability for the system to work, scale smoothly and have sufficiently strong guarantees. System’s heterogeneity, with respect to network capabilities and nodes resources, has important consequences and requires proper strategies to avoid a slow node to impact the entire system.
zenoh provides different mechanisms to deal with these challenges. It allows users to clearly define the reliability semantics they need without bringing extra complexity.
Reliability and Scalability
Hop to hop reliability
The zenoh protocol is composed of two layers:
- The session protocol establishes a bidirectional 1 to 1 session between two zenoh runtimes (client, peer or router). Each session comes by default with a best-effort channel and a reliable channel. The session protocol among other things, takes care of performing automatic batching for maximising network usage and fragmentation to give the illusion of an unlimited MTU.
- The routing protocol leverages the session protocol to propagate interests and route data from many producers to many consumers.
Consequently the reliability state maintained by each application is independent of the number of data producers and data subscribers hosted by the application.
As zenoh offers routed communication, a single data producer connected to a zenoh router can reliably send data to as many data consumers as needed while maintaining a single reliability state.
This strategy is highly scalable and offers a good level of reliability. No data samples are lost while the infrastructure is stable. If a zenoh router fails, the zenoh infrastructure will automatically adapt to the new topology (details will be provided in a future post). During the failover, data samples may be lost. As soon as the infrastructure re-stabilized, data is distributed reliably again.
A Stronger Reliability
With the default hop to hop reliability strategy data samples can be lost during topology changes. This is the price to pay for a good scalability but can be problematic for some systems. zenoh is designed to offer two stronger reliability strategies which are very briefly described here.
End to End Reliability
A reliability channel is established between each data producer/data consumer pair. This avoids sample loss even during topology changes but is less scalable and induces higher resource consumption on producers and consumers.
First Router to Last Router Reliability
A reliability channel is established between the first zenoh router and the last zenoh router of each data route. This allows to relax pressure on producers and consumers by deporting this pressure to nearest infrastructure components.
Reliability and Flow Control
In a reliable system, there is a constant trade-off between reliability, progress and memory consumption. Indeed a slow or non-responsive data consumer will force matching data producers to either:
- Store more and more messages thus consuming more and more memory.
- Drop messages thus losing reliability.
- Block new writes thus losing progress.
It’s often the receiving application that can decide if messages losses are acceptable or not. When only parts of the subscribers need reliable communications it is more efficient to only propagate data reliably to those subscribers than to all of them. So it seems appropriate to let the receiving application decide if communication should be reliable or not. On the other hand, giving full control to subscribers has downsides. Receiving applications can force data producers to maintain a reliability state while those producers may be resource constrained and not willing to do so. And a single misbehaving receiver application may block or slow down the whole system.
A lot of technologies made opinionated choices to address this problem and applied predefined semantics on which users have very limited control. Those semantics may be good for some use cases and bad for others and you would often need a mix of different behaviors in the same system.
Part of the issue is a confusion between reliability and congestion control. zenoh clearly separates control over message resending, memory usage (buffering) and message dropping.
- Receivers control reliability by selecting a resending strategy. They declare if they need missing messages to be resent or not.
- Senders and intermediate infrastructure components (zenoh routers) individually decide how much memory they are willing to dedicate to reliability. This allows constrained devices to dedicate few resources to reliability while resourceful intermediate routers can dedicate more memory lowering the probabilities of congestion situations.
- Senders control congestion by selecting a message dropping strategy. For each sample they decide what should be done in case of congestion (the reliability queue is full) – drop the sample or block the publication. The congestion control strategy is propagated from the sender to all involved infrastructure components and applied along the entire routing path.
Show me Some Code
Here are examples of how reliability and congestion control can be configured using the zenoh Python API.
Configuring Reliability
zenoh reliability is configured on the subscriber side as shown below:
session = zenoh.net.open({})
+
+Zenoh Reliability, Scalability and Congestion Control
14 June 2021 -- Paris.
Providing many to many reliable communications over a wide area network is challenging. This may even be an understatement, as theoretically, even simple point to point reliable communication over asynchronous channels requires either infinite amount of memory or giving up progress… but guess what, many real systems can’t afford neither of those restrictions. Thus, trade-offs need to be made regarding reliability for the system to work, scale smoothly and have sufficiently strong guarantees. System’s heterogeneity, with respect to network capabilities and nodes resources, has important consequences and requires proper strategies to avoid a slow node to impact the entire system.
zenoh provides different mechanisms to deal with these challenges. It allows users to clearly define the reliability semantics they need without bringing extra complexity.
Reliability and Scalability
Hop to hop reliability
The zenoh protocol is composed of two layers:
- The session protocol establishes a bidirectional 1 to 1 session between two zenoh runtimes (client, peer or router). Each session comes by default with a best-effort channel and a reliable channel. The session protocol among other things, takes care of performing automatic batching for maximising network usage and fragmentation to give the illusion of an unlimited MTU.
- The routing protocol leverages the session protocol to propagate interests and route data from many producers to many consumers.
Consequently the reliability state maintained by each application is independent of the number of data producers and data subscribers hosted by the application.
As zenoh offers routed communication, a single data producer connected to a zenoh router can reliably send data to as many data consumers as needed while maintaining a single reliability state.
This strategy is highly scalable and offers a good level of reliability. No data samples are lost while the infrastructure is stable. If a zenoh router fails, the zenoh infrastructure will automatically adapt to the new topology (details will be provided in a future post). During the failover, data samples may be lost. As soon as the infrastructure re-stabilized, data is distributed reliably again.
A Stronger Reliability
With the default hop to hop reliability strategy data samples can be lost during topology changes. This is the price to pay for a good scalability but can be problematic for some systems. zenoh is designed to offer two stronger reliability strategies which are very briefly described here.
End to End Reliability
A reliability channel is established between each data producer/data consumer pair. This avoids sample loss even during topology changes but is less scalable and induces higher resource consumption on producers and consumers.
First Router to Last Router Reliability
A reliability channel is established between the first zenoh router and the last zenoh router of each data route. This allows to relax pressure on producers and consumers by deporting this pressure to nearest infrastructure components.
Reliability and Flow Control
In a reliable system, there is a constant trade-off between reliability, progress and memory consumption. Indeed a slow or non-responsive data consumer will force matching data producers to either:
- Store more and more messages thus consuming more and more memory.
- Drop messages thus losing reliability.
- Block new writes thus losing progress.
It’s often the receiving application that can decide if messages losses are acceptable or not. When only parts of the subscribers need reliable communications it is more efficient to only propagate data reliably to those subscribers than to all of them. So it seems appropriate to let the receiving application decide if communication should be reliable or not. On the other hand, giving full control to subscribers has downsides. Receiving applications can force data producers to maintain a reliability state while those producers may be resource constrained and not willing to do so. And a single misbehaving receiver application may block or slow down the whole system.
A lot of technologies made opinionated choices to address this problem and applied predefined semantics on which users have very limited control. Those semantics may be good for some use cases and bad for others and you would often need a mix of different behaviors in the same system.
Part of the issue is a confusion between reliability and congestion control. zenoh clearly separates control over message resending, memory usage (buffering) and message dropping.
- Receivers control reliability by selecting a resending strategy. They declare if they need missing messages to be resent or not.
- Senders and intermediate infrastructure components (zenoh routers) individually decide how much memory they are willing to dedicate to reliability. This allows constrained devices to dedicate few resources to reliability while resourceful intermediate routers can dedicate more memory lowering the probabilities of congestion situations.
- Senders control congestion by selecting a message dropping strategy. For each sample they decide what should be done in case of congestion (the reliability queue is full) – drop the sample or block the publication. The congestion control strategy is propagated from the sender to all involved infrastructure components and applied along the entire routing path.
Show me Some Code
Here are examples of how reliability and congestion control can be configured using the zenoh Python API.
Configuring Reliability
zenoh reliability is configured on the subscriber side as shown below:
session = zenoh.net.open({})
sub_info = SubInfo(
zenoh.net.Reliability.Reliable,
diff --git a/blog/2021-07-05-zenoh-overhead/index.html b/blog/2021-07-05-zenoh-overhead/index.html
index 51d3c17a..976795ca 100644
--- a/blog/2021-07-05-zenoh-overhead/index.html
+++ b/blog/2021-07-05-zenoh-overhead/index.html
@@ -1,6 +1,6 @@
Zenoh overhead: a story from our community · Zenoh - pub/sub, geo distributed storage, query
- Zenoh overhead: a story from our community
05 July 2021 -- Paris.
Zenoh’s webpage states that zenoh has a minimal wire overhead of 5 bytes. This is the result of careful considerations in the zenoh design: from using Variable Length Encoding (VLE), to efficient mapping of resource keys and automatic batching.
If you are intrigued about this and want to know more, rest assured that you are not alone. In fact, the minimal overhead aspect of zenoh attracted a lot of attention and curiosity in our community that led to some interesting discussions on zenoh’s Discord Server.
Given the amount of messages and information exchanged, we thought it would be a good idea to write a blog post to explain how zenoh achieves this wire efficiency. It’s easier to read a blog post than scrolling backwards many messages on Discord, isn’t it?
Minimal overhead: what is it?
Let’s start from the beginning. We said that 5 bytes are the minimal overhead in zenoh. What does that mean? It means that zenoh adds at least 5 bytes to user payload but, as you might have guessed, it may also add more if necessary. You might be wondering now in which cases zenoh offers the minimal overhead. To answer these questions we should first have a look at how zenoh serializes data on the wire.
As shown below, user payload is always carried in a zenoh data message. In turn, one or more zenoh data messages are carried within a zenoh frame message. The inner details of these messages and their corresponding weight in the 5 bytes overhead are presented in the following.
+-------+----------------+----------------+- ... -+
+
+Zenoh overhead: a story from our community
05 July 2021 -- Paris.
Zenoh’s webpage states that zenoh has a minimal wire overhead of 5 bytes. This is the result of careful considerations in the zenoh design: from using Variable Length Encoding (VLE), to efficient mapping of resource keys and automatic batching.
If you are intrigued about this and want to know more, rest assured that you are not alone. In fact, the minimal overhead aspect of zenoh attracted a lot of attention and curiosity in our community that led to some interesting discussions on zenoh’s Discord Server.
Given the amount of messages and information exchanged, we thought it would be a good idea to write a blog post to explain how zenoh achieves this wire efficiency. It’s easier to read a blog post than scrolling backwards many messages on Discord, isn’t it?
Minimal overhead: what is it?
Let’s start from the beginning. We said that 5 bytes are the minimal overhead in zenoh. What does that mean? It means that zenoh adds at least 5 bytes to user payload but, as you might have guessed, it may also add more if necessary. You might be wondering now in which cases zenoh offers the minimal overhead. To answer these questions we should first have a look at how zenoh serializes data on the wire.
As shown below, user payload is always carried in a zenoh data message. In turn, one or more zenoh data messages are carried within a zenoh frame message. The inner details of these messages and their corresponding weight in the 5 bytes overhead are presented in the following.
+-------+----------------+----------------+- ... -+
| FRAME | DATA(USER PLD) | DATA(USER PLD) | ... |
+-------+----------------+----------------+- ... -+
Zenoh data messages: carrying your data
In zenoh, users deal with keys/values where each key is a path and is associated with a value. A key looks like just a Unix file system path, such as /myhome/kitchen/temp
, and it represents a resource. For what concerns the value, it can be defined with different encodings (string, JSON, raw bytes buffer, etc.).
As a result, the data, i.e. the value, is always published to a given resource. Zenoh takes this information from the user, and it includes it in a zenoh data message as shown below.
diff --git a/blog/2021-07-13-zenoh-performance-async/index.html b/blog/2021-07-13-zenoh-performance-async/index.html
index ac56fd21..46fa63e0 100644
--- a/blog/2021-07-13-zenoh-performance-async/index.html
+++ b/blog/2021-07-13-zenoh-performance-async/index.html
@@ -1,6 +1,6 @@
Zenoh performance: a stroll in Rust async wonderland · Zenoh - pub/sub, geo distributed storage, query
- Zenoh performance: a stroll in Rust async wonderland
13 July 2021 -- Paris.
Since its very first public release, zenoh provided impressive and easily accessible performances (see here).
+
+Zenoh performance: a stroll in Rust async wonderland
13 July 2021 -- Paris.
Since its very first public release, zenoh provided impressive and easily accessible performances (see here).
But instead of resting on laurels, the zenoh team has been relentlessly working on further improving them.
As a result of this work, we are happy to announce that zenoh delivers at least twice the performances than before:
- more than 3.5M msg/s with 8 bytes payload,
- more than 45 Gb/s with 1 Megabyte payload,
- a latency as little as 35 µsec in backlogged scenarios.
The reminder of this post will take you through the journey of zenoh profiling along with the nuts and bolts of Rust async programming.
If you are unfamiliar with Rust and you are just interested in the results, you can jump directly here.
Getting ready
As we previously wrote in this blog post, zenoh is purely written in Rust and leverages the async features to achieve high performance and scalability.
Even though initial zenoh performances were already quite good, we weren’t completely happy about them. Some numbers didn’t sum up as expected and we were very puzzled about it: we knew that zenoh could deliver more. We had only to discover what was preventing us from getting there. So, during the last few months we have been relentlessly profiling zenoh and looking into its most deep and intimate internals.
The very first thing we did was to properly prepare our testing environment in such a way to get reproducible results. This is very important when profiling your code otherwise you risk to walk down the wrong path: there are plenty of external factors that may impact the performance of the code. If you are about to profile your code, we highly recommend you to follow this guide that summarizes very well how to properly setup a Linux environment and how to get consistent results out of it.
The second thing was to have a thorough read of The Rust Performance Book. If you are developing in Rust like us, we recommend you to go through it since we found it really insightful for what concerns performance tips and tricks along with profiling techniques in Rust.
Another nice reference on how to write performant code in Rust can be found here.
Finding the hotspots
We started with identifying the hotspots in zenoh by generating flame-graphs with this tool. We were confident that flame-graphs were a good way to visualize which part of the code takes most of the time in zenoh. We were wrong.
We couldn’t see any function taking a substantial amount of time to justify the performance mismatch we were observing. In addition, async was making the flame-graph quite difficult to read because of the async scheduler and future executor appearing almost everywhere in the graph. So, we changed the profiling tool and we started using perf which provided, at least for us, a more clear view on the hotspots: notably on serialization and deserialization.
We improved our serializer and deserializer implementation and the synthetic benchmarks immediately improved by roughly 100%. However, that improvement didn’t reflect in the throughput tests. Nothing had changed. We were more puzzled than before.
Heap or not to heap? Stack is the problem
Then we started looking into memory allocations. Since the beginning of zenoh, we have been very careful to avoid heap allocations in the critical path. We used Valgrind to double check if that was still the case and yes, it was: we didn’t observe unnecessary allocations nor suspicious high cache miss rates.
So, if it’s not the heap, it might be the stack. But how to see how deep the stack is? Especially when operating with async? Luckily for us, there is a very useful Rust compilation flag (available only in Rust nightly) to verify how big a data structure is and its cache alignment. It is sufficient to build zenoh (or any Rust code) with:
$ RUSTFLAGS=-Zprint-type-sizes cargo build --release
diff --git a/blog/2021-09-28-iac-experiences-from-the-trenches/index.html b/blog/2021-09-28-iac-experiences-from-the-trenches/index.html
index 08005970..f6ae7fb9 100644
--- a/blog/2021-09-28-iac-experiences-from-the-trenches/index.html
+++ b/blog/2021-09-28-iac-experiences-from-the-trenches/index.html
@@ -1,6 +1,6 @@
Indy Autonomous Challenge (IAC): Experiences from the Trenches · Zenoh - pub/sub, geo distributed storage, query
- Indy Autonomous Challenge (IAC): Experiences from the Trenches
28 September 2021 -- Paris.
The Indy Autonomous Challenge is a competition of autonomous racecars between teams of university students. Even if fully autonomous, each car needs to communicate with its team’s base station to report telemetry, status and to receive commands, such as emergency stop. The communication infrastructure between the cars and the base stations leverages CISCO Ultra-Reliable Wireless Backhaul (CURWB). As all cars share the same infrastructure, some limitations have been imposed on teams in terms of packet rates and bandwidth usage.
In this blog we present the very first lessons learnt from IAC with regard to ROS2 communication over wireless transports.
All the cars’ software is based on Autoware + ROS2 with Eclipse CycloneDDS which is the default middleware for the latest ROS2 release: Galactic Geostone.
Lesson 1: Avoid DDS traffic over constrained transport
As seen in a previous blog, the amount of discovery traffic generated by DDS in a ROS2 context with a lot of nodes/publishers/subscribers can be extremely problematic on wireless transports such as WiFi or CURWB. In these deployments, you really want to constrain the DDS traffic to be bound to wired networks or even better not to leave the host. Then, you can transparently rely on Eclipse zenoh for communication over the wireless network through the zenoh/DDS bridge.
In IAC’s race cars, ROS2 nodes are deployed on a single host – either in the car or in the base station. Thus, we can instruct CycloneDDS to only use the loopback interface by adding to the configuration file the two lines marked below (CycloneDDS < 0.10).
<CycloneDDS xmlns="https://cdds.io/config"
+
+Indy Autonomous Challenge (IAC): Experiences from the Trenches
28 September 2021 -- Paris.
The Indy Autonomous Challenge is a competition of autonomous racecars between teams of university students. Even if fully autonomous, each car needs to communicate with its team’s base station to report telemetry, status and to receive commands, such as emergency stop. The communication infrastructure between the cars and the base stations leverages CISCO Ultra-Reliable Wireless Backhaul (CURWB). As all cars share the same infrastructure, some limitations have been imposed on teams in terms of packet rates and bandwidth usage.
In this blog we present the very first lessons learnt from IAC with regard to ROS2 communication over wireless transports.
All the cars’ software is based on Autoware + ROS2 with Eclipse CycloneDDS which is the default middleware for the latest ROS2 release: Galactic Geostone.
Lesson 1: Avoid DDS traffic over constrained transport
As seen in a previous blog, the amount of discovery traffic generated by DDS in a ROS2 context with a lot of nodes/publishers/subscribers can be extremely problematic on wireless transports such as WiFi or CURWB. In these deployments, you really want to constrain the DDS traffic to be bound to wired networks or even better not to leave the host. Then, you can transparently rely on Eclipse zenoh for communication over the wireless network through the zenoh/DDS bridge.
In IAC’s race cars, ROS2 nodes are deployed on a single host – either in the car or in the base station. Thus, we can instruct CycloneDDS to only use the loopback interface by adding to the configuration file the two lines marked below (CycloneDDS < 0.10).
<CycloneDDS xmlns="https://cdds.io/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://cdds.io/config https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/etc/cyclonedds.xsd">
<Domain id="any">
diff --git a/blog/2021-10-04-zenoh-pico-guide/index.html b/blog/2021-10-04-zenoh-pico-guide/index.html
index 3d593a69..052a49c9 100644
--- a/blog/2021-10-04-zenoh-pico-guide/index.html
+++ b/blog/2021-10-04-zenoh-pico-guide/index.html
@@ -1,6 +1,6 @@
Zenoh goes embedded with zenoh-pico · Zenoh - pub/sub, geo distributed storage, query
- Zenoh goes embedded with zenoh-pico
04 October 2021 -- Paris.
In this post, we will introduce zenoh-pico, a lightweight implementation of Zenoh APIs in C, fully compatible with its Rust counterpart.
As a result of this work, we are happy to announce that we successfully deployed and tested Zenoh in Zephyr (reel_board and nucleo-f767zi) and Arduino (ESP32) compatible boards, with initial results showcasing a quite remarkable performance within the microcontrollers landscape:
- Memory footprint of only ~2.8% (nucleo-f767zi), ~9.2% (reel_board), and ~0.9% (ESP32).
- Deliver more than 5.2k msg/s with a 8 bytes payload in ESP32.
- Application-level throughput of ~9.2 Mbps (thus, saturating a 10 Mbps Ethernet link) with nucleo-f767zi.
The reminder of this post will get you started with the environment setup, library installation, and project creation for your microcontrollers.
A bit of context for zenoh-pico
Zenoh has been natively designed to introduce minimal wire overhead (check our previous blog post) and run across extremely constrained transports such as LPWAN and LowPAN, or directly over OSI Layer 2 (Data Link Layer) as well as to accommodate the resource constraints of embedded systems. However, since its very first public release, Zenoh Rust-based implementations have been focusing on providing high performance in widely used operating systems and platforms (check our previous blog post). As a side note, Arduino was supported in the very first proof-of-concept for Zenoh. But what about other constraints devices and microcontrollers?
Fear not more because zenoh-pico has come a long way to provide such support. Zenoh-pico is a lightweight implementation of Zenoh APIs in C, fully compatible with its Rust counterpart.
Internet of Things (IoT), home automation, and robotic systems appear among a set of use cases where Zenoh capabilities and features are a clear fit, paving the way for several benefits: support for push and pull communication models, geo distributed storage, and minimal wire overhead. However, most of these use cases rely on a variety of heterogeneous, low-powered, and resource constrained devices, making it a challenging environment to be supported. Just as an example, many IoT and smart home appliances being available in the market today (like smart plugs, motion sensors, door sensors, among others) are embedded with a ESP8266/ESP32 devices: the ESP32 is a dual-core 160MHz to 240MHz CPU with 320 KiB SRAM and 4MiB of built-in flash, whereas the ESP8266 is a single-core processor that runs at 80MHz with 80 KiB SRAM and 1 MiB of built-in flash. Similarly, many robotic systems are integrated with microcontrollers to control specific parts of the hardware as a complement to a more powerful device (e.g., Raspberry Pi) where all the logic is running.
But is the Rust-based implementation of Zenoh supported by microcontrollers?
+
+Zenoh goes embedded with zenoh-pico
04 October 2021 -- Paris.
In this post, we will introduce zenoh-pico, a lightweight implementation of Zenoh APIs in C, fully compatible with its Rust counterpart.
As a result of this work, we are happy to announce that we successfully deployed and tested Zenoh in Zephyr (reel_board and nucleo-f767zi) and Arduino (ESP32) compatible boards, with initial results showcasing a quite remarkable performance within the microcontrollers landscape:
- Memory footprint of only ~2.8% (nucleo-f767zi), ~9.2% (reel_board), and ~0.9% (ESP32).
- Deliver more than 5.2k msg/s with a 8 bytes payload in ESP32.
- Application-level throughput of ~9.2 Mbps (thus, saturating a 10 Mbps Ethernet link) with nucleo-f767zi.
The reminder of this post will get you started with the environment setup, library installation, and project creation for your microcontrollers.
A bit of context for zenoh-pico
Zenoh has been natively designed to introduce minimal wire overhead (check our previous blog post) and run across extremely constrained transports such as LPWAN and LowPAN, or directly over OSI Layer 2 (Data Link Layer) as well as to accommodate the resource constraints of embedded systems. However, since its very first public release, Zenoh Rust-based implementations have been focusing on providing high performance in widely used operating systems and platforms (check our previous blog post). As a side note, Arduino was supported in the very first proof-of-concept for Zenoh. But what about other constraints devices and microcontrollers?
Fear not more because zenoh-pico has come a long way to provide such support. Zenoh-pico is a lightweight implementation of Zenoh APIs in C, fully compatible with its Rust counterpart.
Internet of Things (IoT), home automation, and robotic systems appear among a set of use cases where Zenoh capabilities and features are a clear fit, paving the way for several benefits: support for push and pull communication models, geo distributed storage, and minimal wire overhead. However, most of these use cases rely on a variety of heterogeneous, low-powered, and resource constrained devices, making it a challenging environment to be supported. Just as an example, many IoT and smart home appliances being available in the market today (like smart plugs, motion sensors, door sensors, among others) are embedded with a ESP8266/ESP32 devices: the ESP32 is a dual-core 160MHz to 240MHz CPU with 320 KiB SRAM and 4MiB of built-in flash, whereas the ESP8266 is a single-core processor that runs at 80MHz with 80 KiB SRAM and 1 MiB of built-in flash. Similarly, many robotic systems are integrated with microcontrollers to control specific parts of the hardware as a complement to a more powerful device (e.g., Raspberry Pi) where all the logic is running.
But is the Rust-based implementation of Zenoh supported by microcontrollers?
Not yet, but zenoh-pico comes to rescue. Zenoh-pico is a lightweight implementation of the Zenoh protocol in C, fully compatible with its Rust counterpart. Its goal is three-fold: (i) provide a library implementation optimized for microcontrollers; (ii) provide a native C-based implementation (around 80% of embedded systems use C programming language); and (iii) keep the Rust-based implementation abstracted from the constraints imposed by microcontrollers.
Being a lightweight implementation, what is it missing?
Currently, zenoh-pico does offer all the functionalities for you to implement a Zenoh client mode in microcontrollers. The support for peer-to-peer communication is still under planning and it does not feature the same level of message scheduling of the Rust stack.
Which frameworks, platforms, or boards are currently supported?
So far, we have successfully tested zenoh-pico in Zephyr (reel_board and nucleo-f767zi boards) and Arduino (ESP32). No changes have been made in the core of zenoh-pico, requiring only the implementation of the system calls for your specific framework / platform.
Well…enough talk, let’s see how to do it!!
Step by step guide
In the following, we provide a step by step guide to build a Zenoh publisher.
Prepare your environment
In order to manage and ease the process of building and deploying into a variety of microcontrollers, we suggest that PlatformIO is used as a supporting platform. Among other things, PlatformIO provides a multi-platform and multi-architecture build system, supporting ~48 different platforms, ~26 frameworks, and ~1035 boards, without any external dependencies to the operating system.
You can check the super-quick installation instructions (as they call it) here.
Setup your project folder
Different platforms, frameworks, and boards require different project structures. But do not worry because you do not need to do it manually yourself. PlatformIO will give you a hand with that.
A typical PlatformIO project for must have the following structure:
Zephyr
project_dir
diff --git a/blog/2021-11-09-ros2-zenoh-pico/index.html b/blog/2021-11-09-ros2-zenoh-pico/index.html
index c0af3116..34fa618d 100644
--- a/blog/2021-11-09-ros2-zenoh-pico/index.html
+++ b/blog/2021-11-09-ros2-zenoh-pico/index.html
@@ -1,6 +1,6 @@
ROS 2 and microcontrollers integration via Zenoh-pico · Zenoh - pub/sub, geo distributed storage, query
- ROS 2 and microcontrollers integration via Zenoh-pico
09 November 2021 -- Paris.
In a previous blog, we showed how you can easily write native Zenoh applications and seamlessly interact with ROS 2 applications. This was exemplified by developing a native Zenoh teleoperation application to control a ROS 2 powered robot, namely a turtlebot or its simulation counterpart turtlesim, from anywhere in the world. In this blog, we will go one step further by trying to make it cool and fun – together with a bit of nostalgia.
As a result of this work, we are unveiling the capabilities of Zenoh to bridge the gap between ROS 2 and microcontroller environments by providing a lightweight and unified data-centric protocol coupled with its own implementation Zenoh middleware solution and DDS bridge. In other words, ROS 2 users can extend their application towards microcontrollers via Zenoh.
The reminder of this blog will recap the main concepts of our previous blog and guide you towards its extension to use Zenoh-pico and microcontrollers.
Rewinding time
In the scenario described below, the Zenoh teleoperation application discovers the Zenoh/DDS bridge via its scouting protocol that leverages UDP multicast - when available. Once discovered, a TCP connection is established between the app and the bridge. But the Zenoh application can also be configured to directly establish a TCP connection with a known host, without relying on scouting protocol. Thus it can connect directly to the bridge (if reachable) or to 1 or more Zenoh routers that will route the Zenoh communications between the application and the bridge.
At this stage, the user can make use of its keyboard to control the robot (just like in a game).
It seems like the 80s…can we fast forward in time?
Remember that it is a proof-of-concept demo to show the capabilities of Zenoh. Still, we have to agree that the turtlesim and teleoperation via keyboard is too much 80s.
+
+ROS 2 and microcontrollers integration via Zenoh-pico
09 November 2021 -- Paris.
In a previous blog, we showed how you can easily write native Zenoh applications and seamlessly interact with ROS 2 applications. This was exemplified by developing a native Zenoh teleoperation application to control a ROS 2 powered robot, namely a turtlebot or its simulation counterpart turtlesim, from anywhere in the world. In this blog, we will go one step further by trying to make it cool and fun – together with a bit of nostalgia.
As a result of this work, we are unveiling the capabilities of Zenoh to bridge the gap between ROS 2 and microcontroller environments by providing a lightweight and unified data-centric protocol coupled with its own implementation Zenoh middleware solution and DDS bridge. In other words, ROS 2 users can extend their application towards microcontrollers via Zenoh.
The reminder of this blog will recap the main concepts of our previous blog and guide you towards its extension to use Zenoh-pico and microcontrollers.
Rewinding time
In the scenario described below, the Zenoh teleoperation application discovers the Zenoh/DDS bridge via its scouting protocol that leverages UDP multicast - when available. Once discovered, a TCP connection is established between the app and the bridge. But the Zenoh application can also be configured to directly establish a TCP connection with a known host, without relying on scouting protocol. Thus it can connect directly to the bridge (if reachable) or to 1 or more Zenoh routers that will route the Zenoh communications between the application and the bridge.
At this stage, the user can make use of its keyboard to control the robot (just like in a game).
It seems like the 80s…can we fast forward in time?
Remember that it is a proof-of-concept demo to show the capabilities of Zenoh. Still, we have to agree that the turtlesim and teleoperation via keyboard is too much 80s.
So, how to forward this demo in time…
- in the 90s, we had an explosion of game controllers
- in the 00s, we had an explosion of pads, joysticks, racing wheels, and other gaming interfaces.
- in the 10s, we had an explosion of motion controller
- in the 20s, we are having an explosion of immersive experiences.
At this point, you might have guessed already that we are going for an immersive experience.
Zenoh-powered Immersive Controller
As announced in a previous blog, Zenoh-pico is available as a lightweight implementation of Zenoh APIs in C, fully compatible with its Rust counterpart. It mainly targets embedded systems and, in particular, microcontrollers.
Thanks to the combination of Zenoh-pico, microcontrollers and a couple of sensors, we extended our initial teleoperation controller and embedded it anywhere. In doing so, we are going to show you how to control a turtlebot and its simulation counterpart turtlesim by means of hand gestures. For example, the small size of the microcontroller and sensors make them almost imperceptible to the eye and touch, and can be easily embedded in a regular glove for a truly immersive experience.
Wouldn’t it be cool and fun to have the power in your hand? How many of you have ever tried to use the force as a Jedi or telekinetic powers as an X-Men?
Here is a short video of our Zenoh-powered Immersive Controller prototype being used to control the turtlebot.
Show me how to do it myself
All you need is an ESP32, a MPU-6050 accelerometer and gyroscope module and, of course, zenoh-pico. Note that, even if you decide to use other microcontrollers or sensors, all Zenoh-related code and components remain unchanged.
By providing a set of abstractions for pub/sub, geo distributed storage, query, and evals, Zenoh really simplifies the development of distributed applications. In other words, Zenoh internally handles all the inherent complexities of a distributed system and data distribution, keeping your life as a developer much simpler.
1. Pinout and Connections
The first step is to wire the ESP32 with the MPU-6050 sensor. Here are some guidelines:
MPU-6050 ESP32 VCC 3V3 GND GND SCL GPIO22 SDA GPIO21
2. Code
You can find the steps on how to set up your project in our previous blog. Then, you just need this little snippet of code to make it work. Note that, Zenoh-related code is only around 12 lines, while the remaining code is related to reading the values of the sensor, pre-processing them, and creating the Twist message.
#include <Arduino.h>
#include <WiFi.h>
#include <Wire.h>
diff --git a/blog/2022-02-08-dragonbot/index.html b/blog/2022-02-08-dragonbot/index.html
index cd169b4b..b70707b8 100644
--- a/blog/2022-02-08-dragonbot/index.html
+++ b/blog/2022-02-08-dragonbot/index.html
@@ -1,6 +1,6 @@
DragonBotOne Egg Hatching with Zenoh and Zenoh-Pico · Zenoh - pub/sub, geo distributed storage, query
- DragonBotOne Egg Hatching with Zenoh and Zenoh-Pico
08 February 2022 -- Paris.
In previous blogs (1)(2), we showed how you can easily develop native Zenoh applications and seamlessly integrate them with ROS2 applications by using Zenoh bridge for DDS. In particular, this was successfully exemplified by using a TurtleBot, a well-known, low-cost, personal robot kit with open-source software and hardware.
In this blog, we go one step further to show how you can bring Zenoh down to the TurtleBot’s microcontroller and control it from a different geographic location via a Zenoh infrastructure. By following a native Zenoh approach, you can rely on better decentralization concepts where no translation semantics are required.
Such approach allows the same technology to be used across all components from your application, from the microcontrollers to the cloud robotic platform, as well as bringing peer-to-peer capabilities to the microcontroller. To showcase it, we started working on the first demonstration of a TurtleBot look-a-like, fully Zenoh-powered personal robot that we will call from now on DragonBotOne.
Note that, although ROS2 is not used in this example, we still rely on ROS2 data type definitions as a way to leverage robot abstractions and to ease any migration towards Zenoh. As a consequence, leveraging the Zenoh-to-ROS2 connectivity any ROS2 application, anywhere on the Zenoh network, could interact with the robot.
Check out the final result!!!
The remainder of this blog will take you through the journey towards the hatching of our DragonBotOne egg.
Checking behind the scenes
DragonBotOne is brought to life under the wings of Zenoh. Namely, both Zenoh and Zenoh-Pico implementation are on its genesis:
- Zenoh as a powerful and yet low overhead data-centric solution to deal with data in motion, data at rest and computations across the cloud-to-things continuum.
- Zenoh-Pico as the enabler to integrate Zenoh functionalities in embedded systems and microcontrollers natively in C.
DragonBotOne: OpenCR with WiFi connectivity
OpenCR consists of an open-source control module developed for ROS embedded systems. Given its completely open-source hardware and software and the fact it is widely used in several robotic applications, it quickly becomes our preferred choice for the development of DragonBotOne.
Still, we had to move some rocks along the way:
- No networking interfaces: OpenCR is able to work with both versions of ROS. With ROS1, OpenCR relies on ROS Serial over one of its serial ports as a protocol for wrapping standard ROS serialized messages and multiplexing multiple topics and services. With ROS2, it runs the DynamixelSDK protocol between a full fledged ROS2 subscriber and the board itself by leveraging one of its serial ports. As such, it is usually coupled with a RaspberryPi that acts as a proxy for all the network-based communications. However, DragonBotOne is designed to comprise a single microcontroller that interfaces with the different sensors and actuators. As such, OpenCR was enhanced with a WiFi module.
- We added support into Zenoh-Pico: Although Zenoh-Pico was already supporting the Arduino framework, every platform and board have their own specificities that might require additional porting of the system and network syscalls. Such a fact becomes a bit tricker due to the lack of a network interface, thus no native support for the networking aspects.
- Single thread: Despite single-thread applications are a baseline requirement for Zenoh-Pico, it has mostly targeted multi-thread applications, where the main, read, and lease tasks run in separate threads. DragonBotOne paved the way to show the world how Zenoh-Pico can also fit single-thread applications. No modifications were made to the core code of Zenoh-Pico showing how it was already ready for such a paradigm.
Finally, DragonBotOne made it all the way to hatch.
All source-code and step-by-step guides can be found in our GitHub repositories.
Remote Controller: ESP32 with a MPU-6050 accelerometer and gyroscope module
Borning in a time where immersive experiences are becoming the mainstream, it is only natural if the controlling interfaces of DragonBotOne also follow such a paradigm. Thus, you can not only control DragonBotOne with a keyboard or a joypad but also by means of hand gestures.
For the development of this remote controller, we used an ESP32 with a MPU-6050 accelerometer and gyroscope module. By tilting the controller, you can make DragonBotOne to move forward and backward as well as to turn left and right. Moreover, you can control the velocity according to the inclination of the remote controller.
For additional implementation details, check our previous blog.
Conclusion
The simplicity and efficiency of Zenoh allied to the lightweightness of Zenoh-Pico is paving the way for a complete ecosystem in the whole cloud-to-things continuum, without impacting its high-performance or set of features and capabilities.
Summarizing the main takeaways:
- It enhances the set of capabilities and features supported on extremely constrained devices, such as microcontrollers.
- It expands communication in such devices towards low-powered link technologies that can be used as backup links, traffic separation, etc.
- It expands the landscape for how robotic systems and their applications are designed:
- powerful nodes that centralize the communication between the network and the microcontroller can be stripped from the robots, paving the way to cheaper DIY robots.
- each component can be completely independent and act on its own in a fully decentralized design.
- fine-grained control over the data and how it is distributed and consumed within the system.
Nevertheless, Zenoh is completely interoperable with already existing solutions that rely on ROS2+DDS. It is up to you to decide how high will our dragon fly or how deep will it swim.
We will provide all the support you need either in GitHub or Gitter.
–CG
+
+DragonBotOne Egg Hatching with Zenoh and Zenoh-Pico
08 February 2022 -- Paris.
In previous blogs (1)(2), we showed how you can easily develop native Zenoh applications and seamlessly integrate them with ROS2 applications by using Zenoh bridge for DDS. In particular, this was successfully exemplified by using a TurtleBot, a well-known, low-cost, personal robot kit with open-source software and hardware.
In this blog, we go one step further to show how you can bring Zenoh down to the TurtleBot’s microcontroller and control it from a different geographic location via a Zenoh infrastructure. By following a native Zenoh approach, you can rely on better decentralization concepts where no translation semantics are required.
Such approach allows the same technology to be used across all components from your application, from the microcontrollers to the cloud robotic platform, as well as bringing peer-to-peer capabilities to the microcontroller. To showcase it, we started working on the first demonstration of a TurtleBot look-a-like, fully Zenoh-powered personal robot that we will call from now on DragonBotOne.
Note that, although ROS2 is not used in this example, we still rely on ROS2 data type definitions as a way to leverage robot abstractions and to ease any migration towards Zenoh. As a consequence, leveraging the Zenoh-to-ROS2 connectivity any ROS2 application, anywhere on the Zenoh network, could interact with the robot.
Check out the final result!!!
The remainder of this blog will take you through the journey towards the hatching of our DragonBotOne egg.
Checking behind the scenes
DragonBotOne is brought to life under the wings of Zenoh. Namely, both Zenoh and Zenoh-Pico implementation are on its genesis:
- Zenoh as a powerful and yet low overhead data-centric solution to deal with data in motion, data at rest and computations across the cloud-to-things continuum.
- Zenoh-Pico as the enabler to integrate Zenoh functionalities in embedded systems and microcontrollers natively in C.
DragonBotOne: OpenCR with WiFi connectivity
OpenCR consists of an open-source control module developed for ROS embedded systems. Given its completely open-source hardware and software and the fact it is widely used in several robotic applications, it quickly becomes our preferred choice for the development of DragonBotOne.
Still, we had to move some rocks along the way:
- No networking interfaces: OpenCR is able to work with both versions of ROS. With ROS1, OpenCR relies on ROS Serial over one of its serial ports as a protocol for wrapping standard ROS serialized messages and multiplexing multiple topics and services. With ROS2, it runs the DynamixelSDK protocol between a full fledged ROS2 subscriber and the board itself by leveraging one of its serial ports. As such, it is usually coupled with a RaspberryPi that acts as a proxy for all the network-based communications. However, DragonBotOne is designed to comprise a single microcontroller that interfaces with the different sensors and actuators. As such, OpenCR was enhanced with a WiFi module.
- We added support into Zenoh-Pico: Although Zenoh-Pico was already supporting the Arduino framework, every platform and board have their own specificities that might require additional porting of the system and network syscalls. Such a fact becomes a bit tricker due to the lack of a network interface, thus no native support for the networking aspects.
- Single thread: Despite single-thread applications are a baseline requirement for Zenoh-Pico, it has mostly targeted multi-thread applications, where the main, read, and lease tasks run in separate threads. DragonBotOne paved the way to show the world how Zenoh-Pico can also fit single-thread applications. No modifications were made to the core code of Zenoh-Pico showing how it was already ready for such a paradigm.
Finally, DragonBotOne made it all the way to hatch.
All source-code and step-by-step guides can be found in our GitHub repositories.
Remote Controller: ESP32 with a MPU-6050 accelerometer and gyroscope module
Borning in a time where immersive experiences are becoming the mainstream, it is only natural if the controlling interfaces of DragonBotOne also follow such a paradigm. Thus, you can not only control DragonBotOne with a keyboard or a joypad but also by means of hand gestures.
For the development of this remote controller, we used an ESP32 with a MPU-6050 accelerometer and gyroscope module. By tilting the controller, you can make DragonBotOne to move forward and backward as well as to turn left and right. Moreover, you can control the velocity according to the inclination of the remote controller.
For additional implementation details, check our previous blog.
Conclusion
The simplicity and efficiency of Zenoh allied to the lightweightness of Zenoh-Pico is paving the way for a complete ecosystem in the whole cloud-to-things continuum, without impacting its high-performance or set of features and capabilities.
Summarizing the main takeaways:
- It enhances the set of capabilities and features supported on extremely constrained devices, such as microcontrollers.
- It expands communication in such devices towards low-powered link technologies that can be used as backup links, traffic separation, etc.
- It expands the landscape for how robotic systems and their applications are designed:
- powerful nodes that centralize the communication between the network and the microcontroller can be stripped from the robots, paving the way to cheaper DIY robots.
- each component can be completely independent and act on its own in a fully decentralized design.
- fine-grained control over the data and how it is distributed and consumed within the system.
Nevertheless, Zenoh is completely interoperable with already existing solutions that rely on ROS2+DDS. It is up to you to decide how high will our dragon fly or how deep will it swim.
We will provide all the support you need either in GitHub or Gitter.
Additional Notes:
PlatformIO is a great tool when it comes to working with embedded development. Since OpenCR was not listed as one of the supported boards in PlatformIO, we decided to do it ourselves and share it with the community.
- https://github.com/cguimaraes/platform-ststm32/tree/opencr-support
- Apply the changes in this branch as a patch in your
$PLATFORMIO_DIR/platforms/ststm32
directory. - If you do not have this directory then you can opt by cloning the full repository instead.
- Since you are manually installing the packages, you need to manually create the PlatformIO package manager files. To do so, create the following file
.piopm
in $PLATFORMIO_DIR/platforms/ststm32
directory with the following content:
{"type": "platform", "name": "ststm32", "version": "15.2.0", "spec": {"owner": "platformio", "id": 8020, "name": "ststm32", "requirements": null, "url": null}
- https://github.com/cguimaraes/framework-arduinoststm32-opencr
- Clone the following repo as
$PLATFORMIO_DIR/packages/framework-arduinoststm32-opencr
- Since you are manually installing the packages, you need to manually create the PlatformIO package manager files. To do so, create the following file
.piopm
in $PLATFORMIO_DIR/packages/framework-arduinoststm32-opencr
directory with the following content:
{"type": "tool", "name": "framework-arduinoststm32-opencr", "version": "1.4.18", "spec": {"owner": "platformio", "id": 8080, "name": "framework-arduinoststm32-opencr", "requirements": null, "url": null}}
- You are now ready to create your OpenCR project using
platformio init -b opencr
Now you can easily build and upload your own applications into OpenCR boards, but we would love them to be Zenoh-powered 😜