草庐IT

【动量轮自平衡自行车】STM32_PID(开源-含硬件资料)

_旺仔小菠萝 2023-04-20 原文

动量轮自平衡自行车STM32

如何DIY一辆自平衡自行车?下面将制作内容分享给大家,欢迎讨论交流~。

目    录

一、硬件篇(附淘宝链接,店铺不定,也可自行搜索购买)

1. STM32F103C8T6最小系统(小蓝板)

2. MPU6050姿态传感器(3.3V供电)

3. 0.96寸OLED显示屏(四针、IIC通信、3.3V供电)

4. HC-05蓝牙模块

5. 超声波测距模块

6. N20电机及驱动(电机选型:DC 12V A12型)

7. 无刷电机动量轮模组

8. 舵机

9. 3S航模电池(注意电池尺寸)

10. 稳压模块及开关

11. 轮子及轴承

12. 车架及转向结构(3D打印)

13. 电路PCB

二、软件篇

1. main.c

2. PID控制算法

3. TIM2中断

4. 电池电压检测

5. OLED显示

6. 代码阅读注意点

三、链接


一、硬件篇(附淘宝链接,店铺不定,也可自行搜索购买)

1. STM32F103C8T6最小系统(小蓝板)

2. MPU6050姿态传感器(3.3V供电)

3. 0.96寸OLED显示屏(四针、IIC通信、3.3V供电)

4. HC-05蓝牙模块

(串口通信、用于接收小车运动指令)

使用教程链接:https://blog.csdn.net/weixin_44325419/article/details/110727911

5. 超声波测距模块

6. N20电机及驱动(电机选型:DC 12V A12型)

7. 无刷电机动量轮模组

该电机自带驱动和光电编码器。

 该自平衡自行车中我们使用万宝至无刷伺服电机,内置驱动,支持正反转,PWM调速,并且带有100线编码器AB相双通道信号输出。

该电机接线图如上图所示,实际小车中的线的颜色可能与上图有所不符,大家要按照位置来判断而不是线的颜色。

1.)信号A相和信号B相为编码器脉冲输出端;

2.)正反转切换的线我们直接用单片机的引脚3.3V电平控制,是完全没有问题的;

3.)编码器供电接3.3V;

4.)PWM接单片机的PWM输出,启动运行我们接单片机IO口,在电机初始化时置为高电平;

5.)电源负极接GND,电源正极接12V。

8. 舵机

视频中所使用,有点小贵,可以买便宜的。

9. 3S航模电池(注意电池尺寸)

10. 稳压模块及开关

将航模电池电压降至5V给单片机、舵机、蓝牙、超声波、电机编码器供电。

11. 轮子及轴承

由于小车后轮是通过皮带传动,为减小摩擦,使后轮转动更加顺滑,需在后轮安装微型轴承。(轴承根据车轴尺寸购买)

    尺寸如下:

12. 车架及转向结构(3D打印)

点击文章结尾处B站链接三连加关注并留言(或邮箱)即可获取车架及转向结构3D打印模型文件

13. 电路PCB

将上述功能模块集成在一块PCB电路板上(6.5x7.8cm),为方便焊接,电容电阻及三极管均为直插式元件。作者水平有限,PCB供大家参考,其中不足的地方可自行调整更改。

点击文章结尾处B站链接三连加关注并留言(或邮箱)即可获取PCB工程文件 

二、软件篇

点击文章结尾处B站链接三连加关注并留言(或邮箱)即可获取Keil源码文件

1. main.c

#include "sys.h"

float AdcValue;                                    //电池电压数字量
float Pitch,Roll,Yaw;						      //角度
short aacx,aacy,aacz;		                        //加速度传感器原始数据
short gyrox,gyroy,gyroz;	                        //陀螺仪原始数据
int PWM1;
int PWM_MAX=6500,PWM_MIN=-6500;	//PWM限幅变量
int Encoder_Motor;	//编码器数据(速度)

