七、电机三环控制

电机三环控制指的是,直流有刷电机三环(电流环+速度环+位置环)PID 控制。

1、三环PID控制原理

三环 PID 控制就是将三个 PID 控制系统(例如:电流环、速度环以及位置环)串联起来,然后对前一个系统(外环)的输出进行偏差的计算,计算结果作为后一个系统(内环)的输入。

1. 首先设置目标位置,系统会计算出位置偏差,然后将偏差输入到位置环(最外环);

2. 位置环的输出和实际速度进行偏差的计算,计算后的偏差输入到速度环(次外环);

3. 速度环的输出和实际电流进行偏差的计算,计算后的偏差输入到电流环(内环),电流环的输出用于控制 PWM 的占空比,进而控制电机的位置。

2、程序设计

三环 PID 控制的配置步骤: 

1)配置相关定时器

配置基础驱动、编码器测速相关的定时器,实现基础驱动以及编码器测速功能。

2)配置相关 ADC

配置电流采集相关 ADC,实现电流采集功能。

4)初始化串口 1

初始化串口 1,开启串口接收中断,串口 1 在 PID 控制中用于上位机通信。

注意:在 PID 控制的代码中,串口 1 仅用于 PID 数据上传,尽量不要输出其他信息,否则有可能影响 PID 数据。

5)定义 PID 参数结构体变量

为了方便管理 PID 相关的控制量,我们需要定义 3 个 PID 参数结构体变量,方法如下:

PID_TypeDef g_location_pid;/* 位置环 PID 参数结构体 */PID_TypeDef g_speed_pid;/* 速度环 PID 参数结构体 */PID_TypeDef g_current_pid;/* 电流环 PID 参数结构体 */

6)初始化 PID 参数

把三环 PID 控制系统的目标值、期望输出值、累计偏差等清零,然后分别配置各个环的PID 系数。

7)初始化上位机调试

调用 debug_init 函数初始化所需内存,为上位机的调试做准备。

8)编写中断服务函数

在定时器 6 的更新中断回调函数里面进行三环 PID 计算,计算后的结果用于控制 PWM的占空比。

pid.h

/* PID 相关参数 */ 
#define INCR_LOCT_SELECT 0 /* 0:位置式,1:增量式 */ 
#if INCR_LOCT_SELECT 
/* 定义位置环 PID 参数相关宏 */ 
#define L_KP 0.06f /* P 参数 */ 
#define L_KI 0.00f /* I 参数 */ 
#define L_KD 0.01f /* D 参数 */ 
/* 定义速度环 PID 参数相关宏 */ 
#define S_KP 5.00f /* P 参数 */ 
#define S_KI 0.30f /* I 参数 */ 
#define S_KD 0.01f /* D 参数 */ 
/* 定义电流环 PID 参数相关宏 */ 
#define C_KP 8.00f /* P 参数 */ 
#define C_KI 4.00f /* I 参数 */ 
#define C_KD 1.00f /* D 参数 */ 
#define SMAPLSE_PID_SPEED 50 /* 采样周期 单位 ms */ 
#else 
/* 定义位置环 PID 参数相关宏 */ 
#define L_KP 0.06f /* P 参数 */ 
#define L_KI 0.00f /* I 参数 */ 
#define L_KD 0.01f /* D 参数 */ 
/* 定义速度环 PID 参数相关宏 */ 
#define S_KP 5.00f /* P 参数 */ 
#define S_KI 0.30f /* I 参数 */ 
#define S_KD 0.01f /* D 参数 */ 
/* 定义电流环 PID 参数相关宏 */ 
#define C_KP 8.00f /* P 参数 */ 
#define C_KI 4.00f /* I 参数 */ 
#define C_KD 1.00f /* D 参数 */ 
#define SMAPLSE_PID_SPEED 50 /* 采样周期 单位 ms */ 
#endif 
/*PID 结构体*/ 
typedef struct 
{ 
__IO float SetPoint;
/* 目标值 */ 
__IO float ActualValue;
/* 期望输出值 */ 
__IO float SumError;
/* 误差累计 */ 
__IO float Proportion;
/* 比例常数 P */ 
__IO float Integral;
/* 积分常数 I */ 
__IO float Derivative;
/* 微分常数 D */ 
__IO float Error; /* Error[1] */ 
__IO float LastError;
/* Error[-1] */ 
__IO float PrevError;
/* Error[-2] */ 
} PID_TypeDef;
extern PID_TypeDef g_location_pid; /* 位置环 PID 参数结构体 */ 
extern PID_TypeDef g_speed_pid; 
/* 速度环 PID 参数结构体 */ 
extern PID_TypeDef g_current_pid; /* 电流环 PID 参数结构体 */

