Skip to content

aklofas/urbi-embedded

Repository files navigation

urbi-embedded

ci

An embeddable orchestration scripting language for robotics and physical systems, in pure C99.

Implements urbiscript — a prototype-based, parallel-by-default, event-driven language designed for coordinating sensors, actuators, and reactive control loops on fast underlying code. Sits above C/C++ control loops the way Lua sits above game engines: handles concurrency, time, events, and cancellation as first-class primitives instead of patterns the developer has to construct by hand.

Status: release candidate, tagged v0.13.6-consistency — a final pre-release hardening pass is in progress before the stable freeze. The language is complete — separators-encode-concurrency (; | , &), the reactive trio (at / whenever / waituntil), first-class tags with stop / block / freeze, prototype OOP, and try / catch / finally — backed by a tracing-free bytecode VM, incremental tri-color GC, and a cooperative scheduler with a 4-state urbi_step driver. ROS2 integration ships via a host rcl/Fast-DDS backend (with a documented micro-ROS-on-MCU path). Conformance: ~80–85% of the in-scope legacy urbiscript 2.x surface, 100% pass-rate on the implemented surface — see docs/release/conformance-report.md for the coverage breakdown and the intentional divergences. ABI 0/23/7, freezing to 1/0/0 at the stable tag; wire v1.9 / 0x19.

30-second quickstart

make                                     # build liburbi.a + the urbi binary
echo "1 + 2" | ./build/host/urbi -i      # -> [..........] 3
./build/host/urbi -i                     # interactive REPL

Embedding a VM in your own C program is one header and a handful of calls — see the embedding guide. Porting to a new MCU is covered by the ports guide and the worked ports under examples/ (Pico, ESP32-S3, STM32F4); a fresh clone builds all three via make clone-build-demo-check (see docs/release/clone-build-demo.md).

Design goals

  • Pure C99, single library, zero external dependencies
  • Builds with make — no CMake, no autotools, no bootstrap
  • Target footprint: < 400 KB flash on Cortex-M class MCUs
  • Host-pluggable allocator, I/O sink, time source, panic handler
  • No global state — multiple VM instances coexist, fully isolated
  • Bytecode / source split: embedded targets can omit the compiler
  • BSD-3-Clause throughout

Supported targets

Target Status CI gate Runtime smoke Hardware evidence
Linux x86_64 (host) shipped host-test matrix n/a n/a
Raspberry Pi Pico (RP2040 / Cortex-M0+) shipped cross-pico + cross-pico-repl none yes — see docs/release/hardware-validation.md
ESP32-S3 (Xtensa LX7, ESP-IDF v6.0.1) shipped cross-esp32s3 none yes — eye_demo bring-up
STM32F4 (Cortex-M4F) shipped cross-stm32f4 none yes — Mandelbrot demo
ARM Cortex-M7 (generic) shipped cross-arm none n/a — archive build only
RISC-V rv32imc (generic) shipped cross-riscv none n/a — archive build only
STM32H7 planned n/a n/a n/a — see ROADMAP
ESP32-C3 planned n/a n/a n/a — see ROADMAP

Build

make

Produces build/host/liburbi.a. All build variants (release, debug, sanitizers, cross-compiles) land in build/<TARGET>/ subtrees — see CONTRIBUTING.md for the full list. The public API is spread across <urbi/types.h>, <urbi/urbi.h>, <urbi/gc.h>, <urbi/sched.h>, and <urbi/object.h> — VM lifecycle, chunk loading, strand spawn / step driver, ISR-safe event injection, realm globals, GC primitives, and the object surface. The headers are self-contained: external consumers using only -Iinclude resolve cleanly without internal includes. See docs/embedding-guide.md for the full embedding contract (host integration patterns, FreeRTOS pattern, REPL service).

Using the REPL

Build the urbi binary:

make urbi-bin   # produces build/host/urbi

Interactive session:

./build/host/urbi -i
1 + 2
[00000001] 3
5 / 2
[00000012] 2.5

Evaluate a single expression:

./build/host/urbi -e "1 + 2"
3

Run a script:

./build/host/urbi script.urb

Disassemble:

./build/host/urbi --dump-bytecode -e "1 + 2 * 3"

See ./build/host/urbi --help for the full flag list.

REPL service

Opt-in subsystem (build with URBI_ENABLE_REPL=1): NDJSON line-protocol REPL over TCP / Unix socket / UART, with bearer-token auth, per-session output isolation, and 9 introspection ops. Builds two extra host binaries: urbi-server (headless) and urbi-send (client).

Build:

make URBI_ENABLE_REPL=1            # liburbi.a with REPL support
make urbi-server-bin URBI_ENABLE_REPL=1  # build/host/urbi-server
make urbi-send-bin   URBI_ENABLE_REPL=1  # build/host/urbi-send

Start a server on loopback (no token needed):

./build/host/urbi-server --port 54000

From a second shell, send one-shot ops:

./build/host/urbi-send eval "1 + 2"             # → 3
./build/host/urbi-send introspect coros         # → JSON list of strands
./build/host/urbi-send --tail eval "every(1s) { echo 'tick' }"

Exposing the server on a LAN interface requires --token:

./build/host/urbi-server --bind 0.0.0.0 --port 54000 --token "$(openssl rand -hex 16)"
./build/host/urbi-send --host robot.local:54000 --token "$TOK" eval "Robot.battery"

Embedders can also combine local linenoise REPL + network service in one process via the urbi --listen flag, or start the service programmatically with urbi_repl_serve from <urbi/repl.h>. See docs/embedding-guide.md §12 (REPL Service) and docs/internals/repl-service.md for the full API + wire-protocol reference.

Source layout

include/urbi/   public C API headers (urbi.h, gc.h, sched.h, object.h, ...)
src/
├── chunk/      bytecode + UProto + UChunkIO
├── emit/       compiler emit
├── event/      UEvent + native event registration
├── gc/         incremental GC + barriers
├── lex/        lexer
├── object/     UObject + UShape + UIC + UChunkInstance
├── parse/      parser
├── realm/      URealm + lobby + per-realm globals
├── repl/       REPL service + transports + listener
├── runtime/    UCallFrame + UUpvalCell + unwind + cleanup
├── sched/      cooperative scheduler + UStrand
├── stdlib/     baked stdlib + Object/List/Dict/etc.
├── tag/        UTag
├── value/      UValue + intern + arena
├── vm/         dispatch loop + OP_* handlers
└── watcher/    UWatcher + install/eval/drain/spawn
tools/          host binaries (urbi, urbi-server, urbi-send) + vendored linenoise

Subsystem-directory layout under src/; each subsystem is a self-contained set of translation units. The tools/ directory contains host binaries and vendored linenoise — neither is part of liburbi.a.

Documentation

  • CONTRIBUTING.md — build, test, cross-compile, and contribution how-tos
  • docs/STYLE.md — code-level style decisions (naming, const-correctness, error model, initialization, headers, tests)

License

BSD-3-Clause. See LICENSE.

About

New embeddable urbiscript in pure C99 for robotics and physical systems.

Resources

License

Contributing

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors