# skyvison RC starter kit

## What is implemented

- Responsive touch/slider controller, channel visualization, seven vehicle profiles.
- Car/boat: forward-only throttle and steering/rudder through compatible ESC + servo hardware.
- ESP32 Wi-Fi receiver and hosted local controller, Raspberry Pi local web server, Arduino Uno USB output adapter.
- Pairing key, single-session ownership, monotonic command sequence, neutral arming, deadman input, disarm on hidden/blurred page, 10 Hz commands, receiver software watchdog at 500 ms.
- Aircraft/FPV/heli/tricopter: **simulator channel layouts only**. No direct aircraft actuator output, stabilization, mixing or live video.

This is starter software, not universal receiver firmware or a certified control link. Firmware and wiring have not been bench-tested on your hardware. Phone browsers and Wi-Fi are not deterministic. For any powered vehicle, use an independent hardware cutoff/watchdog and verify stop behavior. A Pi process crash, an I2C failure or a microcontroller fault can leave an external PWM board holding its last pulse; software timeouts alone do not cover those failures.

## Wiring and stop semantics

The only supported throttle output is a forward-only ESC with 1000 microseconds = STOP, 2000 = full forward at 50 Hz. Steering is 1500 center, 1000..2000 endpoints. No reverse, brakes or bidirectional 1500-neutral ESCs. Do not connect an incompatible ESC. Servo limits and channel mapping must match your build.

Use a properly rated separate actuator supply and common signal ground. Never power an ESC, motor or high-current servo from a Pi/ESP32 GPIO. Check board pin voltage limits and ESC wiring. Begin with propulsion disconnected and wheels raised. Check STOP, deadman release, tab switching, lost Wi-Fi and receiver restart before any movement.

## ESP32 (Arduino IDE)

1. Install the Espressif Arduino-ESP32 board package 3.x and ArduinoJson 7. Open `firmware/esp32/esp32.ino`; keep generated `controller.h` beside it.
2. Select your actual ESP32 board. Example ESP32 DevKit GPIO25 = ESC, GPIO26 = steering. These pins do not exist on every ESP32 variant; adapt them before use.
3. Leave `ENABLE_OUTPUTS=false` for initial tests. Upload and open Serial Monitor at 115200.
4. Read the generated Wi-Fi password and pairing key. Join `skyvison-rc`, open `http://192.168.4.1` on your phone/tablet, then pair with the displayed key.
5. The controller explicitly reports DRY RUN. Only change `ENABLE_OUTPUTS` after checking the wiring and ESC stop semantics, then rebuild/reflash. The passwords change at each restart.

PWM uses the Arduino-ESP32 3.x LEDC `ledcAttach(pin,50,16)` / `ledcWrite(pin,duty)` API. A separate watchdog task checks command age even when an HTTP client is slow. Use an independent hardware cutoff as well.

## Raspberry Pi (local web controller)

Python 3.10 or later. Extract the whole kit, preserving `controller/` beside `firmware/`.

```sh
cd skyvison-rc-kit
python3 firmware/receiver.py
```

This starts in DRY RUN on port 8080. Read the pairing key in the terminal. Put the phone and Pi on a private Wi-Fi network and open `http://<Pi-private-IP>:8080`. No installation is needed for dry run. Stop with Ctrl+C.

Optional settings: `RC_KEY` (12+ characters), `RC_PORT`, `RC_BIND`. The generated key is not saved. The server intentionally has no cloud relay, remote discovery or CORS support. Do not port-forward or expose it to the public internet. HTTP here is for a trusted private network; anyone who can observe its unencrypted traffic can obtain the key. For encrypted remote control, configure and validate your own TLS gateway and network policy.

### Pi + Arduino Uno USB

Install pyserial in a virtual environment, upload `firmware/arduino/arduino.ino` using the Arduino IDE and its Servo library, then:

```sh
python3 -m venv .venv
. .venv/bin/activate
pip install pyserial
RC_ADAPTER=serial RC_SERIAL_PORT=/dev/ttyACM0 python3 firmware/receiver.py
```

That command is still dry-run. Actual output requires **both** Arduino `ENABLE_OUTPUTS=true` and receiver `RC_OUTPUTS=enabled`, after completing the bench check. Add `RC_OUTPUTS=enabled` to the command only then. Uno D9 = ESC, D10 = steering. Serial frames are `armed,throttle_us,steering_us\n` at 115200. The Uno stops when no valid serial frame arrives for 500 ms. A bare Uno cannot serve a Wi-Fi page; the Pi supplies that connection.

### Pi + PCA9685 I2C board

Enable Pi I2C and install the board vendor's CircuitPython dependencies in a suitable environment:

```sh
pip install adafruit-blinka adafruit-circuitpython-pca9685
RC_ADAPTER=pca9685 python3 firmware/receiver.py
```

Still dry-run. Only add `RC_OUTPUTS=enabled` after testing, fitting an independent cutoff/watchdog and wiring the board correctly. Address 0x40, channel 0 = ESC, channel 1 = steering, 50 Hz. Check SDA/SCL wiring for your Pi and use an appropriate external actuator supply. The PCA9685 does **not** enforce the software watchdog itself.

## Protocol

All API requests are same-origin JSON with `X-RC-Key`. Cross-origin requests are not supported. No credentials or control frames are sent to skyvison. The frontend keeps the key in memory until disconnection/reload.

- `POST /api/session {}` → `{session,outputs,watchdogMs}`. Pairing disarms; a client cannot take over a link active in the last second.
- `POST /api/control {session,seq,profile,armed,deadman,throttle,yaw,pitch,roll}`. `seq` must increase within a session. `profile` must be car or boat. `armed` and `deadman` are booleans. Throttle is finite 0..1; other channels are finite -1..1. Arming from disarmed requires all channels zero. Only throttle and roll drive the ground outputs. No yaw/pitch mixing.
- Deadman false: stop pulse and centered steering. Armed false: disarmed. Missing commands for 500 ms: disarmed. Re-arm requires a new neutral frame.
- Default controller rate limit is 25%; the user can choose 50% or 100%. This is a UI limit, not a receiver-enforced maximum.
- Replies acknowledge commands and output mode. They are **not** battery, GPS, RSSI, attitude or other sensor telemetry.

## Tests

```sh
python3 -m unittest discover -s firmware -p 'test_receiver.py'
```

Tests use fake outputs and time. They do not validate PWM timing or physical hardware. Firmware must be compiled for your selected board and then bench-tested separately.

## References

https://docs.espressif.com/projects/arduino-esp32/en/latest/api/ledc.html
https://arduinojson.org/v7/api/json/deserializejson/
https://docs.circuitpython.org/projects/pca9685/en/latest/

Independent skyvison starter code, supplied as-is. No paid API or mandatory cloud account is required. Third-party tools/libraries retain their own licenses. Downloaded HTML includes the same shared skyvison theme and logo for offline use.
