赞
踩
其实弄清了无人机的控制系统之后,再看球上自平衡的控制系统,你就自己立马能写出来了,
无非是先位置控制再姿态控制,输入的话无人机是输入位置和偏航角,球上自平衡偏航角都不需要输入,而且位置只需要水平位置就可以了。而且如果你不循迹的话,感觉位置控制都可以不用,就一个姿态环就OK了。能站着就已经不错了。
我们自己的球车好像就只用了俯仰角和翻滚角两个PID。
球上自平衡车感觉和平衡车的控制系统差不多,都是一个角度环,再加一个速度环,我们学校球车的源码,还有平衡小车之家的球车的源码都是这样,一个角度环一个速度环。那这样就跟平衡车其实差不多。都不用当作什么四旋翼。其实我推测球车可能一个角度环都够了。球车的角度环和速度环好像不是串级的,好像也没必要串级啊角度的期望不永远都是0度么,没必要用速度环的输出给角度环作为角度的期望。似乎就像平衡车的速度环和角度环可以串级也可以不串级。角度环输入的偏差直接取当时实际的小车角度就行了,因为期望就是0。加速度环应该还是为了让它能够长久地站着。单角度环可能不容易长久地站着。可能因为速度比角度反应更灵敏?那讲道理不如加个角速度内环?是的,好好想想为什么加速度环。
有一个发现就是平衡小车之家的平衡车的代码框架和球车的代码框架差不多。
平衡车都是角度环+速度环+转向环,球上自平衡不需要转向,所以就只有角度环+速度环了,当然它的这个速度环要分解为X,Y方向,角度也有两个方向的角度,一个俯仰角一个翻滚角,平衡车它就一个方向的角度,这样就好理解一些,球上自平衡可以就看作自平衡小车演化出来的。无人机则是有三个角度,三个方向的速度,是的,可以总结一下这个,这里面应该有某种通用的模式。叫自由度?让我想起二自由度的倒立摆。我觉得PID的关键就是你要控制几个量,就有几个PID嘛,就这么简单的事情嘛,你要控制一个角度,就有一个角度的PID嘛,你要控制一个维度的速度,那就有一个PID嘛,平面上的东西,你确定了两个维度的速度就可以完全确定一个东西了嘛,这有点像线性代数里面的矩阵的秩或者向量组的秩,
三维空间里面你最少确定三个量就可以确定一个东西,所以你用三个PID,控制住三个量,就可以控制住一个东西,对吧,无人机,那个系统,所以只需要输入三维坐标和偏航角,你就可以完全确定一个无人机,对吧,这是最少的最少的,我们为了主球效果好点多点也无所谓应该,但是至少这样我们能够更为系统地去分析一个控制系统。平衡车一维地我们最少控制一个量也就是角度就可以了,这就像一级倒立摆,二级倒立摆,三级倒立摆,其实就是一维空间二维空间三维空间地倒立摆嘛,一维的你就只需控制一个量嘛,二维的控制两个量嘛,自由度应该也是这个意思。这样我们去分析一个控制系统会更有条理。
球面自平衡,讲道理,如果不考虑偏航角,整个系统我就输入X,Y就可以确定了,对吧,平衡车我输入X,就可以了,无人机我输入X,Y,Z,偏航角就可以了。甚至板球控制系统我也可以这么分析对吧。我要控制一个球,在平面上,我只需要对这个系统输入X,Y就可以对吧。
这样分析感觉就像变成一类题型,万变不离其宗。
像无人机,你外在看是四个控制量,XYZ偏航角,但是你直接能控制的是四个电机,那么你就得把这两者联系起来。平衡车也是,直接控制的就是电机,球上自平衡也是,直接控制的就三个电机。我发现这些系统它的电机数量和它的外在的控制量是一致的,平衡车本质上可以看作一个电机,另一个起支撑作用,是这样的,无人机如果三个电机的话,它的偏航角没法保证,可能会旋转,球上自平衡两个电机也不行,独轮车一个电机不行,真的是这样的,电机数量不能少于控制系统的维度或者说自由度。少一个都不行,都保证不了,这里面肯定是有道理的。这样我对控制系统的认识又上升到一个新的层面。串级PID的作用可能就是一步步把外在的控制量转化为直接控制量。
平衡车里面已经承认了角度环和速度环直接相加是会有干扰的,我估计球车这样直接加也是会有干扰的。
问你如何调PID,肯定是先调姿态环,再调速度环,而且姿态环的频率应该是远高于速度环的。
感觉球车只需要控制住两个方向的角度和两个方向的速度总共四个PID环就OK了。
是的,如下面所说,可以等效为两个一级倒立摆模型!!!这个太棒了,这不是和我上面的分析本质一样么。平衡车就像一个一级倒立摆模型。
下面是平衡小车之家的球车的代码,可以看到给了两组PID参数。一组是角度环一组是速度环。
X,Y的期望速度可能是遥控器给的。还有如果我是让球车自主循迹呢,是不是要加位置环?或者让球车定点不移动,是不是要加位置环。确实如果是遥控的话,位置环就形同虚设了,就像无人机,期望的角度或者速度直接遥控器给你了,不需要位置环输出,球车应该也是的,就是如果是遥控,期望速度那遥控器直接给力了,不需要位置,如果是自主循迹,我觉得和无人机一样,应该是需要一个位置环的。无人机有不同的模式,我觉得球车应该也是的。
真正PID的代码在这,在control.c的int EXTI15_10_IRQHandler(void)这个函数里。这里面可以清晰看到角度环和速度环是直接叠加的。我仔细看了下学校的球车代码,也是角度环的输出和速度环的输出相加
我仔细看了下学校的球车代码,也是角度环的输出和速度环的输出相加,仔细注意,第二个图等号右边的Motor_No_1_PWM就是第一张图里面角度环的,第二张图就是说明了最后角度环输出的PWM和速度环输出的PWM相加了,最终就是电机的PWM。
这是State_Capture.c这个文件
- #include "common.h"
- #include "include.h"
- #include "State_Capture.h"
-
- extern unsigned char Bluetooth_flag;
- extern unsigned char Command;
- void Gyro_Control(void);
- void Kalman_Fliter(void);
- IMU_Data State_Data;
-
-
- float invSqrt(float x)
- {
- float halfx = 0.5f * x;
- float y = x;
- long i = *(long*)&y;
-
- i = 0x5f3759df - (i>>1);
- y = *(float*)&i;
- y = y * (1.5f - (halfx * y * y));
-
- return y;
- }
-
- int16 X_Gyro_OFF,Y_Gyro_OFF,Z_Gyro_OFF;
- void ReadIMU_OFF()
- {
- uint16 i=0;
- int32 Sum_X,Sum_Y,Sum_Z;
- for(i=0;i<100;i++)
- {
- Sum_X += GetData(GYRO_XOUT_H);
- Sum_Y += GetData(GYRO_YOUT_H);
- Sum_Z += GetData(GYRO_ZOUT_H);
- DELAY_MS(5);
- }
-
- X_Gyro_OFF=Sum_X/100;
- Y_Gyro_OFF=Sum_Y/100;
- Z_Gyro_OFF=Sum_Z/100;
- }
- void Angle_Get()
- {
-
- float ACCE_X_TEMP,ACCE_Y_TEMP,ACCE_Z_TEMP;
- GET_ACCE();
-
- ACCE_X_TEMP=IMU.X_ACCE_Data;
- if(ACCE_X_TEMP>16384)
- ACCE_X_TEMP=(8192-ACCE_X_TEMP)/8192.0;
- else
- ACCE_X_TEMP=-ACCE_X_TEMP/8192.0;
-
- ACCE_Y_TEMP=IMU.Y_ACCE_Data;
- if(ACCE_Y_TEMP>16384)
- ACCE_Y_TEMP=(8192-ACCE_Y_TEMP)/8192.0;
- else
- ACCE_Y_TEMP=-ACCE_Y_TEMP/8192.0;
-
- ACCE_Z_TEMP=IMU.Z_ACCE_Data;
- if(ACCE_Z_TEMP>16384)
- ACCE_Z_TEMP=(8192-ACCE_Z_TEMP)/8192.0;
- else
- ACCE_Z_TEMP=-ACCE_Z_TEMP/8192.0;
-
- State_Data.X_Angle=57.3*atan(ACCE_X_TEMP*invSqrt(ACCE_Y_TEMP*ACCE_Y_TEMP+ACCE_Z_TEMP*ACCE_Z_TEMP));
- State_Data.Y_Angle=57.3*atan(ACCE_Y_TEMP*invSqrt(ACCE_X_TEMP*ACCE_X_TEMP+ACCE_Z_TEMP*ACCE_Z_TEMP));
- State_Data.Z_Angle=57.3*atan(sqrt(ACCE_X_TEMP*ACCE_X_TEMP+ACCE_Y_TEMP*ACCE_Y_TEMP)/ACCE_Z_TEMP);
-
- }
-
- void Gyro_Get()
- {
- GET_GYRO();
- State_Data.X_Omiga=(IMU.X_GYRO_Data-X_Gyro_OFF)/16.4;
- State_Data.Y_Omiga=(IMU.Y_GYRO_Data-Y_Gyro_OFF)/16.4;
- State_Data.Z_Omiga=(IMU.Z_GYRO_Data-Z_Gyro_OFF)/16.4;
- }
-
- float Rotate_Angle=0;
- void Get_Bnlance_State()
- {
- Angle_Get();
- Gyro_Get();
- Rotate_Angle+=State_Data.Z_Omiga*0.002;
- Kalman_Fliter();
-
- }
-
- float Rotate_kp=8,Rotate_ki=0.3,Rotate_kd=0.3;
- float Rotate_pwm,rotate_integrate=0;
- void Rotate_Control()
- {
- if(ABS(Rotate_Angle)<=5) rotate_integrate+=Rotate_ki*Rotate_Angle;
- if(rotate_integrate>=20) rotate_integrate=20;
- if(rotate_integrate>=-20) rotate_integrate=-20;
-
- Rotate_pwm=Rotate_kp*Rotate_Angle+rotate_integrate-Rotate_kd*State_Data.Z_Omiga;
- if(Rotate_pwm>=150) Rotate_pwm=150;
- if(Rotate_pwm<=-150) Rotate_pwm=-150;
-
- }
-
- #define dt 0.002
- float W_Pitch=0.88,W_Roll=0.9;
-
- /**************************************************************************************
- 角度融合
- **************************************************************************************/ //*************
- float Kalman_Filter_Roll(float angle_m,float gyro_m)//非矩阵卡尔曼滤波 //*************
- { //*************
- static float x_roll=0; //*************
- static float P_roll=0.000001; //*************
- static float Q_roll=0.000001; //*************
- static float R_roll=0.35;//0.35 //*************
- static float k_roll=0; //*************
- gyro_m=W_Roll*gyro_m;//角速度修正 //*************
- x_roll=x_roll+gyro_m*dt; //*************
- P_roll=P_roll+Q_roll; //*************
- k_roll=P_roll/(P_roll+R_roll); //*************
- x_roll=x_roll+k_roll*(angle_m-x_roll); //*************
- P_roll=(1-k_roll)*P_roll; //*************
- return x_roll; //*************
- }
-
- /**************************************************************************************
- 角度融合
- **************************************************************************************/ //*************
- float Kalman_Filter_Pitch(float angle_m0,float gyro_m0)//非矩阵卡尔曼滤波 //*************
- { //*************
- static float x_pitch=0; //*************
- static float P_pitch=0.000001; //*************
- static float Q_pitch=0.000001; //*************
- static float R_pitch=0.35;//0.35 //*************
- static float k_pitch=0; //*************
- gyro_m0=W_Pitch*gyro_m0;//角速度修正 //*************
- x_pitch=x_pitch+gyro_m0*dt; //*************
- P_pitch=P_pitch+Q_pitch; //*************
- k_pitch=P_pitch/(P_pitch+R_pitch); //*************
- x_pitch=x_pitch+k_pitch*(angle_m0-x_pitch); //*************
- P_pitch=(1-k_pitch)*P_pitch; //*************
- return x_pitch; //*************
- }
- uint8 Danger_Flag=0;
- float Pitch_Angle=0,Pitch_Gyro=0;
- float Roll_Angle=0,Roll_Gyro=0;
- void Kalman_Fliter()
- {
-
- Pitch_Gyro=-State_Data.Y_Omiga;
- Roll_Gyro=State_Data.X_Omiga;
-
- Pitch_Angle=Kalman_Filter_Pitch(State_Data.X_Angle,Pitch_Gyro);
- Roll_Angle =Kalman_Filter_Roll(State_Data.Y_Angle,Roll_Gyro);
-
-
- if(ABS(Pitch_Angle)>=10) Danger_Flag=1;
- if(ABS(Roll_Angle)>=10) Danger_Flag=1;
- }
-
-
- float Pitch_Kp=35,Pitch_Ki=10,Pitch_Kd=0;
- float Roll_Kp=35,Roll_Ki=10,Roll_Kd;
- float Pitch_Balance_Pwm;
- float Roll_Balance_Pwm;
- float Pitch_Setpoint=-1.2;
- float Roll_Setpoint=0.3;
- float Motor_No_1_PWM,Motor_No_2_PWM,Motor_No_3_PWM;
- float Pitch_Angle_Output,Roll_Angle_Output;
- float Pitch_Angle_Integrate,Roll_Angle_Integrate;
- float Pitch_Angle_Error,Roll_Angle_Error;
- void Ball_Balance_Control()
- {
- Pitch_Angle_Error=(Pitch_Angle-Pitch_Setpoint) ;
- Roll_Angle_Error=(Roll_Angle-Roll_Setpoint);
- if(Pitch_Angle_Error<=3&&Pitch_Angle_Error>=-3) Pitch_Angle_Integrate+=Pitch_Ki*Pitch_Angle_Error;
- if(Pitch_Angle_Integrate>=20) Pitch_Angle_Integrate=20;
- if(Pitch_Angle_Integrate<=-20) Pitch_Angle_Integrate=-20;
-
- if(Roll_Angle_Error<=3&&Roll_Angle_Error>=-3) Roll_Angle_Integrate+=Roll_Ki*Roll_Angle_Error;
- if(Roll_Angle_Integrate>=20) Roll_Angle_Integrate=20;
- if(Roll_Angle_Integrate<=-20) Roll_Angle_Integrate=-20;
-
-
- Pitch_Angle_Output=Pitch_Kp*Pitch_Angle_Error+Pitch_Angle_Integrate+Pitch_Kd*Pitch_Gyro;
-
- Roll_Angle_Output =Roll_Kp*Roll_Angle_Error+Roll_Angle_Integrate+Roll_Kd*Roll_Gyro;
-
-
- // Motor_No_1_PWM=Roll_Balance_Pwm/2;
- // Motor_No_2_PWM=(1.732*Pitch_Balance_Pwm-Roll_Balance_Pwm)/4;
- // Motor_No_3_PWM=(-1.732*Pitch_Balance_Pwm-Roll_Balance_Pwm)/4;
-
-
-
-
- //Motor_No_1_PWM=0;
- /// Motor_No_2_PWM=Pitch_Balance_Pwm;
- //Motor_No_3_PWM=-Pitch_Balance_Pwm;
-
- //Motor_No_1_PWM=Roll_Balance_Pwm/2;
- // Motor_No_2_PWM=-Roll_Balance_Pwm/4;
- // Motor_No_3_PWM=-Roll_Balance_Pwm/4;
-
- }
-
-
- float Pitch_Gyro_Kp=12,Pitch_Gyro_Ki=5,Pitch_Gyro_Kd=100;
- float Roll_Gyro_Kp=12,Roll_Gyro_Ki=5,Roll_Gyro_Kd=100;
- float Pitch_Gyro_Integrate=0;
- float Roll_Gyro_Integrate=0;
- float Pitch_Gyro_Error,Roll_Gyro_Error;
- float Last_Pitch_Gyro_Error,Last_Roll_Gyro_Error;
- void Gyro_Control()
- {
- Last_Pitch_Gyro_Error=Pitch_Gyro_Error;
- Last_Roll_Gyro_Error=Roll_Gyro_Error;
-
- Pitch_Gyro_Error=Pitch_Angle_Output-(-Pitch_Gyro) ;
- Roll_Gyro_Error=Roll_Angle_Output-(-Roll_Gyro);
-
- if(Pitch_Gyro_Error<=20&&Pitch_Gyro_Error>=-20) Pitch_Gyro_Integrate+=Pitch_Gyro_Ki*Pitch_Gyro_Error;
- if(Pitch_Gyro_Integrate>=300) Pitch_Gyro_Integrate=300;
- if(Pitch_Gyro_Integrate<=-300) Pitch_Gyro_Integrate=-300;
-
- if(Roll_Gyro_Error<=20&&Roll_Gyro_Error>=-20) Roll_Gyro_Integrate+=Roll_Gyro_Ki*Roll_Gyro_Error;
- if(Roll_Gyro_Integrate>=300) Roll_Gyro_Integrate=300;
- if(Roll_Gyro_Integrate<=-300) Roll_Gyro_Integrate=-300;
-
-
-
-
- Pitch_Balance_Pwm=Pitch_Gyro_Kp*Pitch_Gyro_Error+Pitch_Gyro_Kd*(Pitch_Gyro_Error-Last_Pitch_Gyro_Error);
- Roll_Balance_Pwm =Roll_Gyro_Kp *Roll_Gyro_Error +Roll_Gyro_Kd *(Roll_Gyro_Error -Last_Roll_Gyro_Error );
-
-
-
-
- Motor_No_1_PWM=-Roll_Balance_Pwm/2;
- Motor_No_2_PWM=(-1.732*Pitch_Balance_Pwm+Roll_Balance_Pwm)/4;
- Motor_No_3_PWM=(1.732*Pitch_Balance_Pwm+Roll_Balance_Pwm)/4;
-
- Rotate_Control();
- }
-
-
-
-
-
- extern int Motor_Speed_No_1,Motor_Speed_No_2,Motor_Speed_No_3;//三个电机反馈脉冲
- float Pitch_Speed_Feedback,Roll_Speed_Feedback;//速度返回值
- float Pitch_Speedset=0,Roll_Speedset=0;//速度设定
- float Pitch_Speederror,Roll_Speederror;//速度偏差
- float Last_Pitch_Speederror,Last_Roll_Speederror;//速度偏差
- float Pitch_SpeedIntegrate,Roll_SpeedIntegrate;//速度积分
- float Pitch_Speed_Kp=6,Pitch_Speed_Ki=1.8;//速度PI
- float Roll_Speed_Kp=6,Roll_Speed_Ki=1.8;//速度PI
- float Pitch_Speed_Output,Roll_Speed_Output;//速度输出
- float Last_Pitch_Speed_Output,Last_Roll_Speed_Output;//上次速度输出
- extern uint8 Speed_Sampile_Cnt;
- float Pitch_Speed_PWM,Roll_Speed_PWM;
-
- void SpeedControl()
- {
-
- Last_Pitch_Speed_Output=Pitch_Speed_Output;
- Last_Roll_Speed_Output=Roll_Speed_Output;
-
- Last_Pitch_Speederror=Pitch_Speederror;
- Last_Roll_Speederror=Roll_Speederror;
-
-
- Roll_Speed_Feedback=Motor_Speed_No_1/2;
- Pitch_Speed_Feedback=(Motor_Speed_No_2+Motor_Speed_No_3)*1.732/2;
-
- Pitch_Speederror=Pitch_Speedset-Pitch_Speed_Feedback;
- Roll_Speederror=Roll_Speederror-Roll_Speed_Feedback;
-
- if(Pitch_Speederror>=100) Pitch_Speederror=100;
- if(Pitch_Speederror<=-100) Pitch_Speederror=-100;
- if(ABS(Pitch_Speederror)<=15) Pitch_SpeedIntegrate+=Pitch_Speed_Ki*Pitch_Speederror;
- if(Pitch_SpeedIntegrate>=200) Pitch_SpeedIntegrate=200;
- if(Pitch_SpeedIntegrate<=-200) Pitch_SpeedIntegrate=-200;
- Pitch_Speed_Output=Pitch_Speed_Kp*Pitch_Speederror+Pitch_SpeedIntegrate;
-
-
- //Pitch_Speed_PWM=Last_Pitch_Speed_Output+(Pitch_Speed_Output);
-
-
- if(Pitch_Speed_Output>=500) Pitch_Speed_Output=500;
- if(Pitch_Speed_Output<=-500) Pitch_Speed_Output=-500;
- ///
- if(Roll_Speederror>=100) Roll_Speederror=100;
- if(Roll_Speederror<=-100) Roll_Speederror=-100;
- if(ABS(Roll_Speederror)<=15) Roll_SpeedIntegrate+=Roll_Speed_Ki*Roll_Speederror;
- if(Roll_SpeedIntegrate>=200) Roll_SpeedIntegrate=200;
- if(Roll_SpeedIntegrate<=-200) Roll_SpeedIntegrate=-200;
- Roll_Speed_Output=Roll_Speed_Kp*Roll_Speederror+Roll_SpeedIntegrate;
- //Roll_Speed_PWM=Last_Roll_Speed_Output+(Roll_Speed_Output);
-
-
-
- if(Roll_Speed_Output>=500) Roll_Speed_Output=500;
- if(Roll_Speed_Output<=-500) Roll_Speed_Output=-500;
- }
-
-
- void Speed_Control_Output()
- {
- Pitch_Speed_PWM=Last_Pitch_Speed_Output+(Speed_Sampile_Cnt+1)*(Pitch_Speed_Output-Last_Pitch_Speed_Output)/50;
- Roll_Speed_PWM=Last_Roll_Speed_Output+(Speed_Sampile_Cnt+1)*(Roll_Speed_Output-Last_Roll_Speed_Output)/50;
- //Pitch_Speed_PWM=Last_Pitch_Speed_Output+(Pitch_Speed_Output);
- //Roll_Speed_PWM=Last_Roll_Speed_Output+(Roll_Speed_Output);
-
- }
-
-
-
- void Control_Output()
- {
-
-
- Motor_No_1_PWM=Motor_No_1_PWM+Roll_Speed_PWM/2+Pitch_Speed_PWM*0-Rotate_pwm;
- Motor_No_2_PWM=Motor_No_2_PWM-Roll_Speed_PWM/4+Pitch_Speed_PWM*1.732/4-Rotate_pwm;
- Motor_No_3_PWM=Motor_No_3_PWM-Roll_Speed_PWM/4-Pitch_Speed_PWM*1.732/4-Rotate_pwm;
- if(Danger_Flag==1)
- {
- Motor_No_1_PWM=0;
- Motor_No_2_PWM=0;
- Motor_No_3_PWM=0;
- }
-
- if(Bluetooth_flag==1)
- {
- // if(Command==0) {Motor_No_1_PWM=0; Motor_No_3_PWM=0; Motor_No_2_PWM=0;}
- // else if(Command==1) {Motor_No_1_PWM=-149;Motor_No_3_PWM=0;Motor_No_2_PWM=408;}
- // else if(Command==2) {Motor_No_1_PWM=0;Motor_No_3_PWM=-500;Motor_No_2_PWM=500;}
- // else if(Command==3) {Motor_No_1_PWM=149;Motor_No_3_PWM=-408;Motor_No_2_PWM=0;}
- //else if(Command==4) {Motor_No_1_PWM=-500;Motor_No_3_PWM=433;Motor_No_2_PWM=433;}
- // else if(Command==5) {Motor_No_1_PWM=500;Motor_No_3_PWM=-433;Motor_No_2_PWM=-433;}
- // else if(Command==6) {Motor_No_1_PWM=0;Motor_No_3_PWM=408;Motor_No_2_PWM=149;}
- // else if(Command==7) {Motor_No_1_PWM=0;Motor_No_3_PWM=500;Motor_No_2_PWM=-500;}
- // else if(Command==8) {Motor_No_1_PWM=408;Motor_No_3_PWM=149;Motor_No_2_PWM=0;}
- // else if(Command=='A') {Motor_No_1_PWM=-500;Motor_No_3_PWM=-500;Motor_No_2_PWM=-500;}
- // else if(Command=='B') {Motor_No_1_PWM=-500;Motor_No_3_PWM=-500;Motor_No_2_PWM=-500;}
- // else if(Command=='C') {Motor_No_1_PWM=-500;Motor_No_3_PWM=-500;Motor_No_2_PWM=-500;}
- // else if(Command=='D') {Motor_No_1_PWM=-500;Motor_No_3_PWM=-500;Motor_No_2_PWM=-500;}
- // else {Motor_No_1_PWM=0; Motor_No_3_PWM=0; Motor_No_2_PWM=0;}
- if(Command==0) {Motor_No_1_PWM=0; Motor_No_3_PWM=0; Motor_No_2_PWM=0;}
- //对角
- else if(Command==1) {Motor_No_1_PWM=-2*288;Motor_No_3_PWM=0;Motor_No_2_PWM=2*288;}
- else if(Command==3) {Motor_No_1_PWM=2*288;Motor_No_3_PWM=-2*288;Motor_No_2_PWM=0;}
- else if(Command==6) {Motor_No_1_PWM=-2*288;Motor_No_3_PWM=2*288;Motor_No_2_PWM=0;}
- else if(Command==8) {Motor_No_1_PWM=2*288;Motor_No_3_PWM=0;Motor_No_2_PWM=-2*288;}
-
- //正交
- else if(Command==2) {Motor_No_1_PWM=0;Motor_No_3_PWM=-1.5*500;Motor_No_2_PWM=1.5*500;}
- else if(Command==4) {Motor_No_1_PWM=-1.5*500;Motor_No_3_PWM=1.5*433/2;Motor_No_2_PWM=1.5*433/2;}
- else if(Command==5) {Motor_No_1_PWM=1.5*500;Motor_No_3_PWM=-1.5*433/2;Motor_No_2_PWM=-1.5*433/2;}
- else if(Command==7) {Motor_No_1_PWM=0;Motor_No_3_PWM=1.5*500;Motor_No_2_PWM=-1.5*500;}
-
- //自旋
- else if(Command=='A') {Motor_No_1_PWM=-500;Motor_No_3_PWM=-500;Motor_No_2_PWM=-500;}
- else if(Command=='B') {Motor_No_1_PWM=500;Motor_No_3_PWM=500;Motor_No_2_PWM=500;}
- else if(Command=='C') {Motor_No_1_PWM=999;Motor_No_3_PWM=999;Motor_No_2_PWM=999;}
- else {Motor_No_1_PWM=0; Motor_No_3_PWM=0; Motor_No_2_PWM=0;}
- }
-
- if(Motor_No_1_PWM>=1000) Motor_No_1_PWM=1000;
- if(Motor_No_1_PWM<=-1000) Motor_No_1_PWM=-1000;
-
- if(Motor_No_2_PWM>=1000) Motor_No_2_PWM=1000;
- if(Motor_No_2_PWM<=-1000) Motor_No_2_PWM=-1000;
-
- if(Motor_No_3_PWM>=1000) Motor_No_3_PWM=1000;
- if(Motor_No_3_PWM<=-1000) Motor_No_3_PWM=-1000;
-
- if(Motor_No_1_PWM>=0)//电机1#
- {
- ftm_pwm_duty(FTM0, FTM_CH1,(uint32)(Motor_No_1_PWM/10));
- ftm_pwm_duty(FTM0, FTM_CH2,0);
- }
- else
- {
- ftm_pwm_duty(FTM0, FTM_CH1,0);
- ftm_pwm_duty(FTM0, FTM_CH2,(uint32)(-Motor_No_1_PWM/10));
- }
-
-
- if(Motor_No_2_PWM>=0)//电机2#
- {
- ftm_pwm_duty(FTM0, FTM_CH5,(uint32)(Motor_No_2_PWM/10));
- ftm_pwm_duty(FTM0, FTM_CH6,0);
- }
- else
- {
- ftm_pwm_duty(FTM0, FTM_CH5,0);
- ftm_pwm_duty(FTM0, FTM_CH6,(uint32)(-Motor_No_2_PWM/10));
- }
-
-
- if(Motor_No_3_PWM>=0)//电机3#
- {
- ftm_pwm_duty(FTM0, FTM_CH4,(uint32)(Motor_No_3_PWM/10));
- ftm_pwm_duty(FTM0, FTM_CH7,0);
- }
- else
- {
- ftm_pwm_duty(FTM0, FTM_CH4,0);
- ftm_pwm_duty(FTM0, FTM_CH7,(uint32)(-Motor_No_3_PWM/10));
- }
-
-
-
- }
平衡小车之家球车里地control.c
- #include "control.h"
- #include "filter.h"
- /**************************************************************************
- 作者:平衡小车之家
- 我的淘宝小店:http://shop114407458.taobao.com/
- **************************************************************************/
- u8 Flag_Target; //相关标志位
- float Voltage_Count,Voltage_All; //电压采样相关变量
- int Balance_Pwm_X,Velocity_Pwm_X,Balance_Pwm_Y,Velocity_Pwm_Y;
- #define X_PARAMETER (0.5f)
- #define Y_PARAMETER (sqrt(3)/2.f)
- #define L_PARAMETER (1.0f)
- /**************************************************************************
- 函数功能:小车运动 逆运动学分析
- 入口参数:X Y Z 三轴速度或者位置
- 返回 值:无
- **************************************************************************/
- void Kinematic_Analysis(float Vx,float Vy,float Vz)
- {
- Target_A = Vx + L_PARAMETER*Vz;
- Target_B = -X_PARAMETER*Vx + Y_PARAMETER*Vy + L_PARAMETER*Vz;
- Target_C = -X_PARAMETER*Vx - Y_PARAMETER*Vy + L_PARAMETER*Vz;
- }
- /**************************************************************************
- 函数功能:小车运动 正运动学分析 注:实际注释掉的是理想的运动学分析,实际使用放大了3倍,对计算结果没影响,主要是避免舍去误差
- 入口参数:A B C三个电机的速度
- 返回 值:无
- **************************************************************************/
- void Forward_Kinematics(float Va,float Vb,float Vc)
- {
- // Motor_X=(Va*2-Vb-Vc)/3;
- // Motor_Y=(Vb-Vc)/2/Y_PARAMETER;
- // Motor_Z=(Va+Vb+Vc)/3;
- Motor_X=Va*2-Vb-Vc;
- Motor_Y=(Vb-Vc)*sqrt(3);
- Motor_Z=Va+Vb+Vc;
- }
- /**************************************************************************
- 函数功能:所有的控制代码都在这里面
- 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读取一次陀螺仪和加速度计的值
- {
- Read_DMP(); //===更新姿态
- Key(); //扫描按键变化
- if(Pitch_Bias>-0.8&&Pitch_Bias<0.8&&Roll_Bias>-0.8&&Roll_Bias<0.8)Led_Flash(0); //接近平衡位置,常亮
- else Led_Flash(100); //===LED闪烁
- Voltage_All+=Get_battery_volt(); //多次采样累积
- if(++Voltage_Count==100) Voltage=Voltage_All/100,Voltage_All=0,Voltage_Count=0;//求平均值 获取电池电压
- return 0;
- } //===10ms控制一次
- Read_DMP(); //===更新姿态
- Roll_Bias =Roll-Roll_Zero; //获取Y方向的偏差
- Pitch_Bias=Pitch-Pitch_Zero; //获取X方向的偏差
- Forward_Kinematics(Motor_A,Motor_B,Motor_C); //正运动学分析,得到X Y Z 方向的速度
- Balance_Pwm_X=balance_Pitch(Pitch_Bias,gyro[1]); //X方向的倾角控制
- Balance_Pwm_Y=-balance_Roll(Roll_Bias, gyro[0]); //Y方向的倾角控制
- Velocity_Pwm_X=velocity_X(Motor_X); //X方向的速度控制
- Velocity_Pwm_Y=velocity_Y(Motor_Y); //Y方向的速度控制
- Move_X =Balance_Pwm_X+Velocity_Pwm_X; //===X方向控制量累加
- Move_Y =Balance_Pwm_Y+Velocity_Pwm_Y; //===Y方向控制量累加
- Move_Z=0; //Z轴不做控制
- Kinematic_Analysis(Move_X,Move_Y,Move_Z);//逆运动学分析,得到A B C电机控制量
- Motor_A=Target_A;//直接调节PWM频率
- Motor_B=Target_B;//直接调节PWM频率
- Motor_C=Target_C;//直接调节PWM频率
- Xianfu_Pwm(1300);//===PWM频率限幅 因为频率太大之后扭矩减小不再满足小车需求
- if(Turn_Off(Voltage)==0) Set_Pwm(Motor_A,Motor_B,Motor_C); //赋值给PWM寄存器
- if(Flag_Zero) //这是人为更新零点值
- {
- Roll_Zero=Roll; //ROLL更新
- Pitch_Zero=Pitch; //Pitch更新
- Flag_Zero=0; //清零过程仅执行一次 等待下一次指令
- }
- }
- return 0;
- }
-
- /**************************************************************************
- 函数功能:直立PD控制Y
- 入口参数:角度、角速度
- 返回 值:直立控制PWM
- 作 者:平衡小车之家
- **************************************************************************/
- int balance_Roll(float Angle,float Gyro)
- {
- float Bias;
- int balance;
- Bias=Angle; //===求出平衡的角度中值 和机械等重心分布相关
- balance=Balance_Kp*Bias+Gyro*Balance_Kd/100; //===计算平衡控制的电机PWM PD控制 kp是P系数 kd是D系数
- return balance;
- }
- /**************************************************************************
- 函数功能:直立PD控制
- 入口参数:角度、角速度
- 返回 值:直立控制PWM
- 作 者:平衡小车之家X
- **************************************************************************/
- int balance_Pitch(float Angle,float Gyro)
- {
- float Bias;
- int balance;
- Bias=Angle; //===求出平衡的角度中值和机械等重心分布相关
- balance=Balance_Kp*Bias+Gyro*Balance_Kd/100; //===计算平衡控制的电机PWM PD控制 kp是P系数 kd是D系数
- return balance;
- }
-
- /**************************************************************************
- 函数功能:速度PI控制 修改前进后退速度,请修Target_Velocity
- 入口参数:左轮速度、右轮速度
- 返回 值:速度控制PWM
- 作 者:平衡小车之家
- **************************************************************************/
- int velocity_X(int velocity)
- {
- static float Velocity,Encoder_Least,Encoder,Movement;
- static float Target_Velocity=2500;
- static float Encoder_Integral;
- if(1==Flag_Left) Movement=-Target_Velocity; //===前进标志位置1
- else if(1==Flag_Right) Movement=Target_Velocity; //===后退标志位置1
- else Movement=0;
- //=============速度PI控制器=======================//
- Encoder_Least=Mean_Filter_X(velocity); //速度滤波
- Encoder *= 0.7; //===一阶低通滤波器
- Encoder += Encoder_Least*0.3; //===一阶低通滤波器
- Encoder_Integral +=Encoder; //===积分出位移
- Encoder_Integral +=Movement; //===接收遥控器数据,控制前进后退
- if(Encoder_Integral>150000) Encoder_Integral=150000; //===积分限幅
- if(Encoder_Integral<-150000) Encoder_Integral=-150000; //===积分限幅
- if(Flag_Stop) Encoder_Integral=0; //===电机关闭后清除积分
- Velocity=Encoder*Velocity_Kp/100+Encoder_Integral*Velocity_Ki/5000; //===速度控制
- if(Flag_Stop) Velocity=0; //===电机关闭后清除积分
- Show_Data1=Encoder_Integral;
- Show_Data3=Velocity;
- if(Velocity>1000) Velocity=1000; //===速度环限幅
- if(Velocity<-1000) Velocity=-1000; //===速度环限幅
- return Velocity;
- }
- /**************************************************************************
- 函数功能:速度PI控制 修改前进后退速度,请修Target_Velocity
- 入口参数:左轮速度、右轮速度
- 返回 值:速度控制PWM
- 作 者:平衡小车之家
- **************************************************************************/
- int velocity_Y(int velocity)
- {
- static float Velocity,Encoder_Least,Encoder,Movement;
- static float Target_Velocity=2500;
- static float Encoder_Integral;
- if(1==Flag_Qian) Movement=Target_Velocity; //===前进标志位置1
- else if(1==Flag_Hou) Movement=-Target_Velocity; //===后退标志位置1
- else Movement=0;
- // //=============速度PI控制器=======================//
- Encoder_Least=Mean_Filter_Y(velocity); //速度滤波
- Encoder *= 0.7; //===一阶低通滤波器
- Encoder += Encoder_Least*0.3; //===一阶低通滤波器
- Encoder_Integral +=Encoder; //===积分出位移
- Encoder_Integral +=Movement; //===接收遥控器数据,控制前进后退
- if(Encoder_Integral>150000) Encoder_Integral=150000; //===积分限幅
- if(Encoder_Integral<-150000) Encoder_Integral=-150000; //===积分限幅
- if(Flag_Stop) Encoder_Integral=0; //===电机关闭后清除积分
- Velocity=Encoder*Velocity_Kp/100+Encoder_Integral*Velocity_Ki/5000; //===速度控制
- if(Flag_Stop) Velocity=0; //===电机关闭后清除积分
- Show_Data2=Encoder_Integral;
- Show_Data4=Velocity;
- if(Velocity>1000) Velocity=1000; //===速度环限幅
- if(Velocity<-1000) Velocity=-1000; //===速度环限幅
- return Velocity;
- }
-
- /**************************************************************************
- 函数功能:赋值给PWM寄存器
- 入口参数:PWM
- 返回 值:无
- **************************************************************************/
- void Set_Pwm(int motor_a,int motor_b,int motor_c)
- {
- int Final_Motor_A,Final_Motor_B,Final_Motor_C;
- if(motor_a>0) INA=0; //电机A方向控制
- else INA=1;
- if(motor_b>0) INB=0; //电机B方向控制
- else INB=1;
- if(motor_c>0) INC=0; //电机C方向控制
- else INC=1;
-
- Final_Motor_A=Linear_Conversion(motor_a); //线性化
- Final_Motor_B=Linear_Conversion(motor_b);
- Final_Motor_C=Linear_Conversion(motor_c);
- Set_PWM_Final(Final_Motor_A,Final_Motor_B,Final_Motor_C);
- }
- /**************************************************************************
- 函数功能:对控制输出的PWM线性化,便于给系统寄存器赋值
- 入口参数:PWM
- 返回 值:线性化后的PWM
- **************************************************************************/
- u16 Linear_Conversion(int motor)
- {
- u32 temp;
- u16 Linear_Moto;
- temp=1000000/myabs(motor); //1000000是经验值
- if(temp>65535) Linear_Moto=65535;
- else Linear_Moto=(u16)temp;
- return Linear_Moto;
- }
-
- /**************************************************************************
- 函数功能:限制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(Motor_C<-amplitude) Motor_C=-amplitude;
- if(Motor_C>amplitude) Motor_C=amplitude;
- }
-
- /**************************************************************************
- 函数功能:按键修改小车运行状态
- 入口参数:无
- 返回 值:无
- **************************************************************************/
- void Key(void)
- {
- u8 tmp,tmp2;
- tmp=click_N_Double(75); //读取按键信息
- tmp2=Long_Press();
- if(tmp==1)Flag_Stop=!Flag_Stop;//单击开机/关闭电机
- if(tmp==2)Flag_Zero=!Flag_Zero;//双击读取零点
-
- if(tmp2==1)Flag_Show=!Flag_Show;//长按切换显示模式
- }
-
- /**************************************************************************
- 函数功能:异常关闭电机
- 入口参数:电压
- 返回 值:1:异常 0:正常
- **************************************************************************/
- u8 Turn_Off( int voltage)
- {
- u8 temp;
- if(Flag_Stop==1||Pitch<-60||Pitch>60||Roll<-60||Roll>60)// 角度过大或者Flag_Stop置1则关闭并失能电机
- {
- temp=1;
- INA=0;
- INB=0;
- INC=0;
- ST=0; //失能电机
- Flag_Stop=1;
- }
- else
- ST=1,
- 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;
- }
- /**************************************************************************
- 函数功能:速度滤波
- 入口参数:速度
- 返回 值:滤波后的速度
- **************************************************************************/
- int Mean_Filter_X(int motor)
- {
- u8 i;
- s32 Sum_Speed = 0;
- s16 Filter_Speed;
- static s16 Speed_Buf[FILTERING_TIMES]={0};
- for(i = 1 ; i<FILTERING_TIMES; i++)//平滑数据
- {
- Speed_Buf[i - 1] = Speed_Buf[i];
- }
- Speed_Buf[FILTERING_TIMES - 1] =motor;
-
- for(i = 0 ; i < FILTERING_TIMES; i++)
- {
- Sum_Speed += Speed_Buf[i];
- }
- Filter_Speed = (s16)(Sum_Speed / FILTERING_TIMES);//取平均
- return Filter_Speed;
- }
- /**************************************************************************
- 函数功能:速度滤波
- 入口参数:速度
- 返回 值:滤波后的速度
- **************************************************************************/
- int Mean_Filter_Y(int motor)
- {
- u8 i;
- s32 Sum_Speed = 0;
- s16 Filter_Speed;
- static s16 Speed_Buf[FILTERING_TIMES]={0};
- for(i = 1 ; i<FILTERING_TIMES; i++)
- {
- Speed_Buf[i - 1] = Speed_Buf[i];
- }
- Speed_Buf[FILTERING_TIMES - 1] =motor;
-
- for(i = 0 ; i < FILTERING_TIMES; i++)
- {
- Sum_Speed += Speed_Buf[i];
- }
- Filter_Speed = (s16)(Sum_Speed / FILTERING_TIMES);//取平均
- return Filter_Speed;
- }
关于球上自平衡机器人X,Y方向的速度和万向轮速度的转换,注意万向轮智能沿着切面转动
我还想找到角度的转换关系,就是俯仰角和翻滚角对应三个万向轮的这个怎么分配的。这个
我看了下平衡小车之家的源码,好像分配是跟速度一样的,X方向的角度PID的输出和速度PID的输出加在一起,Y一样,再通过上面的关系式分配给三个电机的控制量。
可以看他control.c的代码
可以看到分配在Kinematic_Analysis函数中进行,输入Move X,Move Y,得到Target A ,Target B,Target C,也就是三个电机对应的控制量。而MoveX就是X方向的倾角和X方向的速度这两个环输出的和。像balancd_Pitch这个函数你去看它定义就是计算pitch角度偏差的PID输出。其他的一样。这些函数都在control.c里面。
我们可以看看Kinematic_Analysis函数的定义,就在control.c里面,那里面的公式就是上面哪个毕业论文截图的公式!!!!
- #include "control.h"
- #include "filter.h"
- /**************************************************************************
- 作者:平衡小车之家
- 我的淘宝小店:http://shop114407458.taobao.com/
- **************************************************************************/
- u8 Flag_Target; //相关标志位
- float Voltage_Count,Voltage_All; //电压采样相关变量
- int Balance_Pwm_X,Velocity_Pwm_X,Balance_Pwm_Y,Velocity_Pwm_Y;
- #define X_PARAMETER (0.5f)
- #define Y_PARAMETER (sqrt(3)/2.f)
- #define L_PARAMETER (1.0f)
- /**************************************************************************
- 函数功能:小车运动 逆运动学分析
- 入口参数:X Y Z 三轴速度或者位置
- 返回 值:无
- **************************************************************************/
- void Kinematic_Analysis(float Vx,float Vy,float Vz)
- {
- Target_A = Vx + L_PARAMETER*Vz;
- Target_B = -X_PARAMETER*Vx + Y_PARAMETER*Vy + L_PARAMETER*Vz;
- Target_C = -X_PARAMETER*Vx - Y_PARAMETER*Vy + L_PARAMETER*Vz;
- }
- /**************************************************************************
- 函数功能:小车运动 正运动学分析 注:实际注释掉的是理想的运动学分析,实际使用放大了3倍,对计算结果没影响,主要是避免舍去误差
- 入口参数:A B C三个电机的速度
- 返回 值:无
- **************************************************************************/
- void Forward_Kinematics(float Va,float Vb,float Vc)
- {
- // Motor_X=(Va*2-Vb-Vc)/3;
- // Motor_Y=(Vb-Vc)/2/Y_PARAMETER;
- // Motor_Z=(Va+Vb+Vc)/3;
- Motor_X=Va*2-Vb-Vc;
- Motor_Y=(Vb-Vc)*sqrt(3);
- Motor_Z=Va+Vb+Vc;
- }
- /**************************************************************************
- 函数功能:所有的控制代码都在这里面
- 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读取一次陀螺仪和加速度计的值
- {
- Read_DMP(); //===更新姿态
- Key(); //扫描按键变化
- if(Pitch_Bias>-0.8&&Pitch_Bias<0.8&&Roll_Bias>-0.8&&Roll_Bias<0.8)Led_Flash(0); //接近平衡位置,常亮
- else Led_Flash(100); //===LED闪烁
- Voltage_All+=Get_battery_volt(); //多次采样累积
- if(++Voltage_Count==100) Voltage=Voltage_All/100,Voltage_All=0,Voltage_Count=0;//求平均值 获取电池电压
- return 0;
- } //===10ms控制一次
- Read_DMP(); //===更新姿态
- Roll_Bias =Roll-Roll_Zero; //获取Y方向的偏差
- Pitch_Bias=Pitch-Pitch_Zero; //获取X方向的偏差
- Forward_Kinematics(Motor_A,Motor_B,Motor_C); //正运动学分析,得到X Y Z 方向的速度
- Balance_Pwm_X=balance_Pitch(Pitch_Bias,gyro[1]); //X方向的倾角控制
- Balance_Pwm_Y=-balance_Roll(Roll_Bias, gyro[0]); //Y方向的倾角控制
- Velocity_Pwm_X=velocity_X(Motor_X); //X方向的速度控制
- Velocity_Pwm_Y=velocity_Y(Motor_Y); //Y方向的速度控制 //maxi:原来在这里
- Move_X =Balance_Pwm_X+Velocity_Pwm_X; //===X方向控制量累加
- Move_Y =Balance_Pwm_Y+Velocity_Pwm_Y; //===Y方向控制量累加
- Move_Z=0; //Z轴不做控制
- Kinematic_Analysis(Move_X,Move_Y,Move_Z);//逆运动学分析,得到A B C电机控制量
- Motor_A=Target_A;//直接调节PWM频率
- Motor_B=Target_B;//直接调节PWM频率
- Motor_C=Target_C;//直接调节PWM频率
- Xianfu_Pwm(1300);//===PWM频率限幅 因为频率太大之后扭矩减小不再满足小车需求
- if(Turn_Off(Voltage)==0) Set_Pwm(Motor_A,Motor_B,Motor_C); //赋值给PWM寄存器
- if(Flag_Zero) //这是人为更新零点值
- {
- Roll_Zero=Roll; //ROLL更新
- Pitch_Zero=Pitch; //Pitch更新
- Flag_Zero=0; //清零过程仅执行一次 等待下一次指令
- }
- }
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。