FOC 单电阻采样 位置环控制伺服电机

2023-05-16

最近在做微型伺服电机的控制,需要平滑地将电机定位到某个位置。伺服电机、编码器、PCB都是自制的。这里我把整个的流程和遇到的问题记录一下。

目录

硬件设计

STM32CubeMX配置

程序设计

测试遇到的问题

演示视频


硬件设计

这里自制了一个驱动板

(1)MOS管驱动芯片:L6205D

原理图如下:

内部结构: 

  • L6205自带死区控制,同时集成了MOS管,大大缩小了PCB的体积。
  • 有四个MOS管引脚,这里只用到三相,即三个,而该芯片的电流采样引脚为每两个MOS管一个电流引脚,所以这里只能选择单电阻采样。
  • 关于死区的定义和死区时间的设置,可以参考我这篇文章:死区时间的分析与设置

我这里的微型伺服电机,最小7V就可以旋转了。而这个芯片最大能承受52V的电压,所以也可以驱动非微型的电机,但此时图中的双肖特基二极管和自举升压电容的封装都要修改。

(2)运放

电流采样需要运放,由于不知道单电阻采样和L6205的输出电流的范围和正负,所以这里把加法电阻R8加上,同理放大倍数不对的话,换一下反馈链路上的电阻R11即可。

(3)电机

这里控制的是一个微型伺服电机,用PROE画的,然后拿去加工、自己充磁。自制的没有编码器,所以还需要做编码器。

(4)磁编码器:TLV493D-A1B6

采用磁感应芯片TLV493D-A1B6,感应电机转子产生的正弦磁场,通过数学公式得出角度,编写算法,这样就自己做出一个磁编码器。该芯片采用I2C通信,由于FOC执行频率很高,所以需要用到DMA。下图是根据磁场获取角度的流程框图。求角度需要实现arctan算法,这里基于CORDIC原理实现了一种定点arctan算法,后续会写一篇博客介绍。

 (5)CPU芯片:STM32F302K8U6

需要用到的引脚有:电机三相的3个PWM引脚、ADC采样1个引脚、I2C通信2个引脚、串口调试2个引脚、LED指示2个引脚、电源、SWDIO、SWCLK。这里不外接晶振了,采用内部晶振。

所以这里没必要用更多引脚的STM32F302R8TX。但MCSDK并不支持STM32F302K8U6,不能使用软件生成代码,所以需要自己移植修改电机库的代码。正好电机库的代码非常乱,即使你没选上的功能,那些函数、结构体都给你加上,这里我从底层做起,一点一点地移植代码。

最终硬件如图所示

之前画过一个三电阻采样的四层板,元件特别多,高低频分开布线,十分复杂。而这里用了L6205,如图所示,板子体积缩小了不少,二层足矣。

STM32CubeMX配置

首先打开MCSDK(我使用的版本为MotorControl Workbench 5.4.7),选择STM32F302R8TX,生成单电阻采样的代码,大部分都参考这个配置即可。

(1)定时器TIM1

由于L6205自带死区控制和互补输出,所以配置如下:

定时器设置为中央对齐模式3,也就是向上向下计数时都产生一个比较中断,因为可能要在这里面调整波形。而单电阻采样是一个PWM周期要有两个采样点,这里设置TRGO2触发ADC采样,配置通道5和通道6的上升沿产生TRGO2信号,通道5和6的上升沿,即CCR值在单电阻采样的函数中计算并设置。通道4是用来单电阻的PWM波形变形的,其比较值为HTMIN,即电流采样最小脉宽时间(死区时间+上升时间+ADC触发延时时间+采样时间)。

 生成代码后,L6205自带死区控制,程序中的死区时间设置为0。查询L6205手册,上升时间设置为250ns。对应下面两个宏定义。

#define SW_DEADTIME_NS 0
#define TRISE_NS 250

(2)I2C

对于磁感应芯片,需要设置I2C为快速模式,还有根据TLV493D-A1B6芯片手册的参数,设置上升时间和下降时间,最后再打开DMA传输。

(3)USART

主要用作上位机调试。这里不打开中断,因为经过后续测试发现,如果其中断优先级比ADC中断要低,则程序很容易进不了中断;如果其优先级比ADC中断要高,则电机的旋转噪声又不太对劲。所以干脆在while循环里读取USART。

(4)ADC

MCSDK生成的FOC程序都为ADC左对齐,这里我设置为右对齐。稍后会有分析。

程序设计

(1)状态机