可以把上面的宏定义分成两部分,第一部分是 PID 计算方式以及 PID 系数的宏定义,可以通过改变 INCR_LOCT_SELECT 这个宏的值来选择相应的 PID 计算方式,第二部分则 是 PID 参数相关的结构体,这个结构体用于管理 PID 控制所需要的控制量,本示例定义了位置环、速度环以及电流环 PID 参数的结构体变量,它们分别是 g_ location _pid、g_speed_pid、g_current_pid。

pid.c

/** 
* @brief pid 初始化 
* @param 无 
* @retval 无 
*/ 
void pid_init(void) 
{ 
/* 初始化位置环 PID 参数 */ 
g_location_pid.SetPoint = 0.0; 
/* 目标值 */ 
g_location_pid.ActualValue = 0.0; /* 期望输出值 */ 
g_location_pid.SumError = 0.0; 
/* 积分值*/ 
g_location_pid.Error = 0.0; 
/* Error[1]*/ 
g_location_pid.LastError = 0.0; 
/* Error[-1]*/ 
g_location_pid.PrevError = 0.0; 
/* Error[-2]*/ 
g_location_pid.Proportion = L_KP; /* 比例常数 Proportional Const */ 
g_location_pid.Integral = L_KI; 
/* 积分常数 Integral Const */ 
g_location_pid.Derivative = L_KD; /* 微分常数 Derivative Const */ 
/* 初始化速度环 PID 参数 */ 
g_speed_pid.SetPoint = 0.0; 
/* 目标值 */ 
g_speed_pid.ActualValue = 0.0; 
/* 期望输出值 */ 
g_speed_pid.SumError = 0.0; 
/* 积分值 */ 
g_speed_pid.Error = 0.0; 
/* Error[1] */ 
g_speed_pid.LastError = 0.0; 
/* Error[-1] */ 
g_speed_pid.PrevError = 0.0; 
/* Error[-2] */ 
g_speed_pid.Proportion = S_KP; 
/* 比例常数 Proportional Const */ 
g_speed_pid.Integral = S_KI; 
/* 积分常数 Integral Const */ 
g_speed_pid.Derivative = S_KD; 
/* 微分常数 Derivative Const */ 
/* 初始化电流环 PID 参数 */ 
g_current_pid.SetPoint = 0.0; 
/* 目标值 */ 
g_current_pid.ActualValue = 0.0; 
/* 期望输出值 */ 
g_current_pid.SumError = 0.0; 
/* 积分值*/ 
g_current_pid.Error = 0.0; 
/* Error[1]*/ 
g_current_pid.LastError = 0.0; 
/* Error[-1]*/ 
g_current_pid.PrevError = 0.0; 
/* Error[-2]*/ 
g_current_pid.Proportion = C_KP; 
/* 比例常数 Proportional Const */ 
g_current_pid.Integral = C_KI; 
/* 积分常数 Integral Const */ 
g_current_pid.Derivative = C_KD; 
/* 微分常数 Derivative Const */ 
} /** 
* @brief 积分限幅 
* @param *PID:PID 结构体变量地址 
* @param max_limit:最大值 
* @param min_limit:最小值 
* @retval 无
*/ 
void integral_limit( PID_TypeDef *PID , float max_limit, float min_limit ) 
{ 
if (PID->SumError >= max_limit) /* 超过限幅 */ 
{ 
PID->SumError = max_limit; /* 限制积分 */ 
} 
else if (PID->SumError <= min_limit) /* 超过限幅 */ 
{ 
PID->SumError = min_limit; 
} 
} 

该函数主要是将三环 PID 控制系统的目标值、期望输出值、累计偏差等清零,然后配置PID 系数。integral_limit()函数可以对位置式 PID 的积分进行限幅,避免出现积分深度饱和的问题。在使用该函数之前,需要先调整好 PID 系数,再根据系统能达到的最大累计偏差来设置限幅。

