[项目]基于FreeRTOS的STM32四轴飞行器: 十六.激光测距定高功能

基于FreeRTOS的STM32四轴飞行器: 十六.激光测距定高功能

一.芯片介绍

激光测高芯片在飞控板下侧:

原理图如下:

型号为:VL53LX1,为国产仿制,使用I2C进行通信。

GPIO1为中断引脚,XSHUT为上拉关机引脚,如果给予低电平可以关闭芯片,高电平正常使用,每次上电初始化重启 芯片可以防止I2C时序不对。

手册解读:

I2C默认地址为0X52。

二.配置CubeMX

配置I2C2:

配置PB12引脚:

三.激光测距芯片驱动编写

移植驱动:

将原厂代码拷贝到项目。

初始化:

先拉低引脚重启芯片,接着使用API初始化芯片,之后设置距离模式长距或短距,之后设置测量速度测量频率,测量速度意思是从测量开始到结束需要的时间,测量频率是多久测一次需要大于等于测量速度,最后一步开始测量。

c 复制代码
#define DEV 0x52
/**
 * @description: 初始化激光测距芯片
 * @return {*}
 */
void Inf_VL53LX1_Init(void)
{
    /* 1. 先重启芯片 */
    HAL_GPIO_WritePin(VL53LX1_SHUT_GPIO_Port, VL53LX1_SHUT_Pin, GPIO_PIN_RESET);
    HAL_Delay(500);
    HAL_GPIO_WritePin(VL53LX1_SHUT_GPIO_Port, VL53LX1_SHUT_Pin, GPIO_PIN_SET);

    /* 2. 初始化化芯片 */
    VL53L1X_SensorInit(DEV);

    /* 3. 设置距离模式: 长或短  1:short 2:long*/
    VL53L1X_SetDistanceMode(DEV, 2);

    /* 4. 测量的速度 */
    VL53L1X_SetTimingBudgetInMs(DEV, 20);

    /* 5. 测量的频率 ms值必须大于等于上一个*/
    VL53L1X_SetInterMeasurementInMs(DEV, 20);

    /* 6. 开始测量 */
    VL53L1X_StartRanging(DEV);

    uint16_t sensorID;
    VL53L1X_GetSensorId(DEV, &sensorID);
    printf("sensorID:0x%x\r\n", sensorID);
}

观察打印ID:

读取高度:

先判断是否准备好,如果准备好因为有中断机制先清除中断之后返回高度。

c 复制代码
/**
 * @description: 返回测到的高度
 * @return {*}
 */
uint16_t Inf_VL53LX1_GetHeight(void)
{
    static uint16_t height = 0;
    uint8_t         isDataReady;

    /* 检测测距是否完成 */
    VL53L1X_CheckForDataReady(DEV, &isDataReady);
    if(isDataReady)
    {
        VL53L1X_ClearInterrupt(DEV);
        /* 读取测距结果 */
        VL53L1X_GetDistance(DEV, &height);
    }

    return height;
}

获取飞机的飞行高度:

在获得后进行了测得高度的处理,判断是否发生了突变如果突变使用lastHeight。

c 复制代码
/**
 * @description: 获取飞机的飞行高度
 * @return {*} 高度: mm
 */
uint16_t App_Flight_GetHeight(void)
{
    static uint16_t lastHeight = 0;
    uint16_t height = Inf_VL53LX1_GetHeight();

    if (abs(height - lastHeight) > 500 || /* 如果有突变,则返回上次的值 */
        abs(joyStick.PIT - 500) > 100 ||  /* 有水平飞行, 返回上次的值 */
        abs(joyStick.ROL - 500) > 100)
    {
        return lastHeight;
    }

    height = Com_Filter_LowPass(height, lastHeight);
    lastHeight = height;

    return height;
}

观察打印数据:

观察发现打印数据正常。

四.定高PID的计算

代码:

创建定高状态机 根据状态执行定高。

状态0:根据按键是否解锁进入状态1。

状态1:计算PID前的准备,设置期望值,之后进入状态2计算PID。

状态2:进入状态2时判断是否要解除定高,因为飞行任务执行周期为20ms,所以需要5次来计算一次PID,对Z轴速度数据进行互补滤波。

c 复制代码
/**
 * @description: 高度pid控制
 * @param {Com_Status} isRemoteUnlocked
 * @param {uint16_t} height
 * @return {*}
 */
