stm32平衡车

news2024/11/18 12:41:05

目录

一.所需材料

二.PID算法(简单说明)

直立环

速度环

串级PID 

三.使用到的外设 

         1.定时器输出比较-PWM

2.定时器编码器模式 

3.编码器读取速度 

4.电机驱动函数

5.外部中断

四、小车

        调试 


一.所需材料

1.陀螺仪MPU6050--读取三轴的加速度和角速度,然而我们平衡车需要的不是加速度和角速度,而是需要实时的角度,即我们还需要进行姿态角转换,可以直接移植正点原子的DMP函数

2.TB6612电机驱动,l298N也可,我用的是TB6612,点击查看接线

3.OLED,用来显示姿态角,可以直接移植

4.12v锂电池和DCDC降压模块给电机和单片机供电

5.编码电机,点击查看接线

6.c8t6单片机

二.PID算法(简单说明)

P(比例)算法:Kp*误差。

        可以看出,误差越大,P的输出就越大,所以P的作用是减小误差,但是只有P算法会发生超调现象,即在不受外力下可以看作简谐运动,一直震荡

I(积分)算法:Ki*误差的积分。

        可以看出,只要存在误差(一般叫做稳态误差,比如小车在平衡位置偏左或右一点点,但是又不会倒下等等的情况下产生的角度误差)就会一直累加,累加累加的总误差就变的很大,滚雪球一样,越来越大,所以I可以消除稳态误差

D(微分):Kd*误差的微分。

        可以看出,两次误差之差反映的是系统的反应速度,响应越快,误差之差越大,D输出很大,反之很小,所以D算法会抑制过冲,消弱系统的反应速度。例如简谐运动,以最下点为期望点,小球从空中开始速度很小,后面越来越快,即可以理解为误差微分越来越大,且为负的,所以D输出就越来越大,力的方向与小球运动方向相反,若没有D算法,小球就会继续简谐运动,若此时有了D算法,小球的运动就会收到阻碍而令小球到达的高度降低,长此以往,小球就会静止在最低点

        也可以这样看,在水中挥拳,挥的速度越大,受到的阻尼越大

直立环

PWM_OUT=Kp*误差+Kd*误差的微分

误差=真实角度-期望角度

误差的微分=角速度,姿态角转换得到

作用:让小车保持短时间的平衡,但是推一下就可能倒下

/*
直立环
PWM_OUT = Kp*角度偏差+Kd*角度偏差的微分
角度偏差求微分就是对角度偏差求导,即为角速度
gyro_Y:俯仰角的角速度
*/

