MSP430主控 Energia编译(似Arduino) TI坡道行驶小车(4)总体功能实现与代码

        经过我们前面的准备以后,小车已经被我们安装好了,现在就只需要上传代码了。(安装前应该先对各模块进行示例程序的上传来验证该模块的完整性,如果模块没问题再进行小车的接线与封装)

        如图为我本次实验的小车成品与部分功能图片演示:

 

         LCD显示实时速度与运行时间:

程序说明:

1.引脚定义与库的说明(仅需要定义伺服电机库-控制舵机转前轮;液晶屏显示库-控制LCD):

#include <Servo.h>
#include <LiquidCrystal.h>

//蜂鸣器端口定义
#define Buzz P1_6 //控制蜂鸣器

//前轮舵机端口定义
Servo carservo;
#define Servopin P2_0//控制舵机

//LCD显示屏端口定义
LiquidCrystal lcd(P8_1, P8_2, P4_3, P4_0, P3_7, P7_4);

//左电机端口定义
#define MotorLpin1   P4_1//控制位3
#define MotorLpin2   P4_2//控制位4
#define MotorLpwm    P3_5 //使能调速 ENB
#define MotorLcountA P1_3 //编码器B 

//右电机端口定义
#define MotorRpin1   P2_7//控制位1
#define MotorRpin2   P3_2 //控制位2
#define MotorRpwm    P3_6  //使能调速 ENA
#define MotorRcountA P1_2 //编码器B

//三路传感器
#define sensor1 P6_0
#define sensor2 P6_1
#define sensor3 P6_2

 2.PID速度控制前进部分:

        为了使小车在不同坡度上能匀速前进,需要使用PID控制小车的速度,使小车平稳前进。题目要求在10-20s内走完1m的路程,故控制速度在13cm/s左右即可,不过可以调整。(PID控制速度部分参考博客 平衡小车之家PID代码 )

//控速变量
volatile float motorL=0;//中断变量,左轮子脉冲计数
volatile float motorR=0;//中断变量,右轮子脉冲计数
float V_L=0; //左轮速度 单位cm/s
float V_R=0; //右边轮速 单位cm/s
int v1=0;  //单位cm/s
int v2=0;  //单位cm/s
float Target_V_L=8,Target_V_R=8;   //目标速度,单位cm/s
int Pwm_L=0,Pwm_R=0;  //左右轮PWM
 
//PID变量
float kp=1.6,ki=0.8,kd=0;  //PID参数

/*********************************************************
 * 函数功能:增量式PI控制器(左轮)
 *********************************************************/
 int Incremental_Pi_L(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;         //增量输出
 }
 
//右轮速度增量式PID控制器
int Incremental_Pi_R(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;         //增量输出
 }
 
void Set_Pwm(int speed_L,int speed_R){
  //前进模式
  //左电机
  digitalWrite(MotorLpin1,HIGH);
  digitalWrite(MotorLpin2,LOW);
  analogWrite(MotorLpwm,speed_L);
  //右电机
  digitalWrite(MotorRpin1,LOW);
  digitalWrite(MotorRpin2,HIGH);
  analogWrite(MotorRpwm,speed_R);
 // Serial.println("lello");
}

/***********************************
 * 电机实际速度计算:
 * 公式:
 * 已知参数:
 *     车轮直径65mm,
 *     左边轮子一圈:390脉冲(RISING),
 *     右边轮子一圈:390脉冲(RISING),
 * 单位时间读两个轮子脉冲读取两个轮子脉冲
 ***********************************/
 void Read_Moto_V(){
  unsigned long nowtime=0;
  motorL=0;
  motorR=0;
  nowtime=millis()+50;//读50毫秒
  attachInterrupt(digitalPinToInterrupt(MotorLcountA),Read_Moto_L,RISING);//左轮脉冲开中断计数
  attachInterrupt(digitalPinToInterrupt(MotorRcountA),Read_Moto_R,RISING);//右轮脉冲开中断计数
  while(millis()<nowtime); //达到50毫秒关闭中断
  detachInterrupt(digitalPinToInterrupt(MotorLcountA));//左轮脉冲关中断计数
  detachInterrupt(digitalPinToInterrupt(MotorRcountA));//右轮脉冲关中断计数
  //Serial.println(motorL*100);
  //Serial.println(motorR*100);
  V_L=((motorL/390)*6.5*PI)/0.05;   //单位cm/s
  V_R=((motorR/390)*6.5*PI)/0.05;   //单位cm/s
  v1=V_L;
  v2=V_R;
}
 
 
/***************************
 * 中断函数:读左轮脉冲
 **************************/