我的应用中没有过压、过流检测等,不需要用到那么多状态的切换,为了简化代码,这里我仅设置M_INIT和M_TEST两个状态。中频任务中需要运行的初始化函数,在main函数中初始化电机后依次执行:

	R1F30X_TurnOnLowSides(pwmcHandle);
	PWMC_CurrentReadingCalibr(pwmcHandle, CRC_START);
	R1F30X_SwitchOnPWM(pwmcHandle);

(2)角度校正和计算

①校正

由于编码器是自制的根据磁场感应的角度传感器,电机转子在制作的时候也是随机贴上去的,所以感应出来的角度和电机的电角度有一个固定偏差,这需要校正。

这里我无反馈,设置一个固定电流值,软件循环模拟一个角度值,让电机仅用SVPWM缓慢转一圈,此时磁传感器的值和模拟值的误差即电机的角度偏差。

这个校正值并不是每一个电机都一样的,所以需要保存到Flash中,再接一个EEPROM有些大材小用了,所以利用STM32内置Flash的最后几K存储,这个ST官方有相应例程:STM32F3xx微控制器中的EEPROM模拟。

②计算

电角度是在ENC_CalcAngle函数中计算的,这里我的磁编码器写的arctan算法输出的角度范围是0~65535,直接将它赋值给int16变量转到-32768~32767范围。

(3)ADC采样

MCSDK生成的代码默认是左对齐的,ADC精度是12位的,也就是左移4位作为电流了。不知道大家是什么情况,但是我的实际测试,单电阻的采样电流是恒大于0的,如图中CH2所示。

 但是在获取电流函数中:

void R1F30X_GetPhaseCurrents( PWMC_Handle_t * pHdl, ab_t * pStator_Currents )

直接拿JDR寄存器中的注入结果判断溢出,溢出范围是int16范围,而我采样的电流再左移的话是uint16范围的,所以我这个肯定溢出了。

ST代码这样写的前提是保证无电流时运放有1.65V偏置,然后电流有正有负。不知道大家单电阻是不是有正有负,那我的是正的话干脆就把ADC改为右对齐了。

所以大家看前面我的实物图中,右上角运放电路的加法电阻R8已经去掉了,最开始电压有超过3.3V,所以反馈电阻R11我也改小了。

而在PWMC_SetPhaseVoltage函数中,计算定时器CCR值得时候其实除以了131072或262144,这两个数怎么来的,可以参考我的这篇文章:SVPWM函数PWMC_SetPhaseVoltage解析。它们都是32768的倍数,32768代表的其实就是ADC左对齐,所以电流值就是Q15格式的了,在计算CCR值时要转回Q0格式。但是这里我设置为了右对齐,这里不改这个系数,直接在R1F30X_GetPhaseCurrents函数中将最后计算出的电流左移3位。

当然不做任何修改也可以,后边的PID参数调好就行。

(4)位置环

这里我没有添加速度环,而位置环是通过设定位置和实际位置的误差计算出Iq的参考值。

位置控制其实是根据PID调节的,虽然能到达最终位置,但是中间的加速度太快了,我需要一个平滑的旋转过程。用速度环的话,要考虑刚开始和结束的加速度的限制,所以匀速可能又太慢了,效率低。

最终决定加上S曲线控制位置,但S曲线算法又有不少浮点和除法运算,不太适合再加到FOC上,所以我写了一种定点S曲线查表算法,大概思路就是通过S曲线的方程获取一定数量的浮点数,浮点数转为Q16定点数,用的时候就整数乘法,效率高些,乘完右移16位使用。这是我最终的位置环结构体:

typedef struct
{
	PID_Handle_t *PIPos;
	int16_t  hSetPosition;   //设定机械位置
	int16_t  hStartPosition; //起始机械位置
	int16_t  hCurPosition;   //当前机械位置
	int16_t  hError;         //初始机械位置与目标位置的差
	int16_t  hMaxTorque;     //最大力矩
	uint16_t hCurIndex;      //当前S曲线表的索引位置
	uint16_t hStep;          //S曲线调整的时间
	uint8_t  bIsChanging;    //正在调整位置
} PosControl_Handle_t;

具体实现见博客:FOC 位置环S曲线之定点查表算法

最终工程结构如下:

 相比由MCSDK生成的默认工程,我一个个文件移植,去掉了不需要用的文件、宏定义和代码。这样其实也便于我理解整个代码结构,也更容易修改代码。

(5)上位机

①TLV493D-A1B6

转子在旋转时,TLV493D会产生X、Y、Z轴的磁场,三个正弦波,可以通过算法求出当前转子的绝对角度。这里也写了一个程序来验证角度的准确性。

 ②位置环

程序界面很简单,因为我大部分是用JLINK在线仿真,在watch窗口中改变量值调试的。

