基于STM32F407VET6开发板通过Arduino进行13线霍尔编码器电机PID调速

步骤一:硬/软件准备

硬件部分:

1.STM32F407VET6开发板

2.13线霍尔编码器

3.AT8236电机驱动

4.VS code /  Platformio

5.星瞳串口波形显示器

步骤二:硬件线路连接及相关端口定义

 

 相关宏定义:

#include <Arduino.h>
//A电机端口定义
#define Motor_A_IN1   PE9  //输入1
#define Motor_A_IN2   PE11 //输入2
#define Motor_A_countA PA15 //编码器A 
#define Motor_A_countB PB3  //编码器B 
 
//B电机端口定义
#define Motor_B_IN1    PE13 //输入1
#define Motor_B_IN2    PE14 //输入2
#define Motor_B_countA PB4  //编码器A 
#define Motor_B_countB PB5  //编码器B 

//C电机端口定义
#define Motor_C_IN1    PE5  //输入1
#define Motor_C_IN2    PE6  //输入2
#define Motor_C_countA PA0  //编码器A 
#define Motor_C_countB PA1  //编码器B

//D电机端口定义
#define Motor_D_IN1    PB15 //输入1
#define Motor_D_IN2    PB14 //输入2
#define Motor_D_countA PD12 //编码器A 
#define Motor_D_countB PD13 //编码器B

步骤三:相关模块函数

1.电机两输入IN1/IN2及编码器AB相中断定时器使能函数

 //引脚初始化
