Skip to content

Lecture 25: Capstone Project — Custom Linux Images with Yocto

Overview

The previous 24 lectures covered how Linux works: processes, scheduling, memory management, drivers, filesystems, containers, and real-time tuning. This capstone lecture asks: how do you build the Linux image that runs on your AI hardware target? The answer is Yocto — the industry-standard build system for embedded Linux. Every platform covered in this course (Jetson, openpilot Agnos, custom FPGA boards, automotive ECUs) uses either Yocto or a Yocto-derived toolchain to produce reproducible, minimal, production-grade Linux images.

The mental model to carry here is that Yocto is a factory for Linux distributions. You describe what you want (machine hardware, packages, filesystem layout), and Yocto assembles, cross-compiles, and packages it into a flashable image. Unlike installing Ubuntu and removing packages, Yocto starts from nothing — only what you explicitly include ends up on the target. This minimizes attack surface, reduces OTA update size, and guarantees reproducibility: the same inputs always produce bit-identical outputs.

This lecture is structured as two projects that build on each other: - Project 1: Build a minimal general-purpose image on QEMU (x86-64) — no hardware required - Project 2: Build a full AI-ready custom image for the NVIDIA Jetson Orin Nano 8GB using meta-tegra


Yocto Core Concepts

Before building, understand the vocabulary. Yocto has a steep initial learning curve that flattens once these five terms click.

Yocto Conceptual Map

  poky/                          ← Reference distribution (Yocto Project)
  ├── meta/                      ← Core recipes (Linux, glibc, busybox, systemd)
  ├── meta-poky/                 ← Poky distro configuration
  ├── meta-yocto-bsp/            ← Reference BSP machines (qemux86, qemuarm64)
  meta-tegra/                    ← NVIDIA Tegra BSP layer (external)
  meta-openembedded/             ← Additional packages (Python, networking tools)
  meta-my-ai-image/             ← YOUR custom layer
  build/
  ├── conf/
  │   ├── local.conf             ← Your machine/distro/build settings
  │   └── bblayers.conf          ← Which layers are active
  └── tmp/                       ← Build artifacts, rootfs, kernel
Term Meaning
Layer A directory of recipes grouped by purpose (BSP, distro, application). Stacked like Git branches — higher layers override lower ones.
Recipe (.bb) A build script for one package: source URL, patches, compile flags, install paths. Analogous to a Debian .spec file.
Machine Hardware target definition: CPU arch, kernel config, bootloader, Device Tree. Examples: qemux86-64, jetson-orin-nano-devkit.
Distro Global policy: libc (glibc/musl), init system (systemd/SysV), package format (rpm/deb/ipk), debug flags.
Image A recipe that collects packages into a rootfs and disk image. core-image-minimal ≈ 20 MB; core-image-full-cmdline ≈ 80 MB.
BitBake The build engine. Parses all recipes, resolves dependencies, runs fetch/compile/install/package tasks in parallel.

Key Insight: Yocto does not download pre-built binaries — it cross-compiles everything from source for your exact target. This means you control every compiler flag, every enabled feature, and every kernel config option. The trade-off is that the first build takes 2–6 hours (it is building a complete cross-toolchain plus hundreds of packages); incremental rebuilds take minutes.


Project 1: Minimal x86 Image on QEMU

Goal

Build a bootable minimal Linux image for qemux86-64 and run it in QEMU. No physical hardware needed. This teaches the full Yocto workflow in a safe environment before touching real hardware.

Step 1: Install Prerequisites

# Ubuntu 22.04 / 24.04 host (recommended)
sudo apt-get update
sudo apt-get install -y \
    gawk wget git diffstat unzip texinfo gcc build-essential \
    chrpath socat cpio python3 python3-pip python3-pexpect \
    xz-utils debianutils iputils-ping python3-git python3-jinja2 \
    libegl1-mesa libsdl1.2-dev python3-subunit mesa-common-dev \
    zstd liblz4-tool file locales libacl1
# Ensure UTF-8 locale (BitBake requires it)
sudo locale-gen en_US.UTF-8

The build requires approximately 50–100 GB of free disk space and 8 GB of RAM (16 GB recommended). BitBake parallelizes across all available CPU cores by default.

Step 2: Clone Poky (Yocto Reference Distribution)

git clone git://git.yoctoproject.org/poky --branch scarthgap --depth 1
# scarthgap = Yocto 5.0 LTS, released April 2024, kernel 6.6 LTS
# Alternative: kirkstone (Yocto 4.0 LTS, kernel 5.15 LTS)
cd poky

