Run OOMWOO on a Smartphone: ROS 2 on Android with Termux

OOMWOO will be able to use an old Android phone instead of a Raspberry Pi CM4/CM5. Step one: ROS 2 in Termux - options, instructions and measured proot overhead on a Pixel 7.

OOMWOO, the open-source robot vacuum, will be able to use an Android smartphone instead of a Raspberry Pi CM4/CM5 for compute, WiFi and its user interface. The first step is getting ROS 2 to run on the phone. This post covers why, the options I looked at, step-by-step instructions, and test results. I will update it as the full OOMWOO software stack and the USB link to the robot come up.

Why a smartphone

Many of us have an old phone in a drawer. A few-year-old phone is a capable robot computer:

  • 8 CPU cores and 8 GB of RAM on the Pixel 7 I tested with
  • WiFi, Bluetooth, cameras and an IMU built in
  • a touchscreen that becomes the robot’s user interface, seen through the top of the enclosure
  • its own battery, and it costs nothing if you already own it

Reusing a phone also keeps it out of the landfill. Raspberry Pi CM4/CM5 remains the main option; the phone is an alternative.

Options I looked at

OptionEffortNotes
Ubuntu in proot, official ROS 2 packagesLow – no portingproot intercepts some system calls, which costs CPU. Works today; this is what I use below.
Native Termux build of ROS 2High – build and maintain 100+ packagesFastest. Worth it only if proot’s overhead turns out to matter.
glibc-runner (Termux glibc packages)MediumRuns Linux binaries without proot. Does not work with the Google Play build of Termux, which starts every program through Android’s own loader.
Rooted phone with a chrootLowNo proot overhead, but needs root. I want OOMWOO to work on stock phones.

Newer Android versions also include a Linux Terminal app that runs Debian in a virtual machine. I have not tried it yet.

Two old obstacles, now solved

A couple of years ago I ran ROS 2 in Termux and hit two problems.

ROS 2 nodes could not talk to each other. They failed at getifaddrs() with “Permission denied”. Since Android 11, apps may not bind a netlink socket, which is how Linux’s C library lists network interfaces. Today Termux’s proot handles this, so the official ROS 2 packages discover each other out of the box. Android’s own C library also works around it, so a native build would be fine too.

Android kills background processes. Android 12 and newer start killing apps’ child processes once the phone has more than 32 of them in total, and a ROS 2 launch file starts one process per node. Two fixes:

  • Turn on Disable child process restrictions in Settings > System > Developer options (Android 14 and newer)
  • Run the nodes in one process as ROS 2 components. This also uses far less CPU, see the results below.

Install ROS 2 in Termux

Tested on a Pixel 7 with Android 17, the Google Play build of Termux, Ubuntu 24.04 and ROS 2 Jazzy. Ubuntu and ROS 2 take about 2 GB of storage, and the install took about 17 minutes on my phone.

Install Termux, open it and run:

pkg update
pkg install proot-distro
proot-distro install ubuntu:24.04
proot-distro login ubuntu

You are now in Ubuntu. Install ROS 2 Jazzy from the official ROS 2 repository:

apt update
apt install -y curl ca-certificates locales
locale-gen en_US.UTF-8
export ROS_APT_SOURCE_VERSION=$(curl -s https://api.github.com/repos/ros-infrastructure/ros-apt-source/releases/latest | grep -F "tag_name" | awk -F'"' '{print $4}')
curl -L -o /tmp/ros2-apt-source.deb "https://github.com/ros-infrastructure/ros-apt-source/releases/download/${ROS_APT_SOURCE_VERSION}/ros2-apt-source_${ROS_APT_SOURCE_VERSION}.noble_all.deb"
dpkg -i /tmp/ros2-apt-source.deb
apt update
apt install -y ros-jazzy-ros-base ros-jazzy-demo-nodes-cpp

Test it with a talker and a listener. In the Ubuntu shell run:

source /opt/ros/jazzy/setup.bash
ros2 run demo_nodes_cpp talker

Open a second Termux session (swipe right from the left edge, then New session) and run:

proot-distro login ubuntu
source /opt/ros/jazzy/setup.bash
ros2 run demo_nodes_cpp listener

The listener should print “I heard: [Hello World: …]” once a second. The first ros2 node list or ros2 topic list may come back empty while ROS 2 discovers the nodes; run it again.

Two more tips. Run termux-wake-lock so Android does not pause Termux when the screen turns off. And never set PROOT_NO_SECCOMP=1, see below.

Test results

I measured what proot costs on the Pixel 7, with Claude’s help.

System calls

The same calls, timed in Termux directly and in Ubuntu under proot:

System callTermux (native)Ubuntu in proot
getpid, write0.2 µs0.2 µs
clock_gettime0.04 µs0.2 µs (5x)
UDP send + receive5 µs70 µs (14x)
open + close a file1.6 µs105 µs (64x)

proot uses seccomp so that most system calls run at full speed, and only intercepts the ones it needs to translate, such as file paths and network addresses. With seccomp turned off (PROOT_NO_SECCOMP=1) every call costs 80 to 1,900 µs.

A ROS 2 camera pipeline

A 640×480 image stream at 30 Hz, the size of OOMWOO’s camera, from cam2image to showimage. Both setups delivered all 30 frames per second. CPU is in percent of one core; the Pixel 7 has 8.

SetupROS 2 nodesprootTotal CPU
2 separate processes111%34%145%
1 process (composed, intra-process)27%12%42%

Two takeaways:

  • Run the nodes in one process. It cut CPU 3.5x. Messages are passed in memory instead of going through the system calls proot intercepts, and Android’s process limit no longer matters.
  • proot itself takes about a quarter of the CPU. That is acceptable for now. A native build would save it, but only if the robot needs the headroom.

What is next

  • Run the OOMWOO software stack on the phone – navigation, localization and the robot bridge – as components in one process, and see how much headroom the phone has.
  • Connect the phone to the robot’s microcontroller over USB. Without root there is no /dev/ttyACM0; Termux:API’s termux-usb hands over the USB device instead, so the bridge will talk to it through libusb.

I will update this post as these come up.

Leave a Reply

Your email address will not be published. Required fields are marked *