LeoCar:树莓派智能车——电控篇

⚡电控方案

运动模块

小车采用便宜的TT电机进行运动,通过TB6612FNG可以使得ESP32通过PWM控制电机进行调速。
TB6612FNG背面

  • TB6612FNG电机驱动模块的引脚如下:
引脚 连接 引脚 连接
PWMA 电机1的PWM输入 VM 电机的驱动电源(小于12V)
AIN2 电机1的逻辑2输入 VCC 该模块的供电(3.3V)
AIN1 电机1的逻辑1输入 GND
STBY 电机工作状态,1为工作,0为待机 AO1 电机1的输出,接电机正极
BIN1 电机2的逻辑1输入 AO2 电机1的输出,接电机负极
BIN2 电机2的逻辑2输入 BO2 电机2的输出,接电机负极
PWMB 电机2的PWM输入 BO1 电机2的输出,接电机正极
GND GND
  • 当IN1和IN2为00时电机不转,为01时电机正转,为10时电机反转

供电方案

我们采用18650锂电池(3.7V)两节串联的方案,提供7.4V的电压直接供给TB6612FNG的VM。再通过DC-DC降压模块进行降压后输出3.3V或者5V输出给ESP32或单片机等嵌入式设备。

  • 如图,输入端接电池正负极(电池盒子自带正负极的线),输出端接一个转接口将正负极双线转到MICRO-B口,以输出到嵌入式设备。我用的这个DC-DC四个口都有两个短接的焊盘方便扩展。输入端作为结点另外接到TB6612FNG的VM和GND,输出端的正极接给VCC。输出端电压可以通过拧动电位器调节。
    DC-DC降压模块
    双线转MICRO-B口

避障

添加一个超声波模块可以通过测距判断小车前部离障碍物的距离,当距离小于指定值时小车会停止。
超声波模块SRF05

  • 引脚功能:
  1. VCC和GND:接电源的正负极,也可接单片机的5V或3.3V,注意与单片机共地
  2. Trig:触发控制信号输入。通过这个引脚输入10us以上的高电平触发信号,然后模块自动发送8个40KHz的方波进行一次测距。
  3. Echo:回响信号接收。该引脚可以在接收到回响信号后输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。
  4. OUT:该引脚在手册中提到为开关量输出,可以做报警模块使用,应该是一个模块状态口,通过判断OUT的高低电平来判断模块是否上电,基本不用。

⚡ESP32

基于arduino开发平台实现用ESP32控制小车,同时我们可以通过BLE低功耗蓝牙在手机端控制。

总接线图

  • 先进行连线,结合之前的供电方案,完整接线如下,其中ESP32的接线可以根据代码自行更改,ESP32大部分引脚都可以输出PWM,可以很自由地更改引脚,图中接线和之后的代码是对应的。

总接线

代码

  • 代码如下,使用Arduino平台进行开发,主体结构分为蓝牙部分、电机控制部分,最后是Setup和loop函数。
  • 主函数流程也很简单:
  1. setup:初始化引脚输入输出状态,设置PWM引脚,初始化BLE;
  2. loop:通过蓝牙发送数据(如果需要的话),控制电机(输入命令和速度)
  3. BLE接收回调函数:解析信息,如果是小写字母就是控制命令,完成转向进退等操作;如果是数字就设置速度,1024最大,占空比是car_speed / 1024 × 100% ≈ car_speed / 1000 × 100%
  4. ultrasound:超声波部分,ESP32引脚向TRIG发送一个高电平,然后ECHO在接受超声波后会向ESP32发送一个与距离成正比的高电平,我们只需要获得这个高电平时长,即可通过公式距离 = 时长 * 0.034 / 2获得实际距离(cm)。由于倒车和转圈时不需要进行避障所以不会急停。
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <String.h>

//TB6612FNG驱动模块控制信号 共6个
#define IN1 26  //控制电机1的方向A,01为正转,10为反转 
#define IN2 25  //控制电机1的方向B,01为正转,10为反转 
#define IN3 14  //控制电机2的方向A,01为正转,10为反转 
#define IN4 12  //控制电机2的方向B,01为正转,10为反转 

#define PWMA 33  //控制电机1 PWM控制引脚
#define PWMB 13 //控制电机2 PWM控制引脚
#define STBY 27 //工作与待机

#define freq 20000     //PWM波形频率5KHZ
#define pwm_Channel_1  0 //使用PWM的通道0
#define pwm_Channel_2  1 //使用PWM的通道1

#define resolution  10    //使用PWM占空比的分辨率,占空比最大可写2^10-1=1023

#define trigPin  22
#define echoPin  23

int car_speed = 100;
char state = 'e';
/**************************************************************************
蓝牙BLE部分
**************************************************************************/
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
uint8_t txValue = 0;
long lastMsg = 0;//存放时间的变量 
String rxload;
String receive_msg;
float x=0,y=0;

#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };
    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};
 
class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = pCharacteristic->getValue();
      if (rxValue.length() > 0) {
        receive_msg = "";
        for (int i = 0; i < rxValue.length(); i++)
         {
          receive_msg += (char)rxValue[i];
          Serial.print(rxValue[i]);
         }
         Serial.println("");
      if(islower(receive_msg.charAt(0))){          //是小写字母
        state = receive_msg[0];                      //控制
      }
      else{
        car_speed = receive_msg.toInt();     //转数字,修改速度
      }
      }
    }
};
 
