Building KZR OS: A Custom Embedded Linux Distro Using Yocto

Over the past few weeks, I’ve built KZR OS — a minimal embedded Linux distribution tailored for robotics and IoT systems. It’s based on the Yocto Project and includes support for ROS 2, CANbus, MQTT, a web interface, and Wi-Fi Access Point mode. This post outlines the process and structure behind building a custom embedded OS with Yocto, rather than diving deep into code or exact commands.

Why I Chose Yocto

Yocto allows complete control over what goes into your Linux image. It’s reproducible, layered, and designed for embedded systems. Unlike general-purpose Linux distros, Yocto gives you fine-grained customization at the image, package, and kernel level.

Step 1: Understanding Yocto’s Structure

A typical Yocto setup consists of:

  • Poky: The core build system
  • Board Support Package (BSP): Hardware-specific configuration
  • Layers: Each layer contains metadata, recipes, and configurations
  • Image recipe: Defines what gets installed into the final image

You start by cloning the core Yocto layers (poky) and any necessary BSPs for your target board, such as meta-raspberrypi for Raspberry Pi.

Step 2: Board Support Packages (BSPs)

A BSP in Yocto contains everything needed to support a specific hardware platform:

  • Machine configurations
  • Kernel configuration fragments
  • Device tree overlays
  • Bootloader setup (U-Boot, etc.)

For KZR OS, I used meta-raspberrypi as a base BSP and modified machine files and device trees within a custom layer for specific hardware needs. Writing your own BSP is about defining your board’s identity in Yocto terms.

Step 3: Creating Your Own Layers

Custom layers keep your changes isolated. I created two:

  • meta-custom: For hardware-specific overrides, kernel modules, and configurations
  • meta-cookbook: For custom image recipes, services, and packages

Each layer has its own conf/layer.conf file and follows a standard directory structure (recipes-core, recipes-kernel, recipes-ros, etc.).

Step 4: Writing Recipes

Recipes are the core unit of build logic in Yocto. Each .bb file describes how to fetch, build, and install a package.

To write a recipe:

  1. Define the source (Git, tarball, local)
  2. Provide dependencies and licensing
  3. Specify install steps

For example, a custom ROS node or a small Python app can be packaged by writing a recipe under recipes-ros or recipes-apps.

Appending or modifying existing recipes is also possible using .bbappend files in your own layer.

Step 5: Building the Image

With your layers defined, you configure the build with:

  • bblayers.conf: Enables layers
  • local.conf: Controls image features, init system, debug settings, etc.

You then create your own image recipe that defines what packages and features go into the final OS image. For KZR OS, I built a headless image that includes ROS 2, MQTT, CANbus tools, and web server support.

Once configured:

source oe-init-build-env
bitbake your-image-name

Kaizen Robotics KZR-OS Demo:

KZR-OS.

Reference: https://www.yoctoproject.org