心电信号采集与处理

1 实验需求分析

1.1 项目背景介绍

心电信号(Electrocardiogram, ECG)是反映心脏活动电生理变化的重要生物电信号,其特征包括心率、节律、波形等参数,能够直观反映心脏健康状况,在临床医学、健康监测和疾病预防中具有不可替代的作用。通过心电信号的测量与分析,可以检测心律失常、心肌缺血、心脏传导阻滞等异常,为心脏疾病的诊断和治疗提供关键支持;借助便携式和可穿戴设备,实时心电监测已成为健康管理的重要手段,为心血管疾病高危人群提供预警,有助于降低发病率和致死率。此外,心电信号还是生物医学研究的重要工具,为心血管药物开发、人工心脏研究等领域提供了基础数据。在当前人口老龄化加剧和心血管疾病高发的背景下,心电信号测量与分析技术显得尤为重要。本项目旨在开发高精度的心电信号采集系统,结合课程中介绍的数字信号处理等专业知识,为心脏健康提供更加便捷和智能的监测方案,推动精准医疗与个性化健康管理的发展。

1.2 心电信号特征与设计需求

心脏内部产生的一系列非常协调的电刺激脉冲,使得心脏肌肉细胞有节奏的舒张和收缩,这些信号传递到人体表面的不同部位形成不同的电位差。通过仪器设备可以从体表检测到这些微弱的电位差信号,称之为心电信号。换言之,心电信号即为人体心脏细胞细胞膜产生的电势差。在医学上,医生往往需要通过心率与幅值等参数来初步判断患者的健康状况,因此实现高精度的心率与幅值测量是本项目中设计的心电信号采集与处理系统的核心功能。

图1.1:心电信号简介

正常的心电信号频率范围为0.05Hz-100Hz,其能量集中在低频段,其中99%的能量集中在0Hz-35Hz。在其采集过程中容易受到各种干扰,主要分为三种:

  • 工频和工频的谐波频率干扰,工频频率在我国为50Hz;

  • 肌颤噪声和采样电路参考电压引入的电源纹波等高频噪声,频率通常在100Hz以上;

  • 呼吸基线漂移和采样引入的直流分量,频率一般分布在0-0.7Hz。

以上的各种干扰会对心电信号采集结果产生较大的影响,使得采集到的心电信号中出现许多杂波与噪声,这是我们所不希望看到的。因此,为提高心电信号的测量精度,需要设计相应的滤波器对传感器采集到的信号进行滤波,从而减小信号中的噪声震荡,提高心率与幅值测量的准确程度。特别的,由于参考电压受环境温度变化会产生一定的温漂,以及人的呼吸活动和电极滑动也导致基线漂移。这些干扰的频率很低,通常在几Hz以内,但和心电信号的有效频谱非常接近,因此需要过渡带较窄的IIR直流陷波器来消除干扰。

基于心电信号的以上特性,对于该心电信号采集与处理系统,提出如下的技术指标需求:

  • 0频处的缓变直流衰减不低于30dB;

  • 降噪滤波器以35Hz为3dB通带截止频率,过渡带不超过10Hz,阻带衰减不低于40dB;

  • 心率估算误差不超过10%。

2 实现方案论证

2.1 系统框架设计

本项目的核心目标是实现心电信号的采集与滤波以及心率测量,同时需要在屏幕上绘制时域波形与频谱图。具体而言,细分的功能如下:

  • 实现ADS1292获取心电信号原始数据,并通过串口传输至PC电脑;

  • 实现PC电脑中通过MATLAB对原始数据进行时域和频域分析;

  • 实现PC电脑中通过MATLAB对原始数据进行降噪和提取心率;

  • 实现STM32单片机中对原始数据进行降噪和提取心率;

  • TFT屏幕中绘制心电信号曲线和显示心率数值。

为实现以上功能,采用如下的系统设计流程:

  1. 调试ADS1292R_PowerOnInit函数中的ADS1292芯片读取,通过读取芯片device_id验证硬件功能正常且连接正确;

  2. 在中断驱动下,读取ADS1292的原始数据,并存储在单片机的存储器中;

  3. 把原始数据传输到PC;

  4. 在PC中分析原始数据的时域和频域;

  5. 在PC中设计滤波器对原始数据进行处理,并提取心率等;

  6. 把PC中的滤波器移植到单片机中;

  7. 在单片机中把心电波形和心率等数据显示到TFT屏幕。

图2.1:系统设计流程

根据如上设计流程,结合目前提供的材料,设计了如下图所示的心电信号采集与分析系统:

图2.2:系统框架

系统的工作流程如下:

  1. 首先,STM32控制器向心电传感器发送采集指令,传感器随后采集来自人体或模拟信号源的心电信号,并将数据反馈至控制器;

  2. 接着,控制器将采集到的数据传输至PC端,供进一步分析处理;

  3. 然后,根据PC端的分析结果,控制器会调整参数并优化心电信号处理;

  4. 最终,处理后的结果将在TFT屏幕上实时显示,供用户查看。

可以看到,该系统主要涉及到STM32主控芯片、ADS1292R传感器、TFT显示屏、心电信号模拟器以及PC端分析软件MATLAB等关键组件。接下来将对于本项目涉及的各硬件组件进行介绍。

2.2 STM32主控芯片

本项目选用的微控制器STM32F407ZG是系统的核心控制单元,负责协调各个模块的工作。其不仅负责信号的采集,还管理信号传输、滤波器应用、以及与TFT屏幕的显示操作。其强大的处理能力和灵活的控制方式使其成为整个系统的”大脑”。该控制器目前搭载在”正点原子”探索者STM32F407开发板V3上,负责完成系统的信号采集、处理与传输任务。

图2.3:STM32F407探索者开发板V3实物图正面

该单片机具备高性能的ARM Cortex-M4内核,主频高达168MHz,同时集成了丰富的外设接口,包括多个ADC通道、DMA(直接存储器访问)、定时器以及USART串口等,为心电信号的实时采集、处理与传输提供了强有力的硬件支持。它通过SPI协议与ADS1292传感器进行数据交换,采集来自人体或模拟信号源的心电信号,并进行初步处理。

2.3 心电信号模拟器

在实验的过程中,无法总是以人体作为心电信号源,因此在缺乏人体数据的情况下,本项目采用SKX-2000心电信号模拟仪作为测试时的模拟信号源。它能够生成不同类型的心电波形,广泛用于测试系统性能和验证心电信号采集、处理的稳定性。此设备对确保系统在实际使用前达到预期的性能标准至关重要。

图2.4:SKX-2000心电信号模拟仪

图2.5:SKX-2000心电信号模拟仪使用说明书图2.5:SKX-2000心电信号模拟仪使用说明书

在本项目中,主要使用到的是正常的心电波形与标准的心率信号,可以通过操作该模拟仪控制其产生心电信号的心率以及幅度。在连接方面,如图2.3所示,采用三导联接法,RA连接右手(红色),LA连接左手(黄色),LL连接左脚(绿色);通过3.5耳机动态导联线,将模拟仪产生的心电信号输入ADS1292S传感器中以供进一步采集。

2.3 信号采集传感器:ADS1292R

ADS1292R作为一款多通道同步采样的24位模数转换器(ADC),被广泛应用于生物电势测量领域,其独特的设计集成了可编程增益放大器、内部基准源和板载振荡器,确保了心电信号的精准采集。在本系统中,ADS1292R作为信号采集模块的核心组件,负责从心电电极捕获原始心电信号。这些信号随后通过SPI接口传输至STM32微控制器,供后续处理和分析。

图2.6:ADS1292R传感器实物图与电路原理图
图2.6:ADS1292R传感器实物图与电路原理图该模块共有12个输出引脚(传感器模块右侧),各引脚接口功能说明如下:

  • GND:接供电电源地;

  • CLK:提供给ADS1292R工作的外部时钟,由于本项目采用内部时钟,故该引脚无需连接;

  • GPIO1、GPIO2:本项目中未使用,无需连接

  • SPI_SCK:接入由STM32单片机提供的SPI时钟信号;

  • SPI_MISO:向STM32单片机发送SPI数据输入信号;

  • SPI_MOSI:接收STM32单片机发出的数据输出信号;

  • SPI_CS0:接入STM32单片机GPIO,为ADS1292R提供片选选中信号;

  • ADS_DRDY:向STM32单片机发送外部中断输入,告知单片机可以通过SPI接收采集信号;

  • ADS_START:接入STM32单片机GPIO,为ADS1292R提供开始采集信号;

  • ADS_PWDN:接入STM32单片机GPIO,为ADS1292R提供复位信号RESET;

  • +5V:接供电电源+5V(由STM32输出)。

除此之外,由于选用的STM32单片机只允许接收0~3.3V的输出电压,故单片机通过SPI通信接收的信号电压必须限制在该范围内,因此需要将ADS1292R传感器模块中间的VDD与3.3V引脚通过跳线帽相连以实现电压转换(与图2.5中左图的连接方式相反)。

2.4 SPI通信读取采集数据

在本系统中,传感器将数字化后的原始心电信号数据通过SPI接口传输到STM32微控制器。SPI通信具有高速度、全双工传输的优势,非常适合用于实时性要求较高的应用场景。SPI接口确保了心电信号数据的快速、稳定传输,保证了信号的实时处理和准确性。通过SPI,ADS1292R和STM32微控制器能够高效地交换数据,从而提升系统的整体性能和响应速度。

SPI通信采用主从结构,其中STM32微控制器作为主设备,ADS1292R作为从设备。具体来说,SPI通信包括四个主要信号线:时钟信号(SCK)、主输出从输入(MOSI)、主输入从输出(MISO)和片选信号(CS)。时钟信号由STM32微控制器提供,用于同步数据传输。数据通过MOSI线从ADS1292R传输到STM32微控制器,而传感器通过MISO线将必要的反馈信息传回STM32。

图2.7:SPI内部结构简图

为了提高系统的响应速度和处理效率,在单片机端选择了基于中断驱动的数据采集机制。当ADS1292R传感器完成一组心电数据的采集后,通过中断信号通知STM32F407进行数据读取和处理。这种机制有效减少了CPU的空闲时间,提高了系统的整体效率。

图2.8:中断驱动SPI通信采集数据的系统框架简图

在单片机程序工程中,通过调用驱动库文件中的ADS1292_Read_Data函数,可以实现单片机与ADS1292R的数据交互以进行实时数据监测,并通过函数ADS1292_Send_CMD将信号数据通过UART串口以115200的波特率传输至PC端并保存。在此过程中,原始信号数据被保存为.dat格式的文件,后续将通过MATLAB读取和显示这些信号数据,并针对这些数据进行滤波器等模块的设计,对信号进行进一步验证与调试。

图2.9:单片机实现读取原始信号数据的函数ADS1292_Read_Data

图2.10:单片机实现串口输出原始信号数据的函数ADS1292_Send_CMD

图2.11:PC端可视化软件中显示采集到的原始心电信号(解码后)

3 理论推导与MATLAB计算

PC端分析软件(本项目中使用MATLAB)用于对采集到的原始心电信号进行深入分析。为验证滤波器对心电信号的作用和效果,可以先在MATLAB上设计算法对心电信号进行一系列处理,包括数据读取、绘制原始数据时域波形、分析原始数据的频谱、设计数字直流陷波器、设计FIR数字低通滤波器、分析并比较滤波前后数据的频谱以及估算心率。通过这些分析,系统能够设计出合适的滤波器以去除噪声并提取出心率等重要参数,为后续移植到单片机上提供理论验证。

3.1 原始心电信号数据的读取与频谱分析

为了研究信号特征和评估处理效果,首先需要导入心电信号数据并进行基本分析。当心电信号传入单片机后,根据ADS1292R的数据手册,还需在单片机中对数据进行解码处理。在2.4节中,直接存入.dat文件的是未经过解码的原始数据,而图2.11展示的则是经过解码转换后的波形数据可视化结果(由单片机内部程序完成解码转换,将在4.2节中详细展开)。

图3.1:MATLAB从串口读取信号数据并写入.dat文件的程序代码

本章中的MATLAB分析均基于未解码的.dat文件,因此要想获得真实的波形数据(电压值),需要先根据以下规则对数据进行解码(4.2中的解码基于同样的原理,后续不再赘述):

由于原始数据格式是24bits的二进制补码(7FFFFF对应的模拟信号是2.4V。800000对应的模拟信号是-2.4V),若考虑保留高16bits,需要注意此时为补码,同时也要考虑到16bits相比于24bits相当于右移了8位。所以此时7FFF的数值对应模拟信号相当于2.4V,8000对应模拟信号-2.4V。

图3.2:原始信号电压与读取信号数据间的关系

基于这样的规则,可以在MATLAB编写对应的接收数据代码,从文件中读取数据(注意把负数的二进制补码转换为原码),其中Off可以为0或1(因为MATLAB接收的起始数据可能是16bits的高8位或者低8位,用off作为偏移调整,这样组合的数据才不会出现错位);同时通过plot函数绘制出原始心电信号的时域波形,并使用快速傅里叶变换(FFT)分析信号频谱,绘制出频谱图。

图3.3:原始心电信号数据解码读取、时域波形绘制与频谱分析绘制MATLAB代码

图3.4:原始心电信号时域波形与频谱图3.4:原始心电信号时域波形与频谱

从频谱图(上右图)中可以明显观察到信号中的低频基线漂移和工频干扰(与1.2节中的分析基本一致),这些成分需要通过滤波器加以去除。

3.2 IIR数字直流陷波器设计与滤波效果

工程中使用高精度传感器采集动态信号,采集的原始数据会因为环境变化、量化字长和参考电压等因素,包含较强的缓变直流分量,如果不予以消除,会导致在降噪等处理中出现运算饱和溢出。由于在采集心电信号时,人的呼吸活动和电极滑动会导致基线漂移,而这些干扰的频率又与心电信号的有效频谱非常接近,因此需要设计窄带IIR直流陷波器来消除该干扰。

直流陷波器的传递函数Η(z)为:
$$
Η(z) = \frac{z - 1}{z - a}
$$
该数字系统的极点为z = a,零点为z=1,其中参数a决定了陷波器的过渡带宽和衰减性能,为接近1的正实数。因为零点对应的幅角ω = 0,所以数字系统在零频处的增益显著衰减(如图3.5所示),其衰减的程度与过渡带的宽度和极点a的数值有关:a越大衰减变小,同时过渡带变窄,反之则衰减增大和过渡带增宽。通过实验调整,选择a=0.992可在基线漂移和信号完整性之间取得平衡。

图3.5:a=0.992时直流陷波器H(z)的增益和相位特性

图3.6:IIR数字直流陷波器设计及滤波后频谱分析绘制MATLAB代码及其运行结果
图3.6:IIR数字直流陷波器设计及滤波后频谱分析绘制MATLAB代码及其运行结果

可以看到,在加入了直流陷波器进行滤波后,0频处的基线漂移基本被消除,说明该滤波器的设计有效并起到了很好的效果。

3.3 FIR数字低通滤波器设计与滤波效果

根据阻带衰减不低于40dB且过渡带不超过10Hz的要求,利用MATLAB中自带的filterDesigner滤波器设计工具对于FIR数字低通滤波器进行设计。在该滤波器中,采用固定窗口,通过对当前点及其前160个点的加权求和来计算输出(指定滤波器阶数为160)。

在固定窗口的选择上,由于不同窗函数的阻带最小衰减各不相同,过渡带应与对应窗函数的”精确过渡带宽”相等。以下是常用窗函数的对比表:

表3.1 不同窗函数的阻带最小衰减

窗函数 第一旁瓣衰减A/dB 近似过渡带宽Bw 精确过渡带宽 旁瓣峰值衰减/(dB * oct^(- 1))
矩形窗 -13 4π/N 1.8π/N 21
汉宁窗 -31 8π/N 6.2π/N 44
海明窗 -41 8π/N 6.6π/N 53
布莱克曼窗 -57 12π/N 11π/N 74
凯泽窗(β = 7.865) -57 10π/N 80

在实际设计中,选择Chebyshev(切比雪夫)窗,其主要特点为:在给定窗口长度的情况下,能够提供最小的主瓣宽度。因此,通过选用Chebyshev窗,在频域上最小化主瓣的振幅波动,以实现滤波器的设计。

除此之外,设计时还指定采样频率为500Hz,阻带频率设计为35Hz,确定好参数后可在filterDesigner工具中导出为MATLAB函数:

图3.7:基于filterDesigner工具的FIR数字低通滤波器设计及其生成的MATLAB代码图3.7:基于filterDesigner工具的FIR数字低通滤波器设计及其生成的MATLAB代码

在主程序中调用生成的滤波器函数构造一个FIR数字低通滤波器实例,并利用filter函数对于直流陷波后的波形数据进行FIR滤波并通过plot函数绘制滤波后的频谱,代码与结果如下所示:

图3.8:信号经FIR数字低通滤波后频谱分析绘制MATLAB代码及其运行结果图3.8:信号经FIR数字低通滤波后频谱分析绘制MATLAB代码及其运行结果

可以看到,在加入了数字低通滤波器进行滤波后,50Hz处的工频干扰完全被消除,说明该滤波器的设计有效并起到了很好的效果。

3.4 滤波结果综合分析

通过IIR和FIR滤波器的级联处理,最终获得了较为清晰的心电信号波形(如图3.9所示)。此过程有效去除了干扰,为后续心率计算和信号分析提供了可靠的基础。

图3.9 滤波后心电图结果图3.9 滤波后心电图结果

图3.10 信号频谱对比图图3.10 信号频谱对比图

为了更直观地展示信号处理过程的效果,对心电信号在各个处理阶段的频谱进行了对比分析。图3.10中显示了原始心电信号以及经过直流陷波器和FIR低通滤波器联合处理后的信号频谱图。

从原始心电信号频谱可以看出,信号中存在显著的工频干扰(约50Hz)和低频基线漂移(频率较低)。此外,信号还包含较多高频噪声,影响了心电信号的质量。经过直流陷波器处理后,低频基线漂移明显被抑制,低频成分显著减少但同时工频干扰和高频噪声依然存在,但其幅值未发生明显变化,表明直流陷波器主要对低频干扰起到作用;在应用FIR低通滤波器后,信号中50Hz附近的工频干扰被有效抑制,同时高频噪声也显著减弱。

最终处理后的频谱显示出清晰的心电信号主频成分(低于30Hz),为后续的R波检测与心率计算提供了可靠的基础。

3.5 心率计算

在对原始心电信号完成滤波处理后,可进一步估算心率这一关键生理参数。心率的计算基于心电信号中的R波峰值检测,通过分析相邻R波之间的R-R间期推算心率值。R波的检测是心率估算的关键环节。在此实验中,采用MATLAB函数findpeaks来检测心电信号中的峰值。为提高检测精度,将滤波后的信号进行缩放,并设置峰值检测的阈值为信号均值加一倍标准差。

检测到R波位置后,可通过计算相邻峰值位置之间的时间间隔(R-R间期)来估算心率。使用diff函数计算相邻R波的时间间隔并计算R-R间期的平均值,并根据如下公式计算出心率:

$$
心率 = \frac{60}{平均R - R间期}
$$
图3.11 MATLAB心率计算代码

最终得出结果为60.29bpm,对比实际信号发生仪60bmp的心率,可以较为准确地估算心率,其结果符合误差小于10%的预期。

4 STM32程序设计与参数选择

项目代码已推送至Github远程仓库:Asgard-Tim/ECG_Final_Project

4.1 单片机程序架构设计

为实现2.1节所提出的基本功能,除了要采集心电数据并对其进行滤波、显示时域波形外,还需要对滤波后的波形进行频谱分析并显示。为了更高效地完成这一过程,系统引入了快速傅里叶变换(FFT)算法,用于将时域信号转化为频域信号,便于分析信号的频谱特性。然而,由于FFT计算量较大,尤其是在较高采样率下,需要处理大量的点,因此为了加快运行速度,程序采用了FreeRTOS实时操作系统,分别对信号滤波和频谱分析进行任务划分和并行处理。

图4.1 单片机程序工程基本工作框架

在系统的实现中,FreeRTOS将任务分为信号采集与滤波任务ECG和FFT计算任务。如上图所示,信号采集任务负责从ADS1292R中读取原始心电信号,并完成IIR和FIR滤波的处理,将滤波后的数据存储到循环缓冲区中,通过中断驱动的方式与传感器交互,确保数据的实时性和可靠性;而FFT计算任务则专注于对缓冲区中的数据进行频谱分析,每当缓冲区填满指定数量的数据点时,FFT计算任务将被启动,这虽然会导致实际运行时FFT频谱更新会产生一定的延时,但这样的设计将使得整个系统的工作更加稳定可控。

通过引入FreeRTOS,系统充分利用了单片机的多任务并行能力,使信号滤波和频谱分析的运行效率大幅提升,同时保证了心电信号处理的实时性。滤波和频谱分析的结合,不仅提高了信号的可用性,还为后续的心率计算和心电异常检测提供了更加丰富和可靠的数据支持。

4.2 采集原始数据解码

通过SPI接口,STM32微控制器不断与ADS1292R传感器进行交互,读取其输出的24位数字信号数据。基于3.1节提到的价码规则,将读取到的数据经过必要的解码和处理后,可将其转换为实际的电压值,并进一步用于实时显示与分析。其核心代码如下所示:

图4.2 ADS1292R原始数据解码核心代码图4.2 ADS1292R原始数据解码核心代码

在具体实现中,通过将ADS1292R的24位原始数据解码为32位有符号整数,消除了符号位可能引起的误差。随后,将解码后的信号根据增益和参考电压转换为实际的电压值。这一过程中,左导联和右导联的连接状态也会被实时检测,以确保数据采集的可靠性。如果导联连接异常(如电极松动),系统会发出提示并暂停后续的采集。

4.3 处理算法移植:滤波器

经过STM32接收心电信号后,系统根据PC端设计好的滤波器方案对原始信号进行双重滤波处理,先通过IIR滤波器消除直流分量,然后利用FIR滤波器进一步去除高频噪声,从而得到更为清晰的心电信号。经过IIR和FIR滤波后的信号显著改善,直流漂移、工频干扰以及高频噪声均被有效抑制,这一改进不仅提高了信号的可分析性,也为后续的特征提取与心率计算打下了坚实基础。

滤波后,处理得到的心电信号被传输至PC端,并通过可视化工具显示其改进的波形。如下图所示,信号的基线漂移已完全消除,高频噪声也显著减弱。滤波后的心电信号为后续的心率估算和其他心电特征分析提供了高质量的数据输入,从而提升了系统的整体性能和实用性。

图4.3:PC端可视化软件中显示采集到的滤波后心电信号(解码后)

4.3.1 IIR数字直流陷波器

在IIR滤波阶段,STM32程序参考了PC端的滤波器设计,实现了高效的实时滤波。IIR滤波器的核心算法通过递归关系计算当前输出值,其中参数a=0.992控制直流分量的衰减程度。算法以较少的存储空间完成了对信号直流漂移的有效抑制,使用上一输入与上一输出值的递归关系更新当前输出值,从而达到实时滤波的目的。

图4.4:IIR数字直流陷波器单片机C语言代码

4.3.2 FIR数字低通滤波器

经过IIR滤波后,信号中的直流分量被有效去除,但仍可能含有工频干扰和其他高频噪声。因此,信号会进一步通过FIR滤波器进行处理。FIR滤波器利用一个固定长度的滑动队列实现,其滤波系数矩阵B由MATLAB中的filterDesigner工具生成并导出到C代码中。该滤波运算采用定点方式,在初始化时需要将滤波器系数乘以66536(如图4.5中右图所示),再取整保存为16bits整数。该部分的核心算法是,通过遍历队列数据与滤波器系数进行逐项乘积累加,实现对信号的精准滤波。代码设计充分考虑了队列操作的效率,通过队列循环的方式减少内存消耗并保证实时性。

图4.5:filterDesigner导出系数矩阵B的部分结果及FIR滤波器参数初始化
图4.5:filterDesigner导出系数矩阵B的部分结果及FIR滤波器参数初始化

图4.6:FIR数字低通滤波器核心算法单片机C语言代码

4.4 处理算法移植:心率与幅值计算

系统的心跳检测功能基于心电信号的峰谷变化,通过heartbeat_check函数实现对R波峰值的实时检测。该函数采用简单高效的阈值法,以波峰和波谷之间的差值判断是否发生心跳事件。函数的核心逻辑包括记录当前波形的上升和下降趋势,以及动态调整波峰(up_value)和波谷(down_value)的值。

具体来说,当检测到波形从下降趋势转为上升趋势,且波峰与波谷的差值超过设定的阈值(经过调试设置为0.55较为合适),即判定为一次心跳事件。此时,波峰和波谷会重新初始化,为下一次心跳检测做好准备。如果当前波形变化幅度未达到阈值,则认为是噪声或非心跳波形,函数返回0。

在实际应用中,该函数与DWT模块配合使用,每次心跳事件发生时记录时间戳,通过计算相邻两次事件的时间间隔(R-R间期)估算心率。高精度的DWT计数器和简洁的心跳检测算法相结合,使得系统能够在保证实时性的同时,准确识别心跳并计算心率。

图4.7:单次心跳检测函数heartbeat_check代码

图4.8:心率计算函数calc_heartbeat_rate代码(基于单次心跳的检测结果)

为衡量心率信号的幅值范围,编写函数 Cal_PeakToPeak 以计算一组浮点数数据的峰峰值,即数据中的最大值与最小值之间的差值,用以反映数据的动态范围或振幅。函数通过接收一个浮点数数组 samples 和数组中的元素个数 sample_count 作为输入,首先将数组的第一个元素初始化为当前的最大值和最小值,然后从第二个元素开始逐一遍历整个数组。在遍历过程中,函数逐步更新最大值 max 和最小值 min,确保能够捕获数据中的真实极值。遍历完成后,函数通过计算 max - min 得到峰峰值,并将结果作为返回值。整个过程采用单次遍历的方法,计算效率较高,适合处理较大规模的采样数据。

图4.9:幅值检测函数Cal_PeakToPeak代码

4.5 TFT屏幕绘制采集波形

