STM32平衡车开发实战教程:从零基础到项目精通

STM32平衡车开发实战教程:从零基础到项目精通

一、项目概述与基本原理

1.1 平衡车工作原理

平衡车是一种基于倒立摆原理的两轮自平衡小车,其核心控制原理类似于人类保持平衡的过程。当人站立不稳时,会通过腿部肌肉的快速调整来维持平衡。平衡车同样通过传感器检测车身倾斜角度,利用电机驱动实现动态平衡。

核心控制原理

  1. 姿态感知:通过MPU6050六轴传感器(三轴加速度计+三轴陀螺仪)实时检测小车的倾斜角度和角速度
  2. 控制算法:使用PID算法计算电机控制量,其中:
    • 比例项§快速响应角度偏差
    • 积分项(I)消除静态误差
    • 微分项(D)抑制振荡
  3. 执行机构:电机根据控制量调整转速,保持平衡

1.2 系统组成与功能

基本功能模块

  • 主控制器:STM32F103C8T6(性价比高,资源丰富)
  • 姿态传感器:MPU6050(检测倾角)
  • 电机驱动:TB6612(高效驱动电机)
  • 编码器:测量电机转速(反馈控制)
  • 电源管理:锂电池供电系统
  • 通信模块:蓝牙/WiFi(无线控制)
  • 显示模块:OLED(状态显示)

进阶功能扩展

  • 超声波避障
  • 红外循迹
  • 手机APP遥控
  • 语音控制

二、硬件设计与组装

2.1 硬件选型指南

部件推荐型号关键参数注意事项
主控芯片STM32F103C8T6Cortex-M3内核,72MHz主频,64KB Flash确保有足够定时器资源
姿态传感器MPU6050±2g加速度,±2000°/s陀螺仪注意安装方向与位置
电机MG315带编码器减速比1:30,编码器11线需配对使用
电机驱动TB6612FNG双通道,1.2A连续电流比L298N效率高
电源18650锂电池×312V供电需配保护板
蓝牙模块HC-06蓝牙4.0,串口通信注意主从模式
显示模块0.96寸OLEDI2C接口,128×64分辨率可选SPI接口版本

2.2 详细电路连接

STM32最小系统连接

  1. 8MHz晶振连接OSC_IN/OSC_OUT
  2. 复位电路连接NRST
  3. Boot0通过10K电阻接地
  4. 3.3V稳压电路(AMS1117-3.3)

MPU6050连接

  • VCC → 3.3V
  • GND → GND
  • SCL → PB6
  • SDA → PB7
  • INT → PA0(外部中断)

TB6612电机驱动连接

  • PWMA → PA8(TIM1_CH1)
  • PWMB → PA11(TIM1_CH4)
  • AIN1 → PC13, AIN2 → PC14
  • BIN1 → PC15, BIN2 → PD2
  • STBY → 3.3V(常使能)

编码器连接

  • 左编码器A相 → PA0(TIM2_CH1)
  • 左编码器B相 → PA1(TIM2_CH2)
  • 右编码器A相 → PB6(TIM4_CH1)
  • 右编码器B相 → PB7(TIM4_CH2)

电源系统设计

  1. 主电源:3节18650锂电池(12V)
  2. 5V降压:MP1584EN模块(为传感器供电)
  3. 3.3V稳压:AMS1117-3.3(为MCU和传感器供电)

2.3 PCB设计与制作

设计要点

  1. 电机驱动部分走线加宽(至少1mm)
  2. 模拟部分(传感器)与数字部分分开布局
  3. 添加电源滤波电容(10uF电解+0.1uF陶瓷)
  4. MPU6050尽量靠近MCU放置

常见问题解决

  • 电机干扰导致复位:加强电源滤波,缩短电机线长度
  • 传感器数据跳动:确保I2C线上拉电阻(4.7K)正确连接
  • 电机不转:检查STBY引脚电平,确认PWM信号正常

三、软件架构与核心算法

3.1 系统软件架构

