HORUS/blog

Sep 5, 2026 · rust · robot-software · choosing-tools · robotics-middleware

Should You Write Robot Software in Rust?

Yes for the parts that must not fail mid-motion, no for the whole robot. Rust removes a class of crash, but borrowed ROS 2 packages still win.

Yes for the parts that must not fail while the robot moves, no for the whole robot — C++ and Python still own most of it. Rust removes a category of failure that a robot shows as a crash mid-motion, or a buffer read while another thread is still writing it. The verdict flips when your robot's value is borrowed drivers and planners, where ROS 2 wins and HORUS does not. The rest of this post is for a Rust developer weighing a robotics project, and for a team deciding how much of a machine to write in Rust.

You already know why you want it. You have spent an afternoon on a bug that turned out to be one thread reading a buffer while another rewrote it, and you know that class of bug simply cannot reach a running program if the compiler is checking. Then you open the robotics world and every driver is C++, every tutorial is Python, and the sensor you bought ships a package that assumes a workspace, a build tool and a middleware you did not choose.

So you look for the Rust path, and it exists, and it is thinner than you hoped. The bindings are community work. The examples stop before the part you need. Somebody says just wrap the C++ library, and you can, but now you own a wrapper as well as a robot. Meanwhile the machine on your bench does not care what language it is written in, and the deadline does not either. The question stops being philosophical and becomes practical: how much of this can you write in the language you trust, and where does insisting start costing more than it saves?

Should you write robot software in Rust?

Yes for the parts that must keep working while the machine is moving, and no for the whole robot in most projects. Rust's value on a robot is concentrated and specific: it removes an entire family of mistakes at build time, the ones where memory is read after it stopped being valid or two threads touch the same data at once. On a desktop those bugs are a crash and a restart. On a robot they are a crash while an arm is halfway through a motion, or a sensor value that was half-updated when it was read, which is worse because nothing crashes and the machine acts on a number that never existed. Against that, the ecosystem is thinner than C++, the compiler argues most while you are still deciding what the program should do, and much of a robot is not the part that must never fail. The productive framing is not Rust or not. It is which parts, and the answer is usually the parts that run continuously and touch hardware.

What does Rust actually change about robot code?

Rust changes when you find out about a whole class of mistake: at build time, on your laptop, rather than in a workshop with a machine moving. The compiler tracks who owns each piece of data and who is allowed to look at it while somebody else is writing, and it refuses to build code that breaks those rules. In practice that means no dangling pointer into a freed sensor buffer, no torn read of a pose that was being updated, no forgotten cleanup that slowly eats a board's memory over a long run. What it does not do is worth stating just as plainly. Rust will happily compile a controller with the sign flipped, and the arm will drive into the table exactly as it would in any language. Rust does not prevent two parts of a program from waiting on each other forever. It does not make the machine keep time by itself. And a Rust program can still stop dead when a value it did not expect arrives, so robot code has to decide in advance what a missing reading means.

What are the real options for the language a robot runs on?

There are seven honest options, and choosing between them is mostly a question of how much borrowed code your robot contains. You can write plain Rust with no middleware, which is right for a one-program machine. You can go through the community ROS 2 bindings and get Rust with an ecosystem attached, at the price of following work you do not control. You can accept C++ on ROS 2, which is where the drivers and planners actually live. You can write the lot in Python. You can let the languages sit side by side: HORUS is an open-source real-time robotics middleware for Rust, Python and C++ where all three share the same shared-memory ring buffers, so messages between processes on one machine are not serialised, while ROS 2 covers similar ground with a far larger ecosystem and its own officially supported bindings. Below those sit embedded Rust firmware and vendor SDKs. Read the table as a description of a team, not a scoreboard.

OptionWho it is forWhat it assumes you knowWhen to pick itWhen not to
Rust with no middlewareSolo builders and one-program robotsRust, plus your board's hardware cratesThe whole robot is one program on one machineSeveral programs must agree while the machine moves
Rust through community ROS 2 bindingsRust teams who need a handful of ROS 2 packagesRust, ROS 2 concepts, and two build systemsYou want the ecosystem and Rust for your own codeThe binding does not yet cover an interface you need
C++ on ROS 2Teams whose robot is mostly borrowed packagesC++, Linux, workspaces, launch filesThe drivers and planners are the projectNobody left wants to own C++ memory bugs
Python for the whole robotBeginners and machines with no hard rhythmPython and your sensor librariesNothing is judged by its worst momentA loop must hold rhythm while a camera runs
HORUSTeams mixing Rust, Python and C++ on one machineYour message shapes and how your loops are scheduledRust holds the loop and Python decides above itBorrowed packages are the value and would need porting
Embedded Rust firmwareBuilders whose loop must live on the boardAn embedded toolchain and your chip's support cratesThe motor rhythm matters more than the thinking aboveYour chip family has thin crate support
Vendor SDK in C++ or PythonBuyers of a complete arm or mobile baseThe vendor's API and its supported languageThe machine should do its documented jobYou want Rust everywhere and the vendor offers none

