pid-max设置多少合适之原理

本文揭示了PID_MAX内核参数的误解,它不仅受CPU核心数影响,还取决于long类型字节大小。当配置不同,其默认最大值可在32768至4194304之间变化,理解这一概念对于系统优化至关重要。

之前我读源码可能不仔细,“当时认为主机内核的pid-max是不需要修改的,因为已经是最大值了,这个值改大了也没有用,和主机的cpu物理核数有关,这个值是系统在开机的时候会帮我们设置成最大值。因为每核最大值是1024,比如我们32核的机器就是1024*32,也就是系统会设置成32768,40核机器就是40960,所以不需要修改,改小可以,改大改了也没有效果。”

但是,

刚仔细看了下代码,这个要看long字节大小 ,也就是操作系统版本,如果long是大于4字节的,就可以到2^22

/*
 * This controls the default maximum pid allocated to a process
 * 大致意思就是,如果在编译内核时指定或者为CONFIG_BASE_SMALl赋值了,那么默认值就是4096,反而就是32768
 */
#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)

/*
 * A maximum of 4 million PIDs should be enough for a while.
 * [NOTE: PID/TIDs are limited to 2^30 ~= 1 billion, see FUTEX_TID_MASK.] 
 * 如果CONFIG_BASE_SMALL被赋值了,则最大值就是32768,如果条件不成立,则判断long的类型通常应该是操作系统版本,
 * 如果大于4字节,取值范围大约就是4 million,精确计算就是4,194,304,如果条件还不成立则只能取值最被设置的PID_MAX_DEFAULT的值
 */

#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \
    (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))
