bare minimum to fly with a controller. initial navigation development. TODO: mark waypoints as inactive and continue to next when current one is reached, drone stabilization logic.

This commit is contained in:
franchioping 2026-04-06 00:27:32 +01:00
parent b315af0f66
commit bd81652515
10 changed files with 192 additions and 49 deletions

@ -1 +1 @@
Subproject commit 11a55db27127a10a99439cde27a04489bb7318d2 Subproject commit ac127154714cf9ce781757d7203651fed214b5ff

View File

@ -1,17 +1,26 @@
#include "drone.h" #include "drone.h"
#include "DShotRMT.h"
#include "Eigen/Core"
#include "drone_comms.h"
#include "drone_controller.h" #include "drone_controller.h"
#include "dshot_definitions.h"
#include "esp32-hal.h" #include "esp32-hal.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/idf_additions.h" #include "freertos/idf_additions.h"
#include "freertos/projdefs.h" #include "freertos/projdefs.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "imu.h" #include "imu.h"
#include "nav.h"
#include "packet_handler.h"
#include "sens_fus.h" #include "sens_fus.h"
#include "soc/gpio_num.h"
#include <cstdint> #include <cstdint>
#include <cstring>
#include <optional>
#define CONTROLLER_TASK_FREQUENCY 400.0; #define CONTROLLER_TASK_FREQUENCY 1000.0;
dcont::ControllerConfig default_config() { dcont::ControllerConfig default_config() {
dcont::ControllerConfig config; dcont::ControllerConfig config;
@ -39,7 +48,7 @@ dcont::ControllerConfig default_config() {
config.stack.rate_pid = {{0.2f, 0.2f, 2.0f}, config.stack.rate_pid = {{0.2f, 0.2f, 2.0f},
{0.05f, 0.05f, 0.05f}, {0.05f, 0.05f, 0.05f},
{0.003f, 0.003f, 0.001f}, {0.003f, 0.003f, 0.001f},
600.0f}; 1000.0f};
// 2. Set Constraints // 2. Set Constraints
config.stack.max_rate = 3.14f; // ~180 degrees/s config.stack.max_rate = 3.14f; // ~180 degrees/s
@ -69,6 +78,13 @@ dcont::ControllerConfig default_config() {
void setup_drone() { drone_controller = dcont::create(default_config()); } void setup_drone() { drone_controller = dcont::create(default_config()); }
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
}
void drone_controller_task(void *params) { void drone_controller_task(void *params) {
setup_drone(); setup_drone();
uint8_t wait_ms = 1000.0 / CONTROLLER_TASK_FREQUENCY; uint8_t wait_ms = 1000.0 / CONTROLLER_TASK_FREQUENCY;
@ -94,6 +110,69 @@ void drone_controller_task(void *params) {
dcont::set_cur_pos(drone_controller, v3f_to_v3c(position_local)); dcont::set_cur_pos(drone_controller, v3f_to_v3c(position_local));
dcont::set_cur_rot(drone_controller, imu_state_local.rot); dcont::set_cur_rot(drone_controller, imu_state_local.rot);
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));
vTaskDelay(pdMS_TO_TICKS(wait_ms)); vTaskDelay(pdMS_TO_TICKS(wait_ms));
} }
} }
const gpio_num_t motor_pins[4] = {GPIO_NUM_NC, GPIO_NUM_NC, GPIO_NUM_NC,
GPIO_NUM_NC};
void motor_throttles_task(void *params) {
DShotRMT *motors[4];
for (int i = 0; i < 4; i++) {
motors[i] = new DShotRMT(motor_pins[i], DSHOT150, false);
}
// ARM
unsigned long armTime = millis();
while (millis() - armTime < 4000) {
for (int i = 0; i < 4; i++) {
motors[i]->sendThrottlePercent(0);
}
}
while (true) {
for (int i = 0; i < 4; i++) {
if (!killswitch_active) {
motors[i]->sendThrottlePercent(motor_throttles[i] * 100.0f);
} else {
motors[i]->sendThrottlePercent(0.0f);
}
}
vTaskDelay(1);
}
}

View File

@ -22,3 +22,8 @@ inline dcont::StackedController *drone_controller = nullptr;
inline dcont::ModeInput current_input_mode; inline dcont::ModeInput current_input_mode;
void drone_controller_task(void *params); void drone_controller_task(void *params);
void motor_throttles_task(void *params);
inline float motor_throttles[4];
inline bool killswitch_active;

View File

