直流无刷电机控制(FOC):电流模式

news2025/1/11 17:47:47

目录

概述

1 系统框架结构

1.1 硬件模块介绍

1.2 硬件实物图

1.3 引脚接口定义

2 代码实现

2.1 软件架构

2.2 电流检测函数

3 电流环功能实现

3.1 代码实现

3.2 测试代码实现

4 测试


概述

本文主要介绍基于DengFOC的库函数,实现直流无刷电机控制(FOC)的电流环控制。笔者详细介绍了电流环采样电流时用到的函数。DengFOC的软件架构,电流环模式实现的原理等内容。

源代码下载地址:

dengfoctestdemo资源-CSDN文库

1 系统框架结构

1.1 硬件模块介绍

系统硬件框架结构功能如下:

电机模块: 2208直流无刷电机(数量:1)

编码器:  选用AS5600编码器,用于获取当前电机转动的角度,其通过I2C接口与MCU进行通信

驱动板(FOC): 通过接收到MCU传送的PWM芯片,直接作用到MOS管上,以驱动直流无刷电机工作。

主控模块:使用ESP32 ( ESP32-WROOM-32E)

电流检测功能: 使用MCU ADC功能检测INA240的输出电压值

1.2 硬件实物图

1.3 引脚接口定义

 1) 电机驱动板与电机之间的接口

2)编码器与MCU接口

3)电流检测

2 代码实现

2.1 软件架构

2.2 电流检测函数

1)源代码介绍

代码12行: 定义参考电压值

代码13行: ADC的最大值(12bit )

代码16: 计算比率

代码25~26行: 定义ADC的端口

代码28行: 分流电阻

代码29行: 电流放大倍数

代码31行: 电流放大的比率 

代码55~59行: 获取ADC的count值

代码61~66行: 配置ADC的端口模式

​ 

代码69~91行: 获取ADC的均值 

代码93~99行:  读电流参数初始化

代码104~109行:  获取电流值

 2)源代码文件

编写InlineCurrent.c文件的内容

#include <Arduino.h> 
#include "InlineCurrent.h"


//  - shunt_resistor  - 分流电阻值
//  - gain  - 电流检测运算放大器增益
//  - phA   - A 相 adc 引脚
//  - phB   - B 相 adc 引脚
//  - phC   - C 相 adc 引脚(可选)


#define _ADC_VOLTAGE 3.3f            //ADC 电压
#define _ADC_RESOLUTION 4095.0f      //ADC 分辨率

// ADC 计数到电压转换比率求解
#define _ADC_CONV ( (_ADC_VOLTAGE) / (_ADC_RESOLUTION) )

#define NOT_SET -12345.0
#define _isset(a) ( (a) != (NOT_SET) )

CurrSense::CurrSense(int Mot_Num)
{
  if(Mot_Num==0)
  {
    pinA = 39;
    pinB = 36;
    //int pinC;
    _shunt_resistor = 0.01;
    amp_gain  = 50;
    
    volts_to_amps_ratio = 1.0f /_shunt_resistor / amp_gain; // volts to amps
    
    // gains for each phase
    gain_a = volts_to_amps_ratio*-1;
    gain_b = volts_to_amps_ratio*-1;
    gain_c = volts_to_amps_ratio;
  }

  if(Mot_Num==1)
  {
    pinA = 35;
    pinB = 34;
    //int pinC;
    _shunt_resistor = 0.01;
    amp_gain  = 50;
    
    volts_to_amps_ratio = 1.0f /_shunt_resistor / amp_gain; // volts to amps
    
    // gains for each phase
    gain_a = volts_to_amps_ratio*-1;
    gain_b = volts_to_amps_ratio*-1;
    gain_c = volts_to_amps_ratio;
  }
}
float CurrSense::readADCVoltageInline(const int pinA)
{
  uint32_t raw_adc = analogRead(pinA);
  return raw_adc * _ADC_CONV;
}

void CurrSense::configureADCInline(const int pinA,const int pinB, const int pinC)
{
  pinMode(pinA, INPUT);
  pinMode(pinB, INPUT);
  if( _isset(pinC) ) 
     pinMode(pinC, INPUT);
}