int Vertical(float Expect_Angle,float Angle,float gyro_Y)
{
	int PWM_out1=0;
	PWM_out1 = Vertical_Kp*(Expect_Angle-Angle)+Vertical_Kd*(gyro_Y-0);
	return PWM_out1;
}
/*

速度环

PWM_OUT=Kp*误差+Ki*误差的积分 

误差:期望速度-真实速度

误差的积分=误差累加

作用:消除稳态误差,加强系统的反应速度

极性问题:

速度环在平衡一类的基本上都是用正反馈,即积分误差,放大误差,先注释掉直立环,则极性正确的现象就是转动一下轮子,立刻就会加速到最大,因为我们速度理论值是0,我们转了一下,产生了误差,速度环不断放大误差,使速度环输出越大,就会让轮子不断加速到最大速度,若是负反馈,我们很难转动轮子

int Velocity(int Target,int left,int right)
{	
	static int Encoder_S,EnC_Err_Lowout_last,PWM_out3,Encoder_Err,EnC_Err_Lowout;
	float a = 0.7;
	Encoder_Err = left+right-Target;//速度偏差
	
	//对速度偏差进行一阶低通滤波
	EnC_Err_Lowout = a*EnC_Err_Lowout_last+(1-a)*Encoder_Err;
	EnC_Err_Lowout_last=EnC_Err_Lowout;
	
	//积分
	Encoder_S+=EnC_Err_Lowout;
	//限幅
	Encoder_S=I_Limit(Encoder_S);
	
	PWM_out3 = Velocity_Kp*EnC_Err_Lowout + Velocity_Ki*Encoder_S;
	
	return PWM_out3;	
}
int I_Limit(int Encoder_S)
{
	if(Encoder_S>10000)Encoder_S=10000;
	else if(Encoder_S<-10000)Encoder_S=-10000;
	else 
		Encoder_S=Encoder_S;
	return Encoder_S;
}

速度环必须滤波,因为速度会突变,突变的速度会对系统产生很大影响 

        滤波:编码器测到的数据(速度)是存在一些突变的,这些突变会导致系统的不稳定,所以我们要滤除这些突变,这就是滤波,类似于模电里面的“滤除电路中的高频信号”

一阶低通滤波:把权重给到上次滤波后的速度,另一个这次的速度为(1-a)倍,0.5<a<1

积分限幅:误差的积分在一直累加,若没有限幅,积分会越来越大,举个例子:小车倒下了,我们为了保护电机而关掉了电机,但是单片机的电源并没有关掉,误差一直在累加,很大很大了,当我们把小车放好并打开电机后,由于I的作用根本无法平衡。所以要限幅。

串级PID 

 串级,顾名思义,就是一个环的输出作为另一个环的输入,例如速度环的输出作为直立环的输入,或者直立环的输出作为速度环的输入

速度环输入:1.给定速度。2.速度反馈。

输出:角度值(直立环的期望速度输入)

直立环输入:1.给定角度(速度环输出)。2.角度反馈

输出:PWM(直接控制小车)

Vertical_out=Kp1*(Angle-Expect_Angle)+Kd* gyro_y

直立环输出=Kp1*(真实角度-期望角度+机械中值)+Kd*角度偏差的微分

Velocity_out =Kp2*(Encoder_ real- Encoder_ expect)+Ki*(Encoder_ real- Encoder_ expect)的积分

速度环输出=Kp2*(反馈编码器值-期望编码器值)+Ki*编码器偏差的积分

合并推导:Expect_Angle   =     Velocity_out

Vertical_out = Kp1*{ Angle-[ Kp2*(Encoder_ real- Encoder_ expect)+Ki*Σ(Encoder_ real- Encoder_ expect) ]}+Kd*gyro_y

          =Kp1*真实角度+ Kd*角度偏差的微分-Kp1* [Kp2*编码器偏差- Ki *编码器偏差的积分]

                         

三.使用到的外设 

      1.定时器输出比较-PWM

void PWM_Init_TIM1(uint16_t Psc,uint16_t Per)
{
	//开时钟,AFIO
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1 | RCC_APB2Periph_AFIO,ENABLE);

	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_8 | GPIO_Pin_11;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);//因为没有将所有的结构体内容全部配置,所以这里先初始化一下
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;//不分频----滤波器的采样频率,可以由内部时钟直接提供,
																													//也可以由内部时钟加一个时钟分频而来,
																													//分频系数就是由TIM_ClockDivision决定
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
	TIM_TimeBaseInitStruct.TIM_Period = Per;//ARR的值
	TIM_TimeBaseInitStruct.TIM_Prescaler = Psc;//PSC的值
	//TIM_TimeBaseInitStruct.TIM_RepetitionCounter  重复计数器,这里不需要
	TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct);
	
	TIM_OCInitTypeDef  TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);//初始化输出比较结构体
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//输出比较模式 
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //极性,有效电平为高电平
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//输出使能
	TIM_OCInitStruct.TIM_Pulse = 0;//CCR
	TIM_OC1Init(TIM1,&TIM_OCInitStruct);
	TIM_OC4Init(TIM1,&TIM_OCInitStruct);
	
	TIM_CtrlPWMOutputs(TIM1,ENABLE);//高级定时器特有的,必须使能
	
	//使能ARR影子寄存器
	TIM_ARRPreloadConfig(TIM1,ENABLE);
	//使能输出比较预装载值寄存器
	TIM_OC4PreloadConfig(TIM1,TIM_OCPreload_Enable);
	TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);
	
	TIM_Cmd(TIM1,ENABLE);
}
	

2.定时器编码器模式 

//配置编码器
//编码器1-PA0/PA1-TIM2
//编码器2-PB6/PB7-TIM4
void Encoder_TIM2_Init()
{
	//开启GPIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//开启定时器时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//初始化定时器	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);//因为没有将所有的结构体内容全部配置,所以这里先初始化一下
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;//滤波分频系数
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
	TIM_TimeBaseInitStruct.TIM_Period = 65535;//ARR的值
	TIM_TimeBaseInitStruct.TIM_Prescaler = 0;//PSC的值
	//TIM_TimeBaseInitStruct.TIM_RepetitionCounter  重复计数器,这里不需要
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
	
	//编码器特有的配置函数,配置模式
	TIM_EncoderInterfaceConfig(TIM2,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);

	//初始化输入捕获
	TIM_ICInitTypeDef TIM_ICInitStruct;
	TIM_ICStructInit(&TIM_ICInitStruct);//因为没有将所有的结构体内容全部配置,所以这里先初始化一下
	TIM_ICInitStruct.TIM_ICFilter = 10;// 滤波器,范围是 0x0 and 0xF
	TIM_ICInit(TIM2,&TIM_ICInitStruct);
	
	//清除定时器溢出中断标志位
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	//配置溢出中断
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	//设置计数器初始值为0
	TIM_SetCounter(TIM2,0);
	//开启定时器
	TIM_Cmd(TIM2,ENABLE);
}


void Encoder_TIM4_Init()
{
	//开启GPIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	//开启定时器时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
	
	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	//初始化定时器	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);//因为没有将所有的结构体内容全部配置,所以这里先初始化一下
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;//外部时钟滤波分频系数
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
	TIM_TimeBaseInitStruct.TIM_Period = 65535;//ARR的值
	TIM_TimeBaseInitStruct.TIM_Prescaler = 0;//PSC的值
	//TIM_TimeBaseInitStruct.TIM_RepetitionCounter  重复计数器,这里不需要
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStruct);
	
	//编码器特有的配置函数
	TIM_EncoderInterfaceConfig(TIM4,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);

	//配置IC输入
	TIM_ICInitTypeDef TIM_ICInitStruct;
	TIM_ICStructInit(&TIM_ICInitStruct);//因为没有将所有的结构体内容全部配置,所以这里先初始化一下
	TIM_ICInitStruct.TIM_ICFilter = 10;// 滤波器
	TIM_ICInit(TIM4,&TIM_ICInitStruct);
	
	//清除定时器溢出中断标志位
	TIM_ClearFlag(TIM4,TIM_FLAG_Update);
	//配置溢出中断
	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
	//设置计数器初始值为0
	TIM_SetCounter(TIM4,0);
	//开启定时器
	TIM_Cmd(TIM4,ENABLE);
}

3.编码器读取速度 

/*******************
编码器速度读取函数
	*入口参数:定时器2/4
*******************/
int Read_Speed(int TIMx)
{
	int value_1;
	switch(TIMx)
	{
		//int ? short
		case 2:value_1=(short)TIM_GetCounter(TIM2);TIM_SetCounter(TIM2,0);break; //先读取编码器的计数值,然后清零计数值,目的是直接获得速度,而不用计数值相减来算速度
		case 4:value_1=(short)TIM_GetCounter(TIM4);TIM_SetCounter(TIM4,0);break;
		default :value_1 = 0;
	}
	//这里TIM_GetCounter()函数的返回值是uint16_t ,而我们的返回值是有符号的int类型,所以这里强制类型转化一下
	return value_1;
}