dcmotor_time.c

/** 
* @brief 定时器更新中断回调函数 
* @param htim:定时器句柄指针 
* @note 此函数会被定时器中断函数共同调用的 
* @retval 无 
*/ 
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 
{ 
static uint8_t val = 0; 
/* 定时器 3 相关程序 */ 
if (htim->Instance == TIM3) 
{ 
/* 判断 CR1 的 DIR 位 */ 
if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&g_timx_encode_chy_handle)) 
{ 
g_timx_encode_count--; /* DIR 位为 1,也就是递减计数 */ 
} 
else 
{ 
g_timx_encode_count++; /* DIR 位为 0,也就是递增计数 */ 
} 
} 
/* 定时器 6 相关程序 */ 
else if (htim->Instance == TIM6) 
{ 
int Encode_now = gtim_get_encode(); /* 获取编码器值,用于计算速度 */ 
speed_computer(Encode_now, 5); /* 5ms 计算一次速度 */ 
if (val % SMAPLSE_PID_SPEED == 0) /* 进行一次 pid 计算 */ 
{ 
if (g_run_flag) /* 判断电机是否启动了 */ 
{ 
/* 获取当前编码器总计数值,用于位置闭环控制 */ 
g_motor_data.location = (float)Encode_now; 
integral_limit(&g_location_pid , 1000 ,-1000); /* 位置环积分限幅 */ 
integral_limit(&g_speed_pid , 200 ,-200); /* 速度环积分限幅 */ 
integral_limit(&g_current_pid , 150 ,-150); /* 电流环积分限幅 */ 
/* 设置闭环死区,避免小幅度位置抖动 */ 
if((g_location_pid.Error <= 20)&&(g_location_pid.Error >= -20)) 
{ 
g_location_pid.Error = 0; /* 偏差太小了,直接清零 */
g_location_pid.SumError = 0; /* 清除积分 */ 
} 
g_motor_data.motor_pwm = increment_pid_ctrl(&g_location_pid, 
g_motor_data.location); /* 位置环 PID 控制(最外环) */ 
if (g_motor_data.motor_pwm >= 120) /* 限制外环输出(目标速度) */ 
{ 
g_motor_data.motor_pwm = 120; 
} 
else if (g_motor_data.motor_pwm <= -120) 
{ 
g_motor_data.motor_pwm = -120; 
} 
/* 设置目标速度,外环输出作为内环输入 */ 
g_speed_pid.SetPoint = g_motor_data.motor_pwm; 
g_motor_data.motor_pwm = increment_pid_ctrl(&g_speed_pid, 
g_motor_data.speed); /* 速度环 PID 控制(次外环) */ 
if ( g_motor_data.motor_pwm > 0) /* 判断速度环输出值是否为正数 */ 
{ 
dcmotor_dir(0); /* 输出为正数,设置电机正转 */ 
} 
else 
{ 
/* 输出取反 */ 
g_motor_data.motor_pwm = -g_motor_data.motor_pwm; 
dcmotor_dir(1); /* 设置电机反转 */ 
} 
if (g_motor_data.motor_pwm >= 100) /* 限制外环输出(目标电流) */ 
{ 
g_motor_data.motor_pwm = 100; 
} 
/* 设置目标电流,外环输出作为内环输入 */ 
g_current_pid.SetPoint = g_motor_data.motor_pwm; 
g_motor_data.motor_pwm = increment_pid_ctrl(&g_current_pid, 
g_motor_data.current); 
/* 电流环 PID 控制(内环) */ 
if (g_motor_data.motor_pwm >= 8200) /* 限制占空比 */ 
{ 
g_motor_data.motor_pwm = 8200; 
} 
else if (g_motor_data.motor_pwm <= 0) /* 滤掉无效输出 */ 
{ 
g_motor_data.motor_pwm = 0; 
} 
#if DEBUG_ENABLE /* 发送基本参数*/ 
/* 选择通道 1,发送实际位置(波形显示)*/ 
debug_send_wave_data( 1 ,g_motor_data.location); 
/* 选择通道 2,发送目标位置(波形显示)*/ 
debug_send_wave_data( 2 ,g_location_pid.SetPoint); 
#endif 
dcmotor_speed(g_motor_data.motor_pwm); /* 设置占空比 */ 
} 
val = 0; 
} 
val ++; 
} 
}

