Skip to main content
Deploy an Edge Impulse Motion Classifier with Atym Ocre Cont
intermediate
ExploreProjectsDeploy an Edge Impulse Motion Classifier with Atym Ocre Cont

Deploy an Edge Impulse Motion Classifier with Atym Ocre Cont

Build a closed-loop motion classification system using Atym Ocre and Edge Impulse on WebAssembly. Three containers communicate over an internal messaging bus to publish sensor data, run inference, and validate predictions entirely on device. Works on both Linux (Raspberry Pi) and Zephyr (nRF52840) targets with no external tooling required.

MO
moheeb_deveco
Published Mar 26, 2026
0 forks

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.

Tools Required2
Atym.io
Edge Impulse

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:

bash
git clone --recursive https://github.com/atym-io/getting-started.git
cd getting-started

Why --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:

bash
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:

bash
atym version

You should see output like:

bash
Atym CLI
Version: v1.0.3

Then associate the CLI with your Atym account:

bash
atym login

Alternative: 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:

bash
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:

bash
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-runtime

Configure and start the runtime with your device credentials:

bash
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-runtime

You 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:

bash
git clone https://github.com/atym-io/atym-samples-ei-motion-classifier.git
cd atym-samples-ei-motion-classifier

The 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:

  1. Train a motion classification project on Edge Impulse.
  2. Export the trained impulse as a C++ Library (not C++ Standalone).
  3. Extract the exported library into this repository, replacing the existing edge-impulse-sdk folder.
  4. Download the test dataset CBOR files from your Edge Impulse project's Data Acquisition section.
  5. Place all .cbor files in the data/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:

bash
atym login

Then build and push all three containers:

bash
./build.sh atym

This will:

  1. Build the assets, data, and classifier containers.
  2. Automatically push them to your Atym registry as ei-assets, ei-data, and ei-classifier.
  3. 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:

  1. Assets container -- Extracts the test dataset to /testing on the device filesystem.
  2. Data container -- Publishes sample windows and collects validation results.
  3. 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:

bash
atym run assets ei-assets

After the dataset is extracted, deploy the inference and data containers (this will automatically deploy in the correct order):

bash
./run.sh

9. View the Output

With all three containers running, you should see output similar to the following.

Data container output:

bash
[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:

bash
[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.97563

The 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:

bash
[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

  1. Train your motion classification model on Edge Impulse.
  2. Go to Deployment > C++ Library and select the model version to export.
  3. 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

  1. In Edge Impulse, go to Data Acquisition > Testing and download your test samples as CBOR files.
  2. Place all .cbor files in the data/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:

bash
-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 WASI

These are already configured in the included CMakeLists.txt.

Edge Impulse Runtime Considerations

  • Clock: WASI only supports CLOCK_MONOTONIC for timing. If you use your own model, the included patch in ei_classifier_porting.cpp will 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.