一起玩儿物联网人工智能小车(ESP32)——35. 利用超声波传感器和舵机实现自动避障小车(三)

摘要:本文介绍如何使用超声波传感器和舵机实现小车的自动避障功能

接下来就来实现自动避障功能的主程序了。在之前的实验中,大家已经发现了,Arduino的主程序是由2个函数组成,一个是初始化的setup()函数,一个是主循环函数loop()。先来实现主函数setup()。

setup()函数主要是实现系统的初始化工作,这个函数在系统启动后被执行一次,用于完成各种资源的分配和相关功能的初始化。在这个避障小车中,主要涉及了控制行进的GPIO以及LEDC控制器的初始化、舵机的初始化和超声波传感器的初始化。下面就来看一下整个初始化代码。

void setup() {

  // 初始化串口

  Serial.begin(115200);

  // 初始化LEDC PWM控制器

  for (int i = 0; i < 4; i++) {

    ledcSetup(wheels_ch[i], MOTO_PWM_FREQ, MOTO_PWM_RESOLUTIONS_BIT);

    ledcAttachPin(wheels_pin[i], wheels_ch[i]);

  }

  // 初始化超声波传感器

  pinMode(ULTRASONIC_TRIG, OUTPUT);

  pinMode(ULTRASONIC_ECHO, INPUT);

  // 初始化舵机

  servo.attach(STEERING_ENGINE, MOTO_PWM_CH, 500, 2500);

  servo.write(STEERING_ENGINE, 90);

  delay(10000);   // 启动延时

  Serial.println("Setup finished!");

}

在上面的代码可以看到,初始化工作依次完成了以下这些内容:

  1. 初始化串口:这个主要是为了功能测试的时候,输出一些相关信息,方便程序的开发和调试工作。
  2. 初始化LEDC控制器:LEDC控制器的初始化按照之前的介绍就是2步:ledcSetup()函数用来设置LEDC控制器,ledcAttachPin()用来将控制器与GPIO引脚绑定。
  3. 初始化超声波传感器:主要用来设置超声波传感器的Trig控制引脚为输出,Echo控制引脚为输入模式。
  4. 初始化舵机:利用attach()设置了舵机工作的相关参数,然后的write()函数,让舵机回到初始向前的位置,使超声波传感器朝向正前方,为运行做好准备。
  5. Delay()函数在这里是一个便利性的设计,非必须的。它的目的是延长智能小车启动的时间,不让其在通电完成后就立刻开始向前行驶。因为setup()函数执行完毕后,立刻就会循环执行loop()函数,如果没有这个延时,小车立刻就要开始向前行进了。

接下来就来看一下主程序loop()函数,在这个函数中,只是调用了car_avoid_run()函数,如下所示:

void loop() {

  // put your main code here, to run repeatedly:

  car_avoid_run();

}

car_avoid_run()函数,这个函数是本程序的核心,用来完成一次超声波测距,然后再根据返回的障碍物的距离来决定下一步是需要转向行驶还是继续执行。程序的代码如下所示:

// 小车避障行驶

void car_avoid_run() {

  // 超声波测量前方障碍物的距离

  float dist = turn_check_distance(90);

  if (dist < DISTANCE_LIMIT) {      // 小于设定的停车距离

    car_stop();       // 小车停止前进

    dist = turn_check_distance(90);   //再次测量障碍物的距离

    if( dist<15 ) {       //如果距离前方障碍物小于15里面

      car_back(200);    //小车后退行驶200毫秒

    }

    //测量左右两侧的距离,返回下一步行驶的方向

    int d = find_direction();  

    car_turn(d);    //小车转向

  } 

  //小车继续行驶

  car_run();

}

在car_avoid_run()函数的执行逻辑如下:

  1. 利用turn_check_distance()函数得到正前方障碍物的距离
  2. 如果障碍物距离小于停车距离,那么通过find_direction()函数来决定下一步的行驶方向,并用car_turn()函数完成转向。
  3. 小车继续前行

turn_check_distance()函数有一个参数,这个参数用来指定测距的方向,也就是舵机需要转到哪个角度。需要注意的是,在这个小车中使用的是180度的舵机,因此90度为正前方,0度为左侧,180度为右侧。这个函数的实现方法如下:

// 转到某个方向,然后测量距离

float turn_check_distance(int direction) {

  //判断上次测量的是不是同一个方向

  if( lastDir!=direction ) {

    //不是同一个方向,则控制舵机旋转

    servo.write(STEERING_ENGINE,direction);

    delay(500);

    //记录本次测量的方向

    lastDir = direction;

  }

  //返回障碍物的距离

  return checkdistance();

}

在turn_check_distance()函数中,用到了之前定义的全局变量lastDir,这个变量用来记录上一次舵机的朝向,如果本次测量的方向与上一次相同,那么就不进行舵机的旋转操作了,提高了运行的效率。控制舵机的转向使用了Servo对象的write()方法,这个方法在之前已经介绍过了。在这里需要强调的是,舵机的旋转需要一定的时间,一定要等待舵机旋转完成之后,再进行超声波测距工作,这样测量的数据才能准确。

在这个函数的最后,是调用checkdistance()函数来测量前方障碍物的距离。

checkdistance()函数在之前也已经实现过了,是按照超声波测距模块的协议完成了一次超声波测距的工作,代码如下所示:

// 超声波测距函数

