Lab 1 — Worked example: product requirements in Yocto terms¶
Companion: Lecture 3 — Module 1 · Course: Yocto guide
This is a complete reference answer for Lab 1: one plausible embedded product described in Yocto vocabulary (MACHINE, layers, image contents, OTA, partitions). Adapt the hardware and layer names to your real BSP and Yocto release.
Note: Exact MACHINE strings, layer names, and recipe names depend on your vendor BSP and Yocto branch. Always confirm against the BSP README and the release you pinned. For deep Jetson + Yocto production practice on this roadmap, see Phase 4 Track B (Orin-Nano-Yocto-BSP-Production).
1. Target hardware¶
Product concept: Edge AI camera node (video ingest + on-device inference).
| Item | Choice |
|---|---|
| SoC | NVIDIA Jetson Orin Nano (example) |
| Architecture | AArch64 |
| Yocto | Vendor BSP (e.g. meta-tegra / NVIDIA-oriented layers) |
| Acceleration | GPU, Tensor cores (CUDA / TensorRT via vendor stacks where licensed and supported) |
Yocto mapping
- Set
MACHINEto the value defined by your BSP (example placeholder:jetson-orin-nano-devkit— verify in BSP docs). - Add the BSP layer (and its documented dependencies) to
bblayers.conf. - Kernel, firmware, and many userspace GPU pieces are owned by vendor recipes in that layer or companion layers.
2. Connectivity¶
Required / desired interfaces
- Ethernet (primary backhaul)
- Wi-Fi and BLE (optional product goal)
- USB host (peripherals)
- MIPI CSI-2 (camera)
- UART (serial console)
Yocto mapping
- Kernel + device tree: enable or carry the right drivers and DT nodes for your carrier and modules.
- Userspace packages (examples):
wpa-supplicantoriwdfor Wi-Fi,bluez5for Bluetooth,iproute2for networking; exact recipe names vary by layer. - Debug: getty on UART is typically image / distro policy, not something you “apt install” after shipping.
3. Storage layout¶
Assumption: eMMC (or NVMe) for production; SD possible for bring-up.
Intent
- Boot artifacts (bootloader, kernel, DTB as required by platform)
- Root filesystem with A/B slots for OTA
- Writable data partition (logs, models, config)
Yocto mapping
wic(.wks) or BSP-specific image types define partition tables.- Your image recipe + OTA layer must agree on which partition is active, where the rootfs is copied, and how the bootloader selects A vs B.
Illustrative concept only (not a drop-in .wks for any specific BSP):
# Pseudocode — replace with BSP-correct sources and sizes
part /boot --source bootimg-partition --size 256M
part / --source rootfs --label rootfs_a
part / --source rootfs --label rootfs_b
part /data --size 1024M --fstype ext4
4. Update strategy¶
Choice: Image-based OTA with A/B rootfs and rollback.
Typical stacks
- RAUC (
meta-rauc+ integration work), or - Mender (
meta-mender+ integration work)
Yocto mapping
- Add the OTA meta-layer and follow its MACHINE / distro integration guide.
- Bootloader (often U-Boot or platform-specific firmware) must support switching boot paths and failure policies you define.
- CI should produce signed or otherwise protected bundles if your threat model requires it (out of scope here, but plan for it).
5. Must-have userspace¶
Core
- Init:
systemd(if that is your distro policy) - Remote access:
openssh - Logs: journald (with
systemd)
Application / AI stack (product-dependent)
- CUDA / TensorRT (usually vendor recipes; licensing and redistribution rules apply)
- Python 3
- OpenCV (recipe name may be
opencv,opencv-python, or split packages — check your layers) - GStreamer and plugins for camera pipelines
Optional
- Containers: OCI runtime /
docker— often heavy; many teams defer to a dedicated meta-layer or vendor bundle. Treat as explicit image feature, not an afterthought.
Real time
- Moderate latency: often PREEMPT kernel is enough.
- Hard real time: separate exercise (PREEMPT_RT, CPU isolation, measurement). Do not assume it “for free” from a default BSP kernel.
Example local.conf fragment (illustrative)
Use IMAGE_INSTALL:append (syntax for recent Yocto) and only packages that exist in your configured layers:
Add opencv, GStreamer packages, OTA client, etc., after you confirm recipe names with bitbake-layers / oe-pkgdata-util or layer documentation.
Kernel (concept)
- For preemptible kernel behavior, use config fragments or BSP-supported mechanisms; example symbol:
CONFIG_PREEMPT=y(exact integration depends on kernel recipe).
6. Must have vs nice to have¶
Must have (production-critical)
- Boot chain + kernel + DTB for your board
- Camera path (CSI driver + userspace capture stack you will ship)
- Minimum network path (at least Ethernet for many products)
- SSH (or another controlled admin path) if operators need it
- Inference runtime you actually ship (CUDA/TensorRT or lighter stack)
- OTA client + A/B if you committed to image OTA
- systemd units (or your init policy) for the application
Nice to have
- Wi-Fi / BLE if not required on day one
- Docker if you can defer orchestration
- Debug tools (
strace,htop,tcpdump) — often adebugimage variant, not the production image - GUI / Wayland — usually omitted on headless edge cameras
Mindset (what this lab is training)¶
- Yocto builds images from declarative metadata; the question is what is baked in, not what you install later on a golden device.
- Hardware alignment flows through MACHINE, BSP layers, kernel / DT, and image recipes.
- Reproducibility means pinned layers, known DISTRO policy, and CI that rebuilds from the same inputs.
Bonus: sketch of repo-facing files¶
conf/local.conf (fragment)
MACHINE ?= "YOUR_BSP_MACHINE_NAME"
DISTRO ?= "poky"
# Parallelism, download dir, sstate — set per team policy
conf/bblayers.conf (illustrative layer stack)
# Bottom-up: core + hardware + OTA + product
# Exact paths and layer names must match your checkout
BBPATH = "${TOPDIR}"
BBFILES ?= ""
You will add entries such as meta, meta-poky, meta-oe, BSP meta, meta-rauc or meta-mender, then meta-yourproduct for your image and bbappends.
Custom image (in your product layer), conceptually:
Name the image yourproduct-image.bb and bitbake yourproduct-image when the stack is wired.
How to implement (workflow)¶
The sections above are the what. This section is the how: a realistic order of operations from empty checkout to flashable artifact. Treat it as a blueprint—you will adjust branch names, layer paths, MACHINE, and recipe names to match your BSP and Yocto release.
Reality checks
- Layer compatibility: Poky,
meta-openembedded,meta-tegra(OE4T), andmeta-rauceach target specific Yocto branches. Use the combination documented by the BSP (e.g. OE4T manifest or README), not randomgit checkouttags mixed ad hoc. - Jetson + RAUC + A/B: Boot flow and partitioning on Tegra are BSP-specific. Expect extra integration (bootloader, signing, slot layout) beyond “add meta-rauc”.
- CUDA / TensorRT / Docker: Often require vendor or community layers, license acceptance, and sometimes not the same image as a minimal RAUC target. Prove each package with
bitbake -e/bitbake <recipe>before locking the image.
Pipeline: host setup → clone Poky → oe-init-build-env → add layers → local.conf → product layer → image recipe → (optional) app recipe → kernel/DT tweaks → WIC/OTA wiring → bitbake → deploy → vendor flash tools.
1. Host setup and get Poky¶
Install build dependencies (Ubuntu is common; names differ on other distros). Cross-check the Yocto System Requirements page for your release.
sudo apt update
sudo apt 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 pylint xterm
Clone Poky at a named branch or tag that matches your BSP (example branch name only):
git clone git://git.yoctoproject.org/poky
cd poky
git checkout kirkstone # example only — use BSP-required revision
Start a build shell (creates or uses build/):
From here, paths like ../meta-tegra assume sibling directories next to poky/, not inside build/.
2. Add layers (example stack)¶
Clone dependencies your BSP documents (versions must match). Illustrative layout:
Register layers from inside the build directory:
bitbake-layers add-layer ../meta-tegra
bitbake-layers add-layer ../meta-openembedded/meta-oe
bitbake-layers add-layer ../meta-openembedded/meta-python
bitbake-layers add-layer ../meta-rauc
Run bitbake-layers show-layers and fix BBFILE_COLLECTIONS / dependency errors before continuing.
3. Configure conf/local.conf¶
Edit build/conf/local.conf. Replace MACHINE and distro features with values from your BSP.
# Example only — confirm MACHINE with meta-tegra / board docs
MACHINE = "jetson-orin-nano-devkit"
DISTRO_FEATURES:append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
PACKAGE_CLASSES ?= "package_rpm"
# Optional: reclaim disk during build (tradeoff: harder debug of failed workdirs)
INHERIT += "rm_work"
Development image (optional): adds debug affordances; do not ship blindly to production.
4. Create the product layer¶
Typical layout:
meta-myproduct/
├── conf/layer.conf
├── recipes-core/images/
├── recipes-app/
├── wic/ # if you own custom .wks
└── recipes-kernel/linux/ # bbappends or fragments, if needed
5. Custom image recipe¶
File: meta-myproduct/recipes-core/images/my-edge-image.bb
SUMMARY = "Edge AI camera root filesystem (example)"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f833b3da"
inherit core-image
# Use :append (Kirkstone+). Only list packages that exist in your configured layers.
IMAGE_INSTALL:append = " \
python3 \
openssh-sshd \
"
# Add opencv, gstreamer, docker, rauc, etc. only after bitbake resolves them.
# Example placeholders (names vary by layer):
# IMAGE_INSTALL:append = " opencv gstreamer1.0-plugins-base rauc"
Build:
6. Ship an application with systemd (pattern)¶
Recipe meta-myproduct/recipes-app/myapp/myapp_1.0.bb. Put app.py and myapp.service in the same directory as the .bb file (or under a files/ subdirectory, following your layer’s FILESPATH convention).
SUMMARY = "Example AI app service"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f833b3da"
SRC_URI = "file://app.py \
file://myapp.service \
"
S = "${WORKDIR}"
RDEPENDS:${PN} += "python3"
do_install() {
install -d ${D}${bindir}
install -m 0755 ${WORKDIR}/app.py ${D}${bindir}/myapp.py
install -d ${D}${systemd_system_unitdir}
install -m 0644 ${WORKDIR}/myapp.service ${D}${systemd_system_unitdir}
}
inherit systemd
SYSTEMD_SERVICE:${PN} = "myapp.service"
files/myapp.service
[Unit]
Description=Example edge AI app
[Service]
ExecStart=/usr/bin/python3 /usr/bin/myapp.py
Restart=always
[Install]
WantedBy=multi-user.target
Add myapp to IMAGE_INSTALL:append in the image recipe.
7. Kernel and hardware¶
- Menuconfig (when supported):
bitbake virtual/kernel -c menuconfig— some BSPs prefer only fragments; follow vendor docs. - Fragments / defconfig: prefer
*.cfgfragments andbbappendtolinux-yoctoor the BSP kernel recipe instead of hand-editing trees you cannot rebase. - Device tree:
.dts/.dtsiin your layer; apply viaSRC_URI+ patch or via BSP extension mechanisms.
8. Storage layout (WIC)¶
Place a .wks under your layer (e.g. meta-myproduct/wic/my-layout.wks). Do not assume the partition stanza below works on Tegra without BSP alignment.
part /boot --source bootimg-partition --fstype=vfat --label boot --size 256M
part / --source rootfs --fstype=ext4 --label rootfs_a
part / --source rootfs --fstype=ext4 --label rootfs_b
part /data --fstype=ext4 --size 1024M
Point the image at it. Put the .wks under wic/ in your layer; then in the image recipe (names vary by release):
If BitBake cannot find the file, check WKS_SEARCH_PATH / layer BBFILE_COLLECTIONS and the docs for your Yocto version.
A/B + RAUC usually requires matching bootloader env, RAUC system.conf, and partition UUIDs—follow meta-rauc integration for your SoC.
9. OTA (RAUC outline)¶
- Add RAUC distro / image features per
meta-raucdocumentation for your branch. - Install the RAUC client into the image (
raucpackage when available). - Define slots, keys, and bundle recipes in CI; signing is mandatory for serious deployments.
Mender follows a parallel path via meta-mender with its own partition assumptions.
10. Build and artifacts¶
Inspect deploy (path varies by MACHINE and TMPDIR):
tmp/deploy/images/<MACHINE>/
*.wic
*.ext4 / tar / other fstypes
kernel / dtb artifacts (BSP-dependent)
11. Flash to hardware¶
Use vendor tools for the platform (for Jetson, NVIDIA’s flashing workflow / BSP docs—not a generic one-liner). OE4T and L4T document where images land and how they map to flash.sh or equivalent.
Traditional distro vs Yocto (engineering view)¶
| Traditional Linux | Yocto |
|---|---|
| Install packages after boot | Decide image contents at build time |
| Manual snowflake setup | Automated, reviewable metadata |
| Hard to reproduce | Reproducible with pinned layers and cache policy |
Where to go deeper on this roadmap¶
- Failed builds and logs: Lecture 11 — Debugging builds
- Performance / sstate / CI: Lecture 13 — Performance, caching, and CI
- bbappend discipline: Lecture 7 — Layers
- Jetson Yocto production: Phase 4 Track B — Orin-Nano-Yocto-BSP-Production
Next steps on this roadmap¶
- Continue Lecture 4 — Architecture (layers and configs).
- When you move to Jetson-specific BSP depth, use Phase 4 Track B Yocto production material alongside this spec.