Skip to content

Small Bits. Solid Systems. ZeroKernel is the NanoKernel-style embedded orchestration engine built by ZeroBits for microcontrollers that need deterministic behavior without the weight of a full RTOS.

License

Notifications You must be signed in to change notification settings

ZeroBitsTech/ZeroKernel

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

57 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ZeroKernel

Small Bits. Solid Systems.

ZeroKernel is the embedded execution runtime built by ZeroBits for microcontrollers that need deterministic scheduling, bounded memory, and fault-aware orchestration without the weight of a full RTOS.

Official URL: https://kernel.zerobits.tech

Why ZeroKernel

ZeroKernel is designed for firmware that has outgrown ad-hoc loop() code but does not need a preemptive RTOS.

  • Deterministic cooperative scheduling
  • Fixed-capacity runtime with no dynamic allocation in the active path
  • Key-based event and command routing for lean builds
  • Watchdog, safe mode, panic routing, execution contracts, and capability masks
  • Build profiles that scale from small always-on nodes to diagnostics-heavy bring-up

The intended position is simple:

  • stronger than a basic scheduler library
  • smaller and easier to reason about than a full RTOS
  • practical for production firmware on ESP8266, ESP32, RP2040, STM32, and similar targets

What It Provides

  • Cooperative interval scheduler with priority-aware task selection
  • Fixed-size task registry and bounded queues
  • Pub/sub events, command queue, work queue, and cooperative event flags
  • Watchdog supervision with heartbeat timeout, overrun handling, recovery, and safe mode
  • Runtime identity, ABI version, manifest, timing reports, diagnostics hooks, and task-scoped capability gating
  • Low-level internal helpers for cycle counting and idle hints, including C and assembly where it actually helps

Repo Health

The repository now ships with project-level release and validation scaffolding:

  • GitHub Actions CI on every push to main and on pull requests
  • Tag-driven release packaging on v* tags
  • A local CHANGELOG.md for release notes and regression history
  • Wiki-ready documentation pages under docs/wiki/

Start points:

  • docs/wiki/Home.md
  • docs/wiki/Validation.md
  • docs/wiki/Beta-Modules.md

Current Runtime Snapshot

Latest measured references:

  • ESP8266 POWER_SAVE (UniversalSmokeTest): 28864 / 80192 RAM
  • Wemos compare runtime overhead vs blocking baseline: +744 bytes RAM
  • Wemos determinism gate: fast_avg_lag_us=0, fast_max_lag_us=0, fast_miss=0
  • ESP32 compare runtime overhead vs blocking baseline: +704 bytes RAM
  • ESP32 determinism gate: fast_avg_lag_us=0, fast_max_lag_us=0, fast_miss=0
  • Wemos measured free heap during diagnostics: 49280

These are regression references, not marketing numbers. The most important gate is still deterministic timing.

Before vs After

Measured on Wemos D1 mini using the blocking baseline and the current ZeroKernel compare sketch:

Metric Before (blocking) After (ZeroKernel)
RAM usage 28300 / 80192 29044 / 80192
Fast avg lag 2512 us 0 us
Fast max lag 11054 us 0 us
Fast misses 126 0

Tradeoff summary:

  • RAM overhead: +744 bytes
  • Determinism maintained: 0 lag, 0 misses
  • Measured free heap on Wemos diagnostics: 49280

That overhead buys bounded scheduling, watchdog supervision, panic flow, capability-aware task gating, and fixed-capacity queues. On ESP8266-class hardware the measured free heap remains comfortably high, so the extra runtime footprint is a small and controlled tradeoff rather than a practical memory risk.

ESP32 Before vs After

Measured on ESP32 using the blocking baseline and the current ZeroKernel compare sketch:

Metric Before (blocking) After (ZeroKernel)
RAM usage 22116 / 327680 22820 / 327680
Fast avg lag 2022 us 0 us
Fast max lag 8156 us 0 us
Fast misses 124 0

Tradeoff summary:

  • RAM overhead: +704 bytes
  • Determinism maintained: 0 lag, 0 misses

The ESP32 tradeoff is also healthy: the footprint increase is small relative to total headroom, while the scheduling result is materially better under the same workload.

Optional Network Modules (BETA)

The optional network helpers are currently marked BETA:

  • ZeroTransportMetrics
  • ZeroHttpPump
  • ZeroMqttPump
  • ZeroWiFiMaintainer
  • ZeroNetProfileEsp8266 (recommended constrained starting point for Wemos / ESP8266)
  • ZeroNetProfileEsp8266Http (opt-in constrained HTTP-first variant for Wemos / ESP8266)

