esp8266无线小车
Posted 云中志
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了esp8266无线小车相关的知识,希望对你有一定的参考价值。
项目简介
本项目是基于esp8266
实现的无线小车控制,核心的原理是通过js
与esp8266
进行websocket
通信,前端页面模拟操作摇杆,生成操作数据,然后通过websocket
通信将控制数据发送至esp8266
,实现小车的无线控制
准备工作
硬件材料
用到的材料如下:
- esp8266开发板
- L9110电机驱动板
- 双马达小车
- 电脑 & 手机:有条件的话,
nginx
跑前端页面更好 - 充电宝:主要是给开发板工单,如果有其他电源也可以,电流可以稍微高一点,不然驱动电机比较吃力,或者驱动板单独供电
接线
本项目的接线非常简单,你只需要连接好L9110
的四根控制线即可,当然L9110
的电源需要5v
,小了驱动不了电机,节点线图我这里就不展示了,对应关系如下:
序号 | esp8266 | L9110 | 备注 |
---|---|---|---|
1 | GPIO02 (D4) | IA | 连接电机的一端 |
2 | GPIO00 (D3) | IB | 连接电机的一端 |
3 | GPIO13 (D7) | IIA | 连接电机的一端 |
4 | GPIO12 (D6) | IIB | 连接电机的一端 |
电机的转向,可以根据实际测试结果调整接线
代码
esp8266
首先是esp8266
的代码,这里我偷了个懒,直接复制oled
屏幕的代码,而且后面考虑将屏幕集成到小车上,所以代码里面也没有删除:
#include <Arduino.h>
#include <ArduinoWebsockets.h>
#include <ESP8266WiFi.h>
#include <SPI.h>; // 加载SPI库
#include <Wire.h>; // 加载Wire库
#include <Adafruit_GFX.h>; // 加载Adafruit_GFX库
#include <Adafruit_SSD1306.h>; // 加载Adafruit_SSD1306库
#include <ArduinoJson.h>
// 定义 OLED屏幕的分辨率
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);
// WiFi parameters
const char* ssid = "wifi名称";
const char* password = "wifi密码";
String ip = "";
using namespace websockets;
WebsocketsServer server;
// L9110s驱动板A-1A引脚,GPIO02 (D4)
const int IA = 2;
// L9110s驱动板A-1B引脚,GPIO00 (D3)
const int IB = 0;
// L9110s驱动板A-2A引脚 GPIO13 (D7)
const int IIA = 13;
// L9110s驱动板A-12B引脚 GPIO12 (D6)
const int IIB = 12;
// 电机的转速,范围是0-255,本次只有一个电机,所以只关注x轴
byte speed_x = 255; // change this (0-255) to control the speed of the motor
byte speed_y = 255;
StaticJsonDocument<64> doc;
void setup()
// 设置OLED的I2C地址
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
// 清空屏幕
display.clearDisplay();
// 设置字体大小
display.setTextSize(1);
// 设置字体颜色
display.setTextColor(SSD1306_WHITE);
// 设置开始显示文字的坐标
display.setCursor(0, 0);
// Connect to wifi
WiFi.begin(ssid, password);
// Wait some time to connect to wifi
for (int i = 0; i < 15 && WiFi.status() != WL_CONNECTED; i++)
Serial.print(".");
delay(1000);
ip = WiFi.localIP().toString();
// 输出的字符
display.println("IP: " + ip);
// 输出的字符
display.println("webSocket Server");
// 使更改的显示生效
display.display();
// 创建websocket服务器
server.listen(80);
// 设置波特率
Serial.begin(9600);
void loop()
auto client = server.accept();
if (client.available())
auto msg = client.readBlocking();
// return echo
client.send("Echo: " + msg.data());
// 序列化收到的消息
DeserializationError error = deserializeJson(doc, msg.data());
if (error)
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
// 移动的方向
String angle = doc["angle"]; // "up"
// 移动的距离
int distance = doc["distance"]; // 75
// close the connection
client.close();
String ipInfo = "IP: " + ip;
// 将ip信息输出到屏幕上
printText(ipInfo, 1);
printText("direction:" + angle + ", distance=" + distance, 2);
// 控制小车移动
carMove(angle, distance);
// 方向
delay(15);
// 向屏幕输出字符串
void printText(String text, int fontSize)
Serial.print("text:");
Serial.println(text);
display.setTextSize(fontSize); // 设置字体大小
display.setTextColor(SSD1306_WHITE); // 设置字体颜色
display.println(text); // 输出的字符
// 使更改的显示生效
display.display();
/**
小车移动速度
*/
void carMove(String direction, int distance)
speed_x = map(distance, 0, 75, 0, 255);
// 前进
if (direction.equals("up")) // 前进
analogWrite(IA, 0);
analogWrite(IB, speed_x);
analogWrite(IIA, 0);
analogWrite(IIB, speed_x);
else if (direction.equals("down")) // 后退
analogWrite(IA, speed_x);
analogWrite(IB, 0);
analogWrite(IIA, speed_x);
analogWrite(IIB, 0);
else if (direction.equals("right")) // 向右
// 获取速度模拟值
analogWrite(IA, 0);
analogWrite(IB, 0);
analogWrite(IIA, 0);
analogWrite(IIB, speed_x);
else if (direction.equals("left")) // 向左
analogWrite(IA, 0);
analogWrite(IB, speed_x);
analogWrite(IIA, 0);
analogWrite(IIB, 0);
else
analogWrite(IA, 0);
analogWrite(IB, 0);
analogWrite(IIA, 0);
analogWrite(IIB, 0);
Serial.print("speed:");
Serial.println(speed_x, DEC);
记得修改wifi
信息
控制端
这里的代码我就不展开讲了,只说核心的代码,如果没有任何前端基础,只是想控制小车的小伙伴,只需要将index.html
中script
中的ip
和端口换成自己的即可:
ws = new WebSocket("ws://192.168.0.100:80");
192.168.0.100
就是你的esp8266
的ip
,串口监视器会打印,端口代码默认写的是80
,可以根据自己的需要调整。
有技术基础和条件的小伙伴可以把项目部署起来跑,没条件的小伙伴打开index.html
也能操作,如果不知道如何使用nginx
,大家可以试下这个轻量级的文件服务器webd
,服务器本身只有94kb
,还支持多生态,局域网传文件也很方便:
页面也很简洁:
需要注意的是,这个工具需要简单配置用户名和密码:
用户名前面的是权限,权限的描述配置文件里面有注释,感兴趣的小伙伴自己研究。需要说明的是,服务器默认端口是9212
,所以我们的访问地址是电脑的ip
加9212
端口,之后输入我们的用户名和密码进行登录。
以win
环境为例,下载之后解压,配置完之后,直接双击webd.exe
双击运行即可,之后将我们的控制代码的文件夹phone-control
拖到web
目录下,之后通过浏览器访问就可以看到我们的页面,点击index.html
进行访问即可:
至此,这个项目就算结束了,其实在完成这个简单的示例之后,我是有考虑更高效的webRTC
通信的,奈何js
层面需要nodejs
加持,我觉得太复杂,最终放弃了,后面打算试下无线模块和esp32
,性能应该会比esp8266
好一点。
好了,今天的内容就到这里吧,感谢大家的支持,比心,有疑问可以评论区沟通哟
用ESP8266+android,制作自己的WIFI小车
由于官方的定时器做了改变,请自行改一下定时器函数
整体思路ESP8266作为TCP服务器,,手机作为TCP客户端,自己使用Lua直接做到了芯片里面,省了单片机,,节约成本,其实本来就是个单片机(感觉Lua开发8266真的很好,甩AT指令好几条街,,而且很容易上手,),不过呢,等几天我也会做一个51用AT指令的.....强烈建议学习使用Lua开发8266,不要偷懒.....如果谁说难我是不信,,那是因为没有认真去学....下面我会讲的很详细,,,,,让亲们感受一下Lua到底难不难......
因为最近看到朋友遇到各种各样的问题,,我会把遇到的问题统统说一下,,,,,,,
手机界面上放置四个按钮,代表前进,后退,左转,和右转,,,另外呢利用手机的重力感应传感器通过手机的倾斜角度控制小车的速度
前进,后退,左转,右转分别控制ESP8266的一个引脚,,,,速度数据呢是控制ESP8266一个引脚的PWM的占空比
连接
关于板子的引脚
如果发现轮子转的方向不对自己可以调换一下线哈,,,,,,,,,,
现在做ESP8266部分
第一件事情是刷固件
固件的自己可以去下载
官网下载地址
如果自己不想自己去下载或者说不愿意去尝试,那么可以下载我自己下载好的,,,,,每一次改变总需要一个开始......希望亲们自己去官网下载
链接:http://pan.baidu.com/s/1jICE1GM 密码:qn69
对了还有Lua开发的API文档
https://nodemcu.readthedocs.io/en/master/en/modules/gpio/
还有一个简洁版的API资料
链接:http://pan.baidu.com/s/1pL3FHgf 密码:l2nm
再者呢!有些时候需要写Lua语言自带的API函数
链接:http://pan.baidu.com/s/1pLjycR5 密码:qxk8
还有一个简洁版的
链接:http://pan.baidu.com/s/1o8T1nU6 密码:eglx
其实我也写了Lua的入门教程,,很多人都抱怨难难难,,现在自己用Lua开发却是得心应手,,正是之前所做过的那些努力,,当时也没人教自己,要知道自己花了1个多月才摸索到入门的,只感叹没有遇到引导者.....现在只想让别人不再走这么多的弯路,,,简直是煎熬......现在看来Lua开发8266真心不难....但是总需要经历一下过程........最起码最基本的语法还是要懂得吧.......其实只要知道语法,变量也就够了.....其余的就是调用调用
都不用选
然后就会出现下面的界面,,等着哈
选中地址下载就行
烧写固件的软件(一)
链接: http://pan.baidu.com/s/1cpnbVw 密码:2nha
烧写固件的软件(二)
链接:http://pan.baidu.com/s/1boBW4N1 密码:88my
无论哪一个软件,模块的接线都一样
GPIO0 默认是工作模式(不接线)。如果接了低电平就是下载模式(给模块刷固件!!)所以接低电平。CH_PD接高电平,其余除了TX,RX外可以不接线..
其实在模块上电的时候如果GPIO0是低电平那么模块就工作在等待刷固件模式,,,在模块上电的时候如果GPIO0是高电平那么模块就工作在正常工作模式,由于没有按键什么的,所以可以先接好线再上电
先用第一个软件刷固件
选中,,地址是0000
然后呢
然后,复位一下
看一下真实的连接
我的手机镜头晚上拍照感觉有一层东西...........
好了
现在看用第二个软件刷固件
选择固件
给大家各种模块的Flash大小的表
http://wiki.ai-thinker.com/_media/esp8266/esp8266_module_list.png
接上跳线帽,,然后,复位一下
好了
对了可能出现
这呢是串口模块和WIFI模块通信不稳定导致的,,,自己用ch340就出现过这种情况,,,,但是用pl2303就没有出现过,,,,对于这种情况,我感觉第一有条件可以换一个串口模块,比如pl2303,或者CP2102等等...再者呢可以选择好的杜邦线,,尽量短......
不过呢,,用pl2303下载好以后,,用ch340也可以了...............
对了也可以尝试
把这里改小一点
感觉只要不通信那么多数据,,也能减少出错的机会
现在用串口助手看一下
软件
链接:http://pan.baidu.com/s/1qYqh9O4 密码:ddva
如果出现--正在格式化文件系统就等着哈,,
大约不到一分钟
用Lua开发8622用这个软件
http://pan.baidu.com/s/1kVN09cr 密码:pfv7
如果点击的时候提示安装,,安装就行,,如果没有提示呢可以,按照下面链接的提示自己安装哈,,,,,或者自己百度
http://jingyan.baidu.com/article/3c343ff70bc6ea0d377963df.html
最新版本只有64位的
现在新建一个init.lua
如果出现
然后写上
gpio.write(8,0) gpio.write(7,0) gpio.write(6,0) gpio.write(5,0) gpio.mode(8,gpio.OUTPUT)--cs-- gpio.mode(7,gpio.OUTPUT)--mosi-- gpio.mode(6,gpio.OUTPUT)--miso-- gpio.mode(5,gpio.OUTPUT)--clk-- pwm.setup(4, 1000, 500) pwm.start(4)
一上电都是低电平保证不让小车动....
对了想控制GPIO15其实是写的
下面是对应关系
我是把8266的SPI引脚引出来了,不过呢,只是当普通引脚使用
想了解SPI可以看这篇文章
http://www.cnblogs.com/yangfengwu/p/7524297.html
现在看控制速度的PWM引脚
感觉初始化的时候,占空比应该为0(一直是低电平),这样的话小车保证不会动
大家看后面注释一定能看明白..........而且还有例子..........
如果出现
可以先复位一下然后再执行操
对了要是经常出现编译或者下载到模块出问题.........一定是串口模块和WIFI模块通信之间有问题.....尽量使用好的杜邦线,,,尽量短,,,,,再者可以考虑换成pl2303或者CP2102等.......因为自己测试的这两种模块比较可靠
因为GPIO2是WIFI模块上面的灯,,由于执行了PWM所以会看到这个这个灯微弱的发光
现在再新建一个wifi.lua
把下面的代码复制粘贴过去
详细可以参考我的这几篇(由于有些朋友说还是不够详细,,,,后期这几篇我会再在里面详细添加内容)
看完这几篇开发8266一定会让您感觉有了新的突破
一 http://www.cnblogs.com/yangfengwu/p/7514336.html 下载自己选择功能的固件,刷固件,写LUA的软件
二 http://www.cnblogs.com/yangfengwu/p/7520260.html GPIO,串口,注意事项,空闲中断
三 http://www.cnblogs.com/yangfengwu/p/7524297.html SPI通信介绍,,STM32 SPI 从机
四 http://www.cnblogs.com/yangfengwu/p/7524326.html TCP服务器,单个连接
五 http://www.cnblogs.com/yangfengwu/p/7531730.html TCP服务器,多个客户端连接,CRC校验
六 http://www.cnblogs.com/yangfengwu/p/7533302.html TCP Client 断开自动重连,AD采集
七 http://www.cnblogs.com/yangfengwu/p/7533845.html UDP支持一路默认,3路动态连接,ssid 与 pwd 的读取
八 http://www.cnblogs.com/yangfengwu/p/7534521.html ESP8266 文件保存数据(基于Lua脚本语言)
wifi.setmode(wifi.STATIONAP) cfg={} cfg.ssid="Hellow8266" cfg.pwd="11223344" wifi.ap.config(cfg) apcfg={} apcfg.ssid="qqqqq" apcfg.pwd="11223344" wifi.sta.config(apcfg) wifi.sta.connect() TCPSever=net.createServer(net.TCP,28800) TcpConnectCnt = 0 TcpSocketTable={} NowSocket=nil TCPSever:listen(8080,function(socket) if TcpConnectCnt == 4 then if TcpSocketTable[0] ~= nil then TcpSocketTable[0]:close() TcpSocketTable[0] = nil end else if TcpSocketTable[TcpConnectCnt+1] ~= nil then TcpSocketTable[TcpConnectCnt+1]:close() TcpSocketTable[TcpConnectCnt+1] = nil end end TcpSocketTable[TcpConnectCnt] = socket print(TcpConnectCnt.."-Connect") TcpConnectCnt = TcpConnectCnt + 1 if TcpConnectCnt == 5 then TcpConnectCnt = 0 end socket:on("receive",function(socket,data) NowSocket = socket uart.write(0,data) control(data) end) socket:on("disconnection",function(sck,c) for i=0,4 do if TcpSocketTable[i] == sck then TcpSocketTable[i] = nil print(i.."-Disconnect") end end end) end) function control(data) local RevLen = string.len (data) --[[ local i; local datatable={}; for i=1,RevLen do datatable[i] = data:byte(i); end print(CRC16Flage(datatable,6))]] local crc = ow.crc16(string.sub(data,1,RevLen-2)) local recrc = data:byte(RevLen) local recrc = recrc*256 local recrc = recrc + data:byte(RevLen-1) if crc == recrc then if RevLen == 6 then if data:byte(1) == 0xAA and data:byte(2) == 0x55 then stopcar = 0; if data:byte(3) == 0x01 then--forward gpio.write(8,1)--zuo qian gpio.write(7,0)--zuo hou gpio.write(6,1)--you qian gpio.write(5,0)--you hou --print("forward") end if data:byte(3) == 0x02 then--back gpio.write(8,0)--zuo qian gpio.write(7,1)--zuo hou gpio.write(6,0)--you qian gpio.write(5,1)--you hou --print("back") end if data:byte(3) == 0x03 then--right gpio.write(8,1)--zuo qian gpio.write(7,0)--zuo hou gpio.write(6,0)--you qian gpio.write(5,1)--you hou --print("right") end if data:byte(3) == 0x04 then--left gpio.write(8,0)--zuo qian gpio.write(7,1)--zuo hou gpio.write(6,1)--you qian gpio.write(5,0)--you hou --print("left") end if data:byte(3) == 0x05 then--stop gpio.write(8,0)--zuo qian gpio.write(7,0)--zuo hou gpio.write(6,0)--you qian gpio.write(5,0)--you hou --print("stop") end pwm.setduty(4, data:byte(4)*10) end end else if NowSocket ~= nil then --NowSocket:send("CRC16 Faild") NowSocket = nil end end end stopcar = 0; tmr.alarm(1, 100, 1, function() stopcar = stopcar + 1; if stopcar>3 then stopcar = 3; gpio.write(8,0)--zuo qian gpio.write(7,0)--zuo hou gpio.write(6,0)--you qian gpio.write(5,0)--you hou end end) --计算CRC function CRC16(modbusdata,length) local i=0;local j=0;local crc=0;local k=1;local l=1; for k=1 ,length do crc = bit.bxor(crc,modbusdata[k]) for l=1,8 do if bit.band(crc,1) == 1 then crc = bit.rshift(crc,1); crc = bit.bxor(crc,0xa001); else crc = bit.rshift(crc,1); end end end return crc; end function CRC16Flage(modbusdata,length) local Receive_CRC = 0;local calculation = 1; Receive_CRC = CRC16(modbusdata,length-2) calculation = modbusdata[length]; calculation = calculation * 256; calculation = calculation + modbusdata[length-1]; if Receive_CRC == calculation then return 1; else return 0; end end uart.on("data",0,function(data) for i=0,4 do if TcpSocketTable[i] ~= nil then TcpSocketTable[i]:send(data) end end end, 0) printip = 0 wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, function(T) printip = 0 end) wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function(T) if printip == 0 then print("+IP"..T.IP) end printip = 1 end)
用uart.write(0,data),,和print(data)的区别在于uart就相当于咱们单片机常用的串口发送.....而print相当于printf
而且这个print呢默认是遇到\'\\0\'就把这之前的数据发到串口,,所以呢有时候您定义的数据如果有\'0\',,,,那么这个\'0\'后面的数据就发不过去了........
有些人会问,为什么要这样做呢,,,函数为什么是这样....当然是看的API文档啦
API函数很多,,其实无论做什么东西您一定要知道自己想做什么东西,,需要什么功能,然后根据这些去找符合自己需求的API,自己心中一定要有数,,无论做什么东西都是这样...一定是自己先全方面的把握好整体,,然后再进行拆分成各个模块,然后再进行组合..............
所以自己做东西前一些天自己进度很慢很慢,我会考虑哪些模块自己并不会,但是一定会用到,我就会先攻克这块,一定是先把自己不懂或者不会的解决掉,因为如果不解决掉,这一块如果牵扯到别的模块就麻烦了....然后感觉可以了呢!就再花些时间整合一下系统,,,再考虑考虑整个系统所涉及的地方,,可能遇到的问题,尽量杀死在摇篮里面....然后呢就把整个系统做一下拆分,,,如何拆分就看自己的了,经验越多越拆分的合理......感觉可以了,,,开始干了,前期的投入就会发现大有成效,后期会节省很多时间........
很多人问我辞职原因:在我手里做的东西首先要让自己认可,解决当前的问题并不是我为了炫耀什么,这是我自己做东西的底线,我一直相信办法总比困难多,我要的是合作伙伴;我虽然都是自学的,但是我才会对整个系统把握的更好,因为我总是在做整个系统的东西;我从来不会拿公司项目开玩笑,我说在规定时间内能完成就绝对能完成;我要的是做好;解决一个技术难题我认为是自己应该做的,但绝对不会误期,因为如果我觉得会超过时间,我也就不会现在去解决了,我就会留到以后了;
解决的问题 :
http://www.cnblogs.com/yangfengwu/p/6870331.html
看看程序看一看哪里有不会的就赶紧去查资料哈......QQ号和群都在上面显示着呢
其实呢官方只是提供了这些API函数,,,具体里面实现什么具体功能就看自己的了......
现在看数据处理函数
function control(data) local RevLen = string.len (data) --[[ local i; local datatable={}; for i=1,RevLen do datatable[i] = data:byte(i); end print(CRC16Flage(datatable,6))]] local crc = ow.crc16(string.sub(data,1,RevLen-2)) local recrc = data:byte(RevLen) recrc = recrc*256 recrc = recrc + data:byte(RevLen-1) if crc == recrc then if RevLen == 6 then if data:byte(1) == 0xAA and data:byte(2) == 0x55 then stopcar = 0; if data:byte(3) == 0x01 then--forward gpio.write(8,1)--zuo qian gpio.write(7,0)--zuo hou gpio.write(6,1)--you qian gpio.write(5,0)--you hou --print("forward") end if data:byte(3) == 0x02 then--back gpio.write(8,0)--zuo qian gpio.write(7,1)--zuo hou gpio.write(6,0)--you qian gpio.write(5,1)--you hou --print("back") end if data:byte(3) == 0x03 then--right gpio.write(8,1)--zuo qian gpio.write(7,0)--zuo hou gpio.write(6,0)--you qian gpio.write(5,1)--you hou --print("right") end if data:byte(3) == 0x04 then--left gpio.write(8,0)--zuo qian gpio.write(7,1)--zuo hou gpio.write(6,1)--you qian gpio.write(5,0)--you hou --print("left") end if data:byte(3) == 0x05 then--stop gpio.write(8,0)--zuo qian gpio.write(7,0)--zuo hou gpio.write(6,0)--you qian gpio.write(5,0)--you hou --print("stop") end pwm.setduty(4, data:byte(4)*10) end end else if NowSocket ~= nil then --NowSocket:send("CRC16 Faild") NowSocket = nil end end end
我规定的
前进 0xAA,0x55,0x01,((传过来的数0-100,根据手机倾斜角度)速度PWM),CRC16低位,CRC16高位
后退 0xAA,0x55,0x02,((传过来的数0-100,根据手机倾斜角度)速度PWM),CRC16低位,CRC16高位
右转 0xAA,0x55,0x03,((传过来的数0-100,根据手机倾斜角度)速度PWM),CRC16低位,CRC16高位
左转 0xAA,0x55,0x04,((传过来的数0-100根据手机倾斜角度)速度PWM),CRC16低位,CRC16高位
停止 0xAA,0x55,0x05,((0)速度PWM),CRC16低位,CRC16高位
所以现在看一下
下面是自己写的CRC16校验,,对于不是提供了CRC16校验了,为什么还要自己写,...看下面哈
--计算CRC function CRC16(modbusdata,length) local i=0;local j=0;local crc=0;local k=1;local l=1; for k=1 ,length do crc = bit.bxor(crc,modbusdata[k]) for l=1,8 do if bit.band(crc,1) == 1 then crc = bit.rshift(crc,1); crc = bit.bxor(crc,0xa001); else crc = bit.rshift(crc,1); end end end return crc; end function CRC16Flage(modbusdata,length)//这个呢为了检测数据方便直接把数据往里面一丢,直接判断返回的如果是1说明crc正确,,否则0错误 local Receive_CRC = 0;local calculation = 1; Receive_CRC = CRC16(modbusdata,length-2) calculation = modbusdata[length]; calculation = calculation * 256; calculation = calculation + modbusdata[length-1]; if Receive_CRC == calculation then return 1; else return 0; end end
下面还有android的呢!!算法都一样,,,只不过会告诉亲们注意的问题
我重新把wifi,lua贴一下
wifi.setmode(wifi.STATIONAP) cfg={} cfg.ssid="Hellow8266" cfg.pwd="11223344" wifi.ap.config(cfg) apcfg={} apcfg.ssid="qqqqq" apcfg.pwd="11223344" wifi.sta.config(apcfg) wifi.sta.connect() TCPSever=net.createServer(net.TCP,28800) TcpConnectCnt = 0 TcpSocketTable={} NowSocket=nil TCPSever:listen(8080,function(socket) if TcpConnectCnt == 4 then if TcpSocketTable[0] ~=基于STM32设计的遥控小车(手机APP+GPS+温湿度+ESP8266)基于STM32设计的遥控小车(手机APP+GPS+温湿度+ESP8266)