Python SDK for QuadSim drone simulation
Project description
QuadSim Python SDK
Research-oriented drone simulation control for Python.
High-level flight commands and raw low-level access — one import, one object.
Getting Started • Quick Example • API Overview • Coordinate Frame • API Reference • Project Structure
What is QuadSim?
QuadSim is a research-oriented quadrotor simulation platform built in Unity, designed for controls research, autonomy development, and sim-to-real workflows. This SDK is the Python interface, it connects to a running QuadSim Unity scene over ZeroMQ and lets you command drones.
Two layers, one object:
QuadSim ← sim/world entry point, owns the connection
└─ Drone ← everything about the drone (low + high level)
You get takeoff() and send_command() on the same Drone object. No juggling between classes to switch from scripted flight to raw control.
Getting Started
Requirements
- Python 3.8+
- A running QuadSim Unity scene with the RPC adapter enabled
Install
Pip:
pip install quadsim-sdk
From source:
git clone https://github.com/ninonick0607/QuadSimLib.git
cd QuadSimLib
pip install -e .
This installs pyzmq and msgpack automatically.
Verify Connection
from quadsim import QuadSim
sim = QuadSim()
sim.connect()
print(sim.get_status())
sim.disconnect()
If it prints status info, you're connected.
Quick Example
from quadsim import QuadSim
with QuadSim() as sim:
drone = sim.drone()
drone.takeoff(altitude=3.0)
drone.fly_to(x=5, y=0, z=3)
drone.hover(duration=2.0)
drone.yaw_to(heading_deg=180)
drone.fly_path([(5, 5, 3), (0, 5, 3), (0, 0, 3)])
drone.land()
Mixing High-Level and Low-Level
with QuadSim() as sim:
drone = sim.drone()
# Scripted takeoff
drone.takeoff(3.0)
# Drop to raw velocity control
drone.set_mode("velocity")
for _ in range(100):
drone.send_command(vx=1.0, vy=0, vz=0, yaw_rate=10)
time.sleep(0.02)
# Back to high-level
drone.hover(duration=2.0)
drone.land()
Async Flight with Polling
with QuadSim() as sim:
drone = sim.drone()
drone.takeoff(3.0)
future = drone.fly_to_async(x=10, y=0, z=3, speed=2.0)
while not future.done:
pos = drone.get_position()
print(f"Position: ({pos[0]:.1f}, {pos[1]:.1f}, {pos[2]:.1f})")
time.sleep(0.5)
drone.land()
Coordinate Frame
Everything the Python SDK sees is FLU (Forward-Left-Up):
| Axis | Direction | Example |
|---|---|---|
| X | Forward | fly_to(x=5, ...) moves forward |
| Y | Left | fly_to(y=3, ...) moves left |
| Z | Up | fly_to(z=3, ...) = 3 meters altitude |
Z is always altitude. This applies to positions, velocities, and all sensor readings. The C# adapter handles all conversions to/from Unity's internal frame automatically.
API Overview
QuadSim — Sim / World
| Method | Description |
|---|---|
connect() |
Connect to Unity server |
disconnect() |
Clean disconnect |
drone() |
Get a Drone handle |
get_status() |
Sim time, pause state, authority |
pause() / resume() |
Pause/resume simulation |
step(count) |
Advance N physics steps while paused |
set_time_scale(scale) |
Speed up / slow down sim |
reset() |
Reset entire simulation |
Drone — Flight Control
High-level (blocking):
| Method | Description |
|---|---|
takeoff(altitude, speed) |
Climb and stabilize |
land(speed) |
Descend to ground |
hover(duration) |
Hold position for N seconds |
fly_to(x, y, z, speed, yaw) |
Fly to FLU position |
fly_path(waypoints, speed) |
Follow waypoint sequence |
yaw_to(heading_deg) |
Rotate to heading |
All have _async variants that return a Future.
Low-level:
| Method | Description |
|---|---|
set_mode(mode) |
Set goal mode (rate, angle, velocity, position, etc.) |
set_controller(ctrl) |
Switch controller (cascade, geometric) |
send_command(...) |
Send raw Axis4 command with named args |
get_sensors() |
Full sensor snapshot (IMU + GPS) |
get_telemetry() |
Controller state + motor outputs |
get_position() |
Quick GPS position read |
get_attitude() |
Quick attitude read |
get_velocity() |
Quick velocity read |
is_airborne() |
Altitude check |
Resets:
| Method | Description |
|---|---|
reset() |
Full drone reset |
reset_pose(x, y, z, ...) |
Teleport to position |
reset_rotation() |
Level the drone |
reset_physics() |
Zero velocities |
reset_controller() |
Clear PID integrators |
Streaming (PUB/SUB):
| Method | Description |
|---|---|
subscribe_sensors(callback, hz) |
Push-based sensor data |
subscribe_telemetry(callback, hz) |
Push-based telemetry |
subscribe(callback, topics, hz) |
Raw topic subscription |
unsubscribe() |
Stop streaming |
API Reference
send_command Layout
What x, y, z, w mean depends on the active mode:
| Mode | x | y | z | w |
|---|---|---|---|---|
| Rate | roll rate °/s | pitch rate °/s | yaw rate °/s | throttle [0,1] |
| Angle | roll ° | pitch ° | yaw rate °/s | throttle [0,1] |
| Velocity | vx m/s | vy m/s | vz m/s (up+) | yaw rate °/s |
| Position | x m | y m | z m (altitude) | yaw ° |
Named aliases map directly: roll→x, pitch→y, yaw/yaw_rate→z/w, vx→x, vy→y, vz→z, throttle→w.
SensorData Fields
sensors = drone.get_sensors()
sensors.gps_position # (x, y, z) FLU, Z = altitude
sensors.imu_attitude # (roll, pitch, yaw) degrees
sensors.imu_vel # (vx, vy, vz) m/s
sensors.imu_accel # (ax, ay, az) m/s²
sensors.imu_ang_vel # (wx, wy, wz) rad/s
sensors.imu_orientation # (qx, qy, qz, qw) quaternion
sensors.imu_valid # bool
sensors.gps_valid # bool
Telemetry Fields
telem = drone.get_telemetry()
telem.drone_id # str
telem.mode # "rate", "angle", "velocity", "position", ...
telem.controller # "cascade", "geometric"
telem.motors # (FL, FR, BL, BR) in [0, 1]
telem.desired_rates_deg # (roll, pitch, yaw) °/s
telem.desired_angles_deg # (roll, pitch, yaw) °
telem.desired_vel # (vx, vy, vz) m/s
telem.external_cmd # (x, y, z, w) raw Axis4
SimStatus Fields
status = sim.get_status()
status.is_paused # bool
status.time_scale # float
status.sim_time # float (seconds)
status.fixed_dt # float
status.authority # "UI", "Internal", "External"
status.client_connected # bool
Tuning Parameters
Set on the Drone object before or during flight:
drone.position_tolerance = 0.5 # meters — arrival threshold
drone.altitude_tolerance = 0.3 # meters — takeoff/land threshold
drone.landing_altitude = 0.15 # below this = landed
drone.default_speed = 2.0 # m/s fallback
drone.control_loop_hz = 50.0 # SDK tick rate
drone.default_leg_timeout = 30.0 # seconds per waypoint
drone.use_velocity_mode_navigation = False # velocity-mode fly_to fallback
Exceptions
from quadsim import QuadSimError, ConnectionError, CommandError, TimeoutError, ProtocolError
| Exception | When |
|---|---|
ConnectionError |
Not connected, connection denied |
CommandError |
Authority rejected, no drone, invalid mode |
TimeoutError |
RPC timeout, flight command timeout |
ProtocolError |
Wire-level serialization issues |
All inherit from QuadSimError.
Project Structure
QuadSimLib/
├── quadsim/ # SDK package
│ ├── __init__.py # Public exports: QuadSim, Drone, Future, types, exceptions
│ ├── sim.py # QuadSim class — sim/world entry point
│ ├── drone.py # Drone class — all drone control (low + high level)
│ ├── _transport.py # Internal ZMQ/MessagePack transport (not user-facing)
│ ├── _control_loops.py # Internal control loop logic for high-level commands
│ ├── types.py # SensorData, Telemetry, SimStatus dataclasses
│ ├── exceptions.py # QuadSimError hierarchy
│ └── future.py # Async Future handle
├── Examples/
│ ├── flight_demo.py # Full flight demo
│ └── async_demo.py # Async/Future usage demo
├── Testing/ # Low-level integration tests (Phase 9)
│ ├── quadsim_test_client.py
│ ├── quadsim_test_commands.py
│ └── test_high_level.py
└── pyproject.toml # Package config — pip install -e .
How It Works
The SDK communicates with QuadSim's Unity runtime over ZeroMQ:
- REQ/REP (port 5555) — commands, queries, mode changes
- PUB/SUB (port 5556) — streaming telemetry
Messages are serialized with MessagePack. A background heartbeat thread keeps the connection alive. All of this is managed internally by _transport.py — you never touch sockets directly.
The Drone object's high-level methods (takeoff, fly_to, etc.) run Python-side control loops at 50Hz that read sensors and send commands through the same RPC path. This keeps the logic inspectable and modifiable without recompiling Unity.
Related
- Unity_QuadSim — The Unity simulation itself: github.com/ninonick0607/Unity_QuadSim
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file quadsim_sdk-0.11.1.tar.gz.
File metadata
- Download URL: quadsim_sdk-0.11.1.tar.gz
- Upload date:
- Size: 18.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cd30b0567d429320a84fdb31cd2349960fab670b9bd648549135bdecb292ff1c
|
|
| MD5 |
b766ba8ff1066604571557842098c4ce
|
|
| BLAKE2b-256 |
b57775f05c69fe982a0bec6a11294e8a88b00aa324a1e382d0c96cac29d6ed55
|
File details
Details for the file quadsim_sdk-0.11.1-py3-none-any.whl.
File metadata
- Download URL: quadsim_sdk-0.11.1-py3-none-any.whl
- Upload date:
- Size: 18.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
655d761437fc3c01c4d303ed18cd5fbf4cb4413e09b7467ed5c80834d1edf9f1
|
|
| MD5 |
0997b3dbed44aece9756fcd2b8a170cd
|
|
| BLAKE2b-256 |
9698fec0ecb31b1e67edab164e1ccec80bd5eaa198ac974e8e786ed749df8d0a
|