Key Insight: Always pin to a named LTS release (scarthgap, kirkstone). The master branch receives breaking changes continuously. Production systems stay on the same LTS release for the entire product lifetime — just like Linux kernel LTS branches.

Step 3: Initialize the Build Environment

source oe-init-build-env build-qemu
# This script:
# 1. Creates the build/ directory
# 2. Creates build/conf/local.conf (your settings file)
# 3. Creates build/conf/bblayers.conf (active layers list)
# 4. Sets PATH and environment variables for BitBake
# 5. Changes your working directory to build/

After sourcing, you are inside build-qemu/. All bitbake commands run from here.

Step 4: Configure local.conf

Open conf/local.conf and review/set these key variables:

# The hardware target
MACHINE = "qemux86-64"

# Number of parallel compile threads (set to number of CPU cores)
BB_NUMBER_THREADS = "8"
PARALLEL_MAKE = "-j 8"

# Download cache — reused across builds (set to a persistent directory)
DL_DIR = "/opt/yocto/downloads"

# Shared state cache — speeds up rebuilds dramatically
SSTATE_DIR = "/opt/yocto/sstate-cache"

# Image features: add ssh server for remote access
EXTRA_IMAGE_FEATURES += "ssh-server-openssh"

# Disk image format for QEMU
IMAGE_FSTYPES = "ext4 wic.qcow2"

Common Pitfall: If you set DL_DIR and SSTATE_DIR on a separate disk, ensure it supports POSIX extended attributes (xattr). Some filesystems (FAT32, exFAT, some network shares) do not — BitBake will fail with cryptic errors about file locking.

Step 5: Build the Minimal Image

bitbake core-image-minimal

This single command triggers BitBake to: 1. Parse all recipe files in all active layers 2. Resolve the full dependency graph (kernel → glibc → busybox → init → image) 3. Fetch source archives (Linux kernel, BusyBox, systemd, etc.) 4. Build the cross-compilation toolchain (sysroot for qemux86-64) 5. Cross-compile every package 6. Assemble the root filesystem 7. Create the disk image (*.ext4, *.wic.qcow2)

First build time: 1–3 hours depending on hardware. Watch the progress:

# In a separate terminal, monitor build status
bitbake -u taskexp core-image-minimal   # graphical task explorer
# Or watch the log:
tail -f tmp/log/cooker/qemux86-64/console-latest.log

Step 6: Run in QEMU

# Boot the image in QEMU (no external QEMU installation needed — Yocto builds its own)
runqemu qemux86-64 core-image-minimal nographic

# You should see kernel boot messages, then a login prompt
# Default login: root (no password)

Inside the QEMU VM, verify the system:

uname -r              # should show 6.6.x kernel
cat /proc/cpuinfo     # QEMU virtual CPU
free -m               # memory
df -h                 # filesystem (tiny — this is a minimal image)
ps aux                # running processes (very few — truly minimal)

Step 7: Understand the Build Artifacts

build-qemu/
├── conf/
│   ├── local.conf                    ← your settings
│   └── bblayers.conf                 ← active layers
└── tmp/
    ├── deploy/images/qemux86-64/
    │   ├── core-image-minimal-qemux86-64.ext4    ← root filesystem
    │   ├── core-image-minimal-qemux86-64.wic     ← complete disk image
    │   ├── bzImage                               ← compressed kernel
    │   └── modules-qemux86-64.tgz                ← kernel modules
    ├── work/x86_64-linux/            ← host tools (cross-compiler)
    ├── work/qemux86_64-poky-linux/   ← target packages
    │   └── linux-yocto-6.6.*/        ← kernel build directory
    └── sysroots/qemux86-64/          ← target sysroot for SDK

The work/ directory contains the unpacked, patched, compiled, and installed files for every package. When debugging a package build failure, this is where you look.

Step 8: Customize — Add a Package

To add Python 3 to the image, add to local.conf:

IMAGE_INSTALL:append = " python3 python3-pip"

Then rebuild (incremental — only adds the new packages):

bitbake core-image-minimal

Key Insight: Yocto's shared state (sstate) cache records every task's output hash. Adding a package does not rebuild the kernel — it pulls the cached kernel artifact and only builds the new packages. Incremental builds are fast (seconds to minutes), which is why the 2-hour initial build is worth the investment.


Project 2: NVIDIA Jetson Orin Nano 8GB Custom AI Image

