Files
MobKBK 460e0e9e73 init
2026-06-20 21:22:34 +08:00

260 lines
9.9 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "control.h"
#include "filter.h"
/**************************************************************************
作者:平衡小车之家
我的淘宝小店http://shop114407458.taobao.com/
**************************************************************************/
u8 Flag_Target,Flag_Change; //相关标志位
u8 temp1; //临时变量
float Voltage_Count,Voltage_All; //电压采样相关变量
float Gyro_K=0.004; //陀螺仪比例系数
int j;
#define a_PARAMETER (0.275f)
#define T 0.320f //0.145f
#define L 0.315f //0.17f
#define K 570.8f
/**************************************************************************
函数功能:小车运动数学模型
入口参数Y轴速度和角度
返回 值:无
**************************************************************************/
void Kinematic_Analysis(float Vy,float angle)
{
Target_A = Vy*(1+T*tan(angle)/2/L);
Target_B = Vy*(1-T*tan(angle)/2/L);
Servo=SERVO_INIT-angle*K;
}
/**************************************************************************
函数功能:所有的控制代码都在这里面
5ms定时中断由MPU6050的INT引脚触发
严格保证采样和数据处理的时间同步
**************************************************************************/
int EXTI15_10_IRQHandler(void)
{
if(INT==0)
{
EXTI->PR=1<<15; //清除LINE5上的中断标志位
Flag_Target=!Flag_Target;
if(delay_flag==1)
{
if(++delay_50==10) delay_50=0,delay_flag=0; //给主函数提供50ms的精准延时
}
if(Flag_Target==1) //5ms读取一次陀螺仪和加速度计的值
{
if(Usart_Flag==0&&PS2_ON_Flag==0&&Usart_ON_Flag==1) memcpy(rxbuf,Urxbuf,8*sizeof(u8)); //如果解锁了串口控制标志位,进入串口控制模式
Read_DMP(); //===更新姿态
Key();//扫描按键变化
return 0;
} //===10ms控制一次为了保证M法测速的时间基准首先读取编码器数据
UA_Encoder=Read_Encoder(2); //===读取编码器的值
Encoder_A=UA_Encoder/25;
Position_A+=Encoder_A; //===积分得到速度
UB_Encoder=-Read_Encoder(3); //===读取编码器的值
Encoder_B=UB_Encoder/25;
Position_B+=Encoder_B; //===积分得到速度
Read_DMP(); //===更新姿态
Led_Flash(100); //===LED闪烁;常规模式 1s改变一次指示灯的状态
Voltage_All+=Get_battery_volt(); //多次采样累积
if(++Voltage_Count==100) Voltage=Voltage_All/100,Voltage_All=0,Voltage_Count=0;//求平均值 获取电池电压
if(PS2_KEY==4)PS2_ON_Flag=1,CAN_ON_Flag=0,Usart_ON_Flag=0;
if(CAN_ON_Flag==1||Usart_ON_Flag==1||PS2_ON_Flag==1) CAN_N_Usart_Control(); //接到串口或者CAN遥控解锁指令之后使能CAN和串口控制输入
if(RC_Velocity>0&&RC_Velocity<15) RC_Velocity=15; //避免电机进入低速非线性区
if(Turn_Off(Voltage)==0) //===如果电池电压不存在异常
{
if(CAN_ON_Flag==0&&Usart_ON_Flag==0&&PS2_ON_Flag==0) Get_RC(Run_Flag);//===串口和CAN控制都未使能则接收蓝牙遥控指
Motor_A=Incremental_PI_A(Encoder_A,Target_A); //===速度闭环控制计算电机A最终PWM
Motor_B=Incremental_PI_B(Encoder_B,Target_B); //===速度闭环控制计算电机B最终PWM
Xianfu_Pwm(6900); //===PWM限幅
Set_Pwm(-Motor_A,-Motor_B,Servo); //===赋值给PWM寄存器
}
else Set_Pwm(0,0,SERVO_INIT); //===赋值给PWM寄存器
}
return 0;
}
/**************************************************************************
函数功能赋值给PWM寄存器
入口参数PWM
返回 值:无
**************************************************************************/
void Set_Pwm(int motor_a,int motor_b,int servo)
{
if(motor_a<0) INA2=1, INA1=0;
else INA2=0, INA1=1;
PWMA=myabs(motor_a);
if(motor_b<0) INB2=1, INB1=0;
else INB2=0, INB1=1;
PWMB=myabs(motor_b);
SERVO=servo;
}
/**************************************************************************
函数功能限制PWM赋值
入口参数:幅值
返回 值:无
**************************************************************************/
void Xianfu_Pwm(int amplitude)
{
if(Motor_A<-amplitude) Motor_A=-amplitude;
if(Motor_A>amplitude) Motor_A=amplitude;
if(Motor_B<-amplitude) Motor_B=-amplitude;
if(Motor_B>amplitude) Motor_B=amplitude;
if (Servo>1930) Servo=1930;
// if (Servo<1035) Servo=1035;
}
/**************************************************************************
函数功能位置PID控制过程中速度的设置
入口参数:无、幅值
返回 值:无
**************************************************************************/
void Xianfu_Velocity(int amplitude_A,int amplitude_B,int amplitude_C,int amplitude_D)
{
if(Motor_A<-amplitude_A) Motor_A=-amplitude_A; //位置控制模式中A电机的运行速度
if(Motor_A>amplitude_A) Motor_A=amplitude_A; //位置控制模式中A电机的运行速度
if(Motor_B<-amplitude_B) Motor_B=-amplitude_B; //位置控制模式中B电机的运行速度
if(Motor_B>amplitude_B) Motor_B=amplitude_B; //位置控制模式中B电机的运行速度
}
/**************************************************************************
函数功能:按键修改小车运行状态
入口参数:无
返回 值:无
**************************************************************************/
void Key(void)
{
u8 tmp;
tmp=click_N_Double(100);
if(tmp==2)Flag_Show=!Flag_Show;//双击控制显示模式
}
/**************************************************************************
函数功能:异常关闭电机
入口参数:电压
返回 值1异常 0正常
**************************************************************************/
u8 Turn_Off( int voltage)
{
u8 temp;
if(voltage<1110)//电池电压过低关闭电机
{
temp=1;
PWMA=0;
PWMB=0;
}
else
temp=0;
return temp;
}
/**************************************************************************
函数功能:绝对值函数
入口参数long int
返回 值unsigned int
**************************************************************************/
u32 myabs(long int a)
{
u32 temp;
if(a<0) temp=-a;
else temp=a;
return temp;
}
/**************************************************************************
函数功能增量PI控制器
入口参数:编码器测量值,目标速度
返回 值电机PWM
根据增量式离散PID公式
pwm+=Kp[ek-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]
e(k)代表本次偏差
e(k-1)代表上一次的偏差 以此类推
pwm代表增量输出
在我们的速度控制闭环系统里面只使用PI控制
pwm+=Kp[ek-e(k-1)]+Ki*e(k)
**************************************************************************/
int Incremental_PI_A (int Encoder,int Target)
{
static int Bias,Pwm,Last_bias;
Bias=Encoder-Target; //计算偏差
Pwm+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias; //增量式PI控制器
if(Pwm>7200)Pwm=7200;
if(Pwm<-7200)Pwm=-7200;
Last_bias=Bias; //保存上一次偏差
return Pwm; //增量输出
}
int Incremental_PI_B (int Encoder,int Target)
{
static int Bias,Pwm,Last_bias;
Bias=Encoder-Target; //计算偏差
Pwm+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias; //增量式PI控制器
if(Pwm>7200)Pwm=7200;
if(Pwm<-7200)Pwm=-7200;
Last_bias=Bias; //保存上一次偏差
return Pwm; //增量输出
}
/**************************************************************************
函数功能:通过串口指令对小车进行遥控
入口参数:串口指令
返回 值:无
**************************************************************************/
void Get_RC(u8 mode)
{
// float step=0.3f; //设置速度控制步进值。
if(mode==0)//速度
{
switch(Flag_Direction) //方向控制
{
case 1: Move_Y=RC_Velocity; Angle=0; break;
case 2: Move_Y=RC_Velocity; Angle=PI/4; break;
case 3: Move_Y=0; Angle=0; break;
case 4: Move_Y=-RC_Velocity; Angle=-PI/4; break;
case 5: Move_Y=-RC_Velocity; Angle=0; break;
case 6: Move_Y=-RC_Velocity; Angle=PI/4; break;
case 7: Move_Y=0; Angle=0; break;
case 8: Move_Y=+RC_Velocity; Angle=-PI/4; break;
default: Move_Y=0; Angle=0; break;
}
// if(Move_Y<-RC_Velocity) Move_Y=-RC_Velocity;
// if(Move_Y>RC_Velocity) Move_Y=RC_Velocity;
// if(Angle<-RC_Velocity) Angle=-RC_Velocity;
// if(Angle>RC_Velocity) Angle=RC_Velocity;
}
Kinematic_Analysis(Move_Y,Angle);//得到控制目标值,进行运动学分析
}
/**************************************************************************
函数功能接收CAN或者串口控制指令进行处理
入口参数:无
返回 值:无
**************************************************************************/
void CAN_N_Usart_Control(void)
{
// int flag_1, flag_2;
int RX,LY;
int Yuzhi=20;
if(CAN_ON_Flag==1||Usart_ON_Flag==1)
{
// if(rxbuf[1])flag_1=1; else flag_1=-1; //方向控制位
// if(rxbuf[3])flag_2=1; else flag_2=-1; //方向控制位
// Target_A=flag_1*rxbuf[0];
// Target_B=flag_2*rxbuf[1];
if(rxbuf[1]==0)Move_Y=rxbuf[0]; //识别运动方向
else Move_Y=-rxbuf[0]; //速度
Angle=(rxbuf[2]-90)*PI/180; //角度获取
}
else if (PS2_ON_Flag==1)
{
RX=PS2_RX-128;
LY=PS2_LY-128;
if(RX>-Yuzhi&&RX<Yuzhi)RX=0; //消除非线性区
if(LY>-Yuzhi&&LY<Yuzhi)LY=0;
Angle= RX*PI/4/120;
Move_Y=-LY/2.84;
//if(Move_Y<0)Angle=-Angle;
}
Kinematic_Analysis(Move_Y,Angle);//得到控制目标值,进行运动学分析
}