void Read_Moto_L(){
  motorL++;
}
 
 
/**************************
 * 中断函数:读右轮脉冲
 *************************/
void Read_Moto_R(){
  motorR++;
}

//前进函数
void RUN(int RV,int LV){
   Target_V_L=LV,Target_V_R=RV;
   Read_Moto_V();//读取脉冲计算速度
   Pwm_L=Incremental_Pi_L(V_L,Target_V_L);//左轮PI运算
   Pwm_R=Incremental_Pi_R(V_R,Target_V_R);//右轮PI运算
   //Serial.println(V_L);  //直接用串口绘图画出速度曲线
   Set_Pwm(Pwm_L,Pwm_R);  //设置左右轮速度
}

3.终点停车(当三路循迹全检测到黑时停止工作):

//终点停车函数
void Stop(){
   //左电机
   digitalWrite(MotorLpin1,LOW);
   digitalWrite(MotorLpin2,LOW);
   //右电机
   digitalWrite(MotorRpin1,LOW);
   digitalWrite(MotorRpin2,LOW);
   //声音提示
   digitalWrite(Buzz,HIGH);
   delay(500);
   digitalWrite(Buzz,LOW);
   delay(1000);
   while(1);
}

4.LCD显示速度和运行时间(LCD显示具体用法网上随处可查,在此不作过多说明):

void LCDshow(){
   lcd.setCursor(0, 0);
   lcd.print("Speed:");
   lcd.setCursor(6, 0);
   lcd.print(V_L);
   lcd.setCursor(11, 0);
   lcd.print("cm/s");
   lcd.setCursor(0, 1);
   lcd.print("Time:");
   lcd.setCursor(5, 1);
   lcd.print(millis()*0.001);
   lcd.setCursor(10, 1);
   lcd.print("s");
}

5.循迹部分:

         循迹部分红外传感器采集到的是模拟量,从0-4095;然后经过多次尝试采集到黑与白的分界阈值为200(不同场景阈值不同,自己测量即可);舵机转角也是经过多次调试确定下来的,不同小车一般不同,也需要自己调整。(RUN()函数在前面已经定义过了)

void Track(){
   int data[3];
   data[0] = analogRead(sensor1);//读取四个传感器值
   data[0] = map(data[0], 0, 4095, 0, 1000);
   data[1] = analogRead(sensor2);
   data[1] = map(data[1], 0, 4095, 0, 1000);
   data[2] = analogRead(sensor3);
   data[2] = map(data[2], 0, 4095, 0, 1000);
   
   if(data[0]<200&&data[1]>200&&data[2]<200){
       carservo.write(82);
       delay(15);
       RUN(6,6);
    }
   else if((data[0]<200&&data[1]<200&&data[2]<200)&&carservo.read()<100&&carservo.read()>70){
       RUN(6,6);
    }
   else if((data[0]<200&&data[1]<200&&data[2]<200)&&carservo.read()>100){
       RUN(6,10);
    }
   else if(data[0]>200&&data[1]<200&&data[2]<200)
       Turn_right();
   else if(data[0]<200&&data[1]<200&&data[2]>200)
       Turn_left();
   else if(data[0]>200&&data[1]>200&&data[2]>200)
       Stop();
   /*Serial.println(data[0]);
   Serial.println(data[1]);
   Serial.println(data[2]);
   Serial.println("--------------");*/
}
//右转函数
void Turn_right(){
  carservo.write(140);//调整舵机角度 140 9.8 2.2
  delay(15);
  RUN(6,10);//后轮差速(右,左),左快右慢
}

//左转函数
void Turn_left(){
  carservo.write(60);//调整舵机角度
  delay(15);
  RUN(10,6);//后轮差速(右,左),左慢右快
}

6.setup与loop:

/**************************************
 * 初始化函数
 *************************************/
void setup() {
   //LCD初始化
   lcd.begin(16, 2);
   lcd.print("Start");
   Motor_Init();//电机端口初始化
   Servo_Init();//舵机端口初始化
   pinMode(Buzz,OUTPUT);//蜂鸣器初始化
   //循迹初始化
   pinMode(sensor1,INPUT);
   pinMode(sensor2,INPUT);
   pinMode(sensor3,INPUT);
   Serial.begin(9600);//开启串口
}

void Servo_Init(){
   carservo.attach(Servopin); 
   carservo.write(82); 
   delay(15);
}