void Motor_Init(){
  //A电机
  pinMode(Motor_A_IN2,OUTPUT);  //驱动芯片控制引脚
  pinMode(Motor_A_IN1,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(Motor_A_countA,INPUT); //编码器A引脚
  pinMode(Motor_A_countB,INPUT); //编码器B引脚
  
  //B电机
  pinMode(Motor_B_IN2,OUTPUT);  //驱动芯片控制引脚
  pinMode(Motor_B_IN1,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(Motor_B_countA,INPUT); //编码器A引脚
  pinMode(Motor_B_countB,INPUT); //编码器B引脚
 
 //C电机
  pinMode(Motor_C_IN2,OUTPUT);  //驱动芯片控制引脚
  pinMode(Motor_C_IN1,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(Motor_C_countA,INPUT); //编码器A引脚
  pinMode(Motor_C_countB,INPUT); //编码器B引脚
  
  //D电机
  pinMode(Motor_D_IN2,OUTPUT);  //驱动芯片控制引脚
  pinMode(Motor_D_IN1,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(Motor_D_countA,INPUT); //编码器A引脚
  pinMode(Motor_D_countB,INPUT); //编码器B引脚

  //驱动芯片控制引脚全部拉低
  digitalWrite(Motor_A_IN2,LOW); //A电机
  digitalWrite(Motor_A_IN1,LOW);
  digitalWrite(Motor_B_IN2,LOW); //B电机
  digitalWrite(Motor_B_IN1,LOW);
  digitalWrite(Motor_C_IN2,LOW); //C电机
  digitalWrite(Motor_C_IN1,LOW);
  digitalWrite(Motor_D_IN2,LOW); //D电机
  digitalWrite(Motor_D_IN1,LOW);
}

2.增量式PID控制函数(ABCD电机共用)

int Incremental_Pid_A(int current_speed,int target_speed){
  static float pwm,bias,last_bias,prev_bias;  //静态变量存在程序全周期:pwm:增量输出,bias:本次偏差,last_bias:上次偏差,prev_bais_:上上次偏差
  bias=current_speed-target_speed;    //计算本次偏差e(k)
  pwm-=(kp*(bias-last_bias)+ki*bias+kd*(bias-2*last_bias+prev_bias));   //增量式PID控制器
  prev_bias=last_bias;  //保存上上次偏差
  last_bias=bias;     //保存上一次偏差
  //PWM 限幅度  Arduino的PWM 最高为255  限制在250
  if(pwm<-250){
    pwm=250;     
  }
  if(pwm>250){
    pwm=250;  
  }
  //Serial.println(pwm);
  return pwm;         //增量输出
 }

3.中断电机脉冲读取函数

/***************************
 * 中断函数:读A轮脉冲
 *
 **************************/
void Read_Moto_A(){
  motorA++;
}
/**************************
 * 中断函数:读B轮脉冲
 * 
 *************************/
void Read_Moto_B(){
  motorB++;
}
/**************************
 * 中断函数:读C轮脉冲
 * 
 *************************/
void Read_Moto_C(){
  motorC++;
}
/**************************
 * 中断函数:读D轮脉冲
 * 
 *************************/
void Read_Moto_D(){
  motorD++;
}

 4.电机转速读取函数(cm/s)

/***********************************
 * 电机实际速度计算:
 * 已知参数:
 *     车轮直径100mm,
 *     AC轮子一圈:13*30=390脉冲(RISING)
 *     BD轮子一圈:13*30=390脉冲(RISING)
 * 单位时间读两个轮子脉冲读取两个轮子脉冲
 ***********************************/

 void Read_Moto_V(){
  unsigned long nowtime=0;
  motorA=0;
  motorB=0;
  motorC=0;
  motorD=O;
  nowtime=millis()+50;//读50毫秒
  attachInterrupt(digitalPinToInterrupt(Motor_A_countA),Read_Moto_A,RISING);//左轮脉冲开中断计数
  attachInterrupt(digitalPinToInterrupt(Motor_B_countA),Read_Moto_B,RISING);//右轮脉冲开中断计数
  attachInterrupt(digitalPinToInterrupt(Motor_C_countA),Read_Moto_C,RISING);//左轮脉冲开中断计数
  attachInterrupt(digitalPinToInterrupt(Motor_D_countA),Read_Moto_D,RISING);//左轮脉冲开中断计数
  while(millis()<nowtime); //达到50毫秒关闭中断
  detachInterrupt(digitalPinToInterrupt(Motor_A_countA));//左轮脉冲关中断计数
  detachInterrupt(digitalPinToInterrupt(Motor_B_countA));//右轮脉冲关中断计数
  detachInterrupt(digitalPinToInterrupt(Motor_C_countA));//左轮脉冲关中断计数
  detachInterrupt(digitalPinToInterrupt(Motor_D_countA));//左轮脉冲关中断计数
  V_A=((motorA/390)*10*PI)/0.05;   //单位cm/s
  V_B=((motorB/390)*10*PI)/0.05;   //单位cm/s
  V_C=((motorC/390)*10*PI)/0.05;   //单位cm/s
  V_D=((motorD/390)*10*PI)/0.05;   //单位cm/s
  v1=V_A;
  v2=V_B;
  v3=V_C;
  v4=V_D;
}

5.电机速度控制/模式选择函数函数

/**************************************************************************
  函数功能:设置电机工作模式和运动速度
  入口参数:工作模式,pwm
  返回  值:无
**************************************************************************/
void Set_Pwm(int mode,int speed_A,int speed_B,int speed_C,int speed_D){
 
  if(mode==1){
  //前进模式

  //A电机
  digitalWrite(Motor_A_IN2,LOW);
  analogWrite(Motor_A_IN1,speed_A);
  //B电机
  digitalWrite(Motor_B_IN2,LOW);
  analogWrite(Motor_B_IN1,speed_B);
  //C电机
  digitalWrite(Motor_C_IN2,LOW);
  analogWrite(Motor_C_IN1,speed_C);
  //D电机
  digitalWrite(Motor_D_IN2,LOW);
  analogWrite(Motor_D_IN1,speed_D);
  }else if(mode==2){
  //后退模式

  //A电机
  digitalWrite(Motor_A_IN2,speed_A);
  analogWrite(Motor_A_IN1,LOW);
  //B电机
  digitalWrite(Motor_B_IN2,speed_B);
  analogWrite(Motor_B_IN1,LOW);
  //C电机
  digitalWrite(Motor_A_IN2,speed_C);
  analogWrite(Motor_A_IN1,LOW);
  //D电机
  digitalWrite(Motor_B_IN2,speed_D);
  analogWrite(Motor_B_IN1,LOW);
  }else if(mode==3){
  //左旋转模式

  //A电机
  digitalWrite(Motor_A_IN2,speed_A);
  analogWrite(Motor_A_IN1,LOW);
  //B电机
  digitalWrite(Motor_B_IN2,LOW);
  analogWrite(Motor_B_IN1,speed_B);
  //C电机
  digitalWrite(Motor_C_IN2,speed_C);
  analogWrite(Motor_C_IN1,LOW);
  //D电机
  digitalWrite(Motor_D_IN2,LOW);
  analogWrite(Motor_D_IN1,speed_D);

  }else if(mode==4){
  //右旋转模式

  //A电机
  digitalWrite(Motor_A_IN2,LOW);
  analogWrite(Motor_A_IN1,speed_A);
  //B电机
  digitalWrite(Motor_B_IN2,speed_B);
  analogWrite(Motor_B_IN1,LOW);
  //C电机
  digitalWrite(Motor_C_IN2,LOW);
  analogWrite(Motor_C_IN1,speed_C);
  //D电机
  digitalWrite(Motor_D_IN2,speed_D);
  analogWrite(Motor_D_IN1,LOW);
  }else if(mode==5){
  //左平移模式

  //A电机
  digitalWrite(Motor_A_IN2,LOW);
  analogWrite(Motor_A_IN1,speed_A);
  //B电机
  digitalWrite(Motor_B_IN2,speed_B);
  analogWrite(Motor_B_IN1,LOW);
  //C电机
  digitalWrite(Motor_C_IN2,speed_C);
  analogWrite(Motor_C_IN1,LOW);
  //D电机
  digitalWrite(Motor_D_IN2,speed_D);
  analogWrite(Motor_D_IN1,LOW);
 }else if(mode==6){
  //右平移模式

  //A电机
  digitalWrite(Motor_A_IN2,speed_A);
  analogWrite(Motor_A_IN1,LOW);
  //B电机
  digitalWrite(Motor_B_IN2,LOW);
  analogWrite(Motor_B_IN1,speed_B);
  //C电机
  digitalWrite(Motor_C_IN2,LOW);
  analogWrite(Motor_C_IN1,speed_C);
  //D电机
  digitalWrite(Motor_D_IN2,speed_D);
  analogWrite(Motor_D_IN1,LOW);
 }
}

5.PID串口调参函数

//PID串口调试函数  
//格式:参数(kp/ki/kp) 数值   
//示例:ki 2.1
void PID_test(){
 while (Serial.available() > 0) {   // 串口收到字符数大于零。
    if(Serial.find("kp")) 
    {
      kp = Serial.parseFloat();
    }  
      
    if(Serial.find("ki")) 
    {
      ki = Serial.parseFloat();
    }  

    if(Serial.find("kd")) 
    {
      kd = Serial.parseFloat();
    }  
    }
}

步骤四:整合相关模块函数

#include <Arduino.h>
//A电机端口定义
#define Motor_A_IN1    PE9  //输入1
#define Motor_A_IN2    PE11 //输入2
#define Motor_A_countA PA15 //编码器A 
#define Motor_A_countB PB3  //编码器B 
 
//B电机端口定义
#define Motor_B_IN1    PE13 //输入1
#define Motor_B_IN2    PE14 //输入2
#define Motor_B_countA PB4  //编码器A 
#define Motor_B_countB PB5  //编码器B 

//C电机端口定义
#define Motor_C_IN1    PE5  //输入1
#define Motor_C_IN2    PE6  //输入2
#define Motor_C_countA PA0  //编码器A 
#define Motor_C_countB PA1  //编码器B

//D电机端口定义
#define Motor_D_IN1    PB14 //输入1
#define Motor_D_IN2    PB15 //输入2
#define Motor_D_countA PD12 //编码器A 
#define Motor_D_countB PD13 //编码器B

//定义相关变量
volatile float motorA=0;//中断变量,A轮子脉冲计数
volatile float motorB=0;//中断变量,B轮子脉冲计数
volatile float motorC=0;//中断变量,C轮子脉冲计数
volatile float motorD=0;//中断变量,D轮子脉冲计数
float V_A=0; //A轮速度 单位cm/s
float V_B=0; //B边轮速 单位cm/s
float V_C=0; //C轮速度 单位cm/s
float V_D=0; //D轮速度 单位cm/s
int v1=0;  //单位cm/s
int v2=0;  //单位cm/s
int v3=0;
int v4=0;
float Target_V_A=40,Target_V_B=40,Target_V_C=40,Target_V_D=40;  //单位cm/s  经过测试最大速度为 :150 cm/s
int Pwm_A=0,Pwm_B=0,Pwm_C=0,Pwm_D=0 ; //左右轮PWM
 
//PID变量(根据个人情况调试)

 float kp=1,ki=0.15,kd=0;  //PID参数
//函数声明
void Motor_Init();//电机初始化
void Read_Moto_V();//读取电机速度 单位:cm/s
void Read_Moto_A(); //读取编码器脉冲
void Read_Moto_B();
void Read_Moto_C();
void Read_Moto_D();
void Set_Pwm(int mode,int speed_A,int speed_B,int speed_C,int speed_D);//pwm设置
int Incremental_Pid_A(int current_speed,int target_speed);//pid函数
int Incremental_Pid_B(float current_speed,float target_speed);
int Incremental_Pid_C(float current_speed,float target_speed);
int Incremental_Pid_D(float current_speed,float target_speed);
void PID_test();//离线kp ki kd 调试
/**************************************
 * //Arduino初始化函数
 *************************************/
void setup() {
   Motor_Init();//电机端口初始化
   Serial.begin(9600);//开启串口
}
/***************************************
 * Arduino主循环
 * 
 ***************************************/
void loop() {
  Read_Moto_V();//读取脉冲计算速度
  Pwm_A=Incremental_Pid_A(V_A,Target_V_A);//A轮PI运算
  Pwm_B=Incremental_Pid_B(V_B,Target_V_B);//B轮PI运算
  Pwm_C=Incremental_Pid_C(V_C,Target_V_C);//C轮PI运算
  Pwm_D=Incremental_Pid_D(V_D,Target_V_D);//D轮PI运算
  Serial.print("V_A: ");
  Serial.print(V_A);
  Serial.print("cm/s, V_B: ");
  Serial.print(V_B);
  Serial.print("cm/s, V_C: ");
  Serial.print(V_C);
  Serial.print("cm/s, V_D: ");
  Serial.print(V_D);
  Serial.println("cm/s");
  Set_Pwm(1,Pwm_A,Pwm_B,Pwm_C,Pwm_D); //设置速度 
  // PID_test();//调试参数

}
 
/*********************************************************
 * 函数功能:增量式PI控制器(A电机)
 * 入口参数:当前速度(编码器测量值),目标速度
 * 返回 值:电机PWM 
 * 参考资料: 
 *    增量式离散PID公式:
 *                Pwm-=Kp*[e(k)-e(k-1)]+Ki*e(k)+Kd*[e(k)-2e(k-1)+e(k-2)]
 *                e(k):本次偏差
 *                e(k-1):上一次偏差
 *                e(k-2):上上次偏差
 *                Pwm:代表增量输出
 *    在速度闭环控制系统里面我们只使用PI控制,因此对PID公式可简化为:
 *                Pwm-=Kp*[e(k)-e(k-1)]+Ki*e(k)
 *                e(k):本次偏差
 *                e(k-1):上一次偏差
 *                Pwm:代表增量输出
 *                
 *    注意增量式PID先调I,再调P,最后再调D
 *********************************************************/
 int Incremental_Pid_A(int current_speed,int target_speed){
  static float pwm,bias,last_bias,prev_bias;  //静态变量存在程序全周期:pwm:增量输出,bias:本次偏差,last_bias:上次偏差,prev_bais_:上上次偏差
  bias=current_speed-target_speed;    //计算本次偏差e(k)
  pwm-=(kp*(bias-last_bias)+ki*bias+kd*(bias-2*last_bias+prev_bias));   //增量式PID控制器
  prev_bias=last_bias;  //保存上上次偏差
  last_bias=bias;     //保存上一次偏差
  //PWM 限幅度  Arduino的PWM 最高为255  限制在250
  if(pwm<-250){
    pwm=250;     
  }
  if(pwm>250){
    pwm=250;  
  }
  //Serial.println(pwm);
  return pwm;         //增量输出
 }
 
//B电机速度增量式PID控制器
int Incremental_Pid_B(float current_speed,float target_speed){
  static float pwm,bias,last_bias,prev_bias;  //静态变量存在程序全周期:pwm:增量输出,bias:本次偏差,last_bias:上次偏差,prev_bais_:上上次偏差
  bias=current_speed-target_speed;    //计算本次偏差e(k)
  pwm-=(kp*(bias-last_bias)+ki*bias+kd*(bias-2*last_bias+prev_bias));   //增量式PID控制器
  prev_bias=last_bias;  //保存上上次偏差
  last_bias=bias;     //保存上一次偏差
  //PWM 限幅度  Arduino的PWM 最高为255限制在250
  if(pwm<-250){
    pwm=250;     
  }
  if(pwm>250){
    pwm=250;  
  }
  //Serial.println(pwm);
  return pwm;         //增量输出
 }
//C电机速度增量式PID控制器
int Incremental_Pid_C(float current_speed,float target_speed){
  static float pwm,bias,last_bias,prev_bias;  //静态变量存在程序全周期:pwm:增量输出,bias:本次偏差,last_bias:上次偏差,prev_bais_:上上次偏差
  bias=current_speed-target_speed;    //计算本次偏差e(k)
  pwm-=(kp*(bias-last_bias)+ki*bias+kd*(bias-2*last_bias+prev_bias));   //增量式PID控制器
  prev_bias=last_bias;  //保存上上次偏差
  last_bias=bias;     //保存上一次偏差
  //PWM 限幅度  Arduino的PWM 最高为255限制在250
  if(pwm<-250){
    pwm=250;     
  }
  if(pwm>250){
    pwm=250;  
  }
  //Serial.println(pwm);
  return pwm;         //增量输出
 }
//D电机速度增量式PID控制器
int Incremental_Pid_D(float current_speed,float target_speed){
  static float pwm,bias,last_bias,prev_bias;  //静态变量存在程序全周期:pwm:增量输出,bias:本次偏差,last_bias:上次偏差,prev_bais_:上上次偏差
  bias=current_speed-target_speed;    //计算本次偏差e(k)
  pwm-=(kp*(bias-last_bias)+ki*bias+kd*(bias-2*last_bias+prev_bias));   //增量式PID控制器
  prev_bias=last_bias;  //保存上上次偏差
  last_bias=bias;     //保存上一次偏差
  //PWM 限幅度  Arduino的PWM 最高为255限制在250
  if(pwm<-250){
    pwm=250;     
  }
  if(pwm>250){
    pwm=250;  
  }
  //Serial.println(pwm);
  return pwm;         //增量输出
 }

/**************************************************************************
  函数功能:设置电机工作模式和运动速度
  入口参数:工作模式,pwm
  返回  值:无
**************************************************************************/
void Set_Pwm(int mode,int speed_A,int speed_B,int speed_C,int speed_D){
 
  if(mode==1){
  //前进模式

  //A电机
  digitalWrite(Motor_A_IN2,LOW);
  analogWrite(Motor_A_IN1,speed_A);
  //B电机
  digitalWrite(Motor_B_IN2,LOW);
  analogWrite(Motor_B_IN1,speed_B);
  //C电机
  digitalWrite(Motor_C_IN2,LOW);
  analogWrite(Motor_C_IN1,speed_C);
  //D电机
  digitalWrite(Motor_D_IN2,LOW);
  analogWrite(Motor_D_IN1,speed_D);
  }else if(mode==2){
  //后退模式

  //A电机
  digitalWrite(Motor_A_IN2,speed_A);
  analogWrite(Motor_A_IN1,LOW);
  //B电机
  digitalWrite(Motor_B_IN2,speed_B);
  analogWrite(Motor_B_IN1,LOW);
  //C电机
  digitalWrite(Motor_A_IN2,speed_C);
  analogWrite(Motor_A_IN1,LOW);
  //D电机
  digitalWrite(Motor_B_IN2,speed_D);
  analogWrite(Motor_B_IN1,LOW);
  }else if(mode==3){
  //左旋转模式

  //A电机
  digitalWrite(Motor_A_IN2,speed_A);
  analogWrite(Motor_A_IN1,LOW);
  //B电机
  digitalWrite(Motor_B_IN2,LOW);
  analogWrite(Motor_B_IN1,speed_B);
  //C电机
  digitalWrite(Motor_C_IN2,speed_C);
  analogWrite(Motor_C_IN1,LOW);
  //D电机
  digitalWrite(Motor_D_IN2,LOW);
  analogWrite(Motor_D_IN1,speed_D);

  }else if(mode==4){
  //右旋转模式

  //A电机
  digitalWrite(Motor_A_IN2,LOW);
  analogWrite(Motor_A_IN1,speed_A);
  //B电机
  digitalWrite(Motor_B_IN2,speed_B);
  analogWrite(Motor_B_IN1,LOW);
  //C电机
  digitalWrite(Motor_C_IN2,LOW);
  analogWrite(Motor_C_IN1,speed_C);
  //D电机
  digitalWrite(Motor_D_IN2,speed_D);
  analogWrite(Motor_D_IN1,LOW);
  }else if(mode==5){
  //左平移模式

  //A电机
  digitalWrite(Motor_A_IN2,LOW);
  analogWrite(Motor_A_IN1,speed_A);
  //B电机
  digitalWrite(Motor_B_IN2,speed_B);
  analogWrite(Motor_B_IN1,LOW);
  //C电机
  digitalWrite(Motor_C_IN2,speed_C);
  analogWrite(Motor_C_IN1,LOW);
  //D电机
  digitalWrite(Motor_D_IN2,speed_D);
  analogWrite(Motor_D_IN1,LOW);
 }else if(mode==6){
  //右平移模式

  //A电机
  digitalWrite(Motor_A_IN2,speed_A);
  analogWrite(Motor_A_IN1,LOW);
  //B电机
  digitalWrite(Motor_B_IN2,LOW);
  analogWrite(Motor_B_IN1,speed_B);
  //C电机
  digitalWrite(Motor_C_IN2,LOW);
  analogWrite(Motor_C_IN1,speed_C);
  //D电机
  digitalWrite(Motor_D_IN2,speed_D);
  analogWrite(Motor_D_IN1,LOW);
 }
}
 //引脚初始化
void Motor_Init(){
  //A电机
  pinMode(Motor_A_IN2,OUTPUT);  //驱动芯片控制引脚
  pinMode(Motor_A_IN1,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(Motor_A_countA,INPUT); //编码器A引脚
  pinMode(Motor_A_countB,INPUT); //编码器B引脚
  
  //B电机
  pinMode(Motor_B_IN2,OUTPUT);  //驱动芯片控制引脚
  pinMode(Motor_B_IN1,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(Motor_B_countA,INPUT); //编码器A引脚
  pinMode(Motor_B_countB,INPUT); //编码器B引脚
 
 //C电机
  pinMode(Motor_C_IN2,OUTPUT);  //驱动芯片控制引脚
  pinMode(Motor_C_IN1,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(Motor_C_countA,INPUT); //编码器A引脚
  pinMode(Motor_C_countB,INPUT); //编码器B引脚
  
  //D电机
  pinMode(Motor_D_IN2,OUTPUT);  //驱动芯片控制引脚
  pinMode(Motor_D_IN1,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(Motor_D_countA,INPUT); //编码器A引脚
  pinMode(Motor_D_countB,INPUT); //编码器B引脚

  //驱动芯片控制引脚全部拉低
  digitalWrite(Motor_A_IN2,LOW); //A电机
  digitalWrite(Motor_A_IN1,LOW);
  digitalWrite(Motor_B_IN2,LOW); //B电机
  digitalWrite(Motor_B_IN1,LOW);
  digitalWrite(Motor_C_IN2,LOW); //C电机
  digitalWrite(Motor_C_IN1,LOW);
  digitalWrite(Motor_D_IN2,LOW); //D电机
  digitalWrite(Motor_D_IN1,LOW);
}
/***********************************
 * 电机实际速度计算:
 * 已知参数:
 *     车轮直径100mm,
 *     左边轮子一圈:13*30=390脉冲(RISING)
 *     右边轮子一圈:13*30=390脉冲(RISING)
 * 单位时间读两个轮子脉冲读取两个轮子脉冲
 ***********************************/

 void Read_Moto_V(){
  unsigned long nowtime=0;
  motorA=0;
  motorB=0;
  motorC=0;
  motorD=0;
  nowtime=millis()+50;//读50毫秒
  attachInterrupt(digitalPinToInterrupt(Motor_A_countA),Read_Moto_A,RISING);//A轮脉冲开中断计数
  attachInterrupt(digitalPinToInterrupt(Motor_B_countA),Read_Moto_B,RISING);//B轮脉冲开中断计数
  attachInterrupt(digitalPinToInterrupt(Motor_C_countA),Read_Moto_C,RISING);//C轮脉冲开中断计数
  attachInterrupt(digitalPinToInterrupt(Motor_D_countA),Read_Moto_D,RISING);//D轮脉冲开中断计数
  while(millis()<nowtime); //达到50毫秒关闭中断
  detachInterrupt(digitalPinToInterrupt(Motor_A_countA));//A轮脉冲关中断计数
  detachInterrupt(digitalPinToInterrupt(Motor_B_countA));//B轮脉冲关中断计数
  detachInterrupt(digitalPinToInterrupt(Motor_C_countA));//C轮脉冲关中断计数
  detachInterrupt(digitalPinToInterrupt(Motor_D_countA));//D轮脉冲关中断计数
  V_A=((motorA/390)*10*PI)/0.05;   //单位cm/s
  V_B=((motorB/390)*10*PI)/0.05;   //单位cm/s
  V_C=((motorC/390)*10*PI)/0.05;   //单位cm/s
  V_D=((motorD/390)*10*PI)/0.05;   //单位cm/s
  v1=V_A;
  v2=V_B;
  v3=V_C;
  v4=V_D;
}
/***************************
 * 中断函数:读A轮脉冲
 *
 **************************/
void Read_Moto_A(){
  motorA++;
}
/**************************
 * 中断函数:读B轮脉冲
 * 
 *************************/
void Read_Moto_B(){
  motorB++;
}
/**************************
 * 中断函数:读B轮脉冲
 * 
 *************************/
void Read_Moto_C(){
  motorC++;
}
/**************************
 * 中断函数:读B轮脉冲
 * 
 *************************/
void Read_Moto_D(){
  motorD++;
}


//PID串口调试函数  
//格式:参数(kp/ki/kp) 数值   
//示例:ki 2.1
void PID_test(){
 while (Serial.available() > 0) {   // 串口收到字符数大于零。
    if(Serial.find("kp")) 
    {
      kp = Serial.parseFloat();
    }  
      
    if(Serial.find("ki")) 
    {
      ki = Serial.parseFloat();
    }  

    if(Serial.find("kd")) 
    {
      kd = Serial.parseFloat();
    }  
    }
}

步骤五:具体PID调参过程(雾)

本人pid调参过程极其痛苦,很久才发现方向错误,所以本人不想经历第二次调参过程,所以没有相应过程图片,可以参考一下最后调参完成的波形:

不过下面给大家一些过来人的建议:

对于增量式pid调参,尤其是对于13线霍尔编码器,首先调ki,尽量选择10附近的值采用二分法测量,测量过程对于变化较大的波形应及时舍去,当波形满足略微振荡,在调整时间t_s内调整次数在3-5次可以确保调整时间t_s较小,而最大超调量M_p也较小。接着调节kp,这个主要影响其稳定性,可以从10左右的ki开始下调,直至M_p基本等于零,这样就基本完成pi调试,最后kd我的结果为0,查阅相关资料后,发现大部分情况低精度速度增量编码器很难会用到kd,所以大家参考我这种应用场景就可以忽略。

最后祝大家早日找到属于你的kp和ki!(完结撒花)

步骤六:特别鸣谢up

 cbirdfly.

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: STM32F407VET6开发板是一款基于STM32F407VET6芯片的嵌入式开发板。其原理图是一份详细的电路图,包括了所有的电子元器件,连接线路和电路板的布局设计等。由于其功能强大,因此原理图较为复杂,一般分为多个部分来设计。其中,包含了芯片的电源管理电路、时钟电路、复位电路、GPIO等基本电路;还包含了UART、SPI、I2C、CAN等多种通信接口电路;同时也包含了SD卡、WIFI模块、OLED屏幕等常用外设的接口电路。这些电路通过相应的连接方式,能够实现芯片与各种外部设备的连接和通讯,从而使得整个开发板性能更加完备和强大。在开发过程中,通过学习原理图,能够了解开发板的各种功能和实现方式,有效地提高开发效率和调试能力。同时,对于一些修改和扩展开发板功能的需求,也可通过修改原理图来实现。因此,STM32F407VET6开发板的原理图是开发过程中非常重要的参考文档,值得深入研究和学习。 ### 回答2: stm32f407vet6开发板原理图是一张反映该开发板电路连接结构和元器件布局的电路图。该原理图包括大量的电子元件、脚位、功率线、信号线等,在全面展示了STM32F407VET6芯片的所有器件和信号的同时,使用户能够通过对电路图的分析和理解,更加深入地了解STM32F407VET6开发板的性能和功能。 该原理图主要包括以下几个模块:电源部分、时钟部分、调试模块、存储器模块、外设模块、输入输出模块等。其中电源部分提供供电,时钟部分提供时钟信号,存储器模块包括FLASH和SRAM,外设模块则包括USART,SPI,I2C,ADC等常用外设。 在原理图中,不同元器件之间的连接通路采用的是各种不同的电子标记和符号进行标注和表示,像晶体管、电容、电阻、脉冲翻转器等器件都有特定的符号表示。这些标记和符号方便我们理解STM32F407VET6开发板的电路连接及元器件作用,而且也有助于用户进行后续维护和更改。 综上所述,stm32f407vet6开发板原理图是STM32F407VET6开发板的抽象图像,用户可通过该原理图全面掌握开发板的性能和构造,从而更好地进行开发设计。 ### 回答3: stm32f407vet6开发板原理图是指基于ST公司的stm32f407vet6芯片设计的一张电路原理图,该原理图主要展示了stm32f407vet6芯片与各种外部器件之间的连接电路关系,为开发人员提供了硬件设计的参考。 在这张原理图中,我们可以看到STM32F407芯片的引脚连接了足够多的外部器件,比如数码管、LED等,这些外部器件可通过STM32F407芯片提供的外设接口进行控制。此外,我们还可以看到开发板上配备了丰富的外设模块,如CAN总线接口、USB接口、以太网接口、SD卡座等,大大方便了用户进行各类应用的开发。 此外,STM32F407芯片是一款高性能的微控制器,支持ARM Cortex-M4核,拥有高达168MHz的主频,内置1MB的Flash和192KB的SRAM,以及多个实用的硬件模块和外设接口,包括定时器、ADC、DMA、I2C、SPI、UART等。这些强大的硬件资源驱动开发板的工作,使其具有良好的扩展性和通用性。 总之,STM32F407VET6开发板原理图是STM32F407芯片和每个外部器件之间的电路连接关系的展示,它是STM32F407VET6开发板硬件设计的基础。开发人员可以根据这张原理图来调试和修改开发板的硬件电路,在不同应用场景下改造出更为完善和高效的应用系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值