开源三轴云台EVVGC(simple BGC)分析

2023-05-16

一. 主程序分析

主程序结构清晰,流程如图所示,下面将对每个部分做详细分析

 

二. 系统初始化

系统初始化部分的流程如上图所示,下面对每部分做具体分析

 

1. 时钟初始化

 该部分主要是使能DWT,用DWT进行精确延时,没有使用systick进行延时是因为systick作为时基用来确定各任务的运行频率

 

2. 初始化各参数到EEPROM

 系统使用FLASH的最后一页模拟EEPROM来存储参数


// use the last KB for sensor config storage
#define FLASH_WRITE_EEPROM_CONFIG_ADDR  (0x08000000 + (uint32_t)FLASH_PAGE_SIZE * (FLASH_PAGE_COUNT - 1))  

将各参数初始化,然后写入flash,写入flash步骤如下:

①FLASH解锁

②清零EOP、PGERR、WRPRTERR标志位

③进行擦除

④如果擦除完成就进行编程

⑤FLASH上锁

⑥读取FLASH

 

3. 电机驱动初始化

该函数一开始就检查一个标志位(全局静态变量),该标志位默认清零,在本函数执行完后置位,确保本函数只执行一次。

该部分用到了二个高级定时器TIM1和TIM8,还有二个通用定时器TIM4和TIM5,因此把定时器部分的初始化函数独立出来做成二个函数,分别是高级定时器初始化和通用定时器初始化,中断配置部分也独立出来,用了很贴近库函数的写法,值得借鉴。

TIM1用于pitch pwm timer,TIM8用于roll pwm timer,TIM4和TIM5用于yaw pwm timer,在中断配置的时候,yaw pwm timer配置的是TIM5,而在配置计数初值的时候,配置的是TIM4。


TIM8->CNT = timer4timer5deadTimeDelay + 5 + PWM_PERIOD * 2 / 3;

TIM1->CNT = timer4timer5deadTimeDelay + 3 + PWM_PERIOD / 3;

TIM4->CNT = timer4timer5deadTimeDelay;  

通过配置TIM4、TIM5成相反极性,加上计数初值,在中断中变更比较值的时候,给其中一个加上死区时间,模拟成了互补PWM

 

4. 延时

 延时使用了DWT的计数,DWT的初始配置在时钟配置的时候已经完成,us延时函数如下,值得学习


void delayMicroseconds(uint32_t us)

{
    uint32_t elapsed = 0;

    uint32_t lastCount = *DWT_CYCCNT;

    for (;;)

    {

        register uint32_t current_count = *DWT_CYCCNT;

        uint32_t elapsed_us;
 

        // measure the time elapsed since the last time we checked

        elapsed += current_count - lastCount;

        lastCount = current_count;

        // convert to microseconds

        elapsed_us = elapsed / usTicks;
 

        if (elapsed_us >= us)

            break;
 

        // reduce the delay by the elapsed time

        us -= elapsed_us;

 
        // keep fractional microseconds for the next iteration

        elapsed %= usTicks;

    }

}  

 

5. 打印内部还有3s的延时,加上之前之后的延时,至少有23s的延时,该部分延时是为了让传感器稳定下来

 

6. RC初始化部分配置外部中断3、4、5和TIM3

 

7. 时间函数初始化部分配置TIM6,向上计数,在最大中断的时候溢出,用来对主函数中任务的执行间隔时间进行计时,该计时用于积分运算

 

8. 一阶滤波初始化


// TAU = Filter Time Constant

// T   = Filter Sample Time


// A   = 2 * TAU / T


// Low Pass:

// GX1 = 1 / (1 + A)

// GX2 = 1 / (1 + A)

// GX3 = (1 - A) / (1 + A)

 
// High Pass:

// GX1 =  A / (1 + A)

// GX2 = -A / (1 + A)

// GX3 = (1 - A) / (1 + A)  

初始化的参数有ACCEL_X_500HZ_LOWPASS、ACCEL_Y_500HZ_LOWPASS、ACCEL_Z_500HZ_LOWPASS、ROLL_RATE_POINTING_50HZ_LOWPASS、PITCH_RATE_POINTING_50HZ_LOWPASS、YAW_RATE_POINTING_50HZ_LOWPASS、ROLL_ATT_POINTING_50HZ_LOWPASS、PITCH_ATT_POINTING_50HZ_LOWPASS、YAW_ATT_POINTING_50HZ_LOWPASS等,初始赋值都是下面模式:


a = 2.0f * eepromConfig.accelX500HzLowPassTau * 500.0f;


firstOrderFilters[ACCEL_X_500HZ_LOWPASS].gx1 = 1.0f / (1.0f + a);

firstOrderFilters[ACCEL_X_500HZ_LOWPASS].gx2 = 1.0f / (1.0f + a);

firstOrderFilters[ACCEL_X_500HZ_LOWPASS].gx3 = (1.0f - a) / (1.0f + a);

firstOrderFilters[ACCEL_X_500HZ_LOWPASS].previousInput  = 0.0f;

firstOrderFilters[ACCEL_X_500HZ_LOWPASS].previousOutput = 0.0f;  

 

滤波函数如下:


output = filterParameters->gx1 * input +

filterParameters->gx2 * filterParameters->previousInput -

filterParameters->gx3 * filterParameters->previousOutput;  

 

9. PID初始化,注意该部分初始化了rc:


 rc = 1.0f / ( TWO_PI * F_CUT );  

 

10. 初始化正弦表,该部分初始化了一个1024个点的正弦表,对每个点求正弦值后再转化为Q15格式


void initSinArray(void)

{

    int i;

    for (i = 0; i < SINARRAYSIZE; i++)

    {

        float x = i * M_TWOPI / SINARRAYSIZE;

        sinDataI16[i] = (short int)round(sinf(x) * SINARRAYSCALE);

    }

}  

 

11. 初始化IMU方向矩阵:根据IMU的安装位置确定方向矩阵

 

12. MPU6050初始化,通过重写I2C write函数(三个参数:地址、寄存器、数据),发送指令对6050进行初始化 ,初始化的步骤如下:

①设备复位

②延时150ms,等待稳定

③设置时钟源

④关闭待机模式,使能加速度和陀螺仪

⑤加速度、陀螺仪采样频率设定

⑥滤波设定

⑦加速度量程设定

⑧陀螺仪量程设定

 

在这个初始化函数里,配置完MPU6050后,调用了一个计算MPU6050数据的函数,该函数对加速度和陀螺仪的5000次数据求平均(读取出加速度和陀螺仪数据,然后与方向矩阵相乘,再用转化后的数据减去温度偏差),最后再对加速度进行标准化,这里面有几个注意的地方:

① 读取数据的时候,MPU6050先发送高位再发送低位,读取的时候,数据保存到一个数组缓冲区,然后利用联合体共享内存的特性将高低位合并成一个数据

② 读取出来的数据与方向矩阵(在前面初始化的时候已经确定)相乘转化为旋转后的数据

③ 计算MPU6050偏差:偏差 = 温度漂移速率*温度值+偏差截距

温度漂移速率和偏差截距在MPU6050校准函数(该函数在串口校准命令下被执行)中计算,该函数先采集2000次MPU6050的数据求均值,等待10分钟,然后再次采集2000次MPU6050的数据求均值,最后计算温度漂移速率与偏差截距:

温度漂移速率 = (第二次均值 - 第一次均值)/(第二次温度均值 - 第一次温度均值)

偏差截距 = 第二次均值 - 温度漂移速率 * 第二次温度均值

④ 对5000次数据求平均中,每次都需要转化后的数据减去偏差

 

三. 原点初始化

求取150次角度均值,角度求取使用反正切计算

 

四. 主函数里500Hz执行部分是云台控制核心部分

1. 读取TIM6的计数值,重置TIM6,计算两次运行的间隔时间,用于后面的角度积分

 

2. 读取陀螺仪和加速度计数值,进行标定(分别减去偏差值)

 