4.电机驱动函数


//电机初始化函数
void Motor_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;//复用推挽
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
}


//限幅函数
void Limit(int *motorA ,int *motorB)
{
	if(*motorA > PWM_MAX)*motorA=PWM_MAX;
	if(*motorA < PWM_MIN)*motorA=PWM_MIN;
	if(*motorB > PWM_MAX)*motorB=PWM_MAX;
	if(*motorB < PWM_MIN)*motorB=PWM_MIN;
}

//绝对值函数
int abs(int p)
{
	int q;
	q = p>0?p:(-p);
	return q;
}

//电机驱动函数
//入口参数:PID运算完成后最终PWM值
void Load(int moto1,int moto2)
{
	//判断正反转
	if(moto1>0)Ain1=1,Ain2=0;
	else 			 Ain1=0,Ain2=1;
	//输入PWM的绝对值
	TIM_SetCompare1(TIM1,abs(moto1));
	
	if(moto2>0)Bin1=1,Bin2=0;
	else 			 Bin1=0,Bin2=1;
	TIM_SetCompare4(TIM1,abs(moto2));
}

//电机为10KHZ
//72000000/7200 = 10 000 HZ
#define PWM_MAX		 7200	
#define PWM_MIN		-7200

extern int MOTO1,MOTO2;
#define Ain1	PBout(14)
#define Ain2	PBout(15)

