|
发表于 2015-4-23 21:51:09
|
显示全部楼层
你好,我编码器没数据你能帮我看看吗?谢谢
//把小车右侧电机的编码器OUTA信号连接到Arduino控制器的数字端口2
#define PinA_right 2 ////数字端口2是Arduino的外部中断0的端口
#define PinB_right 8 //右侧电机的编码器OUTB 信号对于数字端口8
//把小车左侧电机的编码器OUTA信号连接到Arduino控制器的数字端口3
#define PinA_left 3 //数字端口3是Arduino的外部中断1的端口
#define PinB_left 10 //左侧电机的编码器OUTB 信号对于数字端口10
long count_right = 0; //定义编码器码盘计数值(此编码器转一圈发出334个脉冲)
long count_left = 0;
long rpm_right = 0; //每分钟(min)转速(r/min)
long rpm_left = 0;
unsigned long time = 0,
old_time = 0;// 时间标记 //初始化
unsigned char Re_buf[11],counter=0;
unsigned char sign=0;
int M_left=4;
int M_left2=7;
int M_right=9;
int M_right2=11;
int E_left=5;
int E_right=6;
float a[3],w[3],Angle[3],T;
short sAccelerat[3],sAngleVelocity[3],sAngle[3],sT;
void setup() {
// initialize serial:
Serial.begin(115200);
pinMode(M_left,OUTPUT);
pinMode(M_left2,OUTPUT);
pinMode(M_right,OUTPUT);
pinMode(M_right2,OUTPUT);
pinMode(E_left,OUTPUT);
pinMode(E_right,OUTPUT);
pinMode(PinA_right,INPUT); //伺服电机编码器的OUTA和OUTB信号端设置为输入模式
pinMode(PinB_right,INPUT);
pinMode(PinA_left,INPUT);
pinMode(PinB_left,INPUT); //定义外部中断的中断子程序Code(),中断触发为下跳沿触发 //当编码器码盘的正交编码板OUTA脉冲信号发生下跳沿中断时, //将自动调用执行中断子程序Code()。
attachInterrupt(0, Code_right, FALLING);
attachInterrupt(1, Code_left, FALLING); //对直流电机驱动板的使能端口和转向端口进行设置,以使小车 //执行前进、后退、左转、右转、停止和速度切换动作。
}
void SetMotor(int nLeftVol, int nRightVol) {
if(nLeftVol >=0)
{ digitalWrite(M_left,LOW);
digitalWrite(M_left2,HIGH);
} else {
digitalWrite(M_left,HIGH);
digitalWrite(M_left2,LOW);
nLeftVol=-nLeftVol;
}
if(nRightVol >= 0) {
digitalWrite(M_right,LOW);
digitalWrite(M_right2,HIGH);
} else {
digitalWrite(M_right,HIGH);
digitalWrite(M_right2,LOW);
nRightVol=-nRightVol;
}
if(nLeftVol>255) { nLeftVol = 255 ; } //防止PWM值超过255
if(nRightVol>255) { nRightVol = 255 ; }//防止PWM值超过255
analogWrite(E_left,nLeftVol);//将模拟值(PWM波)输出到管脚
analogWrite(E_right,nRightVol);
}
float PID1(float e,float kp,float ki,float kd)
{
static float es=0,sum=0;
float r;
sum+=e;
r = kp*e+ki*sum+kd*(e-es);
es=e;
return r;
}
float PID2(float e,float kp,float ki,float kd)
{
static float es=0,sum=0;
float r;
sum+=e;
r = kp*e+ki*sum+kd*(e-es);
es=e;
return r;
}
void loop() {
float kp=30,ki=0.0,kd=10,r1,r2;
if (sign==0) return;//sign为数据更新标志,每隔10ms更新一次,也就是说以下代码每隔10ms控制一次。
sign=0;
kd = (float)analogRead(1)/1024*200;
r1=PID1(Angle[0],kp,ki,kd);//PID1、PID2函数就是第四节的PID函数,为了区分左右轮,所以分成两个。
r2=PID2(Angle[0],kp,ki,kd);
SetMotor(r1,r2);//设置电机转速。
old_time= millis();
/*Serial.print("angle:");
Serial.print(Angle[0]);Serial.print(" ");
Serial.print(r1);Serial.print(" ");
Serial.println(kd);Serial.print(" ");*/
time = millis();//以毫秒为单位,计算当前时间 //计算出每0.5秒钟内,编码器码盘计得的脉冲数,
if(abs(time - old_time) >= 500) // 如果计时时间10ms
{ detachInterrupt(0); // 关闭外部中断0
detachInterrupt(1); // 关闭外部中断1
//此直流减速电机的编码器码盘为334个齿,减速比为21.3。 //把编码器每0.5秒钟计得的脉冲数,换算为当前转速值的计算式
rpm_right =(float)count_right*60*2/(334*30);
rpm_left =(float)count_left*60*2/(334*30);
Serial.println( rpm_right);
Serial.println(rpm_left);
Serial.println("---------------");
Serial.println(rpm_right-rpm_left);
Serial.println("---------------");
}
}
void serialEvent() {
while (Serial.available()) {
Re_buf[counter]=(unsigned char)Serial.read();
if(counter==0&&Re_buf[0]!=0x55) return; //第0号数据不是帧头
counter++;
if(counter==11) //接收到11个数据
{
counter=0; //重新赋值,准备下一帧数据的接收
switch(Re_buf [1])
{
case 0x51:
a[0] = float(short(Re_buf [3]<<8| Re_buf [2]))/32768*16;
a[1] = float(short(Re_buf [5]<<8| Re_buf [4]))/32768*16;
a[2] = float(short(Re_buf [7]<<8| Re_buf [6]))/32768*16;
break;
case 0x52:
w[0] = float(short(Re_buf [3]<<8| Re_buf [2]))/32768*250;
w[1] = float(short(Re_buf [5]<<8| Re_buf [4]))/32768*250;
w[2] = float(short(Re_buf [7]<<8| Re_buf [6]))/32768*250;
break;
case 0x53:
Angle[0] = float(short(Re_buf [3]<<8| Re_buf [2]))/32768*180;
Angle[1] = float(short(Re_buf [5]<<8| Re_buf [4]))/32768*180;
Angle[2] = float(short(Re_buf [7]<<8| Re_buf [6]))/32768*180;
T = float(short(Re_buf [9]<<8| Re_buf [8]));///340.0+36.25
sign=1;
break;
}
}
}
}
void Code_right()
{
count_right += 1; // 编码器码盘计数加一
}
//左侧电机编码器码盘计数中断子程序
void Code_left() { count_left += 1; // 编码器码盘计数加一
}
|
|