JumpStation Studio is the JumpStation integrated development environment — a Linux application that provides a single, consistent interface for writing, running, and deploying projects that span a Linux host and one or more attached physical devices.
It runs on any JumpStation-class Linux host:
| Platform | Physical device interface |
|---|---|
| JumpStation (CM5 / RK3588S2) | GPIO breakout adapter → direct GPIO, I2C, SPI, UART |
| JumpStation Turbo (CM5 / RK3588S2 + DX-M1) | Same as base + accelerated profiling |
| Arduino UNO Q | STM32U585 MCU → USB-CDC serial bridge |
| Any Linux host with a serial-attached device | Serial bridge transport |
The key design principle: app code does not know which transport is underneath. A project written on a CM5 with a GPIO breakout adapter runs unchanged on a UNO Q with an STM32 MCU — the DeviceBus abstraction handles the difference.
Arduino App Lab (preloaded on the UNO Q) provides a similar unified interface for Arduino sketch + Python development. JumpStation Studio replaces it with:
| Arduino App Lab | JumpStation Studio | |
|---|---|---|
| Platform | UNO Q only | Any JumpStation Linux host |
| Hardware abstraction | Platform-specific | Unified DeviceBus API |
| AI integration | Pre-loaded models | Full targeting + distillation pipeline |
| Deployment target | UNO Q local only | Any device in the spectrum via JumpBundle |
| Model source | Arduino App Lab catalog | Bring your own + JumpStation targeting |
| Sketch language | Arduino C/C++ | Arduino C/C++ + Python (MCU firmware optional) |
A Studio Project is the unit of development. It contains up to three layers:
my_project/
├── studio.json # Project manifest
├── app.py # Python application (Linux / MPU side)
├── sketch/ # Optional: Arduino sketch (MCU / real-time side)
│ └── sketch.ino
└── model/ # Optional: AI model (JumpBundle model layer)
└── weights.tflite
studio.json declares:
app.py)When a project is ready to deploy, Studio hands it off to the JumpBundle builder, which packages it as a .jbundle targeting the appropriate device class.
The DeviceBus is the unified hardware abstraction layer. Application code imports one API regardless of the physical transport underneath.
from core.studio.device_bus import DeviceBus
bus = DeviceBus.detect() # Auto-detects transport from host platform
bus.digital_write(pin=13, value=1)
reading = bus.analog_read(pin=0)
bus.i2c_write(addr=0x48, data=bytes([0x01, 0x00]))
bus.on_interrupt(pin=2, edge="rising", callback=my_handler)
| Transport | Used when | Backend |
|---|---|---|
GpioTransport |
CM5 / RK3588S2 with breakout adapter | libgpiod (Linux GPIO character device) |
SerialBridgeTransport |
UNO Q (STM32U585) or any serial-attached MCU | USB-CDC / UART serial protocol |
SimulatedTransport |
No hardware attached (CI, unit testing) | In-process state machine |
The transport is selected automatically by DeviceBus.detect() based on the host platform. It can also be specified explicitly:
from core.studio.transports import SerialBridgeTransport
bus = DeviceBus(transport=SerialBridgeTransport(port="/dev/ttyACM0", baud=115200))
| Method | Description |
|---|---|
digital_read(pin) |
Read digital high/low from a pin |
digital_write(pin, value) |
Set a digital pin high or low |
analog_read(pin) |
Read ADC value (0–1023 normalized to 0.0–1.0) |
pwm_write(pin, duty, freq) |
Write PWM signal to a pin |
i2c_read(addr, n_bytes) |
Read N bytes from an I2C device |
i2c_write(addr, data) |
Write bytes to an I2C device |
spi_transfer(data) |
Full-duplex SPI byte exchange |
uart_read(n_bytes) |
Read from UART |
uart_write(data) |
Write to UART |
on_interrupt(pin, edge, callback) |
Register a pin-change interrupt handler |
close() |
Release the transport cleanly |
When the SerialBridgeTransport is active (UNO Q or serial-attached MCU), Studio communicates with the MCU using a lightweight protocol over USB-CDC:
Host → MCU: [CMD][PIN][DATA...]
MCU → Host: [STATUS][DATA...]
Command bytes map directly to the DeviceBus API surface. The MCU-side firmware (a minimal Arduino sketch flashed once at first boot) decodes these commands and executes them against the real-time environment, returning results synchronously.
This means: the MCU does not run application logic. It is a hardware bridge. Application logic lives entirely on the Linux side. This is the opposite of the Arduino App Lab model, where the sketch and Python share application responsibility.
For applications that genuinely require real-time MCU execution (tight timing loops, hardware PWM precision, interrupt-driven protocols), Studio supports a sketch component in the project — a full Arduino sketch that runs on the MCU alongside the bridge firmware. The host communicates with both layers.
From within Studio, once the project is working on the development host, the targeting workflow determines where it ultimately lives:
The application logic is suitable for a Pico, ESP32, or UNO Q. The targeting suite compresses the model, rewrites the entry point for the target runtime, and packages a JumpBundle.
jumpstation target --project my_project/ --calibration data/
# → TargetDeclaration: device_class=pico, backend=tflite_micro
jumpstation bundle --project my_project/ --target pico
# → dist/my_project_pico.jbundle
The JumpStation, JumpStation Turbo, or UNO Q is the deployed device. The JumpBundle packages the full Linux application for installation on a target host.
jumpstation bundle --project my_project/ --target uno_q
# → dist/my_project_uno_q.jbundle (deploys as Linux package + optional sketch)
Both paths produce a JumpBundle. The targeting suite determines which path is appropriate.
core/studio/
├── __init__.py
├── device_bus.py # DeviceBus class + Transport ABC
├── transports.py # GpioTransport, SerialBridgeTransport, SimulatedTransport
├── project.py # StudioProject dataclass + studio.json loader/validator
└── runner.py # run(), deploy(), flash_sketch(), attach_device()