int main(void)
{  
	NVIC_Config();
   	delay_init();
    Led_Init();
    Beep_Init();
    Wave_SRD_Init();
   	uart3_init(9600);
    OLED_Init();			//初始化OLED  
    OLED_Clear();
	adc_Init();
    MOTOR_1_Init();
    MOTOR_2_Init();
    PWM_Init_TIM3(7199,0);//定时器3初始化PWM 10KHZ,用于驱动动量轮电机 
    PWM_Init_TIM2(9999, 143);//定时器2初始化PWM 50HZ,用于驱动舵机
    TIM_SetCompare1(TIM2, 790);//舵机复位
    Init_TIM1(9998,7199);
    Encoder_Init_TIM4(65535,0);
    OLED_ShowString(25,4,"MPU6050...",16);
    MPU_Init();            //MPU6050初始化  
    while(mpu_dmp_init())
 	{
		OLED_ShowString(25,4,"MPU6050 Error",16);
	}  
    OLED_ShowString(25,4,"MPU6050 OK!",16); 
    Beep=1;
    delay_ms(400);
    Beep=0;
    MPU6050_EXTI_Init();
    OLED_Clear();
 	OLED_ShowString(0,0,"Roll :         C",16);
    OLED_ShowString(0,3,"Speed:         R ",16);
    OLED_ShowString(0,6,"Power:        V ",16);    
    

    while(1)
    {	        
        Wave_SRD_Strat();        
        AdcValue=11.09*(3.3*Get_adc_Average(ADC_Channel_4,10)/0x0fff); //ADC值范围为从0-2^12=4095(111111111111)一般情况下对应电压为0-3.3V
        OLED_Showdecimal(55,0,Roll,9,16);  
        OLED_Showdecimal(55,3,Encoder_Motor*0.25,9,16);         
        OLED_Showdecimal(50,6,AdcValue,9,16);       
	}
}

2. PID控制算法

点击文章结尾处B站链接三连加关注并留言(或邮箱)即可获取PID相关教程资料

该小车更够实现直立平衡需要用到两个闭环控制,即直立环(PD控制、负反馈),速度环(PI控制、正反馈),代码原理及调试过程与两轮平衡小车调试过程基本一致。

关于PID控制算法的学习,内容较多,不好详细展开,网上资源丰富,大家可自行学习。这里推荐一篇知乎文章:https://zhuanlan.zhihu.com/p/39573490

3. TIM2中断

为避免小车在运行调试过程中受到超声波避障功能的干扰,可先将超声波避障功能关闭,超声波避障功能在定时器2中断服务函数中实现,所以将TIM2中断使能关闭即可。

//TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //使能TIM2中断,中断模式为更新中断:TIM_IT_Update
void TIM2_IRQHandler()
{   
    static int count=0;
    if(TIM_GetITStatus(TIM2, TIM_IT_Update)==1) //当发生中断时状态寄存器(TIMx_SR)的bit0会被硬件置1
	{
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //状态寄存器(TIMx_SR)的bit0置0
        count++;      
        if(Distance<8)              //与障碍物距离小于8cm时,蜂鸣器发出警报病后退
        {
            Beep=1,Led1=0,Led2=0;
            Backward();
            TIM_SetCompare1(TIM2, 790);//舵机复位
        }
        else Beep=0;
        if(count==25)        //TIM2溢出时间为20ms,20x25=500ms,即后退500ms后停止
        {
            Stopped();count=0;           
        }            
	}
}

4. 电池电压检测

一般航模电池的电量是和电压相关的, 过放必然导致电池永久过放,电池损坏,所以我们有必要通过监控电池电压的变化, 近似表示电池的电量, 在电池电量比较低的情况下, 提醒我们充电,充电时间不超过2个半小时,以免电池过充。长期储存时应确保单节电压在3.8V左右,并且每月充电一次。

3S 满电的时候是 12.6V, 过放时电压低于 9.6V。
2S 满电的时候是 8.4 V , 过放时电压低于 7.4V。

利用STM32内置ADC测量电池电压,ADC值范围为从0-2^12=4095(111111111111)一般情况下对应电压为0-3.3V,而3S航模电池电压为12V,直接测量将烧毁单片机,因此需要将电池分压,原理图如下:

简单分析可知, 电池电压经过电阻分压, 衰竭为原来的 1/11 之后, 送单片机 ADC检测,再将采集到的电压值乘以11即可得到电池的实际电压。(这里是乘以11.09,可根据实际情况进行微调)

#include "adc.h"
#include "delay.h"

//ADC初始化函数
void adc_Init()
{
  GPIO_InitTypeDef GPIO_InitStructure; //定义一个引脚初始化的结构体  
  ADC_InitTypeDef ADC_InitStructure; //定义一个ADC初始化的结构体 
  
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能CPIOB时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能TIM4时钟
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4; //引脚0
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; //引脚输入输出模式为模拟输入模式
	GPIO_Init(GPIOA, &GPIO_InitStructure); //根据上面设置好的GPIO_InitStructure参数,初始化引脚GPIOA_PIN0

	RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
	ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
	
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式:ADC1和ADC2工作在独立模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//是否为扫描(一组)模式:否:单通道模式
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;	//是否为连续转换模式,否:单次转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//转换由软件而不是外部触发启动
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//ADC数据对齐模式:右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1;	//顺序进行规则转换的ADC通道的数目
	ADC_Init(ADC1, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器  
	
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);	//使能复位校准   
	while(ADC_GetResetCalibrationStatus(ADC1));	//等待复位校准结束
	
	ADC_StartCalibration(ADC1);	 //开启AD校准
	while(ADC_GetCalibrationStatus(ADC1));	 //等待校准结束
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能
}