定时器 6 相关的程序,进入更新中断回调函数后,所执行的代码逻辑如下:

第一步,判断是不是定时器 6 的寄存器基地址,如果是则获取编码器的计数总值并存入变量 Encode_now 中,接着计算电机速度。

第二步,每隔 50ms 进行一次 PID 计算,在计算 PID 之前,需要判断 g_run_flag 是否为1,如果是则说明电机已经启动,可以开始 PID 计算。

第三步,把变量 Encode_now 的值存入 g_motor_data.location 这个成员中,然后对三环的积分进行限幅并设置闭环死区。当系统偏差值进入死区范围之内,我们直接让偏差等于 0,并清除累计偏差,此时 PID 系统不再参与控制,这样可以避免小幅度偏差带来的位置抖动。

第四步,进行位置环 PID 计算并限制其输出,然后将位置环的输出作为速度环的目标值;速度环 PID 计算完后,我们先判断其输出,如果输出是正数,则设置电机正转,如果输出是负数,则将输出取反,设置电机反转。因为电流环 PID 的目标值和输出都是正数,我们无法通过电流环的输出来确定电机的转向,所以这里需要通过速度环的输出来确定电机的转向,并保证电流环的目标值是正数。

第五步,将速度环的输出作为电流环的目标值,然后进行电流环 PID 计算并限制其输出。

第六步,发送实际位置、目标位置的波形数据到上位机,最后设置 PWM 的占空比,进而控制电机的位置。

main.c