3. 获取原点位置

该部分先用进行标定后的加速度值进行反正切运算求解出角度,之后用此角度值与先前计算出的角度进行一阶滞后滤波,再用互补滤波融合陀螺仪积分出来的角度和加速度滞后滤波后的角度,该角度用于串口通讯输出

 

4. 对加速度数据进行一阶滤波

 

5. 姿态更新(2ms进行一次)

该部分读取加速度计和陀螺仪的值,进行标定(减去零点偏移值),对加速度值再进行一阶滤波,之后传输给航姿更新模块进行姿态解算,姿态解算过程详见“姿态解算解析”

 

6. 电机驱动

该部分用解算出的姿态角与遥控解析出的角度进行PID运算(2ms进行一次),PID运算的结果传递给电机驱动模块,电机驱动模块详见开环云台电机驱动,电机占空比更新频率与本部分同频,也是2ms一次

 

五. 串口通讯部分

该部分使用USB虚拟串口,通过接收串口命令做出不同处理,将相关联动作的命令用大小写分别定义,减少了命令复杂度,可对应命令写上位机处理

 

六. 遥控命令处理

该部分接收三个通道的信号(分别对应三轴),然后与一个阈值做比较,如果小于阈值则认为没有控制量,如果大于阈值,则根据信号量的大小计算控制量,之后将控制量乘以一个比例因子,使得与限制量在一个量级,再之后判断控制方向和约束可控范围,根据判断选择是否进行角度补偿,最后再进行一阶滤波

 

转载于:https://www.cnblogs.com/yueze/p/7107235.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

开源三轴云台EVVGC(simple BGC)分析 的相关文章