// 查找 ADC 零偏移量的函数
void CurrSense::calibrateOffsets()
{
    const int calibration_rounds = 1000;

    // 查找0电流时候的电压
    offset_ia = 0;
    offset_ib = 0;
    offset_ic = 0;
    // 读数1000次
    for (int i = 0; i < calibration_rounds; i++) 
    {
        offset_ia += readADCVoltageInline(pinA);
        offset_ib += readADCVoltageInline(pinB);
        if(_isset(pinC)) offset_ic += readADCVoltageInline(pinC);
        delay(1);
    }

    // 求平均,得到误差
    offset_ia = offset_ia / calibration_rounds;
    offset_ib = offset_ib / calibration_rounds;
    if(_isset(pinC)) 
      offset_ic = offset_ic / calibration_rounds;
}

void CurrSense::init()
{
    // 配置函数
    configureADCInline(pinA,pinB,pinC);
    // 校准
    calibrateOffsets();
}


// 读取全部三相电流

void CurrSense::getPhaseCurrents()
{
    current_a = (readADCVoltageInline(pinA) - offset_ia)*gain_a;// amps
    current_b = (readADCVoltageInline(pinB) - offset_ib)*gain_b;// amps
    current_c = (!_isset(pinC)) ? 0 : (readADCVoltageInline(pinC) - offset_ic)*gain_c; // amps
}

编写InlineCurrent.h文件的内容

#include <Arduino.h>

class CurrSense
{
  public:
    CurrSense(int Mot_Num);
    float readADCVoltageInline(const int pinA);
    void configureADCInline(const int pinA,const int pinB, const int pinC);
    void calibrateOffsets();
    void init();
    void getPhaseCurrents();
    float current_a,current_b,current_c;
    int pinA;
    int pinB;
    int pinC;
    float offset_ia;
    float offset_ib;
    float offset_ic;
    float _shunt_resistor;
    float amp_gain;
    
    float volts_to_amps_ratio;
    
    float gain_a;
    float gain_b;
    float gain_c;
  private:
    int _Mot_Num;
};

3 电流环功能实现

3.1 代码实现

代码29行: 设置电流环的PID参数

代码36行: 创建电流环的Obj

代码57~63行: 设置电流环参数PID函数

代码271~278行: 获取电流数据函数

代码283~293行: 获取IQ电流值

代码295~300行: 电流滤波函数

dengFOC.c 源文件内容:

#include <Arduino.h> 
#include "AS5600.h"
#include "lowpass_filter.h"
#include "pid.h"
#include "InlineCurrent.h"   //引入在线电流检测

#define _1_SQRT3 0.57735026919f
#define _2_SQRT3 1.15470053838f
//低通滤波初始化
LowPassFilter M0_Vel_Flt = LowPassFilter(0.01); // Tf = 10ms   //M0速度环
LowPassFilter M0_Curr_Flt = LowPassFilter(0.05); // Tf = 5ms   //M0电流环

#define _constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
float voltage_power_supply;
float Ualpha,Ubeta=0,Ua=0,Ub=0,Uc=0;

#define _3PI_2 4.71238898038f
float zero_electric_angle=0;

int PP=1,DIR=1;
int pwmA = 32;
int pwmB = 33;
int pwmC = 25;

//PID
PIDController vel_loop_M0 = PIDController{.P = 2, .I = 0, .D = 0, .ramp = 100000, .limit = voltage_power_supply/2};
PIDController angle_loop_M0 = PIDController{.P = 2, .I = 0, .D = 0, .ramp = 100000, .limit = 100};

PIDController current_loop_M0 = PIDController{.P = 1.2, .I = 0, .D = 0, .ramp = 100000, .limit = 12.6};

//AS5600
Sensor_AS5600 S0=Sensor_AS5600(0);
TwoWire S0_I2C = TwoWire(0);

//初始化电流闭环
CurrSense CS_M0= CurrSense(0);

//=================PID 设置函数=================
//速度PID
void DFOC_M0_SET_VEL_PID(float P,float I,float D,float ramp)   //M0角度环PID设置
{
  vel_loop_M0.P=P;
  vel_loop_M0.I=I;
  vel_loop_M0.D=D;
  vel_loop_M0.output_ramp=ramp;
}