//采集ADC值函数,输入参数为ADC通道
u16 Get_adc(u8 chn)
{
	ADC_RegularChannelConfig(ADC1, chn, 1, ADC_SampleTime_239Cycles5 );	//ADC1,chn:ADC通道,第3个参数设置该通道的转换顺序(多通道模式下)
	                                                                  //采样时间为239.5周期=239.5/ADCCLOK,ADCCLOK=72/6MHZ(6代表ADC初始化时的分频系数)		    
  
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能	
	 
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
	return ADC_GetConversionValue(ADC1);	//返回最近一次ADC1规则组的转换结果
}

//采集多次ADC值求平均值函数,输入参数为ADC通道和采集次数
u16 Get_adc_Average(u8 chn, u8 times)
{
  u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
		temp_val+=Get_adc(chn);
		delay_ms(5);
	}
	return temp_val/times;
}
AdcValue=11.09*(3.3*Get_adc_Average(ADC_Channel_4,10)/0x0fff); //ADC值范围为从0-2^12=4095(111111111111)一般情况下对应电压为0-3.3V

5. OLED显示

一般淘宝购买的OLED显示模块资料中,其显示函数中没有显示小数及显示正负的函数。因此在原有的显示函数中添加了如下函数,从而能够方便的实时显示小车的角度、动量轮转速、电池电压信息。

//显示9位字符,最高位正负,三位整数,第五位小数点,后四位小数部分
//x,y :起点坐标	 
//len :数字的位数
//size:字体大小	 		  
void OLED_Showdecimal(u8 x,u8 y,float num,u8 len,u8 size2)
{         	
	u8 t,temp,len1,temp1;
	float temp2;
	u8 enshow=0;
    if(num < 0)
	{
        OLED_ShowChar(x,y,'0'- 3,size2);
		num =fabs(num);
	}
    else
	OLED_ShowChar(x,y,' ',size2);//第一位显示符号
	temp1 = (int)temp;
	temp2 = num - temp1;
	len1 = len - 6;//len1为整数部分位数,若显示数位需要扩展,修改该行
	OLED_ShowChar(x + size2/2*4,y,'0'- 2,size2);//浮点数的第5位显示小数点
	x = x + size2/2;
	for(t=0;t<len1;t++)//整数部分的显示
	{
		temp=(int)((num/oled_pow(10,len1-t-1)))%10;
		if(enshow==0&&t<(len1-1))
		{
			if(temp==0)
			{
				OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
				continue;
			}else enshow=1; 
		 	 
		}
	 	OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2); 
	}
	OLED_ShowChar(x+(size2/2)*4,y,((int)(temp2*10)%10) + '0',size2); //小数第一位
	OLED_ShowChar(x+(size2/2)*5,y,((int)(temp2*100)%10) + '0',size2); //小数第2位
//	OLED_ShowChar(x+(size2/2)*6,y,((int)(temp2*1000)%10) + '0',size2); //小数第3位
//	OLED_ShowChar(x+(size2/2)*7,y,((int)(temp2*10000)%10) + '0',size2); //小数第4位
} 

6. 代码阅读注意点

1.)所有头文件都包含在sys.h中,每个.h文件都包含sys.h,方便函数调用。

#ifndef __SYS_H
#define __SYS_H	
#include "stm32f10x.h"
#include "adc.h"
#include "oled.h"
#include "led.h" 
#include "beep.h"
#include "wave.h"
#include "control.h" 
#include "exti.h" 
#include "mpu6050.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h" 
#include "motor.h"
#include "pwm.h"
#include "encoder.h"
#include "usart.h"   				
#include "delay.h"

#include <math.h>
#include <stdlib.h>

2.)中断优先级分组配置在sys.c文件中

#include "sys.h"

/*
  ============================================================================================================================
    NVIC_PriorityGroup   | NVIC_IRQChannelPreemptionPriority | NVIC_IRQChannelSubPriority  | Description
  ============================================================================================================================
   NVIC_PriorityGroup_0  |                0                  |            0-15             |   0 bits for pre-emption priority
                         |                                   |                             |   4 bits for subpriority
  ----------------------------------------------------------------------------------------------------------------------------
   NVIC_PriorityGroup_1  |                0-1                |            0-7              |   1 bits for pre-emption priority
                         |                                   |                             |   3 bits for subpriority
  ----------------------------------------------------------------------------------------------------------------------------    
   NVIC_PriorityGroup_2  |                0-3                |            0-3              |   2 bits for pre-emption priority
                         |                                   |                             |   2 bits for subpriority
  ----------------------------------------------------------------------------------------------------------------------------    
   NVIC_PriorityGroup_3  |                0-7                |            0-1              |   3 bits for pre-emption priority
                         |                                   |                             |   1 bits for subpriority
  ----------------------------------------------------------------------------------------------------------------------------    
   NVIC_PriorityGroup_4  |                0-15               |            0                |   4 bits for pre-emption priority
                         |                                   |                             |   0 bits for subpriority                       
  ============================================================================================================================
*/
void NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStruct_extiB5;
    NVIC_InitTypeDef NVIC_InitStruct_extiA10;
	NVIC_InitTypeDef NVIC_InitStruct_usart3;
    NVIC_InitTypeDef NVIC_InitStruct_tim2;
    NVIC_InitTypeDef NVIC_InitStruct_tim1;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//4级抢占,4级响应。
	
	//外部中断PB5
	NVIC_InitStruct_extiB5.NVIC_IRQChannel=EXTI9_5_IRQn;
	NVIC_InitStruct_extiB5.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct_extiB5.NVIC_IRQChannelPreemptionPriority=0;
	NVIC_InitStruct_extiB5.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStruct_extiB5);
	
    //USART3 NVIC 配置
    NVIC_InitStruct_usart3.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStruct_usart3.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3
	NVIC_InitStruct_usart3.NVIC_IRQChannelSubPriority = 0;		//子优先级3
	NVIC_InitStruct_usart3.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStruct_usart3);	//根据指定的参数初始化VIC寄存器
    
    // 定时器2中断
    NVIC_InitStruct_tim2.NVIC_IRQChannel=TIM2_IRQn; //属于TIM2中断
	NVIC_InitStruct_tim2.NVIC_IRQChannelCmd=ENABLE; //中断使能
	NVIC_InitStruct_tim2.NVIC_IRQChannelPreemptionPriority=1; //抢占优先级为1级,值越小优先级越高,0级优先级最高
	NVIC_InitStruct_tim2.NVIC_IRQChannelSubPriority=1; //响应优先级为1级,值越小优先级越高,0级优先级最高
	NVIC_Init(&NVIC_InitStruct_tim2); //根据NVIC_InitStruct_tim1的参数初始化VIC寄存器,设置TIM2中断
    
    //外部中断PA10
	NVIC_InitStruct_extiA10.NVIC_IRQChannel=EXTI15_10_IRQn;
	NVIC_InitStruct_extiA10.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct_extiA10.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStruct_extiA10.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStruct_extiA10);
    
    // 定时器1中断
    NVIC_InitStruct_tim1.NVIC_IRQChannel=TIM1_UP_IRQn; //属于TIM1中断
	NVIC_InitStruct_tim1.NVIC_IRQChannelCmd=ENABLE; //中断使能
	NVIC_InitStruct_tim1.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级为1级,值越小优先级越高,0级优先级最高
	NVIC_InitStruct_tim1.NVIC_IRQChannelSubPriority=2; //响应优先级为1级,值越小优先级越高,0级优先级最高
	NVIC_Init(&NVIC_InitStruct_tim1); //根据NVIC_InitStruct_tim1的参数初始化VIC寄存器,设置TIM2中断
}

3.)STM32F10x系列的MCU复位后,PA13/14/15 & PB3/4默认配置为JTAG功能。有时我们为了充分利用MCU I/O口的资源,会把这些端口设置为普通I/O口。

使用JLINK向STM32烧录程序时,需要使用6个芯片的引脚(以STM32F103C8T6为例),分别是PB4 / JNTRST,PB3 / JTDO,PA13 / JTMS,PA14 / JTCK,PA15 / JTDI,NRST。当芯片IO口资源比较紧张时,可选择SW模式烧录程序。SWD只需用到PA13 / JTMS,PA14 / JTCK两根线,NREST可以接可不接,剩下的PB4 / JNTRST,PB3 / JTDO和PA15 / JTDI就可以当然普通IO使用,但是这三个口当然普通IO使用时需要先进行如下配置。(这里MPU6050模块用到PB3和PB4引脚)

mpuiic.c

//初始化IIC
void MPU_IIC_Init(void)
{					     
  GPIO_InitTypeDef  GPIO_InitStructure;
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB,ENABLE); //打开PB口时钟和AFIO复用时钟
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //重映射
		
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4;	 // 端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
  GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIO 
	
  GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4);						 //PB3,PB4 输出高	
 
}

