一起玩儿物联网人工智能小车(ESP32)——49. 利用循迹模块实现循迹小车(四)

摘要:本文介绍循迹小车的软件实现方法

接下来就来实现具体的Car类了。在这个类中,包含了与小车相关的基本属性和方法。涉及到的属性包括以下这些:

  1. 控制两个轮子运动的GPIO引脚
  2. PWM信号分辨率
  3. PWM信号频率
  4. PWM的通道
  5. PWM占空比率

涉及到小车的行为方法包括:

  1. 向前行驶
  2. 停止
  3. 向左转弯
  4. 向右转弯
  5. 原地向左转弯
  6. 原地向右转弯

规划好属性和方法之后,就可以实现类的定义了。具体的定义如下所示:

/*********************************

    car.h

    by 一起玩儿科技   2024/01/16

 ********************************/

#pragma once

#ifndef _YQWKJ_CAR_

#define _YQWKJ_CAR_

#include <Arduino.h>

#define CAR_STOP 0

#define CAR_RUN 1

#define CAR_TURN_LEFT 2

#define CAR_TURN_LEFT_FAST 3

#define CAR_TURN_RIGHT 4

#define CAR_TURN_RIGHT_FAST 5

class Car {

  public:

    // 构造函数

    Car();    

    Car(uint8_t l1,uint8_t l2,uint8_t r1,uint8_t r2);

    // 初始化方法

    void begin();  

    void begin(uint32_t pwmFreq, uint8_t pwmResolutionsBit);  

    // 设置PWM通道  

    void setChannel(uint8_t c1,uint8_t c2,uint8_t c3,uint8_t c4);

    // 设置PWM占空比率

    void changeSpeed(uint32_t speedl,uint32_t speedr);

    // 向前行驶

    void run();

    // 停止行驶

    void stop();

    // 原地左转

    void turnLeftFast();

    // 原地右转

    void turnRightFast();

    // 左转

    void turnLeft();

    // 右转

    void turnRight();

  private:

    // 两轮的默认驱动引脚

    uint8_t l1=32,l2=33,r1=18,r2=23;    

    // PWM分辨率

    uint8_t pwmResolutionsBit=12;  

    // PWM频率    

    uint32_t pwmFreq=10000;  

    // PWM默认的通道          

    uint8_t channels[4]={0,1,2,3};    

    // PWM默认占空比率

    uint32_t speedl=pow(2,11),speedr=pow(2,11);  

    // 修改小车的行驶状态

    void changeStatus(uint32_t wl1,uint32_t wl2,uint32_t wr1,uint32_t wr2);

};

#endif

接下来就是实现这个类了,具体每个方法的编写方法都不复杂,都是以前见过的代码。具体实现方法如下:

/*********************************

    car.c

    by 一起玩儿科技   2024/01/16

 ********************************/

#include "car.h"

// 无参构造函数

Car::Car() {}

// 构造函数

Car::Car(uint8_t l1,uint8_t l2,uint8_t r1,uint8_t r2) {

  this->l1=l1;

  this->l2=l2;

  this->r1=r1;

  this->r2=r2;

}

// 初始化方法

void Car::begin() {

  uint8_t wheels_pin[] = {l1,l2,r1,r2};

  // 初始化LEDC PWM控制器

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

    ledcSetup(channels[i], this->pwmFreq, this->pwmResolutionsBit);

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

  }

}

// 初始化方法

void Car::begin(uint32_t pwmFreq, uint8_t pwmResolutionsBit) {

  this->pwmFreq=pwmFreq;

  this->pwmResolutionsBit=pwmResolutionsBit;

  begin();

}

// 设置PWM通道

void Car::setChannel(uint8_t c1,uint8_t c2,uint8_t c3,uint8_t c4) {

  channels[0]=c1;

  channels[1]=c2;

  channels[2]=c3;

  channels[3]=c4;

}

// 修改占空比分辨率,这将改变车轮的转速

void Car::changeSpeed(uint32_t speedl,uint32_t speedr) {

  this->speedl=speedl;

  this->speedr=speedr;

}

// 向前直行

void Car::run() {

  changeStatus(speedl, 0, speedr,0);

}

// 停止行驶

void Car::stop() {

  changeStatus(0,0,0,0);

}

// 左转

void Car::turnLeft() {

  changeStatus(0,0,speedr,0);

}

// 右转

void Car::turnRight() {

  changeStatus(speedl,0,0,0);

}

// 原地左转

void Car::turnLeftFast() {

  changeStatus(0,speedl,speedr,0);

}

// 原地右转

void Car::turnRightFast() {

  changeStatus(speedl,0,0,speedr);

}

// 改变PWM输出状态

void Car::changeStatus(uint32_t wl1,uint32_t wl2,uint32_t wr1,uint32_t wr2) {

  ledcWrite(channels[0], wl1);

  ledcWrite(channels[1], wl2);

  ledcWrite(channels[2], wr1);

  ledcWrite(channels[3], wr2);

}

