Rust no_std for production robots: what we lost and what we gained
When building production robots, every detail counts. From the materials used in the mechanical components to the software that controls them, each aspect must be carefully considered to ensure optimal performance and reliability. In our latest project, we chose to use Rust as the primary programming language, but with a twist: we opted for the no_std environment. This decision was not taken lightly, as it meant giving up some of the comforts and conveniences provided by the standard library. In this article, we will explore what we lost and what we gained by choosing the no_std path.
One of the most significant losses was the absence of panic strings. In a standard Rust environment, when a panic occurs, the error message is displayed, providing valuable information for debugging purposes. However, in a no_std environment, this luxury is not available. Instead, we had to rely on custom error handling mechanisms, which, although more tedious to implement, provided more control over the system's behavior. Another loss was the inability to use certain data structures, such as HashMap, unless we implemented them ourselves or shipped a custom version. This added complexity to our codebase, but also allowed us to tailor the implementation to our specific needs.
Opting out of libc and std lib
By choosing no_std, we also opted out of using libc and the standard library. This decision had far-reaching consequences. On the one hand, we lost access to a wide range of functions and data structures that are commonly used in Rust programming. On the other hand, we gained a high degree of control over the system's behavior and performance. The alloc module, which provides dynamic memory allocation, became opt-in, allowing us to carefully manage memory usage and avoid potential pitfalls.
The benefits of this approach became apparent when we considered the performance and security implications. With a custom implementation of the necessary functions and data structures, we were able to achieve deterministic latency, which is critical in real-time systems such as production robots. Additionally, our kernel size was reduced to approximately 120 KB, making it more efficient and less prone to errors. Perhaps most importantly, by avoiding the use of glibc, we eliminated the risk of CVEs (Common Vulnerabilities and Exposures) associated with this library.
Custom implementation and testing
To overcome the limitations imposed by no_std, we had to implement custom versions of the necessary functions and data structures. This process was time-consuming and required careful testing to ensure correctness and reliability. We used a combination of unit tests, integration tests, and simulation-based testing to validate our implementation and identify potential issues. The testing process was iterative, with each iteration refining our implementation and bringing us closer to our performance and reliability goals.
fn custom_hash_map<K, V>() -> CustomHashMap<K, V> {
// Custom implementation of HashMap
}The custom implementation of HashMap, for example, required careful consideration of the trade-offs between memory usage, lookup time, and insertion time. By tailoring the implementation to our specific use case, we were able to achieve optimal performance and minimize memory usage.
Performance and security implications
The decision to use no_std had significant implications for the performance and security of our system. With a custom implementation of the necessary functions and data structures, we were able to achieve deterministic latency and reduce the risk of errors. The smaller kernel size also made it easier to maintain and update the system, reducing the risk of introducing new vulnerabilities.
- Deterministic latency: critical in real-time systems such as production robots
- Reduced kernel size: approximately 120 KB, making it more efficient and less prone to errors
- Eliminated risk of CVEs associated with glibc
In conclusion, our experience with using Rust no_std for production robots has been positive, despite the challenges and limitations imposed by this environment. By carefully implementing custom functions and data structures, we were able to achieve optimal performance, reliability, and security.
Bottom line
The use of Rust no_std for production robots offers a unique set of benefits, including deterministic latency, reduced kernel size, and eliminated risk of CVEs associated with glibc. While it requires careful implementation and testing, the results can be well worth the effort, leading to more efficient, reliable, and secure systems.
QubitPage Editorial
Editorial — QubitPage SRL