#define Bin1	PBout(13)
#define Bin2	PBout(12)

5.外部中断

dmp读取是用的中断读取,10ms读取一次,所以我们要配置MPU6050的外部中断

void MPU6050_EXTI_Init(void)
{

	//开启时钟
	//因为是复用功能,所以开启AFIO
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);
	
	//配置GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;//GPIO_Mode_AF_PP;复用推挽
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);	
	
	//映射GPIO和外部中断
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5);
	
	//配置EXTI结构体
	EXTI_InitTypeDef  EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line = EXTI_Line5;//中断线
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;//使能中断线
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
	EXTI_Init(&EXTI_InitStruct);
	
}

void NVIC_Config()
{
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	//外部中断
	NVIC_InitTypeDef  NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitStruct);
	
	//串口
	NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStruct);
}


void EXTI9_5_IRQHandler(void)
写中断服务函数,里面做的是PID算法
void EXTI9_5_IRQHandler(void)
{		
	
	if(EXTI_GetITStatus(EXTI_Line5) == SET)//MPU6050外部中断是PB5
	{
		if(PBin(5) == 0)//引脚定义为外部上拉,而外部中断触发模式是下降沿,这里就是再进行下降沿的检测
		{
			
			EXTI_ClearITPendingBit(EXTI_Line5);
			
			//1.采集编码器数据和MPU6050的角度信息
			Encoder_Left  = -Read_Speed(2);//因为电机是相对安装的,即左右电机相差180度,为了让编码器输出极性一致,
			Encoder_Right = Read_Speed(4);//所以需要取反,或者调转一下极性也可以
										
			mpu_dmp_get_data(&Pitch,&Roll,&Yaw);		
			MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);
			MPU_Get_Accelerometer(&aacx,&aacy,&aacz);
			
			//2.将数据压入闭环控制中,计算输出控制量			
			Velocity_out = Velocity(Target_Speed,Encoder_Left,Encoder_Right);
			Vertical_out = Vertical(Velocity_out+Med_Angle,Pitch,gyroy);
			Turn_out = Turn(gyroz);	
			
			PWM_out = Vertical_out;
			
			//3.把控制量加载到电机上
			MOTO1 = PWM_out-Turn_out;//这里一加一减是因为两个电机是反向安装的,实际上就是同向加减了
			MOTO2 = PWM_out+Turn_out;
			Limit(&MOTO1,&MOTO2);
			
			Load(MOTO1,MOTO2);
		}
	}
}

四、小车

本人不会打板,所以选择了做一回杜邦线战神!

调了直立环和速度环,但是不理想,不能很好的回位

 

调试 

串级的PID调试时应该断掉两个环的连接

机械中值把平衡小车放在地面上,从前向后以及从后向前绕电机轴旋转平衡小车,两次的向另一边倒下的角度的中值,就是机械中值。

直立环

Kp极性:

极性错误:小车往哪边倒,车轮就往反方向开,会使得小车加速倒下。

极性正确:小车往哪边倒,车轮就往哪边开,以保证小车有直立的趋势。

Kp大小:

Kp一直增加,直到出现大幅低频震荡

Kd极性:

极性错误:拿起小车绕电机轴旋转,车轮反向转动,无跟随。

极性正确:拿起小车绕电机轴旋转,车轮同向转动,有跟随。

Kd大小:

Kd一直增加,直到出现高频震荡

直立环调试完毕后,对所有确立的参数乘以0.6作为最终参数。

原因:之前得到的参数都是Kp、Kd最大值,根据工程经验平衡小车的理想参数为最大参数乘以0.6求得。