Car类每个方法调用的函数都是之前多次使用过的,在这里就不再进一步的解释了。

接下来要实现的就是主程序了。在这个主程序的实现中,两个关键的地方就是初始化函数和中断函数。在实现这两个函数之前,先看一下这个程序中定义的常量,主要配置的内容就是接收循迹模块状态的GPIO引脚。如下所示:

// 配置GPIO

#define SENSOR_LEFT_D1    27

#define SENSOR_LEFT_D2    26

#define SENSOR_RIGHT_D1   21

#define SENSOR_RIGHT_D2   4

而程序用到的全局变量只有一个,就是生成了一个Car对象的实例,如下所示:

Car car;

程序的初始化工作主要包括以下一些内容:

  1. 初始化串口,主要为了输出调试信息
  2. 初始化小车对象
  3. 初始化循迹模块接入的引脚
  4. 绑定中断处理方法
  5. 小车的运动状态初始化

具体的实现代码如下:

void setup() {

  // put your setup code here, to run once:

  Serial.begin(115200);

  // 初始化小车对象的实例

  car.begin();

  pinMode(SENSOR_LEFT_D1,INPUT);

  pinMode(SENSOR_LEFT_D2,INPUT);

  pinMode(SENSOR_RIGHT_D1,INPUT);

  pinMode(SENSOR_RIGHT_D2,INPUT);

  delay(10000);   // 延迟小车运行

 

  // 绑定引脚中断

  attachInterrupt(SENSOR_LEFT_D1, tracking_isr, CHANGE);

  attachInterrupt(SENSOR_LEFT_D2, tracking_isr, CHANGE);

  attachInterrupt(SENSOR_RIGHT_D1, tracking_isr, CHANGE);

  attachInterrupt(SENSOR_RIGHT_D2, tracking_isr, CHANGE);

  // 初始化一下小车的运动状态

  tracking_isr();

}

接下来就是最后一个处理小车中断的方法tracking_isr()的实现了,在这个方法中,要实现之前规划的几种循迹模块状态对应的处理方法。因为具体的方法都已经实现了,在这里,只需要根据循迹模块的状态,调用相应的方法就可以了。具体的实现如下所示:

// 循迹模块状态变化的处理中断方法

void tracking_isr() {

  // 检测每个传感器是否在黑线上

  bool l1=digitalRead(SENSOR_LEFT_D1);

  bool l2=digitalRead(SENSOR_LEFT_D2);

  bool r1=digitalRead(SENSOR_RIGHT_D1);

  bool r2=digitalRead(SENSOR_RIGHT_D2);

  // car.run();

  if(l1&&l2&&r1&&r2 ) {

    // 向前直行

    car.run();

  } if(l1==false&&l2==false&&r1==false&&r2==false) {

    // 向前直行

    car.run();

  } else if(l1&&r1){

    // 向前直行

    car.run();

  } else if(l2) {

    // 原地左转

    car.turnLeftFast();

  } else if(l1) {

    // 左转

    car.turnLeft();

  } else if(r2) {

    // 原地右转

    car.turnRightFast();

  } else if(r1) {

    // 右转

    car.turnRight();

  }

}

好了,整个循迹小车的的功能实现就全部完成了。接下来就可以编译,上传程序,来进行测试一下了,看看是不是可以达到当初的设计目的了。

在进行测试和调试的过程中,需要注意以下几个地方:

  1. 首先应该进行模拟运行调试。用东西把小车支起来,让其车轮悬空,并可以自由的旋转。然后,在白纸上画好之前设计时的几种情况,然后放到循迹传感器的下边,首先保证循迹模块是设计时的状态,看一下,车轮的运转是不是按照预先设想的那样。如果,不是,应该分析代码,找出原因。
  2. 在模拟场景都通过的情况下,就可以到实际场地进行测试了。在测试之前,要把小车摆到轨迹线上,调整循迹模块的调节电位器,保证每一个循迹传感器都能正确的识别场地的轨迹线。同时还要考虑不同光线的影响,进行不同角度,不同位置的测试,确保循迹传感器可以可靠的反映出轨迹线来。
  3. 如果循迹模块的识别始终存在误判的情况,可以适当的增加或者减小循迹模块与地面的距离。通常循迹模块与地面的距离不大于2.5厘米。
  4. 要确保中间的两个循迹模块间的距离大于黑色轨迹线的宽度。也就是要保证两个传感器可以同时落在轨迹线的两侧。
  5. 刚开始调试的时候,要让小车的速度尽量的慢,等到初步测试都正常了,可以适当的调快行驶的速度。

好了,最后祝大家调试顺利!调试中遇到问题,可以给我留言。

  • 28
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 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、付费专栏及课程。

余额充值