Featured image of post [002号机]FPV起飞装置

[002号机]FPV起飞装置

暑假航模队训练时做的小装置

前言

之后要参加的比赛要求赛机从一个桶中起飞,桶必须保持完整,因此我需要设计一个能快速开启的起飞装置

我的设想是桶分为外壳和内部支架两部分,关闭状态外壳下部被固定在支架上部,开启后外壳落下,这样能在保证桶完整的前提下,实现快速打开。开关部分打算用舵机或电磁铁

老登机如下:

零号机

这是在知道新规则前设计的,桶被切开了,万万没想到今年的规则和去年不一样,于是还没测试就死了

一号机

v1.0

ddl临近,没有时间精雕细琢和现学知识了,就做了个简陋的框架,然后ai写了代码,可以实现蓝牙连接后,用蓝牙串口调试软件发送信息,控制舵机旋转

v2.0

整体大改,这次想出了完整的供电方案,画了舵机架和桶导轨

硬件清单

两个 7.4V 锂电池,三个降压模块,两个ESP32,两个舵机

接收端接线

接收端锂电池 → 并联两个降压模块:

降压模块1: 输出5V → 两个舵机 VCC 舵机GND ↔ 主GND

降压模块2: 输出5V → ESP32 VIN 引脚 ESP32 GND ↔ 降压模块2 GND ↔ 舵机 GND(共地)

遥控端接线

遥控端锂电池 → 降压模块: → ESP32 VIN → ESP32 GND ↔ 降压模块 GND

通信采用ESP-NOW

v3.0

买的东西还没到,从老登机上拆零件时,突然琢磨明白了老登机的原理。原来老登机用的是433遥控器,比espnow成本低还稳定方便,所以打算改成这个新方案,不得不感慨我知识的不足

硬件清单

一个7.4V 锂电池,一个3.7V 锂电池,一个降压模块,一个ESP32,一个433MHz 发送与接收模块,两个舵机

电路接线

7.4V 锂电池 ──► 降压模块1 → 输出 5V → 并联连接两个舵机的 VCC和ESP32VIN 舵机GND → 接主GND 3.7V 锂电池──►433模块 IN+ 433模块 IN- 接电池GND 433模块 OUT- 接主GND 433模块 OUT+ → 接 ESP32 数字输入引脚

注意:433 接收模块的电源地(IN-)不要和主电源地混接,但信号输出的 GND 要共地,否则 ESP32 无法识别信号,刚开始因为错误接线排查了好久

程序如下:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "driver/mcpwm_prelude.h"
#include "driver/gpio.h"

static const char *TAG = "dual_servo_433";

// GPIO配置
#define SERVO1_GPIO              12   // 舵机1 PWM信号GPIO
#define SERVO2_GPIO              13   // 舵机2 PWM信号GPIO  
#define RF433_GPIO               14   // 433MHz接收器GPIO

// 舵机参数
#define SERVO_MIN_PULSEWIDTH_US 500
#define SERVO_MAX_PULSEWIDTH_US 2500
#define SERVO_MIN_DEGREE        -90
#define SERVO_MAX_DEGREE        90
#define SERVO_TIMEBASE_RESOLUTION_HZ 1000000
#define SERVO_TIMEBASE_PERIOD        20000

// 舵机角度
#define SERVO_CLOSE_ANGLE  -5   // 关闭角度
#define SERVO_OPEN_ANGLE   150  // 开启角度

// 控制命令
typedef struct {
    int state;       // 0=关闭, 1=开启
} servo_command_t;

// 全局变量
static mcpwm_cmpr_handle_t comparator1 = NULL;
static mcpwm_cmpr_handle_t comparator2 = NULL;
static QueueHandle_t servo_queue;
static int servo_state = 0;
static int last_rf433_state = 0;

// 角度转PWM值
static inline uint32_t angle_to_compare(int angle)
{
    if (angle < SERVO_MIN_DEGREE) angle = SERVO_MIN_DEGREE;
    if (angle > SERVO_MAX_DEGREE) angle = SERVO_MAX_DEGREE;
    
    return (angle - SERVO_MIN_DEGREE) * (SERVO_MAX_PULSEWIDTH_US - SERVO_MIN_PULSEWIDTH_US) / 
           (SERVO_MAX_DEGREE - SERVO_MIN_DEGREE) + SERVO_MIN_PULSEWIDTH_US;
}

// 舵机控制任务
static void servo_control_task(void *arg)
{
    servo_command_t cmd;
    
    while (1) {
        if (xQueueReceive(servo_queue, &cmd, portMAX_DELAY)) {
            servo_state = cmd.state;
            int target_angle = cmd.state ? SERVO_OPEN_ANGLE : SERVO_CLOSE_ANGLE;
            uint32_t compare_value = angle_to_compare(target_angle);
            
            // 设置两个舵机
            mcpwm_comparator_set_compare_value(comparator1, compare_value);
            mcpwm_comparator_set_compare_value(comparator2, compare_value);
            
            ESP_LOGI(TAG, "Servos: %s (%d°)", cmd.state ? "OPEN" : "CLOSE", target_angle);
            vTaskDelay(pdMS_TO_TICKS(500));
        }
    }
}

