HivePaaS
Docker Swarm 기반 오픈소스 자체 호스팅 PaaS, SSL·백업·자동 확장 지원
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기ARM, Articulated Robotic Manipulator: a 6-DOF robot arm with 270° servos on an Arduino Uno and PCA9685. Joystick, keyboard, slider, IK and phone control, macros, live sync between controllers, RIFT fleet mode, and controllers in Python, C++, C#, Go, Rust and Julia.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗scripts/arm and scripts/center_first_motor are for the Arduino UNO and need the Adafruit PWM Servo Driver Library (Library Manager)Windows controller: builds/ARM-Controller.exe shows ARM's own web page in a window, so it always matches the page. Source: scripts/web_controller.
Keyboard on her web page: the same keys as her Python controller: A D, W S, R F, T G and Q E move a joint 5 degrees (1 with Shift), Space holds the claw shut, Home is her rest pose.
Website: https://cursedprograms.github.io/ARM-Robot-v01/
ARM is a six-joint robotic arm: an Arduino UNO drives six 270° servos through a PCA9685, and a controller on the PC talks to it over USB.
http://<PC>:5011/; the Windows controller shows that same page in a window.5011, so the dashboard can drive her too.config.json; the claw stays between 40 and 145°.| Component | Details |
|---|---|
| Microcontroller | Arduino Uno (scripts/arm/arm.ino, 115200 baud) |
| Servo driver | PCA9685 16-channel PWM driver, I2C address 0x40, 50 Hz |
| Servos | 6× 270° servos (claw limited to 40–145°) |
| Servo power | External 5–6 V supply to the PCA9685's V+ terminal (not the Uno's 5 V pin) |
| Controllers | USB joystick, keyboard, phone / browser, RIFT |
| Camera (Mind mode) | Any USB webcam pointed at the arm and the desk around it (--camera N) |
| Signal | Connection |
|---|---|
| PCA9685 SDA / SCL | Uno A4 / A5 |
| PCA9685 VCC / GND | Uno 5 V / GND |
| PCA9685 V+ | External servo supply (share GND with the Uno) |
| Buzzer + / − | Uno D8 / GND (passive buzzer - her voice in the fleet's conversations) |
| Motor 1 base | PCA9685 channel 0 |
| Motor 2 shoulder | channel 1 |
| Motor 3 elbow | channel 2 |
| Motor 4 wrist pitch | channel 3 |
| Motor 5 wrist roll | channel 4 |
| Motor 6 claw | channel 5 |
Channels, limits, rest angles and directions live in config.json.
[!NOTE] The arm's link lengths in
config.json(geometry) are still unmeasured placeholders, so IK mode can't be accurate yet. Measure them in millimetres and fill them in.
| Motor | 1 base | 2 shoulder | 3 elbow | 4 wrist pitch | 5 wrist roll | 6 claw |
|---|---|---|---|---|---|---|
| Rest angle | 135 | 55 | 100 | 230 | 135 | 40 (open) |
The arm goes to this pose:
arm.ino hears nothing for 2 s (controller closed or crashed, cable pulled), the arm eases back to rest.The values live in two places, so change both: rest in config.json (the controllers) and REST_ANGLE in scripts/arm/arm.ino (the Arduino, reflash after changing).
The same list opens in its own window: F1 in any of the controllers (Python, C++, C#, Rust, Go and Julia), or python scripts/keymap.py. They all take the keyboard, the joystick and a gamepad the same way, and notice a joystick or gamepad plugged in or out while they run. The C++ controller reads gamepads through XInput (Xbox pads, a Logitech F710 switched to X); the others go through SDL2, so PlayStation and Switch pads work there too. The other controllers' F1 window reads scripts/keymap.json: after changing the list in keymap.py, write it again with python scripts/keymap.py --json scripts/keymap.json.
Joystick (Joystick mode)
| Key | Does |
|---|---|
| Stick left / right (axis 0) | motor 1, base |
| Stick forward / back (axis 1) | motor 2, shoulder |
| Twist (axis 2) | motor 5, wrist roll |
| Hat up / down | motor 3, elbow: 5 degrees a press |
| Button 3 / button 2 | motor 4, wrist pitch: 5 degrees a press |
| Trigger (button 0) | motor 6, claw: a click closes / opens it (Hold position), or held = closed |
| Hold position (tick box) | ticked: the stick sets speed and letting go holds her where she is; unticked: the stick sets position and letting go sends her back to rest one joint at a time, wrist roll first (Python and C++ controllers; the others: centred = rest) |
| a held hat direction or button is one press; motors 3 and 4 stay where you stepped them | |
| every motor stays inside its min / max from config.json; invert flips its direction |
Gamepad (Joystick mode, when no joystick is plugged in)
| Key | Does |
|---|---|
| Left stick across / up-down | motor 1, base / motor 2, shoulder |
| Right stick across | motor 5, wrist roll |
| D-pad up / down | motor 3, elbow: 5 degrees a press |
| Y (3) / X (2) | motor 4, wrist pitch: 5 degrees a press |
| A (0) | motor 6, claw: like the trigger |
| a joystick always wins over a gamepad; plug either in any time |
Keyboard (every mode except IK; click the window first)
| Key | Does |
|---|---|
| A / D | motor 1, base: -5 / +5 degrees |
| W / S | motor 2, shoulder: up / down 5 degrees |
| R / F | motor 3, elbow: up / down 5 degrees |
| T / G | motor 4, wrist pitch: up / down 5 degrees |
| Q / E | motor 5, wrist roll: -5 / +5 degrees |
| Space | motor 6, claw: held = closed, released = open |
| Shift + any of those | 1 degree steps, for fine positioning |
| Home | every motor back to the rest pose |
| Mind (button) | her LLM mind picks things up: a colour button, a click on the camera, or type what (Python controller) |
| 1 - 9 | pick a macro |
| F1 | this window |
| Esc | quit |
| holding a key repeats it; in Joystick mode a key moves a stick motor until you move that stick again |
--connectconfig.json) and joint
maths (IK_controller.py): from the side (base, shoulder, elbow, wrist, claw, her reach as a circle) and
in 3D, starting from above: drag it to turn her. It follows every command. With no Arduino plugged in it's her emulator:
everything still works, and you see what she would do. Until kinematicZero is calibrated she draws her
rest pose as level.colour_scheme.xml; CUSTOM puts its colours in
scripts/controller_settings.json for you to change.~/.robot_minds/logs/ARM-<date>.log.scripts/arm_voice.ps1, so Windows only; ARM_VOICE=0 keeps her quiet). --ladder or FLEET_LADDER=1
joins the fleet's WiFi through scripts/fleet_ladder.py, so those two need Python. MIND stays with the
Python controller: mind.py is the fleet's one shared file. VOICE's on / off isn't saved on these five..bat, .ps1 and .sh (the C++ controller is a Windows program: its .sh says so).scripts/cpp_controller/ is a native Win32 rewrite of controller.py with the same four modes (Joystick/Sliders/IK/Fleet) and the same macro recording/playback, for anyone who'd rather run a standalone .exe than install Python/pygame. It reads the same config.json, records to the same scripts/macros/*.json, and its Fleet mode serves the same scripts/web/ control page and HTTP API - the two controllers are drop-in equivalents of each other.
build_cpp_controller.bat
cpp_controller.bat --list-ports
cpp_controller.bat --port COM6 --mode fleet
build_cpp_controller.bat compiles it with g++ (MinGW-w64; MSYS2's C:\msys64\ucrt64 comes first if it's installed, since an old GCC 6 MinGW can't build C++17) if found on PATH, falling back to CMake + MSVC otherwise, producing scripts/cpp_controller/build/controller.exe. It's linked statically, so it runs without MinGW's DLLs (picking up a mismatched libstdc++-6.dll from PATH, such as Git's, made it crash on start). It only depends on the Windows SDK (Win32, Winsock, winmm, XInput, SetupAPI) - no other libraries to install.
scripts/julia_controller/ is a Julia rewrite of controller.py, for anyone who'd rather use Julia than Python or C++. Same four modes (Joystick/Sliders/IK/Fleet), same macro recording/playback, same config.json/scripts/macros/*.json/scripts/web/ - a drop-in equivalent of the other two controllers. It draws its window with SDL2 (via SimpleDirectMediaLayer.jl, the same library pygame itself is built on) and talks to the Arduino over LibSerialPort.jl; Fleet mode's HTTP bridge is HTTP.jl.
julia_controller.bat --list-ports
julia_controller.bat --port COM6
julia_controller.bat --port COM6 --mode fleet
julia_controller.bat installs the Julia package dependencies on first run (Pkg.instantiate(), using scripts/julia_controller/Project.toml) and then launches controller.jl - no separate build step, same as the Python controller. Requires Julia on PATH.
scripts/csharp_controller/ is a C# / .NET 8 rewrite of controller.py that runs on both Windows and Linux. Same four modes (Joystick/Sliders/IK/Fleet), same macro recording/playback, same config.json/scripts/macros/*.json/scripts/web/ as the other controllers. The window is Avalonia (cross-platform, built in code rather than XAML), joystick input goes through SDL2 via Silk.NET.SDL (which bundles the native SDL2 library), serial is System.IO.Ports, and Fleet mode's HTTP bridge is Kestrel (ASP.NET Core), so it binds to the network without needing admin rights.
csharp_controller.bat --list-ports
csharp_controller.bat --port COM6
csharp_controller.bat --port COM6 --mode fleet
chmod +x csharp_controller.sh
./csharp_controller.sh --list-ports
./csharp_controller.sh --port /dev/ttyACM0
Requires the .NET 8 SDK; the launchers run it with dotnet run, which restores NuGet packages on first run.
Notes:
System.IO.Ports can't read USB device descriptions like pyserial does, so it asks every port WHO at once and uses the one that answers I am Arm (Finding the arm's port). If none answers, it falls back to a simpler guess: on Linux the first /dev/ttyACM*//dev/ttyUSB*, on Windows only when there's exactly one COM port. Otherwise pass --port.dialout group for serial access (sudo usermod -aG dialout $USER) and input for joystick access, then log out and back in.sudo apt install libsdl2-2.0-0).scripts/rust_controller/ is a Rust rewrite of controller.py for Windows and Linux: same four modes, macros, live sync and --connect client mode as the others, in one native executable. The window is egui (via eframe), serial is the serialport crate (USB descriptions are read, so --port auto-detects an Arduino/FTDI/CH340 like the Python version, preferring the port that answers I am Arm), and Fleet mode's HTTP server is tiny_http. There is no C library to build against: SDL2 is loaded at runtime just for the joystick, so if it isn't found the controller still runs with Joystick mode disabled.
rust_controller.bat --list-ports
rust_controller.bat --port COM6 --serve
chmod +x rust_controller.sh
./rust_controller.sh --port /dev/ttyACM0 --serve
Requires Rust (the first build downloads and compiles the dependencies, which takes a few minutes). Joystick support needs the SDL2 shared library: on Windows put SDL2.dll (from the SDL2 releases, SDL2-2.x.x-win32-x64.zip) next to the built arm_controller.exe or anywhere on PATH; on Linux sudo apt install libsdl2-2.0-0. Linux serial/joystick permissions are the same as for the C# controller (dialout and input groups).
scripts/go_controller/ is a Go rewrite of controller.py for Windows and Linux with the same four modes, macros, live sync and --connect client mode as the others. The window is Fyne, serial is go.bug.st/serial (USB descriptions are read, so --port auto-detects an Arduino/FTDI/CH340, preferring the port that answers I am Arm), and Fleet mode's HTTP server is the standard library's net/http. SDL2 is loaded at runtime (via purego, no cgo for that part) just for the joystick, so a missing SDL2 only disables Joystick mode.
go_controller.bat --list-ports
go_controller.bat --port COM6 --serve
chmod +x go_controller.sh
./go_controller.sh --port /dev/ttyACM0 --serve
Requires Go and, because Fyne uses cgo, a C compiler (Windows: winget install BrechtSanders.WinLibs.POSIX.UCRT; Linux: sudo apt install gcc libgl1-mesa-dev xorg-dev). The first build downloads and compiles Fyne, which takes a few minutes. Joystick support needs the SDL2 shared library, same as the Rust controller (Windows: SDL2.dll next to the executable or on PATH; Linux: sudo apt install libsdl2-2.0-0).
The Mind button (Python controller) hands the arm to her LLM mind: she looks, thinks out loud on screen, says what she's doing in her own voice (patient, dry, Zira slow and low), moves a joint, and remembers. Only on an x86 PC with 8 GB+ RAM and a GTX 1050 or better (mind.py checks), with Ollama's qwen3 (sized to the GPU) and a vision model (gemma3).
--camera N, default 0). The vision model lists what's in the picture and she decides from that list whether her arm is there. (Asked "is there a robot arm?", a small vision model says yes to a dark frame or an empty desk, so it's never asked that.)Requires opencv-python (in requirements.txt) and a USB webcam.
Nothing here needs a hard-coded COM port. scripts/arm/arm.ino answers a one-word question, so a controller can find the arm by asking:
PC: WHO
COM6: I am Arm
Every controller does this when you leave out --port: it opens each port (the compiled controllers only try ports that look like Arduino adapters) at 115200 baud, waits about 2 seconds for the board to reset, sends WHO, and uses the port that answers I am Arm. If none answers it falls back to the old guess (the first port whose description looks like an Arduino, CH340, CP210x or FTDI adapter). --port COM6 still overrides all of it, and --list-ports lists what's there.
arm.ino before it can answer.dream_sensors.ino, 9600 baud) answers WHO with I am Dream the same way, so both projects can run from one computer and each finds its own board, whatever COM numbers Windows hands out. Only one program can hold a serial port, so run one controller per arm.scripts/board_id.py does the asking (python scripts/board_id.py lists every port and who answered). C++, Go, Rust and Julia ask only the ports that look like Arduino adapters, so they skip Bluetooth ports that can take a long time to open. C# can't read USB descriptions, so it asks every port at once.--port is faster when you know it.Every UI takes its colours from one file, colour_scheme.xml in the repo root. Edit a value and restart the controller. The compiled controllers read it at start-up too, so colour changes need no rebuild (build once first to get the code that reads it).
<colour name="background" value="#33292F"/>
<colour name="button_active" value="#9C0060"/>
Write each colour on its own line as name="..." value="#RRGGBB" (name first; the C++, Rust and Julia loaders read it line by line). A missing file, or a missing or malformed colour, falls back to the built-in default for that one colour.
| Role | Default | Used for |
|---|---|---|
background | #33292F | Window and page background |
panel, border | #331F2B, #361529 | Rows, list boxes, outlines |
text, text_dim | #FFFFFF, #C9B6C1 | Main text, status lines |
button, button_hover, button_active, button_disabled | #361529, #691548, #9C0060, #331F2B | Buttons (active = the selected mode) |
accent, accent_hover | #9C0060, #C21F82 | Slider knobs, highlights, values |
track, selected | #691548, #691548 | Slider track, the chosen macro |
danger, danger_hover, warn | #963232, #AD3A3A, #F08C3C | Record and reset, warnings |
How each front end applies it:
| UI | How |
|---|---|
Python window (controller.py) | scripts/colour_scheme.py supplies the colours |
| Web page | The controller serves /colour_scheme.xml; app.js applies it over style.css's defaults |
| Julia | Read into the drawing constants at start-up |
| Rust (egui), Go (Fyne) | Applied as the toolkit's theme |
| C# (Avalonia) | Overrides the Fluent theme's button, slider and list colours |
| C++ (Win32) | Window, labels and list box, with owner-drawn buttons. Buttons don't show a hover colour, and slider thumbs keep the Windows look |
The Go, Rust, C# and Julia versions were not built or run when this was added, so the first build is worth a look.
This arm can join the RIFT fleet dashboard, the same way MILA/WHIP/NORA/KIDA do. Both controllers' Fleet mode bridges RIFT's HTTP protocol to the Arduino's USB serial connection: it serves /status, /cmd?motor=&angle=, and /reset, and heartbeats a /register call to RIFT/NORA so this arm ("ARM", port 5011) shows up in the dashboard.
The same HTTP server also serves a small web control page (scripts/web/index.html/style.css/app.js) at / - open http://<this machine's IP>:5011/ in any browser on the network for a per-motor slider UI, no RIFT required.
run.bat is the entry point: the first time it creates venv\ and installs requirements.txt (again only when that file changes), then starts the controller with whatever arguments you give it. controller.bat and fleet_server.bat go through it too.
run.bat --list-ports :: find the Arduino's port
run.bat --port COM6 --mode fleet
Whichever controller owns the Arduino's serial port keeps one shared set of motor angles. Its own window (sliders, joystick, IK), the browser page on your phone, and RIFT all read and write that same set, so setting Motor 1 to 140 anywhere shows up everywhere: the desktop sliders move, the web page's sliders move, and the arm moves. The rule is "last writer wins": whichever input changed most recently sets the angle, and inputs you aren't touching just follow it.
The Python and C++ controllers start the HTTP server and join RIFT whenever they run, in any mode (Sliders, Joystick, IK), like every other robot - so ARM always shows up in RIFT and the phone stays in sync with the desktop window. Add --no-serve to keep it to yourself (the Go/Rust/Julia/C# controllers still need --serve):
python scripts/controller.py --port COM6 --serve
cpp_controller.bat --port COM6 --serve
The window's status line then shows the address to open on the phone. Only one controller can hold the serial port, so the phone/browser connects to that one; the web page polls four times a second. In Joystick mode an axis only overrides the shared value while you're actually moving it, so untouched axes follow the phone.
--connect)Any controller can also run as a client of another one, with no serial port of its own: --connect http://<hub>:5011 mirrors the hub's angles (10 times a second) and sends this window's changes back, so a Python window on a laptop, the C++ window on the PC and a phone browser all move together. The hub is whichever controller has the Arduino plugged in and --serve (or Fleet mode) on. Connecting never moves the arm - the client adopts the hub's angles first - and it works from every controller, including different ones (a C++ client on a Python hub, etc.).
# PC with the Arduino (the hub)
cpp_controller.bat --port COM6 --serve
# laptop, phone-independent second window
python scripts/controller.py --connect http://192.168.0.10:5011
--connect can't be combined with --serve or --mode fleet.
The robots talk in Brainfuck: every phrase is a Brainfuck program that prints its words (hello is ++++++++[>+++++++++++++<-]>.+. → hi), and a robot says it by beeping the program on its buzzer, one tone per symbol, pitched to its own voice. The phrasebook (talk_bf.h) is generated by RIFT's Fleet/brainfuck_talk.py: phrases 0–6 (hello, how are you, happy, curious, sleepy, let's play, bye) and their replies 7–13. RIFT runs the conversations between robots over WiFi and logs them on its dashboard; it asks ARM to speak with GET /chirp?u=<0-13>. controller.py (Fleet mode) and the C++ controller queue it for the Arduino as TALK:<u>, beeped on the new buzzer on D8 a little lower than the others. They register talk:<fleet port> so RIFT can find her.
ARM is the YFROBOT / Makerfabs 6-DOF disc-arm frame (the Makerfabs PICO arm uses the same one). The link lengths in config.json's "geometry" come from the kit's dimension drawing (about ±3 mm): baseHeight 72 (table to shoulder pivot), upperArmLength 104, forearmLength 143, wristLength 173 (wrist pivot to closed fingertips).
IK measures each joint from an optional per-motor "kinematicZero": the raw angle with the base pointing forward, the upper arm level and the forearm and wrist in line. Until it's set, IK falls back to "rest" (a folded pose, so most targets read as unreachable). "kinematicSign" (1 or -1) says whether a bigger raw angle bends that joint up. The Python and C++ controllers use kinematicZero; the C#, Go, Rust and Julia ones still measure from rest. To calibrate: put the arm in that straight pose in Sliders mode, read motors 1-4, and add them to config.json.
Per-motor servo channel, angle range, resting angle, and invert flag all come from config.json (see scripts/motor_config.py) - the same config every controller uses. .bat launchers (controller.bat, fleet_server.bat, build_cpp_controller.bat, cpp_controller.bat, julia_controller.bat, csharp_controller.bat/.sh) live at the repo root alongside config.json; the Python, C++, Julia, and C# sources themselves stay under scripts/.
Minds — DREAM companion · TINA engineer · NINA caretaker · RIFT fleet hub · LYCEA training school
Robots — NORA · MILA · WHIP · KIDA-00 · KIDA-01 · IDA · ARM · NIKA · ARIA · AURA weather · FLORA gardener
Remotes — RITA handheld remote