//角度PID
void DFOC_M0_SET_ANGLE_PID(float P,float I,float D,float ramp)   //M0角度环PID设置
{
  angle_loop_M0.P=P;
  angle_loop_M0.I=I;
  angle_loop_M0.D=D;
  angle_loop_M0.output_ramp=ramp;
}

void DFOC_M0_SET_CURRENT_PID(float P,float I,float D,float ramp)    //M0电流环PID设置
{
  current_loop_M0.P=P;
  current_loop_M0.I=I;
  current_loop_M0.D=D;
  current_loop_M0.output_ramp=ramp;
}



//M0速度PID接口
float DFOC_M0_VEL_PID(float error)   //M0速度环
{
   return vel_loop_M0(error);
   
}

//M0角度PID接口
float DFOC_M0_ANGLE_PID(float error)
{
  return angle_loop_M0(error);
}


//初始变量及函数定义
#define _constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
//宏定义实现的一个约束函数,用于限制一个值的范围。
//具体来说,该宏定义的名称为 _constrain,接受三个参数 amt、low 和 high,分别表示要限制的值、最小值和最大值。该宏定义的实现使用了三元运算符,根据 amt 是否小于 low 或大于 high,返回其中的最大或最小值,或者返回原值。
//换句话说,如果 amt 小于 low,则返回 low;如果 amt 大于 high,则返回 high;否则返回 amt。这样,_constrain(amt, low, high) 就会将 amt 约束在 [low, high] 的范围内。1


// 归一化角度到 [0,2PI]
float _normalizeAngle(float angle)
{
  float a = fmod(angle, 2*PI);   //取余运算可以用于归一化,列出特殊值例子算便知
  return a >= 0 ? a : (a + 2*PI);  
  //三目运算符。格式:condition ? expr1 : expr2 
  //其中,condition 是要求值的条件表达式,如果条件成立,则返回 expr1 的值,否则返回 expr2 的值。可以将三目运算符视为 if-else 语句的简化形式。
  //fmod 函数的余数的符号与除数相同。因此,当 angle 的值为负数时,余数的符号将与 _2PI 的符号相反。也就是说,如果 angle 的值小于 0 且 _2PI 的值为正数,则 fmod(angle, _2PI) 的余数将为负数。
  //例如,当 angle 的值为 -PI/2,_2PI 的值为 2PI 时,fmod(angle, _2PI) 将返回一个负数。在这种情况下,可以通过将负数的余数加上 _2PI 来将角度归一化到 [0, 2PI] 的范围内,以确保角度的值始终为正数。
}


// 设置PWM到控制器输出
void setPwm(float Ua, float Ub, float Uc) 
{
  // 限制上限
  Ua = _constrain(Ua, 0.0f, voltage_power_supply);
  Ub = _constrain(Ub, 0.0f, voltage_power_supply);
  Uc = _constrain(Uc, 0.0f, voltage_power_supply);
  // 计算占空比
  // 限制占空比从0到1
  float dc_a = _constrain(Ua / voltage_power_supply, 0.0f , 1.0f );
  float dc_b = _constrain(Ub / voltage_power_supply, 0.0f , 1.0f );
  float dc_c = _constrain(Uc / voltage_power_supply, 0.0f , 1.0f );

  //写入PWM到PWM 0 1 2 通道
  ledcWrite(0, dc_a*255);
  ledcWrite(1, dc_b*255);
  ledcWrite(2, dc_c*255);
}

void setTorque(float Uq,float angle_el) 
{
  S0.Sensor_update(); //更新传感器数值
  Uq=_constrain(Uq,-(voltage_power_supply)/2,(voltage_power_supply)/2);
  float Ud=0;
  angle_el = _normalizeAngle(angle_el);
  // 帕克逆变换
  Ualpha =  -Uq*sin(angle_el); 
  Ubeta =   Uq*cos(angle_el); 

  // 克拉克逆变换
  Ua = Ualpha + voltage_power_supply/2;
  Ub = (sqrt(3)*Ubeta-Ualpha)/2 + voltage_power_supply/2;
  Uc = (-Ualpha-sqrt(3)*Ubeta)/2 + voltage_power_supply/2;
  setPwm(Ua,Ub,Uc);
}