void setupBLE(String BLEName){
  const char *ble_name=BLEName.c_str();
  BLEDevice::init(ble_name);
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  BLEService *pService = pServer->createService(SERVICE_UUID);
  pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX,BLECharacteristic::PROPERTY_NOTIFY);
  pCharacteristic->addDescriptor(new BLE2902());
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX,BLECharacteristic::PROPERTY_WRITE);
  pCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}
/**************************************************************************
函数功能:赋值给PWM寄存器 
入口参数:左轮PWM、右轮PWM
返回  值:无
**************************************************************************/
void Set_Pwm(int moto1, int moto2)
{
  int Amplitude = 1000;  //===PWM满幅是1024 限制在950
  
  if (moto1 > 0) {
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);
  } else {
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, HIGH);
  }
  
  if (moto2 > 0) {
    digitalWrite(IN3, LOW);
    digitalWrite(IN4, HIGH);
  } else {
    digitalWrite(IN3, HIGH);
    digitalWrite(IN4, LOW);
  }
  
  //功能:限制PWM赋值 
  if (moto1 < -Amplitude)  moto1 = -Amplitude;
  if (moto1 >  Amplitude)  moto1 =  Amplitude;
  if (moto2 < -Amplitude)  moto2 = -Amplitude;
  if (moto2 >  Amplitude)  moto2 =  Amplitude;
  
  //赋值给PWM寄存器 
  ledcWrite(pwm_Channel_1, abs(moto1));
  ledcWrite(pwm_Channel_2, abs(moto2));
}
void control(char command, int carspeed){
  if(command=='a'){
    Set_Pwm(carspeed, carspeed);      //前
  }
  else if(command=='b')
    Set_Pwm(-carspeed, -carspeed);    //后
  else if(command=='c')
    Set_Pwm(carspeed*0.8, carspeed);  //左
  else if(command=='d')
    Set_Pwm(carspeed, carspeed*0.8);  //右
  else if(command=='e')
    Set_Pwm(0, 0);                      //停
  else if(command=='f')
    Set_Pwm(carspeed/2.0, -carspeed/2.0); //原地转
}
void ultrasound(){      //超声波
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  //计算超声波回波的时间
  long duration = pulseIn(echoPin, HIGH);
  
  //计算物体的距离(cm)
  float distance = duration * 0.034 / 2;
  if(distance < 20 && (state != 'f' && state != 'b'))
    state = 'e';         //除了倒车、转圈都停止
  //输出物体的距离
  Serial.print("distance:");
  Serial.println(distance);
  delay(100);
}
/*********************************setup**********************************/
void setup()
{
    pinMode(IN1, OUTPUT);          //TB6612控制引脚,控制电机1的方向,01为正转,10为反转
    pinMode(IN2, OUTPUT);          //TB6612控制引脚,
    pinMode(IN3, OUTPUT);          //TB6612控制引脚,控制电机2的方向,01为正转,10为反转
    pinMode(IN4, OUTPUT);          //TB6612控制引脚,
    pinMode(PWMA, OUTPUT);         //TB6612控制引脚,电机PWM
    pinMode(PWMB, OUTPUT);         //TB6612控制引脚,电机PWM
    pinMode(STBY, OUTPUT);

    pinMode(trigPin, OUTPUT);     //超声波
    pinMode(echoPin, INPUT);

    digitalWrite(IN1, LOW);       //TB6612控制引脚拉低
    digitalWrite(IN2, LOW);       //TB6612控制引脚拉低
    digitalWrite(IN3, LOW);       //TB6612控制引脚拉低
    digitalWrite(IN4, LOW);       //TB6612控制引脚拉低
    digitalWrite(STBY, HIGH);
  
    ledcSetup(pwm_Channel_1, freq, resolution); //PWM通道一开启设置
    ledcAttachPin(PWMA, pwm_Channel_1);     //PWM通道一和引脚PWMA关联
    ledcWrite(pwm_Channel_1, 0);        //PWM通道一占空比设置为零
    
    ledcSetup(pwm_Channel_2, freq, resolution); //PWM通道二开启设置
    ledcAttachPin(PWMB, pwm_Channel_2);     //PWM通道二和引脚PWMB关联
    ledcWrite(pwm_Channel_2, 0);        //PWM通道二占空比设置为零
    
    Serial.begin(115200);
    setupBLE("LEO_BLE");//设置蓝牙名称

}

/************************************loop************************************/
void loop()
{
    long now = millis();//记录当前时间
    if (now - lastMsg > 500) 
    {//每隔1秒发一次信号  
        if (deviceConnected&&rxload.length()>0) {
            String str=rxload;
          const char *newValue=str.c_str();
          pCharacteristic->setValue(newValue);
          pCharacteristic->notify();
          Serial.println(str);
        }
      lastMsg = now;//刷新上一次发送数据的时间
    }
    ultrasound();
    control(state, car_speed);
}

⚡结果展示

  • 完成小车结构和电路搭建后,烧录ESP32代码,小车启动;
    小车
  • 在手机上使用蓝牙软件(要支持BLE而非经典蓝牙)连接BLE,发送数字设置速度,发送字母控制小车动作(这里用快捷按钮设置发送的字母),结果如下。
    蓝牙控制小车
    小车避障急停
  • 至此我们使用ESP32完成了对供电方案和结构的验证,使得小车能够正常跑起来,后续我们将用之前的树莓派及摄像头替换ESP32实现相同的控制的基础上增加视频流的使用。
  • Copyrights © 2023-2025 LegendLeo Chen
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信