float checkdistance() {

  digitalWrite(ULTRASONIC_TRIG, LOW);

  delayMicroseconds(2);

  digitalWrite(ULTRASONIC_TRIG, HIGH);

  delayMicroseconds(10);

  digitalWrite(ULTRASONIC_TRIG, LOW);

  float distance = pulseIn(ULTRASONIC_ECHO, HIGH) / 58.00;

  delay(10);

  return distance;

}

接下来看一下car_stop()函数,这个函数用来停止小车的行驶。代码如下所示:

// 小车停止

void car_stop() {

  car_change_status(0,0,0,0);

}

car_stop()函数就是调用了car_change_status()函数,改变了小车轮子的运动状态。car_change_status()函数有4个参数,分别表示控制2个轮子的4个LEDC控制器的PWM占空比分辨率,用来调整4个轮子的转速。当这4个参数都是0时,小车停止运动。具体实现代码如下所示:

// 改变小车4轮的运行状态

void car_change_status(uint32_t wl1,uint32_t wl2,uint32_t wr1,uint32_t wr2) {

  ledcWrite(WL1_CHANNEL, wl1);

  ledcWrite(WL2_CHANNEL, wl2);

  ledcWrite(WR1_CHANNEL, wr1);

  ledcWrite(WR2_CHANNEL, wr2);  

}

其中的wl1和wl2用来控制左轮的运动状态,根据参数的不同组合可以实现左轮的向前、向后运动以及停止运动。同样的,wr1和wr2则是用来控制右轮的。

car_back()用来控制小车向后行驶,这个函数有一个参数,用于指定向后行驶的时间,单位是毫秒数,该函数的实现方法如下所示:

// 小车向后行驶

void car_back(int msSecond) {

  // 向后行驶指定的时间

  car_change_status(0,SPEED_L,0,SPEED_R);

  delay(msSecond);

  // 停止行驶

  car_stop();

}

find_direction()函数则用来找到下一步需要行驶的方向。它首先会测量左、右两侧障碍物的距离,然后如果两个距离都小于停车距离,那么小车下一步就掉头行驶,返回向后(也就是270度方向)。否则,返回障碍物距离远的那一侧(0为左侧、180为右侧)。实现方法如下:

// 得到前进的方向

int find_direction() {

  //测量左侧障碍物的距离

  float d0 = turn_check_distance(0);

  //测量右侧障碍物的距离

  float d180 = turn_check_distance(180);

  //判断两侧的障碍物距离是不是都小于停止距离

  if (d0 < DISTANCE_LIMIT && d180 < DISTANCE_LIMIT) {

    return 270;     //小车掉头行驶

  }

  return d0 > d180 ? 0 : 180;   //返回障碍物远的方向

}

实现小车转向的方法是由car_turn()函数来完成的,这个函数根据转向的角度,来控制2轮不同的转动方向来实现小车的转向,具体的实现方法如下:

// 小车转弯

void car_turn(int direction) {

  if (direction == 0) {   //向左转

    car_change_status(SPEED_L,0,0,SPEED_R);

    delay(TURN_TIME);

  } else if (direction == 180) {  //向右转

    car_change_status(0,SPEED_L,SPEED_R,0);

    delay(TURN_TIME);

  } else {  //掉头

    car_change_status(0,SPEED_L,SPEED_R,0);

    delay(TURN_TIME*2);

  }

  Serial.println(direction);

}

在这里需要提醒的是每个转向的运行时间是由后边的延时函数决定的,这是一个需要测量后的出来的时间,要根据个人的情况进行调整,如果转的角度大了,就把延迟时间调短些,如果转动角度小了,就把延迟时间调大些。

最后一个car_run()函数就是控制小车向前行驶。实现方法如下:

// 小车向前行驶

void car_run() {

  car_change_status(SPEED_L,0,SPEED_R,0);

}

好了,到这里,整个避障小车的代码就列举完了,可以把代码输入到Arduino IDE中,然后编译、上传,让自己的小车跑起来吧!

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
舵机超声波测距模块是STM32蓝牙控制循迹避障小车中常用的两个重要组件。 首先,舵机用于控制小车的转向。舵机通过PWM信号控制电机的转动角度,通过改变PWM信号的占空比,可以实现不同的转向角度。通常情况下,舵机的控制信号需要与STM32的定时器模块相连,通过调整定时器的周期和占空比,可以控制舵机的转向角度。在源代码中,通常会包括一些函数用于控制舵机的转向,如设置舵机转动角度等。 其次,超声波测距模块用于检测小车前方的障碍物距离。超声波测距模块通过发射超声波脉冲,然后检测超声波脉冲的回波时间,从而计算出前方障碍物的距离。在源代码中,通常会包括一些函数用于控制超声波测距模块的工作方式,如初始化超声波模块、发送超声波脉冲、接收回波信号等。 舵机超声波测距模块是实现循迹避障功能的关键组件之一。在源代码中,我们需要同时处理舵机超声波测距模块的数据,并根据测距结果调整舵机的转向角度。通过不断的测距和调整转向角度,小车可以根据前方障碍物的距离来做出合适的转向动作,从而实现循迹和避障的功能。 在实际应用中,舵机超声波测距模块的代码通常需要与其他组件的代码进行协调和集成,以实现整个小车的控制逻辑。通过合理的编程和调试,我们可以使得小车根据测距结果和算法判断,实现自动避障和循迹控制的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一起玩儿科技

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

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

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

打赏作者

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

抵扣说明:

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

余额充值