They are already useful and validated on desktop plus ESP32 hardware, but they are still under active tuning for footprint, retry behavior, and cross-board transport quirks. The core runtime is the stable layer; the network helpers should be treated as add-on modules that are ready for evaluation and controlled deployments.

Current target maturity:

  • ESP32: stable enough for production-style evaluation and controlled deployments when validated against the real HTTP/MQTT endpoint you intend to ship with.
  • ESP8266 / Wemos: still BETA for full dual-transport use. The constrained MQTT-first preset is now the recommended path and already has repeatable live runs where MQTT delivery is real and timing beats the naive baseline, but full HTTP+MQTT behavior is still under active hardening.
  • Other supported families: compile-validated, but network helper maturity should still be treated as evaluation-grade until they receive the same live validation depth.

Recommended board-specific path:

  • ESP32: use the default network module configs first, then validate against your real endpoint.
  • ESP8266 / Wemos: start with ZeroNetProfileEsp8266. It is a constrained MQTT-first preset that disables periodic HTTP dispatch by default, prevents offline queue buildup, lowers idle MQTT churn, staggers lighter network task cadence, and recommends a lighter idle strategy. In current validation it is the preferred path for Wemos MQTT delivery, while HTTP remains degraded/off by default unless you deliberately opt back in.
  • ESP8266 / Wemos (HTTP-specific): use ZeroNetProfileEsp8266Http only when your node is intentionally HTTP-first. It keeps the same constrained timing discipline, but does not try to combine HTTP and MQTT in the same default path. Current validation now shows real HTTP delivery with clean request success under the official local compare, but it is still marked experimental because misses and worst-case lag are not yet as tidy as the MQTT-first constrained path.

Current best module tradeoff reference (ESP32, LEAN_NET, manual pattern vs module pattern):

  • RAM overhead: +408 bytes
  • Determinism maintained: fast_miss=0
  • HTTP success count: 6 -> 9
  • MQTT success count: 10 -> 18
  • Queue pressure: 4 -> 1

In other words: the modules do cost memory, but the current tuned path keeps that cost bounded and pays it back with better transport throughput and less queue buildup under the same synthetic workload window.

ESP32 Network Status

The current network helper stack is now strong enough on ESP32 to treat as a practical deployment target, not just a lab demo, as long as you still validate it against your own endpoint, payload size, and retry policy.

Current accepted live compare reference on ESP32:

  • baseline:
    • sample_runs=47
    • fast_avg_lag_us=112955
    • fast_max_lag_us=1609577
    • fast_miss=12
    • http_rate=73
    • mqtt_rate=73
  • modules:
    • sample_runs=85
    • fast_avg_lag_us=15857
    • fast_max_lag_us=1047913
    • fast_miss=5
    • http_rate=66
    • mqtt_rate=100

The important part is the shape of the tradeoff: timing improves materially, MQTT delivery becomes clean, and HTTP stays alive under the same live window. That is why the ESP32 path is now documented as stable enough, even though the global module label remains BETA until the ESP8266 path is cleaned up too.

General-Purpose Validation Workloads

To avoid overfitting the runtime to a single project, ZeroKernel now also ships with three reusable compare workloads:

  • EnvMonitor: sensor sampling + filtering + threshold alarm
  • TelemetryGateway: queue-heavy transport orchestration without tying the example to real Wi-Fi credentials
  • IndustrialLoop: fast control loop + command handling + diagnostics + safe-mode recovery

Current ESP32 references from the compare runners:

  • EnvMonitor
    • sample_runs: 49 -> 50
    • fast_avg_lag_us: 871 -> 0
    • fast_max_lag_us: 1780 -> 0
    • fast_miss: 24 -> 0
  • TelemetryGateway
    • http_ok: 23 -> 27
    • mqtt_ok: 23 -> 27
    • http_rate: 88 -> 87
    • mqtt_rate: 92 -> 90
    • http_queue: 0 -> 0
    • mqtt_queue: 0 -> 0
  • IndustrialLoop
    • control_runs: 99 -> 101
    • fast_avg_lag_us: 241 -> 0
    • fast_max_lag_us: 3983 -> 0
    • fast_miss: 9 -> 0
    • recoveries: 0 -> 1

These workloads are intentionally broader than the micro-benchmarks: they show the runtime under sensor, transport, and control-loop pressure without depending on a single application codebase.