Goal

Build a production-quality AI image for the Jetson Orin Nano 8GB developer kit that includes: - L4T 36.x kernel (6.1 LTS with NVIDIA Tegra patches) - NVIDIA GPU drivers and CUDA userspace - TensorRT and cuDNN - OpenCV with CUDA support - systemd, SSH, Python 3

This image can replace the default NVIDIA JetPack install with a reproducible, customizable, minimal Yocto-based alternative. Used in production for edge AI appliances.

Architecture: meta-tegra

Layer Stack for Jetson Orin Nano 8GB:

meta-tegra/              ← NVIDIA Tegra BSP: kernel, U-Boot, flash tools
                            Machine: jetson-orin-nano-devkit
meta-openembedded/       ← Extra packages: OpenCV, Python libs, networking
meta-tegra-community/    ← Optional: TensorRT, CUDA recipes from community
meta-my-jetson-image/    ← YOUR layer: custom recipes, image definition
poky/meta/               ← Core (gcc, glibc, busybox, systemd)

meta-tegra is maintained by the Open Embedded for Tegra (OE4T) community. It tracks NVIDIA's L4T releases and provides the kernel, U-Boot, Device Tree, and board-specific drivers.

Step 1: Prepare the Workspace

mkdir jetson-orin-build && cd jetson-orin-build

# Clone all required layers
git clone git://git.yoctoproject.org/poky             --branch scarthgap
git clone https://github.com/OE4T/meta-tegra          --branch scarthgap
git clone https://github.com/openembedded/meta-openembedded --branch scarthgap

# Confirm meta-tegra supports Orin Nano
ls meta-tegra/conf/machine/
# Should list: jetson-orin-nano-devkit.conf, jetson-agx-orin-devkit.conf, etc.

Key Insight: meta-tegra branch names track Yocto release names (scarthgap, kirkstone), not L4T versions. The L4T version is set inside meta-tegra's recipes. Scarthgap branch of meta-tegra corresponds to L4T 36.x (JetPack 6.x).

Step 2: Initialize and Configure the Build

source poky/oe-init-build-env build-jetson

# Edit bblayers.conf to include all layers:
cat > conf/bblayers.conf << 'EOF'
POKY_BBLAYERS_CONF_VERSION = "2"
BBPATH = "${TOPDIR}"
BBFILES ?= ""

BBLAYERS ?= " \
  ${TOPDIR}/../poky/meta \
  ${TOPDIR}/../poky/meta-poky \
  ${TOPDIR}/../poky/meta-yocto-bsp \
  ${TOPDIR}/../meta-tegra \
  ${TOPDIR}/../meta-openembedded/meta-oe \
  ${TOPDIR}/../meta-openembedded/meta-python \
  ${TOPDIR}/../meta-openembedded/meta-networking \
  "
EOF

Step 3: Configure local.conf for Jetson Orin Nano 8GB

cat > conf/local.conf << 'EOF'
# ── Machine ───────────────────────────────────────────────────────────────────
MACHINE = "jetson-orin-nano-devkit"
# jetson-orin-nano-devkit covers both Orin Nano 4GB and 8GB developer kits.
# The Orin Nano 8GB module uses a different SOM; the MACHINE is the same
# because the devkit carrier board is identical. The SOM variant is selected
# at flash time via the appropriate Device Tree Blob (DTB).

# ── Distribution ─────────────────────────────────────────────────────────────
DISTRO = "poky"
# Use systemd instead of SysV init (required for most modern AI stacks)
DISTRO_FEATURES:append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit"

# ── NVIDIA GPU / CUDA ─────────────────────────────────────────────────────────
# Include NVIDIA binary drivers (requires accepting NVIDIA's EULA)
LICENSE_FLAGS_ACCEPTED = "commercial_nvidia-l4t-core nvidia-eula"
# Enable CUDA support in packages that support it (OpenCV, etc.)
CUDA_NVCC_EXTRA_FLAGS = "--gpu-architecture=sm_87"
# Jetson Orin Nano has Ampere GPU, SM 8.7

# ── Packages to include ────────────────────────────────────────────────────────
# Core AI stack
IMAGE_INSTALL:append = " \
    cuda-toolkit \
    tensorrt \
    libcudnn \
    opencv \
    python3 \
    python3-numpy \
    python3-pip \
"
# System utilities
IMAGE_INSTALL:append = " \
    openssh \
    git \
    htop \
    i2c-tools \
    can-utils \
    iproute2 \
"
# Real-time tuning tools (from previous OS lectures)
IMAGE_INSTALL:append = " \
    rt-tests \
    trace-cmd \
    perf \
"

