零知两轮小车入门版(ESP32主控)教程3-手机WiFi/蓝牙控制小车

本系列教程讲解零知小车套件以零知迷你板为主控,使用零知开源平台进行智能小车开发。

使用的硬件:零知智能小车套件-http://www.lingzhilab.com/index.php/home/goods/introduction?gid=1365


实现的功能:红外循迹、超声避障、直线运行、手机蓝牙控制等基本功能。

扩展:可以在小车上加入其它传感器模块进行扩展,比如加入摄像头模块进行监控、加入火焰传感器做灭火小车、加入更多超声波模块实现自动跟随...


本系列教程目录

零知两轮小车入门版(ESP32主控)教程1-小车组装

/lzbbs/html/car/c2/car1.html


零知两轮小车入门版(ESP32主控)教程2-让小车跑起来

/lzbbs/html/car/c2/car2.html


零知两轮小车入门版(ESP32主控)教程3-手机WiFi/蓝牙控制小车

/lzbbs/html/car/c2/car3.html


零知两轮小车入门版(ESP32主控)教程4-超声波自动避障

/lzbbs/html/car/c2/car4.html


零知两轮小车入门版(ESP32主控)教程5-红外循迹

/lzbbs/html/car/c2/car5.html


零知两轮小车入门版(ESP32主控)教程6-使用PID走直线

/lzbbs/html/car/c2/car6.html

一、工具材料

(1)组装好的智能小车
(2)零知ESP32
(3)安卓手机+零知星球APP


二、程序代码