What should you pick if you already write Rust for a living?

Write your own code in Rust and borrow everything else in whatever language it already exists in. A fluent Rust developer moving into robotics has a real advantage and one predictable trap. The advantage is that the parts you write will keep running through the long, boring hours where robots actually fail — the overnight test, the demo that runs all afternoon, the deployment nobody restarts. The trap is spending the first month rewriting things that were never yours to write: a driver for a camera, a transform library, a serial protocol somebody already got right. Every hour spent porting a working C++ driver buys you nothing a customer or a supervisor will ever see. So draw the line at ownership. Code that encodes your robot's behaviour, your safety checks, your state machine — Rust, and you will be glad of it in a year. Code that reads a manufacturer's sensor — take what exists and put a boundary around it. The line moves over time, and it should move slowly.

What hardware makes Rust worth the trouble?

Rust pays off most on the two ends of the hardware range and least in the middle. At the small end, a microcontroller running a motor loop with no operating system underneath is a natural fit: there is no interpreter, the code must be right because there is nowhere to log to, and the compiler catching a memory mistake before flashing saves a genuinely painful debugging session. At the large end, a machine that runs for days without a restart benefits from a language where a slow memory leak or a rare thread race cannot quietly build up. The middle — a single-board computer running a hobby robot that gets power-cycled every ten minutes — is where Rust's advantage is smallest and its friction is most visible, because you are still changing the behaviour daily and the machine forgives a restart. One practical check before committing: look at whether your specific chip and your specific sensors have usable Rust support already, because a mature crate for your part changes this decision more than any general argument about the language.

What if the robot has to move in a month?

Use the language your team is fastest in, and give Rust the one part that would hurt most if it failed. A month is not enough time to learn a borrow checker, a robotics stack and your own hardware at once, and the first robot you build is mostly an exercise in discovering how wrong your assumptions were. Rust slows the wrong-assumption loop down, which is exactly backwards under a deadline. That said, deadlines do not excuse everything. If the demo involves a machine that can hurt somebody, or a motion that must stop on a limit, that specific piece is worth writing carefully in a language that will not surprise you, even if the rest of the system is a Python script and some hope. The mistake to avoid is the middle case: starting a full Rust rewrite two weeks before a date, ending with half a robot in each language, and demonstrating neither. Decide the boundary early and leave it alone.

What if nobody else on the team reads Rust?

Then keep the Rust surface small enough that one person leaving does not strand the robot. A language nobody else on the team can read is a maintenance risk regardless of its technical merits, and robotics teams are small enough that one person is often the entire pool of expertise. That does not mean avoiding Rust. It means being deliberate about where it lives: a well-bounded program with a clear input and output, documented at its edges, is something a C++ or Python developer can reason about even without reading the internals. A Rust codebase sprawling across the whole robot is not. There is also a decent middle route where the team learns by reading rather than writing — Rust is easier to review than to author, and a colleague who can follow the control program and spot a wrong constant is worth a lot even if they never write a line. Do the honest thing and ask whether the second person on the project could fix a bug at midnight.

What does it look like when the language choice was wrong?

Choosing wrong shows up as a project where the code compiles and the robot does not progress. In the Rust-too-early version, the compiler is a constant negotiating partner while you are still finding out that the lidar reports distances differently near glass, and every experiment costs a fight about data ownership that would have been a two-line change elsewhere. Weeks pass and the machine still does one thing. In the Rust-too-late version, the symptoms are different: the robot works, then falls over during the long test, and the crash cannot be reproduced at a desk. Somebody adds logging, the fault moves, and the team starts restarting the machine on a schedule instead of fixing it. Both are recoverable, and the second is more expensive because it arrives when there is a customer waiting. The tell for which one you are in is simple: are you fighting the compiler about code whose purpose is still uncertain, or are you fighting a machine whose purpose is settled and whose software will not stay up?

What do Rust developers try first in robotics, and why does it stall?

