mirror of
https://github.com/okalachev/flix.git
synced 2026-03-30 03:54:20 +00:00
Compare commits
9 Commits
auto
...
a1539157b8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1539157b8 | ||
|
|
80922dc68a | ||
|
|
fcd2738763 | ||
|
|
fa07ed3a4e | ||
|
|
dee4d97ab3 | ||
|
|
ea35db37da | ||
|
|
cd953f24ad | ||
|
|
3f80712641 | ||
|
|
18bacb64f3 |
20
README.md
20
README.md
@@ -17,11 +17,11 @@
|
||||
|
||||
* Dedicated for education and research.
|
||||
* Made from general-purpose components.
|
||||
* Simple and clean source code in Arduino.
|
||||
* Control using remote control or smartphone.
|
||||
* Precise simulation with Gazebo.
|
||||
* Simple and clean source code in Arduino (<2k lines firmware).
|
||||
* Control using USB gamepad, remote control or smartphone.
|
||||
* Wi-Fi and MAVLink support.
|
||||
* Wireless command line interface and analyzing.
|
||||
* Precise simulation with Gazebo.
|
||||
* Python library.
|
||||
* Textbook on flight control theory and practice ([in development](https://quadcopter.dev)).
|
||||
* *Position control (using external camera) and autonomous flights¹*.
|
||||
@@ -38,7 +38,11 @@ Version 0 demo video: https://youtu.be/8GzzIQ3C6DQ.
|
||||
|
||||
<a href="https://youtu.be/8GzzIQ3C6DQ"><img width=500 src="https://i3.ytimg.com/vi/8GzzIQ3C6DQ/maxresdefault.jpg"></a>
|
||||
|
||||
See the [user builds gallery](docs/user.md).
|
||||
Usage in education (RoboCamp): https://youtu.be/Wd3yaorjTx0.
|
||||
|
||||
<a href="https://youtu.be/Wd3yaorjTx0"><img width=500 src="https://i3.ytimg.com/vi/Wd3yaorjTx0/sddefault.jpg"></a>
|
||||
|
||||
See the [user builds gallery](docs/user.md):
|
||||
|
||||
<a href="docs/user.md"><img src="docs/img/user/user.jpg" width=500></a>
|
||||
|
||||
@@ -63,8 +67,8 @@ The simulator is implemented using Gazebo and runs the original Arduino code:
|
||||
|Type|Part|Image|Quantity|
|
||||
|-|-|:-:|:-:|
|
||||
|Microcontroller board|ESP32 Mini|<img src="docs/img/esp32.jpg" width=100>|1|
|
||||
|IMU (and barometer²) board|GY‑91, MPU-9265 (or other MPU‑9250/MPU‑6500 board)<br>ICM‑20948³<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|
|
||||
|<span style="background:yellow">(Recommended) Buck-boost converter</span>|To be determined, output 5V or 3.3V, see [user-contributed schematics](https://miro.com/app/board/uXjVN-dTjoo=/?moveToWidget=3458764612179508274&cot=14)|<img src="docs/img/buck-boost.jpg" width=100>|1|
|
||||
|IMU (and barometer²) board|GY‑91, MPU-9265 (or other MPU‑9250/MPU‑6500 board)<br>ICM20948V2 (ICM‑20948)³<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|
|
||||
|<span style="background:yellow">Buck-boost converter</span> (recommended)|To be determined, output 5V or 3.3V, see [user-contributed schematics](https://miro.com/app/board/uXjVN-dTjoo=/?moveToWidget=3458764612179508274&cot=14)|<img src="docs/img/buck-boost.jpg" width=100>|1|
|
||||
|Motor|8520 3.7V brushed motor (shaft 0.8mm).<br>Motor with exact 3.7V voltage is needed, not ranged working voltage (3.7V — 6V).|<img src="docs/img/motor.jpeg" width=100>|4|
|
||||
|Propeller|Hubsan 55 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|
|
||||
@@ -77,7 +81,7 @@ The simulator is implemented using Gazebo and runs the original Arduino code:
|
||||
|Frame main part|3D printed⁴:<br>[`flix-frame-1.1.stl`](docs/assets/flix-frame-1.1.stl) [`flix-frame-1.1.step`](docs/assets/flix-frame-1.1.step)<br>Recommended settings: layer 0.2 mm, line 0.4 mm, infill 100%.|<img src="docs/img/frame1.jpg" width=100>|1|
|
||||
|Frame top part|3D printed:<br>[`esp32-holder.stl`](docs/assets/esp32-holder.stl) [`esp32-holder.step`](docs/assets/esp32-holder.step)|<img src="docs/img/esp32-holder.jpg" width=100>|1|
|
||||
|Washer for IMU board mounting|3D printed:<br>[`washer-m3.stl`](docs/assets/washer-m3.stl) [`washer-m3.step`](docs/assets/washer-m3.step)|<img src="docs/img/washer-m3.jpg" width=100>|2|
|
||||
|*RC transmitter (optional)*|*KINGKONG TINY X8 (warning: lacks USB support) or other⁵*|<img src="docs/img/tx.jpg" width=100>|1|
|
||||
|Controller (recommended)|CC2500 transmitter, like BetaFPV LiteRadio CC2500 (RC receiver/Wi-Fi).<br>Two-sticks gamepad (Wi-Fi only) — see [recommended gamepads](https://docs.qgroundcontrol.com/master/en/qgc-user-guide/setup_view/joystick.html#supported-joysticks).<br>Other⁵|<img src="docs/img/betafpv.jpg" width=100><img src="docs/img/logitech.jpg" width=80>|1|
|
||||
|*RC receiver (optional)*|*DF500 or other⁵*|<img src="docs/img/rx.jpg" width=100>|1|
|
||||
|Wires|28 AWG recommended|<img src="docs/img/wire-28awg.jpg" width=100>||
|
||||
|Tape, double-sided tape||||
|
||||
@@ -86,7 +90,7 @@ The simulator is implemented using Gazebo and runs the original Arduino code:
|
||||
*³ — change `MPU9250` to `ICM20948` in `imu.ino` file if using ICM-20948 board.*<br>
|
||||
*³⁻¹ — MPU-6050 supports I²C interface only (not recommended). To use it change IMU declaration to `MPU6050 IMU(Wire)`.*<br>
|
||||
*⁴ — this frame is optimized for GY-91 board, if using other, the board mount holes positions should be modified.*<br>
|
||||
*⁵ — you may use any transmitter-receiver pair with SBUS interface.*
|
||||
*⁵ — you also may use any transmitter-receiver pair with SBUS interface.*
|
||||
|
||||
Tools required for assembly:
|
||||
|
||||
|
||||
@@ -27,6 +27,6 @@
|
||||
|
||||
Вспомогательные файлы включают:
|
||||
|
||||
* [`vector.h`](https://github.com/okalachev/flix/blob/canonical/flix/vector.h), [`quaternion.h`](https://github.com/okalachev/flix/blob/canonical/flix/quaternion.h) — реализация библиотек векторов и кватернионов проекта.
|
||||
* [`vector.h`](https://github.com/okalachev/flix/blob/canonical/flix/vector.h), [`quaternion.h`](https://github.com/okalachev/flix/blob/canonical/flix/quaternion.h) — реализация библиотек векторов и кватернионов.
|
||||
* [`pid.h`](https://github.com/okalachev/flix/blob/canonical/flix/pid.h) — реализация общего ПИД-регулятора.
|
||||
* [`lpf.h`](https://github.com/okalachev/flix/blob/canonical/flix/lpf.h) — реализация общего фильтра нижних частот.
|
||||
|
||||
@@ -173,7 +173,7 @@ Before flight using remote control, you need to calibrate it:
|
||||
2. Type `cr` command there and follow the instructions.
|
||||
3. Use the remote control to fly the drone!
|
||||
|
||||
#### Control with USB remote control
|
||||
#### Control with USB remote control (Wi-Fi)
|
||||
|
||||
If your drone doesn't have RC receiver installed, you can use USB remote control and QGroundControl app to fly it.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Firmware source files are located in `flix` directory. The key files are:
|
||||
|
||||
Utility files include:
|
||||
|
||||
* [`vector.h`](../flix/vector.h), [`quaternion.h`](../flix/quaternion.h) — project's vector and quaternion libraries implementation.
|
||||
* [`vector.h`](../flix/vector.h), [`quaternion.h`](../flix/quaternion.h) — vector and quaternion libraries implementation.
|
||||
* [`pid.h`](../flix/pid.h) — generic PID controller implementation.
|
||||
* [`lpf.h`](../flix/lpf.h) — generic low-pass filter implementation.
|
||||
|
||||
|
||||
BIN
docs/img/betafpv.jpg
Normal file
BIN
docs/img/betafpv.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
BIN
docs/img/logitech.jpg
Normal file
BIN
docs/img/logitech.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
docs/img/user/robocamp/1.jpg
Normal file
BIN
docs/img/user/robocamp/1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 148 KiB |
@@ -6,6 +6,7 @@ Do the following:
|
||||
|
||||
* **Check ESP32 core is installed**. Check if the version matches the one used in the [tutorial](build.md#firmware).
|
||||
* **Check libraries**. Install all the required libraries from the tutorial. Make sure there are no MPU9250 or other peripherals libraries that may conflict with the ones used in the tutorial.
|
||||
* **Check the chosen board**. The correct board to choose in Arduino IDE for ESP32 Mini is *WEMOS D1 MINI ESP32*.
|
||||
|
||||
## The drone doesn't fly
|
||||
|
||||
|
||||
19
docs/user.md
19
docs/user.md
@@ -4,6 +4,25 @@ This page contains user-built drones based on the Flix project. Publish your pro
|
||||
|
||||
---
|
||||
|
||||
## RoboCamp
|
||||
|
||||
Author: RoboCamp participants.<br>
|
||||
Description: 3D-printed and wooden frames, ESP32 Mini, DC-DC buck-boost converters. BetaFPV LiteRadio 3 to control the drones via Wi-Fi connection.<br>
|
||||
Features: altitude hold, obstacle avoidance, autonomous flight elements.<br>
|
||||
Some of the designed model files: https://drive.google.com/drive/folders/18YHWGquKeIevzrMH4-OUT-zKXMETTEUu?usp=share_link.
|
||||
|
||||
RoboCamp took place in July 2025, Saint Petersburg, where 9 participants designed and built their own drones using the Flix project, and then modified the firmware to complete specific flight tasks.
|
||||
|
||||
See the detailed video about the event:
|
||||
|
||||
<a href="https://youtu.be/Wd3yaorjTx0"><img width=500 src="https://img.youtube.com/vi/Wd3yaorjTx0/sddefault.jpg"></a>
|
||||
|
||||
Built drones:
|
||||
|
||||
<img src="img/user/robocamp/1.jpg" width=500>
|
||||
|
||||
---
|
||||
|
||||
Author: chkroko.<br>
|
||||
Description: the first Flix drone built with **brushless motors** (DShot interface).<br>
|
||||
Features: SpeedyBee BLS 35A Mini V2 ESC, ESP32-S3 board, EMAX ECO 2 2207 1700kv motors, ICM20948V2 IMU, INA226 power monitor and Bluetooth gamepad for control.<br>
|
||||
|
||||
@@ -104,10 +104,7 @@ void doCommand(String str, bool echo = false) {
|
||||
print("qx: %f qy: %f qz: %f qw: %f\n", attitude.x, attitude.y, attitude.z, attitude.w);
|
||||
} else if (command == "imu") {
|
||||
printIMUInfo();
|
||||
print("gyro: %f %f %f\n", rates.x, rates.y, rates.z);
|
||||
print("acc: %f %f %f\n", acc.x, acc.y, acc.z);
|
||||
printIMUCalibration();
|
||||
print("rate: %.0f\n", loopRate);
|
||||
print("landed: %d\n", landed);
|
||||
} else if (command == "rc") {
|
||||
print("channels: ");
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#define WEIGHT_ACC 0.003
|
||||
#define RATES_LFP_ALPHA 0.2 // cutoff frequency ~ 40 Hz
|
||||
|
||||
LowPassFilter<Vector> ratesFilter(RATES_LFP_ALPHA);
|
||||
|
||||
void estimate() {
|
||||
applyGyro();
|
||||
applyAcc();
|
||||
@@ -20,6 +18,7 @@ void estimate() {
|
||||
|
||||
void applyGyro() {
|
||||
// filter gyro to get angular rates
|
||||
static LowPassFilter<Vector> ratesFilter(RATES_LFP_ALPHA);
|
||||
rates = ratesFilter.update(gyro);
|
||||
|
||||
// apply rates to attitude
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
// Fail-safe functions
|
||||
|
||||
#define RC_LOSS_TIMEOUT 0.2
|
||||
#define RC_LOSS_TIMEOUT 0.5
|
||||
#define DESCEND_TIME 3.0 // time to descend from full throttle to zero
|
||||
|
||||
extern double controlTime;
|
||||
|
||||
@@ -122,4 +122,12 @@ void printIMUInfo() {
|
||||
IMU.status() ? print("status: ERROR %d\n", IMU.status()) : print("status: OK\n");
|
||||
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", rates.x, rates.y, rates.z);
|
||||
print("acc: %f %f %f\n", acc.x, acc.y, acc.z);
|
||||
Vector rawGyro, rawAcc;
|
||||
IMU.getGyro(rawGyro.x, rawGyro.y, rawGyro.z);
|
||||
IMU.getAccel(rawAcc.x, rawAcc.y, rawAcc.z);
|
||||
print("raw gyro: %f %f %f\n", rawGyro.x, rawGyro.y, rawGyro.z);
|
||||
print("raw acc: %f %f %f\n", rawAcc.x, rawAcc.y, rawAcc.z);
|
||||
}
|
||||
|
||||
@@ -116,29 +116,31 @@ public:
|
||||
return euler;
|
||||
}
|
||||
|
||||
float getRoll() const {
|
||||
return toEuler().x;
|
||||
}
|
||||
|
||||
float getPitch() const {
|
||||
return toEuler().y;
|
||||
}
|
||||
|
||||
float getYaw() const {
|
||||
// https://github.com/ros/geometry2/blob/589caf083cae9d8fae7effdb910454b4681b9ec1/tf2/include/tf2/impl/utils.h#L122
|
||||
float yaw;
|
||||
float sqx = x * x;
|
||||
float sqy = y * y;
|
||||
float sqz = z * z;
|
||||
float sqw = w * w;
|
||||
double sarg = -2 * (x * z - w * y) / (sqx + sqy + sqz + sqw);
|
||||
if (sarg <= -0.99999) {
|
||||
yaw = -2 * atan2(y, x);
|
||||
} else if (sarg >= 0.99999) {
|
||||
yaw = 2 * atan2(y, x);
|
||||
} else {
|
||||
yaw = atan2(2 * (x * y + w * z), sqw + sqx - sqy - sqz);
|
||||
}
|
||||
return yaw;
|
||||
return toEuler().z;
|
||||
}
|
||||
|
||||
void setRoll(float roll) {
|
||||
Vector euler = toEuler();
|
||||
*this = Quaternion::fromEuler(Vector(roll, euler.y, euler.z));
|
||||
}
|
||||
|
||||
void setPitch(float pitch) {
|
||||
Vector euler = toEuler();
|
||||
*this = Quaternion::fromEuler(Vector(euler.x, pitch, euler.z));
|
||||
}
|
||||
|
||||
void setYaw(float yaw) {
|
||||
// TODO: optimize?
|
||||
Vector euler = toEuler();
|
||||
euler.z = yaw;
|
||||
(*this) = Quaternion::fromEuler(euler);
|
||||
*this = Quaternion::fromEuler(Vector(euler.x, euler.y, yaw));
|
||||
}
|
||||
|
||||
Quaternion operator * (const Quaternion& q) const {
|
||||
|
||||
Reference in New Issue
Block a user