ESP32自带WiFi和蓝牙,所以使用ESP32做为主控板无需另接WiFi或蓝牙模块用以控制。手机WiFi/蓝牙控制2轮的程序代码实现如下:

							
							
	/**********************************************************
	*    文件: 4WD_car.ino      by 零知实验室([url=http://www.lingzhilab.com]www.lingzhilab.com[/url])
	*    -^^- 零知开源,让电子制作变得更简单! -^^-
	*    时间: 2019/11/19 16:35
	*    说明:
	************************************************************/
	  
	#define Bluetooth   // 若使用蓝牙连接,取消此条注释
	  
	#ifdef Bluetooth
	#include <BLEDevice.h>
	#include <BLEUtils.h>
	#include <BLEServer.h>
	  
	//使用其他蓝牙软件需修改此识别码
	#define SERVICE_UUID        "0000ffe0-0000-1000-8000-00805f9b34fb"
	#define CHARACTERISTIC_UUID "0000ffe1-0000-1000-8000-00805f9b34fb"
	  
	bool deviceConnected = false;
	#else
	#include <WiFi.h>
	#include <WiFiMulti.h>
	  
	WiFiMulti WiFiMulti;
	  
	//修改成你的WiFi账号密码
	#define SSID "xxx"
	#define PASSWD "xxx"
	  
	const uint16_t port = 6666;  //服务器端口号
	const char *host = "192.168.0.102";  //服务器IP地址
	  
	WiFiClient ESP32CAR;  //创建WiFi客户端实例
	#endif
	 
	//创建字符串变量存储接收到的信息
	String str;
	String pitch;
	String roll;
	  
	//设置电机引脚
	#define LEFT_MOTO1  32
	#define LEFT_MOTO2  33
	#define RIGHT_MOTO1 25
	#define RIGHT_MOTO2 26
	  
	//#define LEFT_MOTO1  27
	//#define LEFT_MOTO2  14
	//#define RIGHT_MOTO1 12
	//#define RIGHT_MOTO2 13
	  
	#ifdef Bluetooth
	class MyCallbacks: public BLECharacteristicCallbacks {
	        void onConnect(BLEServer* pServer) {
	                deviceConnected = true;
	        };
	          
	        void onDisconnect(BLEServer* pServer) {
	                deviceConnected = false;
	        };
	          
	        void onWrite(BLECharacteristic *pCharacteristic) {
	                std::string value = pCharacteristic->getValue();  //获取蓝牙发送过来的信息
	                //对接收到的信息进行处理
	                for(int i = 0;i<10;i++)
	                {
	                        str += value[i];
	//                        Serial.print(value[i]);
	                }
	                int pos1 = str.indexOf("(");  //检索"("在字符串中的位置
	                int pos2 = str.indexOf(",");
	                int pos3 = str.indexOf(")");
	                pitch = str.substring(pos1+1,pos2);  //将两个位置之间的字符串提取出来
	                roll = str.substring(pos2+1,pos3);
	                str = "";  //清空接收到的信息以存储下一次的信息
	                Serial.print("pitch:");
	                Serial.print(pitch);
	                Serial.print("  roll:");
	                Serial.println(roll);
	        }
	};
	#endif
	  
	void setup() {
	        Serial.begin(9600);
	        pinMode(LEFT_MOTO1,OUTPUT);
	        pinMode(LEFT_MOTO2,OUTPUT);
	        pinMode(RIGHT_MOTO1,OUTPUT);
	        pinMode(RIGHT_MOTO2,OUTPUT);
	  
	        //设置引脚输出PWM的通道
	        ledcAttachPin(LEFT_MOTO1,1);
	        ledcAttachPin(LEFT_MOTO2,2);
	        ledcAttachPin(RIGHT_MOTO1,3);
	        ledcAttachPin(RIGHT_MOTO2,4);
	        ledcSetup(1, 12000, 8);
	        ledcSetup(2, 12000, 8);
	        ledcSetup(3, 12000, 8);
	        ledcSetup(4, 12000, 8);
	  
	        #ifdef Bluetooth
	        BLEDevice::init("ESP32_car");  //初始化蓝牙,参数为蓝牙名称
	        BLEServer *pServer = BLEDevice::createServer();  //创建蓝牙服务器
	  
	        BLEService *pService = pServer->createService(SERVICE_UUID);  //创建蓝牙Service服务
	  
	         //设置蓝牙功能为读/写
	        BLECharacteristic *pCharacteristic = pService->createCharacteristic(
	        CHARACTERISTIC_UUID,
	        BLECharacteristic::PROPERTY_READ |
	        BLECharacteristic::PROPERTY_WRITE
	        );
	  
	        pCharacteristic->setCallbacks(new MyCallbacks());  //设置回调函数
	  
	        pService->start();  //启动服务
	  
	        BLEAdvertising *pAdvertising = pServer->getAdvertising();
	        pAdvertising->start();
	  
	        Serial.println("蓝牙已开启!");
	        #else
	        WiFiMulti.addAP(SSID,PASSWD);  //连接WiFi
	        Serial.println("等待WiFi... ");
	    //等待wifi连接成功
	    while (WiFiMulti.run() != WL_CONNECTED) {
	        Serial.print(".");
	        delay(500);
	    }
	  
	    Serial.println("");
	    Serial.println("WiFi连接成功");
	    Serial.print("IP地址: ");
	    Serial.println(WiFi.localIP());
	  
	        while(!ESP32CAR.connect(host, port)) {  //连接服务器
	                Serial.println("连接失败");
	                Serial.println("等待5秒...");
	                delay(5000);
	    }
	        Serial.print("成功连接到: ");
	        Serial.println(host);
	        #endif
	  
	    delay(500);
	}
	  
	void loop() {
	        #ifdef Bluetooth
	        carRun(pitch.toInt(),roll.toInt());
	        #else
	        if(ESP32CAR.available()){
	                getCommand();
	                carRun(pitch.toInt(),roll.toInt());
	        }
	        #endif
	}
	  
	#ifndef Bluetooth
	//获取WiFi发送过来的pitch,roll
	void getCommand(){
	        str = "";
	        while(ESP32CAR.available()) {
	                char c = ESP32CAR.read();
	                str+=c;
	        }
	        int pos1 = str.indexOf("(");
	        int pos2 = str.indexOf(",");
	        int pos3 = str.indexOf(")");
	        pitch = str.substring(pos1+1,pos2);
	        roll = str.substring(pos2+1,pos3);
	        Serial.print("pitch=");
	        Serial.print(pitch);
	        Serial.print("  roll=");
	        Serial.println(roll);
	}
	#endif
	  
	void carRun(int rate,int extent){
	        //将接收到的pitch映射到控制电机转速的pwm值,roll映射到单个轮子的pwm值
	        int speed = map(rate,15,90,100,250);
	        int right = map(extent,15,90,speed,80);
	        int left = map(extent,-90,-15,80,speed);
	  
	        if(extent>-15&&extent<15&&rate>15){
	                Serial.println("前进");
	                motoRun(speed,speed);
	        }
	        if((extent>165||extent<-165)&&rate>10){
	                Serial.println("后退");
	                motoRun(-speed,-speed);
	        }
	        if(extent>15&&extent<90&&rate>15){
	                Serial.println("右转弯");
	                motoRun(speed,right);
	        }
	        if(extent<-15&&extent>-90&&rate>15){
	                Serial.println("左转弯");
	                motoRun(left,speed);
	        }
	        if(rate<15){
	                Serial.println("停车");
	                motoStop();
	        }
	}
	  
	//控制电机,正值前进,负值后退
	void motoRun(int speedL,int speedR){
	        if(speedL>0){
	                ledcWrite(1,0);
	                ledcWrite(2,speedL);
	        }else{
	                ledcWrite(1,-speedL);
	                ledcWrite(2,0);
	        }
	        if(speedR>0){
	                ledcWrite(3,0);
	                ledcWrite(4,speedR);
	        }else{
	                ledcWrite(3,-speedR);
	                ledcWrite(4,0);
	        }
	  
	}
	  
	//停车
	void motoStop(){
	        ledcWrite(1,0);
	        ledcWrite(2,0);
	        ledcWrite(3,0);
	        ledcWrite(4,0);
	}
							

将以上代码验证上传至ESP32开发板上。

然后我们打开零知星球APP,找到如下页面:

点击右上角的更多,选择连接方式,若使用WiFi连接,在WiFi设置页面选择TCP服务器,填好端口号,点击连接。

若使用蓝牙连接,请打开蓝牙和定位服务扫描蓝牙

扫描到"ESP32_car"这个蓝牙后点击连接即可。

这里我们使用的操作模式是重力感应模式,选择操作模式为重力感应模式,命令设置无需填写

点击开始进入如下页面。

然后点击下面的开启命令发送,就可用手机重力感应来遥控小车了。

手机头部逐渐抬高,小车会逐渐加速;向左偏,小车就向左转弯,向右偏,即向右转弯;且偏转角度越大,转弯半径越小,完成转弯更快。