【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读取飞控三轴加速度、角速度 并且 卡尔曼滤波】
//从 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采集和转换】
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);
}
12bitADC(0~4096)*0.25 +1000 ≈ 航模标准数据 1000~2000
相关文章:
【STM32】飞控设计
【一些入门知识】 1.飞行原理 【垂直运动】 当 mg>F1F2F3F4,此时做下降加速飞行 当 mg<F1F2F3F4,此时做升高加速飞行 当 mgF1F2F3F4 ,此时垂直上保持匀速飞行。 【偏航飞行】 ω 4 ω 2 ≠ ω 1 ω 3 就会产生水…...
MySQL CDC
一、MySQL CDC概念 MySQL CDC(Change Data Capture),即MySQL变更数据捕获,是一种能够捕获MySQL数据库中数据变化(包括插入、更新和删除操作)的技术。这些变化可以实时或准实时地同步到其他系统或服务中&am…...
手把手教你安装 Vivado2022.2(附安装包)
一、Vivado 2022.2 优势 Vivado 2022.2版本与之前的版本相比,具有以下几个显著的优势: 电源设计管理器(PDM):Vivado 2022.2引入了全新的电源设计管理器(PDM),这是一个下一代功耗评…...
旅行者1号有什么秘密?飞行240多亿公里,为什么没发生碰撞?
旅行者1号有什么秘密?飞行240多亿公里,为什么没发生碰撞? 自古以来,人类就对浩瀚无垠的宇宙充满了好奇与向往。从最初的仰望星空,到如今的深空探测,人类探测宇宙的历史发展可谓是一部波澜壮阔的史诗。 在…...
如何保护云主机安全
在数字化时代,云服务器已成为企业数据存储、处理和传输的重要工具。然而,随着其应用的广泛和深入,云服务器也面临着越来越多的安全威胁。为了应对这些威胁,白名单技术应运而生,成为保护云服务器安全的重要手段。 首先&…...
postman教程-19-mock测试
上一小节我们学习了Postman接口参数化方法,本小节我们讲解一下Postman mock测试的方法。 一、什么叫mock测试 mock测试就是在测试过程中,对某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便于测试的一种测试方法,…...
纳秒级网络库【二】技术选型
在十年之前,已经有网络产品实现7纳秒延迟,所以无需质疑是否能够实现,关键问题是:代价是什么。国内不少量化公司在招聘低延迟总线的开发人员,虽然我不知道他们具体的技术选型,从技术底层来看,并没…...
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
远程过程调用(RPC)协议详解 什么是RPC协议RPC的基本原理RPC的关键组件RPC的优缺点Protobuf函数绑定CallEncodeRecvDecodeSocket.Send和Recv项目地址 什么是RPC协议 远程过程调用(Remote Procedure Call,简称RPC)是一种…...
顶顶通呼叫中心中间件(mod_cti基于FreeSWITCH)-通话时长限制
文章目录 前言联系我们场景运用机器人场景普通通话场景 前言 顶顶通呼叫中心中间件限制通话时长有两种写法,分别作用于机器人场景与普通通话场景。 普通场景可分为分机互打、分机外呼手机等。 联系我们 有意向了解呼叫中心中间件的用户,可以点击该链接…...
如何将ai集成到项目中,方法二
上一篇文章:如何将ai集成到radsystems项目中,在项目中引入ai-CSDN博客 上一篇文章内容主要针对于未实现权限分离的项目,这篇文章主要来说一下权限分离的项目怎么做,以及注意的细节。 一、编写前端router.js 二、编写前端askai.vu…...
python的变量的引用与赋值的学习
看代码: a 1 # 初始化变量a,赋值为1 b a # 变量b被赋值为变量a的值,此时b的值也为1 b 2 # 变量b被重新赋值为2 print(a) # 打印变量a的值 执行过程如下: a 1:变量a被赋值为1。b a:变量b被赋值为…...
【FPGA项目】bin文件ram存取回环测试
🎉欢迎来到FPGA专栏~bin文件ram存取回环测试 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒🍹 ✨博客主页:小夏与酒的博客 🎈该系列文章专栏:FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大…...
北航数据结构与程序设计第五次作业选填题复习
选填题考的很多都是基础概念,对于巩固复习一些仡佬拐角的知识点是很有用的。非北航学生也可以来看看这些题,这一节主要是树方面的习题: 一、 我们首先需要知道一个公式 这是证明: 知道了这个公式,我们把题目中的数据…...
【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第40课-实时订阅后端数据
【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第40课-实时订阅后端数据 使用dtns.network德塔世界(开源的智体世界引擎),策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界引…...
系统集成知识科普:核心原理与关键技术
目录 1.系统集成的核心原理 1.1 模块化原理 1.1.1 定义: 1.1.2 优势: 1.1.3 实现方式: 1.2 标准化原理 1.2.1 定义: 1.2.2 作用: 1.2.3 实践案例: 1.2.4 制定与遵循: 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框架中的一个手势识别器类,用于检测用户在视图上的轻击手势。它是UIGestureRecognizer的一个子类&#x…...
一手洞悉巴西slot游戏包投放本土网盟CPI广告优势
一手洞悉巴西slot游戏包投放本土网盟CPI广告优势 在巴西这片热土上,slot游戏包的投放本土网盟CPI广告是一项既充满挑战又富有机遇的任务。CPI(Cost Per Install)广告模式,即按安装付费,已经成为许多游戏开发商推广产品…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
