Arduino 寻迹小车+路径规划

文章介绍了如何使用STM32进行寻迹小车的路径规划,通过中断检测电平变化来判断黑线,结合寻迹和转弯函数,实现小车的自动化行驶。代码示例中涉及了红外传感器、电机控制和中断处理,适合于电子竞赛或嵌入式项目。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近临近电赛,往年都有小车题目。去年也做过小车的题目,但是当时奈何知识太浅,也查询了大量的资料也没有找到自己想要的,而自己经过学习,所有自己就分享关于寻迹小车路径规划的问题。

 寻迹对于的部分人来说应该都没有问题,我当时也是,可比如遇见下面这种路径规划,自己就犯了难,当时查询了很多资料也不明白怎么实现,自己对于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("循迹完成");
    }
  }
}

这个思路呢是来自于我当时备赛一个嵌入式比赛,也是一个关于小车的,然后这个代码是我接的一个单子,赚的外快,但是因为当时只写了代码,然后发给对方是能正常运行的,可能寻迹转弯有些小问题,因为我自己没有设备,所以就需要大家去摸索和改正了,但思路是完全没有问题的。

### PyCharm 打开文件显示不全的解决方案 当遇到PyCharm打开文件显示不全的情况时,可以尝试以下几种方法来解决问题。 #### 方法一:清理缓存并重启IDE 有时IDE内部缓存可能导致文件加载异常。通过清除缓存再启动程序能够有效改善此状况。具体操作路径为`File -> Invalidate Caches / Restart...`,之后按照提示完成相应动作即可[^1]。 #### 方法二:调整编辑器字体设置 如果是因为字体原因造成的内容显示问题,则可以通过修改编辑区内的文字样式来进行修复。进入`Settings/Preferences | Editor | Font`选项卡内更改合适的字号大小以及启用抗锯齿功能等参数配置[^2]。 #### 方法三:检查项目结构配置 对于某些特定场景下的源码视图缺失现象,可能是由于当前工作空间未能正确识别全部模块所引起。此时应该核查Project Structure里的Content Roots设定项是否涵盖了整个工程根目录;必要时可手动添加遗漏部分,并保存变更生效[^3]。 ```python # 示例代码用于展示如何获取当前项目的根路径,在实际应用中可根据需求调用该函数辅助排查问题 import os def get_project_root(): current_file = os.path.abspath(__file__) project_dir = os.path.dirname(current_file) while not os.path.exists(os.path.join(project_dir, '.idea')): parent_dir = os.path.dirname(project_dir) if parent_dir == project_dir: break project_dir = parent_dir return project_dir print(f"Current Project Root Directory is {get_project_root()}") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智奉工作室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值