分层设计

  1. 硬件抽象层(HAL)

    • 传感器驱动(MPU6050)
    • 电机驱动(TB6612)
    • 编码器接口
    • 通信接口(蓝牙/串口)
  2. 算法层

    • 姿态解算(互补滤波/卡尔曼滤波)
    • PID控制算法
    • 数据滤波处理
  3. 应用层

    • 任务调度
    • 人机交互(按键/显示)
    • 遥控处理
  4. 通信层

    • 蓝牙协议处理
    • 串口调试接口

3.2 姿态解算算法

互补滤波实现

// 互补滤波函数
float ComplementaryFilter(float accelAngle, float gyroRate, float dt, float alpha) {static float angle = 0;angle = alpha * (angle + gyroRate * dt) + (1 - alpha) * accelAngle;return angle;
}// 调用示例
void IMU_Update() {// 读取传感器原始数据MPU6050_ReadData(&accelX, &accelY, &accelZ, &gyroX, &gyroY, &gyroZ);// 计算加速度角度float accelAngle = atan2(accelY, accelZ) * 180.0 / PI;// 获取陀螺仪角速度(转换为度/秒)float gyroRate = gyroX / 16.4f;// 互补滤波float dt = 0.005f; // 5ms采样周期float alpha = 0.98f; // 滤波系数currentAngle = ComplementaryFilter(accelAngle, gyroRate, dt, alpha);
}

卡尔曼滤波实现

typedef struct {float Q_angle; // 过程噪声协方差float Q_bias;  // 过程噪声协方差float R_measure; // 测量噪声协方差float angle;  // 计算得到的最优角度float bias;   // 陀螺仪偏置float P[2][2]; // 误差协方差矩阵
} KalmanFilter;float Kalman_Update(KalmanFilter *kf, float newAngle, float newRate, float dt) {// 预测步骤kf->angle += dt * (newRate - kf->bias);kf->P[0][0] += dt * (dt*kf->P[1][1] - kf->P[0][1] - kf->P[1][0] + kf->Q_angle);kf->P[0][1] -= dt * kf->P[1][1];kf->P[1][0] -= dt * kf->P[1][1];kf->P[1][1] += kf->Q_bias * dt;// 更新步骤float y = newAngle - kf->angle;float S = kf->P[0][0] + kf->R_measure;float K[2];K[0] = kf->P[0][0] / S;K[1] = kf->P[1][0] / S;// 更新估计值kf->angle += K[0] * y;kf->bias += K[1] * y;// 更新协方差矩阵float P00_temp = kf->P[0][0];float P01_temp = kf->P[0][1];kf->P[0][0] -= K[0] * P00_temp;kf->P[0][1] -= K[0] * P01_temp;kf->P[1][0] -= K[1] * P00_temp;kf->P[1][1] -= K[1] * P01_temp;return kf->angle;
}

3.3 PID控制算法

串级PID实现

typedef struct {float Kp, Ki, Kd;float integral;float prevError;float integralLimit;
} PID_Controller;float PID_Update(PID_Controller *pid, float error, float dt) {// 比例项float proportional = pid->Kp * error;// 积分项pid->integral += error * dt;// 积分限幅if(pid->integral > pid->integralLimit) pid->integral = pid->integralLimit;else if(pid->integral < -pid->integralLimit) pid->integral = -pid->integralLimit;float integral = pid->Ki * pid->integral;// 微分项float derivative = pid->Kd * (error - pid->prevError) / dt;pid->prevError = error;return proportional + integral + derivative;
}// 直立环PD控制
float Balance_PID(float angle, float targetAngle, float gyroRate) {static PID_Controller pid = {20.0f, 0.0f, 0.5f, 0, 0, 1000};float error = angle - targetAngle;return PID_Update(&pid, error, 0.005f) + pid.Kd * gyroRate;
}// 速度环PI控制
float Velocity_PID(int encoderLeft, int encoderRight) {static PID_Controller pid = {0.3f, 0.001f, 0.0f, 0, 0, 10000};int speed = (encoderLeft + encoderRight) / 2; // 平均速度return PID_Update(&pid, -speed, 0.005f); // 目标速度为0
}

