Open UI controller firmware for DIY motorized camera sliders — MicroPython on a Raspberry Pi Pico (or compact RP2040-Zero), built to shoot, not to demo.
SliderCtrl is the UI controller (UIC) side of an open motorized camera slider system. It gives operators a laptop-free panel on set — analogue knobs, muscle-memory buttons, OLED status, and camera trigger — instead of juggling phone apps mid-take.
You bring the rail, motor, and housing. The firmware and on-set workflow aim at behaviour comparable to expensive commercial motorized sliders: live retarget, smooth ramps, marks and loops, timelapse, STOP / EMO, and hard-limit homing. Mechanics quality depends on your build — the motion stack and panel UX are designed to keep up.
Motion runs on a separate board: SliderMC (STEP/DIR motors, optional RC servos, planner, limits; welcome # MC V1 - …, protocol VP:1). Docs and manuals live in SliderDoc. Optionally extra STEP/DIR motors (typical slider travel + pan) are time-synced with the first — CS motors 2 (or 3); MC_Client already speaks packed channels. Do not send CS axis.
Documentation: SliderDoc
DIY project, pro-set manners. Open MicroPython panel firmware talks to a dedicated motion controller over UART. Control feel, safety interlocks, and motion firmware are meant to stand alongside commercial units — your rail, driver, and enclosure are yours to spec.
Easy on set. Ready for every take.
- Set-first panel — no phone required; analogue SPEED / ACCEL; STOP / EMO / soft and hard limits
- Feel the move — live retarget · sine-smooth ramps · tap/hold MOVE cruise · FAST jog · optional joystick
- Production moves — Pos A / B / C with power-off recall · pair loops · DELAY walk-ins · TIMELAPSE dividers · pause / resume
- Eyes-off status — I2C OLED (SSD1306 / SH1106 / SSD1309) · RGB LED · optional NeoPixel (same colours)
- Open stack — edit
SliderPins.py, Thonny / REPL workflow · fork the panel or build onMC_Client/UIC_Base· or use the stack as a construction kit for custom 1- or 2-axis rigs - Optional extra motors — linear travel + time-synced pan/tilt; SliderMC
CS motors 2(or3);MC_ClientpackedmoveTo/home. Banner is{motors}+{servos} axis. JKSlider and B4Slider select packed axes 1–6 (getAxisCount()); JKSlider marks stay axis 1 - Split architecture — OLED, keypad, and pots never steal STEP timing (SliderMC owns motion)
- Maker-friendly — upcycle rails and linear units · A4988, DRV8825, TMC, and other STEP/DIR drivers
How this compares to commercial motorized sliders: architecture/compare.md.
The stack is a software and electronics construction kit — turnkey panel faces on the same motion firmware, or your own mix of libs and wiring. Pick the panel that fits your shoot and enclosure, or aim the same parts at a mini-dolly, rotating head, turntable, or a slider + pan (2-axis) custom UI.
| Project | Purpose | When to use | Entry |
|---|---|---|---|
| JKSlider | Full motorized camera slider panel — keypad or discrete buttons, SPEED/ACCEL pots, OLED, marks A/B/C, timelapse, DELAY | Default for interviews, product, B-roll, and any shoot that needs the full feature set | JKSlider.py · user manual |
| B4Slider | Minimal AXIS-select remote — MOVE L/R, SET, OPTION, AXIS_1..6, SPEED pot or rotary | Slim handheld or multi-axis kits (typical silk 1/2/3); working-window A/B, no keypad/timelapse | B4Slider.py · user manual |
| More coming | Additional UIC apps on the same MC_Client / UART protocol |
Custom rigs and new panel ideas | project template |
Under the hood, all projects share MC_Client + UIC_Base — kit libraries for your own feature-rich motorized camera slider UI, mini-dolly, rotating head, turntable, 2-axis slider + pan, or other STEP/DIR rig.
UIC panel I/O on one Pico, motion (STEP/DIR, home, limits) on SliderMC, linked by UART.
Why two boards
- Dedicated motion MCU — display redraws, keypad scans, and optional WLAN never steal STEP timing
- MicroPython + AsyncIO on the UIC — easy panel iteration; Thonny / REPL DIY workflow
- Replaceable panel face — same motion board, different UIC project or fork
- Handheld wired remote — UIC in hand, MC by the driver and PSU; 4-wire cable (5 V, GND, TX, RX)
- Build and debug panel and axis separately
Trade-off: a second Pico (~€5), a little more wiring. Philosophy and pinouts: architecture/overview.md.
| UIC may connect | MC may connect |
|---|---|
| Buttons, keypads, OLED, RGB/NeoPixel, pots, joysticks, camera | Motor / STEP·DIR driver, home switch, hard limits, Ext, DRV_ERROR |
| Optional WLAN, USB debug, UART → MC | USB debug, UART → UIC |
SliderMC motion pinout: mc/pins.md · MC_Pico_pinout.png
- Flash MicroPython onto the UIC Pico (or matching UF2 for an RP2040-Zero). Flash SliderMC onto the motion Pico.
- Wire crossed UART (GP16/17 both sides, shared GND) — link and handshake.
- Copy
SliderPins.example.py→SliderPins.pyand edit that file only — config · panel. - Copy project files to the UIC (Thonny or
mpremote) — bring-up. - Run the panel:
import JKSlider
JKSlider.run()await start() unlocks the MC with \n and expects the welcome banner (retry 100 ms, 3 s). If the MC is missing, the UIC prints a timeout on USB/REPL and continues without motion.
Or try the motion library alone:
import SimpleExample
SimpleExample.run()More: Technical manual · Protocol · Hardware / mechanics
| Topic | Document |
|---|---|
| Architecture | architecture/overview.md |
| JKSlider install | uic/projects/jkslider/technical/ |
| UIC API | uic/api/overview.md |
| Protocol | contract/protocol.md |
| MC build | mc/build.md |
Beyond turnkey panels, treat JKSlider, B4Slider, MC_Client, and UIC_Base as kit parts — fork a face, strip features, or wire a new enclosure for a one-off slider, mini-dolly, rotating head, or turntable.
Compose a UART motion client (MC_Client) with local UI (UIC_Base) on the UIC Pico: millimetre API to SliderMC, soft and hard limits, EMO, RGB / NeoPixel / OLED. STEP/DIR generation runs on the motion Pico. Optional 2-axis (typical linear + pan, time-synced) is on the same client.
JKSlider and B4Slider are applications on top — use the libraries when you want a custom UI, scripted moves, or the next panel face.
import uasyncio as asyncio
from MC_client import MC_Client
from UIC_base import UIC_Base
async def main():
mc = MC_Client()
ui = UIC_Base()
mc.set_axis_status_callback(ui.on_axis_status)
await mc.start()
await ui.start()
mc.enable(True)
mc.setSpeed(40)
mc.setAcceleration(150)
mc.home()
await mc.wait()
mc.moveTo(100)
await mc.wait()
mc.move(-25)
await asyncio.sleep(2)
mc.stop()
await mc.wait()
mc.enable(False)
asyncio.run(main())Optional 2-motor (typical motor 1 = linear, motor 2 = pan): dual MT/M is time-synced, not CNC. mc.getMotorCount() / mc.motors come from CG motors; packed axis_count / getAxisCount() is motors+servos (CG axis). Verbose #… is one line: axis-1 fields, then | and the same 1-axis schema (#M 12.5 25 0 100 | 67.8 5 25 90; idle 0 may elide as ||). Panels register set_axis_status_callback (cb(axis, state, pos, speed, accel, dest)); UIC_Base follows setOledAxis (lowest selected on the panels). Use moveTo(pos, pos2), moveTo(None, pos2) → MT _ pos2, home(2), packed jog / moveJoy. Envelopes: MOTOR_N_min/max (Python slider_min is packed channel 1).
| Idea | Entry point |
|---|---|
| Point-to-point demo | SimpleExample.py |
| Pot → velocity | JoystickExample.py |
| Full camera panel | JKSlider.py |
| Minimal AXIS-select panel | B4Slider.py |
| API reference | uic/api/overview.md |
Copy SliderPins.example.py → SliderPins.py and edit that file only for your hardware.
Base (all sliders)
- Raspberry Pi Pico (RP2040), Pico W, or RP2040-Zero
- MicroPython with
rp2.PIOanduasyncio - External STEP/DIR motor driver + SliderMC motion board
- Motorized camera slider mechanics — hardware manual
JKSlider
- Buttons or keypad (3×4 default, optional 4×4 col4 = AXIS_1..4) · pots for SPEED and ACCEL · RGB LED · OLED · optional dual joystick
- Pico AXIS_1..4 = GP21..18 (AXIS_5/6 unwired); JOYSTICK_1 = GP28; keypad OPTION = GP14
- Zero AXIS_1..6 = GP23..18; JOYSTICK_1/2 = GP28/GP29
- Camera shutter is SliderMC
CT/PIN_CAMERA_CTRL(not a UIC GPIO)
B4Slider
- AXIS_1..6 (Pico GP12/11/10/9/8/22; Zero GP3..7/17) · MOVE_L/R · SET · OPTION · RGB LED · SPEED pot or rotary · optional ACCEL pot/rotary · optional OLED · boot homing motors only
- Camera shutter is SliderMC
CT(Pico GP22 is AXIS_6 on this panel)
Copyright (c) 2026 Jochen Krapf <jk@nerd2nerd.org>
Licensed under the MIT License.
Company names and product names mentioned in this project are trademarks or registered trademarks of their respective owners. Use here is for identification only.
ssd1306.py / sh1106.py / ssd1309.py are based on common MicroPython OLED patterns (SSD1306 lineage typically MIT). oledfont.py uses Adafruit GFX 5×7 font data (BSD-style upstream). Keep their notices if you redistribute those files alone.