TFT屏幕是系统的重要输出模块,负责实时显示处理后的心电波形和心率数据。通过高分辨率和快速刷新率,TFT屏幕能够清晰呈现心电信号的变化,供用户随时监控自己的心脏健康状况。它不仅显示心电波形,还提供当前的心率和可能的异常信号提示,帮助用户及时发现问题。

图4.10 2.8寸TFT LCD电阻触摸屏模块320\*240实物图

对于已经滤波后的心电信号,在移植并调用原有LCD驱动库的基础上,编写了drawCurve函数实现实时的波形显示。该函数根据输入的心电信号数值,将其映射到屏幕的像素坐标,并绘制出连续的曲线。

图4.11:TFT屏幕波形绘制函数drawCurve代码

可以看到,对于滤波后的心电信号值,除了基本的指定区域绘制波形外,为避免波形超出屏幕边界,还对计算得到的y坐标进行上下限约束,使其始终位于屏幕的有效显示区域内:如果y坐标超过屏幕范围,则自动截断至边界位置;当x坐标超出屏幕宽度时,程序清空屏幕并从起始位置重新开始绘制新的波形。通过这种循环显示方式,确保波形在屏幕上以滚动形式连续更新,为实时心电信号的监测提供直观的显示效果。

4.6 频谱分析及其TFT屏幕绘制

在频谱FFT计算的具体实现中,程序使用CMSIS-DSP库提供的高效FFT算法,首先将心电信号数据打包为复数输入,其中实部为滤波后的心电数据,虚部置为零。随后调用arm_cfft_radix4_f32函数完成快速傅里叶变换,并通过arm_cmplx_mag_f32函数计算复数频谱的幅值。计算结果存储在FFT输出缓冲区中,用于后续的频谱绘制。

图4.12:频谱计算(FFT)函数FFT_Calculate代码

对于频域波形,系统通过FFT算法计算心电信号的频率分量,并将其可视化为频谱图。频谱图的x轴代表频率,y轴代表频率分量的幅值,能够直观反映心电信号的频率特性。频域波形的可视化主要依赖Draw_Spectrum函数:

图4.13:频谱绘制函数Draw_Spectrum代码

由于屏幕高度有限,为避免绘图时坐标溢出,函数将FFT输出的幅值限制在合理范围内(0到150,其余位置留给时域波形)。当幅值超过上限或低于下限时,进行截断处理。每个频率分量对应一条垂直线,从屏幕底部开始绘制到计算得到的y坐标。

5 程序测试方法

5.1 ADS1292R驱动移植及引脚配置

首先,在通过STM32CubeMX创建工程时,需要配置单片机的时钟速率,SPI接口,中断以及UART串口通信等。为实现与ADS1292R传感器的数据传输,选用SPI1并对引脚进行如下配置:

图5.1:SPI1引脚与参数配置

其中与ADS1292R传感器通信的SPI接口配置为主模式,时钟极性为CPOL=LOW,时钟相位为CPHA=2EDGE,数据帧格式为8位,通信速率依据传感器要求设置在8MHz以下,此处设置为656.25Kbit/s。

此外,还需要根据ADS1292R库文件中的说明,对UART通信进行设置,其中波特率设置为115200,8位数据位,1位停止位,无校验。

图5.2:UART引脚与参数配置

完成引脚配置后就可以进行初始代码生成。在生成的初始代码工程中,引入ADS1292R的相关库文件(ADS1292R.c与ADS1292R.h),根据对应的配置代码将STM32F407开发板与ADS1292R传感器模块进行连线:

图5.3:ADS1292R.h与spi.c代码文件中关于连线的相关说明图5.3:ADS1292R.h与spi.c代码文件中关于连线的相关说明

图5.4:连线实物图
图5.4:连线实物图

连线完成后,要通过SPI接口实现与ADS1292R的数据交互,还需要在主程序中完成相应的初始化,即调用ADS1292R驱动库中的相关函数,由单片机向ADS1292R发送相应的命令以启动数据采集,并配置工作模式、采样速率、增益等参数。根据ADS1292R数据手册及项目要求,以下是对ADS1292R的主要配置过程:

图5.5:函数ADS1292_PowerOnInit中对于ADS1292R的基本配置代码

首先,将ADS1292R的CONFIG2寄存器配置为0xA3,以启用内部参考电压。内部参考电压的稳定性对于后续心电信号的准确采集至关重要,因此在配置完成后需通过DWT_Delay_ms(10)添加延时,确保内部参考电压稳定。随后,将CONFIG1寄存器设置为0x02,配置心电采集的采样速率为500SPS(Samples Per Second),这一速率能够兼顾信号的时域分辨率和数据量。

接下来,对通道1和通道2进行配置。其中,通道1的CH1SET寄存器设置为0x00,表示通道1工作于正常采集模式,且未启用测试信号输入。通道2的CH2SET寄存器配置为0x05,用于指定通道2采集来自内部测试信号的方波,方便在调试阶段验证系统的采集和传输功能。

此外,为了进一步优化信号的质量,对右腿驱动(RLD)电极进行了配置,通过将RLD_SENS寄存器设置为0x2C,使右腿驱动电极同时连接到通道1和通道2,增强了共模信号的抑制能力。在呼吸阻抗测量相关功能中,将RESP1和RESP2寄存器分别配置为0x02和0x03,根据手册要求开启适当的工作模式。

通过上述配置,ADS1292R可以稳定运行于双通道心电采集模式,通道1用于实时采集患者的心电信号,通道2可用于采集ADS1292R传感器的测试信号以验证该传感器模块是否被正常驱动。

5.2 ADS1292R驱动移植验证:读取传感器设备ID

事实上,在ADS1292_PowerOnInit函数中,图5.5所示初始化代码之前还有一段代码:

图5.6:ADS1292_PowerOnInit初始化函数部分代码

可以看到,要实现5.1节中对于ADS1292R传感器模块的正确驱动,就必须要顺利运行该段代码,其中调用了ADS1292_ReadDeviceID这一函数并设置了判断条件,若读取到的设备ID不为83(ADS1292)或115(ADS1292R)则会一直循环读取ID而不进行后续的初始化,以确保读取的心电信号不会出现无效数据且采集数据符合预期格式。由于本次项目使用的传感器芯片为ADS1292R,故成功读取到并在串口助手中打印的device_id为115,这也证明驱动库文件的移植是正确的且能正常驱动该传感器模块。

5.3 ADS1292R驱动移植验证:测试信号采集及其TFT屏幕绘制

在ADS1292R的芯片数据手册中,给出了其内置测试信号的相关参数:

图5.7:ADS1292R芯片手册测试信号部分

可以看到,当PGA增益倍数设置为1时,芯片将输出测试方波信号,通过MATLAB读取并解码原始数据,得到(含直流)范围在-20到8;而去除直流后,该方波动态范围为-14到14。由于参考电压为2.4V(16bits),此时14/32768*2400mv
约等于1mv,说明此时方波动态范围转换为电压是正负1mv,和数据手册说明一致。方波测试信号的成功读取也进一步验证了ADS1292R驱动库移植的正确性且能正常驱动该传感器模块。

图5.8:MATLAB读取测试方波结果

图5.8:MATLAB读取测试方波结果

6 实验数据记录与分析

演示视频链接:https://www.bilibili.com/video/BV1HWCkYzETe/

6.1 测试信号采集

在测试ADS1292的内部方波信号时,设置PGA增益为1,测试结果显示方波波形良好,基本无误差。系统能够准确读取方波信号的峰峰值和幅度值,其效果如图所示:

图6.1:采集测试信号在LCD屏幕上的显示效果(测量幅度值为155)

此外,系统新增了按键功能,按压KEY_0即可实现在显示测试信号波形与显示心电信号波形间切换。

6.2 模拟器心电信号采集

在实际运行中,drawCurve函数结合系统滤波模块的输出数据和心跳检测结果,将心电信号时域与频域的动态变化以实时曲线的形式绘制在屏幕上。同时,在屏幕上显示心率、波幅等关键参数,进一步增强了系统的直观性和信息量。其效果如下图所示:

图6.2:BPM为60的心电信号(模拟器产生)在LCD屏幕上的显示效果

经过测试,测算出的心率值与心电模拟仪中给出的心率值误差不超过3 BPM(每分钟心跳数),满足系统设计需求;但此时滤波器的滤波效果有点过度,也可能是显示的波形幅度调整的不好,导致最终显示的波形丢失了过多的有用信息。

6.3 模拟器心率信号采集

将模拟器调至2档(心率档),产生的心率信号默认为75BPM,此时时域与频域波形的显示效果如下:

图6.3:BPM为75的心率信号(模拟器产生)在LCD屏幕上的显示效果

可以看到,此时测得的心率基本准确,与心电模拟仪中给出的心率值误差不超过3 BPM,满足系统设计需求,且频谱图也有较明显的尖峰且噪声较少;此时滤波器的滤波效果虽然也有点过度了,但效果明显由于6.2节中对于心电信号的测量,有明显的波峰。

心跳检测功能的设计不仅能够适应动态变化的心电信号,还通过灵活的阈值调整提高了对不同信号幅度的适应性。将模拟器调至8档,以调整产生心率信号的幅值(心率BPM仍为75),采集与显示效果如下:

图6.4:幅值为1mV的心率信号(模拟器产生)在LCD屏幕上的显示效果

图6.5:幅值为2mV的心率信号(模拟器产生)在LCD屏幕上的显示效果

图6.6:幅值为3mV的心率信号(模拟器产生)在LCD屏幕上的显示效果

可以看到,随着心率信号幅值的成倍变化,测量出的波形幅值也在成倍变化,且频谱较为干净,这说明该心电信号采集系统对于不同的信号幅度具有较高的灵敏性,但未对测量的幅值数值进行对应电压的换算导致结果并不直观;同时由于测量心率程序中对于检测跳变幅度的阈值设置较小,导致此时当幅值明显增大时,震荡信号的跳变幅度也随之增加,导致心率测量出现一定程度的偏差。

6.4 人体心电信号采集与测量

未接入人体心电信号时,采集到信号的时域波形与频谱如下:

图6.7:未接入任何心率信号时LCD屏幕上显示的时域与频域波形(白板)

对于人体心电信号检测,由于心电电极对接触状态的敏感性,最佳效果仅在涂抹酒精并佩戴三分钟内获得,因此系统仅能在心电电极贴附于人体的短时间内实现精确检测

在实际测试时,邀请室友将电极片分别贴于手腕和脚部,并分别与数据线连接,此时系统采集到的心电波形如下所示(详细测试过程在演示视频中):

图6.8:人体心电信号测试过程掠影
图6.8:人体心电信号测试过程掠影

图6.9:采集到的人体心电信号时域与频域波形显示结果

从图中可以看出,检测人体心电信号时,波形与心电信号模拟仪的输出相比仅存在轻微差别,整体表现良好,但仍然存在滤波过度的问题。

除了将电极贴于手腕和脚部进行测试外,系统还测试了将电极贴在左右锁骨中线第一肋间和胸骨左缘第四肋间的位置。测试结果显示,这些位置的信号稳定性优于手脚部位,并且能够维持更长时间的良好效果。

7 实验结果总结和心得体会

7.1 实验结果

在本项目中,基于 STM32F407ZG 主控芯片和 ADS1292R 传感器模块,成功实现了人体心电信号的采集与分析功能。针对心电信号易受工频干扰和低频基线漂移影响的问题,设计并实现了 IIR 数字直流陷波器 和 FIR 数字低通滤波器,有效消除了干扰并获得了较为清晰的心电波形。

在开发过程中,利用心电信号模拟仪对单片机程序进行了调试,使系统能够稳定采集和显示心电波形。尽管滤波器在MATLAB仿真中效果良好,但移植到单片机工程中后,出现了滤波过度的问题。初步分析认为,这可能与信号采样频率、显示波形的幅度比例调节以及滤波算法的具体实现有关,仍需进一步优化。然而,系统总体性能令人满意,其采集效果、频域分析结果、心电峰峰值及心率测算结果均较为准确。

此外,系统还实现了对 ADS1292R模块自带测试方波信号的读取、显示以及峰峰值测量功能,基本满足了所有的设计需求。最终也成功采集并显示了实际人体心电信号的时域波形与频谱。

7.2 心得体会

通过本次项目的实践,我对数字信号的采集与处理以及滤波器的设计与实现有了更加深刻的理解。这不仅加深了我对数字信号处理理论知识的掌握,还让我在理论与实践的结合中得以进一步巩固相关技能。在单片机的编程实践与调试过程中,我对STM32尤其是F4系列开发板的硬件和软件开发有了更深入的认识,这大大提升了我的开发效率和调试能力。

本项目也是我首次尝试使用 FreeRTOS操作系统搭建整个工程框架。在此过程中,我学习并掌握了实时操作系统的基本原理和任务调度机制,初步理解了如何优化系统资源管理,成功地将操作系统的使用融入到嵌入式项目开发中。这一尝试不仅丰富了我的开发经验,也让我更好地认识到实时操作系统在复杂工程中的价值。

尽管最终心电信号的显示结果并未完全达到预期,但我从问题中发现了自身在信号采集频率、滤波算法实现以及系统显示优化方面的不足,并明确了未来改进的方向。整个项目开发的过程充满了挑战,同时也伴随着大量的收获。我深刻体会到硬件开发与数字信号处理是一个不断探索和优化的过程,而这次项目实践无疑为我在这些领域的技能提升打下了坚实基础。

此外,本次项目还培养了我独立分析和解决问题的能力。从模块功能的实现到整体工程的构建,我逐步熟悉了完整的开发流程,对系统的设计、调试和优化有了更加系统化的认识。我相信,这些经验和能力将在今后的学习和工作中发挥重要作用,为更高层次的开发任务奠定基础。

参考资料

[1] 朱冰莲,方敏编著.数字信号处理[M].电子工业出版社,2014:276.

[2] 程佩青编著.数字信号处理教程[M].清华大学出版社,2015:524.

[3] 任勇,曾浩编著.单片机原理及应用[M].清华大学出版社,2023.

[4] 德州仪器. ADS1292 数据手册

[5] 任勇. CQU_S12XDEV开发板原理图 微电子与通信工程学院

[6] 任勇. ADS1292-心电信号采集原理图及接口说明-RY

基于直流电源调控的自动调光控制设计

摘要

本项目围绕直流电源调控的自动调光控制系统展开研究与设计,系统性地探讨了Buck变换器的基本原理、建模方法、性能分析及其实验验证过程。在硬件设计方面,基于STM32处理器,选择了高性能的元器件并通过合理的电路拓扑实现高效的能量转换;在软件控制算法方面,采用PID闭环控制,并结合自动控制原理中的经典控制理论,利用PSIM与MWorks等仿真与科学计算工具,对控制系统的时域响应、频域特性和稳定性进行了详尽分析,进而通过参数优化与校正环节设计显著提升了系统的响应速度和稳态性能,同时也验证了闭环控制系统在动态性能、抗干扰能力和输出精度方面的显著优势。此外,通过实验测量与仿真结果对比,探讨了电路寄生参数对系统性能的影响,为后续优化提供了理论依据。在基于光敏电阻的自动调光功能模块中,结合蓝牙通信接口实现了系统的智能化控制,同时对于自动调光系统进行外观设计,赋予产品更多的人文关怀与实用价值;在光伏板最大功率点跟踪(MPPT)功能模块中,根据MPPT的原理与基本思想设计了相应的控制算法,并在实验中成功控制光伏板输出功率,使其约等于负载消耗功率,完成了不同光照强度下最大功率点的跟踪。最后,对于该自动控制系统的设计成果及其在实际应用中的可行性与局限性进行总结,并对未来可能的优化方向和工程实现前景提出了展望。

关键词:Buck变换器;PID闭环控制;自动调光;光伏MPPT

1 课程涉及理论基础和STM32简介

1.1 自动控制原理简介

在科学技术飞速发展的今天,自动控制技术和理论已经成为现代社会不可缺少的组成部分。自动控制技术的应用不仅使生产过程实现自动化,从而提高了劳动生产率和产品质量,降低了生产成本,提高了经济效益,改善了劳动条件,使人们从繁重的体力劳动和单调重复的脑力劳动中解放出来;而且在人类征服大自然、探索新能源、发展空间技术和创造人类社会文明等方面都具有十分重要的意义。

自动控制理论是研究关于自动控制系统组成、分析和综合的一般性理论,是研究自动控制共同规律的技术科学。自动控制是在人不直接参与的情况下,利用外加的自动控制设备或装置(控制装置或控制器),使机器、设备或生产过程(统称为被控对象)的某个工作状态或参数(被控量)自动地按照预定的规律运行,使机器的动作、设备的运转、生产过程的状态能够自动地在一定的精度范围内按照给定的规律变化。学习和研究自动控制理论是为了探索自动控制系统中变量的运动规律和改变这种运动规律的可能性和途径,为建立高性能的自动控制系统提供必要的理论依据。

1.2 本项目所涉及的经典控制理论内容

图1.1:项目涉及的经典控制理论框图

本项目从经典控制理论的基本原理与概念出发,以Buck变换器这一单输入-单输出的线性系统作为研究对象,利用微分方程、Laplace变换与传递函数等数学工具建立系统的数学模型,并基于时域分析、频域分析以及根轨迹法等多种分析方法对于系统的稳定性与响应特性进行详细分析,从而针对特定的性能指标进行对应的校正设计,通过引入PID控制器并调控其参数以改变系统的频率特性从而满足给定的各项性能指标,使得整个闭环控制系统能够兼具稳定性、快速性与准确性。

1.3 STM32处理器介绍

控制核心是控制系统中的重要组成部分,用于计算、解析各种数据,并执行相应的控制算法。芯片选型的设计直接决定了控制板的性能和功能。STM32是由意法半导体公司(ST)推出的基于Arm Cortex-M处理器内核的32位微控制器,专为要求高性能、低成本、低功耗的嵌入式应用设计,集实时功能、数字信号处理、低功耗/低电压操作、连接性等特性于一身,同时还保持了集成度高和易于开发的特点,基于行业标准内核,提供了大量工具和软件选项以支持工程开发,非常适用于小型项目或端到端平台。

本项目选用的处理器STM32F103C8T6作为中等容量高性能系列MCU,集成了工作频率为72MHz的高性能Arm Cortex-M3 32位RISC内核、高速嵌入式存储器(高达128KB的Flash存储器和20KB的SRAM存储器),以及大量连接至2条APB总线的增强型I/O与外设,具有36引脚至100引脚等6种不同的封装类型。所有器件均提供2个12位ADC、3个16位通用定时器、2个PWM定时器以及标准和高级通信接口:多达2个I2C和SPI、3个USART、1个USB和1个CAN。器件的工作电压为2.0V至3.6V。该处理器的工作温度范围为-40℃到+85℃,可扩展至-40℃到+105摄氏度。这些特性使得该处理器成为各种应用的理想之选,也能很好满足本项目对于控制器的性能需求。

图1.2:本项目选用的处理器STM32F103C8T6

1.4 本章小结

本章主要介绍了本课程相关的自动控制理论基础,针对本项目涉及到的经典控制理论框架进行了简要概述,同时对于本项目所选用的控制核心——STM32处理器进行简单介绍,重点分析了我们采用的STM32F103C8T6处理器的性能特性并给出选型原因。这为本课程项目提供了整体框架,并从理论上对后续项目的具体实施给出了方向性的指引。

2 直流Buck变换器设计与调试

2.1 Buck变换器拓扑原理分析

Buck(降压式)变换器是一种输出电压≤输入电压的非隔离直流DC-DC变换器,其中输入电流为脉冲式的,而输出电流为连续的低纹波直流电压。Buck变换器实现的稳态输入输出关系为:
$$
U_{0} = DU_{in}
$$
Buck变换器的主电路由开关管Q,二极管D,输出滤波电感L和输出滤波电容C构成。

图2.1:Buck开关功率变换器基本电路

可以看到,在能量缓冲变换电路中,主要由如下三个部分组成:

  1. 电感L与电容C实质上构成了一个二阶低通滤波器,通过滤除开关频率交流分量而仅保留其直流分量,得到平直的输出电压U0;

  2. 脉冲宽度调制(Pulse Width Modulation,PWM)产生方波电压控制开关管Q的导通;

  3. 二极管D为电感电流提供续流回路。

Buck变换器主电路整体的工作逻辑如下:

  1. 当开关管Q驱动为高电平时,开关管导通,储能电感L被充磁,流经电感的电流线性增加,同时给电容C充电,给负载R提供能量;

图2.2:开关管导通时电流环路

  1. 当开关管Q驱动为低电平时,开关管关断,储能电感L通过续流二极管D放电,电感电流线性减少,输出电压靠输出滤波电容C放电以及减小的电感电流维持。

图2.3:开关管关断时电流环路

事实上,对于该电能变换器,可以通过更改个别元器件的种类、接入方式与顺序,实现搭建具有不同功能的电能变换电路,即Buck变换器的拓扑原理。下面列举几种常见的拓扑电路:

  1. 升压变换器:

图2.4:Buck变换器拓扑:降压--->升压

  1. 降压同步整流变换:采用互补工作模式,可减小损耗

图2.5:Buck变换器拓扑:同步整流

  1. H桥DC-AC逆变器:开关管部分串联构成双极性交流电压源

图2.6:Buck变换器拓扑:DC-DC --->DC-AC

  1. 闭环PWM控制:可以在原有Buck电路基础上增加闭环环路,通过PWM调配开关管Q的导通与否,从而实现对于输出电压的控制,使系统能够更加”稳”、”快”、”准”地得到期望的输出。目前的控制器选择主流为PID控制器,根据不同的指标又可将闭环控制系统分为不同类别:若根据控制对象分类,则可分为电压控制与电流控制;若根据接收调控信息的时间先后分类,又可分为反馈控制与前馈控制;根据其他的分类标准,还可分为线性/非线性控制、平均/纹波控制、模拟/数字控制……在此不一一列举。

2.2 Buck变换器元器件参数选择

在Buck变换主电路中,对电路参数进行如下设定:

  • 输入电压
    $$
    U_{in} = 15V
    $$

  • 输出电压
    $$
    U_{o} = 8V
    $$

  • 占空比
    $$
    d = 50%
    $$

  • 电源转换电压:12V、15V、5V、5V(隔离)

  • 电感
    $$
    L = 100\mu F
    $$

  • 电容
    $$
    C = 660\mu F
    $$

  • 工作频率
    $$
    f = 25kHz
    $$

首先,为满足电源转换与单片机供电的需求,需要在电源直接引入Buck电路前先接入电源模块,涉及到的元器件及相关参数如下:

  1. URB2412YMD-10WR3电源模块:降压模块,将电源提供的输入电压(最大35V,本实验中为15V)转换为12V输出,提供0.83A的电流;

图2.7:URB2412YMD-10WR3电源模块原理图与实物图图2.7:URB2412YMD-10WR3电源模块原理图与实物图

  1. CW7805线性稳压器:将12V输入电压转换为稳定的5V输出电压,并将输出电流转换成1A,分输入、输出与接地三端,主要用于使线性的输出电压稳定;

图2.8:CW7805线性稳压器原理图与实物图图2.8:CW7805线性稳压器原理图与实物图

  1. A1215S-2WR3电源模块:升压模块,将12V输入转换为±15V,适合供给双电源运放电路,本实验中主要用于为采样电路(滤波器)供电;

图2.9:A1215S-2WR3电源模块原理图与实物图图2.9:A1215S-2WR3电源模块原理图与实物图

  1. IB1205S-2W电源模块:降压模块,将12V输入转换为5V,通常用于低功耗电路的供电,本实验中主要用于光耦(与驱动)电路的供电。

图2.10:IB1205S-2W电源模块原理图与实物图图2.10:IB1205S-2W电源模块原理图与实物图其次,在Buck变换主电路中,为满足设定元件参数,选取如下元器件:

  1. 贴片MOS管NCE0130KA:VDS=100V,VGS=10V

图2.11: 贴片MOS管NCE0130KA实物图

  1. 贴片电感:色环直插型,100uH

图2.12:贴片电感实物图

  1. 贴片铝电解电容:330uF,±20%,耐压50V,两个并联达到设定660uF

图2.13:贴片铝电解电容实物图

  1. 电流传感器CC6920SO-5A:初级电流测量范围-5A~5A,供电电压5V

图2.14:电流传感器CC6920SO-5A实物图

  1. 电压传感器LV25-NP:初级电流测量范围10-500V,供电电压±15V

图2.15:电压传感器LV25-NP实物图

其中,电容与电感均采用贴片形式的原因主要有以下几点:

【1】 体积小且便于贴装,适合电路的高集成度需求;

【2】 贴片元件引线较短,寄生电感和电容较小,可提高电路的高频性能;

【3】 贴片元件的散热性能通常较好,有助于提高电路的可靠性;

【4】 贴片元件可以有效减小电磁干扰,提高电路的稳定性。

除此之外,由于本实验采用的主控STM32输出能力有限,无法直接驱动管子开关,因此还需要采用光耦和驱动电路为管子提供驱动信号,涉及到的元器件及相关参数如下:

  1. IR21844S驱动:栅极驱动供电范围10-20V

图2.16:IR21844S驱动实物图

  1. 光耦-逻辑输出6N135:5V供电,光耦隔离

图2.17:光耦-逻辑输出6N135实物图

  1. 运算放大器AD823ARZ:最大输入偏置电流25pA,低失真−108dBc

图2.18:运算放大器AD823ARZ实物图

2.3 Buck变换器实物设计与调试

在Buck变换主电路设计时,选择不对Buck变换器的电路部分进行拓扑,而在闭环PWM控制电路中采用平均电压模式进行控制。本项目采用的实验电路板主要包括Buck电路基本器件、开关管驱动、辅助电源以及采样电路(信号调理电路),实验时将元器件焊接至电路板上并分别调试各模块功能。

图2.19:组员焊接电路板过程图2.19:组员焊接电路板过程

图2.20:焊接后Buck变换器整体电路实物图图2.20:焊接后Buck变换器整体电路实物图

2.3.1 主电路设计与调试

图2.21:Buck变换器主电路原理图