四、系统实现与调试

4.1 主程序框架

int main(void) {// 系统初始化HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_TIM1_Init(); // PWM定时器MX_TIM2_Init(); // 编码器1MX_TIM4_Init(); // 编码器2MX_I2C1_Init(); // MPU6050MX_USART1_UART_Init(); // 调试串口// 外设初始化MPU6050_Init();Motor_Init();Encoder_Init();OLED_Init();Bluetooth_Init();// 主循环while (1) {// 1. 读取传感器数据MPU6050_ReadData(&imuData);// 2. 姿态解算currentAngle = ComplementaryFilter(atan2(imuData.Accel_Y, imuData.Accel_Z) * RAD_TO_DEG,imuData.Gyro_X,0.005f, // 5ms0.98f);// 3. 读取编码器速度int speedLeft = Read_Encoder(TIM_ENCODER_LEFT);int speedRight = Read_Encoder(TIM_ENCODER_RIGHT);// 4. PID控制计算float balanceOut = Balance_PID(currentAngle, TARGET_ANGLE, imuData.Gyro_X);float speedOut = Velocity_PID(speedLeft, speedRight);// 5. 综合控制输出int motorOut = balanceOut + speedOut;// 6. 电机控制Motor_SetPWM(MOTOR_LEFT, motorOut);Motor_SetPWM(MOTOR_RIGHT, motorOut);// 7. 状态显示与通信if(HAL_GetTick() - lastDisplayTime >= 100) { // 100ms更新一次显示OLED_ShowAngle(currentAngle);Bluetooth_SendData(currentAngle);lastDisplayTime = HAL_GetTick();}HAL_Delay(5); // 5ms控制周期}
}

4.2 关键模块实现

MPU6050初始化与数据读取

void MPU6050_Init(void) {// 复位设备MPU6050_WriteByte(MPU6050_RA_PWR_MGMT_1, 0x80);HAL_Delay(100);// 唤醒设备,选择时钟源MPU6050_WriteByte(MPU6050_RA_PWR_MGMT_1, 0x01);// 设置陀螺仪量程 ±2000°/sMPU6050_WriteByte(MPU6050_RA_GYRO_CONFIG, 0x18);// 设置加速度计量程 ±2gMPU6050_WriteByte(MPU6050_RA_ACCEL_CONFIG, 0x00);// 设置低通滤波器带宽 44HzMPU6050_WriteByte(MPU6050_RA_CONFIG, 0x03);// 设置采样率 1kHzMPU6050_WriteByte(MPU6050_RA_SMPLRT_DIV, 0x00);
}void MPU6050_ReadData(MPU6050_Data *data) {uint8_t buf[14];MPU6050_ReadBytes(MPU6050_RA_ACCEL_XOUT_H, 14, buf);data->Accel_X = (int16_t)(buf[0] << 8 | buf[1]);data->Accel_Y = (int16_t)(buf[2] << 8 | buf[3]);data->Accel_Z = (int16_t)(buf[4] << 8 | buf[5]);data->Temp = (int16_t)(buf[6] << 8 | buf[7]);data->Gyro_X = (int16_t)(buf[8] << 8 | buf[9]);data->Gyro_Y = (int16_t)(buf[10] << 8 | buf[11]);data->Gyro_Z = (int16_t)(buf[12] << 8 | buf[13]);
}

编码器接口配置

void Encoder_Init(void) {TIM_Encoder_InitTypeDef sConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};// 编码器1配置(TIM2)htim2.Instance = TIM2;htim2.Init.Prescaler = 0;htim2.Init.CounterMode = TIM_COUNTERMODE_UP;htim2.Init.Period = 65535;htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;sConfig.EncoderMode = TIM_ENCODERMODE_TI12;sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;sConfig.IC1Prescaler = TIM_ICPSC_DIV1;sConfig.IC1Filter = 0;sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;sConfig.IC2Prescaler = TIM_ICPSC_DIV1;sConfig.IC2Filter = 0;HAL_TIM_Encoder_Init(&htim2, &sConfig);sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL);// 编码器2配置(TIM4)类似...
}

