当前位置: 首页 > news >正文

【STM32】飞控设计

【一些入门知识】

1.飞行原理

 【垂直运动】

mg>F1+F2+F3+F4,此时做下降加速飞行
mg<F1+F2+F3+F4,此时做升高加速飞行
mg=F1+F2+F3+F4 ,此时垂直上保持匀速飞行。

 【偏航飞行】

ω 4 + ω 2 ≠ ω 1+ ω 3  就会产生水平旋转

 【俯仰飞行】

F1+F4<F2+F3 向前飞行
F1+F4>F2+F3 向后飞行

【横滚飞行】

F4+F3>F1+F2 向右飞行
F4+F3<F1+F2 向左飞行

 2.串级PID

3.飞控的控制系统

4.姿态解算

 一.硬件设计(简)

【主控】

1.电源:3.7V锂电池供电 - DCDC升压至5V -  LDO稳压3.3V

2.USB - 上位机

3.SPI - NRF24L01无线通讯

4.I2C - MPU6050陀螺仪

5.4个PWM

6.主控STM32F103C8T6

【遥控】

1.电源:3.7V锂电池供电 - LDO稳压3.3V

2.I2C - AT24CO2

3.4个ADC - 两个遥感

4.8个IO口 - 8个按键

5.SPI - NRF24L01无线通讯

6.主控STM32F103C8T6

二.主控程序

【MPU6050读取飞控三轴加速度、角速度 并且 卡尔曼滤波】

通过 MPU6050 寄存器手册:我们需要读取的三轴加速度和三轴角速度位于寄存器 0x3B~0X48,读取数据后,需要合成 16bit 的数据。
//从 0x3B 读取 6 个字节放到 buffer 里面
#define Acc_Read() i2cRead(0x68, 0X3B,6,buffer)//从 0x43 读取 6 个字节放到 buffer 里面
#define Gyro_Read() i2cRead(0x68, 0x43,6,&buffer[6])void MpuGetData(void) //读取陀螺仪数据加滤波
{uint8_t i;uint8_t buffer[12];Acc_Read();//读取加速度Gyro_Read();//读取角速度for(i=0;i<6;i++){//整合为 16bit,并减去水平静止校准值pMpu[i] = (((int16_t)buffer[i<<1] << 8) | buffer[(i<<1)+1])-MpuOffset[i];if(i < 3)//对加速度做卡尔曼滤波{{//卡尔曼滤波的数据初始化,这个 8192 是初始化默认 1 个 g 的加速度static struct _1_ekf_filter ekf[3] = {{0.02,0,0,0,0.001,0.543}{0.02,0, 0,0,0.001,0.543},{0.02,0, 0,0,0.001,0.543}};kalman_1(&ekf[i],(float)pMpu[i]); //调用一维卡尔曼滤波函数pMpu[i] = (int16_t)ekf[i].out;//卡尔曼滤波输出}}if(i > 2)//以下对角速度做一阶低通滤波{uint8_t k=i-3;const float factor = 0.15f; //滤波因素,因数越小,滤波力度越大static float last_mpuData[3];//滤波并保存滤波数据 last_mpuData[k] = last_mpuData[k] * (1 - factor) + pMpu[i] * factor; pMpu[i] = last_mpuData[k];//滤波输出}}
}

【遥控数据解析】

