pig881 发表于 2016-4-22 12:43:14

搞了半个月,搞不定小车走直线的问题,PID也调不了

为了小车走个直线,我用了Arduino 的 PID_V1 库,20 线的码盘测速,L298N 调速,把左右马达速度差(左边马达速度-右边马达速度)作为输入 Input ,采用 左边马达PWM +Output, 右边马达PWM-Output ,的计算方式, 在USB线连接Arduino板的时候 ,测试是比较正常的,

但是USB线拔掉,左边马达就直接停了!无论我怎么调PID 参数都没作用!!

我附上视频,在视频里, 如果 连接 USB 线, 按右边轮子减速,左边会跟着减速,按左边轮子,右边也同样的

http://player.youku.com/player.php/sid/XMTU0MzgzMzY5Ng==/v.swf


拔掉USB线后,左边轮子很快就停止了!!
http://player.youku.com/player.php/sid/XMTU0MzgzMzY5Mg==/v.swf

我的PID 参数设置D 为0 ,只调整 P 和 I,

我实在搞不懂是什么原因,难道是不需要积分I,而是要P和 D ?

fish6823 发表于 2016-4-22 13:52:08

看录像两个轮子都转啊!你问问题要把你的接线图和程序放上来,大家才能帮你找出问题,光说现象没人能帮你找出问题出在哪的。

pig881 发表于 2016-4-22 16:34:28

fish6823 发表于 2016-4-22 13:52 static/image/common/back.gif
看录像两个轮子都转啊!你问问题要把你的接线图和程序放上来,大家才能帮你找出问题,光说现象没人能帮你找 ...

看第二个录像,最后左边轮子是停了的

pig881 发表于 2016-4-22 16:34:53

本帖最后由 pig881 于 2016-4-22 16:37 编辑

#include <PID_v1.h>


//========== PID 参数 ======================================

double Setpoint=0, Input, Output;
double   Kp=0.2, Ki=0, Kd=0.08;   //Kp=0.1;   Kp=0.1, Ki=0.05, Kd=0.001;   Kp=0.2, Ki=0, Kd=0.08;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);


//========== End of PID 参数 ===================================



//============= 测速参数 ===================
int OUTL=2;
int OUTR=3;

volatile int scode_L = 0; //左轮编码器码盘脉冲计数值
volatile int scode_R =0;//右轮编码器码盘脉冲计数值

unsigned long old_time=0,new_time=0; // 总时间标记

unsigned long time1 = 0, time2 = 0; //左1,右2 轮 时间标记

double spdLft; //左轮电机每分钟(min)转速(r/min)
double spdRgt; //右轮电机每分钟(min)转速(r/min)

int val_left;//上位机控制字节,用于提供给左轮电机PWM功率值。
int val_right; //小车右轮电机的PWM功率值

int pwm;

//=============END OF 测速参数 ===================




//===================MOTOR马达驱动 参数===================

// motor A   LEFT MOTOR
int dir1PinAL = 13;
int dir2PinAL = 12;
int speedPinAL = 10; //10脚 LEFT spped setter

// motor B   RIGHT MOTOR
int dir1PinBR = 9;
int dir2PinBR = 8;
int speedPinBR = 6; // 6脚RIGHT spped setter

//=================== end of MOTOR马达驱动 参数===================



void setMotor()
{
    //左边马达
    pinMode(dir1PinAL,OUTPUT);
    pinMode(dir2PinAL,OUTPUT);
    pinMode(speedPinAL,OUTPUT);

    //右边马达
    pinMode(dir1PinBR,OUTPUT);
    pinMode(dir2PinBR,OUTPUT);
    pinMode(speedPinBR,OUTPUT);   
   
}

//====================== END OF MOTOR 参数 ===============

void Code1();
void Code2();


void setup() {

    setMotor();
    Serial.begin(9600);

   pwm=60;    //=inString.toInt();
   scode_L = 0; //恢复到编码器测速的初始状态
   scode_R = 0;
   old_time=millis();

   attachInterrupt(0, Code1, FALLING);//小车左车轮电机的编码器脉冲中断函数
   attachInterrupt(1, Code2, FALLING);//小车右车轮电机的编码器脉冲中断函数

   Setpoint=0;//左右差为0 为目标
   myPID.SetOutputLimits(-60,60); //输出限制
   
   myPID.SetTunings(Kp,Ki,Kd);
   myPID.SetSampleTime(1000);
   myPID.SetMode(AUTOMATIC);

}