void App_Flight_PIDHeight(Com_Status isRemoteUnlocked, uint16_t height, float dt)
{
    /* 定高状态机:
        状态0: 检测是否定高
        状态1: 当前的油门值是定高时的油门值  当前的高度: 固定的高度
        状态2: 进行pid控制
     */
    static uint8_t status = 0;
    static uint16_t thrHold = 0;
    static uint16_t heightHold = 0;

    static float staticAcc = 0; /* 静态时z的加速度 */
    if (isRemoteUnlocked == Com_OK && staticAcc == 0)
    {
        staticAcc = Common_IMU_GetNormAccZ();
    }

    switch (status)
    {
    case 0: /* 定高检测 */
    {
        /* pid重置 */
        heightPID.result = 0;
        zSpeedPID.result = 0;
        if (isRemoteUnlocked == Com_OK && isFixHeight == Com_OK)
        {
            status = 1;
        }

        break;
    }

    case 1: /* pid计算前的准备 */
    {
        thrHold = joyStick.THR;
        heightHold = height;
        status = 2;
        break;
    }
    case 2: /* pid计算 */
    {
        /* 定高时: 油门变化超过100, 或者定高的标记为0. 解除定高 */
        if (abs(joyStick.THR - thrHold) > 100 || isFixHeight == Com_FAIL)
        {
            status = 0;               /* 回到状态0 */
            joyStick.isFixHeight = 0; /* 标记定高的变量置为0 */
            isFixHeight = Com_FAIL;
        }
        else
        {

            /* 由于高度变动的周期20ms, 所以我们需要5次来计算一次pid */
            static uint8_t cnt = 0;
            cnt++;
            if (cnt < 5)
                return;
            cnt = 0;
            dt *= 5;
            /* 对z的速度: 互补滤波 */
            float zSpeed = 0.9 * (zSpeedPID.measure + (Common_IMU_GetNormAccZ() - staticAcc) * dt) +
                           0.1 * (height - heightPID.measure) / dt;
            /*
                串级pid
                    外环  高度环
                    内环  z方向的速度环
             */
            heightPID.desire = heightHold;
            heightPID.measure = height;
            heightPID.dt = dt;

            zSpeedPID.measure = zSpeed;
            zSpeedPID.dt = dt;
            Com_PID_CascadePID(&heightPID, &zSpeedPID);
        }
        break;
    }
    default:
        break;
    }
}

设置两个定高PID 参数:

height为外环,speed为内环。

五.定高PID作用到电机上

代码:

将内环PID作用到最终的对象上,加上zPid对zPid进行限幅,注意需要在采集欧拉角后执行获取加速度的函数。

c 复制代码
/**
 * @description: 把定高的pid作用到motor上
 * @param {Com_Status} isRemoteUnlocked
 * @return {*}
 */
void App_Flight_MotorWithHeightPID(Com_Status isRemoteUnlocked)
{
    int16_t zPid = LIMIT(zSpeedPID.result, -150, 150);
    motorLeftTop.speed += zPid;
    motorLeftBottom.speed += zPid;
    motorRightTop.speed += zPid;
    motorRightBottom.speed += zPid;
}
相关推荐
LS_learner5 分钟前
小智机器人关键函数解析,Application::OutputAudio()处理音频数据的输出的函数
人工智能·嵌入式硬件
西城微科方案开发37 分钟前
体重秤PCBA电路方案组成结构
单片机·嵌入式硬件
深圳市青牛科技实业有限公司43 分钟前
「青牛科技 」GC4931P/4938/4939 12-24V三相有感电机驱动芯片 对标Allegro A4931/瑞盟MS4931
科技·单片机·扫地机器人吸尘·筋膜枪电机·驱动轮电机·服务机器人驱动轮电机·工业机器人减速电机
集和诚JHCTECH1 小时前
集和诚携手Intel重磅发布BRAV-7820边缘计算新品,为车路云一体化场景提供强大算力支撑
人工智能·嵌入式硬件·边缘计算
阿超爱嵌入式1 小时前
STM32学习笔记之RCC模块(实操篇)
笔记·stm32·学习
Qingniu011 小时前
「青牛科技」GC5849 12V三相无感正弦波电机驱动芯片
科技·单片机·嵌入式硬件·cpu散热风扇·vga显卡散热风扇·rgb机箱散热风扇·水冷泵及散热风扇
charlie1145141912 小时前
STM32F103C8T6单片机硬核原理篇:讨论GPIO的基本原理篇章1——只讨论我们的GPIO简单输入和输出
c语言·stm32·单片机·嵌入式硬件·gpio·数据手册
阿让啊2 小时前
bootloader+APP中,有些APP引脚无法正常使用?
c语言·开发语言·stm32·单片机·嵌入式硬件
可待电子单片机设计定制(论文)3 小时前
【51单片机】基于单片机的智能门禁系统设计
单片机·mongodb·51单片机
蝎蟹居3 小时前
GB/T 4706.1-2024 家用和类似用途电器的安全 第1部分:通用要求 与2005版差异(1)
人工智能·单片机·嵌入式硬件·物联网·安全