测试遇到的问题

(1)微型伺服电机电感小

我控制的微型伺服电机电感比较小,我在反Park变换后,对Vα和Vβ乘以一个系数,它才有转矩。出现这种情况实际是位置环的最大转矩限制和位置环PID参数没调好。

同时我发现,电感小的电机甚至可以不用电流采样,让Ia、Ib都恒为0都行,西门子的一款微型电机就是这样做的,这仅适合小电感和反电势小的电机,这里还是位置控制,所以不用采样完全没问题。当然如果有人为外力干扰,电流也会比较大,所以还要加个过流检测。

(2)PID调节

定点PID应该根据电机的不同,先调整hKxDivisorPOW2的大小,否则有可能怎么调参数最后PID输出都溢出。调节时先调好电流环,再调节速度环。

另外我把代码中的wDischarge变量去掉了,它是如果输出超过了限制范围,将超出的范围加到下一次积分项中,个人觉得没有必要。

(3)串口

串口就是和上位机通信用作调试用了,实际测试发现中断执行会卡死,收发不了数据。如果把串口优先级设置的比ADC中断优先级还高,电机性能也会受一些影响,所以最终我放在while循环中读取。

还有数据若发得太快,QT收到时则会有粘包问题,所以还需要设计一个简单的协议。

(4)ADC采样

在初始化ADC完之后校准一下,结果更准确一些。

HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);

演示视频

STM32 单电阻FOC控制微型伺服电机

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

