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

server/2025/4/1 20:30:17/

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

  • 一.芯片介绍
  • 二.配置CubeMX
  • 三.激光测距芯片驱动编写
  • 四.定高PID的计算
  • 五.定高PID作用到电机上

一.芯片介绍

激光测高芯片在飞控板下侧:
在这里插入图片描述
原理图如下:
型号为:VL53LX1,为国产仿制,使用I2C进行通信。
在这里插入图片描述
GPIO1为中断引脚,XSHUT为上拉关机引脚,如果给予低电平可以关闭芯片,高电平正常使用,每次上电初始化重启芯片可以防止I2C时序不对。
在这里插入图片描述
手册解读:
I2C默认地址为0X52。
在这里插入图片描述

二.配置CubeMX

配置I2C2:
在这里插入图片描述
配置PB12引脚:
在这里插入图片描述

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

移植驱动:
将原厂代码拷贝到项目。
在这里插入图片描述
初始化:
先拉低引脚重启芯片,接着使用API初始化芯片,之后设置距离模式长距或短距,之后设置测量速度测量频率,测量速度意思是从测量开始到结束需要的时间,测量频率是多久测一次需要大于等于测量速度,最后一步开始测量。

#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:
在这里插入图片描述
读取高度:
先判断是否准备好,如果准备好因为有中断机制先清除中断之后返回高度。

/*** @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。

/*** @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轴速度数据进行互补滤波。

/*** @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进行限幅,注意需要在采集欧拉角后执行获取加速度的函数。

/*** @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;
}

http://www.ppmy.cn/server/180393.html

相关文章

人工智能模型的自我学习能力

一、自我学习的核心机制 现代AI模型通过以下技术路径实现自主知识获取与优化&#xff1a; 自主学习&#xff08;Self-supervised Learning&#xff09; 无监督特征提取&#xff1a;模型从非标注数据中自动发现规律&#xff0c;如CLIP模型通过对比学习建立图文跨模态关联。自模…

SQLAlchemy关键词搜索技术深度解析:从基础过滤到全文检索

在数据驱动的应用开发中&#xff0c;基于关键词的模糊查询是常见的业务需求。SQLAlchemy作为Python生态中最流行的ORM框架&#xff0c;提供了多种实现关键词搜索的技术方案。本文将从性能、适用场景和技术复杂度三个维度&#xff0c;系统对比分析SQLAlchemy中关键词搜索的最佳实…

第4章 IP网络扫描(网络安全评估)

你的网络有多安全&#xff1f;要回答这一问题&#xff0c;最好的方法是对其进行攻击。《网络安全评估》&#xff08;第二版&#xff09;为你提供了用于识别和评估网络安全的技巧和工具&#xff0c;通过学习本书&#xff0c;你可以掌握网络安全加固知识&#xff0c;从而避免网络…

SecureFX for Mac FTP/SSH传输工具

SecureFX for Mac FTP/SSH传输工具 文章目录 SecureFX for Mac FTP/SSH传输工具一、介绍二、效果三、下载 一、介绍 SecureFX mac版是一款Mac平台的FTP/SSH传输工具。SecureFX for Mac支持三种文件传输协议&#xff1a;FTP、SFTP 和 FTP over SSH2。它可以提供安全文件传输。无…

静态网页应用开发环境搭建实战教程

1. 前言 静态网页开发是前端工程师的基础技能之一&#xff0c;无论是个人博客、企业官网还是简单的Web应用&#xff0c;都离不开HTML、CSS和JavaScript。搭建一个高效的开发环境&#xff0c;能够极大提升开发效率&#xff0c;减少重复工作&#xff0c;并优化调试体验。 本教程…

脉冲编码器:精准定位与高效控制的科技先锋

在现代化工业与自动化控制的浪潮中&#xff0c;每一个微小的进步都可能引领一场技术革命。脉冲编码器&#xff0c;这一看似不起眼却至关重要的设备&#xff0c;正是这场革命中的重要一环。它以其卓越的精准定位能力和高效的控制性能&#xff0c;成为了众多工业领域的科技先锋。…

#C8# UVM中的factory机制 #S8.5# 对factory机制的重载进一步思考(二)

今天我们反思,然后总结。 一 先看代码 `timescale 1ns/1ps module tb_top;class Base;function void print(int a);$display("Base: int = %0d", a);endfunction endclassclass Sub extends Base;function void print(string s);$display("Sub: string = %s&…

vue3实现router路由

说明&#xff1a; vue3实现router路由 效果图&#xff1a; step1:项目结构 src/ ├── views/ │ ├── Home.vue │ └── User.vue ├── router/ │ └── index.js ├── App.vue └── main.jsstep2:左边路由列表C:\Users\wangrusheng\PycharmProjects\un…