Field Validation: ESP8266 Seismic Node

Measured on a real ESP8266 direct-AP seismic node using:

  • NodeMCU / ESP8266
  • MPU6050-class accelerometer over I2C
  • local buzzer alarm output
  • direct access point mode with queued HTTP delivery
  • live local backend over Wi-Fi AP during the test window

The original firmware was a single blocking loop. The ZeroKernel rewrite split the workload into sampling, heartbeat, flush, buzzer, temperature, and status tasks.

Metric Before (direct loop) After (ZeroKernel, tuned)
Sample runs (5s window) 476 501
Fast avg lag 5393 us 6 us
Fast max lag 21733 us 2378 us
Fast misses 406 1
Successful local sends 5 7

Tradeoff summary:

  • The direct-loop version remains functional, but it drifts and drops timing quality once live HTTP delivery is active.
  • The tuned ZeroKernel version keeps the same node online, preserves successful local delivery, and holds sensor timing far closer to the target schedule.
  • This is the kind of workload where the difference is visible on real hardware under real transport load, not only in a synthetic lab loop.

Real sample window from the direct AP seismic project:

BASELINE_SEISMIC window_ms=5009 sample_runs=476 fast_avg_lag_us=5393 fast_max_lag_us=21733 fast_miss=406 queue_max=1 sent_ok=5 sent_fail=0 captures=5 clients=1
ZEROKERNEL_SEISMIC window_ms=5000 sample_runs=501 fast_avg_lag_us=6 fast_max_lag_us=2378 fast_miss=1 queue_max=3 sent_ok=7 sent_fail=0 captures=7 clients=1

Representative baseline vs ZeroKernel shape from the seismic firmware:

Baseline-style direct loop:

void loop() {
  const unsigned long nowUs = micros();
  trackSampleTiming(nowUs);
  ++sampleRuns;

  float ax = 0.0f;
  float ay = 0.0f;
  float az = 1.0f;
  readAccel(ax, ay, az);
  updateMotionModel(ax, ay, az);

  if (shouldSend && canCapture) {
    capturePacket(true);
  } else if (heartbeatDue() && hasDirectClient()) {
    capturePacket(false);
  }

  if (txCount > 0) {
    flushQueueOnce();
  }

  delay(LOOP_DELAY_MS);
}

ZeroKernel rewrite:

void sampleSensorTask() {
  trackSampleTiming(micros());
  ++sampleRuns;

  float ax = 0.0f;
  float ay = 0.0f;
  float az = 1.0f;
  readAccel(ax, ay, az);
  updateMotionModel(ax, ay, az);

  if (shouldSend && canCapture) {
    capturePacket(true);
  }
}

void setup() {
  ZeroKernel.begin(zerokernel::adapters::arduinoMillisClock);

  ZeroKernel.addTask("Sample", sampleSensorTask, LOOP_DELAY_MS, 4);
  ZeroKernel.addTask("Flush", queueFlushTask, 120, 3);
  ZeroKernel.addTask("Heartbeat", heartbeatTask, 25, 2);
  ZeroKernel.addTask(buzzerTaskConfig);
  ZeroKernel.addTask(tempTask);
  ZeroKernel.addTask(statusTask);

  ZeroKernel.setTaskPriority("Sample", zerokernel::Kernel::kPriorityCritical);
  ZeroKernel.setTaskPriority("Flush", zerokernel::Kernel::kPriorityLow);
}

void loop() {
  ZeroKernel.tick();
}

That rewrite is the practical difference: the same node behavior is split into bounded, phase-aligned tasks instead of one blocking loop that mixes sensing, transport, alarms, and status work together.

ESP32 Telemetry Parity

The richer ESP32 telemetry workload is also now phase-aligned after the runtime scheduling fix:

  • Baseline: sample_runs=21, fast_avg_lag_us=0, fast_max_lag_us=0, fast_miss=0
  • ZeroKernel: sample_runs=21, fast_avg_lag_us=0, fast_max_lag_us=0, fast_miss=0

This matters because the fix is global to periodic task scheduling. It is not a demo-only patch; it improves sensor, telemetry, heartbeat, and transport polling loops across supported targets.

Install

Arduino IDE

  1. Download or clone this repository.
  2. Put the ZeroKernel folder into your Arduino libraries directory:
    • Linux: ~/Arduino/libraries/
    • Windows: Documents/Arduino/libraries/
    • macOS: ~/Documents/Arduino/libraries/
  3. Restart Arduino IDE.
  4. Open an example from File -> Examples -> ZeroKernel.