int main(void) 
{ 
uint8_t key; 
uint16_t t; 
uint8_t debug_cmd = 0; 
HAL_Init(); 
/* 初始化 HAL 库 */ 
sys_stm32_clock_init(336, 8, 2, 7); 
/* 设置时钟,168Mhz */ 
delay_init(168); 
/* 延时初始化 */ 
usart_init(115200); 
/* 串口 1 初始化,用于上位机调试 */ 
led_init(); 
/* 初始化 LED */ 
lcd_init(); 
/* 初始化 LCD */ 
key_init(); 
/* 初始化按键 */ 
pid_init(); 
/* 初始化 PID 参数 */ 
atim_timx_cplm_pwm_init(8400 - 1 , 0); /* 168Mhz 的计数频率 */ 
dcmotor_init(); 
/* 初始化电机 */ 
gtim_timx_encoder_chy_init(0XFFFF, 0); /* 编码器定时器初始化 */ 
btim_timx_int_init(1000 - 1 , 84 - 1); /* 基本定时器初始化,1ms 计数周期 */ 
adc_nch_dma_init(); 
#if DEBUG_ENABLE 
/* 开启调试 */ 
debug_init(); 
/* 初始化调试 */ 
debug_send_motorcode(DC_MOTOR); 
/* 上传电机类型(直流有刷电机) */ 
debug_send_motorstate(IDLE_STATE); 
/* 上传电机状态(空闲) */ 
/* 同步数据 PID 参数到上位机 ,无论同步哪一组数据,目标值地址只能是外环 PID 的 */ 
debug_send_initdata(TYPE_PID1, (float *)(&g_location_pid.SetPoint), 
L_KP, L_KI, L_KD); /* 位置环 PID 参数(PID1)*/ 
debug_send_initdata(TYPE_PID2, (float *)(&g_location_pid.SetPoint), 
S_KP, S_KI, S_KD); /* 速度环 PID 参数(PID2)*/ 
debug_send_initdata(TYPE_PID3, (float *)(&g_location_pid.SetPoint), 
C_KP, C_KI, C_KD); /* 电流环 PID 参数(PID3)*/ 
#endif 
g_point_color = WHITE; 
g_back_color = BLACK; 
lcd_show_string(10, 10, 200, 16, 16, "DcMotor Test", g_point_color);
lcd_show_string(10, 30, 200, 16, 16, "KEY0:Start forward", g_point_color); 
lcd_show_string(10, 50, 200, 16, 16, "KEY1:Start backward", g_point_color); 
lcd_show_string(10, 70, 200, 16, 16, "KEY2:Stop", g_point_color); 
while (1) 
{ 
key = key_scan(0); 
/* 按键扫描 */ 
if(key == KEY0_PRES) 
/* 当 key0 按下 */ 
{ 
g_run_flag = 1; 
/* 标记电机启动 */ 
dcmotor_start(); 
/* 开启电机 */ 
/* 正转一圈,电机旋转圈数 = 编码器总计数值 / 44 / 30 */ 
g_location_pid.SetPoint += 1320; 
if (g_location_pid.SetPoint >= 6600) 
/* 限制电机位置 */ 
{ 
g_location_pid.SetPoint = 6600; 
} 
#if DEBUG_ENABLE 
debug_send_motorstate(RUN_STATE); 
/* 上传电机状态(运行) */ 
#endif 
} 
else if(key == KEY1_PRES) 
/* 当 key1 按下 */ 
{ 
g_run_flag = 1; 
/* 标记电机启动 */ 
dcmotor_start(); 
/* 开启电机 */ 
g_location_pid.SetPoint -= 1320; 
/* 反转一圈 */ 
if (g_location_pid.SetPoint <= -6600) 
/* 限制电机位置 */ 
{ 
g_location_pid.SetPoint = -6600; 
} 
#if DEBUG_ENABLE 
debug_send_motorstate(RUN_STATE); 
/* 上传电机状态(运行) */ 
#endif 
} 
else if(key == KEY2_PRES) 
/* 当 key2 按下 */ 
{ 
g_location_pid.SetPoint = 0; 
/* 恢复初始位置 */ 
} 
#if DEBUG_ENABLE 
/* 接收 PID 助手设置的位置环 PID 参数 */ 
debug_receive_pid(TYPE_PID1,(float *)&g_location_pid.Proportion, 
(float *)&g_location_pid.Integral,(float *)&g_location_pid.Derivative); 
/* 接收 PID 助手设置的速度环 PID 参数 */ 
debug_receive_pid(TYPE_PID2,(float *)&g_speed_pid.Proportion, 
(float *)&g_speed_pid.Integral,(float *)&g_speed_pid.Derivative); 
/* 接收 PID 助手设置的电流环 PID 参数 */ 
debug_receive_pid(TYPE_PID3,(float *)&g_current_pid.Proportion, 
(float *)&g_current_pid.Integral,(float *)&g_current_pid.Derivative); 
debug_set_point_range(6600, -6600, 6600); 
/* 设置目标调节范围 */ 
debug_cmd = debug_receive_ctrl_code(); 
/* 读取上位机指令 */ 
if (debug_cmd == HALT_CODE) 
/* 电机停机 */ 
{
g_location_pid.SetPoint = 0; 
/* 恢复初始位置 */ 
} 
else if (debug_cmd == RUN_CODE) 
/* 电机运行 */ 
{ 
g_run_flag = 1; 
/* 标记电机启动 */ 
dcmotor_start(); 
/* 开启电机 */ 
g_location_pid.SetPoint = 1320; 
/* 设置目标位置 */ 
debug_send_motorstate(RUN_STATE); 
/* 上传电机状态(运行) */ 
} 
#endif 
t++; 
if(t % 20 == 0) 
{ 
lcd_dis(); 
LED0_TOGGLE(); 
/* LED0(红灯) 翻转 */ 
#if DEBUG_ENABLE 
debug_send_speed(g_motor_data.speed); 
/* 发送速度 */ 
g_debug.encode_p = g_motor_data.location; 
/* 传入编码器当前总计数值 */ 
debug_upload_data(&g_debug, TYPE_HAL_ENC); /* 发送编码器当前总计数值 */ 
#endif 
} 
delay_ms(10); 
} 
} 

main.c 的代码逻辑如下:

第一步,初始化相关的外设,例如定时器、串口以及 ADC 等。

第二步,初始化 PID 参数、上位机调试,它们分别调用的是 pid_init 和 debug_init 函数。

第三步,同步电机的状态(空闲)、类型(直流有刷电机)、PID 参数到上位机。需要注意的是,在多环控制中,只有最外环的目标值可以手动设置,因此,无论同步哪一组 PID 参数,目标值地址只能是最外环 PID 的(本实验最外环为位置环)。

第四步,在 while 循环里面检测按键是否按下,如果 key0 按下,则目标位置增加 1320,也就是目标计数值增加 1320,根据公式:电机旋转圈数 = 目标计数值变化量 / 44 / 30,电机将会正转一圈;如果 key1 按下,则目标位置减小 1320,电机将会反转一圈,然后上传电机状态(运行);如果 key2 按下,电机将回到初始位置。