三、链接

bilibili_[动量轮自平衡自行车]STM32_PID(开源-含硬件资料)https://www.bilibili.com/video/BV1M3411J77m?share_source=copy_web

有关【动量轮自平衡自行车】STM32_PID(开源-含硬件资料)的更多相关文章

  1. ruby - 匹配未转义的平衡定界符对 - 2

    如何匹配未被反斜杠转义的平衡定界符对(其本身未被反斜杠转义)(无需考虑嵌套)?例如对于反引号,我试过了,但是转义的反引号没有像转义那样工作。regex=/(?!$1:"how\\"#expected"how\\`are"上面的正则表达式不考虑由反斜杠转义并位于反引号前面的反斜杠,但我愿意考虑。StackOverflow如何做到这一点?这样做的目的并不复杂。我有文档文本,其中包括内联代码的反引号,就像StackOverflow一样,我想在HTML文件中显示它,内联代码用一些spanMaterial装饰。不会有嵌套,但转义反引号或转义反斜杠可能出现在任何地方。

  2. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  3. STM32的HAL和LL库区别和性能对比 - 2

    LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L

  4. python - 开源 Twitter 克隆(在 Ruby/Python 中) - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭6年前。Improvethisquestion是否有任何用Ruby或Python编写的生产就绪的开源Twitter克隆?我对功能丰富的实现更感兴趣,而不仅仅是简单的Twitter消息(例如:API、FBconnect、通知等)谢谢!

  5. Gradle 自动化构建开源工具 - 2

    文章目录写在前面1、下载与安装(windows)1.1、idea中配置gradle2、基础知识(Gradle6.9为例)2.1、Gradle脚本语法2.1.1、dependsOn2.1.2、创建动态任务2.1.3、增加任务行为2.1.4、参数2.1.5、Ant任务2.1.6、方法2.1.7、默认任务2.1.6、依赖任务的不同输出3、java项目中使用3.1、在已有项目中构建gradle3.2、在新建项目时构建gradle(idea)3.3、gradle项目目录结构3.4、build.gradle3.4.1、plugins3.4.2、repositories3.4.3、dependencies3

  6. ESP32学习入门:WiFi连接网络 - 2

    目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方

  7. Spring Security 6.0系列【32】授权服务器篇之默认过滤器 - 2

    有道无术,术尚可求,有术无道,止于术。本系列SpringBoot版本3.0.4本系列SpringSecurity版本6.0.2本系列SpringAuthorizationServer版本1.0.2源码地址:https://gitee.com/pearl-organization/study-spring-security-demo文章目录前言1.OAuth2AuthorizationServerMetadataEndpointFilter2.OAuth2AuthorizationEndpointFilter3.OidcProviderConfigurationEndpointFilter4.N

  8. ruby - 摘要::CRC32 与 Zlib - 2

    在我的代码中,我需要使用各种算法(包括CRC32)对文件进行哈希处理。因为我还在Digest系列中使用其他加密哈希函数,所以我认为为它们维护一个一致的接口(interface)会很好。为了记录,我确实找到了digest-crc,一颗完全符合我要求的gem。问题是,Zlib是标准库的一部分,并且有一个我想重用的CRC32工作实现。此外,它是用C编写的,因此它应该提供与digest-crc相关的卓越性能,后者是纯ruby​​实现。实现Digest::CRC32一开始看起来非常简单:%w(digestzlib).each{|f|requiref}classDigest::CRC32一切正常:

  9. ruby - Sidekiq 不创建 PID 文件 - 2

    为了停止Sidekiq,我需要使用:$bundleexecsidekiqctlstop/Users/me/Documents/sites/some_site/tmp/pid/sidekiq.pid20我告诉Sidekiq在config.yml文件中创建一个pid文件:#/Users/me/Documents/sites/some_site/config.yml:pidfile:/Users/me/Documents/sites/some_site/tmp/pids/sidekiq.pid:concurrency:25并告诉Sidekiq这个配置文件在哪里使用:$bundleexecsi

  10. ruby - 安装gem : Couldn't reserve space for cygwin's heap, Win32错误487错误 - 2

    我正在尝试在我的机器上安装win32-apigem,但在构建native扩展时我遇到了一些问题:$geminstallwin32-api--no-ri--rdocTemporarilyenhancingPATHtoincludeDevKit...Buildingnativeextensions.Thiscouldtakeawhile...C:\Programs\dev_kit\bin\make.exe:***Couldn'treservespaceforcygwin'sheap,Win32error0ERROR:Errorinstallingwin32-api:ERROR:Failed

随机推荐