<div align="center">

# 🛰️ dronelink

**Serial & MAVLink Drone Communication Library**

*Send gimbal angles, flight commands, and heartbeats over UART/USB-Serial.*

![Python](https://img.shields.io/badge/Python-3.7%2B-blue?logo=python&logoColor=white)
![PySerial](https://img.shields.io/badge/Dependency-PySerial-orange)
![License](https://img.shields.io/badge/License-MIT-yellow)

</div>

---

## ✨ Features

- **Packet Framing** — Header + Command ID + Payload + XOR Checksum
- **GimbalController** — Normalized PID output → servo angle conversion
- **Exponential Smoothing** — Prevents jittery servo movement
- **Rate Limiting** — 50Hz max update rate to prevent serial flooding
- **Heartbeat** — Keep-alive packets for connection monitoring

---

## 📦 Installation

```bash
pip install dronelink
```

---

## 🚀 Quick Start

```python
from dronelink import DroneLink, GimbalController

# Connect to flight controller
drone = DroneLink("COM3", baudrate=115200)

# Create gimbal controller
gimbal = GimbalController(drone, pan_range=(-90, 90), tilt_range=(-45, 45))

# In your tracking loop:
# pid_x, pid_y are from servopilot (-1.0 to +1.0)
gimbal.set_angles(pan=pid_x, tilt=pid_y)

# Send heartbeat periodically
drone.send_heartbeat()

# Check status
print(gimbal.get_status())

# Cleanup
drone.close()
```

### Integration with ServoPilot

```python
from servopilot import DualAxisPID
from dronelink import DroneLink, GimbalController

pid = DualAxisPID(kp=0.4, ki=0.008, kd=0.25)
drone = DroneLink("COM3")
gimbal = GimbalController(drone)

# Tracking loop
signal_x, signal_y = pid.update(error_x, error_y, dt=1/30)
gimbal.set_angles(pan=signal_x, tilt=signal_y)
```

---

## 🔧 API Reference

### `DroneLink(port, baudrate=115200, timeout=1.0)`

| Method | Description |
|---|---|
| `send_command(cmd_id, payload)` | Send framed packet with checksum |
| `send_raw(data)` | Send raw bytes |
| `send_heartbeat()` | Send keep-alive packet |
| `read_response(size)` | Read response bytes |
| `close()` | Close serial connection |

### `GimbalController(link, pan_range, tilt_range, smooth_factor)`

| Method | Description |
|---|---|
| `set_angles(pan, tilt)` | Send normalized (-1 to +1) gimbal angles |
| `center()` | Return to (0°, 0°) |
| `get_status()` | Get current/target angles |

---

## 📜 License

MIT License — use it anywhere.

<div align="center">
<i>Built with ❤️ by <a href="https://github.com/ByIbos">ByIbos</a></i>
</div>
