ESP32-CAN/main/drone.h

312 lines
11 KiB
C
Raw Normal View History

#pragma once
2026-04-24 01:41:23 +01:00
#include "Eigen/Core"
2026-04-19 18:46:42 +01:00
#include "esp_log.h"
2026-04-20 20:31:10 +01:00
#include "gps.h"
2026-04-18 17:16:06 +01:00
#include "nav.h"
#include "esp32-hal.h"
2026-04-17 00:24:52 +01:00
#include <atomic>
#include <cmath>
#include <cstdint>
2026-04-17 00:24:52 +01:00
#include <stdatomic.h>
#ifdef PS
#undef PS
#endif
#ifdef F
#undef F
#endif
#include <Eigen/Dense>
2026-04-07 10:48:44 +01:00
#include "drone_comms.h"
#include "drone_controller.h"
2026-04-17 00:24:52 +01:00
#include "packet_handler.h"
#include "imu.h"
#include "packet_handler.h"
#include "sens_fus.h"
#define CONNECTION_LOST_THRESHOLD 200
2026-04-24 01:41:23 +01:00
#define MAX_LANDING_LINVEL 2.0
2026-04-18 17:16:06 +01:00
void setup_drone();
inline dcont::Vec3C v3f_to_v3c(Eigen::Vector3f v) { return {v[0], v[1], v[2]}; }
void drone_controller_task(void *params);
void motor_throttles_task(void *params);
2026-04-13 14:36:24 +01:00
// 3 4 2 1
2026-04-17 00:24:52 +01:00
inline float *motor_throttles = nullptr;
2026-04-24 01:41:23 +01:00
inline std::atomic_bool killswitch_active = true;
2026-04-17 00:24:52 +01:00
dcont::ControllerConfig default_config();
struct drone_cont_state {
bool angvel_stablilized;
bool fall_vel_stabilized;
2026-04-20 02:52:05 +01:00
dcont::Input last_input;
2026-04-17 00:24:52 +01:00
Eigen::Vector3f pos;
Eigen::Vector3f vel;
Eigen::Quaternionf rot;
Eigen::Vector3f angvel;
dcont::StackedController *drone_controller;
2026-04-24 01:41:23 +01:00
atomic_uint_fast8_t current_input_mode = INPUT_TYPE::AUTO_NAV;
2026-04-17 00:24:52 +01:00
void init() { this->drone_controller = dcont::create(default_config()); }
void drone_cont_stabilize() {
2026-04-24 01:41:23 +01:00
2026-04-17 00:24:52 +01:00
// 1. ANGLE VELOCITY STABILIZATION
// Kill the spin first to ensure sensors/control loops can work accurately.
if (!this->angvel_stablilized) {
2026-04-24 01:41:23 +01:00
2026-04-17 00:24:52 +01:00
if (this->angvel.norm() < 1.0) {
this->angvel_stablilized = true;
2026-04-24 01:41:23 +01:00
} else {
dcont::set_input(drone_controller,
dcont::Input{.joystick = {.throttle_input = 0.0,
.roll_input = 0.0,
.yaw_input = 0.0,
.pitch_input = 0.0},
.acceleration = {0.0, 0.0, 0.0},
.rotation = {0.0, 0.0, 0.0},
.velocity = {0.0, 0.0, 0.0},
.position = {0.0, 0.0, 0.0},
.mode = dcont::ModeInput::Acro});
2026-04-17 00:24:52 +01:00
}
}
// 2. FALL VELOCITY STABILIZATION (WITH PROP WASH AVOIDANCE)
// Instead of climbing straight up, we move at an angle.
if (!this->fall_vel_stabilized) {
if (this->vel.z() - 1.0 >= 0) {
this->fall_vel_stabilized = true;
2026-04-24 01:41:23 +01:00
} else {
dcont::set_input(drone_controller,
dcont::Input{.joystick = {.throttle_input = 0.6,
.roll_input = 0.0,
.yaw_input = 0.0,
.pitch_input = 0.0},
.acceleration = {0.0, 0.0, 0.0},
.rotation = {0.0, M_PI / 8, 0.0},
.velocity = {0.0, 0.0, 0.0},
.position = {0.0, 0.0, 0.0},
.mode = dcont::ModeInput::Rotation});
2026-04-17 00:24:52 +01:00
}
}
dcont::set_input(drone_controller,
dcont::Input{.joystick = {.throttle_input = 0.0,
.roll_input = 0.0,
.yaw_input = 0.0,
.pitch_input = 0.0},
.acceleration = {0.0, 0.0, 0.0},
.rotation = {0.0, 0.0, 0.0},
.velocity = {0.0, 0.0, 0.0},
.position = {0.0, 0.0, 0.0},
.mode = dcont::ModeInput::Velocity});
}
inline bool stabilization_done() {
return this->fall_vel_stabilized && this->angvel_stablilized;
}
2026-04-24 01:41:23 +01:00
Eigen::Vector3f velocity_hist[25];
int velocity_hist_index = 0;
2026-04-17 00:24:52 +01:00
void fetch_sens() {
static imu_state imu_state_local;
if (imu_state_mutex && xSemaphoreTake(imu_state_mutex, 1)) {
imu_state_local = imu_state_var;
xSemaphoreGive(imu_state_mutex);
this->angvel = imu_state_local.angvel;
2026-04-24 01:41:23 +01:00
this->rot = imu_state_local.rot;
2026-04-17 00:24:52 +01:00
}
if (sens_fus_mutex && xSemaphoreTake(sens_fus_mutex, 1)) {
this->pos = sens_fus.position;
2026-04-24 01:41:23 +01:00
velocity_hist[velocity_hist_index] = sens_fus.velocity;
velocity_hist_index++;
velocity_hist_index = velocity_hist_index % 25;
2026-04-17 00:24:52 +01:00
xSemaphoreGive(sens_fus_mutex);
}
2026-04-24 01:41:23 +01:00
this->vel = Eigen::Vector3f::Zero();
for (int i = 0; i < 25; i++) {
this->vel += velocity_hist[i] / 25.0f;
}
2026-04-17 00:24:52 +01:00
}
void update_controller_sens() {
dcont::set_cur_time(drone_controller, millis() / 1000.0f);
dcont::set_cur_angvel(drone_controller, v3f_to_v3c(this->angvel));
dcont::set_cur_linvel(drone_controller, v3f_to_v3c(this->vel));
dcont::set_cur_pos(drone_controller, v3f_to_v3c(this->pos));
dcont::set_cur_rot(drone_controller, dcont::QuatC{.i = this->rot.x(),
.j = this->rot.y(),
.k = this->rot.z(),
.w = this->rot.w()});
}
void update_throttles() {
2026-04-19 18:46:42 +01:00
auto thrt_var = dcont::get_throttles(drone_controller);
auto thrt = thrt_var.values;
memcpy(motor_throttles, thrt, sizeof(float) * 4);
2026-04-17 00:24:52 +01:00
}
void update_input() {
2026-04-20 22:24:16 +01:00
packet_controller_input c;
2026-04-24 01:41:23 +01:00
bool input_was_set = false;
2026-04-17 00:24:52 +01:00
switch (atomic_load(&this->current_input_mode)) {
2026-04-24 01:41:23 +01:00
2026-04-17 00:24:52 +01:00
case INPUT_TYPE::ACRO: {
2026-04-20 02:52:05 +01:00
if (controller_input_semaphore &&
xSemaphoreTake(controller_input_semaphore, 10)) {
2026-04-20 22:24:16 +01:00
c = current_controller_input;
2026-04-17 00:24:52 +01:00
xSemaphoreGive(controller_input_semaphore);
2026-04-24 01:41:23 +01:00
float ly = 0.6 * c.ly + 0.15;
2026-04-17 00:24:52 +01:00
2026-04-24 01:41:23 +01:00
auto inp = dcont::Input{.joystick = {.throttle_input = ly,
2026-04-20 22:24:16 +01:00
.roll_input = c.rx,
.yaw_input = c.lx,
2026-04-24 01:41:23 +01:00
.pitch_input = -c.ry},
2026-04-20 22:24:16 +01:00
.acceleration = {0.0, 0.0, 0.0},
2026-04-24 01:41:23 +01:00
.rotation = {0.0, 0.0, 0.0},
2026-04-20 22:24:16 +01:00
.velocity = {0.0, 0.0, 0.0},
.position = {0.0, 0.0, 0.0},
2026-04-24 01:41:23 +01:00
.mode = dcont::ModeInput::Acro};
2026-04-20 02:52:05 +01:00
dcont::set_input(drone_controller, inp);
2026-04-24 01:41:23 +01:00
this->last_input = inp;
input_was_set = true;
}
} break;
2026-04-20 02:52:05 +01:00
2026-04-24 01:41:23 +01:00
case INPUT_TYPE::LEVEL: {
if (controller_input_semaphore &&
xSemaphoreTake(controller_input_semaphore, 10)) {
c = current_controller_input;
2026-04-20 20:31:10 +01:00
2026-04-24 01:41:23 +01:00
xSemaphoreGive(controller_input_semaphore);
float ly = 0.6 * c.ly + 0.15;
auto inp =
dcont::Input{.joystick = {.throttle_input = ly,
.roll_input = c.rx,
.yaw_input = c.lx,
.pitch_input = -c.ry},
.acceleration = {0.0, 0.0, 0.0},
.rotation = {-c.ry * 7 * 0.087f, c.rx * 7 * 0.087f,
c.lx * (float)M_PI},
.velocity = {0.0, 0.0, 0.0},
.position = {0.0, 0.0, 0.0},
.mode = dcont::ModeInput::Rotation};
dcont::set_input(drone_controller, inp);
this->last_input = inp;
input_was_set = true;
2026-04-17 00:24:52 +01:00
}
} break;
2026-04-24 01:41:23 +01:00
case INPUT_TYPE::VELOCITY: {
if (controller_input_semaphore &&
xSemaphoreTake(controller_input_semaphore, 10)) {
c = current_controller_input;
xSemaphoreGive(controller_input_semaphore);
auto inp = dcont::Input{
.joystick = {.throttle_input = 0.0,
.roll_input = 0.0,
.yaw_input = 0.0,
.pitch_input = 0.0},
.acceleration = {c.rx * 6.0f, c.ry * 6.0f, c.ly * 6.0f},
.rotation = {0.0, 0.0, 0.0},
.velocity = {c.rx * 5.0f, c.ry * 5.0f, c.ly * 5.0f},
.position = {0.0, 0.0, 0.0},
.mode = dcont::ModeInput::Acceleration};
dcont::set_input(drone_controller, inp);
this->last_input = inp;
input_was_set = true;
}
} break;
case INPUT_TYPE::AUTO_NAV: {
if (!stabilization_done()) {
drone_cont_stabilize();
} else if (xSemaphoreTake(nav_mutex, 10)) {
waypoint wayp = nav_man.get_current_waypoint();
if (nav_man.current_waypoint == 8) {
dcont::set_max_linvel(this->drone_controller, MAX_LANDING_LINVEL);
}
xSemaphoreGive(nav_mutex);
if (wayp.coords_in_axis == std::nullopt) {
drone_cont_stabilize();
} else {
auto coords = wayp.coords_in_axis.value();
dcont::set_input(
drone_controller,
dcont::Input{.joystick = {.throttle_input = 0.0,
.roll_input = 0.0,
.yaw_input = 0.0,
.pitch_input = 0.0},
.acceleration = {0.0, 0.0, 0.0},
.rotation = {0.0, 0.0, 0.0},
.velocity = {0.0, 0.0, 0.0},
.position = {coords.x(), coords.y(), coords.z()},
.mode = dcont::ModeInput::Position});
input_was_set = true;
}
} else {
drone_cont_stabilize();
}
break;
}
default:
case INPUT_TYPE::STABILIZE_FALL: {
drone_cont_stabilize();
break;
}
}
if (!input_was_set) {
if (atomic_load(&this->current_input_mode) != INPUT_TYPE::AUTO_NAV) {
auto inp = dcont::Input{.joystick = {.throttle_input = 0.0,
.roll_input = 0.0,
.yaw_input = 0.0,
.pitch_input = 0.0},
.acceleration = {0.0, 0.0, 0.0},
.rotation = {0.0, 0.0, 0.0},
.velocity = {0.0, 0.0, 0.0},
.position = {0.0, 0.0, 0.0},
.mode = dcont::ModeInput::Acro};
dcont::set_input(drone_controller, inp);
this->last_input = inp;
} else {
this->drone_cont_stabilize();
}
2026-04-17 00:24:52 +01:00
}
}
void update() {
this->fetch_sens();
this->update_controller_sens();
this->update_input();
this->update_throttles();
}
};
inline drone_cont_state *drone_cont = nullptr;