// 433MHz检测任务
static void rf433_task(void *arg)
{
    servo_command_t cmd;
    
    while (1) {
        int current_rf433_state = gpio_get_level(RF433_GPIO);
        
        if (last_rf433_state != current_rf433_state) {
            vTaskDelay(pdMS_TO_TICKS(50)); // 防抖
            
            if (gpio_get_level(RF433_GPIO) == current_rf433_state) {
                int new_state = current_rf433_state ? 1 : 0;
                
                if (new_state != servo_state) {
                    cmd.state = new_state;
                    xQueueSend(servo_queue, &cmd, pdMS_TO_TICKS(100));
                }
            }
        }
        
        last_rf433_state = current_rf433_state;
        vTaskDelay(pdMS_TO_TICKS(20));
    }
}

// 初始化单个舵机
static esp_err_t init_servo(int gpio_num, mcpwm_cmpr_handle_t *comparator, int group_id)
{
    // 创建定时器
    mcpwm_timer_handle_t timer = NULL;
    mcpwm_timer_config_t timer_config = {
        .group_id = group_id,
        .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
        .resolution_hz = SERVO_TIMEBASE_RESOLUTION_HZ,
        .period_ticks = SERVO_TIMEBASE_PERIOD,
        .count_mode = MCPWM_TIMER_COUNT_MODE_UP,
    };
    ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config, &timer));

    // 创建操作符
    mcpwm_oper_handle_t oper = NULL;
    mcpwm_operator_config_t operator_config = {
        .group_id = group_id,
    };
    ESP_ERROR_CHECK(mcpwm_new_operator(&operator_config, &oper));
    ESP_ERROR_CHECK(mcpwm_operator_connect_timer(oper, timer));

    // 创建比较器
    mcpwm_comparator_config_t comparator_config = {
        .flags.update_cmp_on_tez = true,
    };
    ESP_ERROR_CHECK(mcpwm_new_comparator(oper, &comparator_config, comparator));

    // 创建发生器
    mcpwm_gen_handle_t generator = NULL;
    mcpwm_generator_config_t generator_config = {
        .gen_gpio_num = gpio_num,
    };
    ESP_ERROR_CHECK(mcpwm_new_generator(oper, &generator_config, &generator));

    // 配置PWM
    ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(generator,
        MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
    ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(generator,
        MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, *comparator, MCPWM_GEN_ACTION_LOW)));

    // 启动定时器
    ESP_ERROR_CHECK(mcpwm_timer_enable(timer));
    ESP_ERROR_CHECK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
    
    return ESP_OK;
}

// 初始化433MHz GPIO
static void init_rf433_gpio(void)
{
    gpio_config_t io_conf = {
        .intr_type = GPIO_INTR_DISABLE,
        .mode = GPIO_MODE_INPUT,
        .pin_bit_mask = (1ULL << RF433_GPIO),
        .pull_down_en = GPIO_PULLDOWN_ENABLE,
        .pull_up_en = GPIO_PULLUP_DISABLE,
    };
    ESP_ERROR_CHECK(gpio_config(&io_conf));
}

void app_main(void)
{
    ESP_LOGI(TAG, "Starting Dual Servo 433MHz Control");
    
    // 创建队列
    servo_queue = xQueueCreate(10, sizeof(servo_command_t));
    
    // 初始化GPIO
    init_rf433_gpio();
    
    // 初始化舵机
    init_servo(SERVO1_GPIO, &comparator1, 0);
    init_servo(SERVO2_GPIO, &comparator2, 1);
    
    // 设置初始位置为关闭
    uint32_t close_value = angle_to_compare(SERVO_CLOSE_ANGLE);
    mcpwm_comparator_set_compare_value(comparator1, close_value);
    mcpwm_comparator_set_compare_value(comparator2, close_value);
    
    // 创建任务
    xTaskCreate(servo_control_task, "servo_control", 4096, NULL, 5, NULL);
    xTaskCreate(rf433_task, "rf433_task", 2048, NULL, 7, NULL);
    
    ESP_LOGI(TAG, "System initialized - 433MHz HIGH=OPEN, LOW=CLOSE");
    
    // 主循环
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(10000));
    }
}

最终组装

画板子

我用的是嘉立创eda,首先创建工程

原理图界面shift+f查找元件,然后放置元件

按w连线,完成原理图绘制

alt+i生成pcb,先调整元件位置

然后布线,需要注意的是gnd不连线,而是给板子铺铜

最后绘制板框,添加丝印,完成

打板效果与最终电路部分

赛机

飞控上面焊接好四个电机,接收机,电源线,接上图传,然后组装好就行了,非常简单。

有一个需要注意的点就是需要新增一个电机作为发射器

完成

Like 0
May you find your worth in the waking world.
使用 Hugo 构建
主题 StackJimmy 设计