This blog is a written presentation of the talk I gave at ROS Meetup Delhi, India in April 2023.
I was inspired by Tangram Vision’s work on Rust for Robotics and the blogs, and talks by Brandon Minor, CEO.
So, I will start with asking a simple question.
As a Roboticist, my preferable coding language is C++ as this is the language that runs on the actual robots. Generally, Python-based ROS nodes suffer performance issues on hardware. Python and in some cases, Matlab are generally used for research and proof of concept purposes.
C++ is well suited for embedded platforms as it can get “Close to the metal”.
But C++ comes with its own set of problems:
Rust is an open Source Systems Programming Language created by Mozilla Research Project.
Fun Fact: It was voted as the most loved language by StackOverflow four years in a row. It is developed with an emphasis on Safety, Speed, and Concurrency. It provides High-Level Abstraction and Low-Level control over system resources.
Rust is based on two principles:
But why is there a Rust buzz? It will be quite evident soon how all the problems with C++ are magically taken care of by Rust.
Before looking at Rust code, it is important to understand the basic Rust Terminologies.
In the below code, I have defined a dangling pointer. A dangling pointer is a pointer that doesn’t point to a valid object.
I declare a mutable raw pointer
p as a null pointer in line 2 and I assign
p to a new pointer
Then I free the memory allocated to
p using the C free function.
This leaves q as a dangling pointer since it still points to the memory location that was just freed.
Finally, I attempt to print the value at
q, which leads to undefined behavior since the memory location it points to has been freed.
Now, I know nobody would deliberately write such code but dangling pointers can exist under certain unknown circumstances in a fairly large codebase. When I try to compile the code in Rust, the compiler throws an error and will not build the code at all. This will never happen in C++ and mostly, I would have to attach the debugger and spend hours finding the crash.
That is how amazing is the safety provided by Rust.
Let’s take a turn and see how ROS and Rust interact with each other.
Below are the Rust-based ROS packages available to begin development of Robotics code in Rust.
Links are available in the Resources section.
The wait is over and now I will show you an example of Rust in Robotics.
I have a simple multi-threading model in ROS 2 shown below. By default, the ROS 2 C++ callbacks are sequential and not parallel. In this example, I have set up two string callbacks in ROS 2 both printing the incoming string from the topic. Furthermore, I have added a 2 seconds wait in callback1. This causes the callback2 to be blocked by callback1 and the rate at which callback should be executed is not maintained as evidenced by the execution of the code. From the timestamp, it is seen that the code execution was; callback1 (1682419871.593) -> wait for 2 seconds -> print the incoming string ‘hey’ (1682419873.593) when callback2’s ‘oy’ message was blocked. Now imagine a robot’s camera image callback is blocked by another callback and the robot is operating on an older camera image for object detection. The robot will not have the latest information about the obstacles. Robots operating on delayed and old information can lead to horrible safety-related incidents and collisions.
ROS 2 does provide a solution that is MultiThreadedExecuter with callback groups. But it comes with the overhead of deadlocks, manual memory management, race condition, deciding the number of threads, and scheduling execution. All of them being standard problems with C++. Fortunately, there is Rust to the rescue.
The next code is an example of the same use case written in Rust where I have created two threads that can run each callback parallelly without blocking each other. From the below result, it is evident from the timestamp that callback1 is published after every 2 seconds while callback2 keeps receiving messages. This example is for a very basic use case of publishing strings. Generally, I would want to extract data from the callbacks and use it elsewhere in the codebase.
Now, this is where things start getting complicated as there will be a case where one thread would be updating the data while another wants to access it simultaneously. In Rust, I can create an
Arc that allows multiple ownership while ensuring thread safety. Overall, in the first line of the example above, a thread-safe shared string is created that can be accessed and modified by multiple threads simultaneously without causing data races. In the second line, I create a clone of data1 since we need to pass it to another thread inside the callback. In this way, I can easily access the data while printing as well as inside the thread without manually managing and figuring out when to lock and unlock the mutex.
Here are some companies already using Rust.
As for Robotics, Rust is ready to be used for UI/Frontend, Webhooks, and systems programming.
While RUST is safe, efficient, and user-friendly, it is heavily under development, especially for ROS Also, C++ has been around for decades whereas Rust has been around only for about 10 years. In my opinion, Rust is very promising as witnessed in the blog but it will take time for Rust to become mainstream for Robotics.
If you liked the article, please buy me a ☕️ coffee