第五步,接收上位机下发的 PID 参数、设置目标位置的调节范围。

第六步,调用 debug_receive_ctrl_code 函数,接收上位机下发的命令。如果上位机的命令为 HALT_CODE(停机),则让电机回到初始位置;如果上位机的命令是 RUN_CODE,则开启电机,设置目标位置为 1320,上传电机状态(运行)到上位机。

第七步,每隔 200ms 更新一次数据到屏幕,然后调用 debug_upload_data 函数发送编码器位置值(计数总值)到上位机。

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

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

相关文章

NLP论文速读(多伦多大学)|利用人类偏好校准来调整机器翻译的元指标

论文速读|MetaMetrics-MT: Tuning Meta-Metrics for Machine Translation via Human Preference Calibration 论文信息&#xff1a; 简介&#xff1a; 本文的背景是机器翻译&#xff08;MT&#xff09;任务的评估。在机器翻译领域&#xff0c;由于不同场景和语言对的需求差异&a…

【Vue】Vue指令

目录 概念 作用 分类 内容渲染指令 属性绑定指令 事件绑定指令 条件渲染指令 v-if/v-else-if/v-else多分支渲染 v-show和v-if的区别 列表渲染指令 v-for中的key属性 双向绑定指令 示例&#xff1a;图片切换 示例&#xff1a;可折叠面板 示例&#xff1a;书架…

C++:类和对象(三)

1.深入了解构造函数 1.1初始化列表 引入&#xff1a;我们首先要知道&#xff0c;在类中我们是声明变量&#xff0c;在实例化的时候才是开空间&#xff0c;在调用构造函数的时候又分两段&#xff0c;一段是定义&#xff08;所有的成员变量进行定义&#xff09;&#xff0c;一段…

北京申请中级职称流程(2024年)

想找个完整详细点的申请流程资料真不容易&#xff0c;做个分享送给需要的人吧。 不清楚为什么说文章过度宣传&#xff0c;把链接和页面去掉了&#xff0c;网上自己找一下。 最好用windows自带的EDGE浏览器打开申请网站&#xff0c;只有在开始申请的时间内才可以进行网上申报&…

好用的js组件库

lodash https://www.lodashjs.com/https://www.lodashjs.com/ uuid 用于生成随机数&#xff0c;常用于生成id标识 GitHub - uuidjs/uuid: Generate RFC-compliant UUIDs in JavaScripthttps://github.com/uuidjs/uuid dayjs 常用于时间的处理 安装 | Day.js中文网 (fenxi…

php:使用socket函数创建WebSocket服务

一、前言 闲来无事&#xff0c;最近捣鼓了下websocket&#xff0c;但是不希望安装第三方类库&#xff0c;所以打算用socket基础函数创建个服务。 二、构建websocket服务端 <?phpclass SocketService {// 默认的监听地址和端口private $address 0.0.0.0;private $port 8…

Tailscale 自建 Derp 中转服务器(全程无 Docker + 无域名纯 IP 版本)

文章目录 整体大纲目的&#xff1a;为什么要建立 Derp 中转服务器云服务器安装 DerpDerp 中转服务器介绍安装 Go 环境通过 Go 安装 Derp处理证书文件自签一个域名给 Derp验证 Derp 是否启动 云服务器安装并登录 Tailscale第一种组合&#xff1a; 官方 Tailscale 账号 自己的 D…

shell--第一次作业

1.接收用户部署的服务名称 # 脚本入口 read -p "请输入要部署的服务名称&#xff1a;" service_name 2.判断服务是否安装 # 判断服务是否安装 if rpm -q "$service_name" &>/dev/null; then echo "服务 $service_name 已安装。" 已…

项目部署问题bug记录(长期更新)

一、编译相关 1.submodules/simple-knn/simple_knn.cu(90): error: identifier "FLT_MAX" is undefined me.minn { FLT_MAX, FLT_MAX, FLT_MAX }; 部署photoreg工程&#xff0c;在编译simple_knn的时候&#xff0c;报错&#xff1a; (photoreg) leelee…

ant-design-vue中table组件多列排序