PlatformIO

Add the local library path in platformio.ini:

[env:your_board]
platform = espressif8266
board = d1_mini
framework = arduino
lib_deps =
  symlink:///absolute/path/to/ZeroKernel

Or vendor the repository inside your project and point lib_extra_dirs to it.

How To Use

1. Include the header

#include <ZeroKernel.h>

2. Start the runtime

ZeroKernel.begin(millis);

For desktop or custom targets, pass your own clock source:

unsigned long boardClock() {
  return millis();
}

ZeroKernel.begin(boardClock);

3. Register non-blocking tasks

void sampleSensors() {
  // Non-blocking work only.
}

void flushTelemetry() {
  // Keep this short and cooperative.
}

ZeroKernel.addTask("Sensors", sampleSensors, 100, 5);
ZeroKernel.addTask("Telemetry", flushTelemetry, 500, 10);

4. Tick the kernel inside loop()

void loop() {
  ZeroKernel.tick();
}

5. Use events or fast topic keys

String route:

ZeroKernel.publishDeferred("telemetry.temperature", 42);

Lean key route:

const zerokernel::Kernel::TopicKey temperatureKey =
    zerokernel::Kernel::makeTopicKey("telemetry.temperature");

ZeroKernel.publishDeferredFast(temperatureKey, 42);

6. Add watchdog and recovery policy

zerokernel::Kernel::WatchdogPolicy policy = {250, 2, true};
ZeroKernel.setWatchdogPolicy(policy);
ZeroKernel.setTaskHeartbeatTimeout("Sensors", 300);
ZeroKernel.heartbeatTask("Sensors");

7. Inspect runtime state

const zerokernel::Kernel::KernelStats stats = ZeroKernel.getStats();
const zerokernel::Kernel::TimingReport timing = ZeroKernel.getTimingReport();

if (ZeroKernel.isSafeMode()) {
  ZeroKernel.exitSafeMode();
}

If diagnostics are enabled:

ZeroKernel.dumpStats(printLine);
ZeroKernel.dumpTasks(printLine);
ZeroKernel.dumpTrace(printLine);

8. Gate tasks by capability when you need subsystem control

zerokernel::Kernel::TaskConfig wifiTask = {
    "WiFiNode",
    pollWifi,
    100,
    0,
    0,
    zerokernel::Kernel::kPriorityHigh,
    true,
    {},
    zerokernel::Kernel::kCapNetwork | zerokernel::Kernel::kCapTelemetry};

ZeroKernel.addTask(wifiTask);
ZeroKernel.disableCapabilities(zerokernel::Kernel::kCapNetwork);
// WiFiNode will stay registered but will not be scheduled until the capability is re-enabled.

Minimal full sketch

#include <ZeroKernel.h>

void readSensor() {
  // Non-blocking work only.
}

void setup() {
  ZeroKernel.begin(millis);
  ZeroKernel.addTask("SensorReader", readSensor, 500, 10);
}

void loop() {
  ZeroKernel.tick();
}

Higher-Intent Demo Projects

Recommended realistic network workload:

  • examples/RealProjectNode: a portable node-style workload that simulates sensor sampling, WiFi link maintenance, HTTP delivery, MQTT delivery, queue pressure, and realistic intermittent transport failures. Latest ESP32 hardware reference: REAL_PROJECT_NODE window_ms=10010 sample_runs=100 fast_avg_lag_us=0 fast_max_lag_us=0 fast_miss=0 link_up=1 wifi_attempts=2 reconnects=1 http_ok=33 http_fail=5 http_rate=86 mqtt_ok=32 mqtt_fail=4 mqtt_rate=88 http_queue=0 mqtt_queue=1

  • examples/ESP32TelemetryNode: a richer ESP32 node example with WiFi maintenance, capability-gated diagnostics, heartbeat events, and periodic runtime summaries.

  • examples/ESP32TelemetryBaseline: a manual-loop baseline for the same ESP32 telemetry workload so timing overhead can be compared fairly.

  • examples/FaultInjectionDemo: a fault-focused demo that injects overruns, exposes watchdog signals, enters safe mode, and then returns to normal operation.

  • examples/FaultInjectionBaseline: a manual-loop baseline for the same fault-focused workload.

