3. Getting started on Zephyr RTOS
emlearn works on any platform that has C99 support. Zephyr is a modern, professional, open-source RTOS. This guide shows you how to use emlearn on that platform.
3.1. Prerequisites
Ensure that you have emlearn setup as per the Getting started on PC (Linux/MacOS/Windows).
You will need to have Zephyr installed already.
Follow the Zephyr Getting Started Guide.
In particular you will a functional setup that includes the Zephyr SDK, and the west
build tool.
You will need to have a Zephyr project setup. If you do not already have one, either use one of the samples in Zephyr as a base, or the Zephyr example application.
No particular hardware is needed. Any board supported by Zepyr should work.
In the example below, a board designed for QEMU simulator is used.
Support for this is included in the standard Zephyr SDK setup.
But if you have gone for a minimal setup, it may need to be installed manually.
The QEMU board specifically requires the arm-zephyr-eabi
compiler toolchain,
and the cmsis
and hal_nordic
Zephyr modules.
3.2. Add emlearn to your Zephyr project
emlearn provides the neccesary metadata to be used a Zephyr module (since Feburary 2024).
To include the module, add an entry to the projects
section of your west.yml
configuration.
projects:
#... exiting projects
- name: emlearn
url: https://github.com/emlearn/emlearn
revision: master
To make sure it worked correctly, you can run
west update emlearn
This should now pull the emlearn git repository into your workspace.
3.3. Enable emlearn in your Zephyr project
Once you have the emlearn Zephyr module, you must enable it in your application.
You can add this manually to your configuration file.
This file is typically called prj.conf
.
CONFIG_EMLEARN=y
3.4. Create model in Python
We will train a simple model to learn the XOR function.
Copy and save this as file xor_train.py
.
1import emlearn
2import numpy
3from sklearn.ensemble import RandomForestClassifier
4from sklearn.metrics import get_scorer
5
6# Generate simple dataset
7def make_xor(lower=0.0, upper=1.0, threshold=0.5, samples=100, seed=42):
8 rng = numpy.random.RandomState(seed)
9 X = rng.uniform(lower, upper, size=(samples, 2))
10 y = numpy.logical_xor(X[:, 0] > threshold, X[:, 1] > threshold)
11 # convert to int16 with a 8 bit range. [0.0-1.0] -> [0-255]
12 X = (X * 255).astype(numpy.int16)
13 return X, y
14
15X, y = make_xor()
16
17# Train a model
18estimator = RandomForestClassifier(n_estimators=3, max_depth=3, max_features=2, random_state=1)
19estimator.fit(X, y)
20score = get_scorer('f1')(estimator, X, y)
21assert score > 0.90, score # verify that we learned the function
22
23# Convert model using emlearn
24path = 'xor_model.h'
25cmodel = emlearn.convert(estimator, method='inline')
26cmodel.save(file=path, name='xor_model')
27print('Wrote model to', path)
Run the script
python xor_train.py
It will generate a file xor_model.h
containing the C code for our model.
Copy this file into your src/
directory.
3.5. Example application code
Here is some example code for calling the XOR model on some inputs.
1/*
2 * emlearn example for Zephyr RTOS
3 */
4
5#include <zephyr/kernel.h>
6
7#include "xor_model.h"
8
9void xor_test(void)
10{
11 const int16_t test_inputs[4][2] = {
12 { 0, 0 },
13 { 255, 0 },
14 { 0, 255 },
15 { 255, 255 },
16 };
17
18 for (int i=0; i<4; i++) {
19 const int16_t *features = test_inputs[i];
20 const int out = xor_model_predict(features, 2);
21
22 printf("xor(%d,%d) = %d\n", (int)features[0], (int)features[1], out);
23 }
24}
25
26int main(void)
27{
28 xor_test();
29 return 0;
30}
3.6. Build and run in simulator
We are assuming that your code is called helloworld_xor.
west build --board qemu_cortex_m3 ./helloworld_xor/ -t run
This should result in output similar to this:
...
-- west build: running target run
...
To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: cortex-m3
...
*** Booting Zephyr OS build zephyr-v3.5.0 ***
xor(0,0) = 0
xor(1,0) = 1
xor(0,1) = 1
xor(1,1) = 0