Most Rust developers start by looking for the Rust version of the robotics stack, and stall when they find the bindings rather than the packages. The bindings are real, and volunteers keep them going, but they trail the official releases, they cover part of the interface surface, and the package you actually wanted — the mapper, the planner, the driver for the camera on your desk — is still C++ underneath. The second attempt is usually to wrap that C++ library, which works and quietly hands you a maintenance job that grows every time the library upstream changes. The third attempt, and the one that tends to hold, is to stop trying to make everything one language. Let the borrowed parts run as they were written, run your own code as a separate Rust program, and let the two exchange messages. That structure also happens to be how robots are built anyway, which is why what middleware actually does in a robot is worth understanding before choosing a language strategy.

What do you give up by writing a robot in Rust?

You give up the largest library of working robotics code in existence, most of which is C++, and some of which you would have to reimplement or wrap. That is the big one, and everything else is smaller. You give up quick experiments: changing behaviour to see what the machine does is slower when the compiler wants the ownership story to be coherent first, and early robotics is mostly changing behaviour to see what the machine does. You give up hiring ease, because the pool of people who can read both robot code and Rust is thinner than the pool who can read C++ or Python. You give up some vendor support, since the SDK that came with your arm was almost certainly written for something else. And you take on a build story that has to work on your board and not just your laptop. None of that is fatal. It is the reason to be selective rather than total, and the reason to keep the Rust parts where the payoff is concrete.

When is ROS 2 the better choice?

ROS 2 is the better choice whenever the robot's value comes from code somebody else already wrote. A machine that must map a building and navigate to a goal is a ROS 2 project, because the mapping and navigation packages are years of work you will not reproduce alongside your day job. If the sensor you bought ships only a ROS 2 driver, that decides it: porting a driver to keep a language pure is a bad trade for almost everybody. ROS 2 also wins when the system spans several computers, when new people must read the robot on their first day, and when a lab already shares the vocabulary — and in that last case a Rust developer is better off writing one node in C++ than importing a toolchain nobody else can build. HORUS is not the answer for those projects, and choosing it there means rebuilding plumbing that could have been inherited. The comparison between the two matters less than being honest about how much borrowed code you need.

Is Rust too hard for a small robotics team?

No, and here is why: the difficulty is front-loaded and it lands on a specific skill, not on the whole job. What people describe as fighting the compiler is nearly always the first few weeks, and nearly always the same lesson — deciding which part of the program owns each piece of data, and how long a borrowed reference is allowed to live. Robot code turns out to be a friendly place to learn that, because the ownership questions map onto physical things: this program owns the motor, that one owns the camera, and a reading is a copy of something that already happened. Where a small team gets hurt is not difficulty but breadth. Trying to write the driver, the transform maths, the planner and the interface in Rust because Rust is the house language is what turns a two-month project into a year. Pick the one program where correctness matters most, write that in Rust, and let the rest be as boring as it likes.

Does Rust make a robot's timing dependable on its own?

Partly, but not the way you think. Rust removes one common source of unpredictable pauses — there is no separate process periodically stopping your program to tidy up memory — and that genuinely helps a loop that must keep to a rhythm. What Rust does not do is stop the operating system from looking away at the wrong moment, stop your program from waiting on a disk write in the middle of a control cycle, or stop a badly shaped design from putting slow work and time-critical work in the same path. A Rust program can miss its deadline exactly as easily as a C++ one if it opens a file inside the loop. Timing on a robot comes from structure and from where code runs: which work is separated from which, what happens to a message that arrived too late to be useful, and whether the fastest loop lives on hardware that has nothing else to do. Rust makes it easier to build that structure without memory bugs. Rust does not build it for you, and the same is true of choosing between Python and compiled code.

How do you decide which parts of the robot to write in Rust?

Write in Rust the parts that must keep working when nobody is watching, and borrow everything else. Sort your robot into three piles and the decision makes itself. The first pile is code that runs continuously, touches hardware, and would cause visible harm if it stopped mid-motion: the control loop, the safety checks, the watchdog. That pile is worth Rust even if the rest is not. The second pile is code you change constantly while you learn what the robot should do — mission logic, calibration, operator tools. Keep that in whatever you can edit fastest, usually Python, and do not feel bad about it. The third pile is code somebody else wrote well: drivers, planners, vision libraries. Take it as it is and put a clear boundary around it. If those piles leave you writing several programs in several languages on one machine, that is normal, and it is a question about plumbing rather than about language.

Decide by situation rather than by preference:

When two options stay close, weigh them on the five axes of the HORUS Fit Framework — ecosystem size, setup effort, team size fit, deployment target, and licence — and take the one that loses on the fewest. No scores and no numbers: five honest questions about your situation rather than about the software. If your robot keeps landing on one machine with Rust holding the loop and other languages above it, star HORUS on GitHub so it is in your list when you start building.

Found this useful? Share it:Discuss on HNShare on X