最近临近电赛,往年都有小车题目。去年也做过小车的题目,但是当时奈何知识太浅,也查询了大量的资料也没有找到自己想要的,而自己经过学习,所有自己就分享关于寻迹小车路径规划的问题。
寻迹对于的部分人来说应该都没有问题,我当时也是,可比如遇见下面这种路径规划,自己就犯了难,当时查询了很多资料也不明白怎么实现,自己对于32方面的知识还不是很完善,每次做东西做什么学什么。终于,自己也明白了如何处理这种问题,所以也想给不明白的同学做一些自己的分享,大佬勿喷┭┮﹏┭┮。首先,如果我们需要用寻迹路径规划,比如下图所示,我们先要学会如何实现寻迹,然后还需要学习中断,既可以完成路径的规划。
红外寻迹如图:
上面就是用的普通的红外寻迹,最初做这个项目的时候是用的IIC通信的寻迹,但是发现arduino中用中断调用IIC通信会导致没数据,所以就使用了这个判断电平变化的寻迹板,我先分享一下路径规划的思路,首先,我们在起点开始寻迹,寻迹到黑线后,停止,然后调用一个前进函数,然后进行左转函数,然后又调用寻迹函数。大部分的寻迹代码中,我们将寻迹监测黑线电平变化的函数和寻迹函数都放在了while里无线循环,但是如果像这种情况,我们就无法实现路径规划。所以我将电平变化检测函数,利用中断检测电平变化,这样的话,我们只需要写寻迹函数,转弯函数,然后用标志位来判断是否检测到黑线,检测到后就做出相应的操作即可。这个思路也可以适用于STM32和其他开发板,代码如下:
//循迹红外引脚定义
//TrackSensorLeftPin1 TrackSensorLeftPin2 TrackSensorRightPin1 TrackSensorRightPin2
// A2 A1 A3 A4
const int Sensor1 = A4; //定义左边第一个循迹红外传感器引脚为A2
const int Sensor2 = A5; //定义左边第二个循迹红外传感器引脚为A1
const int Sensor3 = A6; //定义右边第一个循迹红外传感器引脚为A3
const int Sensor4 = A7; //定义右边第二个循迹红外传感器引脚为A4
int LeftMotor1=2;
int LeftMotor2=4;
int RightMotor1=13;
int RightMotor2=27;
int state1;
int state2;
int state3;
int state4;
const int speenpin = A3;
int leftPWM=850;
int rightPWM=850;
volatile uint8_t Stop_Flag;
volatile uint8_t Track_Flag;
volatile uint8_t wheel_R_Flag;
volatile uint8_t wheel_L_Flag;
volatile uint32_t Wheel_flag;
hw_timer_t *tim1 = NULL;
int tim1_IRQ_count =0;
int key = 0; //定义按键
/*流程:
在直线上进行寻迹、到了黑线就停,进行转弯延迟函数,到了位置在进行寻迹
*/
/*
说明:不用while一直循环检测黑线的状态,因为一个单片机只能一个while循环,
本方案采用定时器处理中断,用中断实时检测电平的变化,然后设置标志位,及
可以定制小车寻迹路线
*/
//中断处理函数
void tim1Interrupt()
{
Track_Roadway();//寻迹数据监测
//flog_monitor();//黑线停止监测
Track_Check();//寻迹启动监测
wheel_Track_check();//转弯停止监测
}
/***************************************************************
寻迹检测函数
****************************************************************/
void Track_Roadway()
{
state1 =digitalRead(Sensor1);
state2 =digitalRead(Sensor2);
state3 =digitalRead(Sensor3);
state4 =digitalRead(Sensor4);
}
//寻迹启动监测
void Track_Check()
{
if(Track_Flag == 1)
{
track();
if(state1==LOW && state2==LOW && state3==LOW && state4==LOW)
{
Stop_Flag = 1;
Track_Flag = 0;
stop_car(0,0);
}
}
}
//黑线停止监测
void flog_monitor()
{
if(Track_Flag == 1){
if(state1==LOW && state2==LOW && state3==LOW && state4==LOW)
{
Stop_Flag = 1;
stop_car(0,0);
//Serial.print("Stop_Flag");Serial.print(Stop_Flag);
//Serial.print("Track_Flag");Serial.print(Track_Flag);
Serial.print("循迹检查完成");
Track_Flag = 0;
}
}
}
//转弯停止监测
void wheel_Track_check()
{
if(wheel_L_Flag == 1)
{
turnLeft(600,600);
if(state2==LOW ||state3==LOW )
{
if(Wheel_flag > 50)
{
wheel_L_Flag = 0;
Wheel_flag=0;
Stop_Flag=2;
stop_car(0,0);
}
}
else if(state1==HIGH && state2==HIGH && state3==HIGH && state4==HIGH)
{
Wheel_flag++;
}
}
else if(wheel_R_Flag == 1)
{
if(state2==LOW ||state3==LOW)
{
if(Wheel_flag > 50)
{
wheel_R_Flag=0;
Wheel_flag=0;
Stop_Flag=2;
stop_car(0,0);
}
}
else if(state1==HIGH && state2==HIGH && state3==HIGH && state4==HIGH)
{
Wheel_flag++;
}
}
}
void setup()
{
pinMode(LeftMotor1,OUTPUT);
pinMode(LeftMotor2,OUTPUT);
pinMode(RightMotor1,OUTPUT);
pinMode(RightMotor2,OUTPUT);
//定义四路循迹红外传感器为输入接口 四路循迹红外传感器初始化为高电平
pinMode(Sensor1, INPUT);
pinMode(Sensor2, INPUT);
pinMode(Sensor3, INPUT);
pinMode(Sensor4, INPUT);
digitalWrite(Sensor1, HIGH);
digitalWrite(Sensor2, HIGH);
digitalWrite(Sensor3, HIGH);
digitalWrite(Sensor4, HIGH);
//定时器中断检测,检测到低电平,就判断是否停下
tim1 = timerBegin(0, 80, true);
timerAttachInterrupt(tim1,&tim1Interrupt,true);
timerAlarmWrite(tim1, 100000, true);
timerAlarmEnable(tim1);
//定义按键接口为输入接口
pinMode(key, INPUT);
ledcSetup(0,5000,10);
ledcSetup(1,5000,10);
ledcSetup(2,5000,10);
ledcSetup(3,5000,10);
ledcAttachPin(LeftMotor1,2);
ledcAttachPin(LeftMotor2,3);
ledcAttachPin(RightMotor1,0);
ledcAttachPin(RightMotor2,1);
analogSetWidth(10);
Serial.begin(9600);
//调用按键扫描函数
key_scan();
}
void loop()
{
}
void xunji(){
Serial.print("begin_tack");
car_track();
Serial.print("开始左转");
car_left(500,500);
car_track();
car_left(500,500);
car_track();
car_right(500,500);
car_track();
forward(800,800);
delay(8);
car_track();
forward(800,800);
delay(8);
car_track();
car_left(500,500);
car_track();
car_left(500,500);
car_track();
car_left(500,500);
car_track();
stop_car(0,0);
}
void car_track()
{
Stop_Flag = 0x00;
Track_Flag = 0x01;
wheel_R_Flag =0x00;
wheel_L_Flag =0x00;
while(true){
if(Stop_Flag == 1){
Serial.print("退出完成");
break;
}
}
//while(Stop_Flag!=0x01);
}
void car_left()
{
Stop_Flag = 0x00;
Track_Flag = 0x00;
wheel_R_Flag =0x00;
wheel_L_Flag =0x01;
Serial.print("调用成功");
}
void car_right(int leftPWM,int rightPWM)
{
Stop_Flag = 0x00;
Track_Flag = 0x00;
wheel_R_Flag =0x01;
wheel_L_Flag =0x00;
turnRight(leftPWM,rightPWM);
//while(Stop_Flag!=0x02);
}
void track()
{
if ( state1 == LOW ){
//turnLeftcrile(20);
turnLeft(600,600);
}
else if ( state4 == LOW)
{
//turnRightcrile(20);
turnRight(600,600);
}
else if ( state2 == LOW && state3 == HIGH)
{
turnLeft(600,600);
}
else if (state2 == HIGH && state3 == LOW)
{
turnRight(600,600);
}
else if (state2 == LOW && state3 == LOW)
{
forward(560,560);
}
}
void stop_car(int leftPWM,int rightPWM){
ledcWrite(0,leftPWM);
ledcWrite(1,0);
ledcWrite(2,rightPWM);
ledcWrite(3,0);
}
void forward(int leftPWM,int rightPWM){
ledcWrite(0,leftPWM);
ledcWrite(1,0);
ledcWrite(2,rightPWM);
ledcWrite(3,0);
}
void backward(int leftPWM,int rightPWM){
ledcWrite(0,0);
ledcWrite(1,leftPWM);
ledcWrite(2,0);
ledcWrite(3,rightPWM);
while(Stop_Flag != 0);
}
void turnLeft(int leftPWM,int rightPWM){
ledcWrite(0,0);
ledcWrite(1,leftPWM);
ledcWrite(2,rightPWM);
ledcWrite(3,0);
}
void turnLeftcrile(int time){
ledcWrite(0,0);
ledcWrite(1,850);
ledcWrite(2,850);
ledcWrite(3,0);
delay(time);
}
void turnRight(int leftPWM,int rightPWM){
ledcWrite(0,leftPWM);
ledcWrite(1,0);
ledcWrite(2,0);
ledcWrite(3,rightPWM);
}
void turnRightcrile(int time){
ledcWrite(0,850);
ledcWrite(1,0);
ledcWrite(2,0);
ledcWrite(3,850);
delay(time);
}
void Stop(int time){
ledcWrite(0,1);
ledcWrite(1,1);
ledcWrite(2,1);
ledcWrite(3,1);
delay(time);
}
void key_scan()
{
while (digitalRead(key)); //当按键没有被按下一直循环
while (!digitalRead(key)) //当按键被按下时
{
delay(10); //延时10ms
if (digitalRead(key) == LOW)//第二次判断按键是否被按下
{
delay(100);
while (!digitalRead(key)); //判断按键是否被松开
// Serial.print("按键成功");
xunji();
Serial.print("循迹完成");
}
}
}
这个思路呢是来自于我当时备赛一个嵌入式比赛,也是一个关于小车的,然后这个代码是我接的一个单子,赚的外快,但是因为当时只写了代码,然后发给对方是能正常运行的,可能寻迹转弯有些小问题,因为我自己没有设备,所以就需要大家去摸索和改正了,但思路是完全没有问题的。