本帖最后由 suncat0504 于 2022-7-25 08:12 编辑
#申请原创# @21小跑堂 上次测试中,简单搭建了一个通过串口控制小车移动的测试环境。在确认没有问题的基础上,把相关模块组装起来,形成一个独立的小车。 这一次,引入ESP8266WIFI模块,通过编程ESP8266,使之工作于AP模式并启动WEB服务。ESP8266会建立一个名为“WIFI_CAR_ESP8266”的WIFI网络,访问密码为“12345678”。 使用手机接入ESP8266的Wifi网络(访问网址192.168.4.1),进入指定网址后,在这个网页提供了5个按钮,分别对应于小车的前进、后退、左转、右转、停止这五个简单的操作。 在网页点击对应的按钮时,ESP8266WIFI模块收到无线指令后,会通过ESP8266WIFI模块本身提供的一个串口,发出对应于小车动作的操作命令串。这个命令串遵循上次测试中的串口接收指令,这样原来的程序不需要做改动,就能直接用于测试。前提是把ESP8266的串口输出接到开发板的PA09上。 网页主代码如下: #include <ESP8266WiFi.h>
const char index_html[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="/css/bootstrap.css">
<title>wifi 遥控小车</title>
</head>
<body>
<div id="app">
<div class="alert alert-primary" role="alert">
<h1 class="display-4">WIFI car</h1>
</div>
<div class="container">
<div>
<div class="row justify-content-center">
<div class="col col-2">
<button class="btn btn-primary btn-lg" @click="forward()">
<span>前进</span>
</button>
</div>
</div>
<div class="row justify-content-center my-3">
<div class="col col-2">
<button class="btn btn-primary btn-lg" @click="left()">
<span>左转</span>
</button>
</div>
<div class="col col-2">
<button class="btn btn-primary btn-lg" @click="stop()">
<span>停止</span>
</button>
</div>
<div class="col col-2">
<button class="btn btn-primary btn-lg" @click="right()">
<span>右转</span>
</button>
</div>
</div>
<div class="row justify-content-center">
<div class="col col-2">
<button class="btn btn-primary btn-lg" @click="backward()">
<span>后退</span>
</button>
</div>
</div>
</div>
</div>
</div>
<script src="/js/vue.js"></script>
<script src="/js/jquery.js"></script>
<script src="/js/popper.js"></script>
<script src="/js/bootstrap.js"></script>
<script src="/js/axios.js"></script>
<script>
new Vue({
el: '#app',
methods: {
forward() {
axios.get('/move?dir=F')
.then((res) => console.log(res.data))
.catch(() => console.log('出错了。'))
},
backward() {
axios.get('/move?dir=B')
.then((res) => console.log(res.data))
.catch(() => console.log('出错了。'))
},
left() {
axios.get('/move?dir=L')
.then((res) => console.log(res.data))
.catch(() => console.log('出错了。'))
},
right() {
axios.get('/move?dir=R')
.then((res) => console.log(res.data))
.catch(() => console.log('出错了。'))
},
stop() {
axios.get('/move?dir=S')
.then((res) => console.log(res.data))
.catch(() => console.log('出错了。'))
}
},
});
</script>
</body>
</html>
)=====";
可以看到五个按钮对应的五个动作中,分别执行了forward、left、right、backward、stop函数,函数处理中向服务器端发动的数据中心,对dir参数进行不同的赋值。这样在服务器端通过request->getParam(“dir”),就可以获得操作网页上的按钮按下的情况。服务器端收到数据后,根据解析结果,向串口发出ATCx数据。其中的“ATCx”(x=0-9,A-Z),就是模拟上次测试中用到的串口通讯指令。Serial.println本身会提供换行符,所以就不用专门追加“\n”了。 在开发板的处理程序中,串口收到的数据经过以下处理函数,向电机驱动板发出动作指令: // 执行串口发过来的指令
void executeComCommand(void) {
if (cmdRxBuf[0]=='A' && cmdRxBuf[1]=='T') {
if (cmdRxBuf[2]=='C') {
if (cmdRxBuf[3]=='0') {
// 驱动向小车向前走1S, 此处暂时不设置时间, TODO
LED2_TOG();
car_forward();
display_string_16x16(0, 2, "forward ");
} else if (cmdRxBuf[3]=='1') {
LED2_TOG();
car_back();
display_string_16x16(0, 2, "Back ");
} else if (cmdRxBuf[3]=='2') {
LED2_TOG();
car_forward_left();
display_string_16x16(0, 2, "forward left ");
} else if (cmdRxBuf[3]=='3') {
LED2_TOG();
car_forward_right();
display_string_16x16(0, 2, "forward right ");
} else if (cmdRxBuf[3]=='4') {
LED2_TOG();
car_fast_forward_left();
display_string_16x16(0, 2, "fast forward left ");
} else if (cmdRxBuf[3]=='5') {
LED2_TOG();
car_fast_forward_right();
display_string_16x16(0, 2, "fast forward right ");
} else if (cmdRxBuf[3]=='6') {
LED2_TOG();
car_forward_left();
display_string_16x16(0, 2, "back left ");
} else if (cmdRxBuf[3]=='7') {
LED2_TOG();
car_forward_right();
display_string_16x16(0, 2, "back right ");
} else if (cmdRxBuf[3]=='8') {
LED2_TOG();
car_fast_forward_left();
display_string_16x16(0, 2, "fast back left ");
} else if (cmdRxBuf[3]=='9') {
LED2_TOG();
car_fast_forward_right();
display_string_16x16(0, 2, "fast back right ");
} else if (cmdRxBuf[3]=='A' || cmdRxBuf[3]=='a') {
LED2_TOG();
car_stop();
display_string_16x16(0, 2, "stop ");
}
}
delay1ms(1000);
car_stop();
}
}
程序中,利用LED2来显示串口数据的解析情况,同时通过display_string_16x16把解析结果显示在液晶上。因为每个动作被执行1000毫秒后,就停止,所以对“stop”的解析处理就没有什么实际意义了。这么做的原因是为了调试时,避免小车跑不停,毕竟是连着JLINK调试的嘛。脱离JLINK测试时,可以把这两行代码注释掉。 为了节省空间,这个小车只用一节18650电池,通过升压模块提高输出电压为8V,然后在通过7805降压得到5V电源。之所以这么做,而不是直接升压到5V给开发板工作,是因为以下2个原因: 1、直接使用升压的5V,如果升压模块出异常导致输出电压升高,会烧毁开发板。 2、电机驱动板也使用5V电源,电压也不能太高。 开发板本身提供了一个DC输入的接口CN24,根据资料: 本来预计通过开发板提供DCIN接口,在不改动J24的跳线,依旧默认给微处理器提供3.3V电压。我的液晶显示模块也是用3.3V,电压不能用5V,以免烧坏液晶(其实有没有液晶,都不会影响遥控小车的运行,只是考虑到调试目的以及查看中间处理结果,由液晶显示会方便很多)。结果实测,在DCIN端接入5V后,开发板本身的电源时指示灯LED3并没有亮。 通过和芯源的工程师沟通,了解到: 使用DCIN作为输入电源的时候,J24需要改跳线到5-6上,这时开发板及微处理器的电源为5V,开发板提供的VDD输出针脚也是5V。但此时J24的1脚因为是接在3.3V稳压器的输出上,所以使用这个针脚是可以得到3.3V的(实测只有1.1V左右)。但是考虑到我的液晶只能工作于3.3V,其数据接口最好也工作于3.3V的逻辑电平上,基于这个考虑,还是要准备一块能提供3.3V的电源板,为开发板专门提供3.3V的电源吧。目前这种调试状态,暂时使用JLINK提供的工作电源。 因为是简单的动作,在电机转动过程中,并没有统计转动角度或者计数脉冲,所以还无法精确控制前进/后退的步数以及左右转动的角度,必须要追加更多的检测装置才行。只有亲自自己动手了,才会发现哪怕做一件小事儿也没那么容易。很多细节的东西,只有在实践中,才会得到深切的体会。进而想到,这个社会上的任何一点科技的进步,都是靠着工程师们在技术上的一点一点积累而实现的,从没有一蹴而就的强大。在此,向那些硬件工程师们致以真诚的敬意!
以下附上所有代码(含wifi端Arduino代码)
|