https://github.com/bleugreen/lnp2
Rust Server PNP
https://github.com/bleugreen/lnp2
Last synced: 3 months ago
JSON representation
Rust Server PNP
- Host: GitHub
- URL: https://github.com/bleugreen/lnp2
- Owner: bleugreen
- Created: 2026-03-07T06:13:03.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-03-08T02:29:23.000Z (4 months ago)
- Last Synced: 2026-03-08T06:32:56.639Z (4 months ago)
- Language: Rust
- Size: 128 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# lnp2
Look N Pick N Look N Place
Single-binary pick-and-place machine controller for LumenPnP. Replaces OpenPnP with a Rust backend and Svelte frontend — owns serial, motion, cameras, vision, feeders, and serves everything over HTTP.
## Quick Start
```bash
# Build
cargo build --release
cd web && npm install && npx vite build && cd ..
# Run
./target/release/lnp2 serve --config config/
```
Server starts on `0.0.0.0:3000` — open in a browser for the control UI.
## Architecture
```
lnp2 binary
├── Serial (GCode) ─────→ Marlin firmware (Rambo board)
│ ├── Motion 5-axis: XY gantry, Z, A/B rotation
│ ├── Actuators Vacuum, blow-off, LED, I2C sensors
│ └── RS-485 bus Photon Smart Feeder protocol
│
├── Cameras (V4L2) ─────→ Top (down-looking) + Bottom (up-looking)
│ ├── MJPEG capture 15fps, turbojpeg lossless flip
│ ├── Auto-exposure v4l2 brightness tracking
│ └── WebSocket stream Binary frames to browser
│
├── Vision ─────────────→ OpenCV + ONNX Runtime (YOLOv8)
│ ├── Pocket detection Locate feeder slots (ML or CV fallback)
│ ├── Fiducial detection PCB alignment markers
│ └── Part alignment Pad-level rotation correction
│
└── Web UI (Svelte) ────→ Served from web/dist/
├── Live camera view Canvas + crosshair + ML overlay
├── Click-to-move Pixel → mm via camera calibration
├── Jog controls Step/feedrate, keyboard shortcuts
└── Actuator panel Vacuum, blow, LED
```
## CLI Commands
```bash
lnp2 serve --config config/ # Start server (default)
lnp2 import --from ~/.openpnp2 --to config/ # Import OpenPnP XML → TOML
lnp2 scan --config config/ # Discover feeders on RS-485 bus
lnp2 feed --config config/ --slot 3 # Test-feed a single slot
```
## API
### Motion & Actuators
| Method | Path | Description |
|--------|------|-------------|
| POST | `/api/gcode` | Send raw GCode command |
| POST | `/api/gcode/batch` | Send multiple GCode commands |
| POST | `/api/move` | Move to coordinates (x, y, z, a, b, feedrate) |
| POST | `/api/move/safe` | Safe XY move (retracts Z first) |
| POST | `/api/home` | Home all axes |
| GET | `/api/position` | Get current position |
| POST | `/api/acceleration` | Set acceleration |
| POST | `/api/vacuum` | Vacuum on/off (nozzle, action) |
| GET | `/api/vacuum/read` | Read vacuum sensor |
| POST | `/api/blow` | Blow-off pulse (nozzle, duration_ms) |
| POST | `/api/led` | LED control (r, g, b, brightness, off) |
### Camera & Vision
| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/camera/list` | List cameras and configs |
| GET | `/api/camera/capture` | Single JPEG frame |
| WS | `/api/camera/stream?name=top` | Live MJPEG WebSocket stream |
| POST | `/api/vision/detect_all` | Run YOLOv8 inference, return detections |
| POST | `/api/vision/detect_pocket` | Detect feeder pocket, return mm offset |
| POST | `/api/vision/detect_fiducial` | Detect PCB fiducial marker |
| POST | `/api/vision/align_part` | Pad-level part alignment |
### Config & Data
| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/config` | Get machine config |
| PUT | `/api/config` | Update machine config (hot-reload) |
| POST | `/api/dataset/capture` | Save labeled frame for ML training |
| GET | `/api/dataset/count` | Count captured images |
### WebSocket Events
`/api/events` streams JSON position updates and state changes:
```json
{"type": "Position", "x": 10.5, "y": 20.3, "z": 15.0, "a": 0, "b": 0}
```
## Configuration
All machine parameters live in `config/*.toml`:
| File | Contents |
|------|----------|
| `machine.toml` | Serial port, axes, nozzles, cameras, LEDs, vision models |
| `feeders.toml` | Feeder definitions (Photon slots, tray positions) |
| `parts.toml` | Part library (package, speed, value) |
| `packages.toml` | Package footprints (pads, body dimensions) |
| `nozzle_tips.toml` | Tip changer waypoint sequences |
Use `lnp2 import` to convert an existing OpenPnP configuration.
## Build Dependencies
Rust crate dependencies are handled by Cargo. System libraries needed on the target:
- `libopencv-dev` — image processing and classical CV
- `libturbojpeg0-dev` — lossless JPEG transforms
- `nasm` + `cmake` — for building turbojpeg from source
- ONNX Runtime — loaded dynamically via `ort` (set `ORT_DYLIB_PATH` if needed)
## Deploy
Deployment uses [just](https://github.com/casey/just) recipes to sync, build, and manage the service on `lumeneer.local`.
```bash
just setup # One-time remote setup (install deps, create dirs, enable service)
just check # Verify remote environment (toolchain, libs, disk)
just build # Sync source + cargo build --release on remote
just build-web # Sync source + npm install + vite build on remote
just deploy # Build all + copy to production dir + restart systemd service
just deploy-rust # Binary-only deploy (skip web build)
just run # Build + run server in foreground (for dev/debug)
just logs # Follow journalctl output
just status # Show systemd service status
just watch # Auto-sync on file save (requires fswatch)
just ssh # SSH into remote build dir
just builds # List remote build dirs with disk usage
just clean # Remove a remote build dir
```
The remote uses per-branch build dirs (`~/lnp2/builds//`) and a single production dir (`~/lnp2/production/`) managed by a systemd service (`remote/lnp2.service`).