项目背景
在现代社会中,远距离通信和远程操作已经成为了人们工作和生活的重要需求。然而,传统的通信和遥控设备在距离和灵活性方面存在限制,无法满足人们对无限制距离通信和操作的需求。因此,开发一种无限制距离视频语音对讲小车的项目应运而生。
这个项目旨在设计和制造一款能够实现无限制距离视频和语音通信的小车。通过使用先进的通信技术和互联网连接,该小车可以让用户随时随地进行远程监控、交流和操作。
以下是项目背景的几个重要方面:
跨地域的合作与救援:在商务领域中,企业之间常常需要进行跨地域合作。传统的通信方式会受到地理距离的限制,而无限制距离视频语音对讲小车可以解决这个问题,让合作者们能够实时交流、共享信息,并远程执行各种任务。此外,对于救援行动来说,这款小车可以让救援人员与远程人员进行实时对话和指挥,提高救援效率。
危险环境下的操作与监控:一些工作环境常常存在危险和风险,例如化学工厂、核电站等。在这些场景中,无限制距离视频语音对讲小车可以让工作人员保持安全的距离,并通过小车上的摄像头和麦克风进行实时监控和操作。
远程教育与学习体验:随着远程教育的兴起,学生们可以参与来自全球各地的课程。无限制距离视频语音对讲小车可以为学生们提供更真实的学习体验,例如参观远程地点或实验室,并与教师和其他学生进行实时互动和讨论。
跨地域的家庭联系与娱乐:随着家庭成员之间分散居住的现象越来越普遍,无限制距离视频语音对讲小车可以帮助家庭成员保持联系。他们可以通过小车进行远程视频通话、分享生活片段、展示家庭成员之间的互动,并在娱乐活动中共同参与
通过实现无限制距离视频和语音通信,这个项目旨在提供一个灵活、便捷和安全的方法,让用户能够跨越地理限制,实现远程监控、通信和操作。这将为商务、救援、教育和家庭等各个领域带来新的机会和便利。
以上是CharGPT生成,其实我就是看到B站上有人做了一辆小车去拿快递,让我狠狠的心动了,理工男的动手欲望让我欲罢不能,无法制止!直接执行力拉满。
项目需求
- 要求使用电池供电,并能够充电;
- 自行安排小车的动力系统,要求能够控制左右转和前后冲即可;
- 小车可以远距离无线控制,要求通过网络控制小车的行动;
- 小车能够显示车前画面,通过网络远距离将画面传输到接收端进行显示;
- 小车能够进行远距离语音对话,既能听到声音也能发出声音;
- 加上显示器件,需要的时候可以打开显示小车状态,比如电量、设备连接情况等,方便维修;
(大概就做这么多功能吧,成本高了谁还想DIY啊,是吧?)
设计思路
电源部分
ESP32电源以及充电 电源是一个大问题,为了兼容充电,预计是使用电池并联的方式供电,不仅电流够大,充电也方便使用常见的充电模块或电路。充电和放电使用TP5400芯片,它可以通过USB给电池充电,还可以输出5V电源。需要的只是一些简单的外围器件。
电机供电
电机是这个项目最吃电的玩意,本想使用动力电池,(就是无人机上的那种航模电池),但是那种电池很贵。先用普通的18450电池直接给电机供电试试,如果耗电很快,就改为动力电池。电机的供电直接将电池接到电机驱动上。
摄像头供电
摄像头用的监控摄像头,看了供电参数是12V2A,2A的电流!我沉默了。感觉开不了多久电池就没有电了,但是先不管。现在需要考虑的是怎么将电池电压3.7V升到摄像头的12V2A。可以使用HX3608,它可以升压最高28V,开关电流有3.5A,我们只要多加几个大电容储储能应该就可以(等我验证完能不能带动这个摄像头)。
小车控制
主控
因为需要通过网络控制小车的行动,所以这里使用ESP32S3作为小车主要控制器件,ESP32S3具有高性能的处理能力、240MHz时钟频率和丰富的通信接口。除了常见的外设功能外,还带有WIFI+蓝牙功能,能够轻松与其他设备进行通信和互联。在淘宝买个开发板就好。
动力系统
使用常见的便宜货,黄色的TTL电机。相信用过这种电机的朋友都知道,这个电机是真的很垃圾,跑久了磨损一高,走直线的走不直。但是N20那种小电机又玩腻了,好电机又贵,随便搞个电机吧。
电机单靠单片机去驱动肯定是不行的,电流不够还可能损坏单片机,为了驱动方法也为了不好器件,需要再加一个电机驱动电路或者模块。电机驱动不知道大家是喜欢搭模块还是画电路。我为了方便后面的供电,比如小车充放电,摄像头的电等,还是自己画一个PCB好,不然后期小车上全部是飞线也太难看了。
电机驱动代定,预计采用RZ7899,TB6612,DRV8833,L298N等等,常见的电机驱动模块太多了,后面根据价格确定使用哪一个。
远程控制
使用arduino的点灯科技库,实现远程控制。带有可以自己DIY的界面控件,自己设计你的APP的UI。硬件方面的代码,点灯科技也给你做好了,只需要修改一点点就可以远程控制用,缺点就是需要使用WIFI,但是我们买了随身WIFI安在小车上,就解决这个问题了。
远距离语音对话以及视频传输
使用监控摄像头作为视频和语音对讲设备。(现在的摄像头行业也卷死了,WIFI版可语音通话带360度视角的摄像头,竟然36就买下了)
联网
因为摄像头和主控ESP32需要用到WIFI,所以需要购买一个随身WIFI给它们梁网。买了,13元拿下。到货了,还可以,需要实名认证,就是网速有点卡。但是只用在嵌入式设备,也用不到好网速,就将就一下,13块钱要啥自行车。(还要再花9.9买流量,所以实际花费22.9元)
形状外壳
因能力有限,不会3D,小车载体以及外壳直接使用PCB作为底板。PCB使用立创EDA设计加打板,不要钱。(感谢嘉立创的免费打板)
成本计算
模块化调试
小车远程控制
使用ESP32S3开发板,通过arduino的blinker库实现通过WIFI去远程操控小车。目前小车的PCB还没有开始设计,所以在代码中没有加入电机控制方面。
blinker库的官方说明资料:点灯科技 (diandeng.tech)
APP下载以及界面设计
app下载
首先是APP的下载:https://diandeng.tech/doc/app-download
也可以在手机的应用商城中搜索:点灯·blinker (我的手机是小米,小米的手机应用商城中已经有该APP)
- 界面设计 打开APP,点击右上角的+号,添加设备。
选择独立设备。
选择网络接入。
记录设备密钥(在后期的代码调试中,需要使用到该密钥)(请使用自己生成的密钥)
进入刚才新建的设备中进行界面设计。我的界面设计如下:
注意!每一个控件的名称都要清楚,因为在后面的代码设计中,需要通过控件名称确定是要操控哪个控件。
代码编程设计
如果是没有任何使用基础的,请参考点灯科技官网的入门说明,去安装对应的编程环境。
官方入门指导:https://diandeng.tech/doc/getting-start-esp32-wifi
使用arduino新建一个工程,接入开发板。
我的开发板参数如下:
写入以下代码,点击左上角的√键(验证),编译测试是否通过。
#define BLINKER_WIFI
#include <Blinker.h>
char auth[] = "08eec437a3de"; //设备秘钥----请修改为你生成的设备密钥!!!
char ssid[] = "4G-UFI-7787"; //WIFI名称---请修改为开发板要链接的WIFI名称
char pswd[] = "1234567890"; //WIFI密码--请修改为开发板要链接的WIFI密码
// //初始创建化数据对象
BlinkerNumber num_temp("num-temp"); //温度数据
BlinkerNumber num_electric("num-electric"); //电量数据
// 如果未绑定的组件被触发,则会执行其中内容
void dataRead(const String & data)
{
int startPos = data.indexOf(""") + 1;
int endPos = data.indexOf(""", startPos);
// 提取双引号内的内容,获取键名
String KeyName = data.substring(startPos, endPos);
//暂时通过串口输出查看是否提取正确
//后期通过键名确定是控制哪一个按钮
Serial.println(KeyName);
startPos = data.indexOf(""", endPos+1) + 1;
endPos = data.indexOf(""", startPos);
// 提取双引号内的内容,获取键值
String KeyValue = data.substring(startPos, endPos);
//暂时通过串口输出查看是否提取正确
//后期通过键值确定是按钮是按下还是松开
Serial.println(KeyValue);
//板载LED状态翻转,说明能够远程控制
digitalWrite(48, !digitalRead(48));
//将值上传到温度的数据对象
num_temp.print(12);
}
void setup()
{
// 初始化串口
Serial.begin(115200);
// 初始化blinker
Blinker.begin(auth, ssid, pswd);
//注册回调函数,当设备收到APP发来的数据时会调用设置的dataRead回调函数
Blinker.attachData(dataRead);
// 初始化有LED的IO
pinMode(48, OUTPUT);
// 点亮LED
digitalWrite(48, LOW);
//设置电机的PWM
ledcSetup(0, 2000, 8); // 设置通道0的频率为2000,分辨率8位
ledcAttachPin(1, 0); // 将通道0与引脚1连接
}
void loop() {
Blinker.run();
//设备延时
//Blinker.delay(500);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
如果不通过,请跟我的blinker版本一样。还有esp32包的版本。
下载验证
将开发板接入电脑,在arduino中设置好ESP32开发板的参数,点击左上角的→键(上传),将代码烧录到开发板中。
在arduino下面的输出窗口中,等待下载完成。下图为下载完成指示图。
下载完成之后,保持ESP32开发板处于上电状态,等待开发板连接上服务器。我们可以去手机APP端查看ESP32开发板是否连接成功。
当APP界面显示设备在线时,说明连接成功。
打开设备,进行数据传输测试。随便点击几个按钮。
电脑端的串口调试助手输出显示在APP上按下的按键名,以及按下的状态:top表示按下一次
手机端显示ESP32开发板上传过来的数据:
验证成功。
无线随身WIFI调试
根据购买的随身WIFI上的说明书进行激活即可。需要注意的是,使用随身WIFI需要实名认证才能够使用。
我购买的设备链接:https://detail.tmall.com/item.htm?_u=u2t4uge500f1&id=723126849433&spm=a1z09.2.0.0.336c2e8d3ccgnA
套餐参数:
这个随身WIFI没有什么好调试的,只是需要注意的是,随身WIFI使用的是5V供电,我们要在后面的PCB设计中加入USB供电接口。
语音对话摄像头调试
根据购买的摄像头上的说明书进行激活即可。需要注意的是,摄像头的APP和手机控制的APP是不一样的,到时候需要在手机上将摄像头APP的界面缩小,形成两个APP在一个界面的样子,这样才好操控。
最终的模块测试结果
最终丐版小车完成
源码
#define BLINKER_WIFI
#include <Blinker.h>
#include <string.h>
//#include "ESP32_CAM_SERVER.h"
bool setup_camera = false;
char auth[] = "08eec437a3de"; //设备秘钥
char ssid[] = "4G-UFI-7787"; //WIFI名称
char pswd[] = "1234567890"; //WIFI密码
String KeyName;
String KeyValue;
// //初始创建化按钮对象
// BlinkerButton Button_left("btn-left");
// BlinkerButton Button_right("btn-right");
// BlinkerButton Button_front("btn-front");
// BlinkerButton Button_back("btn-back");
// BlinkerButton Button_stop("btn-stop");
// //初始创建化数据对象
BlinkerNumber num_temp("num-temp");
BlinkerNumber num_electric("num-electric");
// 如果未绑定的组件被触发,则会执行其中内容
void dataRead(const String & data)
{
// //获取自启动开发板以来经过的毫秒数
// uint32_t BlinkerTime = millis();
// //将时间发送到手机
// Blinker.print(BlinkerTime);
int startPos = data.indexOf(""") + 1;
int endPos = data.indexOf(""", startPos);
// 提取双引号内的内容
KeyName = data.substring(startPos, endPos);
Serial.println(KeyName);
startPos = data.indexOf(""", endPos+1) + 1;
endPos = data.indexOf(""", startPos);
// 提取双引号内的内容
KeyValue = data.substring(startPos, endPos);
Serial.println(KeyValue);
//板载LED状态翻转
digitalWrite(48, !digitalRead(48));
//上传测试:将温度值上传到数据对象
num_temp.print(12);
}
void motor_init()
{
//设置电机的PWM
ledcSetup(0, 10000, 8); // 设置通道0的频率为10000,分辨率8位
ledcAttachPin(1, 0); // 将通道0与引脚1连接
//设置电机的PWM
ledcSetup(1, 10000, 8); // 设置通道1的频率为10000,分辨率8位
ledcAttachPin(2, 1); // 将通道1与引脚2连接
//设置电机的PWM
ledcSetup(2, 10000, 8); // 设置通道2的频率为10000,分辨率8位
ledcAttachPin(3, 2); // 将通道2与引脚3连接
//设置电机的PWM
ledcSetup(3, 10000, 8); // 设置通道3的频率为10000,分辨率8位
ledcAttachPin(4, 3); // 将通道3与引脚4连接
}
void motor_left(int speed)
{
ledcWrite(0, 0); // 输出PWM
ledcWrite(1, speed); // 输出PWM
ledcWrite(2, speed); // 输出PWM
ledcWrite(3, 0); // 输出PWM
}
void motor_right(int speed)
{
ledcWrite(0, speed); // 输出PWM
ledcWrite(1, 0); // 输出PWM
ledcWrite(2, 0); // 输出PWM
ledcWrite(3, speed); // 输出PWM
}
//前进,速度最大256
void motor_forward(int speed)
{
ledcWrite(0, speed); // 输出PWM
ledcWrite(1, 0); // 输出PWM
ledcWrite(2, speed); // 输出PWM
ledcWrite(3, 0); // 输出PWM
}
void motor_back(int speed)
{
ledcWrite(0, 0); // 输出PWM
ledcWrite(1, speed); // 输出PWM
ledcWrite(2, 0); // 输出PWM
ledcWrite(3, speed); // 输出PWM
}
void motor_stop()
{
ledcWrite(0, 256); // 输出PWM
ledcWrite(1, 256); // 输出PWM
ledcWrite(2, 256); // 输出PWM
ledcWrite(3, 256); // 输出PWM
}
/*
小车控制
轻击 tap
长按 press
松开 pressup
*/
void car_control(void)
{
// 如果按下前进
if(KeyName.equals("btn-front"))
{
// 如果是长按
if(KeyValue.equals("press"))
{
//小车前进
motor_forward(100);
}
// 如果长按松开
if(KeyValue.equals("pressup"))
{
//小车停止
motor_stop();
}
}
// 如果按下左转
if(KeyName.equals("btn-left"))
{
if(KeyValue.equals("press"))
{
motor_left(100);
}
if(KeyValue.equals("pressup"))
{
motor_stop();
}
}
//如果是按下右转
if(KeyName.equals("btn-right"))
{
if(KeyValue.equals("press"))
{
motor_right(100);
}
if(KeyValue.equals("pressup"))
{
motor_stop();
}
}
// 如果是按下后退
if(KeyName.equals("btn-back"))
{
if(KeyValue.equals("press"))
{
motor_back(100);
}
if(KeyValue.equals("pressup"))
{
motor_stop();
}
}
// 如果是按下停止
if(KeyName.equals("btn-stop"))
{
if(KeyValue.equals("tap"))
{
motor_stop();
}
if(KeyValue.equals("press"))
{
motor_stop();
}
if(KeyValue.equals("pressup"))
{
motor_stop();
}
}
//清除字符串缓存
KeyName.remove(0);
KeyValue.remove(0);
}
void setup()
{
// 初始化串口
Serial.begin(115200);
BLINKER_DEBUG.stream(Serial);
// 初始化blinker
Blinker.begin(auth, ssid, pswd);
//注册回调函数,当有设备收到APP发来的数据时会调用对应的回调函数
Blinker.attachData(dataRead);
// 初始化有LED的IO
pinMode(48, OUTPUT);
// 点亮LED
digitalWrite(48, LOW);
//初始化电机
motor_init();
}
void loop()
{
// 运行MQTT
Blinker.run();
// 运行小车控制
car_control();
// 局域网摄像头设置
// if (Blinker.connected() && !setup_camera)
// {
// setupCamera();
// setup_camera = true;
// Blinker.printObject("video", "{"str":"mjpg","url":"http://"+ WiFi.localIP().toString() + ""}");
// }
//设备延时
//Blinker.delay(500);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237