[技术问答] 无刷云台代码分析

[复制链接]
1127|1
 楼主| ofsummer 发表于 2016-3-28 21:00 | 显示全部楼层 |阅读模式
1、_044.ino为主程序
void loop() 为主程序大循环
主要功能读取MPU6050平计算出相应数据
2、定时中断驱动电机转动
//用这个程序改多轴飞控一定很稳定。可以用它作为一个模块把算出的数据发给KK_C再进行控制。
  1. /********************************/
  2. /* Motor Control Routines       */
  3. /********************************/
  4. ISR( TIMER1_OVF_vect )
  5. {//定时中断吗?在这里输出电机控制信号吗?
  6.   freqCounter++;
  7.   if(freqCounter==(CC_FACTOR/MOTORUPDATE_FREQ))
  8.   {//中断CC_FACTOR/MOTORUPDATE_FREQ次执行以下程序 即输出频率

  9.     // Move pitch and roll Motor
  10.     deviderCountPitch++;//这里用计数的方式有什么作用喃?pitchDevider越大时延时会越长,好像不太好。直接执行不好吗?
  11.     //if(abs(pitchDevider)>=1)  //胥拟改进 大于或等于1说明有数据才进行调整,免得电机不断输出发热和抖动
  12.     if(deviderCountPitch  >= abs(pitchDevider))  //abs(pitchDevider)=计算参数的绝对值,即不算符号,只管数值
  13.        //分析如果pitchDevider=0时,每次都会执行它,用问题吗?=0时会不断输出到电机,有点问题哦!
  14.     {//Roll电机
  15.       fastMoveMotor(config.motorNumberRoll, rollDirection,pwmSinMotorRoll);
  16.       deviderCountRoll=0;
  17.     }
  18.     freqCounter=0;
  19.   }
  20. }
  21. //=======================================
  22. fastMoveMotor电机驱动子程序

  23. // Hardware Abstraction for Motor connectors,
  24. // DO NOT CHANGE UNLES YOU KNOW WHAT YOU ARE DOING !!!
  25. #define PWM_A_MOTOR1 OCR2A
  26. #define PWM_B_MOTOR1 OCR1B
  27. #define PWM_C_MOTOR1 OCR1A

  28. #define PWM_A_MOTOR0 OCR0A
  29. #define PWM_B_MOTOR0 OCR0B
  30. #define PWM_C_MOTOR0 OCR2B
  31. //以上是引脚定义吗?
  32. void fastMoveMotor(uint8_t motorNumber, int dirStep,uint8_t* pwmSin)
  33. {//fastMoveMotor(uint8_t motorNumber(电机选择?X轴/Y轴), int dirStep(正转1、反转-1或不转0),uint8_t* pwmSin(数据表首地址256字节))
  34.   if (motorNumber == 0)
  35.   {//改这里就可以改成步进电机的了。:)
  36.     //用单片机写个步进电机驱动,再用两个端口进行控制。一个端口控制方向,一个端口控制步数
  37.     currentStepMotor0 += dirStep;//currentStepMotor0 为原来的位置 dirStep=(-1,0,1)
  38.     PWM_A_MOTOR0 = pwmSin[currentStepMotor0];//查表输出A
  39.     PWM_B_MOTOR0 = pwmSin[(uint8_t)(currentStepMotor0 + 85)];//查表输出B
  40.     PWM_C_MOTOR0 = pwmSin[(uint8_t)(currentStepMotor0 + 170)];//查表输出C 总步数85*3=255为一圈
  41.   }

  42.   if (motorNumber == 1)
  43.   {
  44.     currentStepMotor1 += dirStep;
  45.     PWM_A_MOTOR1 = pwmSin[currentStepMotor1] ;
  46.     PWM_B_MOTOR1 = pwmSin[(uint8_t)(currentStepMotor1 + 85)] ;
  47.     PWM_C_MOTOR1 = pwmSin[(uint8_t)(currentStepMotor1 + 170)] ;
  48.   }
  49. }

  50. //==================================================
  51.   pitchDevider = constrain(maxDegPerSecondPitch / (pitchPID + 0.000001), -15000,15000)*2;
  52.   pitchDirection = sgn(pitchDevider) * config.dirMotorPitch;//计算电机输出数据-1,0,1 只转一点点
  53.   rollDevider = constrain(maxDegPerSecondRoll / (rollPID + 0.000001), -15000,15000)*2;
  54.   rollDirection = sgn(rollDevider) * config.dirMotorRoll;//计算电机输出数据-1,0,1


  55. int8_t sgn(int val) {
  56.   if (val < 0) return -1;
  57.   if (val==0) return 0;
  58.   return 1;
  59. }


 楼主| ofsummer 发表于 2016-3-28 21:01 | 显示全部楼层