void RC_Analy(void)  
{static uint16_t cnt;if(NRF24L01_RxPacket(RC_rxData)==SUCCESS){ 	uint8_t i;uint8_t CheckSum=0;uint16_t thr;cnt = 0;for(i=0;i<31;i++){CheckSum +=  RC_rxData[i]; //检查数据的数量是否是31个}if(RC_rxData[31]==CheckSum && RC_rxData[0]==0xAA && RC_rxData[1]==0xAF)  //如果接收到的遥控数据正确{Remote.roll = ((uint16_t)RC_rxData[4]<<8) | RC_rxData[5];  //通道1Remote.roll = LIMIT(Remote.roll,1000,2000);Remote.pitch = ((uint16_t)RC_rxData[6]<<8) | RC_rxData[7];  //通道2Remote.pitch = LIMIT(Remote.pitch,1000,2000);Remote.thr = 	((uint16_t)RC_rxData[8]<<8) | RC_rxData[9];   //通道3Remote.thr = 	LIMIT(Remote.thr,1000,2000);Remote.yaw =  ((uint16_t)RC_rxData[10]<<8) | RC_rxData[11];   //通道4Remote.yaw =  LIMIT(Remote.yaw,1000,2000);Remote.AUX1 =  ((uint16_t)RC_rxData[12]<<8) | RC_rxData[13];   //通道5  左上角按键都属于通道5  Remote.AUX1 =  LIMIT(Remote.AUX1,1000,2000);Remote.AUX2 =  ((uint16_t)RC_rxData[14]<<8) | RC_rxData[15];   //通道6  右上角按键都属于通道6 Remote.AUX2 =  LIMIT(Remote.AUX2,1000,2000);Remote.AUX3 =  ((uint16_t)RC_rxData[16]<<8) | RC_rxData[17];   //通道7  左下边按键都属于通道7 Remote.AUX3 =  LIMIT(Remote.AUX3,1000,2000);Remote.AUX4 =  ((uint16_t)RC_rxData[18]<<8) | RC_rxData[19];   //通道8  右下边按键都属于通道6  Remote.AUX4 = LIMIT(Remote.AUX4,1000,4000);	{const float roll_pitch_ratio = 0.04f;const float yaw_ratio =   0.3f;	pidPitch.desired =-(Remote.pitch-1500)*roll_pitch_ratio;	 //将遥杆值作为飞行角度的期望值pidRoll.desired = -(Remote.roll-1500)*roll_pitch_ratio;if(Remote.yaw>1820){pidYaw.desired -= yaw_ratio;	}else if(Remote.yaw <1180){pidYaw.desired += yaw_ratio;	}						}remote_unlock();}}
//如果3秒没收到遥控数据,则判断遥控信号丢失,飞控在任何时候停止飞行,避免伤人。
//意外情况,使用者可紧急关闭遥控电源,飞行器会在3秒后立即关闭,避免伤人。
//立即关闭遥控,如果在飞行中会直接掉落,可能会损坏飞行器。else{cnt++;if(cnt>500){cnt = 0;ALL_flag.unlock = 0; NRF24L01_init();}}
}

【PID控制器的设计】

void FlightPidControl(float dt)
{volatile static uint8_t status=WAITING_1;switch(status){		case WAITING_1: //等待解锁if(ALL_flag.unlock){status = READY_11;	}			break;case READY_11:  //准备进入控制pidRest(pPidObject,6); //批量复位PID数据,防止上次遗留的数据影响本次控制Angle.yaw = pidYaw.desired =  pidYaw.measured = 0;   //锁定偏航角status = PROCESS_31;break;			case PROCESS_31: //正式进入控制if(Angle.pitch<-50||Angle.pitch>50||Angle.roll<-50||Angle.roll>50)//倾斜检测,大角度判定为意外情况,则紧急上锁	if(Remote.thr>1200)//当油门的很低时不做倾斜检测ALL_flag.unlock = EMERGENT;//打入紧急情况pidRateX.measured = MPU6050.gyroX * Gyro_G; //内环测量值 角度/秒pidRateY.measured = MPU6050.gyroY * Gyro_G;pidRateZ.measured = MPU6050.gyroZ * Gyro_G;pidPitch.measured = Angle.pitch; //外环测量值 单位:角度pidRoll.measured = Angle.roll;pidYaw.measured = Angle.yaw;pidUpdate(&pidRoll,dt);    //调用PID处理函数来处理外环	横滚角PID		pidRateX.desired = pidRoll.out; //将外环的PID输出作为内环PID的期望值即为串级PIDpidUpdate(&pidRateX,dt);  //再调用内环pidUpdate(&pidPitch,dt);    //调用PID处理函数来处理外环	俯仰角PID	pidRateY.desired = pidPitch.out;  pidUpdate(&pidRateY,dt); //再调用内环CascadePID(&pidRateZ,&pidYaw,dt);	//也可以直接调用串级PID函数来处理break;case EXIT_255:  //退出控制pidRest(pPidObject,6);status = WAITING_1;//返回等待解锁break;default:status = EXIT_255;break;}if(ALL_flag.unlock == EMERGENT) //意外情况,请使用遥控紧急上锁,飞控就可以在任何情况下紧急中止飞行,锁定飞行器,退出PID控制status = EXIT_255;
}

【4路PWM电机驱动】

void TIM2_PWM_Config(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;GPIO_InitTypeDef GPIO_InitStructure;/* 使能 GPIOA 时钟时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);/* 使能定时器 2 时钟 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);/* Time base configuration */TIM_TimeBaseStructure.TIM_Period = 999; //定时器计数周期 0-999 1000TIM_TimeBaseStructure.TIM_Prescaler = 8; //设置预分频:8+1 分频 8K PWM 频率TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分频系数:不分频TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);/* PWM1 Mode configuration: Channel */TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //配置为 PWM 模式 1TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;//设置跳变值,当计数器计数到这个值时,电平发生跳变(即占空比) 初始值 0TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//当定时器计数值小于定时设定值时为高电平/* 使能通道 1 */TIM_OC1Init(TIM2, &TIM_OCInitStructure);TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);/* 使能通道 2 */TIM_OC2Init(TIM2, &TIM_OCInitStructure);TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);/* 使能通道 3 */TIM_OC3Init(TIM2, &TIM_OCInitStructure);TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);
/* 使能通道 4 */TIM_OC4Init(TIM2, &TIM_OCInitStructure);TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);TIM_ARRPreloadConfig(TIM2, ENABLE); // 使能 TIM2 重载寄存器 ARRTIM_Cmd(TIM2, ENABLE); //使能定时器 2
}

【解锁 - 启动步骤 - 电机动力分配】

void MotorControl(void)
{	volatile static uint8_t status=WAITING_1;if(ALL_flag.unlock == EMERGENT) //意外情况,请使用遥控紧急上锁,飞控就可以在任何情况下紧急中止飞行,锁定飞行器,退出PID控制status = EXIT_255;	switch(status){		case WAITING_1: //等待解锁	MOTOR1 = MOTOR2 = MOTOR3 = MOTOR4 = 0;  //如果锁定,则电机输出都为0if(ALL_flag.unlock){status = WAITING_2;}case WAITING_2: //解锁完成后判断使用者是否开始拨动遥杆进行飞行控制if(Remote.thr>1100){low_thr_cnt_quiet=0;low_thr_cnt=0;pidRest(pPidObject,6);status = PROCESS_31;}break;case PROCESS_31:{int16_t temp,thr;temp = Remote.thr -1000; //油门+定高输出值//油门比例规划thr = 250+0.45f * temp;if(temp<10) //自动关停判断{if(low_thr_cnt<1500)low_thr_cnt++;thr = thr-(low_thr_cnt*0.6);//油门摇杆值慢慢降为0 if(MPU6050.accZ<8500&&MPU6050.accZ>7800){low_thr_cnt++;if(low_thr_cnt>600)//1800ms{thr = 0;pidRest(pPidObject,6);MOTOR1 = MOTOR2 = MOTOR3 = MOTOR4 =0;status = WAITING_2;break;}}} else low_thr_cnt=0;MOTOR1 = MOTOR2 = MOTOR3 = MOTOR4 = LIMIT(thr,0,700); //留100给姿态控制//以下输出的脉冲分配取决于电机PWM分布与飞控坐标体系。请看飞控坐标体系图解,与四个电机PWM分布分布	
//           机头      
//   PWM3     ♂       PWM1
//      *             *
//      	*       *
//    		  *   *
//      	    *  
//    		  *   *
//         *        *
//      *             *
//    PWM4           PWM2			
//		pidRateX.out 横滚角串级PID输出 控制左右,可以看出1 2和3 4,左右两组电机同增同减
//      pidRateY.out 俯仰角串级PID输出 控制前后,可以看出2 3和1 4,前后两组电机同增同减
//		pidRateZ.out 横滚角串级PID输出 控制旋转,可以看出2 4和1 3,两组对角线电机同增同减	// 正负号取决于算法输出 比如输出是正的话  往前飞必然是尾巴两个电机增加,往右飞必然是左边两个电机增加		MOTOR1 +=    + pidRateX.out + pidRateY.out + pidRateZ.out;//; 姿态输出分配给各个电机的控制量MOTOR2 +=    + pidRateX.out - pidRateY.out - pidRateZ.out ;//;MOTOR3 +=    - pidRateX.out + pidRateY.out - pidRateZ.out;MOTOR4 +=    - pidRateX.out - pidRateY.out + pidRateZ.out;//;}	break;case EXIT_255:MOTOR1 = MOTOR2 = MOTOR3 = MOTOR4 = 0;  //如果锁定,则电机输出都为0status = WAITING_1;	break;default:break;}TIM2->CCR1 = LIMIT(MOTOR1,0,1000);  //更新PWMTIM2->CCR2 = LIMIT(MOTOR2,0,1000);TIM2->CCR3 = LIMIT(MOTOR3,0,1000);TIM2->CCR4 = LIMIT(MOTOR4,0,1000);
} 

【水平校准】

MPU6050 获取的数值要减去水平静止校准值才是真正的飞控可用数据
void MpuGetOffset(void) //校准
{int32_t buffer[6]={0};int16_t i;  uint8_t k=30;const int8_t MAX_GYRO_QUIET = 5;const int8_t MIN_GYRO_QUIET = -5;	
/*           wait for calm down    	                                                          */int16_t LastGyro[3] = {0};int16_t ErrorGyro[3];	/*           set offset initial to zero    		*/memset(MpuOffset,0,12);MpuOffset[2] = 8192;   //set offset from the 8192  TIM_ITConfig(  //使能或者失能指定的TIM中断TIM1,TIM_IT_Update ,DISABLE  //使能);	while(k--)//30次静止则判定飞行器处于静止状态{do{delay_ms(10);MpuGetData();for(i=0;i<3;i++){ErrorGyro[i] = pMpu[i+3] - LastGyro[i];LastGyro[i] = pMpu[i+3];	}			}while ((ErrorGyro[0] >  MAX_GYRO_QUIET )|| (ErrorGyro[0] < MIN_GYRO_QUIET)//标定静止||(ErrorGyro[1] > MAX_GYRO_QUIET )|| (ErrorGyro[1] < MIN_GYRO_QUIET)||(ErrorGyro[2] > MAX_GYRO_QUIET )|| (ErrorGyro[2] < MIN_GYRO_QUIET));}	/*           throw first 100  group data and make 256 group average as offset                    */	for(i=0;i<356;i++)//水平校准{		MpuGetData();if(100 <= i)//取256组数据进行平均{uint8_t k;for(k=0;k<6;k++){buffer[k] += pMpu[k];}}}for(i=0;i<6;i++){MpuOffset[i] = buffer[i]>>8;}TIM_ITConfig(  //使能或者失能指定的TIM中断TIM1, TIM_IT_Update ,ENABLE  //使能);FLASH_write(MpuOffset,6);//将数据写到FLASH中,一共有6个int16数据
}

三.遥控程序

摇杆ADC采集和转换

配置 4 路 ADC 采集遥控摇杆值。DMA 自动采集,转换完成后自动将 ADC 结果存于ADC_ConvertedValue 。
void ADC1_Mode_Config(void)
{DMA_InitTypeDef DMA_InitStructure;ADC_InitTypeDef ADC_InitStructure;/* DMA channel1 configuration */DMA_DeInit(DMA1_Channel1);DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //ADC 结果寄存器地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;//输入数组地址地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = 4;//转换 4 路DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址固定DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址固定DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //半字(12bit ADC存放)DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环传输DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel1, &DMA_InitStructure);/* Enable DMA channel1 */DMA_Cmd(DMA1_Channel1, ENABLE);/* ADC1 configuration */ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立 ADC 模式ADC_InitStructure.ADC_ScanConvMode = ENABLE ; //禁止扫描模式,扫描模式用于多通道采集ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //开启连续转换模式,即不停地进行 ADC 转换ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不使用外部触发转换ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //采集数据右对齐ADC_InitStructure.ADC_NbrOfChannel = 4; //4 路 ADC 通道ADC_Init(ADC1, &ADC_InitStructure);/*配置 ADC 时钟,为 PCLK2 的 8 分频,即 6MHz,ADC 频率最高不能超过 14MHz*/RCC_ADCCLKConfig(RCC_PCLK2_Div8); /*配置 ADC1 的通道 11 为 55. 5 个采样周期,序列为 1 */ ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);/* 使能 DMA 外设*/ADC_DMACmd(ADC1, ENABLE);/*使能 ADC1 外设 */ADC_Cmd(ADC1, ENABLE);/*复位校准寄存器 */ ADC_ResetCalibration(ADC1);/*等待校准寄存器复位完成 */while(ADC_GetResetCalibrationStatus(ADC1));
/* ADC 校准 */ADC_StartCalibration(ADC1);
/* 等待校准完成*/while(ADC_GetCalibrationStatus(ADC1));
/* 软件启动 ADC 转换 */ ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
每 10ms 进行一次 ADC 数据的转换为航模遥控数据:
12bitADC(0~4096)*0.25 +1000   ≈  航模标准数据 1000~2000

相关文章:

【STM32】飞控设计

【一些入门知识】 1.飞行原理 【垂直运动】 当 mg&#xff1e;F1F2F3F4&#xff0c;此时做下降加速飞行 当 mg&#xff1c;F1F2F3F4&#xff0c;此时做升高加速飞行 当 mgF1F2F3F4 &#xff0c;此时垂直上保持匀速飞行。 【偏航飞行】 ω 4 ω 2 ≠ ω 1 ω 3 就会产生水…...

MSPM0G3507——引脚分布图

...

MySQL CDC

一、MySQL CDC概念 MySQL CDC&#xff08;Change Data Capture&#xff09;&#xff0c;即MySQL变更数据捕获&#xff0c;是一种能够捕获MySQL数据库中数据变化&#xff08;包括插入、更新和删除操作&#xff09;的技术。这些变化可以实时或准实时地同步到其他系统或服务中&am…...

手把手教你安装 Vivado2022.2(附安装包)

​一、Vivado 2022.2 优势 Vivado 2022.2版本与之前的版本相比&#xff0c;具有以下几个显著的优势&#xff1a; 电源设计管理器&#xff08;PDM&#xff09;&#xff1a;Vivado 2022.2引入了全新的电源设计管理器&#xff08;PDM&#xff09;&#xff0c;这是一个下一代功耗评…...

旅行者1号有什么秘密?飞行240多亿公里,为什么没发生碰撞?

旅行者1号有什么秘密&#xff1f;飞行240多亿公里&#xff0c;为什么没发生碰撞&#xff1f; 自古以来&#xff0c;人类就对浩瀚无垠的宇宙充满了好奇与向往。从最初的仰望星空&#xff0c;到如今的深空探测&#xff0c;人类探测宇宙的历史发展可谓是一部波澜壮阔的史诗。 在…...

如何保护云主机安全

在数字化时代&#xff0c;云服务器已成为企业数据存储、处理和传输的重要工具。然而&#xff0c;随着其应用的广泛和深入&#xff0c;云服务器也面临着越来越多的安全威胁。为了应对这些威胁&#xff0c;白名单技术应运而生&#xff0c;成为保护云服务器安全的重要手段。 首先&…...

postman教程-19-mock测试

上一小节我们学习了Postman接口参数化方法&#xff0c;本小节我们讲解一下Postman mock测试的方法。 一、什么叫mock测试 mock测试就是在测试过程中&#xff0c;对某些不容易构造或者不容易获取的对象&#xff0c;用一个虚拟的对象来创建以便于测试的一种测试方法&#xff0c…...

纳秒级网络库【二】技术选型

在十年之前&#xff0c;已经有网络产品实现7纳秒延迟&#xff0c;所以无需质疑是否能够实现&#xff0c;关键问题是&#xff1a;代价是什么。国内不少量化公司在招聘低延迟总线的开发人员&#xff0c;虽然我不知道他们具体的技术选型&#xff0c;从技术底层来看&#xff0c;并没…...

ESP32基础应用之esp32连接腾讯云并使用微信小程序控制的智能灯

文章目录 1. 项目简介1.1 功能接收1.2 使用资源1.3 测试平台 2 腾讯云物联网开发平台3 esp32设备开发3.1 准备参考例程3.2 vscode平台创建测试工程3.3 修改工程 问题总结使用PowerShell命令行终端生成的二维码不能用 1. 项目简介 1.1 功能接收 实现腾讯云创建项目与设备&…...

Unity Protobuf+RPC+UniTask

远程过程调用&#xff08;RPC&#xff09;协议详解 什么是RPC协议RPC的基本原理RPC的关键组件RPC的优缺点Protobuf函数绑定CallEncodeRecvDecodeSocket.Send和Recv项目地址 什么是RPC协议 远程过程调用&#xff08;Remote Procedure Call&#xff0c;简称RPC&#xff09;是一种…...

顶顶通呼叫中心中间件(mod_cti基于FreeSWITCH)-通话时长限制

文章目录 前言联系我们场景运用机器人场景普通通话场景 前言 顶顶通呼叫中心中间件限制通话时长有两种写法&#xff0c;分别作用于机器人场景与普通通话场景。 普通场景可分为分机互打、分机外呼手机等。 联系我们 有意向了解呼叫中心中间件的用户&#xff0c;可以点击该链接…...

如何将ai集成到项目中,方法二

上一篇文章&#xff1a;如何将ai集成到radsystems项目中&#xff0c;在项目中引入ai-CSDN博客 上一篇文章内容主要针对于未实现权限分离的项目&#xff0c;这篇文章主要来说一下权限分离的项目怎么做&#xff0c;以及注意的细节。 一、编写前端router.js 二、编写前端askai.vu…...

python的变量的引用与赋值的学习

看代码&#xff1a; a 1 # 初始化变量a&#xff0c;赋值为1 b a # 变量b被赋值为变量a的值&#xff0c;此时b的值也为1 b 2 # 变量b被重新赋值为2 print(a) # 打印变量a的值 执行过程如下&#xff1a; a 1&#xff1a;变量a被赋值为1。b a&#xff1a;变量b被赋值为…...

【FPGA项目】bin文件ram存取回环测试

&#x1f389;欢迎来到FPGA专栏~bin文件ram存取回环测试 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;FPGA学习之旅 文章作者技术和水平有限&#xff0c;如果文中出现错误&#xff0c;希望大…...

北航数据结构与程序设计第五次作业选填题复习

选填题考的很多都是基础概念&#xff0c;对于巩固复习一些仡佬拐角的知识点是很有用的。非北航学生也可以来看看这些题&#xff0c;这一节主要是树方面的习题&#xff1a; 一、 我们首先需要知道一个公式 这是证明&#xff1a; 知道了这个公式&#xff0c;我们把题目中的数据…...

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第40课-实时订阅后端数据

【WEB前端2024】3D智体编程&#xff1a;乔布斯3D纪念馆-第40课-实时订阅后端数据 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界引…...

系统集成知识科普:核心原理与关键技术

目录 1.系统集成的核心原理 1.1 模块化原理 1.1.1 定义&#xff1a; 1.1.2 优势&#xff1a; 1.1.3 实现方式&#xff1a; 1.2 标准化原理 1.2.1 定义&#xff1a; 1.2.2 作用&#xff1a; 1.2.3 实践案例&#xff1a; 1.2.4 制定与遵循&#xff1a; 1.3 协同性原理…...

Coze+Discord:打造你的免费AI助手(教您如何免费使用GPT-4o/Gemini等最新最强的大模型/Discord如何正确连接Coze)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 准备Discord📝 准备Coze🔌 连接💡 测试效果⚓️ 相关链接 ⚓️📖 介绍 📖 你是否想免费使用GPT-4o/Gemini等最新最强的大模型,但又不想花费高昂的费用?本文将教你如何通过Coze搭建Bot,并将其转发…...

「OC」UI练习(二)——照片墙

「OC」UI练习——照片墙 文章目录 「OC」UI练习——照片墙UITapGestureRecognizer介绍照片墙实现 UITapGestureRecognizer介绍 UITapGestureRecognizer是UIKit框架中的一个手势识别器类&#xff0c;用于检测用户在视图上的轻击手势。它是UIGestureRecognizer的一个子类&#x…...

一手洞悉巴西slot游戏包投放本土网盟CPI广告优势

一手洞悉巴西slot游戏包投放本土网盟CPI广告优势 在巴西这片热土上&#xff0c;slot游戏包的投放本土网盟CPI广告是一项既充满挑战又富有机遇的任务。CPI&#xff08;Cost Per Install&#xff09;广告模式&#xff0c;即按安装付费&#xff0c;已经成为许多游戏开发商推广产品…...

中国环保网引领元宇宙新纪元 -探索绿色未来

在数字化浪潮的推动下&#xff0c;元宇宙这一概念正逐渐进入公众视野&#xff0c;成为科技与创新交汇的新前沿。作为环境保护的坚定倡导者&#xff0c;中国环保网秉承着推动绿色发展、构建生态文明的使命&#xff0c;正式踏入元宇宙领域&#xff0c;旨在通过高科技手段为环保事…...

2024最新流媒体在线音乐系统网站源码 音乐社区 多语言开心版

本文来自&#xff1a;2024最新流媒体在线音乐系统网站源码 音乐社区 多语言开心版 - 源码1688 应用介绍 简介&#xff1a; 2024最新流媒体在线音乐系统网站源码| 音乐社区 | 多语言 | 开心版 图片&#xff1a;...

【Java】解决Java报错:FileNotFoundException

文章目录 引言1. 错误详解2. 常见的出错场景2.1 文件路径错误2.2 文件名拼写错误2.3 文件权限问题2.4 文件路径未正确拼接 3. 解决方案3.1 检查文件路径3.2 使用相对路径和类路径3.3 检查文件权限3.4 使用文件选择器 4. 预防措施4.1 使用配置文件4.2 使用日志记录4.3 使用单元测…...

Seate分布式锁

XA模式 在第一阶段资源协调者&#xff08;TC&#xff09;会向资源管理者&#xff08;RM&#xff09;发出一个准备的请求&#xff0c;RM开始处理自身的业务&#xff0c;处理完成后不提交事务&#xff0c;而是向TC响应一个执行结果&#xff0c;表明自己成功还是失败&#xff0c;如…...

金融科技助力绿色金融:可持续发展新动力

随着全球气候变化和环境问题的日益严重&#xff0c;绿色金融作为推动环境保护和经济可持续发展的重要手段&#xff0c;已经受到越来越多的关注。而金融科技&#xff0c;作为科技与金融深度融合的产物&#xff0c;正以其独特的优势为绿色金融的发展注入新动力。本文将探讨金融科…...

灾备建设中虚拟机细粒度恢复的含义及技术使用

灾备建设中为了考虑虚拟机恢复的效率与实际的用途&#xff0c;在恢复上出了普通的恢复虚拟机&#xff0c;也有其余的恢复功能&#xff0c;比如瞬时恢复&#xff0c;细粒度恢复等。这里谈的就是细粒度恢复。 首先细粒度恢复是什么&#xff0c;这个恢复可以恢复单个备份下来的文…...

十种排序方法

目录 1.冒泡排序&#xff08;Bubble Sort&#xff09;代码实现 2.选择排序&#xff08;Selection Sort&#xff09;代码实现 3.插入排序&#xff08;Insertion Sort&#xff09; 4.希尔排序&#xff08;Shell Sort&#xff09;代码实现 5.快速排序&#xff08;Quick Sort&…...

docker-compose启动oracle11、并使用navicat进行连接

一、docker-compose.yml version: 3.9 services:oracle:image: registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11grestart: alwaysprivileged: truecontainer_name: oracle11gvolumes:- ./data:/u01/app/oracleports:- 1521:1521network_mode: "host"logging:d…...

使用ffmpeg进行音频处理

音频处理是数字媒体制作中不可或缺的一部分,而ffmpeg作为一款强大的多媒体处理工具,为我们提供了丰富的音频处理功能。 一、查看音频信息 在处理音频之前,了解音频的基本信息是非常重要的。FFmpeg的ffprobe工具可以帮助我们查看音频的详细信息,如采样率、位深等。 示例命…...

重装系统,以及设置 深度 学习环境

因为联想y7000在ubantu系统上连不到wifi,所以打算弄双系统 第一步&#xff1a;下载win10镜像&#xff0c;之后在系统用gparted新建个分区&#xff0c;格式化成ntfs&#xff0c;用来装win10系统 第二步&#xff0c;制作win10启动盘&#xff0c;这个需要先把u盘用disks格式化&a…...