#include <stdio.h> #include <stdlib.h> #include <unistd.h> // 单级PID结构体 typedef struct { float Kp; // 比例系数 float Ki; // 积分系数 float Kd; // 微分系数 float setpoint; // 目标值 float output; // 输出值 float maxOut; // 最大输出 float minOut; // 最小输出 float error; // 当前误差 float prevError;// 上一次误差 float integral; // 积分项 float derivative; // 微分项 } PID; // 单级PID初始化函数 void PID_Init(PID *pid, float kp, float ki, float kd, float min, float max) { pid->Kp = kp; pid->Ki = ki; pid->Kd = kd; pid->setpoint = 0; pid->output = 0; pid->maxOut = max; pid->minOut = min; pid->error = 0; pid->prevError = 0; pid->integral = 0; pid->derivative = 0; } // 单级PID计算函数 void PID_Calc(PID *pid, float ref, float fdb) { pid->setpoint = ref; pid->error = ref - fdb; pid->integral += pid->error; pid->derivative = pid->error - pid->prevError; // 积分限幅 if(pid->integral * pid->Ki > pid->maxOut) pid->integral = pid->maxOut / pid->Ki; if(pid->integral * pid->Ki < pid->minOut) pid->integral = pid->minOut / pid->Ki; // PID计算 pid->output = pid->Kp * pid->error + pid->Ki * pid->integral + pid->Kd * pid->derivative; // 输出限幅 if(pid->output > pid->maxOut) pid->output = pid->maxOut; if(pid->output < pid->minOut) pid->output = pid->minOut; pid->prevError = pid->error; } //串级PID的结构体,包含两个单级PID typedef struct { PID inner; //内环 PID outer; //外环 float output; //串级输出,等于inner.output } CascadePID; //串级PID的计算函数 //参数(PID结构体,外环目标值,外环反馈值,内环反馈值) void PID_CascadeCalc(CascadePID *pid, float outerRef, float outerFdb, float innerFdb) { PID_Calc(&pid->outer, outerRef, outerFdb); //计算外环 PID_Calc(&pid->inner, pid->outer.output, innerFdb); //计算内环 pid->output = pid->inner.output; //内环输出就是串级PID的输出 } // 模拟获取当前PH值 float getCurrentPH() { // 这里应该是实际读取PH传感器的代码 // 此处用随机数模拟PH值波动,范围在6.0-8.0之间 static float basePH = 7.0; float noise = ((float)rand() / RAND_MAX) * 0.2 - 0.1; // -0.1到0.1的随机噪声 return basePH + noise; } // 模拟设置阀门流速 void setValveFlowRate(float flowRate) { // 这里应该是实际控制阀门的代码 printf("设置阀门流速: %.2f L/min\n", flowRate); } int main() { CascadePID phPID = {0}; // 创建串级PID结构体变量 float targetPH = 7.0; // 目标PH值 // 初始化PID参数 // 内环控制流速,响应要快 PID_Init(&phPID.inner, 10.0, 0.5, 1.0, 0.0, 100.0); // 外环控制PH值,响应可以慢一些 PID_Init(&phPID.outer, 5.0, 0.2, 0.5, 0.0, 100.0); printf("PH值PID控制系统启动,目标PH值: %.1f\n", targetPH); // 模拟运行30个周期 for (int i = 0; i < 30; i++) { float currentPH = getCurrentPH(); float currentFlowRate = i * 2.0; // 模拟当前流速 printf("周期 %d: 当前PH=%.2f, 目标PH=%.2f\n", i+1, currentPH, targetPH); // 执行PID计算 PID_CascadeCalc(&phPID, targetPH, currentPH, currentFlowRate); // 设置阀门流速 setValveFlowRate(phPID.output); // 延时模拟控制周期 usleep(500000); // 500ms } return 0; } 生成matlab
06-05
float Speed_Low_Filter(float new_Spe,encoder_t *encoder) { float sum = 0.0f; uint32_t test_Speed = new_Spe; for(uint8_t i=SPEED_RECORD_NUM-1;i>0;i--) { encoder->speed_Record[i] = encoder->speed_Record[i-1]; sum += encoder->speed_Record[i-1]; } encoder->speed_Record[0] = new_Spe; sum += new_Spe; test_Speed = sum/SPEED_RECORD_NUM; return sum/SPEED_RECORD_NUM; } motor_t motor_l; motor_t motor_r; void motor_Init() { DL_TimerG_startCounter(PWM_0_INST); //pwm初始化 /*使能编码器输入捕获中断*/ NVIC_EnableIRQ(ENCODER1A_INST_INT_IRQN); DL_TimerA_startCounter(ENCODER1A_INST); NVIC_EnableIRQ(ENCODER2A_INST_INT_IRQN); DL_TimerG_startCounter(ENCODER2A_INST); /*使能时钟定时器中断*/ NVIC_EnableIRQ(CLOCK_INST_INT_IRQN); DL_TimerA_startCounter(CLOCK_INST); /*motor_l init*/ motor_l.pwmDuty=0; motor_l.speed=0; motor_l.timer_index=DL_TIMER_CC_0_INDEX; motor_l.forward_GPIO_PORT=GPIO_MOTOR_AIN1_PORT; motor_l.reverse_GPIO_PORT=GPIO_MOTOR_AIN2_PORT; motor_l.forward_GPIO_PIN=GPIO_MOTOR_AIN1_PIN; motor_l.reverse_GPIO_PIN=GPIO_MOTOR_AIN2_PIN; motor_l.speed_pid.kp=0; motor_l.speed_pid.ki=0; motor_l.speed_pid.kd=0; motor_l.speed_pid.max_integral=1000; motor_l.speed_pid.maxoutput=1000; motor_l.speed_pid.dead_zone=0; motor_l.pos_pid.kp=0; motor_l.pos_pid.ki=0; motor_l.pos_pid.kd=0; motor_l.pos_pid.max_integral=1000; motor_l.pos_pid.maxoutput=1000; motor_l.pos_pid.dead_zone=0; /*motor_r init*/ motor_r.pwmDuty=0; motor_r.speed=0; motor_r.timer_index=DL_TIMER_CC_1_INDEX; motor_r.forward_GPIO_PORT=GPIO_MOTOR_BIN1_PORT; motor_r.reverse_GPIO_PORT=GPIO_MOTOR_BIN2_PORT; motor_r.forward_GPIO_PIN=GPIO_MOTOR_BIN1_PIN; motor_r.reverse_GPIO_PIN=GPIO_MOTOR_BIN2_PIN; motor_r.speed_pid.kp=0; motor_r.speed_pid.ki=0; motor_r.speed_pid.kd=0; motor_r.speed_pid.max_integral=1000; motor_r.speed_pid.maxoutput=1000; motor_r.speed_pid.dead_zone=0; motor_r.pos_pid.kp=0; motor_r.pos_pid.ki=0; motor_r.pos_pid.kd=0; motor_r.pos_pid.max_integral=1000; motor_r.pos_pid.maxoutput=1000; motor_r.pos_pid.dead_zone=0; } /*左电机的编码器测速*/ void TIMA0_IRQHandler(void) { switch (DL_TimerA_getPendingInterrupt(ENCODER1A_INST)) { case DL_TIMERA_IIDX_CC0_DN: motor_l.encoder.dierct = DL_GPIO_readPins(GPIO_ENCODER_PORT, GPIO_ENCODER_ENCODER1B_PIN);//读取IO电平获取电机旋转方向 motor_l.encoder.countnum= motor_l.encoder.dierct? (motor_l.encoder.countnum + 1) : (motor_l.encoder.countnum - 1);//通过判断旋转方向来决定countnum增加还是减少 break; default: break; } } /*右电机的编码器测速*/ void TIMG6_IRQHandler(void) { switch (DL_TimerG_getPendingInterrupt(ENCODER2A_INST)) { case DL_TIMERG_IIDX_CC0_DN: motor_r.encoder.dierct= DL_GPIO_readPins(GPIO_ENCODER_PORT, GPIO_ENCODER_ENCODER2B_PIN);//读取IO电平获取电机旋转方向 motor_r.encoder.countnum = motor_r.encoder.dierct ? ( motor_r.encoder.countnum + 1) : ( motor_r.encoder.countnum- 1);//通过判断旋转方向来决定countnum增加还是减少 break; default: break; } } /*period 100Hz*/ void CLOCK_INST_IRQHandler(void) { DL_TimerA_clearInterruptStatus(CLOCK_INST, DL_TIMER_IIDX_ZERO); motor_l.encoder.speed = (float)(motor_l.encoder.countnum - motor_l.encoder.lastcount) * 6000 / PULSE_PER_CYCLE; // rpm motor_r.encoder.speed = (float)(motor_r.encoder.countnum - motor_r.encoder.lastcount) * 6000 / PULSE_PER_CYCLE; // rpm motor_l.encoder.speed = Speed_Low_Filter(motor_l.encoder.speed, &motor_l.encoder); motor_r.encoder.speed = Speed_Low_Filter(motor_r.encoder.speed, &motor_r.encoder); motor_l.encoder.lastcount = motor_l.encoder.countnum; motor_r.encoder.lastcount = motor_r.encoder.countnum; } float PID_Realize(pid_t* pid,float target,float feedback) { pid->err = target - feedback; if(pid->err < pid->dead_zone && pid->err > -pid->dead_zone) pid->err = 0;//pid死区 pid->integral += pid->err; if(pid->ki * pid->integral < -pid->max_integral) pid->integral = -pid->max_integral / pid->ki;//积分限幅 else if(pid->ki * pid->integral > pid->max_integral) pid->integral = pid->max_integral / pid->ki; pid->output = (pid->kp * pid->err) + (pid->ki * pid->integral) + (pid->kd * (pid->err - pid->last_err)); //输出限幅 if(pid->output > pid->maxoutput) pid->output = pid->maxoutput; else if(pid->output < -pid->maxoutput) pid->output = -pid->maxoutput; pid->last_err = pid->err; return pid->output; } void Motor_Set_Duty(motor_t *motor){ if (motor->pwmDuty>=0){//正转 DL_TimerG_setCaptureCompareValue(PWM_0_INST,motor->pwmDuty,motor->timer_index); DL_GPIO_setPins(motor->forward_GPIO_PORT, motor->forward_GPIO_PIN); DL_GPIO_clearPins(motor->reverse_GPIO_PORT, motor->reverse_GPIO_PIN); } else if(motor->pwmDuty<0){//反转 DL_TimerG_setCaptureCompareValue(PWM_0_INST,-motor->pwmDuty,motor->timer_index); DL_GPIO_setPins(motor->reverse_GPIO_PORT, motor->reverse_GPIO_PIN); DL_GPIO_clearPins(motor->forward_GPIO_PORT, motor->forward_GPIO_PIN); } } void Motor_Set_Speed(motor_t *motor){ motor->pwmDuty=PID_Realize(&motor->speed_pid,motor->speed,motor->encoder.speed); Motor_Set_Duty(motor); } void Motor_Set_Position(motor_t *motor){ motor->pos_pulse=(int)((motor->pos*PULSE_PER_CYCLE)/(LINE_SPEED_C)); motor->speed=PID_Realize(&motor->pos_pid, motor->pos_pulse, motor->encoder.countnum); Motor_Set_Speed(motor); } void Motor_Stop(motor_t *motor){ motor->speed=0; Motor_Set_Speed(motor); if(motor->encoder.speed==0){ motor->encoder.countnum=0; motor->encoder.lastcount=0; motor->speed_pid.integral=0; } }解释一下这些代码
最新发布
07-17
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值