From STEM classrooms to early-stage startups, the LiteWing Drone has found its way into the hands of students, makers, and engineers alike. Our goal with Litewing was to build this very same ecosystem by keeping the hardware open and affordable, with software that is scalable and beginner friendly. After the launch of the LiteWing Drone Positioning Module we noticed a lot of people wanted to control their drone from a Python script and make it fly autonomously. While that was already possible using cflib and python, understanding the complete code and reimplementing the position hold every time might be daunting for beginners.
Which is why we released our own Python library for LiteWing drones. Using this library, you will be able to fly your drone using simple lines of Python code. For example, you can ask it to take off and hold its position at a particular height, then land automatically, or even move in a particular direction for a fixed distance and then land.
Not just that, for advanced users, the library also allows you to read all flight parameters and sensor values, and control your drone’s flight and position accordingly. Think about it, you can now combine the power of Python with your LiteWing drone. You could use your laptop camera to control the drone using gestures, use your microphone for voice commands, or interface modules like UWB, GPS RTK, or a lighthouse camera and control your drone based on those inputs, and much more.
We will be building many more interesting tutorials using this library. But for now, in this tutorial, let’s understand the basics of controlling your LiteWing drone using Python and go through the important syntax used in this library. This LiteWing-Library abstracts the low-level communication layer while keeping core engineering concepts such as PID tuning, position hold, sensor fusion visible and configurable, and is built on top of the cflib.
Installation
Requirements
| Dependency | Version | Notes |
| Python | 3.11 (required) | Installed automatically - Other versions are not supported |
| cflib | 0.1.30 | Installed automatically |
| matplotlib | latest | Installed automatically (for GUI features) |
Quick Install (Recommended)
Clone the LiteWing Library repository from GitHub using the following command:
git clone https://github.com/Circuit-Digest/LiteWing-Library.git
After cloning, navigate into the LiteWing-Library directory. Inside the folder, you will find separate installation scripts for Windows and for macOS/Linux systems. Run the script that corresponds to your operating system. This will automatically install the required python version, library dependencies and complete the LiteWing-Library installation.
| Platform | Installation Method | Command / Action |
| Windows | Run the Windows installation script included in the library package | Double-click install.bat |
| macOS | Execute the shell installer from Terminal | chmod +x install.sh ./install.sh |
| Linux | Execute the shell installer from Terminal |
Quick Start Codes
To help you get started quickly and test things, we have provided a few code snippets that you can try as soon as your library is installed and hardware is ready.
Important: Do remember to ensure that your LiteWing drone is powered on and is connected to your laptop via WiFi before executing any of these codes.
Level 1 - Read Sensors (No Flying!!)
At level 1, we start off light by just reading the sensor values from the LiteWing drone. This helps us to ensure that our laptop is able to communicate with the done and the installed Python library is working as expected. As you can see in the below code we use drone.battery and drone.height to measure the battery voltage and height from the drone. But you can read a lot more parameters from your LiteWing Drone, which we will discuss later in this article.
from litewing import LiteWing
import time
drone = LiteWing("192.168.43.42")
drone.connect() # Connect, no motors!
time.sleep(2) # Wait for sensor data
print(f"Battery: {drone.battery:.2f}V")
print(f"Height: {drone.height:.3f}m")
drone.disconnect()Level 2 - First Flight
We take flight at level 2. Make sure your drone is connected to the LiteWing Positioning Module before trying this code, because this code will make the drone to take off at 0.3m height and hold its position there for 10 seconds. To maintain height and hold position, the drone will need a height sensor and a position sensor, both of which are present on the LiteWing Positioning module only. You can also fly your drone using Python without the positioning module by directly controlling the thrust, pitch, roll and yaw explanation for the same will be available later in this article.
import time
from litewing import LiteWing
drone = LiteWing("192.168.43.42")
# ── Configure before flight ──────────────────────────
drone.target_height = 0.3 # Hover at 30cm (keep it low for first tests!)
drone.hover_duration = 3.0 # Hover for 3 seconds
# ── Connect ──────────────────────────────────────────
drone.connect()
time.sleep(2)
# Pre-flight check
print(f"Battery: {drone.battery:.2f}V")
if drone.battery < 3.3:
print("Battery too low! Charge before flying.")
drone.disconnect()
exit()
# ── LED indicator: ready to fly ──────────────────────
drone.set_led_color(0, 255, 0) # Green = ready
time.sleep(1)
# ── Fly! ─────────────────────────────────────────────
print("Arming...")
drone.arm()
print(f"Taking off to {drone.target_height}m...")
drone.takeoff()
print(f"Hovering for {drone.hover_duration}s...")
drone.hover(drone.hover_duration)
print("Landing...")
drone.land()
# ── Done ─────────────────────────────────────────────
drone.clear_leds()
drone.disconnect()
print("Flight complete!")Level 3 - PID Tuning and Waypoints
Now it's time to make the drone fly autonomously on a mission path. The code also shows how to change the pid values, but you don't have to mess with it unless you have made some serious changes in the hardware. What you should look at is the "square" path array, where we feed in the path in which the drone should fly. The code also shows how you can set led color as an indication of your flight mission status.
import time
from litewing import LiteWing
drone = LiteWing("192.168.43.42")
drone.target_height = 0.3
drone.connect()
time.sleep(2)
print(f"Battery: {drone.battery:.2f}V")
drone.start_logging("waypoint_flight.csv")
drone.arm()
drone.takeoff()
# ── Method 1: fly_to (absolute positions) ────────────
print("\n--- fly_to: Triangle pattern ---")
# Fly forward
drone.fly_to(0.0, 0.5, speed=0.3)
print(f" Position: ({drone.position[0]:.2f}, {drone.position[1]:.2f})")
# Fly to the right
drone.fly_to(-0.5, 0.0, speed=0.3)
print(f" Position: ({drone.position[0]:.2f}, {drone.position[1]:.2f})")
# Return to origin
drone.fly_to(0.0, 0.0, speed=0.3)
print(f" Position: ({drone.position[0]:.2f}, {drone.position[1]:.2f})")
drone.hover(2)
# ── Method 2: fly_path (waypoint list) ───────────────
print("\n--- fly_path: Square pattern ---")
square = [
(0.0, 0.3), # Forward
(-0.3, 0.3), # Right-forward corner
(-0.3, 0.0), # Right
(0.0, 0.0), # Back to start
]
drone.fly_path(square, speed=0.3)
print(f" Final: ({drone.position[0]:.2f}, {drone.position[1]:.2f})")
drone.land()
drone.stop_logging()
drone.disconnect()
print("\nDone! Check 'waypoint_flight.csv' for the full trajectory.")
API Reference
Now that we have covered the basics and gotten a glimpse of what this library is capable of. Let's dive deep into each class of the library to understand the full depth and potential of what you can do with this library.
LiteWing Class
from litewing import LiteWing
drone = LiteWing(ip="192.168.43.42")Connection
| Method | Description |
| connect() | Connect to the drone and start reading sensor data. No motors are started. |
| disconnect() | Disconnect from the drone. Safe to call even if not connected. |
Status Properties
| Property | Type | Description |
| is_connected | bool | True if currently connected |
| is_flying | bool | True if currently in flight |
| flight_phase | str | Current phase: IDLE, CONNECTING, TAKEOFF, STABILIZING, HOVERING, LANDING, COMPLETE, ERROR |
Sensor Access
| Property / Method | Returns | Description |
| battery | float | Battery voltage (volts) |
| height | float | Kalman-filtered height (meters) |
| position | (float, float) | Estimated (x, y) position (meters) |
| velocity | (float, float) | Estimated (vx, vy) velocity (m/s) |
| read_sensors() | SensorData | Snapshot of all current sensor readings |
Flight Commands
| Method | Description |
| arm() | Arm the drone - prepare for flight. Must be called before takeoff. |
| takeoff(height=None, speed=None) | Take off to specified height in meters. Blocking. |
| hover(seconds) | Hover in place for the given duration. |
| land() | Land safely. Descends and stops motors. |
| emergency_stop() | Immediately cut all motors. Drone will fall. |
Movement Commands
| Method | Description |
| pitch_forward(distance=None, speed=0.2) | Move forward by distance meters |
| pitch_backward(distance=None, speed=0.2) | Move backward |
| roll_left(distance=None, speed=0.2) | Move left |
| roll_right(distance=None, speed=0.2) | Move right |
Raw Control
| Method | Description |
| send_control(roll=0.0, pitch=0.0, yawrate=0.0, thrust=0) | Send raw motor commands and Bypasses height/position hold. |
Position Hold
| Method | Description |
| enable_position_hold() | Activate optical flow-based position hold |
| disable_position_hold() | Switch to raw velocity mode |
| reset_position() | Reset estimated position to (0, 0) |
Advanced Flight
| Method | Description |
| fly(maneuver_fn=None, hover_duration=None) | Complete flight: connect, takeoff, maneuver, land |
| fly_to(x, y, speed=0.3, threshold=None) | Fly to absolute (x, y) position. Blocking. |
| fly_path(waypoints, speed=0.3, threshold=None) | Fly through a list of (x, y) waypoints |
Manual Control
| Method | Description |
| start_manual_control() | Full automated flight with WASD control |
| stop_manual_control() | Land and end manual mode |
| set_key(key, pressed) | Set state of a key ("w", "a", "s", "d"). pressed = True/False |
| on_key_press(callback) | Register callback for key press events |
| on_key_release(callback) | Register callback for key release events |
LED Control
| Method | Description |
| set_led_color(r, g, b) | Set all LEDs to RGB color (0–255) |
| set_led(index, r, g, b) | Set a single LED (index 0–3) to RGB |
| blink_leds(on_ms=500, off_ms=500) | Start blinking LEDs |
| clear_leds() | Turn off all LEDs |
Data Logging
| Method | Description |
| start_logging(filename=None) | Start recording flight data to CSV |
| stop_logging() | Stop recording and close the file |
Firmware Parameters
| Method | Description |
| apply_firmware_params() | Send thrust_base, z_position_kp, z_velocity_kp to the onboard controller |
Utility
| Method | Description |
| set_logger(fn) | Set a custom output function for log messages (default: print) |
SensorData Class
Returned by drone.read_sensors(). Read-only snapshot of all sensor values.
sensors = drone.read_sensors()| Attribute | Type | Description |
| height | float | Kalman-filtered height from ToF sensor (meters) |
| range_height | float | Raw height from ToF laser (meters) |
| vx | float | Velocity in X axis (m/s) |
| vy | float | Velocity in Y axis (m/s) |
| x | float | Estimated X position (meters) |
| y | float | Estimated Y position (meters) |
| battery | float | Battery voltage (volts) |
| delta_x | int | Raw optical flow delta X |
| delta_y | int | Raw optical flow delta Y |
| roll | float | Roll angle (degrees) |
| pitch | float | Pitch angle (degrees) |
| yaw | float | Yaw angle (degrees) |
| acc_x | float | Accelerometer X (g) |
| acc_y | float | Accelerometer Y (g) |
| acc_z | float | Accelerometer Z (g) |
| gyro_x | float | Gyroscope X (deg/s) |
| gyro_y | float | Gyroscope Y (deg/s) |
| gyro_z | float | Gyroscope Z (deg/s) |
PIDConfig Class
Holds PID gain values. Accessed via drone.position_pid and drone.velocity_pid.
drone.position_pid.kp = 1.5
drone.position_pid.ki = 0.03
drone.position_pid.kd = 0.0| Attribute | Type | Description |
| kp | float | Proportional gain - correction strength |
| ki | float | Integral gain - fixes persistent errors |
| kd | float | Derivative gain - dampens oscillation |
GUI Functions
from litewing.gui import live_dashboard, live_height_plot, live_imu_plot, live_position_plot| Function | Description |
| live_dashboard(drone, max_points=200, update_ms=100) | Full 4-panel dashboard: height, attitude, velocity, battery |
| live_height_plot(drone, max_points=200, update_ms=100) | Kalman-filtered + raw ToF height |
| live_imu_plot(drone, max_points=200, update_ms=100) | Roll, pitch, yaw attitude angles |
| live_position_plot(drone, max_points=500, update_ms=100) | 2D XY position trail |
Configuration Reference
All properties are set directly on the LiteWing instance before or during flight.
Flight Parameters
drone.target_height = 0.3 # Hover height in meters
drone.takeoff_time = 1.0 # Takeoff ramp duration (seconds)
drone.landing_time = 2.0 # Landing descent timeout (seconds)
drone.descent_rate = 0.3 # Landing descent speed (m/s)
drone.hover_duration = 20.0 # Default hover time (seconds)
drone.enable_takeoff_ramp = False # Smooth altitude ramp during takeoff
drone.debug_mode = False # True = disable motors (sensors still work)
drone.enable_csv_logging = False # Auto-create CSV logs during flight
drone.enable_sensor_check = True # Check ToF/flow sensors on arm()Trim Corrections
Trim compensates for hardware-level drift. Adjust these if the drone drifts during hover or raw control.
# Hover mode trim
drone.hover_trim_pitch = 0.0 # Positive = nudge forward
drone.hover_trim_roll = 0.0 # Positive = nudge right
# Raw control mode trim
drone.raw_trim_roll = 0.0 # Roll correction (degrees)
drone.raw_trim_pitch = 0.0 # Pitch correction (degrees)PID Tuning
LiteWing uses a cascaded PID controller: a position PID sets velocity targets, and a velocity PID converts those to tilt corrections.
# Position PID — how aggressively the drone corrects position errors
drone.position_pid.kp = 1.0 # Proportional: correction strength
drone.position_pid.ki = 0.03 # Integral: fix persistent drift
drone.position_pid.kd = 0.0 # Derivative: dampen oscillation
# Velocity PID — how aggressively the drone controls its speed
drone.velocity_pid.kp = 0.7 # Proportional: speed damping
drone.velocity_pid.ki = 0.01 # Integral: correct velocity bias
drone.velocity_pid.kd = 0.0 # Derivative: smooth rapid changesModify tuning parameters gradually to avoid instability. Increase Kp in small steps of 0.1–0.2, and adjust Ki and Kd in finer increments of approximately 0.01 for controlled refinement.
| Parameter Adjustment | When to Increase | Expected Effect |
| Kp (Proportional Gain) | If the drone responds slowly or appears sluggish while moving toward the target | Improves responsiveness and helps the drone reach the target more quickly |
| Ki (Integral Gain) | If the drone consistently settles short of or beyond the target in one direction | Reduces steady-state error and improves long-term accuracy |
| Kd (Derivative Gain) | If the drone oscillates or vibrates around the target position | Dampens oscillations and stabilizes movement |
Position Hold Parameters
drone.max_correction = 0.7 # Max PID correction output
drone.velocity_threshold = 0.005 # Below this = stationary (m/s)
drone.drift_compensation_rate = 0.004 # Gentle pull toward zero when hovering
drone.position_reset_interval = 90.0 # Dead reckoning reset interval (seconds)
drone.max_position_error = 2.0 # Clamp error to prevent runaway (meters)
drone.optical_flow_scale = 4.4 # Optical flow calibration factor
drone.use_height_scaling = True # Velocity depends on altitude
drone.velocity_smoothing = 0.85 # Filter (0 = raw, 1 = max smooth)Manual Control Parameters
drone.sensitivity = 0.2 # Speed per key press (m/s)
drone.hold_mode = "current" # "current" or "origin"
drone.momentum_compensation_time = 0.10 # Predicted stopping distance (seconds)
drone.settling_duration = 0.1 # Duration of corrections after key release
drone.settling_correction_factor = 0.5 # Correction strength during settlingRaw Control Safety
drone.max_thrust = 35000 # Safety cap for send_control() thrust (0–65535)Firmware (Z-Axis) Parameters
Override the onboard height controller. Requires enable_firmware_params = True.
drone.enable_firmware_params = True
drone.thrust_base = 24000 # Base motor thrust (increase if drone feels heavy)
drone.z_position_kp = 1.6 # Height position gain
drone.z_velocity_kp = 15.0 # Vertical velocity damping
# After connecting, send to the drone:
drone.apply_firmware_params()Waypoint Navigation Parameters
drone.maneuver_distance = 0.5 # Default movement distance (meters)
drone.waypoint_timeout = 60.0 # Abort waypoint after N seconds
drone.waypoint_threshold = 0.10 # "Close enough" distance (meters)
drone.waypoint_stabilization_time = 0.5 # Pause at each waypoint (seconds)Control Loop Timing
drone.sensor_update_rate = 10 # Sensor polling period (ms)
drone.control_update_rate = 0.02 # Control loop interval (seconds, 50 Hz)
User Guide
Understanding the Flight Levels
LiteWing-Library Examples organizes complexity into progressive levels:
| Level | What You Do | Sensors Required |
| Level 1 | Read sensors, visualize data | IMU + ToF + Optical Flow |
| Level 2 | Basic flight, LEDs, logging, tuning | IMU + ToF + Optical Flow |
| Level 3 | Waypoints, manual control, position hold | IMU + ToF + Optical Flow |
Each level builds on the previous one. Start at the level that matches your learning needs.
Level 1: Sensor Reading
Connect to the drone and read live sensor data. No motors are started.
Battery Voltage
from litewing import LiteWing
import time
drone = LiteWing("192.168.43.42")
drone.connect()
time.sleep(2)
print(f"Battery: {drone.battery:.2f}V")
# Continuous reading
for i in range(20):
print(f" [{i+1:2d}] Battery: {drone.battery:.2f}V")
time.sleep(0.5)
drone.disconnect()Full Sensor Snapshot
Call read_sensors() to get a snapshot of all sensor values at once:
sensors = drone.read_sensors()
print(f"Height: {sensors.height:.3f}m")
print(f"Position: ({sensors.x:.2f}, {sensors.y:.2f})")
print(f"Velocity: ({sensors.vx:.3f}, {sensors.vy:.3f}) m/s")
print(f"Roll: {sensors.roll:.1f}°")
print(f"Pitch: {sensors.pitch:.1f}°")
print(f"Yaw: {sensors.yaw:.1f}°")
print(f"Battery: {sensors.battery:.2f}V")Live Visualization (GUI)
Built-in matplotlib dashboards for real-time plotting. Requires matplotlib.
from litewing import LiteWing
from litewing.gui import live_dashboard
drone = LiteWing("192.168.43.42")
live_dashboard(drone) # Opens a 4-panel windowAvailable GUI functions:
| Function | Panels |
| live_dashboard(drone) | Height, attitude, velocity, battery all in one window |
| live_height_plot(drone) | Kalman-filtered height vs. raw ToF reading |
| live_imu_plot(drone) | Roll, pitch, yaw angles |
| live_position_plot(drone) | 2D XY position trail |
All GUI functions auto-connect the drone if not already connected. Close the window or press Ctrl+C to stop.
Optional parameters:
live_dashboard(drone, max_points=200, update_ms=100)These parameters allow you to control how much telemetry data is visualized and how frequently the interface updates.
| Parameter | Description | Default Value |
| max_points | Defines the maximum number of data samples displayed on the dashboard at any given time | 200 |
| update_ms | Specifies the dashboard refresh interval in milliseconds | 100 |
Level 2: Basic Flight
Flight Sequence
Every flight follows this pattern:
connect() → arm() → takeoff() → hover() / maneuver → land() → disconnect()from litewing import LiteWing
import time
drone = LiteWing("192.168.43.42")
drone.target_height = 0.3
drone.hover_duration = 3.0
drone.connect()
time.sleep(2)
# Pre-flight check
if drone.battery < 3.3:
print("Battery too low!")
drone.disconnect()
exit()
drone.set_led_color(0, 255, 0) # Green = ready
time.sleep(1)
drone.arm()
drone.takeoff()
drone.hover(drone.hover_duration)
drone.land()
drone.clear_leds()
drone.disconnect()Using fly() for Automated Flights
The fly() helper handles the full lifecycle connect, arm, takeoff, maneuver, land, and disconnect in a single call.
from litewing import LiteWing
drone = LiteWing("192.168.43.42")
drone.target_height = 0.3
# Simple hover for 10 seconds
drone.arm()
drone.fly(hover_duration=10)
Pass a maneuver_fn to execute custom logic during flight:
def my_maneuver(drone_ref, cf, has_pos_hold):
drone_ref.set_led_color(0, 255, 0)
drone_ref.pitch_forward(0.3)
drone_ref.roll_right(0.3)
drone_ref.clear_leds()
drone.arm()
drone.fly(maneuver_fn=my_maneuver)fly() creates its own connection. Do not call connect() before fly().
Using Context Manager
The context manager ensures emergency_stop() is called if anything goes wrong:
from litewing import LiteWing
with LiteWing("192.168.43.42") as drone:
drone.connect()
drone.arm()
drone.takeoff()
drone.hover(5)
drone.land()
drone.disconnect()
# emergency_stop() is called automatically on exitLED Control
The drone has 4 NeoPixel LEDs (indexed 0-3). Colors are specified as RGB values (0-255 each).
from litewing import LiteWing
import time
drone = LiteWing("192.168.43.42")
drone.connect()
# Set all LEDs to the same color
drone.set_led_color(255, 0, 0) # All red
time.sleep(1)
drone.set_led_color(0, 255, 0) # All green
time.sleep(1)
# Set individual LEDs
drone.set_led(0, 255, 0, 0) # LED 0 = red
drone.set_led(1, 0, 255, 0) # LED 1 = green
drone.set_led(2, 0, 0, 255) # LED 2 = blue
drone.set_led(3, 255, 255, 0) # LED 3 = yellow
time.sleep(2)
# Blink all LEDs
drone.set_led_color(128, 0, 255) # Set color first
drone.blink_leds(on_ms=200, off_ms=200) # Fast blink
time.sleep(3)
# Turn off
drone.clear_leds()
drone.disconnect()| Method | Description |
| set_led_color(r, g, b) | Set all 4 LEDs to the same RGB color |
| set_led(index, r, g, b) | Set a single LED (0–3) to an RGB color |
| blink_leds(on_ms, off_ms) | Start blinking with specified on/off timing |
| clear_leds() | Turn off all LEDs |
Data Logging
Record flight data to CSV files for post-flight analysis.
drone.connect()
drone.start_logging("my_flight.csv")
drone.arm()
drone.takeoff()
drone.hover(10)
drone.land()
drone.stop_logging()
drone.disconnect()
If no filename is provided, a timestamped filename is generated automatically:
drone.start_logging() # → "flight_2026-02-26_12-30-00.csv"CSV columns:
| Column | Unit | Description |
| Timestamp (s) | seconds | Time since logging started |
| Position X (m) | meters | Estimated X position |
| Position Y (m) | meters | Estimated Y position |
| Height (m) | meters | Kalman-filtered height |
| Range (m) | meters | Raw ToF laser height |
| Velocity X (m/s) | m/s | X velocity from optical flow |
| Velocity Y (m/s) | m/s | Y velocity from optical flow |
| Correction VX | PID correction applied to X | |
| Correction VY | PID correction applied to Y |
Level 3: Movement Commands
All movement commands are blocking; they return when the drone reaches the target position.
drone.pitch_forward(0.3) # 30cm forward at 0.2 m/s
drone.pitch_forward(0.3, speed=0.7) # Same distance, faster
drone.pitch_backward(0.5) # 50cm backward
drone.roll_left(0.3) # 30cm left
drone.roll_right(0.5) # 50cm right| Method | Description |
| pitch_forward(distance, speed=0.2) | Move forward by distance meters at speed m/s |
| pitch_backward(distance, speed=0.2) | Move backward |
| roll_left(distance, speed=0.2) | Move left |
| roll_right(distance, speed=0.2) | Move right |
distance defaults to drone.maneuver_distance (0.5m). Also, speed defaults to 0.2 m/s.
Waypoint Navigation
Navigate to absolute coordinates or fly through a series of waypoints.
fly_to Single Point
drone.fly_to(0.0, 0.5, speed=0.3) # Fly 50cm forward
drone.fly_to(-0.5, 0.0, speed=0.3) # Fly to the right
drone.fly_to(0.0, 0.0, speed=0.3) # Return to originfly_path Multi-Point Route
# Fly a square
square = [
(0.0, 0.3), # Forward
(-0.3, 0.3), # Right-forward corner
(-0.3, 0.0), # Right
(0.0, 0.0), # Back to start
]
drone.fly_path(square, speed=0.3)Full waypoint flight example:
from litewing import LiteWing
import time
drone = LiteWing("192.168.43.42")
drone.target_height = 0.3
drone.connect()
time.sleep(2)
drone.start_logging("waypoint_flight.csv")
drone.arm()
drone.takeoff()
# Triangle pattern
drone.fly_to(0.0, 0.5, speed=0.3)
drone.fly_to(-0.5, 0.0, speed=0.3)
drone.fly_to(0.0, 0.0, speed=0.3)
drone.hover(2)
drone.land()
drone.stop_logging()
drone.disconnect()Manual (Keyboard) Control
Fly the drone interactively using WASD keyboard controls.
from litewing import LiteWing
drone = LiteWing("192.168.43.42")
drone.target_height = 0.3
drone.sensitivity = 0.2
drone.hold_mode = "current"
drone.start_manual_control()start_manual_control() handles the full flight lifecycle internally connect, arm, takeoff, keyboard loop, land, disconnect. Do not call connect() or arm() before it.
Keyboard controls:
| Key | Action |
| W | Forward |
| S | Backward |
| A | Left |
| D | Right |
| SPACE / Q | Land and stop |
Hold modes:
| Mode | Behavior |
| "current" | Release keys : drone holds its current position |
| "origin" | Release keys : drone returns to launch point |
Programmatic Key Events (GUI Integration)
If you're building a custom GUI (tkinter, PyQt, etc.), you can simulate key presses programmatically:
drone.set_key("w", True) # Simulate W pressed
drone.set_key("w", False) # Simulate W released
# Register callbacks for key events
drone.on_key_press(my_press_handler)
drone.on_key_release(my_release_handler)Position Hold
The position hold system uses optical flow and a cascaded PID controller to keep the drone at a fixed position.
drone.enable_position_hold() # Turn on (default)
drone.disable_position_hold() # Turn off
drone.reset_position() # Reset position to (0, 0)Use reset_position() when accumulated drift makes the estimated position inaccurate.
General Operational Guidelines
| Recommendation | Explanation |
| Perform a battery check before every flight | Immediately land the drone if the battery voltage drops below 3.3V to prevent brownout resets or unstable flight behavior. |
| Begin testing at low altitudes | When validating new configurations or control logic, maintain a hover height between 0.2-0.3 meters to minimize risk. |
| Enable debug_mode = True during development | This allows verification of control logic without activating the motors, reducing the chance of accidental takeoff. |
| Record flight data using start_logging() | Logging enables post-flight analysis, making it easier to diagnose instability, tuning issues, or sensor anomalies. |
| Fly over textured surfaces | Optical flow sensors perform significantly better on patterned or textured ground compared to smooth or reflective surfaces. |
| Keep an emergency command ready | Maintain a terminal session with drone.emergency_stop() prepared for immediate execution in case of unexpected behavior. |