antD中table组件多列排序 使用前注意实现效果图实现的功能点及相关代码1. 默认按某几个字段排序2. 点击排序按钮可同时对多个字段进行排序3. 点击重置按钮可恢复默认排序状态。 功能实现完整的关键代码 使用前注意 先要确认你使用的antD版本是否支持多列排序&#xff0c;我这里…

影视后期学习Ⅰ~

1.DV是光盘 磁带 2.序列就是我们要制作的一个视频。 打开界面显示&#xff1a; 一号面板放的是素材&#xff0c;二号面板叫源监视器面板&#xff08;它的名字需要记住&#xff09;在一号面板点击文件之后&#xff0c;进入二号面板&#xff0c;在二号面板预览没问题后&#xf…

大语言模型---Llama模型文件介绍;文件组成

文章目录 1. 概要2. 文件组成 1. 概要 在使用 LLaMA&#xff08;Large Language Model Meta AI&#xff09;权重时&#xff0c;通常会涉及到与模型权重存储和加载相关的文件。这些文件通常是以二进制格式存储的&#xff0c;具有特定的结构来支持高效的模型操作。以下以Llama-7…

elasticsearch介绍和部署

1 elasticsearch介绍 Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。可以很方便的使大量数据具有搜索、分析和探索的能力。充分利用Elasticsearch的水平伸缩性。Elasticsearch 的实现原理主要分为以下几个步骤&#xff0c;首先用户将数据提交到Elasticsea…

ZYNQ-7020嵌入式系统学习笔记(1)——使用ARM核配置UART发送Helloworld

本工程实现调用ZYNQ-7000的内部ARM处理器&#xff0c;通过UART给电脑发送字符串。 硬件&#xff1a;正点原子领航者-7020 开发平台&#xff1a;Vivado 2018、 SDK 1 Vivado部分操作 1.1 新建工程 设置工程名&#xff0c;选择芯片型号。 1.2 添加和配置PS IP 点击IP INTEGR…

Jenkins更换主题颜色+登录页面LOGO图片

默认主题和logo图片展示 默认主题黑色和白色。 默认LOGO图片 安装插件 Login ThemeMaterial Theme 系统管理–>插件管理–>Available plugins 搜不到Login Theme是因为我提前装好了 没有外网的可以参考这篇离线安装插件 验证插件并修改主题颜色 系统管理–>A…

《操作系统》实验内容 实验二 编程实现进程(线程)同步和互斥(Python 与 PyQt5 实现)

实验内容 实验二 编程实现进程&#xff08;线程&#xff09;同步和互斥 1&#xff0e;实验的目的 &#xff08;1&#xff09;通过编写程序实现进程同步和互斥&#xff0c;使学生掌握有关进程&#xff08;线程&#xff09;同步与互斥的原理&#xff0c;以及解决进程&#xf…

【倍数问题——同余系】

题目 代码 #include <bits/stdc.h> using namespace std; const int N 1e5 10, M 1e3 10; int maxx[M][4]; void consider(int r, int x) {if(x > maxx[r][1]){maxx[r][3] maxx[r][2];maxx[r][2] maxx[r][1];maxx[r][1] x;}else if(x > maxx[r][2]){maxx[…

结合第三方模块requests,文件IO、正则表达式,通过函数封装爬虫应用采集数据

#引用BeautifulSoup更方便提取html信息&#xff1b;requests模块&#xff0c;发生http请求&#xff1b;os模块&#xff0c;文件写入import requests from bs4 import BeautifulSoup import os#当使用requests库发送请求时&#xff0c;如果不设置User - Agent&#xff0c;默认的…

Linux虚拟机网络配置

Linux固定IP 跳转到 cd /etc/sysconfig/network-scripts/ 打开文件并编辑 vim ifcfg-ens33 增加或修改选中内容 重启网卡 systemctl restart network ifconfig -a 查看ip已固定 虚拟机网络编辑器调整 子网IP进行修改&#xff0c;例如本机IP修改为10.212.197.34 此处就修改…

CSS实现实现当文本内容过长时,中间显示省略号...,两端正常展示

HTML 结构解析 文档结构: <ul class"con">: 一个无序列表&#xff0c;包含多个列表项。 每个 <li class"wrap"> 表示一个列表项&#xff0c;内部有两个 <span> 元素&#xff1a; <span class"txt">: 显示文本内容。<…