void loop() {

    //======================= 测速代码 ==========================================
   
    new_time=millis();
    if(abs(new_time - old_time) >= 1000) // 如果计时时间已达1秒
    {
      detachInterrupt(0); // 关闭外部中断0
      detachInterrupt(1); // 关闭外部中断1   
      
       //把每一秒钟编码器码盘计得的脉冲数,换算为当前转速值
       //转速单位是每分钟多少转,即r/min。这个编码器码盘为12个齿。
      
          spdLft =(float)scode_L*60/20;//小车左车轮电机转速      
          spdRgt =(float)scode_R*60/20; //小车右车轮电机转速


          //val_right=(float)val_right+(rpm1-rpm2)*0.4;

          Input=0.6*(spdLft-spdRgt); 这里我用的 0.6 X 左右速度差作为PID输入,我是根据一篇文章提示这么做的 ,具体应该多少我也不懂
          myPID.Compute();

          val_right=pwm-Output;
          val_left=pwm+Output;
         
         testNum('n');   
   
         scode_L = 0; //恢复到编码器测速的初始状态
         scode_R = 0;
         
         old_time=millis();   
         
         attachInterrupt(0, Code1,FALLING); // 重新开放外部中断0
         attachInterrupt(1, Code2,FALLING); // 重新开放外部中断1
      

               

    }
   //======================= END OF 测速代码 ==========================================


    advance();   

}



// 左侧车轮电机的编码器码盘计数中断子程序
void Code1()
{
//为了不计入噪音干扰脉冲,
   //当2次中断之间的时间大于5ms时,计一次有效计数
if((millis()-time1)>5)
//当编码器码盘的OUTA脉冲信号下跳沿每中断一次,
scode_L += 1; // 编码器码盘计数加一
time1=millis();
}




// 右侧车轮电机的编码器码盘计数中断子程序
void Code2()
{
if((millis()-time2)>5)
//当编码器码盘的OUTA脉冲信号下跳沿每中断一次,
scode_R += 1; // 编码器码盘计数加一
time2=millis();
}



//子程序程序段
void advance()//小车前进
{
   MOTORDRIVE(speedPinAL,dir1PinAL,dir2PinAL,val_left,0); //左边马达
   MOTORDRIVE(speedPinBR,dir1PinBR,dir2PinBR,val_right,0); //右边马达
}


void back()//小车后退
{
   MOTORDRIVE(speedPinAL,dir1PinAL,dir2PinAL,val_left,1); //左边马达
   MOTORDRIVE(speedPinBR,dir1PinBR,dir2PinBR,val_right,1); //右边马达
}


void Stop()//小车停止
{
   MOTORDRIVE(speedPinAL,dir1PinAL,dir2PinAL,0,1); //左边马达
   MOTORDRIVE(speedPinBR,dir1PinBR,dir2PinBR,0,1); //右边马达
}


//============================= 马达驱动函数 ====================================================

// speedpin:速度引脚dirPinA:电机极A , dirPinB:电机极B , mspeed:速度值 ,dir:1 正向 0 反向
void MOTORDRIVE(int speedpin,int dirPinA,int dirPinB,int mspeed,int dir)
{
   analogWrite(speedpin,mspeed);   


   if (dir == 1) {
   digitalWrite(dirPinA,LOW);
   digitalWrite(dirPinB,HIGH);   
   }
   else if(dir== 0) {//反转
      digitalWrite(dirPinA,HIGH);
      digitalWrite(dirPinB,LOW);   
   }
   else {
       analogWrite(speedpin,0);
    }
   

}

//============================= end of 马达驱动函数 ====================================================



// ================== 显示函数 =============

void testNum(char a)
{
if(a=='n')
{
    Serial.print("Input=");
    Serial.println(Input);

   Serial.print("Output=");
    Serial.println(Output);

         Serial.print("val_left=");
   Serial.println(val_left);

      Serial.print("val_right=");
   Serial.println(val_right);

    Serial.print("\t speeds left=");
   Serial.println(spdLft);

   Serial.print("\t speeds Right=");
   Serial.println(spdRgt);
}
else if (a=='t')
{


   
   
    Serial.print(spdLft);
   Serial.print(",");
   
    Serial.println(spdRgt);
    Serial.print("\n");
}

      

    delay(1000);
}


通幽境 发表于 2016-4-22 20:06:48

插着USB线正常,拔掉出问题,估摸着硬件BUG的可能比较大

JIMJIM 发表于 2019-3-25 20:19:24

请问你是同时用编码器的AB相的吗
页: [1]
查看完整版本: 搞了半个月,搞不定小车走直线的问题,PID也调不了