# Flix Python library The Flix Python library allows you to remotely connect to a Flix quadcopter from a Python script. It provides access to telemetry data, supports executing CLI commands, and controlling the drone's flight. To use the library, connect to the drone's Wi-Fi. To use it with the simulator, ensure the script runs on the same local network as the simulator. You also can run the script alongside the QGroundControl app. To do this, go to QGroundControl settings ⇒ *Telemetry* (*MAVLink* in older versions), and enable *MAVLink forwarding*. Set the host to `localhost:14445. The Flix library automatically detects the connection type (direct or forwarded). ## Installation If you have cloned the repo, install the library from the repo: ```bash cd /path/to/flix/repo pip install -e tools/pkg ``` Alternatively, install from pip: ```bash pip install pyflix ``` ## Usage The API is accessed through the `Flix` class: ```python from flix import Flix flix = Flix() # create a Flix object and wait for connection ``` ### Telemetry Basic telemetry is available through object properties. Their names generally match the corresponding variables in the firmware itself: ```python print(flix.connected) # True if connected to the drone print(flix.mode) # current flight mode (str) print(flix.armed) # True if the drone is armed print(flix.landed) # True if the drone is landed print(flix.attitude) # attitude quaternion [w, x, y, z] print(flix.attitude_euler) # attitude as Euler angles [roll, pitch, yaw] print(flix.rates) # angular rates [roll_rate, pitch_rate, yaw_rate] print(flix.channels) # raw RC channels (list) print(flix.motors) # motors outputs (list) print(flix.acc) # accelerometer output (list) print(flix.gyro) # gyroscope output (list) ``` > [!NOTE] > The library uses the Front-Left-Up coordinate system — the same as in the firmware. All angles are in radians. ### Events The Flix object implements the *Observable* pattern, allowing to listen for events. You can subscribe to events using `on` method: ```python flix.on('connected', lambda: print('Connected to Flix')) flix.on('disconnected', lambda: print('Disconnected from Flix')) flix.on('print', lambda text: print(f'Flix says: {text}')) ``` You can also wait for specific events using `wait` method. This method returns the data associated with the event: ```python gyro = flix.wait('gyro') # wait for gyroscope update attitude = flix.wait('attitude', timeout=3) # wait for attitude update, raise TimeoutError after 3 seconds ``` The `value` argument specifies a condition for filtering events. It can be either an expected value or a callable: ```python flix.wait('armed', value=True) # wait until armed flix.wait('armed', value=False) # wait until disarmed flix.wait('motors', value=lambda motors: all(m == 0 for m in motors)) # wait until all motors stop flix.wait('attitude_euler', value=lambda att: att[0] > 0) # wait until roll angle is positive ``` Full list of events: |Event|Description|Associated data| |-----|-----------|----------------| |`connected`|Connected to the drone|| |`disconnected`|Connection is lost|| |`armed`|Armed state update|Armed state (*bool*)| |`mode`|Flight mode update|Flight mode (*str*)| |`landed`|Landed state update|Landed state (*bool*)| |`print`|The drone sends text to the console|Text| |`attitude`|Attitude update|Attitude quaternion (*list*)| |`attitude_euler`|Attitude update|Euler angles (*list*)| |`rates`|Angular rates update|Angular rates (*list*)| |`channels`|Raw RC channels update|Raw RC channels (*list*)| |`motors`|Motors outputs update|Motors outputs (*list*)| |`acc`|Accelerometer update|Accelerometer output (*list*)| |`gyro`|Gyroscope update|Gyroscope output (*list*)| |`mavlink`|Received MAVLink message|Message object| |`mavlink.`|Received specific MAVLink message|Message object| |`mavlink.`|Received specific MAVLink message|Message object| |`value`|Named value update (see below)|Name, value| |`value.`|Specific named value update (see bellow)|Value| > [!NOTE] > Update events trigger on every new data from the drone, and do not mean the value is changed. ### Common methods Get and set firmware parameters using `get_param` and `set_param` methods: ```python print(flix.get_param('PITCH_P')) # get parameter value flix.set_param('PITCH_P', 5) # set parameter value ``` Execute CLI commands using `cli` method. This method returns command response: ```python imu = flix.cli('imu') # get detailed IMU data time = flix.cli('time') # get detailed time data flix.cli('reboot') # reboot the drone ``` > [!TIP] > Use `help` command to get the list of available commands. ### Automatic flight The flight control feature is in development. List of methods intended for automatic flight control: * `set_position` * `set_attitude` * `set_rates` * `set_motors` * `set_controls` * `set_mode` ## Tools The following scripts demonstrate how to use the library: * [`cli.py`](../cli.py) — remote access to the drone's command line interface. * `log.py` — download flight logs from the drone. * [`example.py`](../example.py) — a simple example, prints telemetry data and waits for events. * `flight.py` — a simple flight script example. ## Advanced usage ### MAVLink You can access the most recently received messages using `messages` property: ```python print(flix.messages.get('HEARTBEAT')) # print the latest HEARTBEAT message ``` You can wait for a specific message using `wait` method: ```python heartbeat = flix.wait('mavlink.HEARTBEAT') ``` You can send raw messages using `mavlink` property: ```python from pymavlink.dialects.v20 import common as mavlink flix.mavlink.heartbeat_send(mavlink.MAV_TYPE_GCS, mavlink.MAV_AUTOPILOT_INVALID, 0, mavlink.MAV_MODE_FLAG_CUSTOM_MODE_ENABLED, 0, 0) ``` ### Named values You can pass arbitrary named values from the firmware to the Python script using `NAMED_VALUE_FLOAT`, `NAMED_VALUE_INT`, `DEBUG`, `DEBUG_VECT`, and `DEBUG_FLOAT_ARRAY` MAVLink messages. All these named values will appear in the `values` dictionary: ```python print(flix.values['some_value']) print(flix.values['some_vector']) ``` You can send values from the firmware like this (`mavlink.ino`): ```cpp // Send float named value mavlink_msg_named_value_float_pack(SYSTEM_ID, MAV_COMP_ID_AUTOPILOT1, &msg, t, "some_value", loopRate); sendMessage(&msg); // Send vector named value mavlink_msg_debug_vect_pack(SYSTEM_ID, MAV_COMP_ID_AUTOPILOT1, &msg, "some_vector", t, gyroBias.x, gyroBias.y, gyroBias.z); sendMessage(&msg); ``` ## Stability The library is in development stage. The API is not stable.