# ── Image Features ────────────────────────────────────────────────────────────
EXTRA_IMAGE_FEATURES += "ssh-server-openssh debug-tweaks"
# debug-tweaks: enables root login without password (remove for production)

# ── Build parallelism ─────────────────────────────────────────────────────────
BB_NUMBER_THREADS = "12"
PARALLEL_MAKE = "-j 12"

# ── Shared caches ─────────────────────────────────────────────────────────────
DL_DIR = "/opt/yocto/downloads"
SSTATE_DIR = "/opt/yocto/sstate-cache"

# ── Output image format ───────────────────────────────────────────────────────
# Tegra images use tegraflash format — includes CBoot, DTB, rootfs partition
IMAGE_FSTYPES = "tegraflash"
EOF

Common Pitfall: The LICENSE_FLAGS_ACCEPTED variable must include nvidia-eula exactly as shown. If you forget it, BitBake will silently skip all NVIDIA binary recipes and build without CUDA — you will not see an error, just a missing package at runtime. Always run bitbake -g core-image-my-ai and check task-depends.dot if CUDA packages seem absent.

Step 4: Create a Custom Image Recipe

Create your own layer and image recipe to keep customizations clean and version-controlled:

mkdir -p ../meta-my-jetson-image/recipes-core/images
cat > ../meta-my-jetson-image/recipes-core/images/jetson-orin-ai.bb << 'EOF'
# Custom AI image for Jetson Orin Nano 8GB
SUMMARY = "AI inference image for Jetson Orin Nano 8GB"
LICENSE = "MIT"

# Inherit from the standard Tegra image class
require recipes-core/images/tegra-image.inc

# Add the base Tegra runtime (kernel modules, L4T libs)
IMAGE_INSTALL += "tegra-libraries-core"

# ── AI inference stack ────────────────────────────────────────────────────────
IMAGE_INSTALL += " \
    cuda-toolkit \
    tensorrt \
    libcudnn \
    opencv \
    python3 \
    python3-numpy \
    python3-onnxruntime \
"

# ── Real-time and diagnostic tools ───────────────────────────────────────────
IMAGE_INSTALL += " \
    rt-tests \
    trace-cmd \
    bpftrace \
    can-utils \
    i2c-tools \
"

# ── System configuration ──────────────────────────────────────────────────────
IMAGE_INSTALL += " \
    openssh \
    systemd \
    util-linux \
    procps \
    htop \
"

# Enable root filesystem expansion on first boot (fills the eMMC partition)
IMAGE_FEATURES += "read-only-rootfs-delayed-postinsts"
EOF

Add the new layer to bblayers.conf:

# Add to the BBLAYERS list in conf/bblayers.conf:
#   ${TOPDIR}/../meta-my-jetson-image \

Step 5: Build the Image

bitbake jetson-orin-ai

This build is larger than Project 1 — it includes CUDA and TensorRT. Expected time on a modern workstation: - First build: 4–8 hours (downloads ~15 GB of sources and binary blobs) - Incremental rebuild after config change: 10–30 minutes - Incremental rebuild after adding one package: 2–5 minutes

Monitor progress:

# Real-time task log
tail -f tmp/log/cooker/jetson-orin-nano-devkit/console-latest.log

# Show currently running tasks
bitbake -u taskexp jetson-orin-ai

Step 6: Inspect the Output

ls tmp/deploy/images/jetson-orin-nano-devkit/
# Key files:
# jetson-orin-ai-jetson-orin-nano-devkit.tegraflash.tar.gz  ← flash bundle
# Image                                                      ← compressed kernel
# tegra234-p3768-0000+p3767-0005-nv.dtb                    ← Orin Nano 8GB DTB
# bootloader/                                               ← CBoot, MB1, TOS

The tegraflash.tar.gz bundle contains everything tegraflash.py needs to flash the board. The DTB p3767-0005 is the Orin Nano 8GB module identifier.

tegraflash bundle contents:
├── flash.xml              ← partition layout (eMMC map)
├── Image                  ← kernel
├── tegra234-*.dtb         ← Device Tree for your specific module
├── boot.img               ← kernel + initramfs
├── system.img             ← rootfs (ext4, ~2–4 GB)
├── bootloader/
│   ├── mb1_t234_prod.bin  ← MB1 bootloader (NVIDIA signed)
│   ├── cboot.bin          ← CBoot (U-Boot replacement)
│   └── tos-a.img          ← Trusted OS (TrustZone)
└── tegraflash.py          ← flash script