void DFOC_Vbus(float power_supply)
{
  voltage_power_supply=power_supply;

  pinMode(pwmA, OUTPUT);
  pinMode(pwmB, OUTPUT);
  pinMode(pwmC, OUTPUT);

  ledcSetup(0, 30000, 8);  //pwm频道, 频率, 精度
  ledcSetup(1, 30000, 8);  //pwm频道, 频率, 精度
  ledcSetup(2, 30000, 8);  //pwm频道, 频率, 精度

  ledcAttachPin(pwmA, 0);
  ledcAttachPin(pwmB, 1);
  ledcAttachPin(pwmC, 2);

  Serial.println("完成PWM初始化设置");

  //AS5600
  S0_I2C.begin(19,18, 400000UL);
  S0.Sensor_init(&S0_I2C);   //初始化编码器0
  Serial.println("编码器加载完毕");

  //PID 加载
  vel_loop_M0 = PIDController{.P = 2, .I = 0, .D = 0, .ramp = 100000, .limit = voltage_power_supply/2};

   //初始化电流传感器
   CS_M0.init();
 }


float _electricalAngle()
{
  return  _normalizeAngle((float)(DIR *  PP) * S0.getMechanicalAngle()-zero_electric_angle);
}


void DFOC_alignSensor(int _PP,int _DIR)
{  
  PP=_PP;
  DIR=_DIR;
  setTorque(3, _3PI_2);  //起劲
  delay(1000);
  S0.Sensor_update();  //更新角度,方便下面电角度读取
  zero_electric_angle=_electricalAngle();
  setTorque(0, _3PI_2);  //松劲(解除校准)
  Serial.print("0电角度:");
  Serial.println(zero_electric_angle);
}

float DFOC_M0_Angle()
{
  return DIR*S0.getAngle();
}

//无滤波
//float DFOC_M0_Velocity()
//{
//  return DIR*S0.getVelocity();
//}

//有滤波
float DFOC_M0_Velocity()
{
  //获取速度数据并滤波
  float vel_M0_ori=S0.getVelocity();
  float vel_M0_flit=M0_Vel_Flt(DIR*vel_M0_ori);
  return vel_M0_flit;   //考虑方向
}

//==============串口接收==============
float motor_target;
int commaPosition;
String serialReceiveUserCommand() {
  
  // a string to hold incoming data
  static String received_chars;
  
  String command = "";

  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the string buffer:
    received_chars += inChar;

    // end of user input
    if (inChar == '\n') {
      
      // execute the user command
      command = received_chars;

      commaPosition = command.indexOf('\n');//检测字符串中的逗号
      if(commaPosition != -1)//如果有逗号存在就向下执行
      {
          motor_target = command.substring(0,commaPosition).toDouble();            //电机角度
          Serial.println(motor_target);
      }
      // reset the command buffer 
      received_chars = "";
    }
  }
  return command;
}


float serial_motor_target()
{
  return motor_target;
}



//================简易接口函数================
void DFOC_M0_set_Velocity_Angle(float Target)
{
 setTorque(DFOC_M0_VEL_PID(DFOC_M0_ANGLE_PID((Target-DFOC_M0_Angle())*180/PI)),_electricalAngle());   //角度闭环
}

void DFOC_M0_setVelocity(float Target)
{
  setTorque(DFOC_M0_VEL_PID((serial_motor_target()-DFOC_M0_Velocity())*180/PI),_electricalAngle());   //速度闭环
}

void DFOC_M0_set_Force_Angle(float Target)   //力位
{
  setTorque(DFOC_M0_ANGLE_PID((Target-DFOC_M0_Angle())*180/PI),_electricalAngle());
}

void DFOC_M0_setTorque(float Target)
{
  setTorque(Target,_electricalAngle());
}


void runFOC()
{
  //====传感器更新====
 // S0.Sensor_update();
  CS_M0.getPhaseCurrents();
  
  //====传感器更新====
}

//=========================电流读取=========================

//通过Ia,Ib,Ic计算Iq,Id(目前仅输出Iq)
float cal_Iq_Id(float current_a,float current_b,float angle_el)
{
  float I_alpha=current_a;
  float I_beta = _1_SQRT3 * current_a + _2_SQRT3 * current_b;

  float ct = cos(angle_el);
  float st = sin(angle_el);
  //float I_d = I_alpha * ct + I_beta * st;
  float I_q = I_beta * ct - I_alpha * st;
  return I_q;
}