@ -19,7 +19,6 @@
const float TO_RAD = M_PI / 180.0f; const float TO_RAD = M_PI / 180.0f;
const float KNOTS_TO_M_SEC = 0.5144444f; const float KNOTS_TO_M_SEC = 0.5144444f;
const float earth_radius = 6371000.0f; const float earth_radius = 6371000.0f;
struct GPS { struct GPS {
@ -73,8 +72,8 @@ struct GPS {
} }
std::optional<Eigen::Vector3f> get_coordinates() { std::optional<Eigen::Vector3f> get_coordinates() {
if (this->gps->fix == false || this->gps->latitudeDegrees == 0.0 || if (this->gps->fix == false || (this->gps->latitudeDegrees == 0.0 &&
this->gps->longitudeDegrees != 0.0) { this->gps->longitudeDegrees == 0.0)) {
return std::nullopt; return std::nullopt;
} }
float latitude = this->gps->latitudeDegrees; float latitude = this->gps->latitudeDegrees;

View File

@ -33,7 +33,7 @@ void setup_imu() {
imu->rpt.rv_game.enable(2500UL); imu->rpt.rv_game.enable(2500UL);
imu->rpt.linear_accelerometer.enable(2500UL); imu->rpt.linear_accelerometer.enable(2500UL);
imu->rpt.cal_gyro.enable(2500UL); imu->rpt.cal_gyro.enable(1000UL);
imu->register_cb([imu, local_state]() { imu->register_cb([imu, local_state]() {
bool needs_updating = false; bool needs_updating = false;

View File

@ -44,6 +44,10 @@ extern "C" void app_main(void) {
0 // Core ID 0 // Core ID
); );
xTaskCreate(env_sens::baro_poll_task, "baro_poll", 8192, NULL, 1, NULL);
xTaskCreate(gps_poll_task, "gps_poll", 8192, NULL, 5, NULL);
xTaskCreatePinnedToCore(drone_controller_task, // Function name xTaskCreatePinnedToCore(drone_controller_task, // Function name
"drone_controller_task", // Name for debugging "drone_controller_task", // Name for debugging
1024 * 32, // Stack size in bytes 1024 * 32, // Stack size in bytes
@ -53,20 +57,29 @@ extern "C" void app_main(void) {
1 // Core ID 1 // Core ID
); );
xTaskCreate(env_sens::baro_poll_task, "baro_poll", 8192, NULL, 1, NULL); xTaskCreatePinnedToCore(motor_throttles_task, // Function name
"motor_throttles_task", // Name for debugging
xTaskCreate(gps_poll_task, "gps_poll", 8192, NULL, 5, NULL); 1024 * 4, // Stack size in bytes
NULL, // Parameters
20, // Priority (higher = more urgent)
NULL, // Task handle
1 // Core ID
);
ESP_LOGI("MAIN", "All tasks spawned. Main loop free."); ESP_LOGI("MAIN", "All tasks spawned. Main loop free.");
Eigen::Vector3f local_pos = {0, 0, 0}; Eigen::Vector3f local_pos = {0, 0, 0};
Eigen::Vector3f local_vel = {0, 0, 0}; Eigen::Vector3f local_vel = {0, 0, 0};
bool nav_data_ready = false; bool nav_data_ready = false;
uint64_t last_print_time = 0;
while (true) { while (true) {
while (xQueueReceive(packet_tx_queue, &packet_data[0], 1)) { while (xQueueReceive(packet_tx_queue, &packet_data[0], 1)) {
handle_packet(&packet_data[0]); handle_packet(&packet_data[0]);
} }
if (millis() > last_print_time + 1000) {
std::optional<Eigen::Vector3f> coords; std::optional<Eigen::Vector3f> coords;
float lat, lon, alt; float lat, lon, alt;
if (gps_mutex && xSemaphoreTake(gps_mutex, (TickType_t)10) == pdTRUE) { if (gps_mutex && xSemaphoreTake(gps_mutex, (TickType_t)10) == pdTRUE) {
@ -102,7 +115,8 @@ extern "C" void app_main(void) {
ESP_LOGI(TAG, "nav(vel): (%f, %f, %f)", local_vel[0], local_vel[1], ESP_LOGI(TAG, "nav(vel): (%f, %f, %f)", local_vel[0], local_vel[1],
local_vel[2]); local_vel[2]);
} }
}
vTaskDelay(pdMS_TO_TICKS(1000)); vTaskDelay(pdMS_TO_TICKS(10));
} }
} }

View File

@ -2,7 +2,10 @@
#include "Eigen/Core" #include "Eigen/Core"
#include "freertos/idf_additions.h" #include "freertos/idf_additions.h"
#include "gps.h"
#include <cmath>
#include <cstdint> #include <cstdint>
#include <optional>
#ifdef PS #ifdef PS
#undef PS #undef PS
@ -17,8 +20,9 @@
#define WAYPOINT_COUNT 8 #define WAYPOINT_COUNT 8
struct waypoint { struct waypoint {
Eigen::Vector3f coords; // lon, lat, alt Eigen::Vector3f coords; // lat, lon, alt
bool active; // active or to be skipped std::optional<Eigen::Vector3f> coords_in_axis = std::nullopt;
bool active = false; // active or to be skipped
}; };
struct drone_nav { struct drone_nav {
@ -40,6 +44,16 @@ struct drone_nav {
} }
return mask; return mask;
} }
waypoint get_current_waypoint() {
waypoint wayp = this->waypoints[this->current_waypoint];
if (!wayp.coords_in_axis.has_value()) {
auto axis =
gps->waypoint_to_xyz(wayp.coords[0], wayp.coords[1], wayp.coords[2]);
wayp.coords_in_axis = axis;
}
return wayp;
}
}; };
inline SemaphoreHandle_t nav_mutex = NULL; inline SemaphoreHandle_t nav_mutex = NULL;

View File

@ -1,7 +1,10 @@
#include "packet_handler.h" #include "packet_handler.h"
#include "Eigen/Core" #include "Eigen/Core"
#include "drone.h"
#include "drone_comms.h" #include "drone_comms.h"
#include "drone_controller.h"
#include "esp_log.h"
#include "freertos/idf_additions.h" #include "freertos/idf_additions.h"
#include "gps.h" #include "gps.h"
#include "nav.h" #include "nav.h"
@ -32,13 +35,38 @@ void handle_packet(uint8_t *packet_addr) {
} }
// NAV SETTERS // NAV SETTERS
if (packet_type >= PACKET_TYPE::DRONE_NAV_WAYPOINT_0 && else if (packet_type >= PACKET_TYPE::DRONE_NAV_WAYPOINT_0 &&
packet_type <= PACKET_TYPE::DRONE_NAV_WAYPOINT_7) { packet_type <= PACKET_TYPE::DRONE_NAV_WAYPOINT_7) {
uint8_t index = packet_type - PACKET_TYPE::DRONE_NAV_WAYPOINT_0; uint8_t index = packet_type - PACKET_TYPE::DRONE_NAV_WAYPOINT_0;
handle_waypoint_update(packet_addr, index); handle_waypoint_update(packet_addr, index);
} } else if (packet_type == PACKET_TYPE::DRONE_NAV) {
if (packet_type == PACKET_TYPE::DRONE_NAV) {
handle_nav_update(packet_addr); handle_nav_update(packet_addr);
} else if (packet_type == PACKET_TYPE::KILLSWITCH_TOGGLE) {
packet_killswitch_toggle *packet =
(packet_killswitch_toggle *)(packet_addr + sizeof(PACKET_TYPE));
killswitch_active = packet->killswitch_active;
} else if (packet_type == PACKET_TYPE::MODE_INPUT) {
packet_mode_input *packet =
(packet_mode_input *)(packet_addr + sizeof(PACKET_TYPE));
switch (packet->input_type) {
case INPUT_TYPE::ACRO:
current_input_mode = dcont::ModeInput::Acro;
break;
case INPUT_TYPE::LEVEL:
case INPUT_TYPE::STABILIZE_FALL:
ESP_LOGE("PACKET_HANDLER",
"INPUT TYPES NOT IMPLEMENTED. DEFAULTING TO POSITION (AUTONAV)");
case INPUT_TYPE::AUTO_NAV:
current_input_mode = dcont::ModeInput::Position;
}
} else if (packet_type == PACKET_TYPE::CONTROLLER_INPUT) {
packet_controller_input *packet =
(packet_controller_input *)(packet_addr + sizeof(PACKET_TYPE));
if (xSemaphoreTake(controller_input_semaphore, 10)) {
current_controller_input = *packet;
xSemaphoreGive(controller_input_semaphore);
}
} }
} }

View File

@ -2,4 +2,10 @@
#include <cstdint> #include <cstdint>
#include "drone_comms.h"
#include "freertos/idf_additions.h"
void handle_packet(uint8_t *packet_addr); void handle_packet(uint8_t *packet_addr);
inline SemaphoreHandle_t controller_input_semaphore = NULL;
inline packet_controller_input current_controller_input;

View File

@ -5,7 +5,5 @@
inline QueueHandle_t packet_rx_queue = NULL; inline QueueHandle_t packet_rx_queue = NULL;
inline QueueHandle_t packet_tx_queue = NULL; inline QueueHandle_t packet_tx_queue = NULL;
inline SemaphoreHandle_t controller_input_semaphore = NULL;
inline packet_controller_input current_controller_input;
void radio_task(void *pvParameters); void radio_task(void *pvParameters);