void Motor_Init(){
  //左电机
  pinMode(MotorLpin1,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorLpin2,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorLpwm,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(MotorLcountA,INPUT); //左轮编码器B引脚
  
  //右电机
  pinMode(MotorRpin1,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorRpin2,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorRpwm,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(MotorRcountA,INPUT); //右轮编码器B引脚
 
  //驱动芯片控制引脚全部拉低
  digitalWrite(MotorLpin1,LOW); //左电机
  digitalWrite(MotorLpin2,LOW);
  digitalWrite(MotorLpwm,LOW);
  digitalWrite(MotorRpin1,LOW); //右电机
  digitalWrite(MotorRpin2,LOW);
  digitalWrite(MotorRpwm,LOW);
}


/***************************************
 * 主循环
 ***************************************/
void loop() {
   LCDshow();
   Track();
}

       综上,把各部分代码上传后运行小车,根据问题来调整一些代码部分和参数,就可以实现我们的功能。最后附上完整代码:

#include <Servo.h>
#include <LiquidCrystal.h>

//蜂鸣器端口定义
#define Buzz P1_6 //控制蜂鸣器

//前轮舵机端口定义
Servo carservo;
#define Servopin P2_0//控制舵机

//LCD显示屏端口定义
LiquidCrystal lcd(P8_1, P8_2, P4_3, P4_0, P3_7, P7_4);

//左电机端口定义
#define MotorLpin1   P4_1//控制位3
#define MotorLpin2   P4_2//控制位4
#define MotorLpwm    P3_5 //使能调速 ENB
#define MotorLcountA P1_3 //编码器B 

//右电机端口定义
#define MotorRpin1   P2_7//控制位1
#define MotorRpin2   P3_2 //控制位2
#define MotorRpwm    P3_6  //使能调速 ENA
#define MotorRcountA P1_2 //编码器B

//四路传感器
#define sensor1 P6_0
#define sensor2 P6_1
#define sensor3 P6_2

//控速变量
volatile float motorL=0;//中断变量,左轮子脉冲计数
volatile float motorR=0;//中断变量,右轮子脉冲计数
float V_L=0; //左轮速度 单位cm/s
float V_R=0; //右边轮速 单位cm/s
int v1=0;  //单位cm/s
int v2=0;  //单位cm/s
float Target_V_L=8,Target_V_R=8;   //目标速度,单位cm/s
int Pwm_L=0,Pwm_R=0;  //左右轮PWM
 
//PID变量
float kp=1.6,ki=0.8,kd=0;  //PID参数


/**************************************
 * 初始化函数
 *************************************/
void setup() {
   //LCD初始化
   lcd.begin(16, 2);
   lcd.print("Start");
   Motor_Init();//电机端口初始化
   Servo_Init();//舵机端口初始化
   pinMode(Buzz,OUTPUT);//蜂鸣器初始化
   //循迹初始化
   pinMode(sensor1,INPUT);
   pinMode(sensor2,INPUT);
   pinMode(sensor3,INPUT);
   Serial.begin(9600);//开启串口
}

void Servo_Init(){
   carservo.attach(Servopin); 
   carservo.write(82); 
   delay(15);
}

void Motor_Init(){
  //左电机
  pinMode(MotorLpin1,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorLpin2,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorLpwm,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(MotorLcountA,INPUT); //左轮编码器B引脚
  
  //右电机
  pinMode(MotorRpin1,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorRpin2,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorRpwm,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(MotorRcountA,INPUT); //右轮编码器B引脚
 
  //驱动芯片控制引脚全部拉低
  digitalWrite(MotorLpin1,LOW); //左电机
  digitalWrite(MotorLpin2,LOW);
  digitalWrite(MotorLpwm,LOW);
  digitalWrite(MotorRpin1,LOW); //右电机
  digitalWrite(MotorRpin2,LOW);
  digitalWrite(MotorRpwm,LOW);
}
 
 
/*********************************************************
 * 函数功能:增量式PI控制器(左轮)
 *********************************************************/
 int Incremental_Pi_L(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;         //增量输出
 }
 
//右轮速度增量式PID控制器
int Incremental_Pi_R(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;         //增量输出
 }
 
void Set_Pwm(int speed_L,int speed_R){
  //前进模式
  //左电机
  digitalWrite(MotorLpin1,HIGH);
  digitalWrite(MotorLpin2,LOW);
  analogWrite(MotorLpwm,speed_L);
  //右电机
  digitalWrite(MotorRpin1,LOW);
  digitalWrite(MotorRpin2,HIGH);
  analogWrite(MotorRpwm,speed_R);
 // Serial.println("lello");
}


/***********************************
 * 电机实际速度计算:
 * 公式:
 * 已知参数:
 *     车轮直径65mm,
 *     左边轮子一圈:390脉冲(RISING),
 *     右边轮子一圈:390脉冲(RISING),
 * 单位时间读两个轮子脉冲读取两个轮子脉冲
 ***********************************/
 void Read_Moto_V(){
  unsigned long nowtime=0;
  motorL=0;
  motorR=0;
  nowtime=millis()+50;//读50毫秒
  attachInterrupt(digitalPinToInterrupt(MotorLcountA),Read_Moto_L,RISING);//左轮脉冲开中断计数
  attachInterrupt(digitalPinToInterrupt(MotorRcountA),Read_Moto_R,RISING);//右轮脉冲开中断计数
  while(millis()<nowtime); //达到50毫秒关闭中断
  detachInterrupt(digitalPinToInterrupt(MotorLcountA));//左轮脉冲关中断计数
  detachInterrupt(digitalPinToInterrupt(MotorRcountA));//右轮脉冲关中断计数
  //Serial.println(motorL*100);
  //Serial.println(motorR*100);
  V_L=((motorL/390)*6.5*PI)/0.05;   //单位cm/s
  V_R=((motorR/390)*6.5*PI)/0.05;   //单位cm/s
  v1=V_L;
  v2=V_R;
}
 
 
/***************************
 * 中断函数:读左轮脉冲
 **************************/
void Read_Moto_L(){
  motorL++;
}
 
 
/**************************
 * 中断函数:读右轮脉冲
 *************************/
void Read_Moto_R(){
  motorR++;
}

//前进函数
void RUN(int RV,int LV){
   Target_V_L=LV,Target_V_R=RV;
   Read_Moto_V();//读取脉冲计算速度
   Pwm_L=Incremental_Pi_L(V_L,Target_V_L);//左轮PI运算
   Pwm_R=Incremental_Pi_R(V_R,Target_V_R);//右轮PI运算
   //Serial.println(V_L);  //直接用串口绘图画出速度曲线
   Set_Pwm(Pwm_L,Pwm_R);  //设置左右轮速度
}



//终点停车函数
void Stop(){
   //左电机
   digitalWrite(MotorLpin1,LOW);
   digitalWrite(MotorLpin2,LOW);
   //右电机
   digitalWrite(MotorRpin1,LOW);
   digitalWrite(MotorRpin2,LOW);
   //声音提示
   digitalWrite(Buzz,HIGH);
   delay(500);
   digitalWrite(Buzz,LOW);
   delay(1000);
   while(1);
}

void LCDshow(){
   lcd.setCursor(0, 0);
   lcd.print("Speed:");
   lcd.setCursor(6, 0);
   lcd.print(V_L);
   lcd.setCursor(11, 0);
   lcd.print("cm/s");
   lcd.setCursor(0, 1);
   lcd.print("Time:");
   lcd.setCursor(5, 1);
   lcd.print(millis()*0.001);
   lcd.setCursor(10, 1);
   lcd.print("s");
}


void Track(){
   int data[3];
   data[0] = analogRead(sensor1);//读取四个传感器值
   data[0] = map(data[0], 0, 4095, 0, 1000);
   data[1] = analogRead(sensor2);
   data[1] = map(data[1], 0, 4095, 0, 1000);
   data[2] = analogRead(sensor3);
   data[2] = map(data[2], 0, 4095, 0, 1000);
   
   if(data[0]<200&&data[1]>200&&data[2]<200){
       carservo.write(82);
       delay(15);
       RUN(6,6);
    }
   else if((data[0]<200&&data[1]<200&&data[2]<200)&&carservo.read()<100&&carservo.read()>70){
       RUN(6,6);
    }
   else if((data[0]<200&&data[1]<200&&data[2]<200)&&carservo.read()>100){
       RUN(6,10);
    }
   else if(data[0]>200&&data[1]<200&&data[2]<200)
       Turn_right();
   else if(data[0]<200&&data[1]<200&&data[2]>200)
       Turn_left();
   else if(data[0]>200&&data[1]>200&&data[2]>200)
       Stop();
   /*Serial.println(data[0]);
   Serial.println(data[1]);
   Serial.println(data[2]);
   Serial.println("--------------");*/
}
//右转函数
void Turn_right(){
  carservo.write(140);//调整舵机角度 140 9.8 2.2
  delay(15);
  RUN(6,10);//后轮差速(右,左),左快右慢
}

//左转函数
void Turn_left(){
  carservo.write(60);//调整舵机角度
  delay(15);
  RUN(10,6);//后轮差速(右,左),左慢右快
}

/***************************************
 * 主循环
 ***************************************/
void loop() {
   LCDshow();
   Track();
}

评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值