Step 7: Flash to Jetson Orin Nano 8GB

Hardware setup:

1. Connect Jetson Orin Nano devkit to host PC via USB-C (J15 port — Recovery USB)
2. Insert jumper on J14 (Force Recovery header) pins 1-2
3. Power on the board
4. Confirm the board appears on host: lsusb | grep NVIDIA
   → "ID 0955:7323 NVIDIA Corp. APX" indicates recovery mode
5. Remove the recovery jumper

Flash:

# Extract the tegraflash bundle
tar xf tmp/deploy/images/jetson-orin-nano-devkit/jetson-orin-ai-jetson-orin-nano-devkit.tegraflash.tar.gz
cd jetson-orin-ai-*tegraflash/

# Flash all partitions
sudo ./tegraflash.py --flash all
# This takes 5–15 minutes
# Progress: writes bootloader, DTB, kernel, and rootfs to eMMC

Common Pitfall: Flashing fails with "device not found" if the USB cable is plugged into the wrong port. The Orin Nano devkit has two USB-C ports: J14 (display/data) and J15 (recovery/debug). Recovery mode only works on J15. If your cable is marginal (high-resistance), the APX device appears briefly then disappears — use a short, known-good USB 3.0 cable.

Step 8: First Boot and Validation

After flashing, remove the recovery jumper (if still in), power cycle, and connect via serial console or SSH:

# Serial console (115200 baud) on J14 micro-USB
screen /dev/ttyUSB0 115200

# Or wait for DHCP and SSH in
ssh root@<jetson-ip>

Validate the key AI components:

# Verify NVIDIA GPU driver loaded
nvidia-smi
# Should show: "Orin (nvgpu)", CUDA Version, memory

# Verify CUDA installation
nvcc --version
python3 -c "import ctypes; ctypes.cdll.LoadLibrary('libcuda.so'); print('CUDA OK')"

# Verify TensorRT
python3 -c "import tensorrt as trt; print('TRT', trt.__version__)"

# Check kernel version (should be L4T 6.1.x)
uname -r

# Check thermal zones (from Lecture 1 — thermal monitoring)
cat /sys/class/thermal/thermal_zone*/temp
# CPU, GPU, SoC, CV zones in millidegrees Celsius

# RT scheduling tools available?
cyclictest --help
chrt -p 1

Step 9: Customization Patterns

Once the base image works, these are the common customizations for AI deployment:

# ── Disable unnecessary services (reduce boot time and attack surface) ────────
# In a bbappend or local.conf:
SYSTEMD_AUTO_ENABLE:pn-avahi-daemon = "disable"
SYSTEMD_AUTO_ENABLE:pn-bluetooth = "disable"

# ── Pre-install a TensorRT model at build time ────────────────────────────────
# In your image recipe:
IMAGE_INSTALL += "my-model-package"
# Where my-model-package.bb installs the .engine file to /opt/models/

# ── Apply RT tuning at boot (from Lecture 7) ─────────────────────────────────
# Add a systemd service that runs the RT tuning script:
# isolcpus=4-11 nohz_full=4-11 rcu_nocbs=4-11
# in /boot/extlinux/extlinux.conf APPEND line (modify via bbappend)

# ── Set root password for production (remove debug-tweaks) ───────────────────
# Remove "debug-tweaks" from IMAGE_FEATURES
# Add to local.conf:
INHERIT += "extrausers"
EXTRA_USERS_PARAMS = "usermod -p '\$6\$...' root;"

# ── OTA A/B update support (from Lecture 22) ─────────────────────────────────
# meta-tegra supports OTA updates via NVIDIA's Over-the-Air (OTA) framework
# Enable with:
TEGRA_REDUNDANT_BOOT = "1"

Connecting to the OS Curriculum