float DFOC_M0_Current()
{  
  float I_q_M0_ori=cal_Iq_Id(CS_M0.current_a,CS_M0.current_b,_electricalAngle());
  float I_q_M0_flit=M0_Curr_Flt(I_q_M0_ori);
  return I_q_M0_flit;  
}

dengFOC.h 源文件内容:

//灯哥开源,遵循GNU协议,转载请著名版权!
//GNU开源协议(GNU General Public License, GPL)是一种自由软件许可协议,保障用户能够自由地使用、研究、分享和修改软件。
//该协议的主要特点是,要求任何修改或衍生的作品必须以相同的方式公开发布,即必须开源。此外,该协议也要求在使用或分发软件时,必须保留版权信息和许可协议。GNU开源协议是自由软件基金会(FSF)制定和维护的一种协议,常用于GNU计划的软件和其他自由软件中。
//仅在DengFOC官方硬件上测试过,欢迎硬件购买/支持作者,淘宝搜索店铺:灯哥开源
//你的支持将是接下来做视频和持续开源的经费,灯哥在这里先谢谢大家了
//函数声明

void setPwm(float Ua, float Ub, float Uc);
float setTorque(float Uq,float angle_el);
float _normalizeAngle(float angle);
void DFOC_Vbus(float power_supply);
void DFOC_alignSensor(int _PP,int _DIR);
float _electricalAngle();

float serial_motor_target();
String serialReceiveUserCommand();
//传感器读取
float DFOC_M0_Velocity();
float DFOC_M0_Angle();
//PID
void DFOC_M0_SET_ANGLE_PID(float P,float I,float D,float ramp);
void DFOC_M0_SET_VEL_PID(float P,float I,float D,float ramp);
float DFOC_M0_VEL_PID(float error);
float DFOC_M0_ANGLE_PID(float error);
void DFOC_M0_SET_CURRENT_PID(float P,float I,float D,float ramp);

//接口函数
void DFOC_M0_set_Velocity_Angle(float Target);
void DFOC_M0_setVelocity(float Target);
void DFOC_M0_set_Force_Angle(float Target);
void DFOC_M0_setTorque(float Target);

float DFOC_M0_Current();
float cal_Iq_Id(float current_a,float current_b,float angle_el);

void runFOC();

3.2 测试代码实现

代码37行: 设置供电电压

代码38行: 设置电极数和编码器的方向

代码57行: 获取电流参数

代码58行: 设置PID参数

代码59行:设置执行单元

源代码如下:

/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name    : foc_function_test.c
* Description  : FOC 闭环各种模式测试
******************************************************************************
* @attention
*
* COPYRIGHT:    Copyright (c) 2025 tangmingfei2013@126.com 

* CREATED BY:   Alan.tang
* DATE:         JAN 7th, 2025
*  参考代码:    Deng FOC
*
******************************************************************************
*/
/* USER CODE END Header */

#include "DengFOC.h"
const int LED_PIN = 2;

int Sensor_DIR=-1;    //传感器方向
int Motor_PP=7;       //电机极对数
float Sensor_Vel;

/*
  0: 电流模式   
  1: 速度模式
  2: 位置模式
*/
#define SELECT_MODE        0


void setup() 
{
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
  digitalWrite(LED_PIN, HIGH);
  
  // put your setup code here, to run once:
  Serial.begin(115200);

  DFOC_Vbus(11.6);            //设定驱动器供电电压
  DFOC_alignSensor(Motor_PP,Sensor_DIR);

#if SELECT_MODE == 0
  // 设置电流模式闭环PID
  DFOC_M0_SET_CURRENT_PID(5,200,0,100000);

#elif SELECT_MODE == 1
  // 设置速度闭环PID
  DFOC_M0_SET_VEL_PID(0.01,0.00,0,0);

#elif SELECT_MODE == 2
  //设置位置模式闭环PID
  DFOC_M0_SET_VEL_PID(0.01,0.00,0,0);
  DFOC_M0_SET_ANGLE_PID(0.5,0,0,0);
#endif 

}

void postion_Mode_test( void )
{
  //设置速度
   DFOC_M0_set_Velocity_Angle(serial_motor_target());
}