该电路是一个典型的降压型 DC-DC 转换器,其工作原理是通过开关管 Q3 的高速开关动作,将输入电压V_IN转换为期望的输出电压V_OUT。当开关管Q3导通时,输入电压通过 L2、L3和负载形成电流回路,电感存储能量,同时为负载供电;当 Q3关断时,续流二极管 D4 提供电流通路,电感释放能量维持负载电流的连续性。控制器 U6根据反馈电压(通过分压电阻 R8 反馈的V_OUT)与参考电压之间的误差,实时调节 Q3的导通时间(占空比),从而实现输出电压的稳定调节。两级电感 L2 和 L3以及滤波电容 C9、C15进一步平滑输出电流和电压,减少高频纹波,确保输出电压的稳定性和低噪声特性。

经过调试,Buck降压模块主电路可正常实现功能,在参考输入方波幅值为8V、占空比为50%的情况下能够输出占空比为50%、幅值在8V左右(实际约为8.5V)的方波。

图2.22:Buck变换器主电路调试过程与调试结果图2.22:Buck变换器主电路调试过程与调试结果图2.22:Buck变换器主电路调试过程与调试结果图2.22:Buck变换器主电路调试过程与调试结果

2.3.2 控制电路供电设计与调试

图2.23:STM32主控芯片供电电路及预留引脚接口

如图所示为STM32主控芯片供电电路(电源模块)以及单片机内部所使用的接口引脚图,同时将大部分未使用的引脚通过排针引出以供后续拓展功能开发。

在STM32主控芯片供电电路中,包含两个级联的线性稳压器,用于将高电压逐级稳压到所需的5V 和 3.3V。上半部分采用 CJ7805稳压器,将输入电压V_IN转换为稳定的5V输出,通过输入电容C2和C1滤波降低输入纹波,稳压器通过内部反馈电路调节输入电压,使输出稳定在5V,同时通过输出电容C3滤除高频噪声,进一步平滑输出电压。下半部分采用
AMS1117-3.3 稳压器,将上一级提供的 5V 电压进一步稳压为3.3V,通过输入滤波电容 C5和 C6减少输入噪声,并通过输出滤波电容C4提高输出电压的稳定性。整个电路通过分级稳压设计,既提高了稳压效率,又能为负载提供低噪声、高稳定性的5V和3.3V电压,适用于嵌入式系统和低功耗数字电路的电源需求。

调试流程:取下单片机核心板—>接入负载100欧姆—>单片机输出PWM—>观测PA8端口波形—>观测驱动芯片输出端口波形—>上主电24V—>检测辅助电源输出电压—>检测输出电压—>根据占空比计算输出电压是否正常—>完成

经调试,该部分模块可正常工作,为STM32主控芯片提供稳定的5V电压:

图2.24:控制模块供电电路调试输出结果图2.24:控制模块供电电路调试输出结果

2.3.3 驱动电路设计与调试

图2.25:光耦隔离(上)与驱动电路(下)原理图

如图所示,驱动电路为已有的STM32输出提供了合适的电压和电流驱动功率器件,而如果直接使用STM32输出驱动,可能会超出其输出能力或不能实现良好的电气隔离,导致驱动失败或损坏器件,输出信号不稳定。使用光耦和驱动电路则可以更好地实现电气隔离,从而防止高压或大电流对控制电路的干扰或损坏,保护STM32免受高电压或大电流的影响,提高系统工作可靠性。

调试时,先切断仿真器供电,将单片机供电切换为主电路辅助电源供电;单片机烧录输出电压控制程序后,接入后端负载,再上主电,观测输出电压。经调试,驱动电路可正常工作。

图2.26:驱动电路调试后输出结果图2.26:驱动电路调试后输出结果

2.3.4 电压和电流采样调理滤波设计与调试

图2.27:电感电流(上)与输出电压(下)采样调理滤波电路原理图

该电路是一个基于运算放大器的电压比较和分压检测电路,主要功能是将输入电压V_OUT通过电阻分压后与基准电压比较,并输出相应的信号V_S。该电路可用于电压监测或过压保护等场景,通过调整R1 和 R2 的比例,可以设置分压电压,从而灵活设定输入电压的触发阈值。

具体工作原理如下:输入电压$V_{OUT}$经由电阻R1和R2分压后,产生一个分压电压,该电压送入运算放大器U5的反相输入端(引脚2)。运算放大器的非反相输入端(引脚 3)通过稳压二极管 D2提供一个固定的基准电压(3.3V)。当分压后的电压低于基准电压时,运算放大器输出高电平;当分压电压高于基准电压时,运算放大器输出低电平。电容C7和C16用于滤除输入和输出的高频噪声,保证比较过程的稳定性。

调试时,使用仿真器给单片机供电,以调试PWM波形输出是否正常;烧录开环测试程序之后,使用示波器或者上位机观测电路板PA8端口是否正常输出PWM波形。经调试,可对输入信号正确采样并输出对应波形,说明采样模块正常工作:

图2.28:采样模块调试后输出结果图2.28:采样模块调试后输出结果

2.4 本章小结

本章主要介绍了直流Buck变换器的基本工作原理及其拓扑变换,并根据选定的主控芯片STM32F103C8T6以及设定的电路参数进行了基本元器件的选型与电路原理图及PCB电路板的设计,确定电路主要包括Buck降压变换主电路、控制电路供电辅助电源模块、驱动电路以及采样电路(信号调理电路)四个模块;在焊接时对各个模块依次进行焊接与调试,保证各模块均可以正常工作,以便于后续闭环控制实现时STM32主控控制模块与代码的设计与测试。

3 直流Buck变换器建模

3.1 Buck变换器闭环控制原理分析

Buck变换器闭环控制系统主要由以下几个部分组成:

  1. 误差放大器:将参考电压V_ref与实际输出电压V_OUT比较,生成误差信号;

  2. 补偿网络:对误差信号进行处理(例如,PI或PID控制),以提高系统稳定性和动态性能;

  3. PWM调制器:将补偿后的控制信号转换为开关元件的占空比D;

  4. 采样电路:对输出电压 V_OUT进行实时采样。

图3.1:Buck变换器闭环控制电路简图

整个闭环控制系统的工作过程如下:

  1. 输出电压采样:通过分压电路对输出电压V_OUT进行采样,得到反馈电压V_fb;

  2. 误差检测:误差放大器将参考电压V_ref与反馈电压V_fb比较,产生误差信号
    $$
    e(t) = V_{ref} - V_{fb}
    $$

  3. 误差调节:误差信号经过补偿网络调节,生成调节信号V_ctrl,此信号决定PWM占空比;

  4. PWM调制:调制器根据调节信号V_ctrl生成控制信号D,驱动开关元件;

  5. 电感电流调节:开关元件的导通时间决定电感电流的充电时间,从而控制输出电压。

图3.2:Buck变换器闭环控制系统框图

从系统传递函数的角度考虑,根据系统框图与元件特性,可计算其开环传递函数与特征方程:

(1)G_c(s)为PI环节, PI调节器为:
$$
\left{ \begin{aligned}
& \dot{x} = K_{I}v \
& y = K_{p}v + x
\end{aligned} \right.
$$
可得PI环节传递函数G_c(s):

$$
G_{c}(s) = K_{p} + K_{I}\frac{1}{s} = \frac{K_{p}(\tau s + 1)}{\tau s},\tau = \frac{K_{p}}{K_{I}}
$$
(2)PWM脉宽调制环节:由大信号关系
$$
v_{con}(dT) = v_{ramp}(dT) = V_{M}\frac{dT}{T} = dV_{M}
$$
做微分可得小信号的线性关系
$$
\mathrm{\Delta}v_{con} = \mathrm{\Delta}dV_{M}
$$
从而实现传递函数的线性化:

$$
G_{pwm} = \frac{\mathrm{\Delta}d}{\mathrm{\Delta}v_{con}} = 1/V_{M}
$$
(3)PWM脉宽控制开关电路:由大信号关系
$$
v_{D} = dv_{g}
$$
做全微分可得小信号线性关系
$$
\mathrm{\Delta}v_{D} = \mathrm{\Delta}dV_{g} + \mathrm{\Delta}v_{g}D
$$
零初始条件下,对应的工作点为
$$
V_{g} = V_{in},\mathrm{\Delta}v_{g} = 0
$$
于是有传递函数:
$$
G_{vg} = \frac{\mathrm{\Delta}v_{D}}{\mathrm{\Delta}d} = V_{g}
$$
(4)RLC并联二阶输出滤波器:由电路图与元件特性可得各元件间电流电压关系:

$$
\left{ \begin{array}{r}
u_{0} = Ri_{2} \
u_{L} = L\frac{di}{dt} \
i_{1} = C\frac{du_{0}}{dt} \
i = i_{1} + i_{2} \
u_{D} = u_{L} + u_{0}
\end{array} \right.
$$
从而可得该滤波器对应的微分方程:
$$
u_{D} = LC{u_{0}}^{‘’} + \frac{L}{R}{u_{0}}^{‘} + u_{0}
$$
对两边同时进行拉普拉斯变换,化简整理后可得二阶滤波器的传递函数G_vd(s):

$$
G_{vd}(s) = \frac{U_{0}(s)}{U_{D}(s)}V_{in} = \frac{\frac{1}{LC}}{s^{2} + \frac{1}{RC}s + \frac{1}{LC}}V_{in}
$$
又因输出信号v_0直接接入PI控制器,故
$$
H(s) = 1
$$
综上所述:有开环传递函数:

$$
T(s) = G_{c}(s)G_{pwm}G_{\text{vd}}H(s) = \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{\frac{1}{LC}}{s^{2} + \frac{1}{RC}s + \frac{1}{LC}}V_{in} = \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{V_{in}}{LCs^{2} + \frac{L}{R}s + 1}
$$
进而可以得到系统的特征方程
$$
T(s) + 1 = \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{V_{g}}{LCs^{2} + \frac{L}{R}s + 1} + 1 = 0
$$
化简后可得:
$$
\Delta(s) = V_{g}K_{p}(\tau s + 1) + \tau sV_{M}\left( LCs^{2} + \frac{L}{R}s + 1 \right) = \tau V_{M}LCs^{3} + \tau V_{M}\frac{L}{R}s^{2} + (V_{g}K_{p} + V_{M})\tau s + V_{g}K_{p} = 0
$$

3.2 Buck变换器PSIM仿真(开环+闭环)

利用PSIM软件进行电路仿真,根据实际电路结构搭建仿真电路图,并将电路各元件实际参数代入(PI控制器参数:K_p = 0.1,tao = 0.004):

图3.3:Buck变换器开环控制PSIM仿真电路图

图3.4:Buck变换器闭环控制PSIM仿真电路图

运行仿真程序,可得到输出电压的仿真结果:

图3.5:Buck变换器开环控制PSIM仿真结果------输出电压

图3.6:Buck变换器闭环控制PSIM仿真结果------输出电压

对比开环与闭环控制系统的输出电压仿真结果可以发现,尽管两个系统都能在短时间内达到稳定的输出电压,但显然闭环控制系统到达稳态的速度更快且震荡更小,稳定后的电压也更接近参考电压8V(约为7.95V)。这说明闭环控制系统具有更快的响应速度与更好的稳定性和准确性。

3.3 输出电压纹波计算(仿真+实验)

图3.7:Buck变换器开环控制实验输出电压纹波波形图3.7:Buck变换器开环控制实验输出电压纹波波形

首先进行Buck变换器的开环控制实验,并通过示波器观察其输出电压的纹波波形。可以看到,输出波形峰值
$$
V_{omax} = 88mV
$$
谷值
$$
V_{omin} = - 76mV
$$
则波形的震荡幅度为
$$
\Delta V_{o} = V_{omax} - V_{omin} = 164mV
$$
随后利用PSIM软件进行电路仿真,根据实际电路结构搭建仿真电路图,并将电路各元件实际参数代入:

图3.8:Buck变换器开环控制PSIM仿真电路图

可得到输出电压纹波的仿真结果:

图3.9:Buck变换器开环控制PSIM仿真结果------输出电压纹波

可以看到,输出电压信号的震荡波形与实际电路示波器显示的纹波形状一致且震荡幅度大致相同。

3.4 电容寄生电阻计算(仿真+实验)

在Buck变换器开环控制实验中,通过万用表测量得到输入电压V_i= 15.304V,输出电压均值V_o = 7.537V:

图3.10:Buck变换器开环控制实验输入、输出电压测量结果图3.10:Buck变换器开环控制实验输入、输出电压测量结果

除了给定的元件参数之外,为对直流Buck变换器进行精确建模,考虑到电容的寄生参数可能对系统有较大影响,故特别计算其寄生电阻阻值ESR:

图3.11:寄生电阻阻值计算理论依据

结合
$$
U_{esr} = \Delta I_{L}*ESR
$$
一式,考虑到电流因流过电容的寄生电阻而产生的压降U_esr应不大于(实际一般处理为等于)波形的震荡幅度,即:
$$
U_{esr} \leq \Delta V_{o}
$$
可以得到在同步Buck电路中(V_d = 0)电容寄生电阻阻值ESR的计算公式:

$$
ESR \leq \frac{\Delta V_{o}fLV_{i}}{V_{o}\left( V_{i} - V_{o} \right)}
$$
结合Buck变换器开环控制实验结果,代入参数
$$
\Delta V_{o} = 164mV,L = 100\mu F,f = 25kHz,V_{i} = 15.304V,V_{o} = 7.537V
$$
可以计算得出该电路中实际的电容寄生电阻阻值
$$
ESR \approx 107.185m\Omega
$$
这里计算的是接入单个电容的寄生电阻阻值,在实际电路中使用了两个330μF的电容等效替代原设计电路中的660μF电容,为使仿真尽可能接近实际,采取了与实际电路相同的结构,因此需要把寄生电阻同样进行等效,根据电阻并联的等效电阻计算可以得到两个330μF电容的寄生电阻值均为
$$
2ESR \approx 214.371m\Omega
$$
利用PSIM软件进行电路仿真,根据实际电路结构搭建仿真电路图,并将计算出的寄生电阻结果代入仿真电路中:

图3.12:引入寄生电阻后的Buck变换器开环控制PSIM仿真电路图

得到的输出电压仿真结果如下图所示:

图3.13:引入寄生电阻后的Buck变换器开环控制PSIM仿真结果------输出电压

图3.14:引入寄生电阻后的Buck变换器开环控制PSIM仿真结果------输出电压纹波

可以看到,仿真结果中输出电压的均值约为7.65V,与实际的测量结果
$$
V_{o} = 7.537V
$$
较为接近;同时输出电压信号的震荡波形也与实际电路示波器显示的纹波形状一致且震荡幅度大致相同。这也印证了寄生电阻的计算以及电路建模与仿真的正确性。

3.5 本章小结

本章主要介绍了直流Buck控制器及其闭环控制系统的建模过程,通过分析Buck电路中的元件特性及闭环控制的各个环节,实现控制系统的数学建模,得到系统的开环传递函数与特征方程;同时结合Buck控制器开环控制实验的实际测量结果,关注到电容寄生电阻对于系统输出的重要影响,并通过输出电压纹波的相关特性对其进行计算,搭建PSIM电路仿真模型观察修正前后的仿真结果,发现引入寄生电阻后的仿真结果与实际实验波形输出基本一致从而说明考虑寄生电阻的必要性。除此之外,还分别搭建了Buck变换器的开环与闭环控制系统PSIM仿真电路并对比输出电压仿真结果,可以发现闭环控制系统具有更好的动态响应性能,其稳定性、快速性与准确性均优于开环控制系统。

4 直流Buck变换器控制性能分析

4.1 直流Buck变换器劳斯稳定判据分析

基于3.1节得到的开环传递函数与系统特征方程,可利用劳斯判据给出系统稳定的PI控制器比例系数K_p临界条件:

根据系统特征方程可给出如下劳斯表:

劳斯表

根据劳斯判据,要使得系统稳定,需同时满足如下条件:

$$
\left{ \begin{array}{r}
\ \tau V_{M}LC > 0 \
\tau V_{M}\frac{L}{R} > 0 \
\left( V_{in}K_{p} + V_{M} \right)\tau - V_{in}K_{p}RC > 0 \
{\ \ V}{in}K{p} > 0
\end{array} \right.\
$$
这是关于PI控制器比例系数K_p的不等式组,可解得其边界条件为:

$$
0 < K_{p} < \frac{V_{M}\tau}{V_{in}(RC - \tau)}
$$
若选定控制环路的时间常数
$$
\tau = 0.004$
$$
三角载波幅值
$$
V_{M} = 0.5V
$$
则可代入数值解得:比例系数K_p的稳定边界为
$$
\frac{V_{M}\tau}{V_{in}(RC - \tau)} \approx 0.0513
$$
而在实际情况下,需要考虑电容的寄生电阻
$$
ESR \approx 107.185m\Omega
$$
这意味着需要对3.1节建立的数学模型进行修正。显然电路结构中除二阶滤波器外的其他环节没有发生改变,针对考虑电容寄生电阻ESR的RLC并联二阶输出滤波器,由电路图与元件特性可得各元件间电流电压关系:

$$
\left{ \begin{array}{r}
u_{0} = Ri_{2} \
u_{L} = L\frac{di}{dt} \
i_{1} = C\frac{du_{C}}{dt} \
i = i_{1} + i_{2} \
u_{0} = u_{C} + ESRi_{1} \
u_{D} = u_{L} + u_{0}
\end{array} \right.\
$$
从而可得该滤波器对应的微分方程,对两边同时进行拉普拉斯变换,化简整理后可得二阶滤波器的传递函数G_vd(s):

$$
G_{vd}(s) = \frac{U_{0}(s)}{U_{D}(s)}V_{in} = \frac{\frac{1}{LC} + \frac{ESR}{L}s}{(1 + \frac{ESR}{R})s^{2} + (\frac{1}{RC} + \frac{ESR}{L})s + \frac{1}{LC}}V_{in}
$$
其他环节保持不变,于是有开环传递函数:
$$
T(s) = G_{c}(s)G_{pwm}G_{\text{vd}}H(s) = \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{\frac{1}{LC} + \frac{ESR}{L}s}{\left( 1 + \frac{ESR}{R} \right)s^{2} + \left( \frac{1}{RC} + \frac{ESR}{L} \right)s + \frac{1}{LC}}V_{in} \approx \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{1 + C \bullet ESRs}{LCs^{2} + \frac{L}{R}s + 1}V_{in}
$$
因此近似后系统的特征方程
$$
T(s) + 1 = \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{(1 + C \bullet ESRs)V_{in}}{LCs^{2} + \frac{L}{R}s + 1} + 1 = 0
$$
化简后可得:

$$
\Delta(s) = {(1 + C \bullet ESRs)V}{in}K{p}(\tau s + 1) + \tau sV_{M}\left( LCs^{2} + \frac{L}{R}s + 1 \right) = V_{M}LC\tau s^{3} + (V_{M}\frac{L}{R} + C \bullet ESR \bullet V_{in}K_{p})\tau s^{2} + (V_{in}K_{p}\tau + V_{M}\tau + C \bullet ESR \bullet V_{in}K_{p})s + V_{in}K_{p} = 0
$$
接下来利用劳斯判据给出系统稳定的PI控制器比例系数K_p临界条件:

根据系统特征方程可给出如下劳斯表:

劳斯表

根据劳斯判据,要使得系统稳定,需同时满足如下条件:

$$
\left{ \begin{array}{r}
\ \tau V_{M}LC > 0 \
\tau V_{M}\frac{L}{R} > 0 \
V_{in}K_{p}\tau + V_{M}\tau + C \bullet ESR \bullet V_{in}K_{p} - \frac{V_{M}LCV_{in}K_{p}}{V_{M}\frac{L}{R} + C \bullet ESR \bullet V_{in}K_{p}} > 0 \
{\ \ V}{in}K{p} > 0
\end{array} \right.\
$$
这是关于PI控制器比例系数K_p的不等式组,其中第1、2、4个不等式均指向K_p > 0,而第三个不等式是一个关于K_p的一元二次不等式,代入电路元件参数可解得
$$
K_{p} < - 0.0232或K_{p} > - 0.0067
$$
因此可得到K_p的稳定边界为:
$$
K_{p} > 0
$$
即该情况下系统始终稳定。

4.2 直流Buck变换器系统根轨迹分析(手绘+MWorks绘制)

基于3.1节得到的开环传递函数,代入数值可得:

$$
T(s) = \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{V_{in}}{LCs^{2} + \frac{L}{R}s + 1} = \frac{30K_{p}(s + 250)}{s(6.6*10^{- 8}s^{2} + 10^{- 5}s + 1)}
$$
根据该开环传递函数可知,该系统:

具有1个零点:
$$
z_{1} = 250
$$
具有3个极点:
$$
p_{0} = 0,p_{1} + p_{2} = \frac{5}{33}*10^{3} \approx 151.5,p_{1} = \frac{5}{66}*10^{3} + a_i,p_{1} + p_{2} = \frac{5}{66}*10^{3} - a_i
$$
故有3条根轨迹,1条止于开环零点,2条止于无穷远;

根轨迹的渐近线与实轴的夹角
$$
\varphi_{a} = \pm \frac{2k + 1}{2}\pi(k = 0,1,2\ldots) = \pm 90{^\circ}、180{^\circ}
$$
渐近线与实轴交点的坐标值
$$

  • \delta_{a} = \frac{\sum_{}^{}\left( - p_{i} \right) - \sum_{}^{}\left( - z_{i} \right)}{2} = \frac{- \frac{5}{33}*10^{3} + 250}{2} \approx 49.24
    $$

基于以上结果,可手绘根轨迹草图如下:

图4.1:不考虑寄生电阻------手绘根轨迹草图

编写如下MWorks代码:

1
2
3
4
using TyControlSystems
s=tf('s');
G=(s+250)/(s*(6.6*10^(-8)*s*s+10^(-5)*s+1));
rlocus(G);

运行该段代码,得到MWorks绘制的根轨迹图如下:

图4.2:不考虑寄生电阻------MWorks绘制根轨迹图

根轨迹本质上反映的随着比例系数K_p的变化,特征方程根的变化情况;当两个共轭根恰好位于虚轴上时,此时对应的比例系数K_p(可将此时特征根带回特征方程求出)即为其稳定的边界值(大于该值不稳定,小于该值稳定)。

编写如下MWorks程序,寻找根轨迹与虚轴的交点并带回特征方程,求出比例系数K_p稳定边界值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
% 找寻与虚轴交点
k = linspace(0, 10, 1000); % 增加点数,1000个点
[r, k]=rlocus(G,k);
real_part = real(r);
imag_part = imag(r);
% 查找实部接近零的索引
tolerance = 1e-1; % 设定阈值
idx = find(abs(real_part) < tolerance); % 找到所有交点的索引
intersections = r(idx); % 交点的复数值
% 求解临界kp
s = intersections(2);
% 系统参数
tao = 0.004;
vm = 0.5;
l = 10^(-4);
c = 6.6*10^(-4);
vin = 15;
r = 10;
syms kp; % 定义符号变量
eq = tao*vm*l*c*s*s*s + tao*vm*l*s*s/r + vin*kp*tao*s + vm*tao*s + vin*kp == 0;
solutions = solve(eq, kp); % 求解
real_solutions = real(solutions); % 取实部
decimal_solutions = double(real_solutions); % 转换为小数
disp(decimal_solutions); % 显示结果

运行上述MWorks代码,得到的比例系数K_p稳定边界值结果为:0.0514,这与先前依据劳斯判据得到的结果
$$
\frac{V_{M}\tau}{V_{in}(RC - \tau)} \approx 0.0513
$$
大致一致。

而在实际情况下,需要考虑电容的寄生电阻;基于4.1节修正后的开环传递函数,代入数值可得:

$$
T(s) \approx \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{1 + C \bullet ESRs}{LCs^{2} + \frac{L}{R}s + 1}V_{in} \approx \frac{30K_{p}(s + 250)(1 + 7.0710^{- 5}s)}{s(6.610^{- 8}s^{2} + 10^{- 5}s + 1)}
$$
根据该开环传递函数可知,该系统:

具有2个零点:
$$
z_{1} = 250,z_{2} \approx 1.41*10^{5}
$$
具有3个极点:
$$
p_{0} = 0,p_{1} + p_{2} = \frac{5}{33}*10^{3} \approx 151.5,p_{1} = \frac{5}{66}*10^{3} + bi,p_{1} + p_{2} = \frac{5}{66}*10^{3} - bi
$$
故有3条根轨迹,2条止于开环零点,2条止于无穷远;

根轨迹的渐近线与实轴的夹角
$$
\varphi_{a} = \pm (2k + 1)\pi(k = 0,1,2\ldots) = 180{^\circ}
$$
基于以上结果,可手绘根轨迹草图如下:

图4.3:考虑寄生电阻------手绘根轨迹草图

编写MWorks代码如下:

1
2
3
4
5
6
using TyControlSystems
s=tf('s');
c = 6.6*10^(-4);
esr = 0.107185;
G=(s+250)*(1+c*esr*s)/(s*(6.6*10^(-8)*s*s+10^(-5)*s+1));
rlocus(G);

运行该段代码,得到MWorks绘制的根轨迹图如下:

图4.4:考虑寄生电阻------MWorks绘制根轨迹图

可以看到,在考虑电容寄生电阻的情况下,根轨迹完全位于虚轴左侧,这意味着无论比例系数K_p(>0)如何变化,系统特征方程的根均位于虚轴左侧,即此情况下系统始终稳定,这与先前依据劳斯判据得到的结果也是一致的。这样的结果也充分说明,寄生电阻的加入使得系统的稳定性提高。

4.3 直流Buck变换器奈奎斯特稳定判据分析

在不考虑寄生电阻的情况下,基于3.1节得到的开环传递函数,取负载电阻R = 2欧姆,代入PI控制器参数:
$$
K_{p} = 0.05、\tau = 1\text{/}5000
$$
与三角载波幅值
$$
V_{M} = 3V
$$
可得:

$$
T(s) = \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{V_{in}}{LCs^{2} + \frac{L}{R}s + 1} = \frac{0.05 \times \left( \frac{1}{5000}s + 1 \right)}{\frac{1}{5000}s} \cdot \frac{1}{3} \cdot \frac{15 \times 10^{8}}{6.6s^{2} + 5000s + 10^{8}} = \frac{2.5 \times 10^{7}(s + 5000)}{s(6.6s^{2} + 5000s + 10^{8})}
$$
根据该开环传递函数,编写MWorks代码如下:

1
2
3
using TyControlSystems
H = tf([2.5*10^7 2.5*10^7*5000],[6.6 5000 10^8 0]);
nyquist(H);

运行该段代码,得到MWorks绘制的奈氏图如下:

图4.5:不考虑寄生电阻------MWorks绘制奈氏图图4.5:不考虑寄生电阻------MWorks绘制奈氏图

观察奈氏图图像可得:正穿越次数N+=1,负穿越次数N- =1

又由系统开环传递函数可知:系统开环右极点数P=0

故由奈奎斯特稳定判据可知:该闭环系统稳定。

图4.6:奈奎斯特稳定判据

4.4 直流Buck变换器系统波特图分析(MWorks绘制)

与4.3节使用相同参数,即开环传递函数可写为:

$$
T(s) = \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{V_{in}}{LCs^{2} + \frac{L}{R}s + 1} = \frac{2.5 \times 10^{7}(s + 5000)}{s(6.6s^{2} + 5000s + 10^{8})}
$$
根据该开环传递函数,编写如下MWorks代码绘制波特图:

1
2
3
4
using TyControlSystems
s=tf('s');
G=2.5*10^7*(s+5000)/(s*(6.6*s^2+5000*s+10^8));
bode(G);

运行该段代码,得到MWorks绘制的波特图如下:

图4.7:不考虑寄生电阻------MWorks绘制波特图

从图中可读出:剪切频率
$$
\omega_{c}≈1.49*10^{3}rad/s
$$
相位裕度
$$
γ≈102{^\circ}
$$
根据对数频率特性稳定判据可知:当相位裕度γ与增益裕度Lg同时大于零时,闭环系统稳定;而对于最小相位系统,相位裕度γ>0与增益裕度Lg>0是同时发生或同时不发生的,因此只需通过相位裕度γ即可判定闭环系统稳定情况。显然此时相位裕度大于零,表明闭环系统稳定,且稳定性较好(相位裕度较大)。

4.5 直流Buck变换器闭环负载稳定边界计算及仿真验证

基于2.2节中的电路元件参数以及输入电压恒为15V的客观事实,在给定PI控制器参数:
$$
K_{p} = 0.1、\tau = 0.004
$$
与三角载波幅值
$$
V_{M} = 0.5V
$$
的情况下,若不考虑电容寄生电阻,根据4.1节劳斯判据化简后的结果:
$$
RCV_{g}K_{p} \leq (\tau V_{M} + V_{g}K_{p}\tau)
$$
可推得系统处于稳定状态的电阻值范围应为:
$$
R \leq \frac{\tau}{C}\left( \frac{V_{M}}{V_{g}K_{p}} + 1 \right) \approx 8.08\Omega
$$
即直流Buck变换器闭环系统的负载电阻稳定边界约为8.1Ω。

为进一步通过仿真验证计算结果,建立PSIM仿真电路图如下:

图4.8:直流Buck变换器闭环控制负载电阻稳定边界PSIM仿真验证电路图

  1. 取负载电阻值R = 5Ω(小于临界值)时:

图4.9:负载电阻值R=5Ω时输出电压PSIM仿真结果

图4.10:负载电阻值R=5Ω时输出电压纹波PSIM仿真结果

  1. 取负载电阻值R = 8.1欧姆(约等于临界值)时:

图4.11:负载电阻值R=8.1Ω时输出电压PSIM仿真结果

图4.12:负载电阻值R=8.1Ω时输出电压纹波PSIM仿真结果取负载电阻值R=10Ω(大于临界值)时:

图4.13:负载电阻值R=10Ω时输出电压PSIM仿真结果

图4.14:负载电阻值R=10Ω时输出电压纹波PSIM仿真结果

通过对比三组仿真结果可以发现:取不同的负载电阻值并不会影响系统的响应速度与响应瞬时超调量,而是影响输出电压趋于稳定后的纹波波形:

  1. 当负载电阻值小于临界值时,稳定后的输出电压会有较大的震荡(负载越小,震荡幅度越大),但该震荡上没有纹波,系统处于稳定状态;

  2. 当负载电阻接近临界值(实际临界值略小于8.1Ω)时,稳定后输出电压的震荡幅度减小,但开始出现纹波,系统处于临界稳定状态;

  3. 当负载电阻大于临界值时,稳定后输出电压的震荡幅度进一步减小,但纹波幅度有所增大,系统处于不稳定状态。

4.6 考虑寄生参数直流Buck变换器波特图分析(MWorks绘制)

在实际情况下,为实现对直流Buck变换器闭环控制系统更加精准的建模,需要考虑电容的寄生电阻,基于4.1节修正后的开环传递函数(取未近似结果):

$$
T(s) = \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{\frac{1}{LC} + \frac{ESR}{L}s}{\left( 1 + \frac{ESR}{R} \right)s^{2} + \left( \frac{1}{RC} + \frac{ESR}{L} \right)s + \frac{1}{LC}}V_{in}
$$
取PI控制器参数:
$$
K_{p} = 1、\tau = 0.01
$$
三角载波幅值
$$
V_{M} = 2V
$$
负载电阻
$$
R = 2\Omega
$$
代入电路各元件参数与3.4节测算得到的寄生电阻
$$
ESR \approx 107.185m\Omega
$$
编写如下MWorks程序绘制波特图:

1
2
3
4
5
6
7
8
9
10
11
12
using TyControlSystems
s=tf('s');
vm=2;
r=2;
esr=0.107185;
c=6.6\*10\^(-4);
l=10\^(-4);
vg=15;
kp=1;
tao=0.01;
G=kp\*(tao\*s+1)\*(esr\*c\*s+1)\*vg/(tao\*s\*vm\*(l\*c\*(1+esr/r)\*s\*s+(l/r+esr\*c)\*s+1));
bode(G);

运行该段代码后绘制出的波特图如下:

图4.15:考虑寄生电阻------MWorks绘制波特图

从图中可读出:剪切频率
$$
\omega_{c}≈1.29*10^{4}rad/s
$$
相位裕度
$$
γ≈50{^\circ}
$$
根据对数频率特性稳定判据可知,此时相位裕度γ>0,表明闭环系统稳定。

4.7 PSIM仿真扫频波特图

取与4.6节相同的参数,利用PSIM搭建扫频电路进行仿真得到波特图:

图4.16:考虑寄生电阻------PSIM扫频仿真电路图

图4.17:考虑寄生电阻------PSIM扫频仿真结果

从图中可读出:剪切频率
$$
\omega_{c} \approx 1997Hz \approx 1.25*10^{4}rad/s
$$
相位裕度
$$
γ≈50{^\circ}
$$
扫频仿真结果与MWorks根据系统开环传递函数绘制的波特图基本一致。

若在仿真电路图中加入锁存器与零阶保持器:

图4.18:考虑寄生电阻------加入锁存器与零阶保持器后PSIM扫频仿真电路图

图4.19:考虑寄生电阻------加入锁存器与零阶保持器后PSIM扫频仿真结果

图4.19:考虑寄生电阻——加入锁存器与零阶保持器后PSIM扫频仿真结果

从图中可读出:剪切频率
$$
\omega_{c}≈1997Hz
$$
相位裕度
$$
γ≈18{^\circ}
$$
可以发现,在仿真中加入锁存器与零阶保持器后,剪切频率基本未发生改变,图线也大致与MWorks通过传递函数得到的波特图相同,但相位裕度有所降低,系统仍然保持稳定。

4.8 本章小结

本章主要对于直流Buck变换器闭环控制系统的控制性能进行了详细的分析,特别是针对系统的稳定性问题,从系统的开环传递函数入手,对于考虑电容寄生电阻与否的两种不同情况,在时域上利用劳斯稳定判据与根轨迹法,讨论在负载电阻R与PI控制器时间常数τ给定的情况下,PI控制器比例系数K_p的稳定边界;在频域上依据奈奎斯特稳定判据(基于奈奎斯特图)与对数频率特性稳定判据(基于波特图,由MWorks绘制与PSIM扫频仿真得到,两者结果高度吻合),通过系统相位裕度γ判断闭环系统稳定性,同时在PI控制器参数给定的情况下讨论负载电阻R的稳定边界,并搭建PSIM仿真电路对不同负载电阻下闭环系统的稳定性进行验证,仿真结果与理论推导结论基本一致。

5 直流Buck变换器闭环控制实验

5.1 KEIL5软件环境安装及创建

Keil 5是一款集成开发环境(IDE),它以其强大的功能和丰富的特性,在嵌入式系统开发领域占据了重要的地位。在本项目中,需要借助该IDE编写主控代码并烧录至STM32芯片中,使其能够在闭环控制系统中正常发挥控制作用。

下载助教在课程群内上传的安装程序压缩包并解压,文件夹内包含如下文件:

图5.1:Keil5 MDK安装程序压缩包解压结果

双击安装程序”MDK524a.EXE”,一路点击”NEXT>>“(注意勾选同意许可证条款与指定软件安装位置)即可完成Keil5软件安装;软件安装完成后会自动运行,关闭后需要重新以管理员身份运行Keil5(右键->以管理员身份运行),随后进入keygen_new2032文件夹,双击运行破解程序”keygen_new2032.exe”,输入Keil5软件内”File->Licence Management…”里的CID并选择ARM,点击”Generate”并将生成的序列号复制到Keil5软件内”File->Licence Management…”下方的LIC一栏,点击”ADD LIC”即可完成破解。

图5.2:Keil5 MDK软件破解流程图5.2:Keil5 MDK软件破解流程

图5.2:Keil5 MDK软件破解流程图5.2:Keil5 MDK软件破解流程

除此之外,针对本项目选用的STM32F103C8T6芯片,还需要安装相关芯片库:双击”支持包”文件夹中的”Keil.STM32F1xx_DFP.2.2.0.pack”文件并点击”NEXT>>“即可完成安装。

完成软件环境的安装后,需要进入Keil5软件,点击上侧菜单栏中”Project->New μVision Project”新建工程,随后会进入到芯片设备的选择环节,选择芯片”STM32F103C8”并点击”OK”,在弹出的Manage Run-Time Environment对话框中再次点击”OK”即可完成工程创建。

图5.3:Keil5中STM32工程创建流程图5.3:Keil5中STM32工程创建流程图5.3:Keil5中STM32工程创建流程图5.3:Keil5中STM32工程创建流程

当然事实上这样建立的工程仍然无法正常使用,还需要引入一系列启动文件与库函数文件等,具体流程在此不详细赘述,可以参考博客:如何在keil中建立一个STM32F10x完整工程。至此Keil5的软件环境安装及工程创建过程已经全部完成,再额外导入一些系统辅助函数文件(如”Delay.c”等),即可在”main.c”文件中进行闭环控制程序的编写了。

5.2 ADC采样及PWM生成原理

ADC(Analog-to-Digital Converter),即模拟到数字转换器,主要用于将连续传输的模拟信号转换为数字信号,便于数字系统(如中央处理器CPU、微控制器MCU等)对传输信息进行快速处理和分析。

图5.4:STM32F103C8T6芯片参考手册中ADC相关模块

采样是指ADC在一定时间间隔内对连续变化的模拟信号进行取样,得到一系列离散的样本点,实现在有限采样率条件下,无失真还原信号波形信息。采样率决定了每秒采集的样本量,通常单位为Hz;其必须满足奈奎斯特采样定理(大于信号最高频率的两倍),否则会产生混叠。

由于数字信号本身不具有实际意义,仅仅表示一个相对大小,故任何一个模数转换器都需要一个参考模拟量作为转换的标准,比较常见的参考标准为最大的可转换信号大小,而输出的数字量则表示输入信号相对于参考信号的大小。在STM32单片机中,ADC为12位,即单片机读取的ADC值应在0~4095范围内,这样的ADC值与0~3.3V的输入电压值之间存在线性对应关系(若输入电压范围超出0~3.3V,则需要在输入ADC引脚前加入电阻分压和放大器等外围电路,在2.3.4小节中有详细介绍该部分采样电路)。

PWM(Pulse Width Modulation),即脉冲宽度调制,是一种通过调节脉冲信号的宽度(即占空比,高电平持续时间占整个周期的比例)来控制输出信号平均值的方法。在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量。简单而言,PWM可以视为一种DA(数字->模拟)转换,通过产生PWM波形这一数字信号等效地实现了模拟信号的输出。

图5.5:PWM信号示意图

PWM实现的原理是:通过锯齿波/三角波(载波)所需要合成的波形(调制波)进行比较,然后确定PWM所需要输出的极性,锯齿波从比较器的反相端端输入,当大于参考电压时输出与锯齿波相反的极性,而当锯齿波从比较器同相端输入,当大于参考电压时输出与锯齿波相同极性。

图5.6:PWM实现流程:黄色线------计算器溢出频率(ARR),即PWM更新频率;红色线------捕获比较寄存器(CRR)的值;蓝色线------计数器(CNT)的值

在Keil工程中,基于以上PWM生成原理编写函数文件”PWM.c”,其中包含了生成PWM波形所需的全部函数。实际运行时,PWM波形是通过定时器的计数和输出比较模块的配合生成的,其具体过程如下:

(1)计数器计数:TIM2定时器按照内部时钟驱动,从0计数到ARR(2999),然后重新清零,重复循环。

(2)比较与输出:定时器每次计数到CCR(1500)时,切换PWM输出的电平状态:从计数开始到计数器值为CCR时,输出高电平;从计数器值为CCR到ARR,输出低电平。

(3)占空比:由CCR与ARR的比值决定。程序中初始设定CCR=1500,ARR=2999,故可计算得出占空比为
$$
\frac{CCR}{ARR + 1} = 50%
$$
同时在主程序的控制过程中还可通过函数PWM_SetCompare1动态设置CCR值,从而实时改变占空比,进而影响输出的等效电压值。

5.3 基本PI控制理论及程序

PI控制器是比例-积分控制器的一种,其核心是通过调节控制变量(输出电压),使系统输出接近目标值,是在控制工程中技术成熟、理论完善、应用最为广泛的一种控制策略。

对于PI控制器而言,其控制量的计算公式为:
$$
u(t) = K_{P} \cdot \mathbb{e}(t) + K_{I}\int\mathbb{e}(t)\mathbb{d}t
$$
其中:

(1)e(t):当前时刻系统输出电压与参考电压之间的误差值;

(2)K_P:比例增益系数,用于快速响应;

(3)K_I:积分增益系数,用于消除稳态误差;

(4)u(t):待控制变量——系统输出电压。

写成微分方程形式则为:
$$
\left{ \begin{aligned}
& \dot{x} = K_{I}v \
& y = K_{p}v + x
\end{aligned} \right.
$$
根据传递函数定义,其传递函数可表示为:

$$
G_{c}(s) = K_{p} + K_{I}\frac{1}{s} = \frac{K_{p}(\tau s + 1)}{\tau s}
$$
其中积分时间常数
$$
\tau = \frac{K_{p}}{K_{I}}
$$
PI控制器具有以下特点:

  1. 从时域上看,只要存在偏差,积分就会不停对偏差积累,因此稳态时误差一定为零;

  2. 比例与积分动作都是对过去控制误差进行操作,不对未来控制误差进行预测,限制了控制性能;

  3. PI调节将比例调节的快速反应与积分调节消除静差的特点结合,主要用于改善控制系统的稳态性能。

图5.7:具有PI控制器的控制系统控制框图

在Keil工程中的主函数文件”main.c”中,其main函数在进行了PWM、ADC与串口等必要的初始化后,在while循环中反复运行update_voltage_reference与control_buck两个函数,其中前者主要是进行参考电压的动态更新,而后者中则包含了PI控制的主要逻辑,部分核心代码如下:

1
2
3
4
error = voltage_ref \* 2500 \* 1000 / 1050 / 20000 - voltage_fb;
integral += error;
control_signal = KP \* error + KI \* integral;
last_error = error;

该段代码主要按照如下流程实现PI控制:

  1. 误差计算:error
    $$
    e(t) = V_{ref} - V_{fb}
    $$

其中V_ref(voltage_ref)为函数update_voltage_reference中设定的目标电压,而V_fb(voltage_fb)为系统输出并反馈至控制器的实际电压。

  1. 积分计算:
    $$
    integral = \int\mathbb{e}(t)\mathbb{d}t
    $$
    为累加误差,用于消除系统的稳态误差(输出电压voltage_fb与参考电压voltage_ref的差值error)。

  2. PI控制量:control_signal
    $$
    u(t) = K_{P} \cdot \mathbb{e}(t) + K_{I}\int\mathbb{e}(t)\mathbb{d}t
    $$
    为最终控制信号,用于调节PWM占空比。

除此之外,为防止占空比超出合理范围,还对控制信号control_signal进行约束:

1
2
3
4
if (control_signal \> 0.8)
control_signal = 0.8;
else if (control_signal \< 0.2)
control_signal = 0.2;

除了PI控制的核心逻辑外,在主控函数control_buck中还实现了其他功能:

  1. 模拟信号采集得到系统输出并反馈至控制器的实际电压V_fb(voltage_fb):
1
2
voltage_fb = (float)AD_GetValue()\*3.3/4096;
trueVoltage = voltage_fb \* 1050 \* 20000 / 2500 / 1000;
  1. 根据PI控制结果,实时更新PWM占空比:
1
2
3
duty_cycle = control_signal \* PWM_PERIOD;
i = (int)duty_cycle;
PWM_SetCompare1(i);
  1. 通过串口发送调试信息,用于监控采样值和控制效果:
1
Serial_Printf(\"%d,%.2f\\r\\n\", sample_index, trueVoltage);

5.4 闭环PI稳压调控输出(8V、10V)

5.3节中对于主控函数control_buck进行了详细的解析,整个闭环PI调控过程都由此函数完成,在此不重复赘述;而对于函数update_voltage_reference而言,该函数实现了电压的切换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void update_voltage_reference(void){
time_counter += 40; // 每次调用增加计时器值
if (time_counter \>= 10000) // 达到10秒{
time_counter = 0; // 重置计时器
if (voltage_state == 0){
voltage_ref = 10.0; // 切换到10V
voltage_state = 1; // 更新状态
}
else{
voltage_ref = 8.0; // 切换到8V
voltage_state = 0; // 更新状态
}
}
}

可以看到,该函数每隔10秒就对于目标电压voltage_ref进行一次切换,由10V切换为8V,再由8V切换回10V,循环往复。该函数主要用于模拟动态负载或参考值变化的情景,以测试控制器再目标电压变化时的响应性能。

事实上,在main函数中,在进行各项初始化(PWM、ADC、串口等)后,while循环中只有参考电压切换函数update_voltage_reference与PI主控函数control_buck反复作用,也正是这两个函数使得该直流Buck变换器闭环控制PI系统能够交替稳压输出8V或10V的电压。

5.5 闭环参考电压8V-10V连续跳变实验与分析(仿真+实验)

在直流Buck变换器闭环PI控制系统参考电压8V-10V连续跳变实验时,重点对于输出电压分别为8V与10V的两种情况下单片机的PWM输出波形进行测试,通过观察其占空比反映其输出电压情况:

  1. 先使用仿真器给单片机供电,以调试PWM波形输出是否正常;

  2. 将上述闭环控制程序放入Keil工程中,成功编译后烧录至单片机内,将单片机(最小系统板)插入电路板上预留的引脚接口处并上电测试,使用示波器或者上位机观测电路板PA8端口输出PWM波形的占空比。

图5.8:参考电压设置为10V时的PWM波形

图5.9:参考电压设置为8V时的PWM波形

可以看到,在参考电压设置为8V时,单片机输出的PWM占空比明显小于参考电压为10V时的结果。

为进一步观察参考电压连续跳变时的动态响应过程,进行了对应的PSIM电路仿真(仿真参数:kp=0.12,τ_i=1/5000,R=2Ω),其中跳变效果通过在直流参考电压后接入一个周期方波信号实现,跳变周期为0.1s:

图5.10:参考电压8V-10V连续跳变PSIM仿真电路图

图5.11:参考电压8V-10V连续跳变PSIM仿真动态响应结果

可以看到,跳变瞬间系统的动态响应较快(约为0.01s)且输出电压稳定后震荡幅度较小,说明该参数下系统具有较好的动态响应性能。

5.6 本章小结

本章主要介绍了对于直流Buck变换器PI闭环控制的整体实验流程,从STM32单片机编程环境的搭建,到根据PWM生成原理编写PWM的初始化函数及占空比实时调控函数,再到根据PI控制的基础理论编写对应的主控代码,在参考电压连续跳变(8V-10V)的情况下调控闭环PI的稳压输出,最后将代码烧录进行实际实验,测试单片机的PWM输出调控情况,并通过仿真观察参考电压连续跳变时的动态响应情况。通过该闭环控制实验,充分证明了PI闭环控制系统对于直流Buck变换器具有良好的控制效果。

6 复合PI控制直流Buck变换器

6.1 PI+超前校正(复合PI)分析设计

为提高PI闭环控制系统暂态响应速度,可以在原有的控制系统中加入一些其参数可以根据需要而改变的控制器,即对于系统进行校正,从而使整个系统的频率特性发生变化。本项目中针对直流Buck变换器的PI闭环控制系统,采用PI+串联超前校正的复合PI控制器,以进一步提升系统性能指标。

图6.1:串联超前校正环节示意图

串联超前校正的核心思想是,将补偿中心ω_ m设计为期望剪切频率ω_ c处,从而提升剪切频率(补偿中心)所对应相位,并利用补偿处增益放大(+20)来改善剪切频率处斜率。具体的设计流程如下:

  1. 根据静态性能指标,确定开环增益K

  2. 为确定校正环节的设计方向,根据所确定的开环增益,画出系统固有部分G_s(s)的波特图,并计算其剪切频率ω_ c1与相位裕度γ_ 0;

  3. 根据要求的相位裕度γ,确定
    $$
    \varphi_{m} = \mathrm{\Delta}\varphi = \gamma - \gamma_{0} + \varepsilon,\varepsilon =5° - 25°
    $$

    $$
    \varphi_{m} < 60{^\circ}
    $$
    说明可采用串联超前校正,即
    $$
    \varepsilon \approx \varphi(\omega_{c1})-
    \varphi(\omega_{c2}),\omega_{c1}为原穿越频率,\omega_{c2}为校正后穿越频率
    $$

  4. 由φ_m确定α:
    $$
    $\alpha = \frac{1 + \sin\varphi_{m}}{1 - \sin\varphi_{m}} > 1
    $$

  5. 令校正后剪切频率
    $$
    \omega_{c2} = \omega_{m} = \frac{1}{T\sqrt{\alpha}}
    $$

  6. 画出校正后系统的波特图,并验算相位裕度是否满足要求:若满足要求,则需要在原有PI控制器前增加环节
    $$
    G_{c}(s) = \frac{\alpha Ts + 1}{Ts + 1}
    $$
    若不满足要求,需增大ε的值,从第(3)步重新开始计算。

图6.2:超前校正环节一般设计流程

对于比例积分PI控制器,一般采用如下的超前校正方式:

图6.3:PI控制器超前校正电路原理图

图6.3:PI控制器超前校正电路原理图

针对直流Buck变换器的PI闭环控制系统,给定PI控制器参数:
$$
K_{p} = 0.8、\tau = 1/5000
$$
负载电阻
$$
R = 2\Omega
$$
与三角载波幅值
$$
V_{M} = 1V
$$
根据3.1节给出的系统开环传递函数(不考虑电容寄生电阻):
$$
T(s) = \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{V_{in}}{LCs^{2} + \frac{L}{R}s + 1}
$$
在MWorks中编写如下代码绘制校正前的波特图:

1
2
3
4
5
6
7
8
9
10
11
using TyControlSystems
s=tf('s');
vm=1;
r=2;
c=10^(-4);
l=10^(-4);
vg=20;
kp=0.8;
tao=1/5000;
G=kp*(tao*s+1)*vg/(tao*s*vm*(l*c*s*s+(l/r)*s+1));
bode(G);

绘制出校正前的波特图:

图6.4:校正前MWorks绘制波特图

从图中可读出:校正前系统的剪切频率
$$
\omega_{c1}≈4.20*10^{4}rad/s
$$
相位裕度
$$
\gamma_{0}≈0{^\circ}
$$
此时系统处于临界稳定状态。

为使得校正后的相位裕度
$$
\gamma > 30{^\circ}
$$
可确定需增加的相位裕度
$$
\varphi_{m} = \mathrm{\Delta}\varphi = \gamma - \gamma_{0} + \varepsilon = 30{^\circ} - 0{^\circ} + 15.5{^\circ} = 45.5{^\circ} < 60{^\circ}
$$
满足超前校正要求,进而可以确定

$$
\alpha = \frac{1 + \sin\varphi_{m}}{1 - \sin\varphi_{m}} \approx 6
$$
又因为系统周期
$$
T = \frac{1}{70000}s
$$
从而可以确定增加的超前校正环节的开环传递函数为:

$$
H(s) = \frac{\frac{6}{70000}s + 1}{\frac{1}{70000}s + 1}
$$
这意味着校正后整个闭环控制系统的传递函数变为
$$
T^{‘}(s) = T(s)H(s)
$$
可在上述MWorks代码的基础上增加下列代码以实现对于校正后闭环控制系统波特图的绘制:

1
2
3
H=(6*s/70000+1)/(s/70000+1);
G1=G*H;
bode(G1);

绘制出校正后的波特图:

图6.5:校正后MWorks绘制波特图

从图中可读出:校正后系统的剪切频率
$$
\omega_{c2}≈8.71*10^{4}rad/s
$$
相位裕度
$$
\gamma≈31{^\circ} > 30{^\circ}
$$
相位裕度较校正前有明显提升且满足系统对品质指标的要求,校正正确。

6.2 复合PI控制PSIM仿真(校正前后参考电压变化时输出电压分析)

首先通过PSIM扫频仿真对先前波特图的MWorks绘制结果进行验证:

图6.6:超前校正控制PSIM扫频仿真电路图

图6.7:校正前PSIM扫频仿真结果

图6.8:校正后PSIM扫频仿真结果

从图中可读出:校正前系统的剪切频率
$$
\omega_{c1}≈6554Hz
$$
相位裕度
$$
\gamma_{0}≈0{^\circ}
$$
校正后系统的剪切频率
$$
\omega_{c2}≈14126Hz
$$
相位裕度
$$
\gamma≈35{^\circ}
$$
与MWorks绘制的波特图结果基本一致。

为反映超前校正的引入对于系统暂态响应速度的提升效果,搭建PSIM仿真电路,分析校正前后参考电压跳变瞬间的输出电压响应情况:

图6.9:超前校正控制参考跳变PSIM仿真电路图

图6.10:校正前系统暂态响应PSIM仿真结果

图6.11:校正后系统暂态响应PSIM仿真结果

对比校正前后参考电压跳变瞬间的输出电压暂态响应PSIM仿真结果,可以发现:校正前系统暂态响应时间约为0.034s,而加入超前校正环节后系统暂态响应时间为0.0006s,较校正前有显著缩短,说明超前校正的引入有效提升了系统的动态响应特性(快速性)。

6.3 PI+微分环节D(PID)分析设计

除增加串联超前校正环节设计外,还可以通过在原有PI控制器基础上加入微分环节D实现PID闭环控制来提升系统的稳定性与暂态响应速度。事实上,在PID控制器的三个环节中,比例环节P主要负责动态性能的提升,积分环节I主要负责稳态精度的提升,而引入微分环节D则可进一步改善系统的稳定裕度以提升系统稳定性。

图6.12:PID控制器电路原理图

与PI控制器类似,通过对PID控制器的微分方程组进行拉普拉斯变换,可以得到其传递函数为:
$$
G_{c}(s) = \frac{K_{p}(\tau_{i}s + 1)}{\tau_{i}s} + \tau_{d}s
$$
其中τ_ i为积分时间常数,而τ_ d为微分时间常数。

接下来将通过MWorks绘制波特图,配合PSIM的扫频仿真结果,从相位裕度的角度来反映微分环节D的引入对于系统稳定性的提升:

对于PI控制器,给定控制器参数:
$$
K_{p} = 0.12、\tau = 1/5000
$$
负载电阻
$$
R = 2\Omega
$$
与三角载波幅值
$$
V_{M} = 1V
$$
根据3.1节给出的系统开环传递函数(不考虑电容寄生电阻):
$$
T(s) = \frac{K_{p}(\tau s + 1)}{\tau s}\frac{1}{V_{M}}\frac{V_{in}}{LCs^{2} + \frac{L}{R}s + 1}$
$$
在MWorks中编写如下代码绘制波特图:

1
2
3
4
5
6
7
8
9
10
11
12
using TyControlSystems
s=tf('s');
vm=1;
r=2;
esr=0.107185;
c=6.6*10^(-4);
l=10^(-4);
vg=15;
kp=0.12;
tao=1/5000;
G=kp*(tao*s+1)\*(esr*c*s+1)*vg/(tao*s*vm*(l*c*(1+esr/r)*s*s+(l/r+esr*c)*s+1));
bode(G);

图6.13:PI控制器MWorks绘制波特图

同时在PSIM中搭建扫频仿真电路,通过扫频仿真结果验证MWorks绘制波特图的正确性:

图6.14:PI控制器PSIM扫频仿真电路图

图6.15:PI控制器PSIM扫频仿真结果

从图中可读出:PI闭环控制系统剪切频率
$$
\omega_{c}≈6.78*10^{3}rad/s \approx 1105Hz
$$
相位裕度
$$
\gamma$≈$10{^\circ}
$$
且MWorks绘制波特图与PSIM扫频仿真结果基本一致。

对于加入微分环节D后的PID控制器,给定控制器参数:
$$
K_{p} = 0.12、\tau_{i} = 1/5000、\tau_{d} = 0.00001
$$
负载电阻
$$
R = 2\Omega
$$
与三角载波幅值
$$
V_{M} = 1V
$$
根据3.1节给出的系统开环传递函数(不考虑电容寄生电阻)并将其中PI控制器的传递函数替换为PID控制器的传递函数,可得到PID闭环控制系统的开环传递函数:
$$
T(s) = (\frac{K_{p}(\tau_{i}s + 1)}{\tau_{i}s} + \tau_{d}s)\frac{1}{V_{M}}\frac{V_{in}}{LCs^{2} + \frac{L}{R}s + 1}
$$
在MWorks中编写如下代码绘制波特图:

1
2
3
4
5
6
7
8
9
10
11
12
13
using TyControlSystems
s=tf('s');
vm=1;
r=2;
esr=0.107185;
c=6.6*10^(-4);
l=10^(-4);
vg=15;
kp=0.12;
tao=1/5000;
taod=0.00001;
G=(kp*(tao*s+1)+taod*tao*s*s)*(esr*c*s+1)*vg/(tao*s*vm*(l*c*(1+esr/r)*s*s+(l/r+esr*c)*s+1));
bode(G);

图6.16:PID控制器MWorks绘制波特图

同时在PSIM中搭建扫频仿真电路,通过扫频仿真结果验证MWorks绘制波特图的正确性:

图6.17:PID控制器PSIM扫频仿真电路图

图6.18:PID控制器PSIM扫频仿真结果

从图中可读出:PID闭环控制系统剪切频率
$$
\omega_{c}≈6.78*10^{3}rad/s \approx 1026Hz
$$
相位裕度
$$
\gamma≈36{^\circ}
$$
且MWorks绘制波特图与PSIM扫频仿真结果基本一致。

通过对比PI和PID控制下的波特图与扫频结果可以发现,相比于PI控制器,PID控制下的直流Buck变换器闭环系统具有更高的相位裕度,这意味着在加入微分环节D之后,系统具有更好的稳定性。

6.4 PID控制PSIM仿真(校正前后R变化时输出电压分析)

为反映微分环节D的引入对于系统稳定性与响应速度的提升效果,搭建PSIM仿真电路,分析PI与PID控制器在负载电阻R不同时输出电压响应情况:

图6.19:PI控制器动态响应PSIM仿真电路图

图6.20:PI控制器负载电阻R=2Ω时动态响应PSIM仿真结果

图6.21:PI控制器负载电阻R=5Ω时动态响应PSIM仿真结果

图6.22:PID控制器动态响应PSIM仿真电路图

图6.23:PID控制器负载电阻R=2Ω时动态响应PSIM仿真结果

图6.24:PID控制器负载电阻R=5Ω时动态响应PSIM仿真结果

对比PI与PID控制器在负载电阻R不同时的输出电压暂态响应PSIM仿真结果,可以发现:当负载电阻R=2Ω时,在原有的PI控制器闭环控制下,系统的暂态响应时间约为0.008s,而加入微分环节D后,系统在PID控制器的闭环控制下暂态响应时间为0.004s,这意味着在加入微分环节D后,系统的动态响应特性得到一定提升(响应时间缩短50%);除此之外,在相同的控制器作用下,随着负载电阻阻值由2Ω增大到5Ω,系统的输出电压在稳定后的振荡幅度明显减,但此时暂态响应时间也明显增加(增加近两倍)。

6.5 本章小结

本章主要介绍了基于PI控制器的校正设计,对于直流Buck变换器的闭环控制而言,分别采用在原有控制系统上增加超前校正环节与微分环节D的两种校正方式实现复合PI控制,通过MWorks绘制波特图与PSIM扫频仿真,反映校正环节的引入对于相位裕度即系统稳定性的提升效果,并结合PSIM电路仿真的输出电压结果,观察校正环节的引入对于系统暂态响应速度即动态响应特性的提升效果。仿真实验结果表明,对于PI控制器的校正设计(超前校正/引入微分环节形成PID控制)在提升系统稳定性与动态响应快速性方面取得了良好的效果。

7 基于直流电源调控的自动调光控制设计

该系统的主要功能是将灯的电压通过直流Buck变换器完成闭环PID控制,将输出电压控制在0-15V范围内。系统主要包含电量控制与亮度控制两个部分,其中电量控制由STM32数字控制器通过电压控制信号调节Buck变换器输出电压;亮度控制则通过光敏传感器感知外界光强,并将反馈信号传递给STM32,实现对LED灯源亮度的动态调整,从而形成电压与亮度的双闭环调节系统。

图7.1:基于直流电源调控的自动调光系统整体架构

基于该架构,系统设计的基本流程如下:

  1. 搭建Buck电路控制系统,用于调控LED灯源;

  2. 使用开发工具Keil5编写STM32控制程序,实现PWM信号生成和调节;

  3. 将光敏传感器的输出连接到STM32的ADC(模数转换器)端口;

  4. 设计闭环控制系统并编写主控程序,实现根据光照强度自动调节PWM占空比,从而控制LED灯光的亮度;

  5. 调试系统,过程中实时监测电路工作状态,确保电路安全稳定运行且光照强度变化时LED灯亮度能够迅速进行响应调整;

  6. 对系统功能进行测试与优化,验证系统的响应速度和调光精度。

图7.2:基于直流电源调控的自动调光系统设计流程

除此之外,在系统基本功能的设计实现基础上,还进行了基于无线通信的远程控制这一拓展功能设计,将调光系统与蓝牙无线通信模块结合,实现通过手机应用对LED灯进行调光控制,增加系统的便携性和灵活性。

接下来将分模块具体阐述自动调光控制系统各功能设计的详细过程。

7.1 默认电压值设置

在系统上电之后,输出电压默认设置为9V。之所以选择9V作为默认值,是因为这一电压能够在不消耗过多能量的情况下提供足够的亮度,同时避免由于过高或过低电压对系统性能的影响。

具体来说,9V的默认值具有以下几个优点:

(1)能耗平衡:相较于较低电压(5V),9V能够提供更高的亮度输出,同时不会像满电压(15V)那样带来显著的能量消耗,适合作为常规环境下的起始亮度。

(2)避免电压冲击:在系统刚启动时,设定较高的默认电压可能会导致电流冲击,影响电源和负载的寿命。9V作为中间值,有效降低了这种风险。

(3)用户体验优化:默认电压为9V时,灯光亮度适中,避免了开机过亮或过暗对用户造成的不适,同时为后续手动或自动调节提供了便利。

(4)环境适应性:在普通家庭或办公室环境下,9V的亮度通常能满足基本照明需求,而无需立即调整,增强了系统的即用性。

此外,9V的默认值通过主程序固化设置,确保每次系统启动时都能快速恢复到该默认电压值。这一设置不仅提高了系统的稳定性,还为后续用户操作提供了可靠的初始状态。设计中对默认电压的选择经过多次实验验证,综合考虑了实际照明需求和电源性能,最终确定了这一合理数值。

7.2 蓝牙接口通信控制

在本系统中,蓝牙模块被用作与手机或其他移动设备的通信桥梁,用户可通过蓝牙实现对灯光的远程控制,增强系统的操作便利性和用户体验。蓝牙模块选用低功耗蓝牙(Bluetooth Low Energy, BLE)技术,保证了通信的可靠性和功耗优化。具体而言,蓝牙通信具有以下优点:

  • 便捷性:用户可通过手机远程调节灯光,无需物理接触,尤其适合家庭场景。

  • 可扩展性:蓝牙接口支持更多功能指令的扩展,如灯光模式切换等。

  • 低成本实现:蓝牙模块硬件成本低,结合STM32可轻松实现稳定通信。

以下是蓝牙接口通信功能的详细设计:

  1. 硬件接口设计
  • 蓝牙模块选型:选用HC-05蓝牙模块,该模块具有支持串行通信(UART)功能,能与STM32单片机直接连接;模块通过UART接口与STM32的USART1通道连接,波特率设置为9600bps以平衡数据传输速率与稳定性。

  • 引脚连接:蓝牙模块的TX和RX引脚分别连接STM32的RX和TX引脚,模块的VCC和GND引脚分别接单片机供电端和地线,保证模块稳定供电。

  1. 软件功能设计

蓝牙通信通过STM32主程序实现对蓝牙模块接收指令的解析和响应。指令的解析流程大致是这样的:主程序中设定一个蓝牙接收缓冲区,用于存储用户发送的指令;当蓝牙模块接收到数据时,触发中断,将数据写入缓冲区;程序定时轮询缓冲区,并根据指令类型解析执行以下指令以实现功能,包括灯的开关、亮度百分比调整,以及环境光自动调节的触发:

  • “on”/“off”指令:通过电压直接跳转的方式实现即时开关

“on”:将输出电压设定为最大值15V,点亮灯光;

“off”:将输出电压设定为最小值0V,关闭灯光。

  • 亮度调整指令:接收一个0-100的整数,表示灯光亮度为15V的百分比。程序计算目标电压时依据公式:
    $$
    V_{target} = \frac{百分比指令}{100} \times 15
    $$
    调用PWM控制函数调整Buck变换器的输出电压至目标值,实现实时亮度调节。

  • “LL”指令:触发光敏传感器,启动环境光度自动调节模式(详见7.3节)。

  1. 通信协议设计

蓝牙通信基于简单的ASCII协议,用户可通过手机APP或终端工具发送指令。每条指令均以换行符\n结尾,便于解析。以下是通信协议的具体格式:

  • “on\n”:开启灯光。

  • “off\n”:关闭灯光。

  • “50\n”:将亮度设置为50%。

  • “LL\n”:启动环境光度自动调节模式。

通过蓝牙接口通信,系统不仅支持手动调节灯光,还为后续的智能化功能扩展奠定了基础。

7.3 基于光敏传感器的调光功能

本系统采用光敏传感器对环境光强进行实时检测,并基于检测值动态调整灯光的亮度,提供适应不同场景的自动调光功能。通过光敏传感器实现调光,既可以减少用户手动调整灯光的频率,还可以自动优化输出电压,适用多种场景需求。通过闭环控制机制,确保灯光的输出电压与环境光强度的变化相匹配,为用户提供更舒适、高效的照明体验。以下为光敏传感器调光功能的详细设计与实现过程:

  1. 硬件接口设计
  • 光敏传感器选型:选用光敏电阻模块,输出光强的模拟信号值。传感器将环境光强信号转换为电压信号,供STM32单片机的ADC模块读取。

  • 传感器连接方式:光敏传感器的模拟输出端(AO口)连接到STM32单片机的PA5引脚,PA5被配置为ADC输入通道。供电引脚(VCC)连接单片机的3.3V供电,地线(GND)连接系统地,保证传感器的稳定工作。

  1. 软件功能设计
  • 数据采集与转换:STM32通过ADC模块以一定采样频率读取光敏传感器的模拟信号,模拟值范围为0到4095,对应电压范围为0到3.3V;可通过公式
    $$
    V_{target} = \frac{ADC值}{4095} \times 15
    $$
    将光强模拟值映射为输出电压目标值,该线性映射关系保证了灯光亮度的平滑过渡,避免突然变化对用户产生视觉不适。

  • 调光逻辑与策略:当ADC值低于预设阈值(如1024)时,认为环境光较暗,此时系统逐步增加输出电压,以提高灯光亮度补偿环境光;当ADC值高于预设阈值(如3072)时,认为环境光较亮,此时系统逐步降低输出电压,以避免浪费电能或造成视觉不适;当光强处于中等范围时(ADC值1024到3072),输出电压以线性比例动态调节,保持环境与灯光亮度的适应性平衡。

  • PID闭环控制:根据光敏电阻值计算目标电压,并作为参考值输入PID控制器;PID控制器实时计算实际输出电压与目标电压之间的误差,并调整PWM信号占空比控制Buck变换器,确保输出电压快速稳定地收敛到目标值。

  • 状态反馈与异常处理:当光敏传感器信号异常(如ADC值恒定不变或超出有效范围)时,系统进入保护模式,将输出电压设定为安全值9V,并通过蓝牙模块通知用户;传感器数据每次读取后均存储在缓冲区中,并定期更新,避免因单次采样噪声造成调光不稳定。

为进一步验证调光功能的灵敏度,需要测试光敏传感器在不同光强条件下的响应时间和精度,确保其采集的光强信号与实际环境光强相符。经过调试,光敏电阻灵敏度较高,但光敏电阻的朝向会对空间中同一点的光敏传感有不同的值。解决方式为固定光敏电阻朝向位置,使其主要接收来自上方的环境光。除此之外,还需要验证在自动调光模式下,灯光亮度调整是否与环境光变化相匹配。经过我们的实验,该灯泡在8V电压以下不会发光,且为了保护电路和用户,我们将最高输出电压15V通过程序限制在12V,于是我们将光亮百分比线性映射公式修改为:
$$
V_{target} = \frac{百分比指令}{100} \times 4 + 8
$$
从而使得亮度百分比更符合实际;由于百分比电压现在被限制在8-12V,光敏需要更多的外边界,从原先0-15V电压的计算,改为5-15V电压的线性映射,光敏电阻映射公式也需要对应修改为:
$$
V_{target} = \frac{ADC值}{4095} \times 10 + 5
$$
此时由于光敏电阻在一般的环境光下位于1024-3072而并不会趋于极端值,且程序有保护设计,故一定可以限制输出电压在8-12V范围内。

为进一步优化用户的使用体验,还开展了用户测试实验为产品优化提供参考。实验记录了光敏传感器自动调光时用户的视觉体验,并通过调整PID参数和映射公式提高舒适性。通过光敏传感器的引入,本系统实现了基于环境光强的自动调光功能,显著提升了灯光控制的智能化水平与用户体验。

7.4 闭环PID控制原理

闭环PID控制是本系统的核心功能之一,负责根据目标输出电压值和实际输出电压值的误差,动态调节PWM信号,从而控制Buck变换器的输出电压,实现稳定、精准的调光效果。通过PID控制算法,可以使Buck变换器的输出电压始终接近目标值,无论输入电压波动、负载变化,还是环境光强条件改变,都能够保持系统的高稳定性和快速响应性。

PID控制算法主要由三部分组成:比例(P)、积分(I)、微分(D),可通过公式
$$
u(t) = K_{p}e(t) + K_{i}\int_{0}^{t}{e(\tau)d\tau} + K_{d}\frac{de(t)}{dt}
$$
计算其控制输出,其中u(t)为控制信号(用于调节PWM占空比);e(t)为当前误差值,定义为目标值与实际值之差,即
$$
e(t) = V_{target} - V_{actual}
$$
K_p,K_i,K_d分别为比例、积分、微分的调节系数,分别控制系统的响应速度、稳态误差消除能力和动态性能。

通过调节K_p,K_i,K_d三个参数,可以调整控制器的性能,从而实现系统响应特性的优化,提升系统控制效果。具体而言,三个参数对于响应输出的影响如下:

  • 比例(P)参数K_p:比例项主要控制误差对输出的直接影响,增大K_p会使系统响应更迅速,但过大可能引起震荡。本系统初始设置
    $$
    K_{p} = 0.1
    $$
    通过实验验证实现了较平滑的响应。

  • 积分(I)参数K_i:积分项通过累积误差消除稳态误差,确保输出精度。由于积分过大会导致超调或积分饱和,本系统设置
    $$
    K_{i} = 0.01
    $$

  • 微分(D)参数K_d:微分项对误差变化率进行调节,用于改善动态性能并抑制震荡。为避免过分灵敏的微分效应引入噪声,D参数设置为较小值
    $$
    K_{d} = 0.01
    $$

在本项目的自动调光系统中,PID控制器的控制流程主要分为如下几个步骤:

  1. 误差计算:STM32单片机实时采集目标电压值 V_target 和实际输出电压值 V_actual,计算误差:
    $$
    e(t) = V_{target} - V_{actual}
    $$

  2. 控制信号计算:根据误差值,通过PID公式计算控制信号u(t),调整PWM信号的占空比:
    $$
    u(t) = K_{p}e(t) + K_{i}\sum_{k = 0}^{t}{e(k)\mathrm{\Delta}t} + K_{d}\frac{e(t) - e(t - 1)}{\mathrm{\Delta}t}
    $$
    其中Δt为控制周期;∑e(k)Δt为误差累积值;(e(t)-e(t-1))/Δt为误差变化率。

  3. PWM调节:将计算得到的u(t)映射为PWM信号的占空比,直接控制Buck变换器的输出电压。占空比范围为10%至80%,对应输出电压范围为0V至15V。

  4. 反馈调整:系统持续监测实际输出电压,更新误差值并重复上述步骤,形成闭环控制。

在基于STM32单片机编写程序具体实现PID控制器算法时,还需要特别注意以下两点:

  • 采样频率:ADC采样频率需要设置为与main函数主循环频率同步,以保证控制系统对输入误差的快速响应。同时PID计算周期也应同步于ADC采样,以避免数据滞后影响调节效果。

  • 保护机制:若误差值持续过大(如超出安全范围),系统触发保护模式,因此实际实现时将PWM占空比最小设为10%,最大设为80%。

在实际调试验证时,主要对于控制系统的动态性能与抗干扰能力进行了测试与优化,以进一步提升自动调光功能的灵敏性与稳定性,从而优化用户体验:

  • 动态性能测试:在快速切换目标电压值时,观察系统的响应时间和稳定性,确保输出电压能够迅速收敛到目标值。在负载变化的情况下,验证系统能否保持输出电压的稳定。

  • 抗干扰能力测试:模拟输入电压波动和环境光强突变,测试系统的鲁棒性和PID调节效果。

最终经过多次调试与不断优化,该闭环PID控制系统实现了以下目标:

  • 高精度输出:在误差范围内快速稳定输出目标电压。

  • 快速响应:对目标值或负载变化的响应时间快,满足实际调光需求。

  • 稳定性强:在输入波动、负载变化和环境干扰下,系统保持良好的稳定性。

7.5 外观设计制作

为了使本系统不仅具有实用性,还能满足美观性和设计感的需求,我们对外观部分进行了重新设计和制作。本节详细介绍了外观设计的灵感来源、制作过程以及技术实现中的注意事项。

本系统的外观设计灵感来源于游戏《无畏契约》(Valorant)中的角色”尚博勒”(Chamber)的道具”摄像头”。这一设计概念契合科技感与现代感的视觉效果,适合科技爱好者的审美需求,同时其独特的造型也为灯具的装饰性增色。我们力求将其视觉元素融入本项目,打造一款既具功能性又有极高辨识度的灯具设备。同时在外壳设计时也结合了灯泡的散热需求,保证了灯具长时间工作时的安全性和稳定性。设计中注重可拆卸性,用户可以方便地调整灯泡朝向和光照亮度。

图7.3:产品外观设计原型

详细的制作过程如下:

  1. 原型拆解

我们首先将旧灯具的灯罩部分锯下来,仅保留其内部核心组件,包括灯泡、散热装置、电路板和连接线。为确保灯具正常运行,对保留的灯泡和电路板进行功能检测,确认其性能稳定,并清理了原型中多余的固定结构,为后续的外壳重新设计预留空间。

图7.4:灯具原型拆解部分过程图7.4:灯具原型拆解部分过程

  1. 3D建模与设计

使用Fusion 360软件,根据”尚博勒摄像头”的设计特点,建模了一个以球体和多面体造型的外壳结构。模拟摄像头的结构,在灯具上设计了圆形凹陷部分,提升灯具的科技感。外壳设计了散热格栅,与灯具散热需求相结合;外壳底部设计了支撑脚架,便于放置和移动。摄像头部分设计轨道凹槽,可旋转控制摄像头方向。

图7.5:产品外形3D建模效果图

  1. 材料选择与加工

外壳部分采用轻质耐用的 PLA 材料,利用3D打印技术制作。打印分为两个部分:上半部分为灯具主壳,下半部分为安装支架,组装后固定。3D打印完成后,外壳表面进行手工打磨并喷涂金色亚光涂料,灯罩边缘则涂上金属漆,营造高科技感。

  1. 组件安装与调试

将灯泡、电路板、散热器嵌入3D打印外壳中,通过卡扣、限位固定,确保结构稳固。为避免外壳对散热产生影响,在装配后对设备进行长时间运行测试,确保温度稳定在安全范围内。重新调整灯光的投射方向和亮度,使其与设计的外壳结构匹配,确保在不同环境下具备良好的照明效果。

图7.6:最终产品样机实物图

为进一步提升用户体验,后续将持续对产品进行深度优化,包括添加更多灯光模式(如动态光效或多色渐变)以进一步增强装饰性和互动性,或引入语音控制功能并将其与蓝牙通信相结合以提升智能化体验。

7.6 本章小结

本章介绍了基于直流电源调控的自动调光控制设计,通过蓝牙模块完成手动输出电压控制,通过光敏传感器进行环境光度自动调节,最终通过Buck变换器闭环PID控制完成灯的电压和光亮度稳定。

8 基于直流电源调控的光伏MPPT控制设计

8.1 设计背景与系统架构

光伏发电是当前清洁能源的主流之一,最大功率点跟踪(Maximum Power Point Tracking, MPPT)是光伏系统中提高效率的关键技术。由于光伏板的输出功率受到光照强度影响,不同的光照强度下最大功率点对应的输出电压不同,需要不断通过改变输出电压来寻找最大功率点(MPP)。因此,希望通过搭建一个基于直流电源调控的光伏MPPT控制系统,结合STM32单片机和Buck变换器实现光伏阵列的最大功率点跟踪,从而使得系统维持在最大功率工作,减少不必要的能量损失,有效储存其他能量转化成的电能。

图8.1:光伏发电板

在该系统中,外界光照被太阳能电池板转化为电能,经功率变换电路处理后向负载供电。STM32微控制器实时采集电池板电压、电流等参数,运行MPPT算法,生成控制信号优化功率变换电路的工作状态,确保太阳能电池板始终在最大功率点运行,提高能源利用效率。

图8.2:基于直流电源调控的光伏MPPT控制系统整体架构

8.2 实验原理

光伏板的输出功率会受到环境条件(如光照、温度)影响,这一点无法改变,但是输出功率同时也受到工作电流、电压的因素影响,因此可以通过调节负载电压,使光伏系统的功率维持在最大值,即工作在最大功率点(实现输入侧阻抗匹配)。在本课程使用的Buck变换器中,可以根据STM32输出PWM波的占空比来控制输出的电压,同时由于电路中在不断采集输出电压,从而可以通过设计相应的控制算法算法实现对于输出电压的精确闭环控制。

为了找到最大功率点,可采用扰动观察法(Perturb and Observe, P&O)算法。通过降低与增加占空比来调节输出电压,由于电阻一定,可以通过计算算出变化后的功率,同时将其与变化前的功率进行比较,若功率增大,则沿当前方向继续调整占空比;否则反向调整。在每次调整占空比后,计算功率并记录趋势,从而找到最大功率点。在本项目中,采用改进的扰动观察法,通过记录功率变化并自动调整占空比,从而快速收敛到最大功率点。

图8.3:不同光照强度对光伏板的P -V曲线

8.3 代码逻辑

在Keil5中编写的STM32主控代码主要分为如下4个主要的功能模块:

  1. 系统初始化:初始化系统时钟与ADC、PWM模块,为数据采集及控制做好准备。
1
2
3
4
SystemInit(); // 初始化系统时钟
PWM_Init(); // 初始化PWM模块
AD_Init(); // 初始化ADC模块
_enable_irq(); // 开启全局中断
  1. PWM控制模块:通过实时调控PWM输出占空比实现Buck变换器输出电压的改变,从而影响光伏阵列的工作点。值得注意的是,需要调整PWM输出频率与Buck变换器相适应,同时确保输出占空比范围在0~1范围内。
1
2
3
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 配置为PWM模式1
TIM_OCInitStructure.TIM_Pulse = 0; // 设置初始占空比为0
TIM_SetCompare1(TIM2, (uint16_t)(dutyCycle * PWM_PERIOD)); // 调整PWM占空比
  1. ADC采样模块:将光伏阵列输出的电压信号通过ADC采样转换为数字信号并读取,再通过与电阻的计算得出电流值,以用于功率计算。值得注意的是,ADC通道需与光伏阵列信号对应,同时为确保采样精度还需事先对ADC模块进行校准。

图8.4:ADC采样模块相关函数代码

  1. MPPT算法实现:根据扰动观察法原理,通过电流与电压相乘得到当前输出功率,与上个点的功率相比较,若大于上个点的功率,则继续增大占空比,增加输出电压,从而增加输出功率,若小于,则减小占空比,并在每次调整占空比后再次计算输出功率。循环往复进行上述流程,同时记录功率变化趋势及对应占空比,以寻找最大功率点。值得注意的是,程序中设置的步长STEP_SIZE值应适中,过大会导致振荡,而过小则会影响跟踪的速度,同时还应避免控制过程中PWM波形的占空比超出0~1范围。

图8.5:MPPT算法实现相关函数代码

在主循环main函数中编写总控代码对上述代码逻辑进行整合,每次循环都会测量电压与电流从而得到功率,再通过进行扰动观察法寻找最大功率点。

图8.6:main函数总控代码

8.4 实验现象

实验时,将Buck变换器、STM32开发板与光伏阵列进行连接,并确保采样与控制电路正常工作。将代码烧录到STM32开发板,并通过调整光照强度,观察功率点变化及最大功率点跟踪效果。接下来需要进行逐步调试:

  1. 使用示波器观察PWM信号及Buck变换器输出电压,验证占空比调节是否正常,并使用万用表验证电压、电流采样值是否准确;

图8.7:PWM输出占空比调试结果

图8.8:Buck变换器输出电压调试结果

可以看到,此时PWM输出占空比为50%,占空比调节正常;光伏板输出电压为5.1V,电流为0.025A,输入功率约为0.1275W。

  1. 通过调整光照强度,观察功率点变化及最大功率点跟踪效果。

图8.9:负载电压图

图8.10:负载消耗功率图

可以看到,此时所接负载为200Ω,输出电压为4.5V,输出功率约为0.12W。考虑功率损耗,光伏板输出功率约等于负载消耗功率,完成了对该光照强度下最大功率点(MPP)的准确寻找。

随后又对于该控制系统的动态跟踪性能进行进一步的测试,可以观察到,当外界环境的光照强度改变时,控制系统能快速做出响应并使光伏板输出功率达到最大(约为负载消耗功率),说明控制系统对于最大功率点的实时跟踪性能良好。

8.5 本章小结

本章主要介绍了基于直流电源调控的光伏板最大功率点追踪(MPPT)控制系统的设计,设计时主要采用递归算法,每次通过扰动当前功将率与变换前功率作比较,若大,则继续增加占空比,若小,则减少占空比,以此类推,不断循环,从而找到最大功率点。每次变化占空比的步长与延时时间影响找到最大功率点的效率,需要调试找到最佳的相应效率。同时,在步长固定的情况下,通过自适应步长控制算法也可以更有效率的寻找最大功率。通过动态追踪,显著提高了光伏发电效率。

9 总结与展望

9.1 课程小结

《自动控制原理》课程作为一门项目制课程,重点围绕经典控制相关理论知识及应用实践,有效地将理论教学与设计实践结合起来。通过课程的理论学习与项目实践,我们在实践操作中对于经典控制理论的知识有了更加深刻的理解,建立了”控制”工程观与系统性分析思维,也锻炼了自己将理论应用于工程实践的能力,以及对于控制工程问题的分析与解决能力。

该项目制课程主要分为两个项目板块:

控制基础实践项目为”直流电源控制分析与系统设计”,以直流电源这一经典工程案例串联起经典控制理论知识各版块,涵盖控制系统建模(微分方程与传递函数)、时域分析、根轨迹分析、频域分析,频域校正与PID控制等,从理论分析、仿真、实验三维度强化同一理论知识点的学习,完成直流电源控制系统的分析设计以及调试。这一部分项目在理论课程学习的同时穿插完成,主要涉及到经典控制理论的学习,并将其应用到实际的Buck变换器PI闭环控制系统中、结合实际电路参数完成的PSIM电路仿真与相应的MWorks分析计算。

综合应用实践项目为”基于电源的综合应用系统”,以直流电源驱动系统应用为综合实践项目,运用传感、闭环控制、先进控制等硬件与算法,完成基于直流电源控制的LED自动调光与光伏最大功率跟踪(MPPT)等项目实践。这一部分项目主要以实验方式开展,最终本小组顺利完成实验与设计内容并进行课程项目汇报。

图9.1:小组答辩风采展示

回顾这门课程一路走来,从课程引入与理论教学,到实际实验调试与项目设计,再到最终的项目测试与汇报,我们在理论与实践的结合中扎实掌握了经典控制理论的相关知识,并锻炼了自己的电路设计分析与实践能力。我们能取得如此的进步与成就离不开两位老师与四位助教的辛勤付出,在此再次向各位老师与助教们送上最真诚的感谢,也衷心祝愿这门课程在未来能建设得越来越好。

图9.2:课程汇报班级合影留念

9.2 课程收获及建议

通过《自动控制原理》这门课程的学习,我了解到了许多经典控制理论的相关知识:从系统的数学建模入手,微分方程与传递函数是描述一个控制系统性能的基本工具;为调整系统参数以提高控制系统的稳定性,可从时域与频域两个角度分别进行分析,时域上可以使用劳斯判据进行系统稳定性的判定并根据根轨迹找到系统的临界稳定状态,频域上可以使用奈奎斯特稳定判据或依据Bode图对系统稳定性进行分析;基于频率特性,还可以从频域校正环节的设计层面调节系统的动态响应特性。理论学习之余,课程紧密穿插了相应的仿真与电路调试实验,理论与实践的结合使得我对于这些枯燥的理论知识有了更加生动而深刻的理解。

在课程项目中,我主要负责对于闭环控制系统的理论分析、仿真验证与参数调试,以及课程项目报告绝大部分的撰写。令我印象最深刻的是,在理论部分对系统进行频率特性分析时,使用MWorks根据系统开环传递函数绘制Bode图,得到了穿越频率与相位裕度;而在根据实际电路结构在PSIM中搭建了相应的扫频电路之后,当看到运行扫频仿真得到的结果与MWorks绘制的Bode图几乎完全一致时,我深刻体会到了理论的有效性,这代表理论的分析确实可以真实地指导实际控制系统的设计,在后续项目设计与调试时也充分利用了这一点,有效提高了设计与调试的效率。最终我们也顺利完成了基于直流电源调控的自动调光与MPPT控制系统的设计与实现,并将自动调光系统实例化为一个具有实际应用意义的产品。相信在这门课程中学到的知识与技能能够为我们未来的硬件产品开发中起到重要的作用。

最后感谢两位老师耐心的教学与指导以及四位助教的辛苦付出,特别是几位助教,耐心地回答我们的问题、批改我们的作业并协助我们进行硬件实物的调试,为我们的项目实践提供了丰富的参考资料,帮助我们快速上手项目。在此提出一点小小的建议,这次项目中在电路焊接方面浪费了许多时间,希望未来的课程项目设计能够在各个实现细节上更加完善,在设计与测试时考虑的更加全面;同时希望在理论课程中穿插的各种仿真作业能够与实际的控制系统结合的更加紧密,完善一些逻辑不严谨的地方(如提供的报告框架中,是否考虑电容寄生电阻这点体现的略显混乱)。但总的来说,这门课程确实是已有项目制课程中的精品,也希望能够在未来建设得越来越好。

参考文献

[1] 胡寿松主编.自动控制原理[M].科学出版社,2019:a670.

[2] 卢京潮主编.自动控制原理习题解答[M].清华大学出版社,2013:195.

[3] 王天威编著.控制之美[M].清华大学出版社,2022.

[4] 李昆.智能技术在室内LED照明系统中的应用研究[J].光源与照明,2024,(10):51-53.

[5] 郑盛梅.恒照度自动调光台灯的设计[J].光源与照明,2023,(01):69-71.

[6] 侯耀华,陈萍,於崇干.直流电源系统高级功能在无人值班变电站的应用[J].供用电,2015,(02):19-24.

[7] 许桂敏,解皓月,张子泉,等.基于Simulink的光伏电池特性及MPPT算法仿真研究[J].智能建筑电气技术,2024,18(06):36-39+60.

[8] 王青苗.PLC模糊PID控制系统在隧道照明节能控制中的应用[J].微型电脑应用,2024,40(06):114-118+122.

[9] 陈礼俊,兰志勇.单片机控制的双调控高压直流电源[J].现代电子技术,2017,40(12):165-168.

[10] 樊战亭,万欣,王超.太阳能电池板自动追光控制系统设计[J].咸阳师范学院学报,2024,39(06):12-16.

[11] Gene F. Franklin, J. David Powell, Abbas Emami-Naeini, et al. Feedback control of dynamic systems[M].Publishing House of Electronics Industry,2013:14,590.

[12] Karl Johan Astrom, Richard M. Murray.自动控制多学科视角[M].人民邮电出版社,2010:310.

附录

1 STM32闭环PI控制程序

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
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "AD.h"
#include "Serial.h"

// 定义全局变量
#define PWM_FREQUENCY 10000 // PWM频率
#define MAX_PWM_VALUE 1000 // PWM最大值
#define PWM_PERIOD 3000 // PWM周期为1000个计数单位
#define KP 0.1 // 比例增益
#define KI 0.01 // 积分增益
#define KD 0.01
float voltage_ref = 10; // 设定的输出电压
float voltage_fb = 0.0; // 反馈的实际输出电压
float duty_cycle = 0.0; // 占空比
float error = 0.0; // 误差
float integral = 0.0; // 积分项
float control_signal = 0.0; // 控制信号
float last_error = 0.0; // 上一次的误差
float derivative = 0.0; // 微分项
int sample_index = 0; // 样本计数器
float trueVoltage=0.0; // 实际输出电压值
float VREF;
uint32_t time_counter = 0; // 用于记录时间的计数器
uint8_t voltage_state = 0; // 0 表示电压为8V,1 表示电压为10V
uint16_t ADValue;
float Voltage;
float i;

void control_buck(void){
voltage_fb = (float)AD_GetValue()*3.3/4096; //读取ADC的值
trueVoltage = voltage_fb*1050*20000/2500/1000; // 计算实际电压 (根据外部电路参数)
error = voltage_ref*2500*1000/1050/20000 - voltage_fb; // 计算误差
integral += error; // 积分计算
derivative = error - last_error; // 微分计算
control_signal = KP * error + KI * integral + KD * derivative; // PID控制输出
if (control_signal > 0.8)
control_signal = 0.8;
else if (control_signal < 0.2)
control_signal = 0.2;
duty_cycle = control_signal * PWM_PERIOD; // 更新占空比
i = (int)duty_cycle;
PWM_SetCompare1(i);
}
int main(void){
OLED_Init();
PWM_Init();
AD_Init();
Delay_ms(10);
NVIC_Configuration();
Serial_Init(); // 初始化串口
while (1){
control_buck();
}
}

2 自动调光程序

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
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "AD.h"
#include "Serial.h"
#include "HC05.h"
#include <string.h>
#include <stdlib.h>

// 定义全局变量
#define PWM_FREQUENCY 10000 // PWM频率
#define MAX_PWM_VALUE 1000 // PWM最大值
#define PWM_PERIOD 3000 // PWM周期为1000个计数单位
#define KP 0.1 // 比例增益
#define KI 0.01 // 积分增益
#define KD 0.01
float Light_Intensity = 0.0; // 光敏实际模拟量
float voltage_ref = 5 * 1.38; // 设定的输出电压
float voltage_fb = 0.0; // 反馈的实际输出电压
float duty_cycle = 0.0; // 占空比
float error = 0.0; // 误差
float integral = 0.0; // 积分项
float control_signal = 0.0; // 控制信号
float last_error = 0.0; // 上一次的误差
float derivative = 0.0; // 微分项
//int sample_index = 0; // 样本计数器
float trueVoltage=0.0; // 实际输出电压值
float VREF;
uint32_t time_counter = 0; // 用于记录时间的计数器
uint8_t voltage_state = 0; // 0 表示电压为8V,1 表示电压为10V
uint16_t ADValue;
float Voltage;
float i;
uint8_t RxSTA = 1;
char RxData[100] = "N";

void control_buck(void){
voltage_fb = (float)AD_GetValue(ADC_Channel_4)*3.3/4096; //读取ADC的值
trueVoltage = voltage_fb*1050*20000/2500/1000; // 计算实际电压 (根据外部电路参数)
error = voltage_ref*2500*1000/1050/20000 - voltage_fb; // 计算误差
integral += error; // 积分计算
derivative = error - last_error; // 微分计算
control_signal = KP * error + KI * integral + KD * derivative; // PID控制输出
if (control_signal > 0.8)
control_signal = 0.8;
else if (control_signal < 0)
control_signal = 0;
duty_cycle = control_signal * PWM_PERIOD; // 更新占空比
i = (int)duty_cycle;
PWM_SetCompare1(i);
}

int main(void){
OLED_Init();
PWM_Init();
AD_Init();
Delay_ms(10);
NVIC_Configuration(); // NVIC初始化
Serial_Init(); // 初始化串口
HC05_Init();

while (1){
// 蓝牙读取开关
HC05_GetData(RxData);
if (RxSTA == 0){
if (strcmp(RxData, "LL") == 0){
RxSTA = 1;
while(1){
// 读取光敏模拟输入量
Light_Intensity = (float)AD_GetValue(ADC_Channel_5);
voltage_ref = (Light_Intensity * 2 / 3500 + 8) * 1.38;
control_buck();
HC05_GetData(RxData);
if (RxSTA == 0)
break;
}
}
else if (strcmp(RxData, "on") == 0)
voltage_ref = 10 * 1.38;
else if (strcmp(RxData, "off") == 0)
voltage_ref = 5 * 1.38;
else{
int num = atoi(RxData);
if (num >= 0 && num <= 100)
voltage_ref = ((float)num / 100 * 2 + 8) * 1.38;
else if (num > 100)
voltage_ref = 10 * 1.38;
else
voltage_ref = 5 * 1.38;
}
memset(RxData, 0, sizeof(RxData));
strcpy(RxData, "N");
RxSTA = 1;
}
control_buck(); // 控制输出电压
}
}

基于STM32F407实现的信号发生与采集分析系统

演示视频已上传至Bilibili视频平台:https://www.bilibili.com/video/BV1wUiRYxE8z


一、系统功能与整体架构设计

系统实现功能

(1)单片机在按键控制下,产生1kHz的正弦波或方波;

(2)单片机能够采集波形,并且显示;

(3)单片机能够分析采集波形的频谱,并且显示频谱与基波频率。

整体架构设计图

系统主页与按键对应功能简介

每次启动系统都会默认直接进入该主页面:

(1)蓝色部分的文字为系统名称与作者姓名,这会在后续的每个功能页面中都有显示;

(2)黑色部分的文字为各按键对应的功能介绍。

正如主页的功能介绍栏所示:

(1)按下KEY0:PA4引脚开始持续输出1kHz的正弦波信号,并在屏幕上实时显示从PA5引脚采集到的输入信号波形;

(2)按下KEY1:PA4引脚开始持续输出1kHz的方波信号,并在屏幕上实时显示从PA5引脚采集到的输入信号波形;

(3)按下KEY2:在屏幕上实时显示从PA5引脚采集到的输入信号的频谱分析结果(幅值谱,频率范围为0~1000Hz);

(3)按下KEY3(KEY_UP):在屏幕上实时显示从PA5引脚采集到的输入信号的频谱分析结果(幅值谱,频率范围为0~8000Hz)。


二、各部分功能实现

1、1kHz正弦波与方波的产生

模块功能架构设计

在实际单片机编程实现时,导入并调用DSP库加速信号数组(正弦波)的计算,并通过时钟TIM6(分频)控制DMA的数据搬运过程,并设置DAC数模转换将搬运后的信号数字数据在PA4引脚以模拟信号形式输出。

模块功能实现依据

为使用单片机产生指定频率的波形,需要根据上述架构设置对应的参数,基本的设置逻辑如下:

(1)首先,这里使用定时器TIM6来控制DMA搬移数据的过程,在CubeMX中已预先设置其时钟频率为84MHz;

(2)在生成信号数组时,C语言程序中设定数组长度为1024(与后续采集一致,为4的整数次幂以便于进行快速傅里叶变换FFT);

(3)事实上,对于信号数组长度N、定时器频率fT与信号基波频率f而言存在如下关系式:f = fT / N,这意味着以输出基波频率f = 1kH的信号为例,经过时钟分频后的定时器频率fT是可以直接确定的,进而可以确定分频倍数(时钟频率/分频后定时器频率)。

经过计算,当分频倍数设置为82时(实际单片机控制程序中为两次分频,取第一次分频倍数为41、第二次分频倍数为2即二分频),输出的信号基波频率f约为1000(由于数组长度为1024,在分频倍数必须取整的情况下,基波频率无法精准等于1000Hz,实际约为1000.38Hz)。

在MATLAB中,可以编写简单的测试程序模拟这一过程:

1
2
3
4
5
6
7
8
TIM6_Frequency = 84000000; %DAC_DMA时钟TIM6频率
DAC_DMA_Divide1 = 41; %DAC_DMA时钟一次分频
DAC_DMA_Divide2 = 2; %DAC_DMA时钟二次分频
DAC_DMA_Frequency = TIM6_Frequency / (DAC_DMA_Divide1 * DAC_DMA_Divide2); %分频后时钟频率

N = 1024; %数组长度与采样点数

f = DAC_DMA_Frequency / N; %产生信号频率(期望值1000)

模块功能实现效果

启动系统后按压按键KEY_0启动正弦波生成,将示波器的通道正极与信号输出引脚PA4连接,示波器的通道负极与单片机的地GND连接,可在示波器上显示出如下波形:

可以看到输出的波形形状为标准的正弦波,输出电平范围为03.3V(对应生成的正弦信号数组振幅为2048、偏置为2047即数据点范围位于04095),均值为1.6V,且周期约为1kHz(示波器显示1.00045kHz;一个周期大致占据五格、每格代表200us即一个周期为1ms)。

按压按键KEY_1切换为生成方波,可在示波器上显示出如下波形:

可以看到输出的波形形状为标准的方波(占空比50%),输出低电平为0V、高电平为3.3V(对应生成的方波信号数组前一半值为0、后一半值为4095),均值为1.6V,且周期约为1kHz(示波器显示1.00043kHz;一个周期大致占据五格、每格代表200us即一个周期为1ms)。

2、波形信号的采集与显示

模块功能架构设计

在实际单片机编程实现时,通过定时器控制从PA5引脚读入模拟信号,通过ADC模数转换为数字数组并通过DMA搬运将其存入长度为1024(为4的整数次幂以便于进行快速傅里叶变换FFT)的数组中,存满一次数组即中断一次DMA搬运并将该数组数据(即采集波形)显示在显示屏上,短暂延迟(控制屏幕刷新速度合适)后进行新一轮的信号采集、搬运与波形显示。

模块功能实现依据

为使用单片机采集信号数据并以合适的形式将波形显示在显示屏上,需要根据上述架构设置对应的参数,基本的设置逻辑如下:

(1)首先,控制ADC1的定时器在CubeMX中已预先设置其时钟频率为84MHz,但根据相关手册与文档,硬件上对于分频后的ADC实际频率有限制,不能高于30MHz,在这样的条件下一般取四分频(仅分频一次,以对应结构体参数hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4实现),即分频后定时器频率为21MHz;

(2)其次,根据相关手册与文档,完成一次采样至少会花费12个时钟周期,为调控实际采样频率通常还可以设置额外的时钟周期(库函数限制只能为特定的几个值),即实际的采样频率Fs应为:分频后定时器频率(21MHz)/一次采样花费的时钟周期数(12+额外设置的时钟周期);

(3)事实上,要想控制屏幕上显示的波形不过于松散/密集,需要控制一次采样(填满数组,DMA中断)内包含的信号周期数量,这可以通过将信号产生的定时器频率fT除以采样频率Fs得到;

(4)另一方面还需要注意为使得采集到的波形没有失真(频域混叠)现象,要求采样频率Fs与待采集波形频率f满足:Fs≥2f。

经过计算与测试,当额外设置的时钟周期设置为112时(sConfig.SamplingTime = ADC_SAMPLETIME_112CYCLES),一次采样中包含(屏幕上显示)的信号周期约为6,这样的显示效果较为合理;同时此时的采样频率Fs约为42683Hz,远大于待采集波形频率f = 1000Hz的两倍,不会发生频谱混叠。

在MATLAB中,可以编写简单的测试程序模拟这一过程(以正弦信号为例):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ADC_Timer_Frequency = 84000000; %ADC时钟频率
%硬件限制:要求ADC实际时钟频率不能超过30MHz
ADC_Divide = 4; %取四分频,分完后达到21MHz满足要求
ADC_Frequency = ADC_Timer_Frequency / ADC_Divide; %分频后ADC时钟频率

%完成一次采样需要多个时钟周期
Collect1 = 12; %固定消耗12次循环,无法更改
Collect2 = 112; %可设置额外消耗循环数以调整采样频率
Fs = ADC_Frequency / (Collect1 + Collect2); %ADC采样频率

Cycle = DAC_DMA_Frequency / Fs; %一次采样采出多少个周期

A = 2047; %幅值
B = 2048; %直流偏置分量
t = 0 : 1 / Fs : (N - 1) / Fs;
x = A * sin(2 * pi * f * t) + B;

% 绘制原始信号
figure;
subplot(2,1,1);
plot(t, x);
title('正弦波信号');
xlabel('时间 (秒)');
ylabel('幅值');

运行该MATLAB程序,绘制出一次采样采集到的波形如下图所示:

模块功能实现效果

启动系统后按压按键KEY_0启动正弦波信号的生成与采集,将信号输出引脚PA4与信号输入引脚PA5连接,屏幕上显示采集波形效果如下:

按压按键KEY_1切换为生成方波信号并采集,屏幕上显示采集波形效果如下:

图上的横坐标单位为ms;可以看到屏幕上显示的即为6个周期的信号波形,这与MATLAB的模拟计算结果是完全一致的,且波形无失真。

3、采集波形信号的频谱分析

模块功能实现依据

在频谱分析与频谱图显示方面,有如下要点需要注意:

(1)首先,频谱分析依赖于对于信号的傅里叶变换,在数字信号层面对于离散的数据点则需要采用离散傅里叶变换,但这样的变换计算速度往往很感人,因此需要利用其快速算法,即快速傅里叶变换FFT,MATLAB可直接调用fft函数实现,单片机编程中在DSP库中也有相应的函数可以实现完全相同的过程,但要求信号数组的长度应为4的整数次幂,故先前均选取1024作为发生与采集信号的数组长度;

(2)其次,经过FFT变换后会得到一个长度相同(1024)的新数组,其中每一个数字的下标index对应的实际频率应为index*Fs/1024,这意味着如果直接将整个FFT变换结果数组作为频谱图显示到屏幕上,横坐标的跨度实际上为Fs≈42683Hz,为使得频谱图更加直观,需要限制绘制频谱图的频率范围,并对应控制绘制数组中的部分数据;

(3)事实上,FFT变换结果的数组中各数值并不是期望的对应频率的幅值,还需要除以数组长度1024(单片机程序中对于起始点只需要除以一半的数组长度即512)才可得到正确的幅值。

由于涉及到信号的基波频率检测以及方波的频谱分析,在KEY_2和KEY_UP按键分别设置了频谱频率范围为01000Hz与08000Hz两种模式。在MATLAB中,可以编写简单的测试程序模拟频谱分析过程并在0~8000Hz的频段上展示频谱:

1
2
3
4
5
6
7
8
9
f_range = linspace(0, Fs, N);%频域横坐标,注意奈奎斯特采样定理,最大原信号最大频率不超过采样频率的一半
xk = fft(x) / N; %用fft得出离散傅里叶变换

% 计算并绘制频谱
subplot(2,1,2);
plot(f_range(1:50),abs(xk(1:50)));%画双侧频谱幅度图
title('正弦波频谱');
xlabel('频率 (Hz)');
ylabel('幅度');

运行该MATLAB程序,绘制出一次采样采集到的波形如下图所示(以正弦信号为例):

可以看到该信号具有直流分量(频率为0)以及1000Hz除的正弦分量,两者幅值均为2048(与产生波形时的一致)。

除此之外,在单片机编程中,为寻找并在屏幕上打印出信号的基波频率,还需要在显示频率波形的同时完成对于除直流分量外最高幅值对应频率的计算(数组返回最大值对应下表,算法较简单在此省略实现过程)。

模块功能实现效果

启动系统后按压按键KEY_0启动1000Hz正弦波信号的生成与采集,将信号输出引脚PA4与信号输入引脚PA5连接,并按压按键KEY_2可启动短频段0~1000Hz的频谱显示如下:

按压按键KEY_UP可启动长频段0~8000Hz的频谱显示如下:

可以看到此时只有直流分量和1000Hz的正弦分量两个尖峰,与MATLAB模拟计算结果一致。

按压按键KEY_1,切换为1000Hz方波波信号的生成与采集,将信号输出引脚PA4与信号输入引脚PA5连接,并按压按键KEY_2可启动短频段0~1000Hz的频谱显示如下:

按压按键KEY_UP可启动长频段0~8000Hz的频谱显示如下:

可以看到此时在01000Hz频段只有直流分量和1000Hz的正弦分量两个尖峰,但在08000Hz频段,由于方波实质上是不同频率的正弦信号的叠加,所以频谱会在基波的奇数倍(1、3、5……)处也有尖峰,但尖峰的幅值会远小于基波1000Hz处,且倍数越大幅值越小,这使得按照先前的算法也能识别出基波频率约为1000Hz。

4、补充测试

由于还需要对于基波频率在0~1000Hz范围内的任意输入信号进行频谱分析,经过调试后,当输入信号频率为200Hz时,为使得显示波形合理,将ADC环节设置的额外时钟周期由112调整至480,结果如下所示:

200Hz正弦波:

时域:

频域:

短频段(0~1000Hz):

长频段(0~8000Hz):

200Hz方波:

时域:

频域:

短频段(0~1000Hz):

长频段(0~8000Hz):

在ADC环节额外时钟周期设置为480的情况下,可以计算得出,对于频率为1000Hz的信号,一次采样(即屏幕内显示)包含21个周期(正好为整数),结果如下所示:

1000Hz正弦波:

时域:

频域:

长频段(0~8000Hz):

1000Hz方波:

时域:

频域:

长频段(0~8000Hz):

可以看到此时虽然时域上波形显示更加狭窄密集,但是频域上尖峰的变化过程也有了迅速的提升,且测得的基波频率也更加精准。


三、总结

通过本次项目实践,不仅在实验中进一步加深了对于数字信号的产生、采集与频谱分析处理过程的理解,特别是通过期望发生信号频率去计算定时器分频系数、采样频率的计算过程以及FFT计算与频谱图像绘制的过程;而且也增加了对于STM32F407单片机开发的实战经验,在巩固了引脚GPIO与时钟配置相关内容的同时,又对于DMA内存搬运及其中断以及DAC数模转换输出与ADC模数转换输入等功能模块有了更深刻的认识,包括定时器对于这些过程的调控也涉及到相关频率的计算,所有模块的配置之间都有着密切的联系。

小车路径规划

本项目全部代码已同步上传至Github,仓库链接:Asgard-Tim/Path-Planning: 重庆大学明月科创实验班定量工程设计方法课程项目 (github.com)

一、设计要求


在本部分的课程项目中,要求我们运用LD14雷达扫描地图,在MATLAB中进行人工势场添加并对STM32小车进行路径规划,在一规定的场地中让小车避开两个矩形障碍物并以尽可能短的路径最终抵达圆形目标位置。


二、系统方案


2.1 移动底盘分析

小车为履带式小车,左右履带分别由一枚直流电机进行驱动,运动模式类似常规双轮小车,通过左右两枚电机转动的差速实现转向。该小车相对来说较为容易进行控制,只需要控制两个驱动轮的速度存在差异,即两轮差速,即可控制机器人实现无滑动摩擦的旋转,也可实现零半径转弯。

图2-1 双轮履带小车外观图

1

图2-2 两轮差速式机器人运动学分析图

2

对小车移动底盘的运动学分析(如上图2-2所示):

小车的速度控制主要是控制 X 轴(前后方向)和 Z 轴(旋转方向)的速度, 以 Vx 和 Vz 来指代,单位分别是 m/s 和弧度/s。X 轴方向以前进记为正,Z 轴方向以右转记为正。车轮速度是使用编码器来计算和得出,读取编码器计数后再转化成车轮的速度。Vz则是通过左右电机转动的差速计算得到的。

图中参数分别代表:

3

2.2 电机特性分析

在本次项目中,我们采用带有减速器与编码器的直流电机驱动小车前进。

直流电机的物理模型图如下图2-3所示。其中,固定部分有磁铁,这里称作主磁极;固定部分还有电刷。转动部分有环形铁心和绕在环形铁心上的绕组。 (其中 2 个小圆圈是为了方便表示该位置上的导体电势或电流的方向而设置的) 它的固定部分(定子)上,装设了一对直流励磁的静止的主磁极 N 和S,在旋转部分(转子)上装设电枢铁心。在电枢铁心上放置了两根导体连成的电枢线圈, 线圈的首端和末端分别连到两个圆弧形的铜片上,此铜片称为换向片。换向片之间 互相绝缘,由换向片构成的整体称为换向器。换向器固定在转轴上,换向片与转轴 之间亦互相绝缘。在换向片上放置着一对固定不动的电刷 B1 和 B2,当电枢旋转时,电枢线圈通过换向片和电刷与外电路接通。在电刷上施加直流电压 U,电枢线圈中的电流流向为:N 极下的有效边中的电流总是一个方向,而 S 极下的有效边中的电流总是另一个方向。这样两个有效边所受的洛伦兹力的方向一致(可以根据左手法则判定),电枢开始转动。具体来说就是,把上图中的+和-分别接到电池的正极和负极,电机即可转动;如果是把上图中的+和-分别接到电池的负极和正极,则电机会反方向转动。电机的转速可以理解为和外接的电压是正相关的(实际是由电枢电流决定)。

总而言之,如果我们可以调节施加在电机上面的直流电压大小,即可实现直流 电机调速,改变施加电机上面直流电压的极性,即可实现电机换向。

图2-3 直流电机的物理模型

4

在具体的使用过程中,我们需要通过在特定的引脚之间(如本次项目所用电机为1/6引脚)接上一个直流电源,电机即可转动,且改变电压大小即可改变电机转速。接线方式说明如下图2-4所示。

5

2.3 电机控制策略以及PID特性分析

小车电机驱动器芯片使用 AT8236,具有过流保护功能,并可设置电流阈值。驱动芯片只需两个逻辑输入,便可达到调速和正反转的功能,本小车中,每个电机使用两路PWM进行调速(实际上一个普通 IO 和一路 PWM 即可进行正反转 和调速)。

电机的速度使用 13 线霍尔编码器输出 AB 相进行测量,电机减速比为 1:30,使用 STM32 的编码器测量功能,并初始化为脉冲上升沿和下降沿都进行计数,可实现轮子转一圈输出 1560 个计数。

电机调速框图如下图2-5所示。

图2-5 电机调速框图

6

基于2.1节提到的小车移动地盘的运动学分析,我们可以进一步讨论这些物理量之间的关系,并求出其运动学正逆解公式(如下图2-6),结合PID实现控制。

图2-6 两轮差速式机器人的运动学正逆解公式

7

8

9

10

下图2-7为PID的控制框图,每个方块代表控制系统的一个组成部分,从图中可看出系统中各组成部分的相互关系和影响,即 PID 调节系统是具有被调参数负反馈的闭环系统。当被控量 Y 受到干扰的影响而升高时,反馈信号将高于给定值 X,经过比较而到放大元件去的偏差信号 e 将为负值,控制器将发出信号而使执行元件动作,其作用方向为负,使被控量下降,这就达到了自动控制的目的。

图2-7中的目标速度一般我们可以通过按键或者开关等方式编程实现改变目标值,测量速度就是通过单片机定时去采集编码器的数据并清零。目标速度和测量速度之间做差这个就是目前系统的偏差。在控制过程中,需要将目标速度、测量速度与偏差三者送入 PID 控制器进行计算输出,然后再经过电机驱动的功率放大控制电机的转动去减小偏差,最终达到目标速度。

图2-7 PID控制框图

11

对于上述PID控制的基于C语言的实现,我们给出以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
`int Incremental_PI (int Encoder,int Target)` 

`{`

`static float Bias,Pwm,Last_bias;`

`Bias=Encoder-Target; //计算偏差`

`Pwm+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias;`

`//增量式 PI 控制器`

`Last_bias=Bias; //保存上一次偏差`

`return Pwm; //增量输出`

`}`

其中,入口参数为编码器的速度测量值和速度控制的目标值,返回值为电机控制 PWM。第一行是相关内部变量的定义。第二行是求出速度偏差,由测量值减去目标值。第三行使用增量 PI 控制器求出电机 PWM。第四行保存上一次偏差,便于下次调用。最后一行是返回。

2.4 嵌入式控制系统总结分析

总体而言,我们基于小车本身的轮距等基本参数编写了一整套嵌入式PID控制流程与系统(基于C语言,面向STM32编程),结合PWM波控制电压,从而控制电机的转速以实现对于车轮速度的反馈调节机制,能够保证小车始终保持相对稳定的速度前进,便于后面进一步规划算法,使小车的运动更加可控。此部分编写的KEIL工程详见附件“PID.zip”。

2.5 传感系统总结分析

本次项目所采用的传感器主要为激光雷达,在此我们选用LD14雷达。LD14 主要由激光测距核心,无线传电单元,无线通讯单元,角度测量单元、电机驱动单元和机械外壳组成。LD14测距核心采用三角测量法技术,可进行每秒 2300 次的测距。每次测距时,LD14从一个固定的角度发射出红外激光,激光遇到目标物体后被反射到接收单元。通过激光、目标物体、接收单元形成的三角关系,从而解算出距离。获取到距离数据后,LD14 会融合角度测量单元测量到的角度值组成点云数据,再进行导出。

雷达扫描点云数据形式如下图2-8所示:

图2-8 雷达扫描点云极坐标数据形式(下图2数据为角度(角度制),右侧为距离)

12

13

在项目的实践过程中,我们需要通过对STM32单片机进行编程,从激光雷达读取数据并通过串口将处理后的数据传输至电脑中(用特定的软件读取串口输出信息)。STM32中烧录的KEIL工程见附件“Lidar.zip”,接线方式如下图所示。

图2-9 激光雷达与单片机接线方式对应

14

15

这里给出KEIL工程中main.c中的主干代码(图2-10),最终会输出数据θ和r,分别代表偏转的角度(AvoidData[i].angle)和距离原点的距离(AvoidData[i].distance)。

图2-10 读取激光雷达数据的主干代码

16


三、硬件电路设计


主要运用模块电路图如下图3-1所示:

图3-1 主要模块电路图

17

其中,小车的主控为STM32 F103RCT6芯片,其主控板实物图如下图3-2所示:

图3-2 STM32主控板实物图

18

由于本次项目需要完成的目标较为单一,仅使用其中少部分接口和器件。


四、软件算法设计


4.1 任务描述

在本项目中,我们需要通过激光雷达对于小车所处的地图环境(2m*2m,放置有三个正方体障碍物与一个圆柱体目标物)进行扫描,并对扫描得到的数据结果进行处理。通过一定的算法对于目标物与障碍物进行识别后,我们还需要通过人工势场法进行路径规划,使得小车能够以最优的路径绕开障碍物到达目标物。

本次项目任务分为静态和动态两个部分,其中动态测试过程中会对障碍物的位置进行人为的随机改动。测试过程中,小车的起点位置与目标物的位置始终不变,且可自由选定小车的初始面对方向。

4.2 技术路径和策略

通过对于任务描述的分析,我们大致可以将静态情况下的路径规划问题拆解为以下几个部分,并给出相应的处理工具与解决策略:

  • (1) 地图扫描:需要通过对STM32单片机进行编程(利用软件工具KEIL),利用串口通信读取激光雷达扫描所获取的周围地图环境点云的极坐标数据
  • (2) 处理数据:将串口所得到的数据导入MATLAB中,利用坐标变换将不同点位扫描的极坐标数据统一到同一个笛卡尔坐标系中以便后续处理与识别
  • (3) 识别物体:在获取扫描后得到的地图后,需要利用RANSAC算法(随机抽样一致算法)识别点云数据中的直线与圆形,并得到相应的障碍物与目标物的二维坐标
  • (4) 路径规划:在MATLAB中编程,利用得到的出发点、障碍物和目标点各自的坐标建立势场,并用梯度下降法寻找避开障碍物、到达目标点的最优路径

实际上,在动态情况下的路径规划问题中,实现的步骤也与上述大致相同,只是并没有MABLAB等电脑端的辅助软件帮助其进行数据处理与路径规划,需要将这些算法通过对STM32单片机编程集成到小车上,从而实现在测试地图环境随机发生改变的情况下仍然能够按照局部最优的路线避开障碍物到达目标点。


4.3 核心程序逻辑
4.3.1 激光雷达极坐标点云数据的处理与变换——得到二维地图

在2.5节,我们给出了我们的KEIL工程。通过将其烧入至STM32内,并按照特定接线方式将激光雷达与主控板连接,利用串口通信及相关软件成功在电脑上读取了激光雷达扫描得到的点云极坐标数据(如图2-8右图)。在实际测试时,我们选取了五个坐标点分别放置小车(控制朝向相同)对周围地图环境进行扫描,获得了“data1.txt”等一系列数据文件(详见附件)。

在MATLAB程序的第一部分,我们首先利用importdata函数从数据文本文件中读取相应数据,并将其按列分割为“angle”和“distance”两部分。随后,我们利用MATLAB中自带的坐标变换函数pol2cart将一系列的极坐标数据转换为笛卡尔坐标系下的x-y数据(算法原理如下图4-1)。事实上,由于小车每次扫描的位置均不同,因此还需要将多次扫描的结果结合每次小车放置位置的坐标进行一系列的拼接与变换,才可得到最终的场地二维地图(效果如下图4-2)。

图4-1 利用pol2cart函数进行坐标变换的原理示意图

19

图4-2 经拼接后得到的场地二维地图

20

该部分的代码给出如下:

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
`%Step1:处理激光雷达扫描数据,绘制二维坐标系地图`

`ans=importdata("data1.txt");`

`angle=ans(:,1);`

`angle=angle.*2.*3.1415926./360;`

`distance=ans(:,2);`

`[x,y] = pol2cart(angle,distance);`

`ans1=importdata("data2.txt");`

`angle1=ans1(:,1);`

`angle1=angle1.*2.*3.1415926./360;`

`distance1=ans1(:,2);`

`[x1,y1] = pol2cart(angle1,distance1);`

`ans2=importdata("data3.txt");`

`angle2=ans2(:,1);`

`angle2=angle2.*2.*3.1415926./360;`

`distance2=ans2(:,2);`

`[x2,y2] = pol2cart(angle2,distance2);`

`ans3=importdata("data4.txt");`

`angle3=ans3(:,1);`

`angle3=angle3.*2.*3.1415926./360;`

`distance3=ans3(:,2);`

`[x3,y3] = pol2cart(angle3,distance3);`

`ans5=importdata("data5.txt");`

`angle5=ans5(:,1);`

`angle5=angle5.*2.*3.1415926./360;`

`distance5=ans5(:,2);`

`[x5,y5] = pol2cart(angle5,distance5);`

`x4 = [x;x1-100;x2+1850;x3+1400;x5+1500]/100;`

`y4 = [y;y1+1750;y2+100;y3+1650;y5+1000]/100;`

`figure(1);`

`scatter(x4,y4,1);`

`hold on`

`axis equal`

`axis( [ -3, 22, -3, 22 ] )`
4.3.2 利用RANSAC算法识别地图中的直线和圆——获得目标点与障碍物的坐标

在成功利用激光雷达的扫描数据建立了二维地图后,我们需要让机器人知道哪里能走哪里不能走,要走向哪里,即明确目标点以及障碍物的具体坐标。在本测试项目中,设定圆柱为目标物而正方体为障碍物,所以问题的关键即为如何从二维地图中识别出圆形以及正方形(本质上为直线的拼接)并获得其坐标。

在之前的课程中,介绍了RANSAC这一算法。随机样本一致性(Random Sample Consensus RANSAC) 是一种迭代方法,用于从包含异常值的观察数据中估计出数学模型参数,因此也可以理解为一种异常值检测方法。RANSAC的一个基本假设是,数据由内点(“inliers”)和外点(“outliers”)组成,其中内点是在一定误差范围内可以通过一些模型参数来解释的数据,外点是不符合模型的数据。RANSAC的另一个假设是,随机选取的样本数据都是内点,存在一个可以估计模型参数的过程,该模型可以最佳地解释或拟合该数据。通过该算法,我们可以有效地从已有的地图(本质上是二维坐标系下的点集数据)中拟合出直线与圆的轮廓,并获取相应图形的对应坐标。

该算法的实现步骤如下:

(1) 从原始数据集S中随机选择子集s,s为假设的内点(子集s一般为最小子集,如:直线选取两个点,圆选择三个点)

(2) 依据子集s估计模型参数

(3) 遍历数据集S中除子集s外的所有数据,如果数据点在给定误差e以内,则标记为内点,否则标记为外点

(4)所有内点组成一致集,如果一致集中点的个数满足给定阈值T,则用一致集中所有内点重新估计模型参数,然后结束算法

(5)如果一致集中内点个数少于阈值T,则重新选择新的子集s,并重复步骤(1)-(4)

(6) 经过K次迭代,选择一个内点数量最多的一致集,用一致集中所有内点重新估计模型参数,然后结束算法

基于上述基本思想与步骤,我们编写了一段MATLAB代码,用于二维坐标地图中直线的识别与拟合。在此基础之上,我们根据算法原理,从点集中随机取出三个点,利用三点成圆获得圆的方程(利用自己编写的函数ThreePoint2Circle)。再对圆的轨迹赋予一个宽度,统计落入这个宽度中的点的数量,对所有的点进行逐个取点,获得最优的圆的方程。值得注意的是,由于待识别的正方形是由多条直边构成,这要求我们需要重复对于该图像进行扫描拟合,且需要在一次拟合之后将该次拟合中涉及的数据点删除以防影响下次拟合。下面将给出这一部分的代码实现以及拟合效果(如图4-3、4-4)。

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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
`%Step2:利用RANSAC算法识别直线和圆`

`%(1)圆的识别`

`a = [x4,y4];`

`% RANSCA参数:`

`% 迭代次数`

`iter = 0;`

`% 查看圆数据的大小`

`[m,n] = size(a);`

`% 误差参数`

`berr = 0.02;`

`% 拟合参数`

`bfit = [];`

`% 内点个数为点数的1/3`

`t = floor(m/3);`

`% 开始循环迭代`

`while iter<100`

`% 随机挑选三个点,三个点不重复`

`% 拟合圆最少需要三个点,拟合直线最少需要两个`

`% ran为索引编号`

`ran = randperm(m,3)';`

`% b为索引得到的点`

`b = a(ran,:);`

`% 根据随机得到的三个点,计算圆的半径和圆心`

`[r1,p1] = ThreePoint2Circle(b(1,1:2), b(2,1:2), b(3,1:2));`

`% 选择除了随机得到的三个点外的其他点`

`c = setdiff(a,b,"rows");`

`% 计算每个点到圆心的距离dis`

`dis = sqrt(sum((c(:,1:2)-p1).^2,2));`

`% 计算 dis和拟合圆的误差`

`res = dis - r1;`

`% 选择小于误差的点,进入到内点中`

`d = c(res<berr,:);`

`len = length(d(:,1));`

`% 判断内点数量是否满足条件`

`if len > t`

​ `% 满足条件时,多点拟合圆,这里用平均值计算圆心`

​ `p = mean(d);`

​ `r = mean(sqrt(sum((d(:,1:2)-p(:,1:2)).^2,2)));`

​ `% 多点拟合的圆和随机点拟合的圆的误差`

​ `err = sqrt(sum((p-p1).^2))+sqrt((r-r1)^2);`

​ `% 如果误差满足条件,则可以结束循环`

​ `% 不满足则继续`

​ `if err < berr`

​ `bfit = [p,r];`

​ `berr = err;`

​ `break`

​ `else`

​ `iter = iter+1;`

​ `continue`

​ `end`

`else`

​ `iter = iter+1;`

`end`

`end`

`%绘图`

`para = [p(1)-r, p(2)-r, 2*r, 2*r];`

`rectangle('Position', para, 'Curvature', [1 1]);`

`%(2)直线的识别`

`iter = 100;`

`data1=transpose(x4);`

`data2=transpose(y4);`

`data=[data1;data2];`

`for t=1:10`

`number = size(data,2); % 总点数`

`bestParameter1=0; bestParameter2=0; % 最佳匹配的参数`

`sigma = 1;`

`pretotal=0; %符合拟合模型的数据的个数`

`for i=1:iter`

`%随机选择两个点`

`idx = randperm(number,2);`

`sample = data(:,idx);`

`%拟合直线方程 y=kx+b`

`line = zeros(1,3);`

`x = sample(:, 1);`

`y = sample(:, 2);`

`k=(y(1)-y(2))/(x(1)-x(2)); %直线斜率`

`b = y(1) - k*x(1);`

`line = [k -1 b];`

`mask=abs(line*[data; ones(1,size(data,2))]); %求每个数据到拟合直线的距离`

`total=sum(mask<sigma); %计算数据距离直线小于一定阈值的数据的个数`

`if total>pretotal %找到符合拟合直线数据最多的拟合直线`

​ `pretotal=total;`

​ `bestline=line; %找到最好的拟合直线`

`end`

`end`

`%显示符合最佳拟合的数据`

`mask=abs(bestline*[data; ones(1,size(data,2))])<sigma;`

`hold on;`

`k=1;`

`index=[];`

`for i=1:length(mask)`

`if mask(i)`

​ `inliers(1,k) = data(1,i);`

​ `k=k+1;`

​ `index=[index i];`

`end`

`end`

`%删除完成拟合的点以进行下一次拟合`

`for i=1:length(index)`

`data(:,index(i))=[];`

`for j=1:length(index)`

​ `if(index(j)>index(i))`

​ `index(j)=index(j)-1;`

​ `end`

`end`

`end`

`% 绘制最佳匹配曲线`

`bestParameter1 = -bestline(1)/bestline(2);`

`bestParameter2 = -bestline(3)/bestline(2);`

`xAxis = min(inliers(1,:)):max(inliers(1,:));`

`yAxis = bestParameter1*xAxis + bestParameter2;`

`plot(xAxis,yAxis,'r-','LineWidth',2);`

`end`

`function [R,P0] = ThreePoint2Circle(P1, P2, P3)`

`%% 求圆心和半径,三个点可以求圆心和半径`

`x1 = P1(1); x2 = P2(1); x3 = P3(1);`

`y1 = P1(2); y2 = P2(2); y3 = P3(2);`

`z1 = x2^2 + y2^2 - x1^2 - y1^2;`

`z2 = x3^2 + y3^2 - x1^2 - y1^2;`

`z3 = x3^2 + y3^2 - x2^2 - y2^2;`

`A = [(x2-x1), (y2-y1); (x3-x1), (y3-y1); (x3-x2), (y3-y2)];`

`B = 0.5*[z1; z2; z3];`

`P0 = (A'*A)\A'*B;`

`R1 = sqrt( (P0(1) - P1(1))^2 + (P0(2) - P1(2))^2 );`

`R2 = sqrt( (P0(1) - P2(1))^2 + (P0(2) - P2(2))^2 );`

`R3 = sqrt( (P0(1) - P3(1))^2 + (P0(2) - P3(2))^2 );`

`R = (R1 + R2 + R3)/3;`

`P0 = P0';`

`End`

图4-3(上) 对于二维地图中一条直线的拟合(红线为拟合结果)

(可以看到拟合效果相对良好)

21

图4-4(右) 对于给定圆坐标数据的RANSAC拟合(上图为给定的圆,下图为拟合出的圆)

(说明该算法实现的有效性)

22

4.3.3 建立势场并利用梯度下降法确定最优路径(人工势场法)

人工势场法引入了物理中斥力场和引力场的思想,把工作环境抽象为一个电磁场,而机器人则是其中的一个电荷,机器人在磁场力的作用下移动。人工势场法会在障碍物周围构建斥力场、在目标点周围构建引力场;这样,机器人便能够在斥力场和引力场的作用下向目标点移动。同时,当障碍物和目标点太近时,机器人很可能会因为刹不住车而出现无法到达目标点等问题,这也就出现了一堆相应的优化算法。

通过利用RANSAC算法对于地图中具有特定形状的边界、障碍物与目标物进行识别,我们成功获得了障碍物与目标点的坐标。在此基础之上,我们基于原型函数23(a,b即为障碍物/目标点的x,y坐标)建立势场。通过观察不难发现,在以(a,b)为圆心、半径为1的圆之外的地方该势函数均为正,反之为负。事实上,对于场地内的3个障碍物以及1个目标物而言,所形成的是一个叠加场,由原型函数作用于不同的点叠加而成。在此,我们不妨认为势场为正处具有排斥力而势场为负处具有吸引力,需要吸引小车向目标点走去而花费尽量少的能量。在这样的算法理念基础上,我们需要在代表目标点的原型函数部分加上负号;更进一步的,我们还希望这个吸引力足够大而防止被障碍物阻断,因此在建立势场时,不妨在代表目标点的原型函数前乘上一定的系数以保证其足够强大的吸引力。最终,我们根据地图实际情况,建立了整个势场叠加后的函数方程:F=log(sqrt((x-4.75).^2+(y-12.5).^2))+log(sqrt((x-12).^2+(y-7.6).^2))+log(sqrt((x-11.2).^2+(y-13).^2))-5*log(sqrt((x-16.5).^2+(y-18.5).^2)),并根据该函数绘制了势能图(如图4-5)与等势线图(如图4-6)。

图4-5 势场函数势能图

24

图4-6 势场函数等势线图

25

该部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
`%Step3:通过识别得到的障碍物和目标坐标建立势场`

`v=-2:1:22;`

`[x,y]=meshgrid(v);`

`F=log(sqrt((x-4.75).^2+(y-12.5).^2))+log(sqrt((x-12).^2+(y-7.6).^2))+log(sqrt((x-11.2).^2+(y-13).^2))-5*log(sqrt((x-16.5).^2+(y-18.5).^2));`

`[px,py]=gradient(F,1,1);`

`contour(x,y,F);`

`hold on;`

`title('人工势场法路径规划');`

`quiver(x,y,px,py,0);`

`figure(2);`

`surf(x,y,-F);`

在建立完势场之后,由于我们需要寻找的是避开障碍物而通往目标点的最优路径,实际上即为所耗费能量最少的路径,我们引入了梯度下降法,通过间隔相同距离的不断迭代,在每一处都寻找能量下降最快的方向(即为梯度方向)前进(在MATLAB中通过调用函数文件path_plan.m与computP.m实现该功能),最终得到了如下图4-7绿色线所示的最优路径。

图4-7 人工势场法路径规划结果(绿色即为规划出的最优路径)

26

其中,path_plan函数是整个算法过程中的关键,也是梯度下降思想的集中体现,其大致实现思路流程如下:

1)起点、终点 、障碍物、迭代次数、取点半径等参数的设定

2)以起点为中心,作半径为r的圆,从圆上取八个均布的点

3)分别计算八个点的前进“代价”—— 终点对其的引力+所有障碍物对其的斥力

4)取“代价”最小的点的坐标,结合现有起点,计算得到新的起点,然后重复上述内容

5)当发现 一个点距离终点很近 or 迭代的次数计算完 程序停止。

该部分的实现代码如下:

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
`%Step4:通过人工势场法确定最优路径`

`axis([-3 22 -3 22]);`

`begin=[0;0]%起始点坐标`

`over=[16.5;18.5];%目标点坐标`

`figure(1);`

`hold on;`

`plot(begin(1),begin(2),'*b','MarkerSize',10);`

`plot(over(1),over(2),'*b','MarkerSize',10);`

`obstacle=[4.75,12,11.35;12.75,7.5,12];%障碍物坐标`

`point= path_plan(begin,over,obstacle);`

`function [ point ] = path_plan(begin,over,obstacle)`

`iters=1; %迭代次数`

`curr=begin;`

`testR=0.1; %测试8点的圆的半径为0.1`

`while (norm(curr-over)>0.2) && (iters<=2000)`

`point(:,iters)=curr;`

`% attr=attractive(curr,over);`

`% repu=repulsion(curr,obstacle);`

`%curoutput=computP(curr,over,obstacle);`

`%计算当前点附近半径为0.2的8个点的势能,然后让当前点的势能减去8个点的势能取差值最大的,确定这个方向,就是下一步迭代的点`

`%先求这八个点的坐标`

`for i=1:8 testPoint(:,i)=[testR*sin((i-1)*pi/4)+curr(1);testR*cos((i-1)*pi/4)+curr(2)];`

​ `testOut(:,i)=computP(testPoint(:,i),over,obstacle);`

​ `%找出来最小的就可以了`

`end`

`[temp num]=min(testOut);`

`%迭代的距离为0.1`

`curr=(curr+testPoint(:,num))/2;`

`plot(curr(1),curr(2),'og');`

`iters=iters+1;`

`end`

`end`

`function [ output ] = computP( curr,over,obstacle )`

`k_att=1;`

`repu=0;`

`k_rep=100;`

`Q_star=2;`

`%计算当前点距离终点的引力`

`attr=1/2*k_att*(norm(curr-over))^2;`

`%计算障碍点与当前点的斥力`

`%设定障碍的斥力作用半径为2`

`for i=1:size(obstacle,2)`

`if norm(curr-obstacle(:,i))<=Q_star`

​ `repu=repu+1/2*k_rep*(1/norm(curr-obstacle(:,i))-1/Q_star)^2;`

`else`

​ `repu=repu+0;`

`end`

`end`

`output=attr+repu;`

`end`
4.4 实现的实际效果

事实上,尽管RANSAC算法在理论上已经具备足够的拟合精度,但在实际的识别过程中,由于激光雷达扫描获取的数据过多而导致干扰噪点的数量达到了一定规模,以及在算法参数设置上考虑到算力有限等因素而没有采用精确度最高的设置,诸如此类的干扰因素导致在多条直线识别时出现了互相覆盖与识别错误的情况,识别圆形时也并未识别出目标点的圆柱所在处,因此在实际的测试过程中,利用RANSAC算法识别圆与直线以获取目标点和障碍物坐标这一过程并未取得特别良好的效果。为了后面的路径规划算法顺利开展,我们最终采用人工识别的方式,分别给出了起点、障碍物以及目标点的大致坐标,并顺利实现了利用人工势场法进行路径规划的算法,合理规划出了从起点避开障碍物到达目标点停下的最优路径,并通过STM32单片机编程成功驱动了小车按照规划好的路径进行运动,顺利完成开环测试。


五、实验结果及分析


经过几次测试,在进行4至5个位置的扫描之后,通过将数据进行变换与拼接,可以得到一张较为完整的二维地图,再将地图中通过RANSAC算法识别出的特定点位数据读入程序运行,可以得到一条较为合理的最优路径。

事实上,在前面的嵌入式控制系统设计部分,我们计划采用PID方式对于小车与电机进行反馈调节控制,但在实际的测试中,PID的控制方式实现的效果并不尽如人意,无法合理利用MATLAB路径规划所得到的数据结果顺利完成测试。于是我们果断选择了重新使用PWM的方式,依托于MATLAB程序运行规划出的路径对应的相关数据计算所需要的PWM以及延时的时间。最终采用的代码如下图5-1所示(具体KEIL工程内容详见Run.zip附件)。

图5-1 PWM电机驱动部分实现代码

27

28

通过调整PWM的方式对小车进行开环运动控制,最终可以较好达到项目要求。(实现效果见下图5-2及视频附件“测试.mp4”)

图5-2 静态路径规划实现效果实地测试

29

30

虽然静态路径规划部分完成情况相对较好,但遗憾的是,由于对于C语言编程不是特别熟悉,包括受限于对库的了解、算法的时间复杂度较高、实现繁琐以及对于STM32内部利用效率的不完全开发等因素,最终并没有能够成功完成动态部分的路径规划。事实上,动态情况下的路径规划更符合我们在日常生活中常见的应用场景,不论是扫地机器人还是汽车导航,本身所应对的环境都在时刻发生着改变,因此动态的路径规划问题仍然值得在课程结束之后继续进行深挖和探索。希望在未来的工程实践中,我们能够以更加定量化的思维去分析和思考问题,同时更加熟练的掌握相关的算法设计,提高自己的硬件嵌入式编程能力。


六、个人总结


在路径规划这一阶段的课程中,我在前半段主要负责的是STM32单片机的一些基础开发,对于其基本的开发流程以及GPIO等基本的功能模块有了一定的了解并能进行一些简单的32单片机编程;在后半段,我主要负责整体路径规划项目的思路整理与算法设计,结合课堂上介绍的RANSAC识别算法以及人工势场法规划路径,课下积极结合概念的巩固以及相关资料的查询,阅读了相关的示例代码,并根据算法的整体思路自己动手实现了RANSAC算法对于直线与圆的识别拟合以及在建立的势场中利用梯度下降法实现路径规划的MATLAB程序,积极将自己的算法实现与队友编写的STM32 C语言程序融合在一起,在与队友的充分交流沟通与合作的基础上共同完成了该项目。在死亡之桥的测试项目中,我在一个人调试了单片机程序许久未果后,与队友进行了积极的沟通与合作,也基本确定了由我负责编写MATLAB算法程序给队友的单片机编程提供数据支持的合作模式,对于我们团队的所有人来说都是一次难忘的经历。在利用激光雷达扫描地图的过程中,我们也充分信任彼此,在他们编写好了读取雷达数据的相关程序后,我结合着MATLAB程序的需求对于KEIL代码的输出格式部分进行了一定的修改,在通力合作下最终圆满完成了该项任务。除此之外,也非常感谢整个课程阶段过程中凌睿老师在算法思路方面对我们进行的一系列教学与指导以及助教学长们在答疑时的倾力相助。

寻迹小车

一、绪论


1.1 实验背景
1.1.1 问题的情景

长期以来,由于我国是人口大国而且工业基础薄弱,因此早期在我国机器人的发展受到一定的限制。然而随着制造业工人的人力成本的不断上升与社会自动化程度的不断提高,我国也开始着重于发展机器人,并且也取得了较大的进步。在 1995 年,我国沈阳自动化所开始研制HT—100A点焊机器人,是我国较早的机器人了,如图1所示;此后,沈阳新松公司研发出了6 kg弧焊机器人,此机器人不仅实用,而且轻便,如图 2 所示;之后,哈尔滨工业大学机器 人研究所也研发出了便携式机器人,此机器人具有 6 自由度,增强了焊接能力,成为在恶劣环境中实现焊接功能的重要设备。总之,在国家“863 计划”与“十一五”计划的指导下,我国机器人的设计取得了飞速发 展,甚至在机器人的某些关键部件的设计已经接近于世界先进水平,并在世界工业机器人领域已经占有一席之地了。

1

2

1.1.2 实验的目的

目前,机器人的发展趋势非常的迅猛,机器人可以替代人类去从事高危险的工作,减轻了人类的劳动强度。本文通过对机器人的发展史进行简要的介绍,阐明了我国发展机器人的必要性。同时,对于我国的发展而言,我国正处于工业化进程的关键时期,将来的高强度、高危险行业的工人数量将会急剧的下降,机器人将会迎来新的“春天”,所以机器人的发展仍拥有巨大的发展空间。同时,由于我国各机器人的厂商对于机器人的研发能力与金钱投资的不同,在我国的机器人市场上的竞争也会愈演愈烈,最终也将形成我国的机器人研发市场。总之,在未来的几十年里,相信重点发展机器人将会成为社会的发展趋势,不久机器人将会引领未来,加入到我国现代化建设的行列中。小车,也就是轮式机器人,作为以学科交叉、产品创新为特色的明月班同学,切入这个产业不失为优秀的选择,故而选取小车为切入点了解相关知识。

1.2 实验内容
1.2.1 使用51单片机控制及其元器件

STC89C52控制板芯片、1.5V干电池x4、L298N电机驱动板x1、红外循迹模块、直流电机x2以及搭建材料若干;

3

1.2.2使用FPGA开发板控制及其元器件

Cyclonell EP2C5T144控制板芯片1.5V干电池x4、L298N电机驱动板x1、红外循迹模块、直流电机x2以及搭建材料若干;

4


二、实现过程


2.1 总体工作原理简释
2.1.2 红外循迹模块

第一步,位于小车前端的红外模块会释放红外线探测下方是否为黑色区域,并将相应的高低电平信号传递至控制模块(51单片机/FPGA开发板)处理,控制模块随后将发送信息至L298N电机驱动的控制模块,并由此控制左右两轮的转动速度以及转动方向,从而实现对黑线的反应和循迹。

作为电机的驱动模块,该模块对控制小车移动有着重要且直接的作用。

5

利用红外发射器向地面发射红外线,并用传感器接收由地面反射的红外线。当红外接收模块下方为黑色轨迹时,红外线被黑色轨迹吸收,传感器没有接收到红外线,红外循迹模块输出低电平到单片机。反之,传感器接收到红外线,红外循迹模块输出高电平到单片机。可通过红外循迹模块输出的信号来判断小车是否偏离轨迹。可调电阻可以调节传感器的灵敏度,易于调试。使用红外循迹模块方案也易于实现,红外循迹方案相比于摄像循迹成本更加便宜,软件设计更加简单,设计制作周期短,具备一定可靠性。

对于左电机,共有输入ENA、IN1、IN2,输出OUT1(黑线)、OUT2(红线)、其信号与运动对应如下:(0,X,X)停止、(1,0,0)停止、(1,1,0)正传、(1,0,1)反转、(1,1,1)停止;

对于右电机,共有输入ENB、IN3、IN4,输出OUT3(黑线)、OUT4(红线),其信号与运动对应如下:(0,X,X)停止、(1,0,0)停止、(1,1,0)反传、(1,0,1)正转、(1,1,1)停止。

2.1.3 L298N电机驱动模块

6

L298N是ST公司的一款电机驱动芯片,也是集成了双H桥,但与上面两个略有不同。电机驱动电压3~48V;可持续工作的输出电流为2A,峰值可达3A。如上图,L298N模块明显有较多的外接元件,这与L298N的内部结构有关。如上图,由于该芯片在H桥上的损耗严重发热较明显(饱和压降大),需要加装散热片,因此在使用上比前两个芯片复杂,体积也相对较大。其各引脚如下图所示。

7

2.2 使用51单片机部分
2.2.1 硬件接线

8

9

1为电源输入,与电池盒的输出线相连;2为电源输出,3为驱动板输入,两者需要相连,注意红线为VCC,黑线为GND;4 为单片机IO口引脚,5为驱动板的IN1到 IN4以及ENA和ENB,按照器件上的标注对应连接即可。 6 为与循迹模块的对应接口,按照器件上的标注对应连接即可。 7 和 8 为驱动板与两个电机之间的连线,按照上图所示连接即可。 到这里,基本完成了小车的硬件组装与线路连接,小车要完成循迹进行这些连线就够了,不过在烧录程序到单片机中时还需要 额外的连线,这个将在后面进行说明。

供电上使用四节5号电池。

2.2.2 程序设计

首先是如何处理红外模块的探测结果。我们需要先对结果进行编码。我们记没有识别到黑线为0,识别到为1,则我们需要一个算式来囊括左右传感器结果并能对不同情况进行表示。在这里,我们记data2为左边的结果,data3为右边的结果,现给出算式data1=data2*10+data3,data1即检测结果。根据data2、data3不同组合:(1,1)在黑线上;(1,0)略向右偏离;(0,1)略向左偏离;(0,0)完全偏离轨道,分别对应了data1的四个取值,即11、10、1、0,亦即四种情况。相应的,我们需要做出四种反馈,即“前进”、“左转”、“右转”、“停下”。

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
#include <reg52.h>//51头文件
unsigned char pwm\_val\_left, pwm\_val\_right; //中间变量
unsigned char pwm\_left, pwm\_right; //定义PWM输出高电平的时间的变量(用户操作PWM的变量)
#define PWM\_DUTY 100 //定义PWM的周期,数值为定时器0溢出周期,假如定时器溢出时间为100us,则PWM周期为10ms。
#define PWM\_HIGH\_MIN 35 //限制PWM输出的最小占空比
#define PWM\_HIGH\_MAX PWM\_DUTY //限制PWM输出的最大占空比

/\*电机驱动IO定义\*/
sbit leftMotorPwm = P1^5; //为1 左电机使能
sbit IN1 = P1^4; //为1 左电机正转
sbit IN2 = P1^3; //为1 左电机反转
sbit IN3 = P1^2; //为1 右电机反转
sbit IN4 = P1^1; //为1 右电机正转
sbit rightMotorPwm = P1^0; //为1 右电机使能

sbit leftSensor = P3^4;//左传感器:为0没有识别到黑线,为1识别到黑线
sbit rightSensor = P3^5;//右传感器:为0没有识别到黑线,为1识别到黑线

void Timer0\_Init(void); //定时器初始化
void LoadPWM(void);//装入PWM输出值
void forward(unsigned char LeftSpeed, unsigned char RightSpeed);//前进
void left\_run(unsigned char LeftSpeed, unsigned char RightSpeed);//左转
void right\_run(unsigned char LeftSpeed, unsigned char RightSpeed);//右转
void back(void);//后退修正

void Tracking()
{
//为0 没有识别到黑线 为1识别到黑线
char data1, data2 = leftSensor,data3 = rightSensor;
data1 = data2\*10+data3;
if(data1 == 11)//在黑线上,前进
{
//forward(120,120);//前进
forward(70,70);//前进
}
else
{
if(data1 == 10)//小幅偏右,左转
{
//left\_run(80,160);//左转
left\_run(70,70);//左转
}
if(data1 == 1)//小幅偏左,右转
{
//right\_run(160,80);//右转
right\_run(70,70);//右转
}
if(data1 == 0)//大幅偏左或偏右,已脱离轨道
{
back();//后退校正
}
}
}

/\*主函数\*/
void main(void)
{
Timer0\_Init();//定时0初始化
while(1)
{
Tracking();
}
}

void forward(unsigned char LeftSpeed,unsigned char RightSpeed)
{
pwm\_left = LeftSpeed,pwm\_right = RightSpeed;//设置速度
IN1 = 1;
IN2 = 0;
IN3 = 0;
IN4 = 1;
}

void left\_run(unsigned char LeftSpeed, unsigned char RightSpeed)
{
pwm\_left = LeftSpeed,pwm\_right = RightSpeed;//设置速度
IN1 = 1;
IN2 = 0;
IN3 = 1;
IN4 = 0;
}

void right\_run(unsigned char LeftSpeed, unsigned char RightSpeed)
{
pwm\_left = LeftSpeed,pwm\_right = RightSpeed;//设置速度
IN1 = 0;
IN2 = 1;
IN3 = 0;
IN4 = 1;
}

void back(void)
{
pwm\_left = LeftSpeed,pwm\_right = RightSpeed;//设置速度
IN1 = 0;
IN2 = 1;
IN3 = 1;
IN4 = 0;
}

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* Timer0初始化\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
void Timer0\_Init(void)
{
TMOD |= 0x02;//定时器0,8位自动重装模块
TH0 = 164;
TL0 = 164;//11.0592M晶振,12T溢出时间约等于100微秒
TR0 = 1;//启动定时器0
ET0 = 1;//允许定时器0中断
EA = 1;//总中断允许
}

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* Timer0中断函数\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
void timer0\_int (void) interrupt 1
{
pwm\_val\_left++;
pwm\_val\_right++;
if(pwm\_left > PWM\_HIGH\_MAX) pwm\_left = PWM\_HIGH\_MAX; //如果左输出写入大于最大占空比数据,则强制为最大占空比。
if(pwm\_left < PWM\_HIGH\_MIN) pwm\_left = PWM\_HIGH\_MIN; //如果左输出写入小于最小占空比数据,则强制为最小占空比。
if(pwm\_right > PWM\_HIGH\_MAX) pwm\_right = PWM\_HIGH\_MAX; //如果右输出写入大于最大占空比数据,则强制为最大占空比。
if(pwm\_right < PWM\_HIGH\_MIN) pwm\_right = PWM\_HIGH\_MIN; //如果右输出写入小于最小占空比数据,则强制为最小占空比。
if(pwm\_val\_left<=pwm\_left) leftMotorPwm = 1; //装载左PWM输出高电平时间
else leftMotorPwm = 0; //装载左PWM输出低电平时间
if(pwm\_val\_left>=PWM\_DUTY) pwm\_val\_left = 0; //如果左对比值大于等于最大占空比数据,则为零
if(pwm\_val\_right<=pwm\_right) rightMotorPwm = 1; //装载右PWM输出高电平时间
else rightMotorPwm = 0; //装载右PWM输出低电平时间
if(pwm\_val\_right>=PWM\_DUTY) pwm\_val\_right = 0; //如果右对比值大于等于最大占空比数据,则为零
}
2.3 使用FPGA开发板部分
2.3.1 硬件接线

系统时钟和复位信号必须为PIN17和PIN_90,不过这两个引脚在开发板上已经连接上了,无须手动连接。其它的引脚可以在下表中“FPGA引出I/O”部分选择即可,然后参照之间的51单片机进行连接。

此处附上接线实物图,需要注意的是,FPGA需要独立的接线供电,如充电宝等等。

10

2.3.2程序设计

逻辑上大体与51相同,此处附上代码部分以及引脚的设置图。

11

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
LIBRARY ieee;
USE ieee.std\_logic\_1164.all;
ENTITY cartracking IS
GENERIC (
--时钟为50MHz,为了产生100Hz的PWM波,设置计数值为500000
cnt\_meta : INTEGER := 500000;
--对应了停止、前进、左转、右转状态IN4到IN1的输出
Back : STD\_LOGIC\_VECTOR(3 DOWNTO 0) := "0110";
Forward : STD\_LOGIC\_VECTOR(3 DOWNTO 0) := "1001";
Left\_Go : STD\_LOGIC\_VECTOR(3 DOWNTO 0) := "0101";
Right\_Go : STD\_LOGIC\_VECTOR(3 DOWNTO 0) := "1010"
);

--\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*输入输出端口\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
PORT (
sys\_clk : IN STD\_LOGIC;
sys\_rst\_n : IN STD\_LOGIC;
infrared : IN STD\_LOGIC\_VECTOR(1 DOWNTO 0);
pwm\_left : OUT STD\_LOGIC;
pwm\_right : OUT STD\_LOGIC;
in\_motor : OUT STD\_LOGIC\_VECTOR(3 DOWNTO 0)
);
END cartracking;

ARCHITECTURE trans OF cartracking IS
SIGNAL cnt : INTEGER;
SIGNAL duty\_left : INTEGER;
SIGNAL duty\_right : INTEGER;
BEGIN
PROCESS (sys\_rst\_n, infrared)
BEGIN
IF (sys\_rst\_n = '0') THEN
duty\_right <= 60;
duty\_left <= 60;
ELSE
CASE infrared IS
WHEN "00" =>
in\_motor <= Back;--后退
WHEN "01" =>
in\_motor <= Right\_Go;--右转
--PWM波的占空比,应设置合适的值来控制小车的转速,为了在仿真时可以对比,特将左右轮设置了不同的占空比。
duty\_left <= 35;
duty\_right <= 55;
WHEN "10" =>
in\_motor <= Left\_Go;--左转
duty\_left <= 55;
duty\_right <= 35;
WHEN OTHERS =>
in\_motor <= Forward;--前进
duty\_left <= 50;
duty\_right <= 50;
END CASE;
END IF;
END PROCESS;

PROCESS (sys\_clk, sys\_rst\_n)
BEGIN
IF (sys\_rst\_n = '0') THEN
cnt <= 0;
ELSIF (sys\_clk'EVENT AND sys\_clk = '1') THEN
IF (cnt = cnt\_meta) THEN
cnt <= 0;
ELSE
cnt <= cnt + 1;
END IF;
END IF;
END PROCESS;

PROCESS (sys\_clk, sys\_rst\_n)
BEGIN
IF (sys\_rst\_n = '0') THEN
pwm\_left <= '0';
pwm\_right <= '0';
ELSIF (sys\_clk'EVENT AND sys\_clk = '1') THEN
IF (cnt >= (cnt\_meta / 100)\* duty\_left) THEN
pwm\_left <= '0';
ELSE
pwm\_left <= '1';
END IF;
IF (cnt >= (cnt\_meta / 100) \* duty\_right) THEN
pwm\_right <= '0';
ELSE
pwm\_right <= '1';
END IF;
END IF;
END PROCESS;
END trans;

3调试及优化


3.1简单优化

由于在测试时需要在保证小车前进速度的同时兼顾其转弯的效率和稳定性,特别是如果直行时转速过快会导致小车在转弯时直接冲出赛道而无法循迹。在原本的设计中,我们将未识别到黑线的反应设置为电机停转而使得小车停止,而这会使得小车无法在冲出赛道后进行自我校正。因此,我们将未识别到黑线时的输出信号由“0000”改为“0110”,即使得左右电机均由原本的停转改为反转,从而实现循迹过程中对于轨道循迹的自我修正。

在 PWM 频率设置的时候, PWM 的频率太低可能导致电机转动不稳定,不 是匀速转动,而 PWM 频率过高可能导致电机反应不过来或者超过电路的上限截止频率。事实上,考虑到转弯过程的稳定性与速度问题,包括与直行过程的速度以及传感器的灵敏度调节配合,我们需要通过实际测试来进一步确定在直行、左转、右转和倒退过程中设定的PWM占空比与转速。具体在调试之后所得到的合适参数已经在上面的代码中有所体现,在此不过多赘述。

12

13

3.2调试过程

考虑到验收时的重要评判标准是小车循迹一周的时间,且小车本身运动缓慢,我们首先将目光放在了转速的提高上。修改参数大幅提高了轮子的转速后,我们进行了一次实验:结果出乎意料,小车非但没有预想的那样,反而在行进的过程中持续摇摆。分析原因是行进角度不平行于轨道时容易冲出轨道,后续针对此原因,在红外灵敏度以及直行、左转、右转和倒退过程中设定的PWM占空比与转速多次调试与测试。中途红外模块损坏,经过排查确定后更换了新的。此外,我们注意到行进中的不稳定性还来自于万向轮的松散,我们尝试了不限于胶带、缠绳等各种方式加以限制,效果均不理想,虽然直道可以稳定快速行进,转弯却尤为吃力。

最后51的部分取得了第二名的不错成绩。但是FPGA部分却难遂人意。我们一直将注意力放在数据的调试上却忽略了时间的把控,以至于直到最后快结束才仓促进行测试,测试时还发生了接线断开等突发状况。我们本着希望更加灵活的愿望想别的同学借来充电宝供电,没想到这成为了测试失败的最大缘由——充电宝供电严重不足,导致小车行进乏力,但等到我们重新接上电脑供电确认可以正常运行时,却被告知时间已到,不允许再次测试以保证公平。最后无奈接受这个最慢的成绩。


参考文献


[1] 默默无闻小菜鸡. 电机驱动芯片(H桥、直流电机驱动方式)——DRV8833、TB6612、A4950、L298N的详解与比较[EB/OL]. https://blog.csdn.net/qq_44897194/article/details/105524808, 2020-5-11.

[2] 周海,叶兵. 机器人的发展现状及应用前景[J]. https://kns.cnki.net/kcms2/article/abstract?v=3uoqIhG8C44YLTlOAiTRKibYlV5Vjs7iAEhECQAQ9aTiC5BjCgn0Rn5ykE3W8_mbbrKtMuQk3r9gP-p4derKJErhs1XrNO9Y&uniplatform=NZKPT, 2017-6-18.


致谢


感谢老师们在本课程中的精心准备与付出。在数电和模电部分得到了曾正教授和袁刚教授的悉心教诲,在后续的项目部分得到了李敏教授和凌睿教授的认真指导,最终得以基本实现预定目标,特此鸣谢!