四轴飞控8——处理飞行状态

发布时间:2026/6/26 4:08:54

四轴飞控8——处理飞行状态 目录一、VSCode(1)App_receive_data.h(2)App_receive_data.c(3)App_freertos_task.c(4)Com_config.h(5)飞行状态机(6)油门解锁状态机二、可能遇到的问题一、VSCode(1)App_receive_data.h#ifndef __APP_RECEIVE_DATA__ #define __APP_RECEIVE_DATA__ #include Int_SI24R1.h #include Com_config.h // 定义帧头校验的值 #define FRAME_HEAD_CHECK_1 s #define FRAME_HEAD_CHECK_2 g #define FRAME_HEAD_CHECK_3 g // 最大重试次数 #define MAX_RETRY_TIMES 10 /** * brief 接收遥控器发送的遥控数据 解析为结构体 * * return uint8_t 0:校验通过 是正常的数据 1:没收到数据 或者 校验失败 */ uint8_t App_receive_data(void); /** * brief 处理连接状态的状态 * * param res 上一次接收数据的返回值 */ void App_process_connect_state(uint8_t res); /** * brief 处理飞机的飞行状态 * */ void App_process_flight_state(void); #endif // __APP_RECEIVE_DATA__(2)App_receive_data.c#include App_receive_data.h extern Remote_Data remote_data; uint8_t rx_buff[TX_PLOAD_WIDTH] {0}; // 遥控连接状态 extern Remote_State remote_state; // 飞行状态 extern Flight_State flight_state; // 油门解锁状态值 Thr_state thr_state FREE; // MAX状态的进入时间 uint32_t max_enter_time 0; // MIN状态的进入时间 uint32_t min_enter_time 0; // 重试次数 uint8_t retry_count 0; /** * brief 接收遥控器发送的遥控数据 解析为结构体 * * return uint8_t 0:校验通过 是正常的数据 1:没收到数据 或者 校验失败 */ uint8_t App_receive_data(void) { memset(rx_buff, 0, TX_PLOAD_WIDTH); Int_SI24R1_RxPacket(rx_buff); if (strlen((char *)rx_buff) 0) { return 1; } // 1. 帧头校验 if (rx_buff[0] ! FRAME_HEAD_CHECK_1 || rx_buff[1] ! FRAME_HEAD_CHECK_2 || rx_buff[2] ! FRAME_HEAD_CHECK_3) { return 1; } // 2. 帧尾校验 uint32_t sum 0; uint32_t sum_receive 0; for (uint8_t i 0; i 13; i) { sum rx_buff[i]; } // 高位在前 sum_receive rx_buff[13] 24 | rx_buff[14] 16 | rx_buff[15] 8 | rx_buff[16]; if (sum ! sum_receive) { return 1; } // 3. 保存数据 remote_data.thr (rx_buff[3] 8) | rx_buff[4]; remote_data.yaw (rx_buff[5] 8) | rx_buff[6]; remote_data.pit (rx_buff[7] 8) | rx_buff[8]; remote_data.rol (rx_buff[9] 8) | rx_buff[10]; remote_data.shutdown rx_buff[11]; remote_data.fix_height rx_buff[12]; debug_printf(:%d,%d,%d,%d,%d,%d\n, remote_data.thr, remote_data.yaw, remote_data.pit, remote_data.rol, remote_data.shutdown, remote_data.fix_height); return 0; } /** * brief 处理连接状态的状态 * * param res 上一次接收数据的返回值 */ void App_process_connect_state(uint8_t res) { if (res 0) { // 接收数据成功一次 即为连接成功 // 此处使用的全局变量 只有当前一个地方会修改 LED灯控任务当中是读取使用 remote_state REMOTE_CONNECTED; retry_count 0; } else if (res 1) { // 接收数据失败 即为 retry_count; if (retry_count MAX_RETRY_TIMES) { remote_state REMOTE_DISCONNECTED; retry_count 0; } } } /** * brief 处理解锁逻辑 * * return uint8_t 0: 解锁成功 1: 解锁失败 */ static uint8_t App_process_unlock(void) { // 1. 考虑安全问题 解锁完成的最终状态应该是油门为0 switch (thr_state) { case FREE: if (remote_data.thr 900) { // 2. 进入max状态 thr_state MAX; // freeRTOS操作系统中以ms为单位计数的时间 max_enter_time xTaskGetTickCount(); } break; case MAX: // 3. 持续的时间应该是离开的时间减去进入的时间 if (remote_data.thr 900) { if (xTaskGetTickCount() - max_enter_time 1000) { // 4. 油门保持最高状态超过1s 进入leave_max状态 thr_state LEAVE_MAX; } else { // 5. 油门保持最高状态时间小于1s 退回到free 重新解锁 thr_state FREE; } } break; case LEAVE_MAX: if (remote_data.thr 100) { // 6. 油门回到0 进入min状态 thr_state MIN; min_enter_time xTaskGetTickCount(); } break; case MIN: // 7. 每次判断当前已经保持了多久 if (xTaskGetTickCount() - min_enter_time 1000) { // 还不够1s if (remote_data.thr 100) { thr_state FREE; } } else { // 已经保持够1s 解锁完成 thr_state UNLOCK; } break; case UNLOCK: /* code */ break; default: break; } if (thr_state UNLOCK) { return 0; } return 1; } /** * brief 处理飞机的飞行状态 * */ void App_process_flight_state(void) { // 使用状态机逻辑实现 // 1. 轮询调用判断当前所处的状态 switch (flight_state) { case IDLE: // 2. 只需要编写指向其他状态的代码即可 if (App_process_unlock() 0) { flight_state NORMAL; // 每一次解锁成功 需要将解锁状态重置 thr_state FREE; } break; case NORMAL: // 3. 判断进入定高 if (remote_data.fix_height 1) { flight_state FIX_HEIGHT; remote_data.fix_height 0; } // 4. 判断进入故障失联状态 if (remote_state REMOTE_DISCONNECTED) { flight_state FAIL; } break; case FIX_HEIGHT: // 5. 取消定高 if (remote_data.fix_height 1) { flight_state NORMAL; remote_data.fix_height 0; } // 6. 判断故障 if (remote_state REMOTE_DISCONNECTED) { flight_state FAIL; } break; case FAIL: // 7.处理失联故障 缓慢停止电机 // TODO vTaskDelay(1); flight_state IDLE; break; default: break; } }(3)App_freertos_task.c#include App_freeRTOS_Task.h // STM32F103C8T6 SRAM 20k 分配12K给操作系统 // 内存管理 C语言中的结构体通常保存在堆中 不会自动垃圾回收 始终使用同一个结构体 不断循环使用 // 电机结构体 Motor_Struct left_top_motor {.tim htim3, .channel TIM_CHANNEL_1, .speed 200}; Motor_Struct left_bottom_motor {.tim htim4, .channel TIM_CHANNEL_4, .speed 200}; Motor_Struct right_top_motor {.tim htim2, .channel TIM_CHANNEL_2, .speed 200}; Motor_Struct right_bottom_motor {.tim htim1, .channel TIM_CHANNEL_3, .speed 200}; // LED结构体 LED_Struct left_top_led {.port LED1_GPIO_Port, .pin LED1_Pin}; LED_Struct right_top_led {.port LED2_GPIO_Port, .pin LED2_Pin}; LED_Struct right_bottom_led {.port LED3_GPIO_Port, .pin LED3_Pin}; LED_Struct left_bottom_led {.port LED4_GPIO_Port, .pin LED4_Pin}; // 表示当前连接状态 Remote_State remote_state REMOTE_DISCONNECTED; // 表示当前的飞行状态 Flight_State flight_state IDLE; // 扩展获取接收的遥控数据 Remote_Data remote_data {0}; // 电源管理任务 void power_task(void *args); // 最小推荐填写128 128*4 512B #define POWER_TASK_STACK_SIZE 128 // 任务优先级 数值越小 优先级越小 最大4 不推荐使用最小优先级0 #define POWER_TASK_PRIORITY 4 TaskHandle_t power_task_handle; // 定义任务的周期 #define POWER_TASK_PERIOD 10000 // 飞行控制任务 void flight_task(void *args); #define FLIGHT_TASK_STACK_SIZE 128 #define FLIGHT_TASK_PRIORITY 3 TaskHandle_t flight_task_handle; #define FLIGHT_TASK_PERIOD 6 // LED任务 void led_task(void *args); #define LED_TASK_STACK_SIZE 128 #define LED_TASK_PRIORITY 1 TaskHandle_t led_task_handle; #define LED_TASK_PERIOD 100 // 通讯任务 void com_task(void *args); #define COM_TASK_STACK_SIZE 128 #define COM_TASK_PRIORITY 2 TaskHandle_t com_task_handle; // 任务周期 #define COM_TASK_PERIOD 6 /** * brief 启动freeRTOS操作系统 * */ void App_freeRTOS_start(void) { // 1. 创建电源管理任务 xTaskCreate(power_task, power_task, POWER_TASK_STACK_SIZE, NULL, POWER_TASK_PRIORITY, power_task_handle); // 2. 创建飞行控制任务 xTaskCreate(flight_task, flight_task, FLIGHT_TASK_STACK_SIZE, NULL, FLIGHT_TASK_PRIORITY, flight_task_handle); // 3. 创建LED灯任务 xTaskCreate(led_task, led_task, LED_TASK_STACK_SIZE, NULL, LED_TASK_PRIORITY, led_task_handle); // 4. 创建通讯任务 xTaskCreate(com_task, com_task, COM_TASK_STACK_SIZE, NULL, COM_TASK_PRIORITY, com_task_handle); // 5. 启动调度器 vTaskStartScheduler(); } void power_task(void *args) { // 获取当前的基准时间 TickType_t xLastWakeTime xTaskGetTickCount(); while (1) { // // 每10s执行一次 启动电源 避免自动关机 // vTaskDelayUntil(xLastWakeTime, POWER_TASK_PERIOD); // // 启动电源 // Int_IP5305T_start(); // 使用直接任务通知的接收方法实现10s处理一次 // 一直等任务通知 直到收到通知res1 或者 超时res0 uint32_t res ulTaskNotifyTake(pdTRUE, POWER_TASK_PERIOD); if (res ! 0) { // 收到关机通知 Int_IP5305T_shutdown(); } else { // 不需要关机 正常执行启动 Int_IP5305T_start(); } } } void flight_task(void *args) { // 获取当前的基准时间 TickType_t xLastWakeTime xTaskGetTickCount(); while (1) { // 1. 设置电机的转速 left_top_motor.speed 400; // 2. 直接启动电机 // Int_motor_start(left_top_motor); // Int_motor_start(right_bottom_motor); vTaskDelayUntil(xLastWakeTime, FLIGHT_TASK_PERIOD); } } void led_task(void *args) { // 获取当前的基准时间 TickType_t xLastWakeTime xTaskGetTickCount(); uint8_t count 0; while (1) { count; // 前两个灯表示连接状态 // 1. 判断当前连接状态 if (remote_state REMOTE_CONNECTED) { // 点亮前两个灯 Int_led_turn_on(left_top_led); Int_led_turn_on(right_top_led); } else if (remote_state REMOTE_DISCONNECTED) { // 关掉前两个灯 Int_led_turn_off(left_top_led); Int_led_turn_off(right_top_led); } // 后两个灯表示飞行状态 // 2. 判断当前飞行状态 if (flight_state IDLE) { // 灯慢闪烁 500ms亮 500ms灭 if (count % 5 0) { // 循环5次 一次是100ms 5次等于500ms Int_led_toggle(left_bottom_led); Int_led_toggle(right_bottom_led); } } else if (flight_state NORMAL) { // 灯快闪 200ms亮 200ms灭 if (count % 2 0) { // 循环2次 一次是100ms 2次等于200ms Int_led_toggle(left_bottom_led); Int_led_toggle(right_bottom_led); } } else if (flight_state FIX_HEIGHT) { // 后两个灯常量 Int_led_turn_on(left_bottom_led); Int_led_turn_on(right_bottom_led); } else if (flight_state FAIL) { // 后两个灯灭 Int_led_turn_off(left_bottom_led); Int_led_turn_off(right_bottom_led); } // 将count计数重置 if (count 10) { count 0; } vTaskDelayUntil(xLastWakeTime, LED_TASK_PERIOD); } } void com_task(void *args) { // 获取当前的基准时间 TickType_t xLastWakeTime xTaskGetTickCount(); while (1) { // 1. 接收数据 uint8_t res App_receive_data(); // 2. 根据接收数据的返回值 处理当前飞机的连接状态 App_process_connect_state(res); // 3. 处理关机命令 if (remote_data.shutdown 1) { // 使用Int_IP5305T_shutdown 关机 功能可以实现 但是项目结构比较奇怪 // Int_IP5305T_shutdown(); // 使用freeRTOS直接任务通知 通知电源任务 执行关机 xTaskNotifyGive(power_task_handle); } // 4. 处理飞机的飞行状态 App_process_flight_state(); // 6ms执行一次 接收数据的时间间隔应该等于发送数据的时间间隔 vTaskDelayUntil(xLastWakeTime, COM_TASK_PERIOD); } }(4)Com_config.h#ifndef _COM_CONFIG_H #define _COM_CONFIG_H #include main.h // 连接状态 typedef enum { REMOTE_CONNECTED 0, REMOTE_DISCONNECTED, }Remote_State; // 飞行状态 typedef enum { IDLE 0, NORMAL, FIX_HEIGHT, FAIL, }Flight_State; // 油门解锁状态 typedef enum { FREE 0, MAX, LEAVE_MAX, MIN, UNLOCK, } Thr_state; typedef struct { int16_t thr; int16_t yaw; int16_t pit; int16_t rol; uint8_t shutdown; // 1: 关闭 0: 不关机 uint8_t fix_height; // 1. 切换定高和不定高 0: 不切换 } Remote_Data; #endif // !_COM_CONFIG_H(5)飞行状态机(6)油门解锁状态机二、可能遇到的问题在飞控失联/故障的情况下小灯没有熄灭是因为油门解锁状态没有设为FREE

相关新闻