
Atym extends WebAssembly (Wasm) beyond the browser to secure, resource-constrained edge devices. In this project, we combine Atym with Edge Impulse's motion classifier to create a closed-loop inference system: raw sensor data is published, classified, and the prediction is validated -- all on device.
The system runs on both Linux and Zephyr targets and is organized as three independent containers that communicate via Atym Ocre's internal messaging bus:
- Classifier Container -- Receives raw sensor samples, runs the Edge Impulse motion classifier, and publishes predictions.
- Data Container -- Publishes labeled test samples from the dataset, collects prediction results, and reports overall accuracy.
- Assets Container -- Embeds the test dataset CBOR files and extracts them to the filesystem at runtime.
The data publisher validates predictions in a closed loop, so you can measure accuracy without any external tooling.
Documentation References
1. Sign Up for the Atym Eval Program
Before you can build and deploy containers, you need an Atym account. Head to the Atym Eval Program signup page and fill out the form with your name, email, phone number, industry, and role. Once submitted, Atym will provision your account and send you login credentials via email.
If you've already completed the Run WebAssembly Containers on Raspberry Pi Using Atym getting started guide and have a working Atym setup, skip ahead to Step 4.
2. Set Up the Development Environment
Atym provides a preconfigured Dev Container with the full toolchain for building WebAssembly containers. This is the recommended approach.
Prerequisites:
- Docker installed and running
- Visual Studio Code with the Dev Containers extension
Clone the Atym getting-started repository:
git clone --recursive https://github.com/atym-io/getting-started.git
cd getting-startedWhy
--recursive? This repository includes the Atym SDK as a submodule, which provides the C API definitions needed to build Atym applications.
Open the directory in VS Code:
code .Run Dev Containers: Open Folder in Container... from the Command Palette (Cmd+Shift+P on Mac, Ctrl+Shift+P on Windows/Linux). Select the folder and wait for the container to build. This may take a few minutes the first time.
Once inside the Dev Container, verify the toolchain:
atym versionYou should see output like:
Atym CLI
Version: v1.0.3Then associate the CLI with your Atym account:
atym loginAlternative: If you prefer not to use the Dev Container, you can install the Atym CLI directly on your machine. See the Atym CLI Setup docs for Linux, macOS, and Windows instructions.
3. Set Up Your Device
You need the Atym Ocre runtime installed on a Linux device (like a Raspberry Pi 4) and registered with your account.
Register the device from your development machine:
atym add device --deviceName "my-rpi" --description "Raspberry Pi 4" --serialNumber "RPI4001"Save the deviceUUID, pskSecret, and tenantUUID from the output -- you'll need them to configure the runtime.
Install the Atym runtime on your Pi. SSH in and download the latest runtime. Check the Atym Quickstart Guide for the most current download link:
wget https://atympublicshare.blob.core.windows.net/runtime/linux/latest/atym-runtime-debian-aarch64.tar.gz
tar -xzf atym-runtime-debian-aarch64.tar.gz
cd atym-runtimeConfigure and start the runtime with your device credentials:
atym config set device/id deviceUUID@tenantID
atym config set device/psk pskSecret
atym config set server/endpoint coapgw.prod.atym.io
atym runtime config set server/port 5684
./bin/atym-runtimeYou should see Client connected successfully when the device connects.
For a more detailed walkthrough of the Raspberry Pi setup (including headless mode, flashing the OS, and troubleshooting), see the Run WebAssembly Containers on Raspberry Pi Using Atym guide.
4. Requirements
At this point you should have:
- A Linux device (e.g., Raspberry Pi 4) with the Atym Ocre runtime installed and connected
- The Atym CLI set up on your development machine (via Dev Container or direct install)
- Git and CMake available for building (included in the Dev Container)
- Optionally, a Zephyr board (e.g., Nordic nRF52840) if you want to test on an MCU target
- Optionally, an Edge Impulse account if you want to train and export your own motion classifier
5. Clone the Repository
On your development machine (or inside the Dev Container), clone the example repo:
git clone https://github.com/atym-io/atym-samples-ei-motion-classifier.git
cd atym-samples-ei-motion-classifierThe repo includes an Edge Impulse motion classifier model and test dataset in the edge-impulse-sdk and data/testing/ directories, so you can build and deploy immediately without needing an Edge Impulse account.
6. Prepare the Dataset and Edge Impulse Model
If you want to use the included model, skip ahead to the build step. To use your own model instead:
- Train a motion classification project on Edge Impulse.
- Export the trained impulse as a C++ Library (not C++ Standalone).
- Extract the exported library into this repository, replacing the existing
edge-impulse-sdkfolder. - Download the test dataset CBOR files from your Edge Impulse project's Data Acquisition section.
- Place all
.cborfiles in thedata/testing/directory.
Edge Impulse generates model_metadata.h and model_variables.h in the model-parameters/ directory when you export. These define the raw sample count, input frame size, and labels -- they generally don't require editing.
7. Build the Containers
Before building, make sure you're logged in to your Atym registry:
atym loginThen build and push all three containers:
./build.sh atymThis will:
- Build the assets, data, and classifier containers.
- Automatically push them to your Atym registry as
ei-assets,ei-data, andei-classifier. - Generate C headers for any CBOR files in
data/testing/and embed them into the assets container at build time.
8. Deployment Order (Critical)
The containers must be deployed in a specific order:
- Assets container -- Extracts the test dataset to
/testingon the device filesystem. - Data container -- Publishes sample windows and collects validation results.
- Classifier container -- Subscribes to sample messages and publishes predictions.
Deploy the assets container first because the data container depends on the extracted dataset, and the classifier must be listening before data is published. On Zephyr targets, this order is especially important to populate the filesystem before launching the other containers.
Deploy the assets container:
atym run assets ei-assetsAfter the dataset is extracted, deploy the inference and data containers (this will automatically deploy in the correct order):
./run.sh9. View the Output
With all three containers running, you should see output similar to the following.
Data container output:
[DATA] Data publisher start
[DATA] Using sample directory: /testing
[DATA] Found 3 CBOR files
[DATA] Publish window 0 of sample "testing/idle.1.cbor.XXXX.cbor"
[DATA] Comparison for sample 'testing/idle.1.cbor...cbor' window 0:
[DATA] expected='idle' predicted='idle' score=0.97563 -> MATCH
...
[DATA] Test results:
[DATA] Total windows: 25
[DATA] Correct windows: 24
[DATA] Window accuracy: 96.00 %Classifier container output:
[CLS] EI classifier subscriber starting up (closed-loop responder)...
[CLS] Listening for samples on topic 'ei/sample/raw'
[CLS] Publishing results on topic 'ei/result'
[CLS] [0.00241, 0.97563, ...]
[CLS] Published result: label=idle score=0.97563The data publisher streams sample windows from the test dataset, the classifier responds with predicted labels, and the publisher reports overall accuracy.
10. Architecture
The three containers communicate via Atym Ocre's messaging bus:
[Assets Container] (extracts CBOR files)
|
v
/testing/ (filesystem)
^
|
[Data Container] -------[ei/sample/raw]-------> [Classifier Container]
(publishes samples) (runs inference)
^
|
[ei/result]
(receives predictions)The assets container extracts dataset files to the /testing directory. The data container reads samples from this directory and publishes them on the ei/sample/raw topic. The classifier container subscribes to this topic, runs inference, and publishes predictions on the ei/result topic. The data container subscribes to ei/result to compare expected and predicted labels.
11. Integrate Your Own Model
You can reuse this infrastructure for your own motion classification model.
Step 1 -- Export from Edge Impulse
- Train your motion classification model on Edge Impulse.
- Go to Deployment > C++ Library and select the model version to export.
- Download the exported ZIP file and extract it to this directory, replacing the existing
edge-impulse-sdk/folder.
The model-parameters/ directory contains model_metadata.h and model_variables.h, which define EI_CLASSIFIER_RAW_SAMPLE_COUNT, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, and the label count. These are automatically generated and should not need manual editing.
Step 2 -- Prepare Test Dataset
- In Edge Impulse, go to Data Acquisition > Testing and download your test samples as CBOR files.
- Place all
.cborfiles in thedata/testing/directory.
During the build, the gen_embedded_assets.py script will detect these files and embed them into the assets container automatically.
Step 3 -- Build and Deploy
Run the build script and deployment commands as described in Steps 7 and 8. The CMake build system will automatically discover CBOR files in data/testing/, generate C headers to embed them via gen_embedded_assets.py, and link everything into the final containers.
12. Wasm and Zephyr Porting Notes
This example has been tested on both Linux and Zephyr RTOS. If you're porting your own model to a WebAssembly/Zephyr environment, here's what to watch out for.
Model Export Settings
When exporting from Edge Impulse for Wasm targets, enable "Use xxd instead of INCBIN to link TFLite/ONNX files". Wasm doesn't support INCBIN's binary embedding method. This setting is found in Edge Impulse's Dashboard under Experiments.
Compilation Flags
The following flags are critical for Wasm compatibility:
-fno-exceptions # Wasm doesn't support C++ exceptions
-DEIDSP_SIGNAL_C_FN_POINTER # Use C function pointers for signal processing
-DEI_C_LINKAGE # Use C linkage for EI functions
-DUSE_CMSIS_NN=OFF # CMSIS-NN optimizations not supported in WASIThese are already configured in the included CMakeLists.txt.
Edge Impulse Runtime Considerations
- Clock: WASI only supports
CLOCK_MONOTONICfor timing. If you use your own model, the included patch inei_classifier_porting.cppwill need to be manually added. - Linking: The Edge Impulse SDK is statically linked (not as a shared library) for portability.
- Memory: Wasm modules run in isolated memory -- no cross-container memory sharing occurs.
Conclusion
By combining Atym Ocre with Edge Impulse's motion classifier, you can build a portable, closed-loop inference system that runs on both Linux and Zephyr devices. Because Atym uses WebAssembly, the same application can be built once and run across multiple hardware architectures with minimal changes, enabling efficient experimentation at the edge.