2026-04-04 02:39:41 +01:00
|
|
|
#include "drone.h"
|
|
|
|
|
|
2026-04-06 00:27:32 +01:00
|
|
|
#include "DShotRMT.h"
|
|
|
|
|
#include "Eigen/Core"
|
2026-04-13 14:36:24 +01:00
|
|
|
#include "driver/rmt_tx.h"
|
2026-04-06 00:27:32 +01:00
|
|
|
#include "drone_comms.h"
|
2026-04-04 02:39:41 +01:00
|
|
|
#include "drone_controller.h"
|
|
|
|
|
|
2026-04-06 00:27:32 +01:00
|
|
|
#include "dshot_definitions.h"
|
2026-04-04 02:39:41 +01:00
|
|
|
#include "esp32-hal.h"
|
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
|
#include "freertos/idf_additions.h"
|
|
|
|
|
#include "freertos/projdefs.h"
|
|
|
|
|
#include "freertos/task.h"
|
|
|
|
|
#include "imu.h"
|
2026-04-06 00:27:32 +01:00
|
|
|
#include "nav.h"
|
|
|
|
|
#include "packet_handler.h"
|
2026-04-04 02:39:41 +01:00
|
|
|
#include "sens_fus.h"
|
2026-04-06 00:27:32 +01:00
|
|
|
#include "soc/gpio_num.h"
|
2026-04-04 02:39:41 +01:00
|
|
|
#include <cstdint>
|
2026-04-06 00:27:32 +01:00
|
|
|
#include <cstring>
|
|
|
|
|
#include <optional>
|
2026-04-04 02:39:41 +01:00
|
|
|
|
2026-04-06 00:27:32 +01:00
|
|
|
#define CONTROLLER_TASK_FREQUENCY 1000.0;
|
2026-04-04 02:39:41 +01:00
|
|
|
|
|
|
|
|
dcont::ControllerConfig default_config() {
|
|
|
|
|
dcont::ControllerConfig config;
|
|
|
|
|
|
|
|
|
|
// 1. Configure the PID Stack
|
|
|
|
|
// Note: kp, ki, kd are arrays of 3 [roll, pitch, yaw]
|
|
|
|
|
|
|
|
|
|
// Position Loop (Position -> Velocity)
|
|
|
|
|
config.stack.position_pid = {
|
|
|
|
|
{1.0f, 1.0f, 1.0f}, // kp
|
|
|
|
|
{0.0f, 0.0f, 0.0f}, // ki
|
|
|
|
|
{0.0f, 0.0f, 0.0f}, // kd
|
2026-04-13 14:36:24 +01:00
|
|
|
5.0f // frequency (Hz)
|
2026-04-04 02:39:41 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Velocity Loop (Velocity -> Acceleration/Tilt)
|
|
|
|
|
config.stack.linvel_pid = {
|
2026-04-13 14:36:24 +01:00
|
|
|
{1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, 15.0f};
|
2026-04-04 02:39:41 +01:00
|
|
|
|
|
|
|
|
// Rotation Loop (Angle -> Angular Rate)
|
|
|
|
|
config.stack.rotation_pid = {
|
2026-04-13 14:36:24 +01:00
|
|
|
{4.0f, 4.0f, 4.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f}, 50.0f};
|
2026-04-04 02:39:41 +01:00
|
|
|
|
|
|
|
|
// Rate Loop (Angular Rate -> Torque) - The "Inner" Loop
|
2026-04-13 14:36:24 +01:00
|
|
|
config.stack.rate_pid = {{0.1f, 0.1f, 1.0f},
|
|
|
|
|
{0.01f, 0.01f, 0.01f},
|
|
|
|
|
{0.001f, 0.001f, 0.001f},
|
|
|
|
|
100.0f};
|
2026-04-04 02:39:41 +01:00
|
|
|
// 2. Set Constraints
|
|
|
|
|
config.stack.max_rate = 3.14f; // ~180 degrees/s
|
|
|
|
|
config.stack.max_linvel = 10.0f; // 10 m/s
|
|
|
|
|
|
|
|
|
|
// 3. Physical Drone Properties
|
|
|
|
|
config.mass = 0.350f; // kg
|
|
|
|
|
config.max_thrust = 2.6f; // Newtons
|
|
|
|
|
config.max_torque = 0.5f; // Nm
|
2026-04-13 14:36:24 +01:00
|
|
|
/*
|
|
|
|
|
* roll, pitch, yaw
|
2026-04-04 02:39:41 +01:00
|
|
|
{1.0f, -1.0f, 1.0f}, // Front Right
|
|
|
|
|
{-1.0f, -1.0f, -1.0f}, // Front Left
|
|
|
|
|
{-1.0f, 1.0f, 1.0f}, // Rear Left
|
|
|
|
|
{1.0f, 1.0f, -1.0f} // Rear Right
|
2026-04-13 14:36:24 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
float mixer[4][3] = {
|
|
|
|
|
{1.0f, -1.0f, 1.0f}, // Front Right - Real front
|
|
|
|
|
{-1.0f, -1.0f, -1.0f}, // Front Left - Real left
|
|
|
|
|
{-1.0f, 1.0f, 1.0f}, // Rear Left - Real rear
|
|
|
|
|
{1.0f, 1.0f, -1.0f} // Rear Right - Real right
|
2026-04-04 02:39:41 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
for (int j = 0; j < 3; j++) {
|
|
|
|
|
config.motor_map[i][j] = mixer[i][j];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setup_drone() { drone_controller = dcont::create(default_config()); }
|
|
|
|
|
|
2026-04-06 00:27:32 +01:00
|
|
|
void drone_cont_stabilize() {
|
|
|
|
|
// TODO: Implement stabilization. if |angvel| > something, we should make it 0
|
|
|
|
|
// first, then if falling fast, pull rotation to the side, then when falling
|
|
|
|
|
// is stabilized, turn slowly up until pointing up. let velocity dissipate
|
|
|
|
|
// afterwards
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-04 02:39:41 +01:00
|
|
|
void drone_controller_task(void *params) {
|
|
|
|
|
setup_drone();
|
|
|
|
|
uint8_t wait_ms = 1000.0 / CONTROLLER_TASK_FREQUENCY;
|
|
|
|
|
|
|
|
|
|
imu_state imu_state_local;
|
|
|
|
|
Eigen::Vector3f position_local = Eigen::Vector3f::Zero();
|
|
|
|
|
Eigen::Vector3f velocity_local = Eigen::Vector3f::Zero();
|
|
|
|
|
|
|
|
|
|
while (true) {
|
2026-04-06 03:39:08 +01:00
|
|
|
if (imu_state_mutex && xSemaphoreTake(imu_state_mutex, 1)) {
|
2026-04-04 02:39:41 +01:00
|
|
|
imu_state_local = imu_state_var;
|
|
|
|
|
xSemaphoreGive(imu_state_mutex);
|
|
|
|
|
}
|
2026-04-06 03:39:08 +01:00
|
|
|
if (sens_fus_mutex && xSemaphoreTake(sens_fus_mutex, 1)) {
|
2026-04-04 02:39:41 +01:00
|
|
|
position_local = sens_fus.position;
|
|
|
|
|
velocity_local = sens_fus.velocity;
|
|
|
|
|
xSemaphoreGive(sens_fus_mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dcont::set_cur_time(drone_controller, millis() / 1000.0f);
|
|
|
|
|
dcont::set_cur_angvel(drone_controller, v3f_to_v3c(imu_state_local.angvel));
|
|
|
|
|
dcont::set_cur_linvel(drone_controller, v3f_to_v3c(velocity_local));
|
|
|
|
|
dcont::set_cur_pos(drone_controller, v3f_to_v3c(position_local));
|
|
|
|
|
dcont::set_cur_rot(drone_controller, imu_state_local.rot);
|
|
|
|
|
|
2026-04-06 00:27:32 +01:00
|
|
|
packet_controller_input cont_input;
|
|
|
|
|
if (current_input_mode == dcont::ModeInput::Acro &&
|
|
|
|
|
xSemaphoreTake(controller_input_semaphore, 10)) {
|
|
|
|
|
cont_input = current_controller_input;
|
|
|
|
|
|
|
|
|
|
xSemaphoreGive(controller_input_semaphore);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
waypoint wayp;
|
|
|
|
|
if (current_input_mode == dcont::ModeInput::Position &&
|
|
|
|
|
xSemaphoreTake(nav_mutex, 10)) {
|
|
|
|
|
wayp = nav_man.get_current_waypoint();
|
|
|
|
|
|
|
|
|
|
xSemaphoreGive(nav_mutex);
|
|
|
|
|
}
|
|
|
|
|
if (current_input_mode == dcont::ModeInput::Position &&
|
|
|
|
|
wayp.coords_in_axis == std::nullopt) {
|
|
|
|
|
drone_cont_stabilize();
|
|
|
|
|
} else {
|
|
|
|
|
auto coords = wayp.coords_in_axis.value_or(Eigen::Vector3f::Zero());
|
|
|
|
|
|
|
|
|
|
dcont::set_input(drone_controller,
|
|
|
|
|
dcont::Input{{cont_input.ly, cont_input.lx,
|
|
|
|
|
cont_input.rx, cont_input.ry},
|
|
|
|
|
{0.0, 0.0, 0.0},
|
|
|
|
|
{0.0, 0.0, 0.0},
|
|
|
|
|
{0.0, 0.0, 0.0},
|
|
|
|
|
{coords.x(), coords.y(), coords.z()},
|
|
|
|
|
current_input_mode});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(dcont::get_throttles(drone_controller).values, motor_throttles,
|
|
|
|
|
sizeof(motor_throttles));
|
|
|
|
|
|
2026-04-04 02:39:41 +01:00
|
|
|
vTaskDelay(pdMS_TO_TICKS(wait_ms));
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-06 00:27:32 +01:00
|
|
|
|
2026-04-13 14:36:24 +01:00
|
|
|
const gpio_num_t motor_pins[4] = {GPIO_NUM_46, GPIO_NUM_16, GPIO_NUM_14,
|
|
|
|
|
GPIO_NUM_15};
|
|
|
|
|
|
|
|
|
|
const bool reversed[4] = {false, true, false, false};
|
2026-04-06 00:27:32 +01:00
|
|
|
|
2026-04-13 14:36:24 +01:00
|
|
|
DShotRMT *motors[4];
|
2026-04-06 00:27:32 +01:00
|
|
|
void motor_throttles_task(void *params) {
|
2026-04-13 14:36:24 +01:00
|
|
|
|
2026-04-06 00:27:32 +01:00
|
|
|
for (int i = 0; i < 4; i++) {
|
2026-04-13 14:36:24 +01:00
|
|
|
motors[i] = new DShotRMT(motor_pins[i], DSHOT300, false);
|
|
|
|
|
|
|
|
|
|
motors[i]->begin();
|
|
|
|
|
|
|
|
|
|
rmt_tx_wait_all_done(motors[i]->_rmt_tx_channel, 2);
|
|
|
|
|
motors[i]->_cleanupRmtResources();
|
2026-04-06 00:27:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ARM
|
|
|
|
|
unsigned long armTime = millis();
|
2026-04-12 16:52:29 +01:00
|
|
|
while (millis() - armTime < 5000) {
|
2026-04-06 00:27:32 +01:00
|
|
|
for (int i = 0; i < 4; i++) {
|
2026-04-13 14:36:24 +01:00
|
|
|
motors[i]->begin();
|
2026-04-06 00:27:32 +01:00
|
|
|
motors[i]->sendThrottlePercent(0);
|
2026-04-13 14:36:24 +01:00
|
|
|
|
|
|
|
|
rmt_tx_wait_all_done(motors[i]->_rmt_tx_channel, 2);
|
|
|
|
|
// delayMicroseconds(50);
|
|
|
|
|
motors[i]->_cleanupRmtResources();
|
2026-04-06 00:27:32 +01:00
|
|
|
}
|
2026-04-13 14:36:24 +01:00
|
|
|
// vTaskDelay(1);
|
2026-04-06 00:27:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
2026-04-13 14:36:24 +01:00
|
|
|
motors[i]->begin();
|
|
|
|
|
|
|
|
|
|
motors[i]->sendThrottlePercent(motor_throttles[i] * 100.0f);
|
|
|
|
|
|
|
|
|
|
rmt_tx_wait_all_done(motors[i]->_rmt_tx_channel, 2);
|
|
|
|
|
// delayMicroseconds(50);
|
|
|
|
|
motors[i]->_cleanupRmtResources();
|
2026-04-06 00:27:32 +01:00
|
|
|
}
|
2026-04-13 14:36:24 +01:00
|
|
|
// vTaskDelay(1);
|
2026-04-06 00:27:32 +01:00
|
|
|
}
|
|
|
|
|
}
|