结果:乘以0.6后,小车的抖动消失,但同时直立效果也变差。待下面加入速度环就能得到更好的性能。

在调试速度环参数极性时:需要去掉(注释掉)直立环运算

在调试速度环参数大小时:再次引入(取消注释)直立环运算

Kp&Ki

线性关系、Ki=(1/200)*Kp、仅调Kp即可。

Kp&Ki极性:

极性错误:手动转动其中一个车轮,另一车轮会以同样速度反向旋转——典型负反馈。

极性正确:手动转动其中一个车轮,两个车伦会同向加速,直至电机最大速度——典型正反馈。

Kp&Ki大小:

增加Kp&Ki,直至:小车保持平衡的同时,速度接近于零。且回位效果较好。

转向环

Kp极性:

极性错误:拿起小车,并将小车绕Z轴旋转,两车轮旋转的趋势与小车旋转趋势一致——典型正反馈。

极性正确:拿起小车,并将小车绕Z轴旋转,两车轮旋转的趋势与小车旋转趋势相反——典型负反馈。

Kp大小:

加大Kp,直至走直线效果较好,且无剧烈抖动。 

参考于b站up主天下行走的平衡车教学 

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

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

相关文章

C++类和对象进阶

CSDN成就一亿技术人 C类的6个默认成员函数(构造)-CSDN博客https://blog.csdn.net/lh11223326/article/details/136917667?spm1001.2014.3001.5502 目录 一.再谈构造函数 1.构造函数体赋值&#xff1a; 在创建对象时&am…

# Maven Bom 的使用

Maven Bom 的使用 文章目录 Maven Bom 的使用概述BOM特点优点缺点 MavenMaven 安装安装步骤settingx.ml常用仓库地址Idea 使用maven常见坑 SpringBoot 项目Bom使用案例项目结构主项目 zerocode-back-servezc-dependency&#xff08;第三方jar管理&#xff09;子模块zc-serve子模…

Qt creator构建DLL库

文章目录 一、构建DLL库二、隐式调用DLL库 一、构建DLL库 Qt creator创建DLL项目。 实现功能函数。 运行代码&#xff0c;debug目录下会有.dll和.lib文件。 二、隐式调用DLL库 QT新建控制台项目。将.lib文件和与之关联的头文件赋值到项目文件夹。 3. 添加头文件和外部依赖库…

目标检测——YOLOR算法解读

论文&#xff1a;YOLOR-You Only Learn One Representation: Unifified Network for Multiple Tasks 作者&#xff1a;Chien-Yao Wang, I-Hau Yeh, Hong-Yuan Mark Liao 链接&#xff1a;https://arxiv.org/abs/2105.04206 代码&#xff1a;https://github.com/WongKinYiu/yolo…

Python界面库Flet(1)介绍和快速使用

Python界面库Flet(1)快速上手使用 Author&#xff1a;Once Day Date&#xff1a;2024年3月19日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: Pyt…

利用sealos安装k8s集群

1. 环境准备 准备三台干净&#xff08;未安装过k8s环境&#xff09;的虚拟机 # 所有的主机都要配置主机名和域名映射 # 设置主机名 hostnamectl set-hostname k8s-master01 # vim /etc/hosts 192.168.59.201 k8s-master01 192.168.59.202 k8s-worker01 192.168.59.203 k8…

飞鸟写作能用吗 #笔记#笔记

飞鸟写作是一个强大的论文写作工具&#xff0c;不仅可以帮助用户高效、准确地完成论文写作&#xff0c;还能帮助用户对论文进行查重和降重。那么&#xff0c;飞鸟写作能用吗&#xff1f;答案是肯定的&#xff0c;飞鸟写作非常好用&#xff01; 首先&#xff0c;飞鸟写作拥有强大…

视频记录历史播放位置效果

简介 每次打开页面视频从上一次的播放位置开始播放 利用lodash库做节流 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-sca…

MySQL | 视图

视图是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。视图的数据变化会影响到基表&#xff0c;基表的数据变化也会影响到视图。 1. 基本使用 1.1. 创建视图 create view 视图名 as select语句&#xff1b; 创建测…