FOC 单电阻采样 位置环控制伺服电机 的相关文章

  • gstreamer获取视频采集卡的数据

    gstreamer获取视频采集卡的视频数据 gstreamer可以用于采集硬件视频数据 xff0c 转码 xff0c 播放 xff0c 传输等 xff0c 但由于框架相对于FFmpeg较为小众 xff0c 所以资料较少 xff0c 整理一份
  • 使用c++来实现一个简单的数据库功能

    使用c 43 43 来实现一个简单的文件数据库功能 功能点1 xff1a 建表 1 创建和表同名的文件 2 在文件中存储表的信息 xff0c 包括attribute的name xff0c 数量 xff0c 类型 xff0c 是否唯一 3 添
  • 【性能优化】cpu时间抖动问题的解决修复

    问题描述 xff1a 边缘设备的cpu在低占有率时 xff0c 进程运行时间抖动较大 xff0c 在高占有率时 xff0c 运行时间抖动更稳定 低占有率运行情况图 xff1a 相同处理逻辑循环中 xff0c 两次处理的时间间隔 xff1a
  • pointRCNN 结果可视化

    由于pointRCNN源码的训练和inference很详细 xff0c 但是没有可视化的代码 xff0c 本文介绍其3d框结果的可视化方法 1 跑通pointRCNN https github com sshaoshuai PointRCN
  • C/C++学习笔记——C提高: 函数指针和递归函数

    函数指针 函数类型 通过什么来区分两个不同的函数 xff1f 一个函数在编译时被分配一个入口地址 xff0c 这个地址就称为函数的指针 xff0c 函数名代表函数的入口地址 函数三要素 xff1a 名称 参数 返回值 C语言中的函数有自己特
  • 算法基础22-最小生成树

    最小生成树 primkruskal prim 链接 acwing上一个关于prim很好的题解 prim 算法干的事情是 xff1a 给定一个无向图 xff0c 在图中选择若干条边把图的所有节点连起来 要求边长之和最小 在图论中 xff0c
  • C/C++学习笔记——C提高:预处理

    预处理的基本概念 C语言对源程序处理的四个步骤 xff1a 预处理 编译 汇编 链接 预处理是在程序源代码被编译之前 xff0c 由预处理器 xff08 Preprocessor xff09 对程序源代码进行的处理 这个过程并不对程序的源代
  • C/C++学习笔记——C提高:动态库的封装和使用

    库的基本概念 库是已经写好的 成熟的 可复用的代码 每个程序都需要依赖很多底层库 xff0c 不可能每个人的代码从零开始编写代码 xff0c 因此库的存在具有非常重要的意义 在我们的开发的应用中经常有一些公共代码是需要反复使用的 xff0c
  • FreeRTOS学习笔记——基础知识与移植(STM32F103)

    1 1 前后台系统 xff1a 早期嵌入式开发没有嵌入式操作系统的概念 xff0c 直接操作裸机 xff0c 在裸机上写程序 xff0c 比如用51单片机基本就没有操作系统的概念 通常把程序分为两部分 xff1a 前台系统和后台系统 简单的
  • STM32开源代码——MAX30100程序

    正点原子精英开发板 模块化封装 xff0c 入口函数简明 xff0c 易上手操作 展示main c代码 xff0c 完整代码请下载 xff08 数据打印到串口在MAX30100 PulseOximeter c xff09 点击下载代码 in
  • STM32开源代码——2.8寸TFTLCD屏虚拟键盘触摸程序

    正点原子精英开发板 模块化封装 xff0c 入口函数简明 xff0c 易上手操作 展示main c代码 xff0c 完整代码请下载 点击下载代码 include 34 sys h 34 include 34 delay h 34 inclu
  • STM32开源代码——光敏传感器

    正点原子精英开发板 模块化封装 xff0c 入口函数简明 xff0c 易上手操作 展示main c代码 xff0c 完整代码请下载 点击下载代码 include 34 led h 34 include 34 delay h 34 inclu
  • 个人项目——机智云开源APP基础修改教程(Android)

    之前写过一篇STM32接入机智云的教程 xff0c 最后说要有时间给大家写一篇修改机智云开源Demo APP的教程 xff0c 刚好楼主考完直流传动 xff0c 然后帮小学弟的一个32项目接入了机智云 xff0c 然后打算帮他修改一下Dem
  • FreeRTOS学习笔记——FreeRTOS任务创建和删除实验(静态方法)

    6 3 任务创建和删除实验 静态方法 6 3 1 实验程序设计 1 实验目的 上一小节我们讲了使用函数xTaskCreate 来创建任务 xff0c 本节在上一小节的基础上做简单的修改 xff0c 使用函数xTaskCreateStatic
  • FreeRTOS学习笔记——FreeRTOS 系统内核控制函数

    FreeRTOS 中有一些函数只供系统内核使用 xff0c 用户应用程序一般不允许使用 xff0c 这些API 函数就是系统内核控制函数 本章我们就来学习一下这些内核控制函数 xff0c 本章分为如下几部分 xff1a 10 1 内核控制函
  • FreeRTOS学习笔记——FreeRTOS 时间管理

    在使用FreeRTOS 的过程中我们通常会在一个任务函数中使用延时函数对这个任务延时 xff0c 当执行延时函数的时候就会进行任务切换 xff0c 并且此任务就会进入阻塞态 xff0c 直到延时完成 xff0c 任务重新进入就绪态 延时函数
  • 算法基础23-二分图

    二分图 二分图的判断二分图的最大匹配数 可以去看acwing题解 二分图的判断 span class token comment AcWing 860 染色法判定二分图 span span class token macro propert
  • Router 选择

    Connected Dominating Set Example of a Connected Dominating Set Router 必须形成一个 CDS xff08 Connected Dominating Set xff0c 连接
  • devtool: unset _PYTHON_SYSCONFIGDATA_NAME

    问题 在 Ubuntu 20 04 1 LTS 上进行编译Yocto时报错 xff0c 出现如下错误 xff1a bb data smart ExpansionError Failure expanding variable SRCPV e
  • VsCode 配置PySide6及测试

    目录 VSCode插件安装安装Python插件安装PySide6插件 PySide6安装PySide6配置VSCode创建UI文件 在这里插入图片描述 https img blog csdnimg cn cbf7cd76d7d84048ab