Quick runners:

  • scripts/run_esp32_real_project_demo.sh /dev/ttyUSB1
  • scripts/run_esp32_telemetry_demo.sh /dev/ttyUSB1
  • scripts/run_esp32_telemetry_compare.sh /dev/ttyUSB1
  • scripts/run_fault_injection_demo.sh /dev/ttyUSB0
  • scripts/run_fault_injection_compare.sh /dev/ttyUSB0

Validation Pipeline

ZeroKernel already includes local and hardware validation:

  • Desktop regression suite
  • Lean profile smoke test
  • Desktop benchmark with optional performance gate
  • Cross-target compile and resource matrix with budget gates
  • Wemos before/after compare with determinism gate
  • ESP32 before/after compare with determinism gate
  • Wemos diagnostics and level-2 stress with automatic firmware restore

Main scripts:

  • scripts/run_desktop_tests.sh
  • scripts/run_desktop_lean_smoke.sh
  • scripts/run_desktop_benchmark.sh --enforce-performance
  • scripts/run_resource_matrix.sh --enforce-budget
  • scripts/run_wemos_compare.sh /dev/ttyUSB0 --enforce-determinism
  • scripts/run_esp32_compare.sh /dev/ttyUSB1
  • scripts/run_full_audit.sh /dev/ttyUSB0

Build Profiles

The runtime can be tuned at compile time through ZeroKernelConfig.h and project-level macros.

Key profiles:

  • ZEROKERNEL_PROFILE_TINY
  • ZEROKERNEL_PROFILE_MINIMAL_RUNTIME
  • ZEROKERNEL_PROFILE_POWER_SAVE
  • ZEROKERNEL_PROFILE_LEAN_NET
  • ZEROKERNEL_PROFILE_NETWORK_NODE
  • ZEROKERNEL_PROFILE_EXTENDED
  • ZEROKERNEL_PROFILE_DIAGNOSTIC

Important lean-build switches:

  • ZEROKERNEL_ENABLE_LEGACY_LABEL_API
  • ZEROKERNEL_ENABLE_TOPIC_KEY_ONLY
  • ZEROKERNEL_ENABLE_EXTENDED_TASK_METRICS
  • ZEROKERNEL_ENABLE_DIAGNOSTICS
  • ZEROKERNEL_ENABLE_CAPABILITIES

ZEROKERNEL_ENABLE_CAPABILITIES stays enabled in full profiles and is compiled out in POWER_SAVE and MINIMAL_RUNTIME, so lean targets do not pay extra static RAM for capability state.

ZEROKERNEL_PROFILE_NETWORK_NODE biases the runtime toward WiFi/BLE/MQTT-style firmware: key-first routing, bounded command/work queues, stronger drain budgets, and leaner metadata by default. ZEROKERNEL_PROFILE_LEAN_NET pushes harder on that same direction for module-heavy nodes: smaller queue defaults, stripped diagnostics, topic-key routing, and tighter runtime state for optional network helpers.

  • ZEROKERNEL_PROFILE_TINY now also defaults to key-first routing and stripped extended task metrics, so the name better matches the footprint target.
  • ZEROKERNEL_PROFILE_NETWORK_NODE now keeps capability gating enabled, which aligns the profile with network-aware runtime supervision.
  • ZEROKERNEL_ENABLE_DEBUG_DUMP

For small builds, the goal is to preserve the public API while collapsing runtime cost toward key-based routing and stripped diagnostics.

Reliability Model

ZeroKernel is built around explicit runtime constraints:

  • No dynamic allocation in the active runtime path
  • Fixed-capacity scheduler, queues, and trace buffers
  • Non-blocking task callbacks only
  • Bounded drain and backpressure policies
  • Fault containment through watchdog supervision, recovery, safe mode, and panic routing
  • Architecture-specific low-level instructions remain isolated to internal or adapter layers

Open Source Direction

ZeroKernel is structured to work well as an open-core infrastructure project:

  • Open source: kernel core, scheduler, runtime, adapters, validation tooling
  • Private / future commercial layers: higher-level deployment, cloud diagnostics, analytics, and enterprise integrations

The repository is now set up as a serious infrastructure codebase, not an Arduino toy project.

Project Layout

ZeroKernel/
  src/
    core/
    diagnostics/
    internal/
    adapters/
  examples/
  tests/
  benchmarks/
  docs/
  scripts/

Key files:

About

Small Bits. Solid Systems. ZeroKernel is the NanoKernel-style embedded orchestration engine built by ZeroBits for microcontrollers that need deterministic behavior without the weight of a full RTOS.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors