一、电机驱动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输出有效
二、MPU6050陀螺仪
MPU6050是一款常用的六轴陀螺仪和加速度计传感器模块,广泛用于嵌入式系统、机器人、飞行器、运动控制等应用。它集成了三轴陀螺仪和三轴加速度计,能够提供精确的姿态和运动数据,通常称为六轴运动陀螺仪。
陀螺仪的三个角度:
Pitch:俯仰角(抬头低头)
Roll:滚转角(翻身)
Yaw:偏航角(转弯)
MPU6050是使用IIC通信协议与单片机进行通信,以此来获取陀螺仪的角度和角加速度数据。
VCC:电源正
GND:地
SCL: I2C串行时 钟线/SPI串行时钟端口
SDA: I2C串行 数据线/SPI串行数据输入
XDA:连接其他I2C设备的主机数据口(不需要接单片机)
XCL:给I2C设备提供主时钟(不需要接单片机)
ADO:I2C器件地址选择位,地址管脚(不需要接单片机)
INT:中断引脚(接单片机的引脚组成外部中断或者不接使用其他中断)
// MPU6050 IIC PB8 PB9
//初始化
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB
}
//获取mpu6050角度值
void Get_Angle(void)
{
Read_DMP(); //===读取加速度、角速度、倾角
Angle_Balance=Pitch; //===更新平衡倾角
Angle_Turn=Yaw;
Gyro_Balance=gyro[1]; //===更新平衡角速度
Gyro_Turn=gyro[2]; //更新转向角速度
Acceleration_Z=accel[2]; //===更新Z轴加速度计
Gyro_Z=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_L); //读取Z轴陀螺仪
}
三、霍尔编码电机
霍尔编码电机是一种具有霍尔传感器的电机,通常用于测量电机的转速和位置。霍尔传感器是一种用于检测磁场的传感器,可以用来测量电机转子的位置和速度。这种编码方式常用于电机控制和位置反馈系统中。
-
原理:霍尔编码电机通常集成了霍尔传感器,这些传感器可以检测电机的转子上的永磁磁极。通过检测磁场的变化,霍尔传感器可以确定电机转子的位置和速度。
-
位置反馈:霍尔编码电机提供了位置反馈,可以告诉你电机的当前位置。这对于需要精确控制电机的应用非常重要,如机器人、CNC机床和自动化系统。
-
速度反馈:除了位置反馈,霍尔编码电机还可以提供速度反馈。通过测量位置变化的速度,你可以获得电机的实时速度信息。
-
闭环控制:霍尔编码电机通常与闭环控制系统一起使用。闭环控制可以根据实际的位置和速度反馈调整电机的控制信号,以实现精确的位置和速度控制。
-
编码方式:霍尔编码电机通常使用不同的霍尔编码方式,如单通道霍尔编码、双通道霍尔编码和四通道霍尔编码。这些编码方式提供不同的精度和分辨率。
-
应用:霍尔编码电机广泛用于需要精确控制的应用,包括工业自动化、机器人、医疗设备、自动门、摄像机云台等
引脚说明:
1、M1电机动力线1 ( 12V)(接l298n的输出端)
2、GND编码器电源-
3、C1编码器A相(接单片机定时器捕获引脚)
4、C2编码器B相(接单片机定时器捕获引脚)
5、3V3编码器电源+ ( 5V)
6、M2电机动力线2 ( 12V )(接l298n的输出端)
①定时器捕获编码器脉冲:
#include "encoder.h"
#include "stm32f10x_gpio.h"
//TIM3 CH1 PA6
//TIM3 CH2 PA7
void Encoder_Init_TIM3(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能定时器4的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOB
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0x00; // 预分频器
TIM_TimeBaseStructure.TIM_Period = 65535; //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 10;
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_ClearFlag(TIM3, TIM_FLAG_Update);//清除TIM的更新标志位
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
//Reset counter
TIM_SetCounter(TIM3,0);
TIM_Cmd(TIM3, ENABLE);
}
//TIM4 CH1 PB6
//TIM4 CH2 PB7
void Encoder_Init_TIM4(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//使能定时器4的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器
TIM_TimeBaseStructure.TIM_Period = 65535; //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 10;
TIM_ICInit(TIM4, &TIM_ICInitStructure);
TIM_ClearFlag(TIM4, TIM_FLAG_Update);//清除TIM的更新标志位
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
//Reset counter
TIM_SetCounter(TIM4,0);
TIM_Cmd(TIM4, ENABLE);
}
int Read_Encoder(u8 TIMX)
{
int Encoder_TIM;
switch(TIMX)
{
case 3: Encoder_TIM= (short)TIM3 -> CNT; TIM3 -> CNT=0;break;
case 4: Encoder_TIM= (short)TIM4 -> CNT; TIM4 -> CNT=0;break;
default: Encoder_TIM=0;
}
return Encoder_TIM;
}
void TIM4_IRQHandler(void)
{
if(TIM4->SR&0X0001)//溢出中断
{
}
TIM4->SR&=~(1<<0);//清除中断标志位
}
void TIM3_IRQHandler(void)
{
if(TIM3->SR&0X0001)//溢出中断
{
}
TIM3->SR&=~(1<<0);//清除中断标志位
}
②定时器PWM的产生(定时器TIM8是高级定时器,配置时需要注意)
#include "motor.h"
// TIM5 PA2 PA3
// TIM8 PC6 PC7
void TIM5_PWM_Init(u16 arr,u16 psc){
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3; //TIM5_CH3 //TIM_CH4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period=arr;
TIM_TimeBaseStructure.TIM_Prescaler=psc;
TIM_TimeBaseStructure.TIM_ClockDivision=0;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse=0;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OC3Init(TIM5, &TIM_OCInitStructure);
TIM_OC4Init(TIM5, &TIM_OCInitStructure);
TIM_CtrlPWMOutputs(TIM5,ENABLE); //MOE 主输出使能
TIM_OC3PreloadConfig(TIM5, TIM_OCPreload_Enable); //CH3预装载使能
TIM_OC4PreloadConfig(TIM5, TIM_OCPreload_Enable); //CH4预装载使能
TIM_ARRPreloadConfig(TIM5, ENABLE); //使能TIM5在ARR上的预装载寄存器
TIM_Cmd(TIM5, ENABLE); //使能TIM5
}
void TIM8_PWM_Init(u16 arr,u16 psc){
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitstruct;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM8 ,ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE); //时钟使能
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler =psc;
TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
TIM_OCInitstruct.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitstruct.TIM_OCNPolarity=TIM_OCNPolarity_High;
TIM_OCInitstruct.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitstruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitstruct.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitstruct.TIM_OCNIdleState=TIM_OCNIdleState_Reset;
TIM_OC1Init(TIM8,&TIM_OCInitstruct);
TIM_OC2Init(TIM8,&TIM_OCInitstruct);
TIM_OC1PreloadConfig(TIM8,TIM_OCPreload_Enable);
TIM_OC2PreloadConfig(TIM8,TIM_OCPreload_Enable);
TIM_CtrlPWMOutputs(TIM8,ENABLE); //MOE 主输出使能
TIM_ARRPreloadConfig(TIM8, ENABLE); //使能TIM3在ARR上的预装载寄存器
TIM_Cmd(TIM8, ENABLE); //使能TIM3
TIM_CtrlPWMOutputs(TIM8, ENABLE);// 主输出使能,当使用的是通用定时器时,这句不需要 s
}
四、0.96寸OLED的使用(增加人机交互,可更好实时观察数据)
0.96寸OLED(Organic Light Emitting Diode)显示屏是一种小尺寸的有机发光二极管显示屏,通常用于嵌入式系统、小型电子设备和Arduino项目中。它提供了高亮度、高对比度、低功耗以及较宽的视角,非常适合小型信息显示和用户界面设计。
OLED通常有2种,第一种是IIC通讯,第二种是SPI通讯。IIC协议更加简单,使用起来方便,但是性能没有SPI强,但是在OLED上使用IIC是完全足够了。这里就不详细讲解IIC和SPI的区别了,有兴趣的同学可以去下面的网站看看大佬写的文章。
平衡车使用OLED的主要目的是用来观察一下数据,比如:编码器的数据、陀螺仪角度数据、使用按键调PID参数时的参数数据等等。
//初始化OLED
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE ); //使能GPIOC时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_12|GPIO_Pin_11);
delay_ms(200);
OLED_WR_Byte(0xAE,OLED_CMD);//--display off
OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
OLED_WR_Byte(0x40,OLED_CMD);//--set start line address
OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
OLED_WR_Byte(0x81,OLED_CMD); // contract control
OLED_WR_Byte(0xFF,OLED_CMD);//--128
OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap
OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
OLED_WR_Byte(0x00,OLED_CMD);//
OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
OLED_WR_Byte(0x80,OLED_CMD);//
OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
OLED_WR_Byte(0x05,OLED_CMD);//
OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
OLED_WR_Byte(0xF1,OLED_CMD);//
OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
OLED_WR_Byte(0x12,OLED_CMD);//
OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
OLED_WR_Byte(0x30,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
OLED_WR_Byte(0x14,OLED_CMD);//
OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
}
五、HC06蓝牙模块
HC-06是一种常见的蓝牙串口模块,通常被用于将串口设备(如Arduino或其他微控制器)与蓝牙无线通信连接起来。以下是一些关于HC-06蓝牙模块的重要信息:
-
功能:HC-06蓝牙模块是一个串口蓝牙模块,可通过UART串口与其他设备通信。它可以用作透明串口传输,将串口数据通过蓝牙连接传输到其他设备,也可以用于构建蓝牙串口通信的应用程序。
-
通信距离:通常,HC-06模块的通信距离在10米左右,但这取决于环境条件和障碍物。
-
配对:HC-06通常以主从设备的方式工作,其中一个设备(通常是手机或电脑)充当主机,而HC-06模块充当从设备。在首次使用时,通常需要将HC-06模块与主机设备进行蓝牙配对。
-
配置:HC-06模块通常有一个AT命令模式,您可以使用这些命令来配置模块的参数,如蓝牙名称、波特率等。要进入AT命令模式,通常需要将模块上的特定引脚连接到地,并重启模块。
-
电源:HC-06通常需要3.3V或5V电源供电,具体的电源要求可以查看模块的规格。
-
应用:HC-06模块广泛用于各种项目,例如蓝牙遥控器、传感器数据传输、蓝牙串口通信等。它是一个经济实惠的解决方案,用于在项目中添加蓝牙功能。
-
注意事项:使用HC-06模块时需要小心处理电源和引脚连接,以免损坏模块。还需要注意模块的默认配置,例如波特率和配对密码。
#include "hc06.h"
u8 res; //设置全局变量
void HC06_Init(u16 arr)
{
GPIO_InitTypeDef GPIO_InitStrue;
USART_InitTypeDef USART_InitStrue;
NVIC_InitTypeDef NVIC_InitStrue;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //GPIO端口使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口端口使能
GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStrue.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStrue);
GPIO_InitStrue.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStrue.GPIO_Pin=GPIO_Pin_11;
GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStrue);
USART_InitStrue.USART_BaudRate=arr;
USART_InitStrue.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStrue.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
USART_InitStrue.USART_Parity=USART_Parity_No;
USART_InitStrue.USART_StopBits=USART_StopBits_1;
USART_InitStrue.USART_WordLength=USART_WordLength_8b;
USART_Init(USART3,&USART_InitStrue);
USART_Cmd(USART3,ENABLE); //ʹ�ܴ���2
USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//���������ж�
NVIC_InitStrue.NVIC_IRQChannel=USART3_IRQn;
NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStrue.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStrue);
}
void USART3_IRQHandler(void)
{
if(USART_GetITStatus(USART3,USART_IT_RXNE)!=RESET)
{
res= USART_ReceiveData(USART3);
USART_SendData(USART3,res); //串口3发送数据给蓝牙模块接收,也就是手机app接收到的数据
}
}
六、PID算法
PID(Proportional-Integral-Derivative)控制算法是一种用于控制系统的反馈控制算法。它通过比较实际输出与期望目标值之间的差异(误差),来调整控制器的输出,以使系统保持在期望的状态。PID控制算法由三个主要组成部分组成,分别是比例(Proportional)、积分(Integral)和微分(Derivative)。
以下是每个部分的解释以及PID控制的工作原理:
-
比例(Proportional)部分:比例部分的作用是根据当前误差的大小来调整控制输出。它与误差成正比,如果误差增大,比例部分的输出也增大,反之亦然。这个部分的作用是快速减小误差,但它单独使用时可能导致系统出现震荡。
-
积分(Integral)部分:积分部分的作用是积累误差并进行修正,以减小静态误差。它根据误差的积累来调整控制输出,通常用于减小比例控制导致的静态误差。积分部分的存在可以确保系统最终收敛到期望值,即使存在系统参数变化或外部干扰。
-
微分(Derivative)部分:微分部分的作用是预测误差的未来变化趋势,以减小控制输出的突变。它对误差的变化率进行调整,有助于防止系统在接近期望值时出现过冲或震荡。微分部分可以提高系统的稳定性。
PID控制算法的总输出是这三个部分的加权和,通常表示为:
Output=Kp⋅P+Ki⋅I+Kd⋅D
其中,P 是比例部分的输出,I 是积分部分的输出,D 是微分部分的输出,而 Kp、Ki 和 Kd 则是控制器的参数,通过调整这些参数可以实现不同的控制效果。
PID控制算法在自动化控制系统中广泛应用,如温度控制、电机控制、飞行控制等。通过适当调整参数,PID控制器可以实现系统快速响应、减小静态误差和维持系统稳定性。
//直立环(比例p、微分d)
int balance(float Angle,float Gyro){
static float Bias;
int balance;
Bias=Angle-ZHONGZHI;
balance=Bias*Kzp+Gyro*Kzd;
return balance;
}
//速度环(比例p、积分i)
int velocity(int Encoder_left,int Encoder_right){
static float Velocity, Encoder_Least, Encoder;
static float Encoder_Integral;
Ksi=Ksp/200;
Encoder_Least = (Encoder_Left+Encoder_Right)-0;
Encoder=Encoder*0.7+Encoder_Least*0.3;
Encoder_Integral=Encoder_Integral+Encoder;
Encoder_Integral=Encoder_Integral-Target_Velocity; //改变Target_Velocity就是控制小车前进后退
if(Encoder_Integral>15000) Encoder_Integral=15000;
if(Encoder_Integral<-15000) Encoder_Integral=-15000;
Velocity=Encoder*Ksp+Encoder_Integral*Ksi;
return Velocity;
}
//转向环(比例p、微分d)
int Turn(float yaw,float Gyro)
{
float Turn;
float Bias;//目标角度
Ktd=Ktp/100;
Bias=yaw-0;
Turn=Bias*Ktp+Gyro*Ktd;
return Turn;
}
平衡小车
平衡小车之家资料
链接: https://pan.baidu.com/s/1J6Rluf0T4mVtif2dqRtWxw?pwd=ghjm 提取码: ghjm
本人自制平衡车代码
链接: https://pan.baidu.com/s/1J6Rluf0T4mVtif2dqRtWxw?pwd=ghjm 提取码: ghjm