当前位置:   article > 正文

STM32F103RCT6双轮PID闭环小车(L298N)_l298n电机驱动使用

l298n电机驱动使用

一、电机驱动L298N

        L298N是一个常用的双H桥电机驱动器模块,用于控制直流电机或步进电机的方向和速度。它适用于许多电机控制应用,如机器人、小车、舵机等。

       l298n的使用方法有好几种,我所使用的是最简单的一种,使用方法如下:

        输出A: 通道A输出 ,连接1电机的正负
        输出B: 通道B输出 ,连接2电机正反
        12V供电: 主电源正极输入
        供电GND: 主电源正负极极输入
        5V输出: 5v电压输出端,可用于给MCU单片机供电
        ENA: 通道A使能 (插上跳线帽)
        ENB: 通道B使能 (插上跳线帽)
        IN1~IN4: 逻辑输入IN1 ~ IN2控制通道A,逻辑输入IN3~IN4控制通道B(分别接入4路PWM)
        板载5V跳线帽: 接上后板载5V输出有效

详细的L298N的使用方法

二、MPU6050陀螺仪

      MPU6050是一款常用的六轴陀螺仪和加速度计传感器模块,广泛用于嵌入式系统、机器人、飞行器、运动控制等应用。它集成了三轴陀螺仪和三轴加速度计,能够提供精确的姿态和运动数据,通常称为六轴运动陀螺仪。

        陀螺仪的三个角度:

                Pitch:俯仰角(抬头低头)
                Roll:滚转角(翻身)
                Yaw:偏航角(转弯)

        MPU6050是使用IIC通信协议与单片机进行通信,以此来获取陀螺仪的角度和角加速度数据。

VCC:电源正
GND:地
SCL: I2C串行时 钟线/SPI串行时钟端口
SDA: I2C串行 数据线/SPI串行数据输入
XDA:连接其他I2C设备的主机数据口(不需要接单片机)
XCL:给I2C设备提供主时钟(不需要接单片机)
ADO:I2C器件地址选择位,地址管脚(不需要接单片机)
INT:中断引脚(接单片机的引脚组成外部中断或者不接使用其他中断)

  1. // MPU6050 IIC PB8 PB9
  2. //初始化
  3. void IIC_Init(void)
  4. {
  5. GPIO_InitTypeDef GPIO_InitStructure;
  6. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟
  7. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; //端口配置
  8. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
  9. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M
  10. GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB
  11. }
  12. //获取mpu6050角度值
  13. void Get_Angle(void)
  14. {
  15. Read_DMP(); //===读取加速度、角速度、倾角
  16. Angle_Balance=Pitch; //===更新平衡倾角
  17. Angle_Turn=Yaw;
  18. Gyro_Balance=gyro[1]; //===更新平衡角速度
  19. Gyro_Turn=gyro[2]; //更新转向角速度
  20. Acceleration_Z=accel[2]; //===更新Z轴加速度计
  21. Gyro_Z=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_L); //读取Z轴陀螺仪
  22. }

三、霍尔编码电机

        霍尔编码电机是一种具有霍尔传感器的电机,通常用于测量电机的转速和位置。霍尔传感器是一种用于检测磁场的传感器,可以用来测量电机转子的位置和速度。这种编码方式常用于电机控制和位置反馈系统中。

  1. 原理:霍尔编码电机通常集成了霍尔传感器,这些传感器可以检测电机的转子上的永磁磁极。通过检测磁场的变化,霍尔传感器可以确定电机转子的位置和速度。

  2. 位置反馈:霍尔编码电机提供了位置反馈,可以告诉你电机的当前位置。这对于需要精确控制电机的应用非常重要,如机器人、CNC机床和自动化系统。

  3. 速度反馈:除了位置反馈,霍尔编码电机还可以提供速度反馈。通过测量位置变化的速度,你可以获得电机的实时速度信息。

  4. 闭环控制:霍尔编码电机通常与闭环控制系统一起使用。闭环控制可以根据实际的位置和速度反馈调整电机的控制信号,以实现精确的位置和速度控制。

  5. 编码方式:霍尔编码电机通常使用不同的霍尔编码方式,如单通道霍尔编码、双通道霍尔编码和四通道霍尔编码。这些编码方式提供不同的精度和分辨率。

  6. 应用:霍尔编码电机广泛用于需要精确控制的应用,包括工业自动化、机器人、医疗设备、自动门、摄像机云台等

引脚说明:

1、M1电机动力线1 ( 12V)(接l298n的输出端)
2、GND编码器电源-
3、C1编码器A相(接单片机定时器捕获引脚)
4、C2编码器B相(接单片机定时器捕获引脚)
5、3V3编码器电源+ ( 5V)
6、M2电机动力线2 ( 12V )(接l298n的输出端)

 ①定时器捕获编码器脉冲:

  1. #include "encoder.h"
  2. #include "stm32f10x_gpio.h"
  3. //TIM3 CH1 PA6
  4. //TIM3 CH2 PA7
  5. void Encoder_Init_TIM3(void)
  6. {
  7. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  8. TIM_ICInitTypeDef TIM_ICInitStructure;
  9. GPIO_InitTypeDef GPIO_InitStructure;
  10. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能定时器4的时钟
  11. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PB端口时钟
  12. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //端口配置
  13. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  14. GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOB
  15. TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  16. TIM_TimeBaseStructure.TIM_Prescaler = 0x00; // 预分频器
  17. TIM_TimeBaseStructure.TIM_Period = 65535; //设定计数器自动重装值
  18. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
  19. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数
  20. TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
  21. TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
  22. TIM_ICStructInit(&TIM_ICInitStructure);
  23. TIM_ICInitStructure.TIM_ICFilter = 10;
  24. TIM_ICInit(TIM3, &TIM_ICInitStructure);
  25. TIM_ClearFlag(TIM3, TIM_FLAG_Update);//清除TIM的更新标志位
  26. TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
  27. //Reset counter
  28. TIM_SetCounter(TIM3,0);
  29. TIM_Cmd(TIM3, ENABLE);
  30. }
  31. //TIM4 CH1 PB6
  32. //TIM4 CH2 PB7
  33. void Encoder_Init_TIM4(void)
  34. {
  35. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  36. TIM_ICInitTypeDef TIM_ICInitStructure;
  37. GPIO_InitTypeDef GPIO_InitStructure;
  38. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//使能定时器4的时钟
  39. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能PB端口时钟
  40. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //端口配置
  41. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  42. GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB
  43. TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  44. TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器
  45. TIM_TimeBaseStructure.TIM_Period = 65535; //设定计数器自动重装值
  46. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
  47. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数
  48. TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
  49. TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
  50. TIM_ICStructInit(&TIM_ICInitStructure);
  51. TIM_ICInitStructure.TIM_ICFilter = 10;
  52. TIM_ICInit(TIM4, &TIM_ICInitStructure);
  53. TIM_ClearFlag(TIM4, TIM_FLAG_Update);//清除TIM的更新标志位
  54. TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
  55. //Reset counter
  56. TIM_SetCounter(TIM4,0);
  57. TIM_Cmd(TIM4, ENABLE);
  58. }
  59. int Read_Encoder(u8 TIMX)
  60. {
  61. int Encoder_TIM;
  62. switch(TIMX)
  63. {
  64. case 3: Encoder_TIM= (short)TIM3 -> CNT; TIM3 -> CNT=0;break;
  65. case 4: Encoder_TIM= (short)TIM4 -> CNT; TIM4 -> CNT=0;break;
  66. default: Encoder_TIM=0;
  67. }
  68. return Encoder_TIM;
  69. }
  70. void TIM4_IRQHandler(void)
  71. {
  72. if(TIM4->SR&0X0001)//溢出中断
  73. {
  74. }
  75. TIM4->SR&=~(1<<0);//清除中断标志位
  76. }
  77. void TIM3_IRQHandler(void)
  78. {
  79. if(TIM3->SR&0X0001)//溢出中断
  80. {
  81. }
  82. TIM3->SR&=~(1<<0);//清除中断标志位
  83. }

②定时器PWM的产生(定时器TIM8是高级定时器,配置时需要注意)

  1. #include "motor.h"
  2. // TIM5 PA2 PA3
  3. // TIM8 PC6 PC7
  4. void TIM5_PWM_Init(u16 arr,u16 psc){
  5. GPIO_InitTypeDef GPIO_InitStructure;
  6. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  7. TIM_OCInitTypeDef TIM_OCInitStructure;
  8. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
  9. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
  10. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3; //TIM5_CH3 //TIM_CH4
  11. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  12. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13. GPIO_Init(GPIOA, &GPIO_InitStructure);
  14. TIM_TimeBaseStructure.TIM_Period=arr;
  15. TIM_TimeBaseStructure.TIM_Prescaler=psc;
  16. TIM_TimeBaseStructure.TIM_ClockDivision=0;
  17. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
  18. TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
  19. TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
  20. TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
  21. TIM_OCInitStructure.TIM_Pulse=0;
  22. TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
  23. TIM_OC3Init(TIM5, &TIM_OCInitStructure);
  24. TIM_OC4Init(TIM5, &TIM_OCInitStructure);
  25. TIM_CtrlPWMOutputs(TIM5,ENABLE); //MOE 主输出使能
  26. TIM_OC3PreloadConfig(TIM5, TIM_OCPreload_Enable); //CH3预装载使能
  27. TIM_OC4PreloadConfig(TIM5, TIM_OCPreload_Enable); //CH4预装载使能
  28. TIM_ARRPreloadConfig(TIM5, ENABLE); //使能TIM5在ARR上的预装载寄存器
  29. TIM_Cmd(TIM5, ENABLE); //使能TIM5
  30. }
  31. void TIM8_PWM_Init(u16 arr,u16 psc){
  32. GPIO_InitTypeDef GPIO_InitStructure;
  33. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  34. TIM_OCInitTypeDef TIM_OCInitstruct;
  35. RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM8 ,ENABLE);
  36. RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE); //时钟使能
  37. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
  38. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6 | GPIO_Pin_7;
  39. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  40. GPIO_Init(GPIOC,&GPIO_InitStructure);
  41. TIM_TimeBaseStructure.TIM_Period = arr;
  42. TIM_TimeBaseStructure.TIM_Prescaler =psc;
  43. TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;
  44. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  45. TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
  46. TIM_OCInitstruct.TIM_OCMode=TIM_OCMode_PWM1;
  47. TIM_OCInitstruct.TIM_OCNPolarity=TIM_OCNPolarity_High;
  48. TIM_OCInitstruct.TIM_OCPolarity=TIM_OCPolarity_High;
  49. TIM_OCInitstruct.TIM_OutputState=TIM_OutputState_Enable;
  50. TIM_OCInitstruct.TIM_OCIdleState = TIM_OCIdleState_Set;
  51. TIM_OCInitstruct.TIM_OCNIdleState=TIM_OCNIdleState_Reset;
  52. TIM_OC1Init(TIM8,&TIM_OCInitstruct);
  53. TIM_OC2Init(TIM8,&TIM_OCInitstruct);
  54. TIM_OC1PreloadConfig(TIM8,TIM_OCPreload_Enable);
  55. TIM_OC2PreloadConfig(TIM8,TIM_OCPreload_Enable);
  56. TIM_CtrlPWMOutputs(TIM8,ENABLE); //MOE 主输出使能
  57. TIM_ARRPreloadConfig(TIM8, ENABLE); //使能TIM3在ARR上的预装载寄存器
  58. TIM_Cmd(TIM8, ENABLE); //使能TIM3
  59. TIM_CtrlPWMOutputs(TIM8, ENABLE);// 主输出使能,当使用的是通用定时器时,这句不需要 s
  60. }

四、0.96寸OLED的使用(增加人机交互,可更好实时观察数据)

        0.96寸OLED(Organic Light Emitting Diode)显示屏是一种小尺寸的有机发光二极管显示屏,通常用于嵌入式系统、小型电子设备和Arduino项目中。它提供了高亮度、高对比度、低功耗以及较宽的视角,非常适合小型信息显示和用户界面设计。

        OLED通常有2种,第一种是IIC通讯,第二种是SPI通讯。IIC协议更加简单,使用起来方便,但是性能没有SPI强,但是在OLED上使用IIC是完全足够了。这里就不详细讲解IIC和SPI的区别了,有兴趣的同学可以去下面的网站看看大佬写的文章。

        平衡车使用OLED的主要目的是用来观察一下数据,比如:编码器的数据、陀螺仪角度数据、使用按键调PID参数时的参数数据等等。

IIC和SPI简介

  1. //初始化OLED
  2. void OLED_Init(void)
  3. {
  4. GPIO_InitTypeDef GPIO_InitStructure;
  5. RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE ); //使能GPIOC时钟
  6. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;
  7. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
  8. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  9. GPIO_Init(GPIOC, &GPIO_InitStructure);
  10. GPIO_SetBits(GPIOC,GPIO_Pin_12|GPIO_Pin_11);
  11. delay_ms(200);
  12. OLED_WR_Byte(0xAE,OLED_CMD);//--display off
  13. OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
  14. OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
  15. OLED_WR_Byte(0x40,OLED_CMD);//--set start line address
  16. OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
  17. OLED_WR_Byte(0x81,OLED_CMD); // contract control
  18. OLED_WR_Byte(0xFF,OLED_CMD);//--128
  19. OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap
  20. OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
  21. OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
  22. OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
  23. OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
  24. OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
  25. OLED_WR_Byte(0x00,OLED_CMD);//
  26. OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
  27. OLED_WR_Byte(0x80,OLED_CMD);//
  28. OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
  29. OLED_WR_Byte(0x05,OLED_CMD);//
  30. OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
  31. OLED_WR_Byte(0xF1,OLED_CMD);//
  32. OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
  33. OLED_WR_Byte(0x12,OLED_CMD);//
  34. OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
  35. OLED_WR_Byte(0x30,OLED_CMD);//
  36. OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
  37. OLED_WR_Byte(0x14,OLED_CMD);//
  38. OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
  39. }

五、HC06蓝牙模块

        HC-06是一种常见的蓝牙串口模块,通常被用于将串口设备(如Arduino或其他微控制器)与蓝牙无线通信连接起来。以下是一些关于HC-06蓝牙模块的重要信息:

  1. 功能:HC-06蓝牙模块是一个串口蓝牙模块,可通过UART串口与其他设备通信。它可以用作透明串口传输,将串口数据通过蓝牙连接传输到其他设备,也可以用于构建蓝牙串口通信的应用程序。

  2. 通信距离:通常,HC-06模块的通信距离在10米左右,但这取决于环境条件和障碍物。

  3. 配对:HC-06通常以主从设备的方式工作,其中一个设备(通常是手机或电脑)充当主机,而HC-06模块充当从设备。在首次使用时,通常需要将HC-06模块与主机设备进行蓝牙配对。

  4. 配置:HC-06模块通常有一个AT命令模式,您可以使用这些命令来配置模块的参数,如蓝牙名称、波特率等。要进入AT命令模式,通常需要将模块上的特定引脚连接到地,并重启模块。

  5. 电源:HC-06通常需要3.3V或5V电源供电,具体的电源要求可以查看模块的规格。

  6. 应用:HC-06模块广泛用于各种项目,例如蓝牙遥控器、传感器数据传输、蓝牙串口通信等。它是一个经济实惠的解决方案,用于在项目中添加蓝牙功能。

  7. 注意事项:使用HC-06模块时需要小心处理电源和引脚连接,以免损坏模块。还需要注意模块的默认配置,例如波特率和配对密码。

  1. #include "hc06.h"
  2. u8 res; //设置全局变量
  3. void HC06_Init(u16 arr)
  4. {
  5. GPIO_InitTypeDef GPIO_InitStrue;
  6. USART_InitTypeDef USART_InitStrue;
  7. NVIC_InitTypeDef NVIC_InitStrue;
  8. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //GPIO端口使能
  9. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口端口使能
  10. GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;
  11. GPIO_InitStrue.GPIO_Pin=GPIO_Pin_10;
  12. GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz;
  13. GPIO_Init(GPIOB,&GPIO_InitStrue);
  14. GPIO_InitStrue.GPIO_Mode=GPIO_Mode_IN_FLOATING;
  15. GPIO_InitStrue.GPIO_Pin=GPIO_Pin_11;
  16. GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz;
  17. GPIO_Init(GPIOB,&GPIO_InitStrue);
  18. USART_InitStrue.USART_BaudRate=arr;
  19. USART_InitStrue.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
  20. USART_InitStrue.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
  21. USART_InitStrue.USART_Parity=USART_Parity_No;
  22. USART_InitStrue.USART_StopBits=USART_StopBits_1;
  23. USART_InitStrue.USART_WordLength=USART_WordLength_8b;
  24. USART_Init(USART3,&USART_InitStrue);
  25. USART_Cmd(USART3,ENABLE); //ʹ�ܴ���2
  26. USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//���������ж�
  27. NVIC_InitStrue.NVIC_IRQChannel=USART3_IRQn;
  28. NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;
  29. NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=0;
  30. NVIC_InitStrue.NVIC_IRQChannelSubPriority=1;
  31. NVIC_Init(&NVIC_InitStrue);
  32. }
  33. void USART3_IRQHandler(void)
  34. {
  35. if(USART_GetITStatus(USART3,USART_IT_RXNE)!=RESET)
  36. {
  37. res= USART_ReceiveData(USART3);
  38. USART_SendData(USART3,res); //串口3发送数据给蓝牙模块接收,也就是手机app接收到的数据
  39. }
  40. }

六、PID算法

        PID(Proportional-Integral-Derivative)控制算法是一种用于控制系统的反馈控制算法。它通过比较实际输出与期望目标值之间的差异(误差),来调整控制器的输出,以使系统保持在期望的状态。PID控制算法由三个主要组成部分组成,分别是比例(Proportional)、积分(Integral)和微分(Derivative)。

以下是每个部分的解释以及PID控制的工作原理:

  1. 比例(Proportional)部分:比例部分的作用是根据当前误差的大小来调整控制输出。它与误差成正比,如果误差增大,比例部分的输出也增大,反之亦然。这个部分的作用是快速减小误差,但它单独使用时可能导致系统出现震荡。

  2. 积分(Integral)部分:积分部分的作用是积累误差并进行修正,以减小静态误差。它根据误差的积累来调整控制输出,通常用于减小比例控制导致的静态误差。积分部分的存在可以确保系统最终收敛到期望值,即使存在系统参数变化或外部干扰。

  3. 微分(Derivative)部分:微分部分的作用是预测误差的未来变化趋势,以减小控制输出的突变。它对误差的变化率进行调整,有助于防止系统在接近期望值时出现过冲或震荡。微分部分可以提高系统的稳定性。

PID控制算法的总输出是这三个部分的加权和,通常表示为:

Output=Kp​⋅P+Ki​⋅I+Kd​⋅D

        其中,P 是比例部分的输出,I 是积分部分的输出,D 是微分部分的输出,而 Kp​、Ki​ 和 Kd​ 则是控制器的参数,通过调整这些参数可以实现不同的控制效果。

        PID控制算法在自动化控制系统中广泛应用,如温度控制、电机控制、飞行控制等。通过适当调整参数,PID控制器可以实现系统快速响应、减小静态误差和维持系统稳定性。

PID控制详解

平衡车PID调参

  1. //直立环(比例p、微分d)
  2. int balance(float Angle,float Gyro){
  3. static float Bias;
  4. int balance;
  5. Bias=Angle-ZHONGZHI;
  6. balance=Bias*Kzp+Gyro*Kzd;
  7. return balance;
  8. }
  9. //速度环(比例p、积分i)
  10. int velocity(int Encoder_left,int Encoder_right){
  11. static float Velocity, Encoder_Least, Encoder;
  12. static float Encoder_Integral;
  13. Ksi=Ksp/200;
  14. Encoder_Least = (Encoder_Left+Encoder_Right)-0;
  15. Encoder=Encoder*0.7+Encoder_Least*0.3;
  16. Encoder_Integral=Encoder_Integral+Encoder;
  17. Encoder_Integral=Encoder_Integral-Target_Velocity; //改变Target_Velocity就是控制小车前进后退
  18. if(Encoder_Integral>15000) Encoder_Integral=15000;
  19. if(Encoder_Integral<-15000) Encoder_Integral=-15000;
  20. Velocity=Encoder*Ksp+Encoder_Integral*Ksi;
  21. return Velocity;
  22. }
  23. //转向环(比例p、微分d)
  24. int Turn(float yaw,float Gyro)
  25. {
  26. float Turn;
  27. float Bias;//目标角度
  28. Ktd=Ktp/100;
  29. Bias=yaw-0;
  30. Turn=Bias*Ktp+Gyro*Ktd;
  31. return Turn;
  32. }

平衡小车

平衡小车之家资料

链接: https://pan.baidu.com/s/1J6Rluf0T4mVtif2dqRtWxw?pwd=ghjm 提取码: ghjm 

本人自制平衡车代码

链接: https://pan.baidu.com/s/1J6Rluf0T4mVtif2dqRtWxw?pwd=ghjm 提取码: ghjm 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/694978
推荐阅读
相关标签
  

闽ICP备14008679号