The Cost of Convenience: Ubuntu, Robotics, and the Loss of Control
Over the past several years, I have become increasingly uncomfortable with two related trends: Linux becoming more centralized and opaque in the name of convenience, and robotics researchers becoming increasingly dependent on abstractions they often do not understand underneath. Ubuntu, ROS, Python environments, and containers are all useful technologies. The concern is what happens when useful abstractions become the only layer people know.
This article is an attempt to connect those trends.
Is Ubuntu Becoming Another Windows?
Calling Ubuntu “another Windows” is obviously provocative, and taken literally it is wrong. Ubuntu is still built overwhelmingly from free and open-source software. Its source code can be inspected, modified, redistributed, and forked in ways that Windows cannot. The point of the comparison is not licensing. It is the philosophy of the operating system.
Ubuntu increasingly behaves less like one distribution participating in the Linux ecosystem and more like a vendor-controlled platform.
Traditional Linux distributions tend to preserve an explicit relationship between the user and the system. The package manager matters. The repository matters. The build recipe matters. The dependency graph matters. If I install a Debian package, I generally understand that I am asking the distribution to integrate that software into the system using Debian’s packaging model. If I use Arch, I can inspect a PKGBUILD and see, often quite directly, how upstream source turns into the files installed on my machine.
This is not merely aesthetic. It is part of the administrative contract of a Unix-like system: the user should be able to understand what changed, why it changed, and which component is responsible.
Ubuntu has increasingly moved away from that model.
Snap is the clearest example. The objection to Snap is not simply that it is slower, larger, or technically different from .deb packaging. The more important issue is that it changes the relationship between the distribution, the software publisher, and the machine owner.
Instead of software primarily being integrated into the distribution, Snap encourages applications to arrive as publisher-prepared bundles distributed through infrastructure closely associated with Canonical.
Dependencies are increasingly hidden inside the application artifact rather than expressed as visible parts of the host system.
This changes the question from:
How has this software been integrated into my system?
to:
Does the application run?
That is a very different computing culture.
The distinction becomes even more troubling when Ubuntu blurs the boundary between APT and Snap. A user typing
sudo apt install firefoxhas a reasonable expectation that they are choosing the Debian packaging model: APT metadata, .deb packages, distribution-managed dependencies, and software delivered through configured APT repositories.
Yet Ubuntu has used transitional packages and other integration mechanisms to move applications from traditional packages to Snap. From the user’s perspective, the familiar package-management interface may remain while the underlying distribution mechanism changes.
One can defend this technically. Canonical can argue that users care about obtaining an application, not about the exact format in which it arrives; maintaining multiple packaging systems is expensive, application publishers want predictable environments, and bundled dependencies can simplify support.
But that defense reveals the philosophical shift.
In a traditional Linux model, the delivery mechanism is part of the administrator’s choice. In a platform model, the user chooses the application and the vendor decides how it should be delivered, which is the philosophy of Windows, macOS, Android, and other vendor-managed operating environments.
The same tendency appears elsewhere in Ubuntu. Automatic update mechanisms, Canonical-managed services, Ubuntu Pro, extended security maintenance, entitlement checks, telemetry systems, and vendor infrastructure may each have reasonable individual justifications. Security maintenance costs money. Enterprise customers need predictable support. Automatic updates can protect users who would otherwise run vulnerable software indefinitely.
The concern is not that any one of these features is uniquely malicious. The concern is what they become collectively.
The operating system increasingly establishes an ongoing relationship between the user’s machine and the company that produced the distribution. The vendor is no longer merely producing packages and publishing releases. It increasingly participates in application delivery, update policy, support entitlement, lifecycle management, and system services after installation.
For an enterprise customer, this may be exactly what is wanted.
For a traditional Linux user, it raises a more fundamental question:
Why should the company that produced my distribution continue to exercise authority over my machine after I have installed it?
This question becomes especially important because Ubuntu’s influence extends far beyond its existing users. Hardware manufacturers support Ubuntu because it has many users. Software vendors test on Ubuntu because customers expect it. Tutorials assume Ubuntu because that is what beginners are likely to run. Research software documents Ubuntu installation because maintaining instructions for ten distributions is expensive.
Every individual decision is rational.
Together, they create a network effect.
More Ubuntu users produce more Ubuntu-specific support. More Ubuntu-specific support makes alternative distributions less convenient. The reduced convenience pushes more users toward Ubuntu. Eventually, software can claim “Linux support” while in practice meaning “we tested this on the currently supported Ubuntu LTS.”
Ubuntu therefore does not need a formal monopoly to acquire monopoly-like influence.
Users remain legally free to choose Debian, Arch, Fedora, NixOS, openSUSE, or something else. But freedom in principle may not necessarily be freedom in practice. If hardware documentation, research software, binary releases, vendor support, and third-party tutorials increasingly assume one distribution, the cost of exercising that freedom rises.
ROS is a good example. Windows and macOS may be officially supported, but in practical robotics work the surrounding ecosystem—hardware drivers, vendor SDKs, tutorials, simulation tooling, and third-party ROS packages—is often much more strongly oriented toward Linux. Debian itself is only a Tier 3 platform for ROS 2 Lyrical, while Ubuntu 26.04 is Tier 1. RHEL/Fedora provides another Linux path, but with Tier 2 support it does not occupy anything close to Ubuntu’s position within the robotics community. Thus ROS may be formally cross-platform while Ubuntu remains the de facto platform.
ROS 2 Lyrical lists the following supported platforms even for building from source:
Building from source--------------------
We support building ROS 2 from source on the following platforms:
* :doc:`Ubuntu Linux 26.04 <Installation/Alternatives/Ubuntu-Development-Setup>`* :doc:`Ubuntu Linux 26.04 (Pixi) <Installation/Alternatives/Ubuntu-Development-Setup-Pixi>`* :doc:`Windows 11 <Installation/Alternatives/Windows-Development-Setup>`* :doc:`RHEL-10/Fedora <Installation/Alternatives/RHEL-Development-Setup>`* :doc:`macOS <Installation/Alternatives/macOS-Development-Setup>`Ubuntu can become effectively mandatory without ever being declared mandatory.
The desktop itself illustrates the same tendency. Ubuntu Desktop is not a neutral collection of interchangeable components from which users are expected to construct their preferred environment. It presents a curated product: GNOME, Canonical’s modifications, a chosen set of applications, predefined integration, and an intended workflow.
Of course these components can be replaced. Linux remains Linux. Other Ubuntu flavors exist (e.g., Kubuntu), and an experienced user can rebuild large portions of the system.
But there is an important difference between something being technically replaceable and a system being designed around replaceability.
Traditional Linux culture often treats composability as a first-class property. A window manager, display manager, shell, package source, service, or desktop environment is a component. The user chooses it because the machine belongs to the user.
The increasingly product-oriented distribution instead says: this is the experience we have designed; customization occurs around that experience.
Again, this resembles the direction of mainstream proprietary operating systems far more than it resembles the older Unix ideal.
None of this makes Ubuntu equivalent to Windows. The distinction in licensing and source availability remains enormous. Nor does it mean Canonical’s engineering decisions are irrational. In many cases Canonical is solving genuine problems created by Linux itself: fragmentation, dependency incompatibility, maintenance burden, security, poor application distribution, and the difficulty of supporting arbitrary combinations of system components.
That is precisely why the trend deserves criticism.
Centralization rarely arrives by announcing itself as centralization. It arrives as a solution to inconvenience.
A centralized application store is easier for publishers. Bundled applications are easier to test. Automatic updates are easier for users. A single supported distribution is easier for hardware vendors. A preselected desktop is easier to document. A commercial support layer is easier for enterprises to purchase.
Every step can make sense locally while producing an unhealthy result globally.
The danger is not that Canonical will suddenly make Ubuntu proprietary. The danger is that Ubuntu becomes so deeply embedded as the default interpretation of “Linux” that the diversity of the wider ecosystem becomes increasingly theoretical, especially in fields such as robotics.
This is therefore a betrayal of a different Linux tradition: that the operating system should remain legible, composable, decentralized, and ultimately subordinate to the person administering the machine.
Ubuntu still gives the user freedom.
The more uncomfortable question is whether it is building an ecosystem in which fewer users understand that freedom, fewer users exercise it, and progressively more infrastructure assumes that they will not.
Roboticists Who Don’t Understand Their Computers
Robotics makes the problem especially visible: freedom is of limited practical value to users who do not understand the system they are supposedly free to control. Worse, the increasing abstraction and standardization of the ecosystem can reinforce that lack of understanding.
The easier it becomes to treat Ubuntu, ROS, containers, and package managers as opaque infrastructure, the less incentive there is to understand what happens underneath. In turn, users who lack that understanding become even more dependent on the default platform and its abstractions.
A surprising number of people working in the field do not have a strong grasp of basic computer systems.
This is not a claim that roboticists are unintelligent, nor that everyone working on robotics should be a computer scientist. Robotics naturally attracts people from mechanical engineering, electrical engineering, controls, signal processing, computer vision, and many other disciplines. That diversity is one of the field’s strengths.
The problem is that modern robotics has become, to a large extent, a computing discipline without fully accepting the educational consequences of becoming one.
In my own experience, I have encountered researchers and engineers who can work on sophisticated robotics problems but do not understand even the basic mechanics of building software: what compilation does, what linking does, why a linker cannot find a symbol, what a shared library is, or what a build system such as CMake is actually doing. This is not about knowing compiler theory or being able to write a linker. The problem is the absence of a basic mental model of how source code becomes a running program.
The same problem appears in networking, operating systems, permissions, processes, and security. Remote-access services may be exposed casually because getting access to the robot is treated as the objective, while questions about authentication, network boundaries, or who else might be able to reach that service are treated as secondary concerns. Permissions are sometimes bypassed rather than understood. Networking problems are debugged by repeatedly changing settings until something works rather than by reasoning about routes, ports, interfaces, or trust boundaries.
These are not exotic areas of computer science. They are basic properties of the machines on which modern robots depend.
This becomes particularly important because a robot is not simply an algorithm attached to some motors. A modern robot is a networked computer system with actuators attached to it. It may contain multiple computers, cameras, microphones, wireless interfaces, remote-management services, GPUs, embedded controllers, cloud connections, and software from many different vendors. A mistake in an ordinary desktop application may crash the application. A mistake in a robotic system may expose cameras, provide remote control of the machine, or affect something moving in the physical world.
The security problems discovered in Yarbo robotic lawnmowers are an example. Researchers found serious weaknesses involving remote access and privileged credentials. What is striking about such failures is not that they required some obscure cryptographic breakthrough to understand. Yarbo intentionally built remote administrative access, but apparently designed its security model extraordinarily poorly.
It is tempting to describe such incidents simply as cybersecurity failures, but that may be too narrow. They can also reveal a more fundamental lack of computer systems knowledge—or an organization that failed to ensure such knowledge was present in the design and review process. One does not need to be a professional security researcher to understand that the same root password should not be hard-coded across deployed machines, or that remotely accessible control interfaces require careful authentication and isolation.
The organizational problem is equally important. In robotics research groups and startups, an engineer may be hired because of expertise in computer vision, controls, mechanical design, or machine learning and then gradually become responsible for software deployment, networking, remote access, build infrastructure, or system administration simply because somebody has to do it. Expertise in one technical area is quietly treated as if it implies competence in all the others.
It does not.
Knowing how to train a vision model is not the same thing as knowing how to build a computer system. Knowing control theory does not imply understanding operating-system privileges. Expertise in embedded electronics does not automatically imply competence in network security. These are different bodies of knowledge, and robotics increasingly requires them to interact.
ROS both responds to and reinforces this situation.
ROS is enormously valuable precisely because it hides a great deal of systems complexity. It provides communication abstractions, package conventions, launch mechanisms, tooling, and a common structure that allows researchers to focus on the robotics problem rather than repeatedly rebuilding infrastructure.
That is good engineering.
The problem begins when abstraction becomes a substitute for understanding rather than a tool built on top of it. A researcher may learn which ROS command to run without understanding what processes are being created, how packages were built, how libraries are found, how communication occurs between machines, or why changing an environment variable suddenly fixes the system.
As long as the abstraction works, this can appear perfectly sufficient.
Robotics, however, is a field in which abstractions leak constantly. Drivers fail. Devices disappear. Networks become unreliable. Libraries conflict. Timing changes. GPUs run out of memory. Processes crash. Permissions prevent access to hardware. A binary built against one library version is deployed onto another machine. A researcher may then wonder why “it stops working” after simply copy-pasting a built binary onto another machine. Suddenly the researcher has crossed the boundary between “using ROS” and “understanding the computer.”
The problem, therefore, is not abstraction itself. Good abstractions are one of the reasons modern robotics is possible. Nor should every robotics researcher be expected to become an operating-system specialist, a network engineer, and a compiler developer.
But there has to be a minimum level of systems literacy below the abstraction.
A person deploying software onto a networked physical machine should understand, at least conceptually, processes, users and privileges, networking, compilation and linking, libraries, dependencies, and basic security boundaries. These are no longer peripheral skills for robotics. They are part of understanding the experimental apparatus itself.
Yet the incentives of robotics research frequently push in the opposite direction. The researcher is rewarded for the new controller, perception algorithm, planning method, or benchmark result. Time spent understanding a linker problem, improving deployment infrastructure, reviewing remote-access security, or making a build system robust rarely produces a paper.
The rational response is therefore to learn only enough computing to make the experiment run.
ROS, Ubuntu, Docker, Python environments, and increasingly sophisticated tooling make this easier than ever. That is useful, but it also means that someone can operate remarkably high in the software stack while having only a vague idea of what is underneath.
The result is a strange contradiction: robotics is one of the most systems-oriented areas of engineering, yet its research culture can allow people to work on extremely complex systems without requiring them to understand the computers at the center of those systems.
When everything works, that knowledge can look unnecessary.
When it does not, the robot quickly reminds us otherwise.
When Everything Becomes pip install
This pressure to learn only enough computing to make the experiment run has shaped the tooling culture of modern robotics. Python, Conda, prebuilt wheels, containers, and increasingly complete software environments all reduce the amount of systems knowledge required to get from an idea to a working result.
That is one of their greatest strengths.
It is also where the next problem begins.
Python became dominant in robotics research for good reasons. It shortens the distance between an idea and an experiment. But the workflow around it increasingly encourages users to think of software as something that can simply be installed, imported, and executed, while the native libraries, binary interfaces, compiler toolchains, drivers, and runtime dependencies underneath disappear from view.
A command such as
pip install torchlooks simple, but what it installs is not simply “Python code.” Packages such as PyTorch depend heavily on compiled C/C++ and CUDA components. Current PyTorch binaries may bring their own CUDA runtime libraries rather than relying directly on the system CUDA toolkit.
This becomes messy as soon as the Python world interacts with software outside it.
A user may have a Conda environment containing PyTorch and its CUDA runtime while also using C++ code built against the CUDA installation on the host system. Different processes can legitimately use different CUDA runtimes, but problems begin when native extensions, plugins, build environments, or runtime search paths cross those boundaries. Which library gets loaded can then depend on search paths, RPATHs, environment variables, and the order in which libraries are loaded.
At that point, “which CUDA version am I using?” no longer has an obvious answer.
The same problem appears when building Python wheels inside Conda environments. A package may compile a native extension and silently discover headers or shared libraries from the host system. The resulting wheel works on the developer’s machine, but it is not really self-contained: it has accidentally acquired dependencies on libraries outside the environment. Later, another version of the same library may appear inside Conda, the environment may be moved to another computer, or the system libraries may change.
The failure then looks mysterious only because the dependency boundary was never understood in the first place.
This is one of the strange properties of the modern Python scientific ecosystem: it gives the appearance of being high-level and self-contained while resting on an increasingly complicated collection of native software underneath. Python package managers solve dependencies at the package level, but native software still ultimately lives in the world of compilers, ABIs, shared objects, dynamic loaders, drivers, and operating-system search paths.
Those worlds do not always align cleanly.
The problem is made worse by the fact that many users do not know they are crossing that boundary at all. A wheel is experienced as a Python package even when most of the important work is being performed by compiled libraries. A Conda environment is experienced as an isolated environment even when software built inside it has linked against the host. A machine-learning library is experienced as a Python library even when its execution depends on a particular relationship between CUDA userspace libraries and the host NVIDIA driver stack.
When this becomes difficult enough, the standard answer is increasingly:
Just use Docker.
Docker is extremely useful, especially for reproducibility and deployment. In robotics it can make sense to distribute different components as separate images, isolate dependencies, pin versions, and deploy the same software across many machines. I have even seen commercial robots delivered with several Docker containers running different parts of the system, and this is becoming a common architectural pattern.
But Docker is also increasingly treated as a universal cure for dependency problems that nobody wants to understand.
A container can make a complicated dependency graph reproducible without making that dependency graph understood.
The GPU case demonstrates this especially well. A Docker image containing CUDA software is not actually independent of the host GPU stack. The NVIDIA kernel driver still lives on the host, and GPU access from containers depends on additional machinery such as the NVIDIA Container Toolkit. The supposedly self-contained container therefore still relies on a carefully maintained boundary between the host driver, device nodes, container runtime, CUDA userspace libraries, and the application inside the container.
The abstraction becomes something like:
host Linux kernel ↓host NVIDIA driver ↓NVIDIA Container Toolkit ↓container runtime ↓CUDA libraries inside the container ↓PyTorch / TensorRT / ROS ↓robotics applicationWhen everything works, the user may only see the last line.
When it stops working, suddenly the difference between the host driver and CUDA runtime matters. So does the container runtime configuration. So do device permissions. So does the way GPU devices are passed into the container.
And robotics makes the container boundary even less clean.
A web service can often live comfortably inside a container and communicate through a network socket. A robot frequently needs direct access to cameras, serial devices, USB devices, CAN interfaces, GPUs, shared memory, real-time scheduling, and sometimes host networking. Each requirement punches another hole through the supposedly isolated environment.
The closer containerized software gets to physical hardware, the less convincing the idea of the completely self-contained container becomes.
Again, this does not mean containers are bad engineering. Quite the opposite: when the boundaries are deliberately understood and designed, they can be one of the best ways to deploy a complicated robotics system.
The problem is using them as a substitute for understanding those boundaries.
There is a recurring pattern:
native dependencies become difficult ↓use a Python environment
Python and native dependencies become difficult ↓use Conda
Conda and system dependencies become difficult ↓use Docker
Docker and hardware integration become difficult ↓add runtime hooks, device mappings, host networking,privileges, volumes, and vendor-specific toolingThe dependency problem has not disappeared. It has moved.
Meanwhile, the stack has gained another abstraction layer, and the person operating it may understand less of what is happening underneath.
This is why the Pythonic workflow matters beyond language preference. It reflects a broader change in research culture. The dominant goal is increasingly to make software easy to consume: install the package, activate the environment, start the container, run the launch file.
That is enormously productive, and research incentives reward it. The researcher wants to test an algorithm, not spend three days understanding ELF symbol resolution or CUDA library loading.
But there is a cost when this convenience becomes the only model of computing that the researcher knows.
Python itself is not the problem. Conda is not the problem. Docker is not the problem. ROS is not the problem. Each solves a real and difficult problem.
The problem appears when each abstraction is used to cover the previous abstraction without anyone maintaining a clear mental model of the complete system.
At some point, a robotics researcher may be using Python code inside a Conda environment inside a Docker container, calling into C++ and CUDA libraries, communicating through ROS, accessing GPU and hardware devices through runtime-specific mechanisms, on an Ubuntu system whose own software stack they do not fully understand.
Everything may work.
But when it does not, the debugging problem is no longer a Python problem, a ROS problem, a Docker problem, or an Ubuntu problem.
It is a computer-systems problem.
And that is precisely the knowledge the workflow has made easiest to avoid learning.
Conclusion: Convenience, Abstraction, and the Loss of Control
None of the technologies discussed here are inherently the problem. Ubuntu, ROS, Python, Conda, and Docker all became popular because they solve real problems and make difficult work easier.
The problem is what happens when convenience becomes dependence, abstraction becomes opacity, and standardization becomes centralization.
Ubuntu risks turning “Linux” into a platform defined by one vendor. ROS reinforces that platform because doing otherwise is expensive. Robotics culture often rewards getting the experiment to run more than understanding the system that runs it. Pythonic workflows and containers then make it increasingly possible to operate high in the stack without ever learning what lies underneath.
Each step is individually rational. Together, they can produce an ecosystem that is easier to use but harder to understand, easier to standardize but harder to escape, and increasingly dependent on abstractions that fewer people are capable of debugging when they fail. Coding agents may accelerate that trend by making it possible to repair systems through language rather than through understanding.
Perhaps the real question is not whether these tools give us enough freedom.
It is whether we will still know what that freedom means when the abstractions stop working.
Written by Yafei Ou, assisted by ChatGPT (2026-08-15).
© 2026 Yafei Ou. All rights reserved.