4.3 PID参数整定方法

调参步骤

  1. 确定机械中值

    • 将小车放在地面上,寻找能够自然平衡的角度
    • 记录这个角度作为TARGET_ANGLE(通常在-3°到3°之间)
  2. 直立环调参

    • 先调Kp(比例项):
      • 从较小值开始(如10)
      • 逐渐增大直到小车出现低频振荡
      • 典型值范围:20-50
    • 再调Kd(微分项):
      • 从0.1开始
      • 逐渐增大抑制振荡
      • 过大则会出现高频抖动
      • 典型值范围:0.3-0.8
  3. 速度环调参

    • 先调Kp:
      • 从0.1开始
      • 增大使小车能抵抗外力
      • 过大则会出现前后摆动
      • 典型值范围:0.2-0.5
    • Ki与Kp保持比例关系(Ki ≈ Kp/200):
      • 消除静态误差
      • 过大则积分饱和
  4. 转向环调参(可选)

    • 使用单独的Kp控制
    • 根据转向灵敏度调整
    • 典型值范围:0.1-1.0

调试技巧

  • 使用蓝牙或串口实时调整参数
  • 记录数据并分析响应曲线
  • 采用"试凑法"结合理论分析
  • 先调内环再调外环

五、进阶优化与功能扩展

5.1 系统优化策略

实时性优化

  1. 使用定时器中断确保控制周期精确

    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM6) { // 5ms定时器// 执行控制算法Control_Task();}
    }
    
  2. 优化传感器数据读取速度

    • 使用DMA传输减少CPU开销
    • 提高I2C时钟频率(400kHz)
  3. 关键代码使用汇编优化

    • PID计算等关键算法

稳定性优化

  1. 增加软件看门狗
  2. 异常状态检测与保护
    • 角度过大时切断电机
    • 通信异常处理

5.2 功能扩展实现

蓝牙遥控功能