OS Lecture Yocto Manifestation
Lecture 1: Linux kernel architecture Yocto builds the kernel from source; KCONFIG_MODE controls which drivers compile in
Lecture 5: Boot process & Device Tree meta-tegra provides DTB files; SRC_URI in kernel recipe patches the DTS
Lecture 7: PREEMPT_RT Add PREFERRED_PROVIDER_virtual/kernel = "linux-tegra" and patch CONFIG_PREEMPT_RT=y
Lecture 17: Linux driver model Recipes in meta-tegra/recipes-kernel/ add out-of-tree modules (nvgpu.ko, nvcsi.ko)
Lecture 21: Filesystems IMAGE_FSTYPES controls ext4/btrfs/F2FS; EXTRA_IMAGECMD:ext4 sets block size
Lecture 22: OTA partitioning tegraflash.xml defines A/B partition layout; TEGRA_REDUNDANT_BOOT=1 enables it
Lecture 23: Containers Add docker to IMAGE_INSTALL; NVIDIA Container Runtime is a separate meta-tegra recipe
Lecture 24: L4T, Yocto for AI This project IS the production workflow for AI edge devices

Summary

Project Target Image Key Tool Flash Method
Project 1 qemux86-64 (virtual) core-image-minimal runqemu No flashing needed
Project 2 Jetson Orin Nano 8GB jetson-orin-ai tegraflash.py USB-C Recovery Mode

Conceptual Review

  • Why use Yocto instead of flashing the stock JetPack image? Stock JetPack is a fixed Ubuntu-based distribution you cannot easily customize or reproduce bit-for-bit. Yocto builds a minimal image from source that contains only what you explicitly include, with reproducible builds guaranteed by the sstate cache. For production devices, this reduces attack surface, controls binary composition, and enables automated OTA updates.
  • What does source oe-init-build-env actually do? It sets BBPATH, PATH, and BUILDDIR environment variables, creates build/conf/local.conf and bblayers.conf from templates, and cd's into the build directory. BitBake relies on these environment variables to locate recipes and configuration.
  • Why does the Jetson image use tegraflash format instead of a raw ext4? The Tegra platform has a complex partition layout: separate partitions for MB1 (first-stage bootloader), CBoot, Device Tree, A/B kernel, A/B rootfs, and RPMB (secure storage). tegraflash.py knows how to write each partition to the correct eMMC offset using the flash.xml partition map. A raw ext4 would only contain the rootfs and boot on nothing.
  • What is the relationship between meta-tegra and L4T? meta-tegra is the Yocto layer that packages L4T. It pulls the L4T kernel source from NVIDIA's GitHub, applies Tegra-specific patches, and builds it with the configuration needed for the target board. The layer pins to specific L4T versions in its recipe files.
  • How do you add a custom Python application to the Yocto image? Write a recipe (my-app.bb) that sets SRC_URI to your application's source, defines do_install to copy files to ${D}/opt/my-app/, and adds my-app to IMAGE_INSTALL. BitBake handles cross-compilation, dependencies, and packaging automatically.
  • Why does the first build take 4–8 hours but incremental builds take minutes? BitBake hashes the inputs of every task (source code, recipe contents, environment variables). If the hash is unchanged, it restores the output from the sstate cache without rerunning the task. Adding one package to IMAGE_INSTALL only triggers that package's fetch/compile/install tasks, then reassembles the rootfs — the kernel, glibc, and all other packages are served from cache instantly.

AI Hardware Connection

  • Yocto is the standard build system for every production AI edge device in this roadmap: openpilot Agnos, Jetson commercial deployments, automotive ECU Linux partitions, and custom FPGA SoC boards all use Yocto or Yocto-derived build systems (meta-tegra, OpenWRT).
  • The PREEMPT_RT kernel config from Lecture 7 is added to a Yocto Jetson build by creating a linux-tegra_%.bbappend file that sets CONFIG_PREEMPT_RT=y in a kernel fragment — the same kernel you studied is now yours to configure at build time.
  • OTA A/B updates (Lecture 22) on Jetson are enabled by TEGRA_REDUNDANT_BOOT = "1" in Yocto and managed by NVIDIA's nv-update-engine — building this into the image from the start is far cheaper than retrofitting it after deployment.
  • The TensorRT and CUDA packages in the Yocto image (cuda-toolkit, tensorrt) are the same userspace libraries studied in Phase 4 Track B (Jetson), but now you control which version is on the device — critical for ensuring model compatibility across a fleet of devices that may have been manufactured months apart.
  • Reproducibility matters for safety: ISO 26262 ASIL certification requires the ability to rebuild the exact binary that was certified. Yocto's sstate cache and SSTATE_MIRRORS infrastructure provide this guarantee — a certified build can be reproduced years later from the same recipe inputs.
  • Custom layers (meta-my-jetson-image) are the production engineering artifact: when you join an AI hardware team, you will be working in a meta layer that defines the company's product image, adding sensors, optimizing services, and managing the OS across firmware updates.