//以下是主程序分析
//功能分析:除了通过陀螺仪和加速度仪数据运算调整两个电机移动以外还加入了外部控制的调整量
//主程序内只算出移动数据,在中断中才不断的进行输出动作
  1. /**********************************************/
  2. /* Main Loop                                  */
  3. /**********************************************/
  4. int count=0;
  5. void loop()
  6. {


  7.   sampleTimePID = (micros()-timer)/1000000.0/CC_FACTOR; // in Seconds!  检测时间控制设置   通过CC_FACTOR调节因子调节大小?
  8.    //得到上次运行到本次运行的时间长短,用于PID算法
  9.   timer = micros();//存本次时间,用于和下次时间的比较。
  10.   //定时器会溢出吗?要进行相应处理吗?大约50天溢出一次,要进行确认!
  11.   
  12.   // Update raw Gyro //更新陀螺仪数据
  13.   updateRawGyroData(&gyroRoll,&gyroPitch);//读取陀螺仪数据
  14.    
  15.   // Update DMP data approximately at 50Hz to save calculation time.


  16.   if(config.useACC==1)//根据变量控制程序流程
  17.   {//流程1 执行频率不同
  18.    //周期长
  19.     count++;
  20.     // Update ACC data approximately at 50Hz to save calculation time.
  21.     if(count == 20)
  22.     {
  23.       sampleTimeACC = (micros()-timerACC)/1000.0/CC_FACTOR; // in Seconds * 1000.0 to account for factor 1000 in parameters
  24.       timerACC=timer;//计算时间差值
  25.       //{Serial.print(sampleTimeACC,5);Serial.print(" ");Serial.println(sampleTimePID,5);}
  26.       mpu.getAcceleration(&x_val,&y_val,&z_val);//读三轴加速度值中吗?
  27.     }
  28.     if(count == 21)
  29.     //roll角度控制计算
  30.     rollAngleACC = 0.9 * rollAngleACC + 0.1 * ultraFastAtan2(-y_val,-z_val); //rollAngleACC = 0.8 * rollAngleACC + atan2(-y_val,-z_val)*57.2957795 * 0.2;
  31.     if(count == 22)
  32.     {//pitch角度控制计算
  33.       pitchAngleACC = 0.9 * pitchAngleACC + 0.1 * -ultraFastAtan2(-x_val,-z_val);//角度计算吗?
  34.       count=0;
  35.       if(config.accOutput==1){Serial.print(pitchAngleACC);Serial.print(" ACC ");Serial.println(rollAngleACC);}
  36. //      {Serial.print(gyroPitch);Serial.print(" ACC G ");Serial.println(gyroRoll);}
  37.     }
  38.   }
  39.   else // Use DMP
  40.   {//流程2
  41.    //周期短
  42.    //不进行加速度计算吗?
  43.     if(count == 2)
  44.     {//pitch角度控制计算
  45.       pitchAngleACC = -asin(-2.0*(q.x * q.z - q.w * q.y)) * 180.0/M_PI;//角度计算吗?
  46.       count=0;
  47.       if(config.dmpOutput==1){Serial.print(pitchAngleACC);Serial.print(" DMP ");Serial.println(rollAngleACC);}
  48. //      {Serial.print(gyroPitch);Serial.print(" DMP G ");Serial.println(gyroRoll);}
  49.     }
  50.     if(count == 1)
  51.     {//roll角度控制计算
  52.       rollAngleACC = ultraFastAtan2(2.0*(q.y * q.z + q.w * q.x), q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z);
  53.       rollAngleACC = -1*(sgn(rollAngleACC) * 180.0 - rollAngleACC);//角度计算吗?
  54.       count++;
  55.     }
  56.     if(mpuInterrupt) 判断MPU 中断标志吗?
  57.     { //两个不同地方的sampleTimeACC有冲突吗?
  58.       sampleTimeACC = (micros()-timerACC)/1000.0/CC_FACTOR; // in Seconds * 1000.0 to account for factor 1000 in parameters
  59.       timerACC=timer;//计算时间差值通过CC_FACTOR调节因子调节大小?
  60.      //有中断产生时读取MPU6050的相应数据吗?
  61.       mpu.getFIFOBytes(fifoBuffer, 18); // I2C 800000L : 1300-1308 micros fo 42 bytes, ~540 micros for 16bytes
  62.       mpu.dmpGetQuaternion(&q, fifoBuffer); // I2C 800000L : 64-68 micros
  63.       mpuInterrupt = false;
  64.       count++;
  65.     }
  66.   }

  67. //      {Serial.print(pitchAngleACC);Serial.print(" ");Serial.println(rollAngleACC);}   // 调试时往串口发数据 AngleACC角度控制数据

  68.    
  69.   if(config.rcAbsolute==1) // Absolute RC control 绝对控制
  70.   {//方式1?
  71.     // Get Setpoint from RC-Channel if available.
  72.     // LPF on pitchSetpoint
  73.     if(updateRCPitch==true)//手动修正判断吗?
  74.     {
  75.       pulseInPWMPitch = constrain(pulseInPWMPitch,MIN_RC,MAX_RC);
  76.       pitchSetpoint = 0.025 * (config.minRCPitch + (float)(pulseInPWMPitch - MIN_RC)/(float)(MAX_RC - MIN_RC) * (config.maxRCPitch - config.minRCPitch)) + 0.975 * pitchSetpoint;
  77.       updateRCPitch=false;
  78.     }
  79.     if(updateRCRoll==true)//手动修正判断吗?
  80.     {
  81.       pulseInPWMRoll = constrain(pulseInPWMRoll,MIN_RC,MAX_RC);
  82.       rollSetpoint = 0.025 * (config.minRCRoll + (float)(pulseInPWMRoll - MIN_RC)/(float)(MAX_RC - MIN_RC) * (config.maxRCRoll - config.minRCRoll)) + 0.975 * rollSetpoint;
  83.       updateRCRoll=false;
  84.     }
  85.   }
  86.   else // Proportional RC control
  87.   {//方式2?
  88.     if(updateRCPitch==true)//手动修正判断吗?
  89.     {
  90.       pulseInPWMPitch = constrain(pulseInPWMPitch,MIN_RC,MAX_RC);
  91.       if(pulseInPWMPitch>=MID_RC+RC_DEADBAND)
  92.       {
  93.         pitchRCSpeed = 0.1 * (float)(pulseInPWMPitch - (MID_RC + RC_DEADBAND))/ (float)(MAX_RC - (MID_RC + RC_DEADBAND)) + 0.9 * pitchRCSpeed;
  94.       }
  95.       else if(pulseInPWMPitch<=MID_RC-RC_DEADBAND)
  96.       {
  97.         pitchRCSpeed = -0.1 * (float)((MID_RC - RC_DEADBAND) - pulseInPWMPitch)/ (float)((MID_RC - RC_DEADBAND)-MIN_RC) + 0.9 * pitchRCSpeed;
  98.       }
  99.       else pitchRCSpeed = 0.0;
  100.       updateRCPitch=false;
  101.     }
  102.     if(updateRCRoll==true)//手动修正判断吗?
  103.     {
  104.       pulseInPWMRoll = constrain(pulseInPWMRoll,MIN_RC,MAX_RC);
  105.       if(pulseInPWMRoll>=MID_RC+RC_DEADBAND)
  106.       {
  107.         rollRCSpeed = 0.1 * (float)(pulseInPWMRoll - (MID_RC + RC_DEADBAND))/ (float)(MAX_RC - (MID_RC + RC_DEADBAND)) + 0.9 * rollRCSpeed;
  108.       }
  109.       else if(pulseInPWMRoll<=MID_RC-RC_DEADBAND)
  110.       {
  111.         rollRCSpeed = -0.1 * (float)((MID_RC - RC_DEADBAND) - pulseInPWMRoll)/ (float)((MID_RC - RC_DEADBAND)-MIN_RC) + 0.9 * rollRCSpeed;
  112.       }
  113.       else rollRCSpeed = 0.0;
  114.       updateRCRoll=false;
  115.     }
  116.   }

  117. //480-900
  118. //计算陀螺仪数据
  119.   if((fabs(rollRCSpeed)>0.0)&& (rollAngleACC<config.maxRCRoll)&& (rollAngleACC>config.minRCRoll))//判断rollAngleACC是否在最大值和最小值之间同时 rollRCSpeed的绝对值>0
  120.   {//
  121.     gyroRoll = gyroRoll + config.accelWeight * rollRCSpeed * RC_GAIN;//config.accelWeight=15,config.accelWeight * rollRCSpeed * RC_GAIN为特性修正吗?还是?
  122.     rollSetpoint = rollAngleACC;
  123.   }
  124.   else//
  125.     gyroRoll = gyroRoll + config.accelWeight * (rollAngleACC - rollSetpoint) /sampleTimeACC;//

  126.   if((fabs(pitchRCSpeed)>0.0)&&(pitchAngleACC<config.maxRCPitch)&&(pitchAngleACC>config.minRCPitch))
  127.   {
  128.     gyroPitch = gyroPitch + config.accelWeight * pitchRCSpeed * RC_GAIN;
  129.     pitchSetpoint = pitchAngleACC;
  130.   }
  131.   else
  132.     gyroPitch = gyroPitch + config.accelWeight * (pitchAngleACC - pitchSetpoint) /sampleTimeACC;//加入加速度计算出的调节系数吗?
  133.      

  134. //     pitchSetpoint=constrain(pitchSetpoint,config.minRCPitch,config.maxRCPitch);
  135. //      rollSetpoint=constrain(rollSetpoint,config.minRCRoll,config.maxRCRoll);

  136. //630-1130
  137. //计算电机数据
  138.   pitchPID = ComputePID(sampleTimePID,gyroPitch,0.0, &pitchErrorSum, &pitchErrorOld,config.gyroPitchKp,config.gyroPitchKi,config.gyroPitchKd,maxDegPerSecondPitch);
  139.   rollPID = ComputePID(sampleTimePID,gyroRoll,0.0, &rollErrorSum, &rollErrorOld,config.gyroRollKp,config.gyroRollKi,config.gyroRollKd,maxDegPerSecondRoll);
  140. //
  141. /*
  142. float ComputePID(float SampleTimeInSecs, float in, float setPoint, float *errorSum, float *errorOld, float Kp, float Ki, float Kd, float maxDegPerSecond)
  143. {
  144. //PID算法说明,PID 分为P比例调节,I积分 预设置和反馈值之间的差值在时间上的累积,累积值大到一定时才处理,有滞后控制的作用。D微分项调节即根据趋势作提前量调整,有提前控制的作用
  145.   float error = setPoint - in;//计算差值,0.0-gyroRoll
  146. //算法分析&rollErrorSum+=(0.0-gyroRoll)然后限幅
  147.   // Integrate Errors
  148.   *errorSum += error;//积分
  149.   *errorSum = constrain(*errorSum, -maxDegPerSecond ,maxDegPerSecond);//限幅

  150.   /*Compute PID Output*/
  151. //PID算法代码
  152.   float out = (Kp * error + SampleTimeInSecs * Ki * *errorSum + Kd * (error - *errorOld) / (SampleTimeInSecs + 0.000001))/1000.0;
  153. //1、比例调节算法P:当前error*Kp(error为差值,Kp为P值即比例调节量,可进行人工设置、基础的调整速度只根据差值大小确定调整快慢)+2、积分调节算法I:总error*Ki*SampleTimeInSecs(差值积分总值*errorSum(是角度值吗?)*调节因子Ki*时间变量+3、微分D 调节,即根据在一定时间内的变化量来确定调整效果的快慢来作一个提前量调整。调整因子Kd*变化量(error - *errorOld)/时间
  154. //D的作用就是在一定时间内判断差值的变化趋势。越大就调的调的越快。越少调的越慢。
  155. //I的算法好像有点问题,不像网上说的那样吗?
  156.   *errorOld = error;// &rollErrorOld=error 存本次的差值,以便和下一次角速度即差值比较

  157.   return constrain(out, -maxDegPerSecond ,maxDegPerSecond);//返回限幅后的数据out
  158. }
  159. */
  160. //1250-1700

  161.   pitchDevider = constrain(maxDegPerSecondPitch / (pitchPID + 0.000001), -15000,15000)*2;//调整信号
  162.   pitchDirection = sgn(pitchDevider) * config.dirMotorPitch;//计算电机输出数据1、0、-1只转动一点点 0不转
  163.   rollDevider = constrain(maxDegPerSecondRoll / (rollPID + 0.000001), -15000,15000)*2;//2、调整信号 constrain的作用是限幅,功能为如果maxDegPerSecondRoll / (rollPID + 0.000001)小于-15000则返回-15000,大于15000则返回15000。否则返回原来的值       2、+ 0.000001的作用是为了防止rollPID为0吗?3、(rollPID + 0.000001)为角度值?不像但和角度相关
  164.         //maxDegPerSecondRoll = MOTORUPDATE_FREQ * 1000.0 / N_SIN / (config.nPolesMotorRoll/2) * 360.0;//转动的最大值吗?
  165.   
  166.   // Initialize Motor Movement (初始化 电机 运动) 最大值?
  167. // maxDegPerSecondPitch = MOTORUPDATE_FREQ * 1000.0 / N_SIN / (config.nPolesMotorPitch/2) * 360.0;
  168.   //maxDegPerSecondRoll = MOTORUPDATE_FREQ * 1000.0 / N_SIN / (config.nPolesMotorRoll/2) * 360.0;

  169.   rollDirection = sgn(rollDevider) * config.dirMotorRoll;//计算电机输出数据1、0、-1
  170. //1400-1850



  171. //Serial.println( (micros()-timer)/CC_FACTOR);
  172.   sCmd.readSerial();

  173. }


您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

71

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部