随机推荐

  • stm32经典笔试题_stm32嵌入式试题

    第一章 为什么学习 STM32 STM32 是一系列以 ARM Cortex M 为内核的 32 位嵌入式微控制器 第二章 初识 STM32 库 1 什么是启动文件 xff1f 启动文件的作用是什么 xff1f 具体实现了哪些功能 xff1
  • imu相机标定_相机+imu标定

    官方上是跑在ros indigo上的 xff0c 但是实测用kinetic也没问题 xff0c 主要就是装依赖的时候改下名字 下面命令行里有写注释 1 工具箱 Kalibr 安装 安装依赖 sudo apt get install pyth
  • linux双系统如何选择顺序,双系统中怎么设置Ubuntu多系统的默认启动顺序?

    很多人在安装Linux系统 xff0c 如Fedora或Ubuntu等操作系统玩的时候 xff0c 一般还会保留一份Windows操作系统作为主用系统 xff0c 但是发现安装了Linux系统之后 xff0c 默认的启动菜单就变成了Linu
  • rpe matlab,Constant velocity range-parameterized EKF initialization

    The RPEKF is a special type of filter that can be initialized using angle only measurements that is azimuth and or eleva
  • 计算机与工作 生活的小论文,电脑与生活作文

    电脑与生活作文 在生活 工作和学习中 xff0c 大家或多或少都会接触过作文吧 xff0c 作文是人们把记忆中所存储的有关知识 经验和思想用书面形式表达出来的记叙方式 那要怎么写好作文呢 xff1f 以下是小编收集整理的电脑与生活作文 xf
  • gVim的字体和背景颜色设置

    电脑环境是XP xff0c 软件是gVim7 3 xff0c 安装在C盘的 Program Files 下 如何设置gVim的字体和背景颜色 xff1a C gt Program Files gt Vim gt vimrc文件 xff0c
  • xlight ftp linux,Xlight FTP Server

    Xlight FTP Server的功能按钮都是中文的 xff0c 国内用户可以轻易地创建新的服务器 xff0c 并且能够为同一台计算机的多个端口创建各自的虚拟服务器 此外 xff0c 它还具有用户虚拟目录 xff0c 每个用户的虚拟目录都
  • 参数控制c语言代码走向,C语言可变参数完全解读

    本文转自 xff1a http www cnblogs com wangyonghui archive 2010 07 12 1776068 html 一 是什么 我们学习C语言时最经常使用printf 函数 xff0c 但我们很少了解其原
  • VHDL计算机硬件能直接执行吗,第5章 VHDL程序结构.ppt

    第5章 VHDL程序结构 VHDL 数字系统设计 第5章 VHDL程序结构 VHDL语言的特点 xff1a VHDL语言具有很强的电路描述和建模能力 xff0c 能从多个层次对数字系统进行建模和描述 xff0c 从而大大简化了硬件设计任务
  • opencv双目标定原理_双目视觉原理及流程概述

    击上方 新机器视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 双目原理 双目视觉是利用视差原理的一种视觉方法 如图所示为空间中一点P在左右相机中的成像点Pleft 61 Xleft Yleft xf
  • java怎么写算法_用Java写算法之一:冒泡排序

    从这篇文章开始 xff0c 我会陆陆续续将我所能用Java实现的算法在这里简单做个梳理 xff0c 也算温故而知新吧 受个人水平和时间限制 xff0c 可能会有错漏 xff0c 欢迎各位批评指正 那么 xff0c 就从冒泡排序开始 显然 x
  • docker显示linux桌面,怎样在桌面上安装 Docker CE?

    按照这些简单的步骤在你的 Linux Mac 或 Windows 桌面上安装 Docker CE 在上一篇文章中 xff0c 我们学习了容器世界的一些基本术语 当我们运行命令并在后续文章中使用其中一些术语时 xff0c 这些背景信息将会派上
  • 信号量-邮箱-消息队列的区别

    为什么要用 xff1a 任务间的通信可以通过全局变量或者信号量来完成 全局变量虽然可以承载通信的内容 xff0c 但是接收方无法意识到信息的到达 xff0c 除非发送方向接收方发送一个信号量 xff0c 或者接收方不断该全局变量 xff1b
  • 乱码大全(二) (转)

    乱码大全 二 转 64 more 64 2 XxencodeXML namespace prefix 61 o ns 61 34 urn schemas microsoft com Office office 34 gt 提到Uuencod
  • 成都麻将胡牌算法

    四川麻将胡牌算法 xff08 不支持风 花牌 xff09 支持缺一门 七小对 xff0c 正常胡牌 xff0c 带杠 感谢 华仔 对我的代码提出了宝贵的意见 xff0c 华仔很适合做测试啊 xff01 xff01 include lt st
  • linux lvm 扩容磁盘,Linux LVM磁盘空间扩容的新方法

    导读 传统LVM扩容方法需要增加PV磁盘 xff0c 扩容多次后 xff0c 服务器的磁盘数量会越来越多 xff0c 容易增加日后维护存储和磁盘布局的难度 当服务器是虚拟机 xff0c 或者使用SAN NAS存储的物理机时 xff0c 由于
  • keil中的串口调试:

    keil中串口的虚拟调试信息在通过View serial windows usart1 2 3 4 debug printf 可以看到 当然也可以通过虚拟串口VSPD 43 串口调试助手在外部实现 xff0c 方法如下 xff1a 虚拟 串
  • Eclipse的Ctrl+s不能保存问题的解决!

    原因1 xff1a eclipse快捷键设置有问题 xff0c 解决方式 xff1a 检查windows gt perferences gt Keys中的Save项 xff0c 是否绑定了Ctrl 43 S xff0c 以及相关设置是否正确
  • linux 查看磁盘空间大小

    1 Ubuntu 查看磁盘空间大小命令 df h Df命令是linux系统以磁盘分区为单位查看文件系统 xff0c 可以加上参数查看磁盘剩余空间信息 xff0c 命令格式 xff1a df hl 显示格式为 xff1a 文件系统 容量 已用
  • 开源三轴云台EVVGC(simple BGC)分析

    一 xff0e 主程序分析 主程序结构清晰 xff0c 流程如图所示 xff0c 下面将对每个部分做详细分析 二 系统初始化 系统初始化部分的流程如上图所示 xff0c 下面对每部分做具体分析 1 时钟初始化 该部分主要是使能DWT xff