自动驾驶轨迹规划之时空语义走廊(一)

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 目录 1.摘要 2.系统架构 3.MPDM 4.时空语义走廊 ​4.1 种子生成 4.2 具有语义边界的cube inflation ​4.3 立方体松弛 本文解析了丁文超老师…

JetBrains数据库驱动下载失败解决方法

本方法可通用于解决PyCharm等JetBrains家的IDE下载数据库驱动问题。 在Jet家IDE内连接数据库时&#xff0c;mysql、sqlite等的驱动有部分在 https://download.jetbrains.com 网站上&#xff0c;可能由于网络问题无法访问。 解决方法是修改 JetBrains 路径下的 jdbc.drivers.xm…

计算机基础系列 —— 从 Nand 门、DFF 到 RAM

Memory: The faculty of the brain by which data or information is encoded, stored, and retrieved when needed.It is the retention of information over time for the purpose of influencing future action —— Wikipedia 文中提到的所有实现都可以参考&#xff1a;nan…

Typecho如何去掉/隐藏index.php

Typecho后台设置永久链接后&#xff0c;会在域名后加上index.php&#xff0c;很多人都接受不了。例如如下网址&#xff1a;https://www.jichun29.cn/index.php/archives/37/&#xff0c;但我们希望最终的形式是这样&#xff1a;https://www.jichun29.cn/archives/37.html。那么…

【Oracle】Linux——Centos7安装Oracle12c

安装前拍快照、安装前拍快照、安装前拍快照 目录 安装前拍快照、安装前拍快照、安装前拍快照1.下载Oracle12C安装包2.基本环境搭建2.1创建用户和组2.2创建oralce安装目录,oracle用户分配目录权限2.3上传安装包 3.系统参数配置及服务器设置3.1依赖安装3.2内核参数配置3.3配置完成…

【项目自我反思之vue的组件通信】

为什么子组件不能通过props实时接收父组件修改后动态变化的值 一、现象二、可能的原因1.响应式系统的限制2.异步更新队列3.父组件和子组件的生命周期4.子组件内部对 props 的处理 三、组件通信的几种场景&#xff08;解决方案&#xff09;1.子组件想修改父组件的数据2.子组件传…

Keepalive与idle监测及性能优化

Keepalive 与 idle监测 Keepalive&#xff08;保活&#xff09;: Keepalive 是一种机制&#xff0c;通常用于TCP/IP网络。它的目的是确保连接双方都知道对方仍然存在并且连接是活动的。这是通过定期发送控制消息&#xff08;称为keepalive消息&#xff09;实现的。如果在预定时…

机器学习K-means算法

K-Means 算法&#xff08;K-Means算法、K-Means 中心值计算、K-Means 距离计算公式、K-Means 算法迭代步骤、K-Means算法实例&#xff09; 问题引入 给你如下两种图片&#xff0c;快读回答2个问题&#xff0c;问 图1 中有几类五谷杂粮&#xff1f;问 图2 中有几类五谷杂粮&…

深度分析鸿蒙应用开发的准确红利期、前景、未来发展方向

近年来&#xff0c;随着互联网技术的不断发展&#xff0c;鸿蒙生态开发逐渐成为热门话题。作为一种新兴的操作系统&#xff0c;其发展趋势备受关注。同时&#xff0c;鸿蒙生态开发的价值、就业岗位需求以及相关学习方面也引起了广泛关注。 那么就目前的形势来看&#xff0c;鸿…

6-191 拓扑排序

一项工程由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其他子任务后才能执行。例如,下图表示了一项工程若干子任务之间的先后关系。 编写函数输出所有子任务的拓扑序列。 函数接口定义: Status Push_SeqStack(SeqStack &s, ElemType x)//入栈,x入到…

镁光的sdram手册阅读--MT48LCC16M16A2

镁光的sdram手册阅读–MT48LCC16M16A2 一、这个sdram的总容量是256Mb&#xff0c;MT48LC16M16A2对应的参数是&#xff1a;4Meg 16 4banks&#xff0c;也可表示为16M16。4164256Mbit。 1&#xff09;其中&#xff0c;4Meg表示单个bank包含的存储单元个数&#xff0c;计算公式…