void velocity_Mode_test( void )
{
  //设置速度
   DFOC_M0_setVelocity(serial_motor_target());
}

void current_Mode_test( void )
{
  static int count=0;

  // 电流模式
  runFOC();
  DFOC_M0_setTorque(serial_motor_target());
  count++;
  if(count>30)
  {
      count=0;
      Serial.printf("%0.2f \n", DFOC_M0_Current());
  }
}

void loop() 
{
#if SELECT_MODE == 0
  current_Mode_test(); 
#elif SELECT_MODE == 1
  velocity_Mode_test();
#elif SELECT_MODE == 2
  postion_Mode_test();
#endif

  //接收串口
  serialReceiveUserCommand();
}




4 测试

1) 设置电流值为0时,电流的输出波形

2)设置电流为2

 3)设置电流值为-2

测试视频如下:

直流无刷电机控制(FOC):电流模式测试视频

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

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

相关文章

(四)结合代码初步理解帧缓存(Frame Buffer)概念

帧缓存&#xff08;Framebuffer&#xff09;是图形渲染管线中的一个非常重要的概念&#xff0c;它用于存储渲染过程中产生的像素数据&#xff0c;并最终输出到显示器上。简单来说&#xff0c;帧缓存就是计算机图形中的“临时画布”&#xff0c;它储存渲染操作生成的图像数据&am…

Linux离线部署ELK

文章目录 前期准备开始安装安装elastic search安装logstash安装kibana 配置ELK配置ElasticSearch配置logstash配置kibana 启动ELK启动命令启动测试 设置ELK策略创建ILM策略将ILM策略与日志index关联查看索引是否被ILM策略管理 前期准备 ELK包含三部分软件 ElasticSearch用作搜…

LabVIEW数据库管理系统

LabVIEW数据库管理系统&#xff08;DBMS&#xff09;是一种集成了数据库技术与数据采集、控制系统的解决方案。通过LabVIEW的强大图形化编程环境&#xff0c;结合数据库的高效数据存储与管理能力&#xff0c;开发人员可以实现高效的数据交互、存储、查询、更新和报告生成。LabV…

微服务实现高并发 秒杀系统,前后端实现

一、前端实现 前端项目初始化 首先&#xff0c;我们需要创建一个新的 Vue 3 项目。你可以使用 Vue CLI 来快速搭建项目。 安装 Vue CLI&#xff08;如果尚未安装&#xff09; bash npm install -g vue/cli 创建 Vue 项目 bash vue create seckill-frontend cd seckill-f…

Http请求响应——请求

Http概述 Http协议&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;&#xff0c;是一种用于传输网页数据的协议&#xff0c;规定了浏览器和服务器之间进行数据传输的规则&#xff0c;简单说来就是客户端与服务器端数据交互的数据格式。 客户端…

Vue3 + Vite + Electron + Ts 项目快速创建

