1 Commits

Author SHA1 Message Date
Oleg Kalachev b235825f3d Implement battery voltage monitoring
Add power subsystem.
Add PWR_VOLT_PIN, PWR_VOLT_SCALE, PWR_VOLT_LPF_A parameters.
Support BATTERY_STATUS mavlink messages streaming.
Add pw cli command.
Add voltage field to pyflix library.
2026-04-21 05:18:52 +03:00
31 changed files with 50 additions and 118 deletions
-2
View File
@@ -25,8 +25,6 @@ jobs:
path: flix/build
- name: Build firmware for ESP32-S3
run: make BOARD=esp32:esp32:esp32s3
- name: Build firmware for ESP32-C3
run: make BOARD=esp32:esp32:esp32c3
- name: Check c_cpp_properties.json
run: tools/check_c_cpp_properties.py
+2 -1
View File
@@ -1,5 +1,6 @@
BOARD = esp32:esp32:d1_mini32
PORT := $(strip $(wildcard /dev/serial/by-id/usb-Silicon_Labs_CP21* /dev/serial/by-id/usb-1a86_USB_Single_Serial_* /dev/cu.usbserial-* /dev/cu.usbmodem*))
PORT := $(wildcard /dev/serial/by-id/usb-Silicon_Labs_CP21* /dev/serial/by-id/usb-1a86_USB_Single_Serial_* /dev/cu.usbserial-*)
PORT := $(strip $(PORT))
build: .dependencies
arduino-cli compile --fqbn $(BOARD) flix
+5 -7
View File
@@ -53,7 +53,7 @@ The simulator is implemented using Gazebo and runs the original Arduino code:
<img src="docs/img/simulator1.png" width=500 alt="Flix simulator">
## Documentation articles
## Documentation
1. [Assembly instructions](docs/assembly.md).
2. [Usage: build, setup and flight](docs/usage.md).
@@ -75,10 +75,10 @@ Additional articles:
|IMU (and barometer¹) board|GY91, MPU-9265 (or other MPU9250/MPU6500 board)<br>ICM20948V2 (ICM20948)³<br>GY-521 (MPU-6050)³⁻¹|<img src="docs/img/gy-91.jpg" width=90 align=center><br><img src="docs/img/icm-20948.jpg" width=100><br><img src="docs/img/gy-521.jpg" width=100>|1|
|Boost converter (optional, for more stable power supply)|5V output|<img src="docs/img/buck-boost.jpg" width=100>|1|
|Motor|8520 3.7V brushed motor.<br>Motor with exact 3.7V voltage is needed, not ranged working voltage (3.7V — 6V).<br>Make sure the motor shaft diameter and propeller hole diameter match!|<img src="docs/img/motor.jpeg" width=100>|4|
|Propeller|55 mm or 65 mm|<img src="docs/img/prop.jpg" width=100>|4|
|Propeller|55 mm (alternatively 65 mm)|<img src="docs/img/prop.jpg" width=100>|4|
|MOSFET (transistor)|100N03A or [analog](https://t.me/opensourcequadcopter/33)|<img src="docs/img/100n03a.jpg" width=100>|4|
|Pull-down resistor<br>Voltage measurement resistor|10 kΩ|<img src="docs/img/resistor10k.jpg" width=100>|6|
|3.7V Li-Po battery|LW 952540 (or any compatible by the size).<br>Make sure the battery has enough discharge rate — 25C or more!|<img src="docs/img/battery.jpg" width=100>|1|
|Pull-down resistor|10 kΩ|<img src="docs/img/resistor10k.jpg" width=100>|4|
|3.7V Li-Po battery|LW 952540 (or any compatible by the size)|<img src="docs/img/battery.jpg" width=100>|1|
|Battery connector cable|MX2.0 2P female|<img src="docs/img/mx.png" width=100>|1|
|Li-Po Battery charger|Any|<img src="docs/img/charger.jpg" width=100>|1|
|Screws for IMU board mounting|M3x5|<img src="docs/img/screw-m3.jpg" width=100>|2|
@@ -154,12 +154,10 @@ You can see a user-contributed [variant of complete circuit diagram](https://mir
|VIN|VCC (or 3.3V depending on the receiver)|
|Signal (TX)|GPIO4¹|
*¹ — UART2 RX pin was [changed](https://docs.espressif.com/projects/arduino-esp32/en/latest/migration_guides/2.x_to_3.0.html#id14) to GPIO4 in Arduino ESP32 core 3.0.*
*¹ — UART2 RX pin was [changed](https://docs.espressif.com/projects/arduino-esp32/en/latest/migration_guides/2.x_to_3.0.html#id14) to GPIO4 in Arduino ESP32 core 3.0.*
* Optionally connect the battery voltage divider for voltage monitoring to any ADC1 pin (e. g. *GPIO32* on ESP32, *GPIO3* on ESP32S3).
ESP32 and ESP32S3 [can measure](https://docs.espressif.com/projects/arduino-esp32/en/latest/api/adc.html#analogsetattenuation) up to 3.1 V and ESP32S3/ESP32C3 can measure up to 2.5 V, so choose the voltage divider resistors accordingly.
## Resources
* Telegram channel on developing the drone and the flight controller (in Russian): https://t.me/opensourcequadcopter.
-2
View File
@@ -28,8 +28,6 @@ Soldered components ([schematics variant](https://miro.com/app/board/uXjVN-dTjoo
<img src="img/assembly/7.jpg" width=600>
See an alternative assembly process photos here: https://drive.google.com/drive/folders/1FG5BH9RCzdf1XmJcC70PymiRMXcz6Fx7?usp=sharing.
## Motor directions
> [!WARNING]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

+7 -13
View File
@@ -12,25 +12,20 @@ Do the following:
Do the following:
* **Check the battery voltage**. Use a multimeter to measure the battery voltage. The fully charged battery should have about 4.2V.
* **Check the battery you use has enough discharge current**. The battery should be able to provide 15A of current. So the C-rating for a 1000 mAh battery should be at least 15C (higher is better).
* **Check the battery voltage**. Use a multimeter to measure the battery voltage. It should be in range of 3.7-4.2 V.
* **Check if there are some startup errors**. Connect the ESP32 to the computer and check the Serial Monitor output. Use the Reset button or `reboot` command to see the whole startup output.
* **Check the baudrate is correct**. If you see garbage characters in the Serial Monitor, make sure the baudrate is set to 115200.
* **Make sure correct IMU model is chosen**. If using ICM-20948/MPU-6050 board, change `MPU9250` to `ICM20948`/`MPU6050` in the `imu.ino` file.
* **Check if the console is working**. Perform `help` command in Serial Monitor. You should see the list of available commands. You can also access the console using QGroundControl *(Vehicle Setup**Analyze Tools**MAVLink Console)*.
* **Configure QGroundControl correctly before connecting to the drone** if you use it to control the drone. Go to the settings and enable *Virtual Joystick*. *Auto-Center Throttle* setting **should be disabled**.
* **If QGroundControl doesn't connect**, you might need to disable the firewall and/or VPN on your computer.
* **Make sure correct IMU model is chosen**. If using ICM-20948/MPU-6050 board, change `MPU9250` to `ICM20948`/`MPU6050` in the `imu.ino` file.
* **Check the IMU is working**. Perform `imu` command and check its output:
* The `status` field should be `OK`.
* The `rate` field should be about 1000 (Hz).
* The `accel` and `gyro` fields should change as you move the drone.
* **Check the IMU orientation is set correctly**. If the attitude estimation is rotated, set the correct IMU orientation as described in the [tutorial](usage.md#define-imu-orientation).
* **Calibrate the accelerometer.** if is wasn't done before. Type `ca` command in Serial Monitor and follow the instructions.
* **Check the attitude estimation**. Connect to the drone using QGroundControl. Rotate the drone in different orientations and check if the attitude estimation is shown exactly as on the video below:
<a href="https://youtu.be/yVRN23-GISU"><img width=200 src="https://i3.ytimg.com/vi/yVRN23-GISU/maxresdefault.jpg"></a>
* **Check the IMU output**. Connect to the drone using QGroundControl on your computer. Go to the *Analyze* tab, *MAVLINK Inspector*. Plot the data from the `SCALED_IMU` message. The gyroscope and accelerometer data should change according to the drone movement.
* **Check the attitude estimation**. Connect to the drone using QGroundControl. Rotate the drone in different orientations and check if the attitude estimation shown in QGroundControl is correct.
* **Check the IMU orientation is set correctly**. If the attitude estimation is rotated, set the correct IMU orientation as described in the [tutorial](usage.md#define-imu-orientation).
* **Check the motors type**. Motors with exact 3.7V voltage are needed, not ranged working voltage (3.7V — 6V).
* **Check the motors**. Perform the following commands using Serial Monitor:
* `mfr` — should rotate front right motor (counter-clockwise).
@@ -38,10 +33,9 @@ Do the following:
* `mrl` — should rotate rear left motor (counter-clockwise).
* `mrr` — should rotate rear right motor (clockwise).
* **Check the propeller directions are correct**. Make sure your propeller types (A or B) are installed as on the picture:
<img src="img/user/peter_ukhov-2/1.jpg" width="200">
* **If using an SBUS receiver**:
* **Check the remote control**. Using `rc` command, check the control values reflect your sticks movement. All the controls should change between -1 and 1, and throttle between 0 and 1.
* **If using SBUS receiver**:
* **Define the used GPIO pin** in `RC_RX_PIN` parameter.
* **Calibrate the RC** using `cr` command in the console.
* **Check the controls** using `rc` command. All the controls should change between -1 and 1, and the throttle between 0 and 1.
* **Check the IMU output using QGroundControl**. Connect to the drone using QGroundControl on your computer. Go to the *Analyze* tab, *MAVLINK Inspector*. Plot the data from the `SCALED_IMU` message. The gyroscope and accelerometer data should change according to the drone movement.
+8 -10
View File
@@ -112,9 +112,9 @@ You can also work with parameters using `p` command in the console. Parameter na
### Define IMU orientation
The IMU orientation (relative to the drone's axes) is defined using the parameters: `IMU_ROT_ROLL`, `IMU_ROT_PITCH`, and `IMU_ROT_YAW`.
Use parameters, to define the IMU board axes orientation relative to the drone's axes: `IMU_ROT_ROLL`, `IMU_ROT_PITCH`, and `IMU_ROT_YAW`.
The drone has *X* axis pointing forward, *Y* axis pointing left, and *Z* axis pointing up, and the supported IMU boards have *X* axis pointing to the mounting holes side and *Z* axis pointing up from the component side:
The drone has *X* axis pointing forward, *Y* axis pointing left, and *Z* axis pointing up, and the supported IMU boards have *X* axis pointing to the pins side and *Z* axis pointing up from the component side:
<img src="img/imu-axes.png" width="200">
@@ -122,10 +122,10 @@ Use the following table to set the parameters for common IMU orientations:
|Orientation|Parameters|Orientation|Parameters|
|:-:|-|-|-|
|<img src="img/imu-rot-3.png" width="180">|`IMU_ROT_ROLL` = 0<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = 0 |<img src="img/imu-rot-7.png" width="180">|`IMU_ROT_ROLL` = 3.142<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = 0|
|<img src="img/imu-rot-2.png" width="180">|`IMU_ROT_ROLL` = 0<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = -1.571|<img src="img/imu-rot-6.png" width="180">|`IMU_ROT_ROLL` = 3.142<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = -1.571|
|<img src="img/imu-rot-1.png" width="180">|`IMU_ROT_ROLL` = 0<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = 3.142|<img src="img/imu-rot-5.png" width="180">|`IMU_ROT_ROLL` = 3.142<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = 3.142|
|<img src="img/imu-rot-4.png" width="180"><br>☑️ **Default**|<br>`IMU_ROT_ROLL` = 0<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = 1.571|<img src="img/imu-rot-8.png" width="180">|`IMU_ROT_ROLL` = 3.142<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = 1.571|
|<img src="img/imu-rot-1.png" width="180">|`IMU_ROT_ROLL` = 0<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = 0 |<img src="img/imu-rot-5.png" width="180">|`IMU_ROT_ROLL` = 3.142<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = 0|
|<img src="img/imu-rot-2.png" width="180">|`IMU_ROT_ROLL` = 0<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = 1.571|<img src="img/imu-rot-6.png" width="180">|`IMU_ROT_ROLL` = 3.142<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = -1.571|
|<img src="img/imu-rot-3.png" width="180">|`IMU_ROT_ROLL` = 0<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = 3.142|<img src="img/imu-rot-7.png" width="180">|`IMU_ROT_ROLL` = 3.142<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = 3.142|
|<img src="img/imu-rot-4.png" width="180"><br>☑️ **Default**|<br>`IMU_ROT_ROLL` = 0<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = -1.571|<img src="img/imu-rot-8.png" width="180">|`IMU_ROT_ROLL` = 3.142<br>`IMU_ROT_PITCH` = 0<br>`IMU_ROT_YAW` = 1.571|
### Calibrate accelerometer
@@ -138,8 +138,6 @@ Before flight you need to calibrate the accelerometer:
If using non-default motor pins, set the pin numbers using the parameters: `MOTOR_PIN_FL`, `MOTOR_PIN_FR`, `MOTOR_PIN_RL`, `MOTOR_PIN_RR` (front-left, front-right, rear-left, rear-right respectively).
Certain ESP32 models (such as ESP32-S3) support a lower maximum PWM frequency; on these boards the parameter `MOT_PWM_FREQ` should be set to 38000 Hz.
If using brushless motors and ESCs:
1. Set the appropriate PWM using the parameters: `MOT_PWM_STOP`, `MOT_PWM_MIN`, and `MOT_PWM_MAX` (1000, 1000, and 2000 is typical).
@@ -247,7 +245,7 @@ When finished flying, **disarm** the drone, moving the left stick to the bottom
### Flight modes
Flight mode is changed using mode switch on the remote control (if configured) or using the console commands. The main flight mode is *STAB*. In order to change modes using SBUS remote control, set the parameters: `CTL_FLT_MODE_0`, `CTL_FLT_MODE_1`, and `CTL_FLT_MODE_2` to required mode numbers (0 for *RAW*, 1 for *ACRO*, 2 for *STAB*, 3 for *AUTO*).
Flight mode is changed using mode switch on the remote control (if configured) or using the console commands. The main flight mode is *STAB*.
#### STAB
@@ -268,7 +266,7 @@ In this mode, the pilot controls the angular rates. This control method is diffi
In this mode, the pilot inputs are ignored (except the mode switch). The drone can be controlled using [pyflix](../tools/pyflix/) Python library, or by modifying the firmware to implement the needed behavior.
If the pilot moves the control sticks and mode switch is not configured, the drone will switch back to *STAB* mode.
If the pilot moves the control sticks, the drone will switch back to *STAB* mode.
## Wi-Fi configuration
-8
View File
@@ -4,14 +4,6 @@ This page contains user-built drones based on the Flix project. Publish your pro
---
Author: [Ina Tix](https://t.me/ina_tix).<br>
Description: XR2981 based DC-DC converter, ELRS MINI 2.4GHz RX SX1280 receiver (SBUS interface), Radiomaster TX12 remote control.<br>
[Flight validation](https://drive.google.com/file/d/1yqkKNuz4R_yxGqUNQxVpixJbXqEEcUSj/view?usp=share_link).
<img src="img/user/ina_tix/1.jpg" height=200> <img src="img/user/ina_tix/2.jpg" height=200> <img src="img/user/ina_tix/3.jpg" height=200>
---
Author: [FanBy0ru](https://https://github.com/FanBy0ru).<br>
Description: custom 3D-printed frame.<br>
Frame STLs and flight validation: https://cults3d.com/en/3d-model/gadget/armature-pour-flix-drone.
+1 -2
View File
@@ -168,7 +168,6 @@ void doCommand(String str, bool echo = false) {
print("Chip: %s\n", ESP.getChipModel());
print("Temperature: %.1f °C\n", temperatureRead());
print("Free heap: %d\n", ESP.getFreeHeap());
print("Firmware: " __DATE__ " " __TIME__ "\n");
// Print tasks table
print("Num Task Stack Prio Core CPU%%\n");
int taskCount = uxTaskGetNumberOfTasks();
@@ -179,7 +178,7 @@ void doCommand(String str, bool echo = false) {
String core = systemState[i].xCoreID == tskNO_AFFINITY ? "*" : String(systemState[i].xCoreID);
int cpuPercentage = systemState[i].ulRunTimeCounter / (totalRunTime / 100);
print("%-5d%-20s%-7d%-6d%-6s%d\n",systemState[i].xTaskNumber, systemState[i].pcTaskName,
systemState[i].usStackHighWaterMark, systemState[i].uxCurrentPriority, core.c_str(), cpuPercentage);
systemState[i].usStackHighWaterMark, systemState[i].uxCurrentPriority, core, cpuPercentage);
}
delete[] systemState;
#endif
+1 -14
View File
@@ -67,7 +67,7 @@ void control() {
void interpretControls() {
if (controlMode < 0.25) mode = flightModes[0];
else if (controlMode <= 0.75) mode = flightModes[1];
else if (controlMode < 0.75) mode = flightModes[1];
else if (controlMode > 0.75) mode = flightModes[2];
if (mode == AUTO) return; // pilot is not effective in AUTO mode
@@ -149,25 +149,12 @@ void controlTorque() {
motors[MOTOR_REAR_LEFT] = thrustTarget + torqueTarget.x + torqueTarget.y - torqueTarget.z;
motors[MOTOR_REAR_RIGHT] = thrustTarget - torqueTarget.x + torqueTarget.y + torqueTarget.z;
desaturate(motors[MOTOR_FRONT_LEFT], motors[MOTOR_FRONT_RIGHT], motors[MOTOR_REAR_LEFT], motors[MOTOR_REAR_RIGHT]);
motors[0] = constrain(motors[0], 0, 1);
motors[1] = constrain(motors[1], 0, 1);
motors[2] = constrain(motors[2], 0, 1);
motors[3] = constrain(motors[3], 0, 1);
}
void desaturate(float& a, float& b, float& c, float& d) {
float maxThrust = max(max(a, b), max(c, d));
if (maxThrust > 1) {
float diff = maxThrust - 1;
a -= diff;
b -= diff;
c -= diff;
d -= diff;
}
}
const char* getModeName() {
switch (mode) {
case RAW: return "RAW";
-11
View File
@@ -13,13 +13,11 @@ Quaternion attitude; // estimated attitude
bool landed;
float accWeight = 0.003;
float levelWeight = 0.0002;
LowPassFilter<Vector> ratesFilter(0.2); // cutoff frequency ~ 40 Hz
void estimate() {
applyGyro();
applyAcc();
applyLevel();
}
void applyGyro() {
@@ -44,12 +42,3 @@ void applyAcc() {
// apply correction
attitude = Quaternion::rotate(attitude, Quaternion::fromRotationVector(correction));
}
void applyLevel() {
if (landed) return;
// assume the pilot keeps the drone more or less level in flight
Vector up = Quaternion::rotateVector(Vector(0, 0, 1), attitude);
Vector correction = Vector::rotationVectorBetween(Vector(0, 0, 1), up) * levelWeight;
attitude = Quaternion::rotate(attitude, Quaternion::fromRotationVector(correction));
}
+1 -1
View File
@@ -18,8 +18,8 @@ extern float motors[4];
void setup() {
Serial.begin(115200);
print("Initializing flix\n");
disableBrownOut();
setupParameters();
setupPower();
setupLED();
setLED(true);
setupMotors();
+2 -2
View File
@@ -10,7 +10,7 @@
#include "util.h"
MPU9250 imu(SPI);
Vector imuRotation(0, 0, PI / 2); // imu orientation as Euler angles
Vector imuRotation(0, 0, -PI / 2); // imu orientation as Euler angles
Vector gyro; // gyroscope output, rad/s
Vector gyroBias;
@@ -121,7 +121,7 @@ void printIMUInfo() {
print("model: %s\n", imu.getModel());
print("who am I: 0x%02X\n", imu.whoAmI());
print("rate: %.0f\n", loopRate);
print("gyro: %f %f %f\n", gyro.x, gyro.y, gyro.z);
print("gyro: %f %f %f\n", rates.x, rates.y, rates.z);
print("acc: %f %f %f\n", acc.x, acc.y, acc.z);
imu.waitForData();
Vector rawGyro, rawAcc;
+1 -1
View File
@@ -65,7 +65,7 @@ void sendMavlink() {
sendMessage(&msg);
mavlink_msg_scaled_imu_pack(mavlinkSysId, MAV_COMP_ID_AUTOPILOT1, &msg, time,
acc.x / ONE_G * 1000, -acc.y / ONE_G * 1000, -acc.z / ONE_G * 1000, // convert to frd
acc.x * 1000, -acc.y * 1000, -acc.z * 1000, // convert to frd
gyro.x * 1000, -gyro.y * 1000, -gyro.z * 1000,
0, 0, 0, 0);
sendMessage(&msg);
+1 -1
View File
@@ -54,7 +54,7 @@ bool motorsActive() {
void testMotor(int n) {
print("Testing motor %d\n", n);
motors[n] = 0.2;
motors[n] = 1;
delay(50); // ESP32 may need to wait until the end of the current cycle to change duty https://github.com/espressif/arduino-esp32/issues/5306
sendMotors();
pause(3);
+2 -6
View File
@@ -36,16 +36,13 @@ Parameter parameters[] = {
{"CTL_R_RATE_I", &rollRatePID.i},
{"CTL_R_RATE_D", &rollRatePID.d},
{"CTL_R_RATE_WU", &rollRatePID.windup},
{"CTL_R_RATE_D_A", &rollRatePID.lpf.alpha},
{"CTL_P_RATE_P", &pitchRatePID.p},
{"CTL_P_RATE_I", &pitchRatePID.i},
{"CTL_P_RATE_D", &pitchRatePID.d},
{"CTL_P_RATE_WU", &pitchRatePID.windup},
{"CTL_P_RATE_D_A", &pitchRatePID.lpf.alpha},
{"CTL_Y_RATE_P", &yawRatePID.p},
{"CTL_Y_RATE_I", &yawRatePID.i},
{"CTL_Y_RATE_D", &yawRatePID.d},
{"CTL_Y_RATE_D_A", &yawRatePID.lpf.alpha},
{"CTL_R_P", &rollPID.p},
{"CTL_R_I", &rollPID.i},
{"CTL_R_D", &rollPID.d},
@@ -73,7 +70,6 @@ Parameter parameters[] = {
{"IMU_GYRO_BIAS_A", &gyroBiasFilter.alpha},
// estimate
{"EST_ACC_WEIGHT", &accWeight},
{"EST_LVL_WEIGHT", &levelWeight},
{"EST_RATES_LPF_A", &ratesFilter.alpha},
// motors
{"MOT_PIN_FL", &motorPins[MOTOR_FRONT_LEFT], setupMotors},
@@ -110,8 +106,8 @@ Parameter parameters[] = {
{"RC_MODE", &modeChannel},
// wifi
{"WIFI_MODE", &wifiMode},
{"WIFI_PORT_LOC", &udpLocalPort},
{"WIFI_PORT_REM", &udpRemotePort},
{"WIFI_LOC_PORT", &udpLocalPort},
{"WIFI_REM_PORT", &udpRemotePort},
// mavlink
{"MAV_SYS_ID", &mavlinkSysId},
{"MAV_RATE_SLOW", &telemetrySlow.rate},
-7
View File
@@ -3,8 +3,6 @@
// Power management
#include <soc/soc.h>
#include <soc/rtc_cntl_reg.h>
#include "lpf.h"
#include "util.h"
@@ -13,11 +11,6 @@ LowPassFilter<float> voltageFilter(0.2);
int voltagePin = -1;
float voltageScale = 2;
void setupPower() {
// Disable reset on low voltage
REG_CLR_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ENA);
}
void readVoltage() {
if (voltagePin < 0) return;
static Rate rate(10);
+1 -1
View File
@@ -6,7 +6,7 @@
#include <SBUS.h>
#include "util.h"
SBUS rc(Serial1);
SBUS rc(Serial2);
int rcRxPin = -1; // -1 means disabled
uint16_t channels[16]; // raw rc channels
+2 -2
View File
@@ -37,8 +37,8 @@ void descend() {
void autoFailsafe() {
static float roll, pitch, yaw, throttle;
if (roll != controlRoll || pitch != controlPitch || yaw != controlYaw || abs(throttle - controlThrottle) > 0.05) {
// controls changed and mode switch is not configured
if (mode == AUTO && invalid(controlMode)) mode = STAB; // regain control by the pilot
// controls changed
if (mode == AUTO) mode = STAB; // regain control by the pilot
}
roll = controlRoll;
pitch = controlPitch;
+7
View File
@@ -6,6 +6,8 @@
#pragma once
#include <math.h>
#include <soc/soc.h>
#include <soc/rtc_cntl_reg.h>
const float ONE_G = 9.80665;
extern float t;
@@ -33,6 +35,11 @@ float wrapAngle(float angle) {
return angle;
}
// Disable reset on low voltage
void disableBrownOut() {
REG_CLR_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ENA);
}
// Trim and split string by spaces
void splitString(String& str, String& token0, String& token1, String& token2) {
str.trim();
+3 -16
View File
@@ -105,23 +105,10 @@ public:
}
static Vector rotationVectorBetween(const Vector& a, const Vector& b) {
float an = a.norm();
float bn = b.norm();
if (an < 1e-6 || bn < 1e-6) {
return Vector(0, 0, 0);
}
Vector direction = cross(a, b);
if (direction.norm() < 1e-6) { // vectors are parallel
if (dot(a, b) > 0) { // same direction
return Vector(0, 0, 0);
}
// opposite direction
Vector perp = cross(a, Vector(1, 0, 0));
if (perp.norm() < 1e-6) {
perp = cross(a, Vector(0, 1, 0));
}
perp.normalize();
return perp * PI;
if (direction.zero()) {
// vectors are opposite, return any perpendicular vector
return cross(a, Vector(1, 0, 0));
}
direction.normalize();
float angle = angleBetween(a, b);
-1
View File
@@ -25,7 +25,6 @@ void setupWiFi() {
} else if (wifiMode == W_STA) {
WiFi.begin(storage.getString("WIFI_STA_SSID", "").c_str(), storage.getString("WIFI_STA_PASS", "").c_str());
}
WiFi.setSleep(false); // disable power save
udp.begin(udpLocalPort);
}
+1 -3
View File
@@ -21,8 +21,6 @@
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
template<typename T> T max(T a, T b) { return a > b ? a : b; }
template<typename T> T min(T a, T b) { return a < b ? a : b; }
long map(long x, long in_min, long in_max, long out_min, long out_max) {
const long run = in_max - in_min;
@@ -151,7 +149,7 @@ public:
void setRxInvert(bool invert) {};
};
HardwareSerial Serial, Serial1, Serial2;
HardwareSerial Serial, Serial2;
class EspClass {
public:
-2
View File
@@ -27,13 +27,11 @@ void step();
void computeLoopRate();
void applyGyro();
void applyAcc();
void applyLevel();
void control();
void interpretControls();
void controlAttitude();
void controlRates();
void controlTorque();
void desaturate(float& a, float& b, float& c, float& d);
const char* getModeName();
void sendMotors();
int getDutyCycle(float value);
+1
View File
@@ -1,3 +1,4 @@
// Dummy file to make it possible to compile simulator with Flix' util.h
#define WRITE_PERI_REG(addr, val) {}
#define REG_CLR_BIT(_r, _b) {}
+2 -2
View File
@@ -24,13 +24,13 @@ pip install pyflix
The API is accessed through the `Flix` class:
```python
from pyflix import Flix
from flix import Flix
flix = Flix() # create a Flix object and wait for connection
```
### Telemetry
Basic telemetry is available through object properties. The property names generally match the corresponding variables in the firmware code:
Basic telemetry is available through object properties. The property names generally match the corresponding variables in the firmware itself:
```python
print(flix.connected) # True if connected to the drone
+1 -2
View File
@@ -186,8 +186,7 @@ class Flix:
self._trigger('motors', self.motors)
if isinstance(msg, mavlink.MAVLink_scaled_imu_message):
ONE_G = 9.80665
self.acc = self._mavlink_to_flu([msg.xacc * ONE_G / 1000, msg.yacc * ONE_G / 1000, msg.zacc * ONE_G / 1000])
self.acc = self._mavlink_to_flu([msg.xacc / 1000, msg.yacc / 1000, msg.zacc / 1000])
self.gyro = self._mavlink_to_flu([msg.xgyro / 1000, msg.ygyro / 1000, msg.zgyro / 1000])
self._trigger('acc', self.acc)
self._trigger('gyro', self.gyro)
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "pyflix"
version = "0.14"
version = "0.11"
description = "Python API for Flix drone"
authors = [{ name="Oleg Kalachev", email="okalachev@gmail.com" }]
license = "MIT"