void Bluetooth_Process(void) {if(UART_Receive(&huart3, &bluetoothData, 1) == HAL_OK) {switch(bluetoothData) {case 'F': targetSpeed += 10; break; // 前进case 'B': targetSpeed -= 10; break; // 后退case 'L': turnOffset = -5; break;   // 左转case 'R': turnOffset = 5; break;    // 右转case 'S': targetSpeed = 0; break;   // 停止}}
}

超声波避障功能

float Ultrasonic_GetDistance(void) {// 触发信号HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);HAL_Delay(0.01);HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);// 等待回波while(HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin) == GPIO_PIN_RESET);uint32_t start = HAL_GetTick();while(HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin) == GPIO_PIN_SET);uint32_t end = HAL_GetTick();// 计算距离(cm)return (end - start) * 0.034 / 2;
}

数据记录与分析

  1. 使用SD卡模块记录运行数据
  2. 通过无线模块上传到云端
  3. 使用MATLAB/Python分析数据

六、项目总结与进阶学习

6.1 常见问题解决

问题1:小车无法保持平衡

  • 检查传感器数据是否正确
  • 确认PID参数极性是否正确
  • 检查电机转向是否正确

问题2:小车出现高频振荡

  • 减小微分项Kd
  • 检查机械结构是否牢固
  • 增加传感器数据滤波

问题3:小车向一边偏移

  • 检查机械结构对称性
  • 校准传感器
  • 调整机械中值

6.2 学习资源推荐

开源项目参考

  1. 平衡小车之家开源项目
  2. Cleanflight/Betaflight飞控代码
  3. 小马哥四轴开源项目

推荐书籍

  • 《STM32库开发实战指南》
  • 《自动控制原理》
  • 《嵌入式实时操作系统》

进阶方向

  1. 改用RTOS实现多任务
  2. 加入机器学习算法
  3. 实现集群控制
  4. 开发手机APP控制界面

6.3 项目展示与分享

博客撰写要点

  1. 项目背景与意义
  2. 系统设计与实现
  3. 关键技术难点与解决方案
  4. 效果展示(视频/图片)
  5. 经验总结与未来改进

面试项目介绍要点

  • 突出技术难点和解决方案
  • 展示对系统原理的深入理解
  • 说明个人贡献和收获
  • 准备技术细节的深入讨论

通过本教程,您已经掌握了STM32平衡车从硬件设计到软件实现的完整开发流程。建议按照步骤实际动手实践,在实践中深化理解。平衡车项目是学习嵌入式系统和控制算法的绝佳平台,希望您能在此基础上不断探索和创新!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/901527.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#设计模式-状态模式

状态模式案例解析&#xff1a;三态循环灯的实现 案例概述 本案例使用 状态模式&#xff08;State Pattern&#xff09; 实现了一个 三态循环灯 的功能。每点击一次按钮&#xff0c;灯的状态会按顺序切换&#xff08;状态1 → 状态2 → 状态3 → 状态1...&#xff09;&#xff…

Mac系统升级node.js版本和npm版本并安装pnpm

1.升级node.js版本 第一步&#xff1a;查询当前node.js版本 node -v第二步&#xff1a;清除node.js的缓存 sudo npm cache clean -f第三步&#xff1a;验证缓存是否清空 npm cache verify第四步&#xff1a;安装n工具&#xff0c;n工具是专门用于管理node.js版本的工具 su…

[net 5] udp_dict_server 基于udp的简单字典翻译(服务器与业务相分离)

目录 1. 功能了解 1.1. 啥是 dic_server? 1.2. dic_server 的小目标 2. 基本框架 2.1. 基本文件框架 2.2. 业务与服务器解耦 -> 回调函数 3. 字典 3.1. 字典配置文件 3.2. 构建字典类 3.2.1. 字典类的基本成员 3.2.2. 字典类构造 3.2.2.1. 构造 3.2.2.2. 信息加…

七种驱动器综合对比——《器件手册--驱动器》

九、驱动器 名称 功能与作用 工作原理 优势 应用 隔离式栅极驱动器 隔离式栅极驱动器用于控制功率晶体管&#xff08;如MOSFET、IGBT、SiC或GaN等&#xff09;的开关&#xff0c;其核心功能是将控制信号从低压侧传输到高压侧的功率器件栅极&#xff0c;同时在输入和输出之…

EM储能网关ZWS智慧储能云应用(8) — 电站差异化支持

面对不同项目、种类繁多的储能产品&#xff0c;如何在储能云平台上进行电站差异化支持尤为关键&#xff0c;ZWS智慧储能云从多方面支持储能电站差异化。 简介 随着行业发展&#xff0c;市场“内卷”之下&#xff0c;各大储能企业推陈出新的速度加快。面对不同项目、种类繁多…

图像预处理-色彩空间补充,灰度化与二值化

一.图像色彩空间转换 1.1 HSV颜色空间 HSV颜色空间使用色调&#xff08;Hue&#xff09;、饱和度&#xff08;Saturation&#xff09;和亮度&#xff08;Value&#xff09;三个参数来表示颜色 一般对颜色空间的图像进行有效处理都是在HSV空间进行的&#xff0c;然后对于基本…

Midnight Flag CTF 2025

周末还是三个比赛&#xff0c;可惜不好弄。不是远端连不上就是远端打不开。再有就是太难了。 Crypto ABC 这个题还是不算难的。给了两个30位数的平方和&#xff0c;并且pu1*baser0,qu2*baser1其中r 都很小&#xff0c;可以copper。 只是sage里的two_squres不管用&#xff0…

深度学习--激活函数

激活函数通过计算加权和并加上偏置来确定神经元是否应该倍激活&#xff0c;它们将输入信号转换为输出的可微运算。大多数激活函数都是非线性的&#xff0c;由于激活函数是深度学习的基础&#xff0c;下面简要介绍一些常见的激活函数。 1 RelU函数 最受欢迎的激活函数是修正线性…

深入解析 OrdinalEncoder 与 OneHotEncoder:核心区别与实战应用

标题&#xff1a;深入解析 OrdinalEncoder 与 OneHotEncoder&#xff1a;核心区别与实战应用 摘要&#xff1a; 本文详细探讨了机器学习中类别特征编码的两种核心方法——OrdinalEncoder 和 OneHotEncoder。通过对比两者的功能、特点、适用场景及代码实现&#xff0c;帮助读者…

CTF web入门之命令执行 完整版

web29 文件名过滤 由于flag被过滤,需要进行文件名绕过,有以下几种方法: 1.通配符绕过 fla?.* 2.反斜杠绕过 fl\ag.php 3.双引号绕过 fl’‘ag’.php 还有特殊变量$1、内联执行等 此外 读取文件利用cat函数,输出利用system、passthru 、echo echo `nl flag.php`; ec…

【Linux实践系列】:用c/c++制作一个简易的进程池

&#x1f525; 本文专栏&#xff1a;Linux Linux实践项目 &#x1f338;作者主页&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客励志语录&#xff1a; 人生没有标准答案&#xff0c;你的错题本也能写成传奇。 ★★★ 本文前置知识&#xff1a; 匿名管道 1.前置知识回顾…

2.2 函数返回值

1.回顾def def sum(x,y): return xy res sum(10,20) #调用函数 print(res) 2.函数的三个重要属性 -函数的类型&#xff1a;function -函数的ID&#xff1a;16进制的整数数值 -函数的值&#xff1a;封装在函数中的数据和代码 # - 函数是一块内存空间&#xff0c;通过…

【3GPP核心网】【5G】精讲5G网络语音业务系统架构

1. 欢迎大家订阅和关注,精讲3GPP通信协议(2G/3G/4G/5G/IMS)知识点,专栏会持续更新中.....敬请期待! 目录 1. 音视频业务 2. 消息类业务 SMS over IMS SMS over NAS 3. 互联互通架构 3.1 音视频业务互通场景 3.2 5G 用户与 5G 用户互通 3.3 5G 用户与 4G 用户的互通…

系统环境变量有什么实际作用,为什么要配置它

系统环境变量有什么实际作用,为什么要配置它 系统环境变量具有以下重要实际作用: 指定程序路径:操作系统通过环境变量来知晓可执行文件、库文件等的存储位置例如,当你在命令提示符或终端中输入一个命令时,系统会根据环境变量PATH中指定的路径去查找对应的可执行文件。如果…

qt/C++面试题自用学习(更新中)

最近在找工作…面试中遇到了的问题总以为自己会但回答的时候磕磕巴巴&#xff0c;觉得还是要总结一下&#xff1a; vector和list的区别 vector list 底层数据结构 基于动态数组实现&#xff0c;元素在内存中连续存储 基于双向链表实现&#xff0c;元素在内存中非连续存储&…

Day09【基于Tripletloss实现的简单意图识别对话系统】

基于Tripletloss实现的表示型文本匹配 目标数据准备参数配置数据处理Triplet Loss目标Triplet Loss计算公式公式说明 模型构建网络结构设计网络训练目标损失函数设计 主程序推理预测类初始化加载问答知识库文本向量化知识库查询主程序main测试测试效果 参考博客 目标 在此之前…

说说什么是幂等性?

大家好&#xff0c;我是锋哥。今天分享关于【说说什么是幂等性&#xff1f;】面试题。希望对大家有帮助&#xff1b; 说说什么是幂等性&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 幂等性&#xff08;Idempotence&#xff09; 是指在某些操作或请求…

【自相关】全局 Moran’s I 指数

自相关&#xff08;Autocorrelation&#xff09;&#xff0c;也称为序列相关性&#xff0c;指的是同一变量在不同时间或空间点的值之间的关系。简而言之&#xff0c;自相关就是一个变量与自身在不同位置或时间点的相关性 自相关&#xff1a;针对同一属性之间进行分析相关性 本…

【C#】Html转Pdf,Spire和iTextSharp结合,.net framework 4.8

&#x1f339;欢迎来到《小5讲堂》&#x1f339; &#x1f339;这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。&#x1f339; &#x1f339;温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01;&#…