一、创建 Vue 项目 1. 创建项目 pnpm create vite 2. 安装依赖 cd excel-electron pnpm install 3. 运行项目 pnpm dev 二、添加 Electron 1. 安装 electron pnpm add electron -D 2. 修改 package.json 添加入口 js 和执行命令。 {"main": "dist-ele…

socket网络编程-TC/IP方式

网络编程 1.概念&#xff1a;两台设备之间通过网络数据传输。 2.网络通信&#xff1a;将数据通过网络从一台设备传输另外一台设备。 3.java.net包下提供了一系列的类和接口&#xff0c;提供程序员使用&#xff0c;完成网络通信。 TCP和UDP TCP协议&#xff1a; 1.使用TCP协…

RabbitMQ基本介绍及简单上手

&#xff08;一&#xff09;什么是MQ MQ&#xff08;message queue&#xff09;本质上是队列&#xff0c;满足先入先出&#xff0c;只不过队列中存放的内容是消息而已&#xff0c;那什么是消息呢&#xff1f; 消息可以是字符串&#xff0c;json也可以是一些复杂对象 我们应用场…

【Rust自学】11.3. 自定义错误信息

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 11.3.1. 添加错误信息 在 11.2. 断言(Assert) 中我们学习了assert!、assert_eq!和assert_ne!这三个宏&#xff0c;而这篇文章讲的就是它…

某漫画网站JS逆向反混淆流程分析

文章目录 1. 写在前面1. 接口分析2. 反混淆分析 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Pyth…

网络分析与监控:阿里云拨测方案解密

作者&#xff1a;俞嵩(榆松) 随着互联网的蓬勃发展&#xff0c;网络和服务的稳定性已成为社会秩序中不可或缺的一部分。一旦网络和服务发生故障&#xff0c;其带来的后果将波及整个社会、企业和民众的生活质量&#xff0c;造成难以估量的损失。 2020 年 12 月&#xff1a; Ak…

STL——二叉搜索树

目录 二叉搜索树的概念 ⼆叉搜索树的性能分析 ⼆叉搜索树的插⼊ ⼆叉搜索树的查找 ⼆叉搜索树的删除 中序遍历结果为升序序列 二叉搜索树的概念 ⼆叉搜索树⼜称⼆叉排序树&#xff0c;它或者是⼀棵空树&#xff0c;或者是具有以下性质的⼆叉树 • 若它的左⼦树不为空&#…

【文件I/O】UNIX文件基础

IO编程的本质是通过 API 操作 文件。 什么是 IO I - Input 输入O - Output 输出 这里的输入和输出都是站在应用&#xff08;运行中的程序&#xff09;的角度。外部特指文件。 这里的文件是泛指&#xff0c;并不是只表示存在存盘中的常规文件。还有设备、套接字、管道、链接…

VS调试MFC进入系统源代码配置

调试MFC代码有时候能进入MFC的源代码,有时候不能.之前一直没有深入研究.后面经过查资料发现每次调试必能进入源代码的配置.很简单,只需要3步. 1.打开工具->选项->调试->符号,勾选Microsoft符号服务器. 2.打开项目->属性->配置属性->常规,MFC的使用修改成&qu…

车载网络:现代汽车的数字心跳

在汽车领域&#xff0c;“智能汽车”一词毫不夸张。如今的汽车已不再是原始的机械工程&#xff0c;而是通过先进的车载网络无缝连接的精密数字生态系统。这些滚动计算机由复杂的电子控制单元(ECU)网络提供动力&#xff0c;ECU是负责管理从发动机性能到信息娱乐系统等一切事务的…

mycat介绍与操作步骤

文章目录 1.分库分表2.mycat 入门2.1 概述2.2 案例&#xff1a;水平分表1&#xff09;准备工作2&#xff09;配置3&#xff09;启动并测试 3.mycat 配置详解3.1 schema.xml3.2 rule.xml3.3 server.xml 4.mycat 分片&#xff1a;垂直拆分1&#xff09;准备工作2&#xff09;配置…

【Python】Python之Selenium基础教程+实战demo:提升你的测试+测试数据构造的效率!

这里写目录标题 什么是Selenium&#xff1f;Selenium基础用法详解环境搭建编写第一个Selenium脚本解析脚本脚本执行结果常用的元素定位方法常用的WebDriver方法等待机制 Selenium高级技巧详解页面元素操作处理弹窗和警告框截图和日志记录多窗口和多标签页操作 一个实战的小demo…

Apache XMLBeans 一个强大的 XML 数据处理框架

Apache XMLBeans 是一个用于处理 XML 数据的 Java 框架&#xff0c;它提供了一种方式将 XML Schema (XSD) 映射到 Java 类&#xff0c;从而使得开发者可以通过强类型化的 Java 对象来访问和操作 XML 文档。下面将以一个简单的案例说明如何使用 Apache XMLBeans 来解析、生成和验…

带格式 pdf 翻译

支持 openAI 接口&#xff0c;国内 deepseek 接口兼容 openAI 接口&#xff0c; deepseek api 又非常便宜 https://pdf2zh.com/ https://github.com/Byaidu/PDFMathTranslate

ubuntu22.04降级安装CUDA11.3

环境&#xff1a;主机x64的ubuntu22.04&#xff0c;原有CUDA12.1&#xff0c;但是现在需要CUDA11.3&#xff0c;本篇文章介绍步骤。 一、下载CUDA11.3的run文件 下载网址&#xff1a;https://developer.nvidia.com/cuda-11-3-1-download-archive?target_osLinux&target_…