随机推荐

  • Ubuntu 14.04 Desktop的Raid1安装总结

    Ubuntu 14 04 Desktop的Raid1安装总结 安装基于Ubuntu14 04 Desktop的Raid1 由于采用UEFI GPT方式作为系统启动方式 xff0c 在安装过程中出现了很多异常情况 本文记录安装的过程 安装步骤
  • sem_wait sem_post信号量操作进本函数

    sem wait sem post 信号量的数据类型为结构sem t xff0c 它本质上是一个长整型的数 函数sem init xff08 xff09 用来初始化一个信号量 它的原型为 xff1a extern int sem init
  • 常见gcc编译警告整理(开始)

    1 warning no newline at end of file 在文件最后一行加上回车键 解释 xff1a 在 Rationale for the C99 standard 一文中 xff0c 有C99的相关信息 xff1a A b
  • 对于结构体变量赋值的误区

    以前在使用结构体时没有在结构体变量之间直接赋值 xff0c 今天同事在查看别人的代码时 xff0c 发现有两个结构体变量直接赋值的语句当时感觉这个语句不对 xff0c 认为在一个结构体里边 xff0c 既有一般的无符号整形与数组 xff0c
  • 线程同步(互斥锁与信号量的作用与区别)

    信号量用在多线程多任务同步的 xff0c 一个线程完成了某一个动作就通过信号量告诉别的线程 xff0c 别的线程再进行某些动作 xff08 大家都在semtake的时候 xff0c 就阻塞在 哪里 xff09 而互斥锁是用在多线程多任务互斥
  • 误解程序运行(从单片机到开始)

    误解程序运行 从单片机到开始 关于程序的执行 xff0c 以前想的不多 xff0c 没有意识到一个程序在运行时 xff0c 从哪里读指令 xff0c 数据又写在哪里 最近在看CSAPP时这个念头经常在脑袋中晃荡 从单片机上知道 xff0c
  • Out-of-Bounds Memory References and Buffer Overflow

    callee pushl edp save edp on stack movl esp edp pushl ebx save ebx subl 20 esp popl ebx restore ebx popl edp restore
  • 嘉立创专业板stm32拓展板十分钟快速入门

    本文是为不想深入学PCB但是迫不得已需要用PCB的人或者想要做一个32的拓展版的童鞋们的快速入门并做出板子的博客 xff0c 因此 xff0c 本文内容不会深入讨论元件 xff0c 只会教授基础流程 xff0c 并且没有画芯片 本文内容 x
  • 电子信息工程四年学习之思

    毕业后 xff0c 回顾四年学习历程发现 xff0c 当时以为的明白 xff0c 到现在都是那时的不明白 或许是自己的经历 xff08 参加比赛比较多 xff09 导致了现在的反思 但是 xff0c 回顾那个时候的课程设置 xff0c 却都
  • 将要到来的三大技术革命与联系

    http www csdn net article 2013 02 14 2814128 2013大数据 http www csdn net article 2013 02 15 2814135 bigdata is coming 大数据
  • Keil的常见编译警告

    1 warning 767 D conversion from pointer to smaller integer 解释 xff1a 将指针转换为较小的整数 影响 xff1a 可能造成的影响 xff1a 容易引起数据截断 xff0c 造成
  • 《大数据时代》之后

    现在想想也不记得当时是怎么找到 大数据时代 这本书的 xff0c 好像是在查找数据库方面的书 xff0c 看到亚马逊推荐的书里有这本 xff0c 发现最近才出版的就买一本回来看看 然而这个过程中 xff0c 其实自己已经得到了大数据带来的影
  • 《代码大全》笔记

    最近将去年毕业时 xff0c 大神推荐的 代码大全 看完了 xff08 已经过去一年了 xff0c 要十分感谢推荐 xff0c 还有凤林兄的 深入理解计算机系统 xff09 零零碎碎的时间 xff0c 发现很多东西虽然在书中标记了 xff0
  • 《编程精粹》思之代码与产品

    之前眼中有代码无产品 xff0c 现在眼中有产品有代码 xff0c 什么时候能做到有产品无代码 xff1f 还需要努力 刚开始实习的时候 xff0c 总喜欢在程序中使用 p 43 1 61 而不是p 1 来给入参 xff0c 甚至于用来给定
  • 树莓派4B+Intel神经计算棒(Stick2)+YoloV5可行性考察报告

    1 神经棒只能作为协处理器 在执行脚本时 xff0c 通过在命令后面加上 d 设备名 就可以指定硬件设备来加速推理 例如 命令行指定神经棒运行 demo squeezenet download convert run span class
  • 在Vue中获取v-for的index值

    lt el submenu index 61 34 item id 43 39 39 34 v for 61 34 item index in menuList 34 key 61 34 item id 34 gt lt template
  • 死区时间的分析与设置

    出现死区的主要原因是因为MOS管的源极和栅极之间的结电容 现在在栅极加上一个门电路 当门电路输出的信号跳变的瞬间 xff0c 电流是非常大的 xff0c 会导致MOS管发热 xff0c 所以需要在门电路后面再串联一个电阻 xff0c 这个电
  • MOS管特性和导通过程

    三极管是流控流器件 xff0c 它不能驱动功率太大的器件 xff0c 因为此时C极电流大 xff0c 而CE压降为0 3V左右 xff0c 在三极管上面消耗的功率就很大 xff0c 还容易发热 所以压控压型的MOS管就诞生了 特性 一开始给
  • 2014欢聚时代(YY)软件研发笔试题

    本文转载自 xff1a http blog csdn net arcsinsin article details 12714027
  • FOC 单电阻采样 位置环控制伺服电机

    最近在做微型伺服电机的控制 xff0c 需要平滑地将电机定位到某个位置 伺服电机 编码器 PCB都是自制的 这里我把整个的流程和遇到的问题记录一下 目录 硬件设计 STM32CubeMX配置 程序设计 测试遇到的问题 演示视频 硬件设计 这