Project Background
In modern society, long-distance communication and remote operation have become important needs in people's work and life. However, traditional communication and remote control equipment have limitations in terms of distance and flexibility, and cannot meet people's needs for unlimited-distance communication and operation. Therefore, the project of developing an unlimited-distance video voice intercom car emerged.
This project aims to design and manufacture a car that can achieve unlimited-distance video and voice communication. By using advanced communication technology and internet connectivity, this car allows users to perform remote monitoring, communication, and operation anytime, anywhere.
Here are several important aspects of the project background:
Cross-regional collaboration and rescue: In the business world, companies often need to collaborate across regions. Traditional communication methods are limited by geographic distance, but an unlimited-distance video voice intercom car can solve this problem, allowing collaborators to communicate in real time, share information, and perform various tasks remotely. In addition, for rescue operations, this car allows rescuers to have real-time conversations and command with remote personnel, improving rescue efficiency.
Operation and monitoring in dangerous environments: Some work environments are often dangerous and risky, such as chemical plants and nuclear power plants. In these scenarios, the unlimited-distance video voice intercom car allows staff to maintain a safe distance and perform real-time monitoring and operation through the camera and microphone on the car.
Remote education and learning experience: With the rise of remote education, students can participate in courses from all over the world. The unlimited-distance video voice intercom car can provide students with a more realistic learning experience, such as visiting remote locations or laboratories, and having real-time interactions and discussions with teachers and other students.
Cross-regional family connection and entertainment: With the phenomenon of family members living apart becoming more and more common, the unlimited-distance video voice intercom car can help family members stay connected. They can use the car for remote video calls, share life moments, show interactions between family members, and participate together in entertainment activities.
By realizing unlimited-distance video and voice communication, this project aims to provide a flexible, convenient, and safe method for users to transcend geographic limitations and achieve remote monitoring, communication, and operation. This will bring new opportunities and convenience to various fields such as business, rescue, education, and family.
The above was generated by ChatGPT. Actually, I just saw someone on Bilibili make a car to pick up packages, which made my heart flutter. The hands-on desire of an engineering guy was unstoppable! I went all-in on execution.
Project Requirements
- Requires battery power and the ability to charge;
- Arrange the car's power system yourself; it is required to be able to control left and right turns and forward/backward movement;
- The car can be controlled wirelessly over long distances; it is required to control the car's actions via network;
- The car can display the view in front of the car and transmit the video to the receiving end over a long distance via the network for display;
- The car can perform long-distance voice conversations, both hearing sound and producing sound;
- Add a display component so that the car's status can be displayed when needed, such as battery level, device connection status, etc., for easy maintenance;
(That's about all the features. If the cost is too high, who would want to DIY, right?)
Design Approach
Power Section
ESP32 Power and Charging Power is a big issue. To support charging, we plan to use batteries connected in parallel for power supply. This not only provides sufficient current, but also makes charging convenient with common charging modules or circuits. Charging and discharging use the TP5400 chip, which can charge the battery via USB and also output 5V power. It only requires some simple peripheral components.
Motor Power Supply
The motor is the most power-hungry component in this project. I originally wanted to use a power battery (the kind of model airplane battery used on drones), but those batteries are very expensive. Let's first try using ordinary 18450 batteries to power the motor directly. If the power drains quickly, we'll switch to a power battery. The motor power supply directly connects the battery to the motor driver.
Camera Power Supply
The camera used is a surveillance camera. I looked at the power parameters: 12V 2A, 2A current! I was speechless. I felt like the battery would run out shortly after starting, but let's ignore that for now. What we need to consider now is how to step up the battery voltage of 3.7V to the camera's 12V 2A. We can use the HX3608, which can step up to a maximum of 28V, with a switching current of 3.5A. We just need to add a few large capacitors for energy storage and it should be fine (waiting for me to verify whether it can drive this camera).
Car Control
Main Controller
Because the car's actions need to be controlled via network, the ESP32S3 is used here as the car's main controller. The ESP32S3 has high-performance processing capability, a 240MHz clock frequency, and rich communication interfaces. In addition to common peripheral functions, it also has Wi-Fi + Bluetooth, making it easy to communicate and interconnect with other devices. Just buy a development board online.
Power System
Using common cheap stuff: the yellow TTL motor. I believe friends who have used this motor know that it's really bad — after running for a long time, the wear gets high and it can't go straight. But those small N20 motors are boring to play with, and good motors are expensive. Let's just use some random motor.
It's definitely not OK to drive the motor with only an MCU — the current is insufficient and it may damage the MCU. For the driving method and to avoid damaging components, we need to add a motor driver circuit or module. For the motor driver, I don't know whether you prefer assembling modules or designing circuits. For the convenience of later power supply, such as car charging/discharging, camera power, etc., it's better to design my own PCB. Otherwise, the car will be full of flying wires later, which would be too ugly.
The motor driver is yet to be determined. We plan to use RZ7899, TB6612, DRV8833, L298N, etc. There are too many common motor driver modules. We'll decide which one to use based on price later.
Remote Control
Use the Arduino Blinker library to implement remote control. It comes with customizable interface widgets, so you can design your own APP UI. For the hardware code, Blinker has also prepared it for you. You only need to make a few modifications to achieve remote control. The downside is that it requires Wi-Fi, but we bought a portable Wi-Fi to install on the car, which solves this problem.
Long-Distance Voice Conversation and Video Transmission
Use a surveillance camera as the video and voice intercom device. (The camera industry is also super competitive nowadays. A Wi-Fi version surveillance camera with voice calling and 360-degree view, I actually bought it for only 36 yuan.)
Networking
Because both the camera and the main controller ESP32 need Wi-Fi, we need to buy a portable Wi-Fi to provide them with internet. Bought it for 13 yuan. It arrived and it's okay. It requires real-name authentication, but the network speed is a bit slow. However, it's only for embedded devices, so we don't need high network speed. Let's make do with it. For 13 yuan, what more could you ask for? (You also need to spend another 9.9 yuan to buy data, so the actual cost is 22.9 yuan.)
Shape and Housing
Due to limited ability, I don't know 3D design. The car carrier and housing directly use PCB as the base board. The PCB is designed and fabricated using JLCEDA. It's free. (Thanks to JLC's free prototyping service.)
Cost Calculation
Modular Debugging
Car Remote Control
Use the ESP32S3 development board and the Arduino Blinker library to remotely control the car via Wi-Fi. Currently, the car's PCB has not yet been designed, so the motor control part is not included in the code.
Official documentation for the Blinker library: Diandeng Tech (diandeng.tech)
APP Download and Interface Design
APP Download
First, the APP download: https://diandeng.tech/doc/app-download
You can also search in your phone's app store: blinker (My phone is Xiaomi, and the Xiaomi app store already has this APP.)
- Interface Design Open the APP, click the + sign in the upper right corner, and add a device.
Select Independent Device.
Select Network Access.
Record the device key (it will be used in later code debugging). (Please use your own generated key.)
Enter the newly created device to design the interface. My interface design is as follows:
Note! The name of each widget must be clear, because in the subsequent code design, the widget name is needed to determine which widget to control.
Code Programming Design
If you have no prior experience, please refer to the official getting-started guide on Diandeng Tech's website to install the corresponding programming environment.
Official getting-started guide: https://diandeng.tech/doc/getting-start-esp32-wifi
Use Arduino to create a new project and connect the development board.
My development board parameters are as follows:
Write the following code and click the √ button (verify) in the upper left corner to compile and test whether it passes.
#define BLINKER_WIFI
#include <Blinker.h>
char auth[] = "08eec437a3de"; // Device key ---- Please change it to your generated device key!!!
char ssid[] = "4G-UFI-7787"; // Wi-Fi name --- Please change it to the Wi-Fi name the development board will connect to
char pswd[] = "1234567890"; // Wi-Fi password -- Please change it to the Wi-Fi password the development board will connect to
// // Initialize data objects
BlinkerNumber num_temp("num-temp"); // Temperature data
BlinkerNumber num_electric("num-electric"); // Battery data
// If an unbound component is triggered, the content inside will be executed
void dataRead(const String & data)
{
int startPos = data.indexOf(""") + 1;
int endPos = data.indexOf(""", startPos);
// Extract the content within double quotes to get the key name
String KeyName = data.substring(startPos, endPos);
// Temporarily output via serial port to check whether the extraction is correct
// Later, determine which button to control based on the key name
Serial.println(KeyName);
startPos = data.indexOf(""", endPos+1) + 1;
endPos = data.indexOf(""", startPos);
// Extract the content within double quotes to get the key value
String KeyValue = data.substring(startPos, endPos);
// Temporarily output via serial port to check whether the extraction is correct
// Later, determine whether the button is pressed or released based on the key value
Serial.println(KeyValue);
// Toggle onboard LED state, indicating remote control is working
digitalWrite(48, !digitalRead(48));
// Upload the value to the temperature data object
num_temp.print(12);
}
void setup()
{
// Initialize serial port
Serial.begin(115200);
// Initialize blinker
Blinker.begin(auth, ssid, pswd);
// Register callback function. When the device receives data from the APP, the configured dataRead callback function will be called
Blinker.attachData(dataRead);
// Initialize the IO with LED
pinMode(48, OUTPUT);
// Light up LED
digitalWrite(48, LOW);
// Set motor PWM
ledcSetup(0, 2000, 8); // Set channel 0 frequency to 2000, 8-bit resolution
ledcAttachPin(1, 0); // Connect channel 0 to pin 1
}
void loop() {
Blinker.run();
// Device delay
//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
If it doesn't pass, please use the same Blinker version as mine. And the same ESP32 package version.
Download Verification
Connect the development board to the computer, set the ESP32 development board parameters in Arduino, and click the → button (upload) in the upper left corner to burn the code into the development board.
In the output window at the bottom of Arduino, wait for the download to complete. The following figure shows the download completion indicator.
After the download is complete, keep the ESP32 development board powered on and wait for the development board to connect to the server. We can go to the mobile APP to check whether the ESP32 development board is connected successfully.
When the APP interface shows the device is online, it means the connection is successful.
Open the device and perform data transmission tests. Click a few buttons at random.
The computer's serial debugging assistant output displays the button names pressed on the APP, as well as the pressed status: top means pressed once.
The phone displays the data uploaded from the ESP32 development board:
Verification successful.
Wireless Portable Wi-Fi Debugging
Just activate it according to the instructions that come with the purchased portable Wi-Fi. Note that using the portable Wi-Fi requires real-name authentication.
Link to the device I purchased: https://detail.tmall.com/item.htm?_u=u2t4uge500f1&id=723126849433&spm=a1z09.2.0.0.336c2e8d3ccgnA
Plan parameters:
There's nothing to debug for this portable Wi-Fi. Just note that the portable Wi-Fi uses 5V power supply. We need to add a USB power interface in the later PCB design.
Voice Conversation Camera Debugging
Just activate it according to the instructions that come with the purchased camera. Note that the camera APP and the phone control APP are different. When the time comes, you need to minimize the camera APP interface on the phone, so that the two APPs appear on one interface. This makes it easier to control.
Final Module Test Results
Final Budget-Version Car Complete
Source Code
#define BLINKER_WIFI
#include <Blinker.h>
#include <string.h>
//#include "ESP32_CAM_SERVER.h"
bool setup_camera = false;
char auth[] = "08eec437a3de"; // Device key
char ssid[] = "4G-UFI-7787"; // Wi-Fi name
char pswd[] = "1234567890"; // Wi-Fi password
String KeyName;
String KeyValue;
// // Initialize button objects
// 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");
// // Initialize data objects
BlinkerNumber num_temp("num-temp");
BlinkerNumber num_electric("num-electric");
// If an unbound component is triggered, the content inside will be executed
void dataRead(const String & data)
{
// // Get the number of milliseconds since the development board started
// uint32_t BlinkerTime = millis();
// // Send the time to the phone
// Blinker.print(BlinkerTime);
int startPos = data.indexOf(""") + 1;
int endPos = data.indexOf(""", startPos);
// Extract the content within double quotes
KeyName = data.substring(startPos, endPos);
Serial.println(KeyName);
startPos = data.indexOf(""", endPos+1) + 1;
endPos = data.indexOf(""", startPos);
// Extract the content within double quotes
KeyValue = data.substring(startPos, endPos);
Serial.println(KeyValue);
// Toggle onboard LED state
digitalWrite(48, !digitalRead(48));
// Upload test: upload the temperature value to the data object
num_temp.print(12);
}
void motor_init()
{
// Set motor PWM
ledcSetup(0, 10000, 8); // Set channel 0 frequency to 10000, 8-bit resolution
ledcAttachPin(1, 0); // Connect channel 0 to pin 1
// Set motor PWM
ledcSetup(1, 10000, 8); // Set channel 1 frequency to 10000, 8-bit resolution
ledcAttachPin(2, 1); // Connect channel 1 to pin 2
// Set motor PWM
ledcSetup(2, 10000, 8); // Set channel 2 frequency to 10000, 8-bit resolution
ledcAttachPin(3, 2); // Connect channel 2 to pin 3
// Set motor PWM
ledcSetup(3, 10000, 8); // Set channel 3 frequency to 10000, 8-bit resolution
ledcAttachPin(4, 3); // Connect channel 3 to pin 4
}
void motor_left(int speed)
{
ledcWrite(0, 0); // Output PWM
ledcWrite(1, speed); // Output PWM
ledcWrite(2, speed); // Output PWM
ledcWrite(3, 0); // Output PWM
}
void motor_right(int speed)
{
ledcWrite(0, speed); // Output PWM
ledcWrite(1, 0); // Output PWM
ledcWrite(2, 0); // Output PWM
ledcWrite(3, speed); // Output PWM
}
// Forward, max speed 256
void motor_forward(int speed)
{
ledcWrite(0, speed); // Output PWM
ledcWrite(1, 0); // Output PWM
ledcWrite(2, speed); // Output PWM
ledcWrite(3, 0); // Output PWM
}
void motor_back(int speed)
{
ledcWrite(0, 0); // Output PWM
ledcWrite(1, speed); // Output PWM
ledcWrite(2, 0); // Output PWM
ledcWrite(3, speed); // Output PWM
}
void motor_stop()
{
ledcWrite(0, 256); // Output PWM
ledcWrite(1, 256); // Output PWM
ledcWrite(2, 256); // Output PWM
ledcWrite(3, 256); // Output PWM
}
/*
Car control
tap tap
long press press
release pressup
*/
void car_control(void)
{
// If forward is pressed
if(KeyName.equals("btn-front"))
{
// If it is a long press
if(KeyValue.equals("press"))
{
// Car moves forward
motor_forward(100);
}
// If long press released
if(KeyValue.equals("pressup"))
{
// Car stops
motor_stop();
}
}
// If left turn is pressed
if(KeyName.equals("btn-left"))
{
if(KeyValue.equals("press"))
{
motor_left(100);
}
if(KeyValue.equals("pressup"))
{
motor_stop();
}
}
// If right turn is pressed
if(KeyName.equals("btn-right"))
{
if(KeyValue.equals("press"))
{
motor_right(100);
}
if(KeyValue.equals("pressup"))
{
motor_stop();
}
}
// If backward is pressed
if(KeyName.equals("btn-back"))
{
if(KeyValue.equals("press"))
{
motor_back(100);
}
if(KeyValue.equals("pressup"))
{
motor_stop();
}
}
// If stop is pressed
if(KeyName.equals("btn-stop"))
{
if(KeyValue.equals("tap"))
{
motor_stop();
}
if(KeyValue.equals("press"))
{
motor_stop();
}
if(KeyValue.equals("pressup"))
{
motor_stop();
}
}
// Clear string buffer
KeyName.remove(0);
KeyValue.remove(0);
}
void setup()
{
// Initialize serial port
Serial.begin(115200);
BLINKER_DEBUG.stream(Serial);
// Initialize blinker
Blinker.begin(auth, ssid, pswd);
// Register callback function. When a device receives data from the APP, the corresponding callback function will be called
Blinker.attachData(dataRead);
// Initialize the IO with LED
pinMode(48, OUTPUT);
// Light up LED
digitalWrite(48, LOW);
// Initialize motors
motor_init();
}
void loop()
{
// Run MQTT
Blinker.run();
// Run car control
car_control();
// LAN camera setup
// if (Blinker.connected() && !setup_camera)
// {
// setupCamera();
// setup_camera = true;
// Blinker.printObject("video", "{"str":"mjpg","url":"http://"+ WiFi.localIP().toString() + ""}");
// }
// Device delay
//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